Skip to content

Commit b796266

Browse files
committed
fix(ci): a cancelled Test Core leg with partial attestations counts its 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
1 parent 1ca95df commit b796266

1 file changed

Lines changed: 136 additions & 21 deletions

File tree

scripts/check-shard-attestation.mjs

Lines changed: 136 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,24 @@
6666
*
6767
* ## What is deliberately NOT changed
6868
*
69-
* - `cancelled` still passes without counting (#3668). Cancellation is a
70-
* run-lifecycle state: with cancel-in-progress on, every superseded push
71-
* cancels the in-flight matrix, and #3668 measured (run 30271824408) that a
72-
* real shard failure DOMINATES the aggregate over a cancelled sibling — it
73-
* reads `failure`, never `cancelled`. So `cancelled` masks no regression,
74-
* and demanding credentials there would paint the false red on the
75-
* superseded SHA that #3668 removed.
69+
* - `cancelled` with ZERO attestations still passes without counting
70+
* (#3668). Cancellation is a run-lifecycle state: with cancel-in-progress
71+
* on, every superseded push cancels the in-flight matrix, and #3668
72+
* measured (run 30271824408) that a real shard failure DOMINATES the
73+
* aggregate over a cancelled sibling — it reads `failure`, never
74+
* `cancelled`. So a superseded matrix masks no regression, and demanding
75+
* credentials there would paint the false red on the superseded SHA that
76+
* #3668 removed.
77+
* ⛔ That argument covers a shard that RAN AND FAILED. It does not cover a
78+
* shard killed while still executing, which produces no verdict at all —
79+
* there is no `failure` to dominate (#16157, run 34007386254: `Test Core
80+
* (2/6)` cancelled at 35m by its job timeout with the test step still
81+
* `in_progress`, five siblings attested, and the required check went
82+
* green two seconds later over the shard's untested packages). So the
83+
* count splits `cancelled`: with AT LEAST ONE attestation of the leg
84+
* present, the matrix ran, the declared roster is knowable, and it is
85+
* REQUIRED — every missing shard is named and the gate is red. Only the
86+
* zero-attestation shape keeps the pass; `judge()` carries both.
7687
* - `skipped` still passes ONLY when the `filter` job itself succeeded
7788
* (#4928). `skipped` alone cannot separate "the path filter said no core
7889
* paths changed" from "the path filter exploded and took every downstream
@@ -299,12 +310,31 @@ export function judge({ gate, legs, filterResult, present, runId, runAttempt, do
299310
log.push(` leg ${label} — aggregate result: ${leg.result}`);
300311

301312
if (leg.result === 'cancelled') {
302-
// #3668: a run-lifecycle state, not a shard verdict. Legs that finished
303-
// before the cancellation may legitimately have attested, so their
304-
// credentials are ALLOWED but none are REQUIRED.
313+
// A run-lifecycle state, not a shard verdict — and it arrives in two
314+
// shapes that the count tells apart (#16157):
315+
//
316+
// - ZERO shards of the leg attested: the whole matrix was superseded
317+
// (cancel-in-progress on a newer push, #3668). No shard produced a
318+
// verdict, the SHA is dead, and demanding credentials would paint
319+
// the false red #3668 removed. Passes without counting.
320+
// - AT LEAST ONE shard attested: the matrix RAN. A sibling that still
321+
// reads `cancelled` was killed mid-suite and produced no verdict, so
322+
// no `failure` exists to dominate the aggregate (run 34007386254:
323+
// shard 2/6 cancelled by its job timeout with the test step
324+
// `in_progress`, five siblings attested). The declared roster is
325+
// knowable from the shards that did attest, so it is REQUIRED —
326+
// the leg falls through to the count below, every missing shard is
327+
// named, and the required check goes red.
305328
for (const id of roster) allowed.add(id);
306-
log.push(` satisfied (cancelled — run-lifecycle state, #3668; expected attestations: 0)`);
307-
continue;
329+
const attested = roster.filter((id) => present.has(id));
330+
if (attested.length === 0) {
331+
log.push(` satisfied (cancelled — run-lifecycle state, #3668; expected attestations: 0)`);
332+
continue;
333+
}
334+
log.push(
335+
` cancelled AFTER ${attested.length} of ${roster.length} declared shard(s) attested — not a superseded matrix; ` +
336+
`the roster is REQUIRED and every missing shard is named (#16157)`,
337+
);
308338
}
309339

310340
if (leg.result === 'skipped') {
@@ -339,8 +369,13 @@ export function judge({ gate, legs, filterResult, present, runId, runAttempt, do
339369
counted += roster.length;
340370
if (missing.length > 0) {
341371
errors.push(
342-
`${gate}: ${missing.length} of ${roster.length} declared shard(s) of ${leg.job} published no positive attestation ` +
343-
`(${missing.join(', ')}). A shard that never ran cannot be counted as passing — see #6082.`,
372+
leg.result === 'cancelled'
373+
? `${gate}: ${missing.length} of ${roster.length} declared shard(s) of ${leg.job} published no positive attestation ` +
374+
`(${missing.join(', ')}) while ${roster.length - missing.length} sibling(s) did ` +
375+
`(${roster.filter((id) => present.has(id)).join(', ')}). The leg was cancelled mid-run, so the missing ` +
376+
`shard(s) produced no verdict at all — an untested shard is not a passing shard, see #16157.`
377+
: `${gate}: ${missing.length} of ${roster.length} declared shard(s) of ${leg.job} published no positive attestation ` +
378+
`(${missing.join(', ')}). A shard that never ran cannot be counted as passing — see #6082.`,
344379
);
345380
}
346381
if (leg.result === 'failure') {
@@ -933,7 +968,8 @@ const SELF_TEST_BATTERIES = Object.freeze({
933968
'(iii) N-1 positives + one explicit failure ⇒ red': 4,
934969
'(iv) filter-skipped family ⇒ green with expected-N adjusted to 0': 1,
935970
'the #4928 guard itself must not regress': 8,
936-
'#3668 lifecycle: cancelled passes without counting': 2,
971+
'#3668 lifecycle: a superseded matrix (cancelled, zero attestations) passes without counting': 3,
972+
'#16157 partial cancellation: attested shards make the roster REQUIRED': 14,
937973
'dogfood-gate: a matrix leg and a single leg under one context': 5,
938974
'foreign / stale credentials': 3,
939975
'#11998: attempt scoping, in both directions': 26,
@@ -947,7 +983,7 @@ const SELF_TEST_BATTERIES = Object.freeze({
947983

948984
// DELETING an entry silences that battery's floor exactly as effectively as
949985
// zeroing it, so the roster's own size is pinned too.
950-
const SELF_TEST_BATTERY_FLOOR = 15;
986+
const SELF_TEST_BATTERY_FLOOR = 16;
951987

952988
// The key an assertion is filed under when no battery is open. It is not a
953989
// declared battery, so it reds by the same set difference rather than silently
@@ -1043,10 +1079,89 @@ async function selfTest() {
10431079
assert(testGate('skipped', [], 'cancelled').ok, '#3668: a cancelled filter still lets a skipped leg pass');
10441080
assert(!testGate('skipped', [attest('test', 1, 3)]).ok, 'a credential from a leg that was reported skipped is a contradiction ⇒ red');
10451081

1046-
// ── #3668 lifecycle: cancelled passes without counting ────────────────────
1047-
battery('#3668 lifecycle: cancelled passes without counting');
1048-
assert(testGate('cancelled', []).ok, '#3668: a cancelled matrix passes with zero credentials (superseded SHA)');
1049-
assert(testGate('cancelled', [attest('test', 1, 3)]).ok, '#3668: a leg that attested before the cancellation is allowed, not required');
1082+
// ── #3668 lifecycle: a superseded matrix passes without counting ──────────
1083+
// The shape #3668 measured: cancel-in-progress killed the whole matrix on a
1084+
// superseded SHA, no shard ran, none attested. That — and only that — is the
1085+
// cancellation the gate passes without counting.
1086+
battery('#3668 lifecycle: a superseded matrix (cancelled, zero attestations) passes without counting');
1087+
const superseded = testGate('cancelled', []);
1088+
assert(superseded.ok, '#3668: a cancelled matrix passes with zero credentials (superseded SHA)');
1089+
assert(
1090+
superseded.log.some((l) => l.includes('#3668') && l.includes('expected attestations: 0')),
1091+
'#3668: the zero-attestation pass still says so in its own log line, verbatim',
1092+
);
1093+
assert(
1094+
superseded.log.some((l) => l.includes('no shard was expected to run, and none claimed to')),
1095+
'#3668: with nothing attested the verdict line may honestly say none claimed to',
1096+
);
1097+
1098+
// ── #16157 partial cancellation: attested shards make the roster REQUIRED ─
1099+
// THE MEASURED SEQUENCE (run 34007386254, PR #16131): `Test Core (2/6)` was
1100+
// cancelled at 35m01s by its job timeout with `Run this shard's tests` still
1101+
// `in_progress`; shards 1, 3, 4, 5 and 6 attested; the aggregate read
1102+
// `cancelled`; and the required `Test Core` context went green two seconds
1103+
// later printing `expected attestations: 0` — while the step above it had
1104+
// just downloaded five credentials. A killed shard produces no verdict, so
1105+
// #3668's "failure dominates" argument has nothing to dominate with. The
1106+
// ruling on #16157 (option A) overturns the pin that used to sit here
1107+
// ("a leg that attested before the cancellation is allowed, not required"):
1108+
// once ANY shard of a cancelled leg attested, the roster is REQUIRED.
1109+
battery('#16157 partial cancellation: attested shards make the roster REQUIRED');
1110+
const partialCancel = testGate('cancelled', [attest('test', 1, 3)]);
1111+
assert(!partialCancel.ok, '#16157: a cancelled leg with 1 of 3 attested ⇒ red (the overturned #3668 pin, inverted)');
1112+
assert(
1113+
partialCancel.errors.some((e) => e.includes('test-2-of-3') && e.includes('test-3-of-3') && e.includes('#16157')),
1114+
'#16157: the error names EVERY missing shard and its issue',
1115+
);
1116+
assert(
1117+
partialCancel.errors.some((e) => e.includes('test-1-of-3') && e.includes('sibling')),
1118+
'#16157: the error also names the sibling(s) that did attest — the reason the roster is knowable',
1119+
);
1120+
assert(
1121+
partialCancel.log.some((l) => l.includes('cancelled AFTER 1 of 3') && l.includes('REQUIRED')),
1122+
'#16157: the log states that the leg fell through to the count and why',
1123+
);
1124+
assert(
1125+
!partialCancel.log.some((l) => l.includes('expected attestations: 0')),
1126+
'#16157: a partially attested leg never prints the zero-expectation line that made the transcript contradict itself',
1127+
);
1128+
// The measured shape itself, on the real 6-shard roster.
1129+
const sixShard = (result, ids, runAttempt = '1') =>
1130+
judge({ gate: 'Test Core', legs: [{ job: 'test', total: 6, result }], filterResult: 'success', present: new Map(ids), runId: '99', runAttempt });
1131+
const fiveOfSix = [1, 3, 4, 5, 6].map((n) => attest('test', n, 6));
1132+
const measuredCancel = sixShard('cancelled', fiveOfSix);
1133+
assert(!measuredCancel.ok, '#16157 measured sequence: shard 2/6 killed mid-run, five siblings attested ⇒ red');
1134+
assert(
1135+
measuredCancel.errors.some((e) => e.includes('1 of 6 declared shard(s)') && e.includes('(test-2-of-6) while 5 sibling(s) did')),
1136+
'#16157 measured sequence: exactly the killed shard is named as missing, none of the five that attested',
1137+
);
1138+
// Both directions of the split: zero attested keeps #3668's pass; a full
1139+
// roster under a late cancellation (a post-step cancelled after every shard
1140+
// attested) is a pass because every shard is accounted for, not because the
1141+
// word `cancelled` waived the count.
1142+
assert(sixShard('cancelled', []).ok, '#16157 boundary: cancelled with ZERO attestations is still the #3668 pass');
1143+
const lateCancel = sixShard('cancelled', [1, 2, 3, 4, 5, 6].map((n) => attest('test', n, 6)));
1144+
assert(lateCancel.ok, '#16157: cancelled with 6 of 6 attested ⇒ green — every shard is accounted for');
1145+
assert(
1146+
lateCancel.log.some((l) => l.includes('all 6 declared shard(s) published a positive attestation')),
1147+
'#16157: that green is a COUNTED verdict (6/6), never "none claimed to"',
1148+
);
1149+
// Orthogonal to the dominance experiment: a real failure is still a declared
1150+
// negative, and it still dominates a cancelled sibling in the aggregate, so
1151+
// the `failure` path is untouched by the split.
1152+
const dominated = testGate('failure', [attest('test', 1, 3), attest('test', 2, 3)]);
1153+
assert(!dominated.ok && dominated.errors.some((e) => e.includes('declared negative')), '#3668 dominance: a real failure over a cancelled sibling still reads `failure` and is red on its own veto');
1154+
// #11998 interplay: attempt scoping is unchanged. Credentials a declared leg
1155+
// accounts for are counted whichever attempt of this run published them.
1156+
const carriedFull = sixShard('cancelled', [1, 2, 3, 4, 5, 6].map((n) => attest('test', n, 6, '99', '1')), '2');
1157+
assert(carriedFull.ok, '#16157 × #11998: attempt 2 cancelled, all six attempt-1 credentials carried over ⇒ green');
1158+
const carriedShort = sixShard('cancelled', [1, 2, 3, 4, 5].map((n) => attest('test', n, 6, '99', '1')), '2');
1159+
assert(!carriedShort.ok && carriedShort.errors.some((e) => e.includes('(test-6-of-6)')), '#16157 × #11998: attempt 2 cancelled with five carried-over credentials ⇒ red naming the sixth');
1160+
// The final verdict line never contradicts the download step above it.
1161+
assert(
1162+
!measuredCancel.log.some((l) => l.includes('none claimed to')) && !measuredCancel.log.some((l) => l.includes('satisfied')),
1163+
'#16157: a red partial cancellation prints no satisfied line at all',
1164+
);
10501165

10511166
// ── dogfood-gate: a matrix leg and a single leg under one context ─────────
10521167
battery('dogfood-gate: a matrix leg and a single leg under one context');
@@ -1497,7 +1612,7 @@ async function selfTest() {
14971612
process.exit(1);
14981613
}
14991614
console.log(
1500-
`✓ check-shard-attestation --self-test: ${checked} assertions (dominance experiment + both #6082 counter-examples + the #4928 guard + the #6589 classifier pins + the #10889 quoting pins + the #11998 attempt-scoping sequence).`,
1615+
`✓ check-shard-attestation --self-test: ${checked} assertions (dominance experiment + both #6082 counter-examples + the #4928 guard + the #6589 classifier pins + the #10889 quoting pins + the #11998 attempt-scoping sequence + the #16157 partial-cancellation split).`,
15011616
);
15021617

15031618
return SELF_TEST_VERDICT;

0 commit comments

Comments
 (0)