Contracts
terminal-cancel.contract.md
Contract: Terminal-Cancel Verdict (4a) + Stale-Running Sweep (4b)
4a — scripts/ci/fleet_verdict.py
classify(runs, labels) -> strgainsinfra-errorper the precedence indata-model.md(rule 4, inserted between the incomplete check and the green line). The:95green line, the dedup guard (:325-331), and the recognition regex (:323, already listsinfra-error) are unchanged.comment_body(...)adds one plain-language line whenstate=="infra-error": a required run was cancelled (infra/timeout kill), not a code failure; re-run to release the head.classifydocstring namesinfra-error.scripts/ci/fleet_main.pyis not edited (reusesclassify); its P0 gate staysstate != "red"soinfra-erroropens no incident.
4a test obligations (red-first on today's code)
1. test_terminal_cancel_reposts_and_is_not_suppressed — full report(): seed latest bot comment [ci] running @HEAD, one required gate completed/cancelled; assert today not api.posts, after-fix api.posts[0]["body"].startswith("[ci] infra-error @HEAD"). (template :242) 2. flip test_fleet_verdict.py:175 ("completed","cancelled","running")→infra-error; keep :176 skipped→running. 3. flip test_fleet_verdict.py:319 ("cancelled","running")→("cancelled","infra-error"). 4. test_cancel_among_pending_runs_stays_running — {cancelled, in_progress} and {cancelled, None} → running (INV-2). 5. test_failure_and_cancel_is_red (INV-3); test_deferred_not_overridden_by_cancel (INV-4); test_all_success_green_never_infra (INV-1). 6. migrate test_fleet_main.py:109 — cancelled→infra-error + not api.mutations (no P0); skipped/None→running. 7. test_infra_error_tip_appended_to_open_incident_does_not_escalate.
4b — scripts/ci/stale_running_sweep.py (new) + .github/workflows/ci-stale-running-sweep.yml (new)
find_stale_running(...) -> list[StaleHead]perdata-model.md— pure, no I/O.main():ghat the edge (list open PRs +[ci]comments + required runs;mainhead); surface = idempotent[ci-sweep]watch comment +::warning::. NEVER a[ci] <state>verdict, never edits reporter comments, never re-triggers.- Workflow:
on: schedule + workflow_dispatch; invokespython3 scripts/ci/stale_running_sweep.py.
4b test obligations
1. red-first detector: stale detected (latest running + all runs terminal); NOT stale (latest terminal); NOT stale (a run in_progress); fail-closed on partial evidence. 2. idempotency: second run against an already-flagged head yields no duplicate surface. 3. execution-grounded wiring guard: the workflow step invokes scripts/ci/stale_running_sweep.py.
Frozen (assert unchanged)
# round-trip: skip: illustrative contract anchors, not a parseable mission artifact
frozen:
- path: scripts/ci/router_gate.py # separate unrelated classify (C-001)
- path: scripts/ci/fleet_verdict.py
parts: ["dedup running-guard ~:325-331", "recognition regex ~:323", "green line ~:95"]
- path: .github/workflows/ci-fleet-verdict.yml # Stage-1 concurrency levers (C-002)