fix(ci): a cancelled Test Core leg with partial attestations counts its roster — a missing shard is red, not green (#16157) - #16316
Merged
Conversation
…ts roster `judge()` in scripts/check-shard-attestation.mjs short-circuited every leg whose aggregate result read `cancelled` to "expected attestations: 0", before the count. That is #3668's shape (whole matrix superseded, zero shards ran) and stays; but a shard killed mid-run by its job timeout produces no verdict, no `failure` exists to dominate, and the required `Test Core` context went green over its untested packages (run 34007386254, five of six attested). Split `cancelled` by the count: zero attestations of the leg keep the #3668 pass verbatim; at least one attestation makes the declared roster REQUIRED, every missing shard is named, and the gate is red. The pinned self-test assertion "a leg that attested before the cancellation is allowed, not required" is overturned and rewritten; a #16157 battery pins both directions, the measured 6-shard shape, the dominance experiment and the #11998 attempt-scoping interplay. Battery floor 15 -> 16. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
baozhoutao
marked this pull request as ready for review
September 6, 2026 14:23
baozhoutao
enabled auto-merge
September 6, 2026 14:24
This was referenced Sep 6, 2026
This was referenced Sep 6, 2026
Merged
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 #16157
Clause-②: yes — required-check semantics change (
Test Coreaccepts fewer leg states than before; see derived judgments).Ruling executed: option A (issue comment
5559243179, director seat, decision batch #54, maintainer 「同意」). Head sha of every reading below:b79626679.What changed
judge()inscripts/check-shard-attestation.mjsshort-circuited every leg whose aggregate result readcancelledtoexpected attestations: 0— before the count — so the requiredTest Corecontext went green over a shard that was killed mid-run while its five siblings had attested (run34007386254, the card's measurement; 43 further instances today, table below). That is #3668's shape only when the whole matrix was superseded and nothing ran; a shard cancelled by its job timeout produces no verdict, so there is nofailureto dominate the aggregate.The
cancelledbranch is now split by the count, on the samepresentmap--verifyreads from the downloadedshard-attest-test-*artifacts:satisfied (cancelled — run-lifecycle state, #3668; expected attestations: 0), no counting.cancelled AFTER k of N declared shard(s) attested — not a superseded matrix; the roster is REQUIRED and every missing shard is named (#16157)and falls through to the ordinary count: every missing shard is aMISSINGline, the error names the missing shard(s) and the sibling(s) that did attest, and the gate exits 1.One counting path, not two: the partial-cancellation case reuses the roster count that
success/abandoned/leaked values already go through, so the #11998 attempt-scoping rules apply to it unchanged. The header's "What is deliberately NOT changed" bullet now states both shapes; the pinned self-test assertion "a leg that attested before the cancellation is allowed, not required" is overturned and rewritten; the#3668 lifecyclebattery is renamed to the case it actually measured; a#16157battery pins both directions. Noci.ymledit: the gate already receives--leg "test/6:$OS_TEST_RESULT"and the artifact download step is unchanged.Derived judgments — the required check's accept/reject set, before and after
origin/mainat1ca95df16)b79626679)cancelledcancelledexpected attestations: 0(the defect)cancelledall N declared shard(s) published a positive attestation)failuresuccess/abandoned/ any leaked valuesuccess/abandoned/ any leaked valueskipped, filtersuccessskipped, filtersuccessskipped, filtercancelledskipped, filter otherNote on the
skipped-while-filter-cancelledbranch (judge(), the block right under the cancelled one): left as is. The ruling's logic keys on a shard of the leg having run — "the matrix ran, so a cancelled sibling was killed mid-suite". Askippedleg scheduled nothing, so no shard of it can have been killed mid-run; the only credential that can sit there is a carried-over earlier-attempt one, which is #11998's domain. The distinction is therefore not forced, and the branch is out of scope per the dispatch; flagging it here so the reviewer can disagree.Blast radius — every ci.yml run since 2026-09-06T00:00Z with a cancelled
Test Core (k/6)shardRead from the Actions API only (
/actions/workflows/ci.yml/runs?event=merge_group|pull_request&created=…, then/runs/{id}/jobs?filter=latest,/pulls/{n}); nothing was re-run. 252 runs scanned (110merge_group, 142pull_request); 48 had at least one cancelled shard.Summary:
Test Core=success). Under this PR every one of them is red.(5/6)or(1/6)cancelled with the other five attested.publicSharing.enabledis a standing policy held at redemption;resolveTokennames the switched-off block among itsnullcauses #16196, docs(spec): record DeleteDataRequestSchema's consumer and why the DELETE data door carries no requestSchema #16191, fix(analytics): a dataset measure's result type stops contradicting its own value — min/max over a temporal field istime, notnumber#16101) — the PR check that admitted the PR to the queue. Their queue runs are separate rows where they also hit.NAMESPACE_CONFLICTinERROR_CODE_LEDGER#16252 twice).34005462440(fix(cli): refuseos lint --generatorwithout--evalinstead of silently ignoring it #16115) is the whole-matrix supersession (all six cancelled, zero attested — stays green under this PR, CI: Dogfood Regression Gate 把 cancelled 当失败 —— 每次连续推送都产生一条假红 #3668); run34018547387(feat(spec): every metadata.endpoints.* switch gates exactly the face its name states, and the whole-store operations get their own keymaintenance#16243) is the dominance experiment live (shard 2failure+ shard 1cancelled⇒ aggregatefailure, red before and after); runs34018298477,34009395649,34007386254are attempt-2 re-runs whose latest attempt attested 6/6 (green before and after — note the card's own run34007386254was re-run by someone after the card was filed; recorded, not judged).Real-data reading on run
34033611402(queue group of #16286, the 6th confirmation): the artifact listing for that run names exactlyshard-attest-test-1-of-6,-2-,-3-,-4-,-6-of-6(shard 5 absent). Replaying--verifyatb79626679over a fixture directory emitted with that exact roster and--leg test/6:cancelledexits 1 with1 of 6 declared shard(s) of test published no positive attestation (test-5-of-6) while 5 sibling(s) did. The artifact BYTES themselves are NOT MEASURED — the blob host answers CONNECT 403 from this container — so the fixture battery is the evidence, with the artifact names as the roster reading.Cause of the cancellations is #16173 (shard duration straddling the 30-minute job timeout; parallel card, not a prerequisite). After this PR lands, each such cancellation is a red
Test Coreinstead of a silent pass — a queue entry ejected rather than merged untested — until #16173's timings refresh removes the timeouts. That is the accepted cost of the ruling.Self-test battery
#3668 lifecycle: cancelled passes without counting(2 cases, one of them the overturned pin) → renamed#3668 lifecycle: a superseded matrix (cancelled, zero attestations) passes without counting(3 cases: zero-credential pass, itsexpected attestations: 0log line verbatim, itsnone claimed toverdict line).#16157 partial cancellation: attested shards make the roster REQUIRED(14 cases): (a) cancelled + 1 of 3 ⇒ red naming both missing shards, the attested sibling, and [finding] A single cancelled shard makes the requiredTest Corecheck green over untested packages — the attestation gate zeroes the whole roster oncancelled#16157; theREQUIREDlog line; noexpected attestations: 0line; (b) the measured 6-shard shape, shard 2 killed, five attested ⇒ red naming exactlytest-2-of-6; (c) cancelled + 0 of 6 ⇒ green (the CI: Dogfood Regression Gate 把 cancelled 当失败 —— 每次连续推送都产生一条假红 #3668 boundary); (d) cancelled + 6 of 6 ⇒ green as a COUNTED 6/6 verdict; (e)failureover two attested ⇒ red on its own declared-negative veto (dominance unchanged); (f) [finding] check-shard-attestation.mjs is attempt-blind — after a filter death, rerun-failed-jobs can NEVER converge: prior-attempt attestations poison every later attempt of the same run #11998 interplay: attempt 2 cancelled with six carried-over attempt-1 credentials ⇒ green, with five ⇒ red naming the sixth; (g) a red partial cancellation prints nosatisfiedline.SELF_TEST_BATTERY_FLOOR15 → 16; assertions 129 → 144.Ablation (at
b79626679, committed first; restore by blob hash)Mutation: the new guard
if (attested.length === 0)rewritten to an always-true comparison (attested.lengthat-or-above 0), which restores the pre-PR short-circuit exactly. On-disk proof before/after: marker count 0 → 1, original count 1 → 0, working blob9aba2c8e…→191edd2c….The 4 cases of the new battery that stay green under ablation are the unchanged directions (zero-attestation pass, 6/6 pass,
failuredominance, six carried-over credentials) — as intended.--verifyunder ablation exits 0 over five downloaded credentials and printsnone claimed to: the self-contradicting transcript the card quoted. With the change (same fixture): exit 1,::error::Test Core: 1 of 6 declared shard(s) of test published no positive attestation (test-2-of-6) while 5 sibling(s) did (test-1-of-6, test-3-of-6, test-4-of-6, test-5-of-6, test-6-of-6). The leg was cancelled mid-run, so the missing shard(s) produced no verdict at all — an untested shard is not a passing shard, see #16157.No
dist/is involved (the gate runsscripts/source directly under node), so no preflight beyond the on-disk grep counts applies.Gates (all at
b79626679, each exit code captured by redirect, not through a pipe)node scripts/pm/dispatch-gates.mjs --changed --repo objectstack-ai/objectstack --ran …→✓ dispatch-gates --ran: 31 derived famil(ies) accounted for — 31 run, 0 NOT-MEASURED.All 31 exit 0, includingpnpm check:shard-attestation(✓ check-shard-attestation --self-test: 144 assertions …+✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).),node scripts/check-self-test-wired.mjs(+--self-test),pnpm check:nul-bytes,pnpm check:pm-dispatch-gates,pnpm check:cross-package-test-inputs.pnpm check:required-contexts(named by the dispatch; imports this script) → exit 0:✓ check-required-contexts --self-test: 153 assertions …/✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s) ….eslint --no-inline-config scripts/check-shard-attestation.mjs→ exit 0. The repo-widepnpm lintis CI's run; not narrowed here beyond the one changed file (type-aware linting is not enabled ineslint.config.mjs, so this diff moves no other file's verdict).scripts/tooling, nothing published from any package;skip-changesetapplied.Out of scope, noted for the reviewer
skipped-while-filter-cancelledbranch (see the derived-judgments note).aggregate result: abandoned判成红 —— 在队 PR 零测试失败被踢出(ci.yml 两处白名单缺abandoned) #6082, [finding] check-shard-attestation.mjs is attempt-blind — after a filter death, rerun-failed-jobs can NEVER converge: prior-attempt attestations poison every later attempt of the same run #11998,filterjob 一旦失败,Test Core / Build Core / Dogfood 会全部 skipped 而分支保护判为通过 —— 隐式 success() 今天已第三次咬人 #4928 remain in force and are cited, not modified.Generated by Claude Code