Skip to content

test(scripts): instrument check-route-envelope's declared-vs-discovered correspondence - #12080

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-11920-route-envelope-correspondence-instrument
Aug 25, 2026
Merged

test(scripts): instrument check-route-envelope's declared-vs-discovered correspondence#12080
yinlianghui merged 1 commit into
mainfrom
claude/issue-11920-route-envelope-correspondence-instrument

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#11920

Gives check-route-envelope.mjs's declared-vs-discovered correspondence the instrument it had none of — and closes the whole class rather than the one lookup the card measured.

The measurement — the card's scope was one lookup of nine

The card ablated one site (MODULES[file]). The dispatch asked whether the two sibling lookups carried the same defect. They do, and so does every other site that decides this correspondence. Measured on f7b25c546, one ablation per site, each mutation confirmed on disk (anchor 1 to 0, injected marker 0 to 1) before any reading was taken, each restored under a trap with git status clean afterwards:

ablated sitemutationproduction--self-test
MODULES[file] (surface 1, the card's)basename credit0 GREEN0 GREEN
PLUGIN_ROUTE_MODULES[file] (surface 3)basename credit0 GREEN0 GREEN
EXPRESS_RESPONSE_MODULES[file] (surface 4)basename credit0 GREEN0 GREEN
DISPATCHER_DOMAINS[name] (surface 2)prefix credit0 GREEN0 GREEN
discovered.includes(file) (surface 1 reverse)basename credit0 GREEN0 GREEN
honoRoutes.includes(file) (surface 3 reverse)basename credit0 GREEN0 GREEN
expressRoutes.includes(file) (surface 4 reverse)basename credit0 GREEN0 GREEN
MODULES[rel] in discoverHonoRoutes (surface routing)basename credit0 GREEN0 GREEN

Positive control, reproduced — same harness, same gate, a different mutation. Narrowing discover()'s convention so some modules stop being discovered:

production run, clean tree -> exit 1 (RED)
--self-test -> exit 0

So the harness can redden this gate, and the eight double-greens are a property of the rule rather than of a broken probe.

The reverse-direction and surface-routing rows are new: they do not match the const declared = TABLE[file] shape the card and the dispatch both grepped for, and they carry the identical defect.

Why the live run can never see it

Green means the finding set is empty; loosening a correspondence can only shrink that set; the empty set is the fixed point of shrinking. On a clean tree every discovered module already has an exact declaration, so a fallback never fires and the verdict is identical before and after the rule breaks. --self-test supplies the adversarial population a clean tree by construction cannot contain, and is the only instrument this rule has. That is the #11150 family shape.

What changed

Two pure exported functions become the one place the correspondence is decided, and every site above routes through them:

  • declarationFor(table, key) — the declaration a discovered key is credited with, by exact key. Object.hasOwn rather than a bare index read, so a key naming something on Object.prototype answers undefined instead of a truthy inherited function.
  • unfoundDeclarations(table, discovered) — the other direction, by exact key, in the table's own key order.

--self-test then drives them over the population the card names: a route module moved to another package keeping its file name. Under exact equality that is two findings at once — NOT DECLARED for the new path and declared ... but not found for the old one. Under a basename credit it is silently zero, each missing finding covering for the other's absence. Every negative case is paired with a positive control, both boundaries (#10534's longer-sibling shape and the prototype shape) are pinned, and a live-population case asserts the helper is wired to the real table rather than only to fixtures.

Reverse verification, from the committed state

Re-ablated at the extracted decision point, mutation confirmed on disk each time, restored from the commit:

mutationproduction--self-test
declarationFor to a basename fallback0 GREEN1 REDa discovered path was credited to a same-named declaration at ANOTHER path
unfoundDeclarations to a basename comparison0 GREEN1 REDthe abandoned declaration must read as not found
declarationFor to a bare index read0 GREEN1 REDa declaration table answered from Object.prototype
positive control re-run (narrowed discovery)1 RED0 GREEN

