Skip to content

Commit ff875a3

Browse files
committed
Run model contracts as observational PR checks
1 parent 6fac16c commit ff875a3

2 files changed

Lines changed: 79 additions & 18 deletions

File tree

‎.github/workflows/contracts.yml‎

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ name: Model integration contracts
33
# Proof of concept (huggingface/transformers-mic, docs/transformers-ci-proof.md).
44
# Runs the model integration contracts the changed files can affect, on slim
55
# fixtures pinned on the Hub, against the reviewed baselines in
6-
# tests/contracts/expectations/. Not a required check: a failure here is a
7-
# signal for review, with the reproduce command in the job summary.
6+
# tests/contracts/expectations/. This first wave is observational: failures
7+
# are reported in the summary and artifacts but do not block the PR.
88

99
on:
1010
pull_request:
@@ -22,6 +22,8 @@ concurrency:
2222

2323
jobs:
2424
contracts:
25+
# Infrastructure failures must not block PRs during the observational rollout.
26+
continue-on-error: true
2527
runs-on:
2628
group: aws-m8i-l-cache
2729
timeout-minutes: 90
@@ -47,6 +49,8 @@ jobs:
4749
fetch-depth: 0
4850

4951
- name: Install
52+
id: install
53+
continue-on-error: true
5054
run: |
5155
git config --global --add safe.directory "$GITHUB_WORKSPACE"
5256
start=$SECONDS
@@ -63,13 +67,19 @@ jobs:
6367
echo "Installed in $((SECONDS - start)) s on $(lscpu | sed -n 's/^Model name: *//p'), $(nproc) cores"
6468
6569
- uses: actions/cache@v4
70+
continue-on-error: true
6671
with:
6772
path: /tmp/hf_home/hub
6873
key: contracts-hf-${{ hashFiles('tests/contracts/fleet-lock.json') }}
6974

7075
- name: Run the contracts
7176
id: run
77+
if: steps.install.outcome == 'success'
7278
continue-on-error: true
79+
env:
80+
REF_NAME: ${{ github.ref_name }}
81+
HEAD_REF: ${{ github.head_ref }}
82+
BASE_REF: ${{ github.base_ref }}
7383
run: |
7484
export PYTHONPATH="$PWD/src"
7585
python - <<'PY_SOURCE'
@@ -104,12 +114,12 @@ jobs:
104114
path.write_text(json.dumps(lock, indent=2) + "\n")
105115
print("Whisper generation fix present:", fixed)
106116
PY_WHISPER_MATCH
107-
if [[ "${{ github.ref_name }}" == contracts-proof || "${{ github.head_ref }}" == contracts-proof ]]; then
117+
if [[ "$REF_NAME" == contracts-proof || "$HEAD_REF" == contracts-proof ]]; then
108118
selection=(--run-all)
109-
elif [[ "${{ github.event_name }}" == pull_request ]]; then
110-
git diff --name-only "origin/${{ github.base_ref }}...HEAD" > /tmp/changed-files.txt
119+
elif [[ "$GITHUB_EVENT_NAME" == pull_request ]]; then
120+
git diff --name-only "origin/$BASE_REF...HEAD" > /tmp/changed-files.txt
111121
selection=(--changed-files /tmp/changed-files.txt)
112-
elif [[ "${{ github.ref_name }}" == proof-* ]]; then
122+
elif [[ "$REF_NAME" == proof-* ]]; then
113123
git diff --name-only origin/contracts-proof...HEAD > /tmp/changed-files.txt
114124
selection=(--changed-files /tmp/changed-files.txt)
115125
else
@@ -135,7 +145,7 @@ jobs:
135145
for line in sys.stdin:
136146
r = json.loads(line)
137147
print(r["status"].ljust(6), r["target"], r.get("variant", ""), r.get("platform", ""), flush=True)' || status=$?
138-
if [[ "${{ github.ref_name }}" == contracts-proof || "${{ github.head_ref }}" == contracts-proof ]]; then
148+
if [[ "$REF_NAME" == contracts-proof || "$HEAD_REF" == contracts-proof ]]; then
139149
python - <<'PY_COVERAGE'
140150
import json
141151
from pathlib import Path
@@ -161,22 +171,64 @@ jobs:
161171
exit "${status:-0}"
162172
163173
- name: Summary
174+
id: summary
164175
if: always()
176+
continue-on-error: true
177+
env:
178+
INSTALL_OUTCOME: ${{ steps.install.outcome }}
179+
RUN_OUTCOME: ${{ steps.run.outcome }}
165180
run: |
166181
touch /tmp/results.jsonl
167-
tmic report /tmp/results.jsonl --log /tmp/run.log \
168-
--lock "$LOCK" >> "$GITHUB_STEP_SUMMARY"
182+
{
183+
echo "**Observational run:** failures do not block this PR."
184+
echo
185+
echo "Source: \`$GITHUB_SHA\`; event: \`$GITHUB_EVENT_NAME\`."
186+
echo
187+
} >> "$GITHUB_STEP_SUMMARY"
188+
if command -v tmic >/dev/null 2>&1; then
189+
tmic report /tmp/results.jsonl --log /tmp/run.log \
190+
--lock "$LOCK" >> "$GITHUB_STEP_SUMMARY" || \
191+
echo "Could not render the contract report; see the artifact and job log." >> "$GITHUB_STEP_SUMMARY"
192+
else
193+
echo "Contract runner was not installed; see the job log." >> "$GITHUB_STEP_SUMMARY"
194+
fi
195+
python - <<'PY_RESULT'
196+
import json
197+
import os
198+
from collections import Counter
199+
from pathlib import Path
200+
201+
results = Path('/tmp/results.jsonl')
202+
rows = [json.loads(line) for line in results.read_text().splitlines() if line.strip()]
203+
log = Path('/tmp/run.log')
204+
selections = [json.loads(line) for line in log.read_text().splitlines() if line.startswith('{"selection"')] if log.exists() else []
205+
report = {
206+
'event': os.environ['GITHUB_EVENT_NAME'],
207+
'sha': os.environ['GITHUB_SHA'],
208+
'run_id': os.environ['GITHUB_RUN_ID'],
209+
'pr': json.loads(Path(os.environ['GITHUB_EVENT_PATH']).read_text()).get('pull_request', {}).get('number'),
210+
'install_outcome': os.environ['INSTALL_OUTCOME'],
211+
'run_outcome': os.environ['RUN_OUTCOME'],
212+
'counts': dict(Counter(row['status'] for row in rows)),
213+
'selections': [item['selection'] for item in selections],
214+
'results': len(rows),
215+
}
216+
Path('/tmp/contracts-observation.json').write_text(json.dumps(report, indent=2) + '\n')
217+
print('Observation:', json.dumps(report))
218+
PY_RESULT
169219
170220
- uses: actions/upload-artifact@v4
221+
id: artifact
171222
if: always()
223+
continue-on-error: true
172224
with:
173225
name: contracts
174226
path: |
175227
/tmp/results.jsonl
176228
/tmp/run.log
229+
/tmp/contracts-observation.json
177230
178-
- name: Result
179-
if: steps.run.outcome == 'failure'
231+
- name: Flag contract failures for review
232+
if: always() && (steps.install.outcome == 'failure' || steps.run.outcome == 'failure' || steps.summary.outcome == 'failure' || steps.artifact.outcome == 'failure')
180233
run: |
181-
echo "::error::A model integration contract failed: see the job summary for the failing target and how to reproduce it."
182-
exit 1
234+
echo "::warning::A model integration contract failed or could not run; see the job summary and artifact for details. This observation does not block the PR."

