Repository navigation
fix(pm): check-expected-skips refuses to judge a live head with a roster that is not the base branch's - #24892
Merged
objectstack-fleet[bot] merged 2 commits intoOct 20, 2026
Conversation
…ter that is not the base branch's The roster a live run judges with is this file plus every workflow file in the checkout it runs from; a head's check-runs come from the workflows of the merge they were built on. A checkout behind its base therefore read a job rostered on the base since as an unexpected skip (exit 4). A live run now compares the roster's sources (this file and every workflow, by git blob id, working tree against the base branch's live tip via the contents API: no history, no fetch) before it judges, and answers exit 3 NOT MEASURED naming each differing path and the re-pin when they differ. The offline paths (--check-runs-json, --roster) are unchanged. Claude-Session: https://claude.ai/code/session_01M82feuetLzrCiBz41BJb7L Co-authored-by: Claude <noreply@anthropic.com>
…laim Claude-Session: https://claude.ai/code/session_01M82feuetLzrCiBz41BJb7L Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
席位核对ACCEPT ·
Generated by Claude Code |
objectstack-fleet
Bot
deleted the
claude/issue-24849-expected-skips-stale-roster
branch
October 20, 2026 14:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #24849
Clause-②: no
What changed
scripts/pm/check-expected-skips.mjsis the only file in the diff.A live run (
--pr N/--head SHA) now compares the roster in hand with the base branch's roster before it judges anything. When they differ it answers exit 3 NOT MEASURED, naming each differing path and the re-pin recipe. When they are identical it judges as before, and the verdict line names whose roster judged it (... every one in main's roster (exit 0)).--check-runs-jsonand--rosterare unchanged: no network, no comparison, and the offline verdict line is byte-identical (pinned).What is compared. The roster is a function of exactly two inputs in the checkout the command runs from: this file (the listed rows and the derivation code) and every
.github/workflows/*.yml(the derived rows). Their working-tree bytes are hashed in-process as git blob ids, then compared with the blob ids the contents API lists forscripts/pmand.github/workflowsat the base branch's live tip. That takes two directory listings and needs no history, no fetch and no git binary.A refused live run, measured from this branch (its copy of the script is not main's):
Refuse or print the gap: the card left this to the script's maintainer
The choice is to refuse, under the existing exit 3, with no new exit code. A roster that is not the base's belongs in the same class as an unreadable head, because it gives no confident verdict in either direction. A stale roster produces a false ⛔ for a newly rostered job and a false OK for a retired row's skip. Printing the gap beside a 0 or 4 would keep the confident exit code, which is the defect itself. A distinct exit code would give callers a third NOT MEASURED spelling to learn. The header's exit register is updated in place.
Which ref can say whether the roster is current (measured 2026-10-20)
HEADbehindorigin/main(ancestry or behind-count)b1676441b, only 14 of them touching.github/workflowsand 1 touching this file (scripts/pm/git-history.mjs count; the history floor of 2026-09-06 predates the window).merge-baseandrev-listalso answer green from a shallow clone. And a localorigin/mainis only as fresh as the last fetch.base.shabase.sha=580fd4ed3(committed 04:15Z). Its head7a9bc58c6was pushed at 08:05:59Z, and its 08:06Z runs were built on a main that already carriedab9890169. Measured against thatbase.sha, the stale6b222464cwould have read as ahead of its base: a false green on the instance itself.--headwithout a PR compares with the board's default branch, at the cost of one extraGET /repos/{repo}read. A different board, whose base carries neither this file nor these workflows, is now refused instead of being judged against objectstack's roster. That matches the pm-dispatch enqueue bar, which already says the roster judges objectstack only (名单 check-expected-skips.mjs 只判 objectstack). The header paragraph that described cross-board judging is rewritten to match.Evidence
--check-runs-jsonon PR docs(readme): say "ontology-driven" beside "the ontology is the software" #24771's head7a9bc58c6(all 37 of its check-runs, read once into a fixture file):6b222464cexits 4 with⛔ 1 skipped check-run(s) outside the roster, naming18.x upgrade harness (opt-in);c56115bf9exits 0 with10 skipped check-run(s), every one in the roster.b1676441b(42 roster sources on main), through the exported functions:6b222464c: gap 2, exactly.github/workflows/upgrade-harness-optin.yml — on main (921469dc9), absent hereandscripts/pm/check-expected-skips.mjs — here 6df58d83c, on main acb32de67;--pr 24771and--head 7a9bc58c6...both exit 3 with the gap and the re-pin shown above, at 3 REST reads each.scripts/pm/check-expected-skips.mjsat main, the contents-APIshaandgit rev-parse origin/main:PATHboth readacb32de67....Tests
node scripts/pm/check-expected-skips.mjs --self-teststays fully offline. It now runs 169 cases, up from 154, and exits 0 atfbd5fa30b. The new cases:absent-hereand this filediffers, nothing else; the reverse readshere-only;main's roster, while the offline line is byte-for-byte the old one;rosterGap(beforereadCheckRuns(.Gates (local, at
fbd5fa30b)node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, run with no paths (change set taken from merge baseb1676441b), derived 33 commands. All 33 ran and exited 0, with exit codes captured before any pipe.--ranprinted✓ dispatch-gates --ran: 33 derived famil(ies) accounted for — 33 run, 0 NOT-MEASURED.pnpm check:pm-dispatch-gates, run detached as its header prescribes:✓ dispatch-gates self-test (fast tier): 1913 cases pass; 6 slow section(s) deferred, exit 0.pnpm check:pm-half-statesexits 0 (4916 cases). Thedispatch-gates.data.mjsanddispatch-gates.self-test.mjspins run inside the battery above. The header edit adds no lines above theself-test-readsmarker, so it stays on line 133, where that self-test pins it.eslint --no-inline-configon this one file exits 0. Repo-wide scans are left to CI.Acceptance notes
node scripts/measure-self-test-floor.mjsrefuses its census (exit 1:2 file(s) carry a landed handshake spelling the recogniser reads as none: scripts/pm/check-prior-rulings.mjs, scripts/pm/dispatch-gates.mjs). It refuses identically on base3fbef41b4, and this diff touches none of those three files. The tool is a measurement with no CI wiring; carrier: none.scripts/pm/**publishes nothing, so this PR carriesskip-changeset.Generated by Claude Code