Skip to content

test(devx): sweep the shrink-only ratchet self-tests for baseline-presence pins — 33 derived, 1 repaired - #12050

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-11694-selftest-present-ratchet-class
Aug 25, 2026
Merged

test(devx): sweep the shrink-only ratchet self-tests for baseline-presence pins — 33 derived, 1 repaired#12050
yinlianghui merged 2 commits into
mainfrom
claude/issue-11694-selftest-present-ratchet-class

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#11694

A shrink-only ratchet exists to be driven to zero. If its self-test pins the current
baseline entries as present — rather than a property of the gate that survives their
removal — the last commit of the burn-down turns the gate's own self-test red, and the
ledger becomes un-burnable by construction. #11692 repaired one instance; this is the
class sweep.

Result: population of 33 derived, 1 defect found and repaired, 32 unchanged.
Files changed: scripts/check-driver-memory-census.mjs — and nothing else.

1. The population, derived (not taken from the card's candidate list)

Both the card and its first comment say the candidate list is a lead. It was: none of
the six named candidates carries the shape
, and the one gate that does is not on the
list.

Definition used — a scripts/** gate that (a) enforces a baseline the project may only
shrink (a roster of entries, or per-file numeric ceilings), and (b) ships a selfTest().

Reproducible, in three passes:

# (a) every scripts/ gate shipping a self-test — the outer bound
grep -rlE '^(export )?(async )?function selfTest ?\(' scripts --include=*.mjs --include=*.mts | wc -l
# → 133
# (b) of those, the ones whose SELF-TEST reads the real ledger/baseline (the only ones
# that CAN carry the shape — a fixture-driven self-test cannot; discriminator 1)
# grep the selfTest() body of each for: loadLedger|readLedger|loadBaseline|
# readBaseline|loadCensus|readCensus|loadDebt|readDebt|readRoster|loadRoster
# → 4: check-cli-test-child-env.mjs (readBaseline, l.865)
# check-driver-memory-census.mjs (loadLedger, l.660)
# check-optional-error-sink-contract.mjs (loadBaseline, l.1053)
# check-test-typecheck.mts (loadLedger, l.516 — in main(), NOT in selfTest)
# (c) the in-file arm: gates whose ledger is a module constant rather than a JSON file,
# scanned for assertions over that constant inside selfTest()
# → the 29 roster/JSON candidates below, plus 4 numeric/registry ratchets the roster
# regex missed (skills-token, pm skill-line, error-code-casing, i18n-coverage)

Derivation of the gate families at the final commit, as required:

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
dispatch-gates: gate list derived from the tree of 'objectstack-ai/objectstack' at commit 650639399
--repo 'objectstack-ai/objectstack' checked against this checkout's 'origin' remote — it holds.
change set derived from git — 1 path(s) vs merge base 1e79aa4f8

2. Per-item verdict — all 33

SURVIVES = the self-test's assertions still hold with the baseline emptied. Before ==
after for every row except row 6.

#gatebaselineverdict
1check-adr-0087-registration.mjsADR-0087 registriesSURVIVES — registry-vocabulary pins; LEDGER_SOURCES are fixture paths
2check-adr-anchors.mjsKNOWN_NUMBER_COLLISIONSSURVIVES — ablation asserts red.length === numbers.length; reduces to 0 === 0
3check-adr-links.mjsKNOWN_DEAD_TARGETSSURVIVES — staleEntries.length === 0; [].filter() is 0
4check-auth-mount-ledger.mjsPENDING_DISPOSITIONSURVIVES — every use is a fixture array
5check-cli-test-child-env.mjscli-test-child-env.baseline.jsonSURVIVES — the instance, repaired in #11692; re-verified here
6check-driver-memory-census.mjsdriver-memory-census.ledger.jsonDEFECT → REPAIRED (§3)
7check-driver-conformance.mjsLEDGERSURVIVES — fixture-driven
8check-durability-degradation-log-level.mjs2 baselinesSURVIVES — fixture-only self-test
9check-engine-double-contract.mjsengine-double-contract.baseline.jsonSURVIVES — fixture-only self-test
10check-entry-guard.mjsKNOWN_IMPORT_UNSAFESURVIVES — asserts NON-membership
11check-error-code-casing.mjsshrink-only code registrySURVIVES — self-test drives a fixture, by its own header
12check-error-status-conformance.mjserror-status-unpinned-baseline.jsonSURVIVES — PRE_8963_* are frozen historical snapshots, not the ledger
13check-i18n-coverage.mjsi18n-coverage-baseline.jsonSURVIVES — fixture/probe; ships an explicit emptyPopulationVerdict
14check-optional-error-sink-contract.mjsoptional-error-sink-contract.baseline.jsonSURVIVES — entry-shape loop; zero iterations at empty
15check-plugin-teardown-shape.mjsKNOWN_TEARDOWN_UNREACHEDSURVIVES — fresh/stale === 0; positive control is a git-pinned revision
16check-published-readme-exports.mjspublished-readme-exports.baseline.jsonSURVIVES — fixture-only
17check-query-options-erasure-ratchet.mjsquery-options-erasure-baseline.jsonSURVIVES — fixture-only
18check-ratchet-remedy-authority.mjsCONTROL registrySURVIVES — a positive-control roster, not burnable debt. Rule untouched (#11935)
19check-release-section-coverage.mjsPRE_10232_*SURVIVES — frozen snapshots used as positive controls
20check-role-word.mjsrole-word-baseline.jsonSURVIVES — its own summary already states "the same result once the ledger is empty"
21check-settings-bind-window.mjsKNOWN_PRE_BIND_READS ([])SURVIVES — auditSource(code, ledger = []). Spot-checked, §5
22check-skill-compatibility-version.mjsEXEMPTSURVIVES — passed into fixtures
23check-skills-token-ratchet.mjsCEILINGSSURVIVES — a ceiling map burns by lowering numbers, not by losing keys
24check-startup-registry-verdict.mjsstartup-registry-verdict.baseline.jsonSURVIVES — fixture-only
25check-test-source-alias.mjsKNOWN_UNALIASED_TEST_IMPORTSSURVIVES — self-test asserts nothing about entry presence
26check-test-typecheck.mtstest-typecheck-debt.jsonSURVIVES — the loadLedger() call is in main(), not in selfTest()
27check-type-check-coverage.mjs5 ledgersSURVIVES — every self-test use is a fixture ledger literal
28check-type-source-resolution.mjsKNOWN_DIST_RESOLVED_TYPE_IMPORTSSURVIVES — as row 25
29check-where-matcher-conformance.mjswhere-matcher-conformance.baseline.jsonSURVIVES — fixture-only
30pm/dispatch-gates.mjsESCAPABLE_LITERAL_LEDGER (empty)SURVIVES — the model of the repaired form: a witness pair keeps the positive half exercised at zero rows
31pm/check-skill-line-ratchet.mjsCEILINGSSURVIVES — as row 23
32check-slot-lookup-ratchet.mjsslot-lookup-baseline.jsonNO self-test — outside the repair surface. Recorded as an observation (§6). Rule untouched (#11681)
33regen-artifacts.mjs3 baselinesNO self-test — a generator, not a gate

Zone-1 constraint honoured: rows 18, 13 and 32 are the gates whose rules#11935 / #11671 /
#11681 claim. None of them carries this shape, so not one byte of any of those three
gates changed
.

3. The one repair — scripts/check-driver-memory-census.mjs

Before:

expect('the ledger rules exactly the consumers #5704/#6664 named',(realLedger.ruledConsumers??[]).length===2);

The gate's own LIVE invariant says "a migrated consumer must lose its entry in the same
PR, or the ledger becomes the next stale census"
. That deletion is exactly what #5499's
frozen-driver retirement programme exists to produce — and this equality makes it
impossible: obey LIVE, and the self-test reds with a message reading "the ledger lost
an entry it must have"
when the entry was correctly deleted.

After: the claim the pin was actually protecting — no third consumer may be waved into
ruled-permanent under a marker of this programme's invention — which survives the set
shrinking to empty. validateLedgerShape already requires somerulingMarker; it did
not require the ruling to be one this programme issued.

constRULING_ISSUES=['#5704','#6664'];constadmittedByARuling=(e)=>(e.rulingMarkers??[]).some((m)=>RULING_ISSUES.includes(m));construled=realLedger.ruledConsumers??[];// witness pair — `[].every(...)` is a pass that proves nothing, so the synthetic row keeps// the positive half exercised at zero rows and the negative witness gives it teeth there.expect('every ruled consumer is admitted by one of this programme\'s two rulings',[...ruled,WITNESS_RULED].every(admittedByARuling));expect('…and that rule can FAIL: a marker neither ruling issued does not admit a consumer',!admittedByARuling(WITNESS_UNRULED));expect('the ruled set never grows past what those rulings named (2 arm(s); it may shrink to empty)',ruled.length<=RULED_CEILING);

The anti-growth half the equality was also doing is kept as RULED_CEILING, a
shrink-only ceiling: lowered by any PR that migrates an arm away, raised only by a new
maintainer ruling. The witness-pair idiom is taken from ESCAPABLE_LITERAL_LEDGER in
scripts/pm/dispatch-gates.mjs, which already solved this at zero rows.

No rule changed. No assertion deleted. No exclusion added. The gate's production verdict is
byte-identical.

4. Reverse verification — three legs, each mutation confirmed on disk, restore on a trap

legmutation (confirmed on disk)before repairafter repair
AruledConsumers 2 → 1 — the shrink the programme exists to performEXIT 1x self-test: the ledger rules exactly the consumers #5704/#6664 namedEXIT 0, 0 failure lines
BruledConsumers 2 → 3 (third arm pointing at a file the scan really binds, so only the ceiling can fire)EXIT 1x self-test: the ruled set never grows past what those rulings named (2 arm(s); it may shrink to empty)
Centry's rulingMarkers['#0']EXIT 1x self-test: every ruled consumer is admitted by one of this programme's two rulings

Leg A is the defect, measured on the unrepaired file. Legs B and C are the pin still
discriminating: it is not a pin that only ever answers "pass". Every leg printed
MUTATION CONFIRMED ON DISK from a ruledConsumers length / marker read before its
reading was taken, and the ledger was restored and re-read after each (git status clean).

5. Premise checks against origin/main

  • The card's "most urgent candidate" is falsified — as its own first comment already
    said, and it has not drifted since.
    check-settings-bind-window.mjs line 162 is
    const KNOWN_PRE_BIND_READS = [];, auditSource = (code, ledger = []), and both runs are
    green: ✓ settings bind-window guard self-test: all cases pass. /
    ✓ settings bind-window: 4 declared / 0 self / 1 structurally upstream / 0 ledgered (68 plugin unit(s) scanned…).
  • The other five named candidates are clean too — rows 18, 27, 17, 32, 13 above.
  • Discriminator 1 is the whole sweep. Of 133 self-tests in scripts/, only 3 read the
    real baseline from inside selfTest(). Everything else defaults its fixture ledger, so
    the empty path was never cold and the shape cannot be acquired.
  • Zone-3 secondary check (an empty ledger must not read as an empty population): no
    instance found.
    Every ratchet whose ledger is already empty still reports its scanned
    population — check-settings-bind-window68 plugin unit(s),
    check-where-matcher-conformance298 matcher(s) discovered … 0 grandfathered file(s),
    check-entry-guard157 scripts/ file(s) … 2 known-unsafe.

6. Out of scope — recorded, deliberately not touched

  • The shape's habitat is not confined to scripts/ — reported, deliberately not swept.
    packages/spec/scripts/ and packages/lint/scripts/ carry shrink-only ratchets of their
    own (check-dual-source-exports.ts, check-exported-any.ts, check-liveness.mts,
    check-doc-formula-expressions.mjs), and two carry test twins under packages/**
    rather than a --self-test (check-generated-ledger.test.ts,
    check-react-blocks-declaration-parity.test.ts). One of those twins pins bucket counts as
    exactly 1 (expect(output).toContain('1 explicit manual-only generators')) — the same
    species. Widening the sweep is the PM's call, so it is measured here and not touched.
  • scripts/check-slot-lookup-ratchet.mjs is a shrink-only ratchet with no self-test at
    all
    , and its check:slot-lookup wiring invokes none. check-self-test-wired.mjs
    enforces only the superset ("a script that ships one must run it"), so this is invisible
    to it.

Verification

All at 650639399. Exit codes captured before any pipe; each line below is the gate's own
verdict.

gateexitverdict
check:driver-memory-census0check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled file states "#6664 census: 2 ruled consumers".
check:agent-test-spelling0green
check:cross-package-test-inputs0All 109 self-test cases passed. OK: 16 package(s) read outside themselves, all declared…
check:entry-guard0✓ check:entry-guard: 157 scripts/ file(s) … 2 known-unsafe, ⛔ SHRINK-ONLY
check:parse-guard0green
check:pnpm-filter-targets0✓ check:pnpm-filter-targets: 135/168 --filter occurrence(s) across 26 file(s)…
scripts/check-ci-filter-parity.mjs0OK: all 96 declared cross-package glob(s) (81 unique) are covered…
scripts/check-cross-package-test-inputs.mjs0OK: 16 package(s) read outside themselves, all declared…
check:nul-bytes0check-nul-bytes: OK (scanned 6672 text file(s) … no raw ASCII control bytes)
check:pm-dispatch-gates0✓ dispatch-gates self-test: 579 cases pass.
check:where-matcher0✓ where-matcher conformance holds: 298 matcher(s) discovered…

The last two are not in the derived list: dispatch-gates --residue flags them as the two
artifact-roster gates whose roster sits under scripts/, where a silent verdict "is not
evidence in EITHER direction". Run rather than assumed.

Repo-wide lint, not narrowed:eslint . --no-inline-config --format jsonEXIT 0,
5066 files linted, 0 errors, 0 warnings
— run under the shared verify lock, not narrowed
and not skipped.

No changeset: this is root scripts/ gate tooling and publishes nothing. skip-changeset
applied.


Generated by Claude Code

… on its ledger's size
The self-test asserted `ruledConsumers.length === 2`. That holds only while both
ruled arms are still ledgered, so the gate's own LIVE invariant — "a migrated
consumer must lose its entry in the same PR" — could not be obeyed without
turning the self-test red, and red with a message reading "the ledger lost an
entry it must have" when the entry was correctly deleted. #5499/#5704 exist to
shrink that set; an equality on its size made it un-burnable by construction.
Re-spelled as the claim the pin was actually protecting, which survives the set
shrinking to empty: every ruled consumer is admitted by one of the two rulings
this programme issued (#5704 Q2 / #6664 A), carried on a witness pair so the
positive half stays exercised at zero rows; plus a shrink-only CEILING for the
anti-growth half that the equality was also doing.
Measured: shrinking the ledger by one entry was EXIT 1 before, EXIT 0 after;
growth past the ceiling and a marker neither ruling issued both still red.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6
`#9999` reads as a real issue reference to the next author, and quoting it in a
PR body cross-references an unrelated card. `#0` is what this repo's other gate
fixtures already use for a marker that names nothing on purpose.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6
@yinlianghuiyinlianghui added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 25, 2026 — with Claude
@yinlianghui
yinlianghui marked this pull request as ready for review August 25, 2026 07:09
@yinlianghui
yinlianghui added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit 7f6dc4cAug 25, 2026
32 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-11694-selftest-present-ratchet-class branch August 25, 2026 07:29
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@yinlianghui@claude