‎utils/contracts/README.md‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
# Model integration contracts (proof)
22

3-
The CI workflow installs the immutable `TMIC_SHA` of
3+
The PR CI workflow installs the immutable `TMIC_SHA` of
44
[huggingface/transformers-mic](https://github.com/huggingface/transformers-mic) and
55
uses `tmic check` and `tmic report`. The old vendored scripts are retained as a
66
reference for the original proof; CI executes the installed package.
77

8+
The first PR wave selects the BF16 variant of 23 published prototype contracts
9+
and one historical SmolLM control. Changed files select affected contracts;
10+
shared Transformers code selects the whole wave. This is an observational job:
11+
failures produce a warning and a job summary but do not block the PR. Download
12+
the `contracts` artifact for per-case JSONL, the runner log and
13+
`contracts-observation.json` with status counts, selection reasons and source
14+
metadata. A run with no selected contracts has no validation result.
815

916
- `tests/contracts/fleet-lock.json`: pinned contracts, fixtures, checkpoints, and environment. Contracts and fixtures are downloaded from the Hub (`hf-internal-testing/*`) at their pinned revisions and checked against their hashes. No `local_patches`: open framework bugs are narrowed `known_failures` entries (an error message to match, or outputs to skip).
1017
- `tests/contracts/expectations/<contract>/{cpu-x86_64,cpu-x86_64-bf16,cpu-arm64}/`: reviewed baselines. CI uses `cpu-x86_64` (and `cpu-x86_64-bf16` for bfloat16 fixtures); `cpu-arm64` (Apple silicon) lets a failure reproduce on a Mac with the same command.
@@ -15,12 +22,14 @@ git diff --name-only origin/main...HEAD > /tmp/mic-changed-files.txt
1522
tmic check --fixtures-only --lock tests/contracts/fleet-lock.json --changed-files /tmp/mic-changed-files.txt
1623
```
1724

18-
`tests/contracts/prototype-fleet.lock` adds 17 `tmic`-generated architecture
25+
`tests/contracts/prototype-fleet.lock` adds 23 `tmic`-generated architecture
1926
contracts, checked against published Hub pins on CPU and GPU before export.
2027
The prototype lock uses `mic-*` contract keys to avoid case collisions with
21-
historical names such as `BERT`. These run in default, eager and bfloat16 variants. The original six-contract
22-
fleet remains the historical regression control. Both fleets use changed-file
23-
selection on PRs and run in full on pushes to `contracts-proof`.
28+
historical names such as `BERT`. The current PR wave runs only their BF16
29+
variants; default and eager results remain historical proof evidence. The
30+
original six-contract fleet remains historical regression evidence, with only
31+
the SmolLM control included in this wave. Pushes to `contracts-proof` run all
32+
24 selected cases and check that none were missed.
2433

2534
The prototype CPU expectations were measured on the GPU worker's x86 CPU under
2635
the pinned runtime. This branch also checks them on the dedicated CPU CI runner;

0 commit comments

Comments
 (0)