Uh oh!
There was an error while loading. Please reload this page.
feat(tooling): gate the swallow-census control families the repair programme cannot destroy (#13919) - #14413
Merged
baozhoutao merged 3 commits intoSep 2, 2026
Conversation
…me cannot destroy (#13919) `scripts/measure-durability-swallow-family.mjs` declares four control families and, measured on `origin/main`, nothing ran any of them: zero references to the script in `package.json` or `.github/**`, counter-checked against `measure-stall-guard-headroom` (2 hits) so the zero was a reading and not a broken query. Meanwhile the resolver those controls pin was repaired three times with no gate holding any previous repair, and the census's numbers feed the #12981 repair worklist, so a wrong denominator propagates unwatched. Adds one lightweight mode selector, `--self-test=gated`, wired as `check:swallow-census-controls` from `lint.yml` beside the sanctioned precedent `check:stall-guard-headroom`. The gated run asserts RESOLUTION + NEGATIVE + REGRESSION plus the zero-member floor -- the families a successful repair cannot destroy, because a repair moves a member from tier `dark` to tier `channelled` and it stays a member. POSITIVE_CONTROLS stays manual, permanently. It pins tier-1 DARK members of the worklist the repair programme exists to remove; the file's own record shows batch 2 already turning this self-test red for doing exactly what the ruling asked. A gate that reddens on success is not a gate. Bare `--self-test` is byte-identical (`--self-test=all` is its spelling), and an unknown mode is REFUSED with exit 2 rather than falling through to the census, which would exit 0 and read in a CI log like a self-test that passed.
…13919) Wiring `check:swallow-census-controls` makes the census's SCAN_ROOT visible to the bare-root sweep as a FRESH, unjudged row. REFUSE-WIDE, measured on this tree: the walk admits every non-test TypeScript source under `packages` (2193 of 5755, 38%), the same class and nearly the same ratio as check:authz-resolver, so a bare-root declaration would be TRUE and is refused for width alone.
…onest (#13919) Wiring `check:swallow-census-controls` turns `measure-durability-swallow-family.mjs` into a GATE SCRIPT, so the convention KIND now hits it and it can no longer serve as the card where the block harvest and `--commands` must agree exactly. Repointed at `measure-partial-retirement-annotation.mjs` — the shape the census copied, which no check family runs. Also classifies the new `selfTestMode` argv parser in COMPOUND_ANCHOR_LEDGER as accidental, rather than renaming it to dodge the anchor.
baozhoutao
marked this pull request as ready for review
September 2, 2026 05:34
baozhoutao
enabled auto-merge
September 2, 2026 05:34
Uh oh!
There was an error while loading. Please reload this page.
baozhoutao
deleted the
claude/issue-13919-swallow-census-gated-controls
branch
September 2, 2026 05:58
This was referenced Sep 2, 2026
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 freeto 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#13919
The #12981 census (
scripts/measure-durability-swallow-family.mjs) declares fourcontrol families and, measured on
origin/main, nothing ran any of them — zeroreferences to the script anywhere in
package.jsonor.github/**, counter-checkedagainst a control that must return non-zero (
measure-stall-guard-headroom, 2 hits) sothe zero was a reading and not a broken query. Meanwhile the resolver those controls pin
was repaired three times (#13459, #13474, PR #13915), each time with no gate holding the
previous repair, and the census's numbers feed #12981's repair worklist — so a wrong
denominator propagates into that programme with nobody watching.
The ruling this implements (verbatim, unchanged — comment 5494601066, maintainer 2026-09-01 「同意」)
What landed
One mode selector, no duplicated reporting.
selfTestMode(argv)reads the mode;selfTest(mode)takes onegated ? [] : POSITIVE_CONTROLSon the loop it must skip, oneextra success-print branch, and one refusal branch. The problem list, the failure
formatter, the census call and the other three family loops are the same code on both
paths. Implementation cost against ruling item 3, bullet 3: the stop condition was not
reached — the split needed no duplication of the self-test's reporting logic.
--self-test=gatedrunsRESOLUTION+NEGATIVE+REGRESSION, plus thezero-member floor. Wired as root
check:swallow-census-controlsand run fromlint.ymlbeside the sanctioned precedentcheck:stall-guard-headroom— the sameshape and the same asymmetry: the self-test leg only, never a bare invocation.
--self-testis byte-identical (proof below);--self-test=allis itsspelling. Print semantics of the bare legs are deliberately untouched — that surface
belongs to [finding] the #12981 census prints 5 DARK sites as "the repair worklist" when 4 are settled determinations — an annotation cannot move a site out of the bucket #13886, see the serial note.
--self-test=gatdwould missargv.includes('--self-test'), reachreport(), exit 0and read in a CI log exactly like a self-test that passed.
banner line, now a single constant shared with
report()rather than a second copy.Why POSITIVE stays out, in the file's own terms rather than restated:
SELF_TEST_MODESpoints at the
darkcontrol's recordedwhy, where batch 2 already turned thisself-test red for doing exactly what the ruling asked. The exclusion is written as
permanent, not pending — repairs move a member from tier
darkto tierchannelledand it stays a member, so none of the three wired families can be destroyed by a
successful repair.
⛔
DURABILITY_CRITICAL_CALLEESis untouched, no entry was added todurability-degradation.baseline.json, and the gate vocabulary is unchanged in eitherdirection (ruling item 3, bullet 2 — this PR must not be used to bring that step forward).
Readings
All on
93aecd5cf(the implementation commit; the two follow-ups touch only PM tooling). Every mutation confirmed on disk before the reading was taken(injected marker counted and deleted text counted), every restore proved by hashing
the path against its HEAD blob, each harness carrying
trap restore EXIT INT TERMwithabsolute paths.
--self-test=gatedon this branch3 negative control(s) yield none, 2 regression control(s) stay clear, 6 resolution control(s) resolve as declared, 56 member site(s) total--self-test--self-test=gatdx REFUSED: unknown self-test modeBare-output identity, measured not asserted. The base blob (
e2a7fa5b8) was checkedout over the path, confirmed on disk by hash, run, and restored to the HEAD blob
(
71f3ae1e5, verified).cmpon the two captures: identical.Ablation A — the RESOLUTION family, on the defect it exists for. Reverted
indexFunctionBodies().getto the flat last-wins lookup (marker present 1, anchorconsumed).
--self-test=gated→ exit 1, four resolution controls firing:Bare
--self-test→ exit 1 on the same tree. ⇒ the wired leg carries a real failuresignal into CI.
Ablation C — the hazard the ruling excluded POSITIVE for, reproduced. Simulated a
successful repair of the
darkpositive control's site by givingshare-link-service.ts :: resolveToken's telemetry catch aconsole.error(markerpresent 1, original comment text consumed):
--self-testpositive control found NO member: packages/plugins/plugin-sharing/src/share-link-service.ts--self-test=gated56members becomes55, and the gate stays green⇒ this is the ruling's boundary 1 as a measurement: the full self-test reddens when the
repair programme succeeds, and the wired subset does not.
Ablation B — reported as a NULL result rather than dropped. Removing the #13459
bare-identifier refusal from the lexical walk landed on disk — marker 1, the deleted
return null;gone — and moved nothing:--jsonbefore and after is equal in everystat (
files2193,guardedWrites221,refusedShadowed4, 56 members, empty symmetricdifference on the member set). The site the
action-executionregression control pins isanswered a second time by the scope-aware body index, which refuses it too. So the two
departures are defence-in-depth there, and this ablation proves nothing about the
REGRESSION family in either direction. It is recorded because a discarded null ablation is
how a "we exercised that family" claim gets minted from a reading that never happened;
Ablation A is the failure proof.
Two things the wiring forced, both found by running the derived gates
Neither is scope creep: both are consequences of this card's own change, each caught by a
gate on this PR's derived list, and each landed with the repair the gate's own remedy text
names rather than the one that quiets it.
1.
scripts/pm/dispatch-gates.mjs— the seam card is now a GATE SCRIPT. Its--self-testwent red in three cases. Wiringcheck:swallow-census-controlsmakesmeasure-durability-swallow-family.mjsa file some discovered check family runs, so the"adds or edits a GATE SCRIPT" convention KIND started hitting it — and that card is the
fixture chosen for the one assertion pair that needs the block harvest and
--commandstoagree exactly, i.e. a card no convention KIND hits. Repointed at
measure-partial-retirement-annotation.mjs(block 13, commands 13, convention 0, fournoderows — measured), which is the very shape the census copied and which no checkfamily runs. ⛔ Not repaired by loosening the equality; the comment says so at the
constant. The third case is
COMPOUND_ANCHOR_LEDGER: the newselfTestModeargv parsermatches the compound self-test name anchor and is classified
accidental: true, which iswhat that ledger's own "Maintaining this table" section prescribes — ⛔ explicitly not by
renaming the function to dodge the anchor.
2.
scripts/pm/bare-root-worklist.mjs— a FRESH bare-root row. Wiring the familymakes the census's
SCAN_ROOTvisible toscripts/pm/bare-root-worklist.mjsas a FRESH, unjudged row, and its
--self-testreds until a verdict is recorded (it did,on the first sweep). Recorded REFUSE-WIDE, measured on this tree in both terms and not
carried from a sibling row: the walk admits every non-test, non-declaration TypeScript
source under the root at four extensions — 2193 of 5755 (38%), numerator from the
instrument's own printed scan count, denominator from
git ls-files packages. Same classand nearly the same ratio as the
check:authz-resolverrow: a bare-root declaration wouldbe TRUE and is refused for width alone.
No changeset —
skip-changesetThis diff publishes nothing from any package: a root
check:*alias, alint.ymlstep, arepo-root
measure-*script, and a PM worklist verdict. The precedent is exact —0079e2585(#13358), which wired this same family's precedent and touched precisely.github/workflows/lint.yml+package.json+scripts/measure-stall-guard-headroom.mjs,carried no changeset. An empty-frontmatter changeset is not the alternative:
scripts/check-empty-changeset.mjsrejects one, and its header records why (an emptychangeset is a real input to
changesets/actionand can stall a release, which the labelcannot). The label is applied on this PR.
Serial note — #13886 is next on this file
#13886 (same file, print semantics of the DARK worklist) is queued behind this card
(triage 2026-09-01, comment 5486764050) and is deliberately not folded in. That is also
why the bare self-test legs' output is left byte-identical here: changing print semantics
is that card's surface, not this one's. #13886 is not addressed by this PR and remains
open.
Gate record
Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsfrom the real change set (three-dot against merge base
e80889095; the tool takes thechange set from git itself, no hand-written path list). Re-derived after each of the two
follow-up commits — the union stayed at 37 families throughout. All 37 were run, and
the union was re-run on the final commit
990649a77:check:swallow-census-controlsitself,check:pm-dispatch-gates(✓ dispatch-gates self-test: 1232 cases pass.),check:self-test-wiredandcheck:self-test-workflow-commands— the two the new stepnewly puts this script into the population of — plus
check:declared-population-live,check:ratchet-remedy-authority,check:watch-hint-literal,check:entry-guard,check:parse-guardandnode scripts/pm/bare-root-worklist.mjs --self-test(OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) — none stale, none missing, none contradicted.).line:
check-test-completeness.mjs("The log comes from a test RUN. This gate does notrun tests and cannot produce one... the local reading for this gate is NOT MEASURED"),
check:dual-build-cjs-loadsandcheck:type-check-debt("PREREQUISITE NOT MET... ⛔This is NOT a pass and NOT a finding: nothing was measured"). Structural — they need a
built workspace or a real test-run log, which CI has and a local sweep does not.
scripts/pm/bare-root-worklist.mjs --self-test(FRESH row) andcheck:pm-dispatch-gates(3 of 1232 cases). Both green on the final commit.Exit codes were captured before any pipe (
cmd > log 2>&1; rc=$?), never through one, andevery verdict quoted here is the gate's own printed line rather than a bare
$?.Generated by Claude Code