Production staying green under all three is the point, not a defect: it is the card's thesis, now carried by an instrument.

The gate's rules did not move

Strengthening only, as the card and the dispatch require. Proof rather than assertion: origin/main's gate and this branch's gate were both run over the same tree and their production output is byte-identical (diff exit 0, both exit 0). Same verdicts, same diagnostics, same tables, same counts — 10 route modules, 16 dispatcher domains, 12 Hono modules, the express walk unchanged.

Verification

All gates re-run on the final commit 86b5c3a2c, exit codes captured before any pipe:

check:agent-test-spelling exit=0
check:cross-package-test-inputs exit=0
check:entry-guard exit=0
check:parse-guard exit=0
check:pnpm-filter-targets exit=0
check:route-envelope exit=0
check-ci-filter-parity.mjs exit=0
check-cross-package-test-inputs exit=0
check:nul-bytes exit=0
check-self-test-wired (#11918) exit=0 both legs

Gate verdict lines, quoted from the gates themselves:

✓ check-route-envelope self-test passed
✓ Route-envelope conformance — 10 route module(s) audited: 7 conformant, 2 ratcheted, 1 exempt
✓ check-self-test-wired: every one of the 128 script(s) CI runs that ship a `--self-test` has that self-test run by CI.

The family list was derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack against this branch's own diff, not inherited.

Lint — a measured narrowing, not a skip. Ran on the changed file rather than the repo, with the three readings that make the narrowing checkable: (1) the receiving population read from eslint's own --print-config — 2 active rules, parserOptions.project and projectService both null, so type-aware linting is not enabled; (2) --format json reports 1 file linted, 0 errors, 0 warnings, exit 0; (3) with type-aware linting off, each file's verdict is computed from its own source plus the flat config, and this diff touches one file and no config file — so no untouched file's verdict can move. The repo-wide sweep is CI's run.

Determinations

  • Bare-root obligation (scripts/pm/bare-root-worklist.mjs): does not apply. Verified rather than assumed — the sweep was run against this changed tree and reports 0 untriaged row(s), and check-route-envelope.mjs appears in no row. The change assembles no new scan root; discover(), discoverResponseWriters and discoverDomains are untouched in their root assembly.
  • Changeset: skip-changeset, derived from the workflow's own prescription rather than inherited — lint.yml states that "this PR edits a CI-internal script" is the textbook case, since such a PR releases nothing. The diff is one CI-internal script under root scripts/; no package, no published surface, no skills/ file moves.
  • Not a governed surface — no docs/adr/, no .claude/, no skills/, no root instruction file. Left draft for the PM seat to review and land.

Generated by Claude Code

…ed correspondence
The gate reconciles discovered route modules against four declaration tables by
exact path key, in both directions. Measured on f7b25c5: loosening exact
equality to a basename credit left BOTH the production run and --self-test green
at every one of those sites -- the four forward lookups, the three reverse
`includes` checks, and the two `MODULES[rel]` predicates that route a file to its
surface. Positive control (narrowing discover()'s convention) reddens the
production run, so the double-greens are a property of this rule, not of a
harness that cannot red.
Structural reason: green means the finding set is empty, loosening only shrinks
that set, and on a clean tree every discovered module already has an exact
declaration -- so the fallback never fires and the verdict cannot move.
Route every site through two pure exported functions -- declarationFor() and
unfoundDeclarations() -- and drive them from --self-test over the adversarial
population a clean tree by construction cannot supply: a route module moved to
another package keeping its file name. Under exact equality that is two findings
at once; under a basename credit it is silently zero.
The gate's rules are unchanged: same live verdicts, same diagnostics, same
tables.
Part of #11920
@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 08:15
@yinlianghui
yinlianghui added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit ae25b0cAug 25, 2026
32 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-11920-route-envelope-correspondence-instrument branch August 25, 2026 08:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

check-route-envelope's declared-vs-discovered module correspondence has no instrument — loosening it moves neither the production run nor --self-test

2 participants

@yinlianghui@claude