Uh oh!
There was an error while loading. Please reload this page.
feat(gate): fail a rawApp auth mount that carries no ledger row (#10534 follow-up 4) - #11149
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PnJHU45vPJj5UQrxe946Bx
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. |
This was referenced Aug 22, 2026
The PENDING_DISPOSITION paths expand a shrink-only exemption list; both now name their owner in the author-facing message, and the control corpus in check-ratchet-remedy-authority.mjs records the gate as 'marked'. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PnJHU45vPJj5UQrxe946Bx
Contributor
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32601247997 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
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.
Part of #10534 — follow-up 4 only. This card keeps remaining scope after this PR (follow-up 3, the
REGISTRAR_FILE_REbridge; and the ninth ledger row, #10975), so this PR must not carry a closing keyword. It does not.The hole
auth-plugin.tsmounts routes directly on the raw Hono app, ahead of the better-auth catch-all. The catch-all never sees them, so the vendor's own route table cannot account for them, andauth.api's enumeration — which is whatauth-route-ledger.conformance.test.tsdrives — cannot see them either. A mount with no row in either half of the ledger was therefore invisible to every check in this tree. That state produced #9941 and #10050, and #10534's census found it was not a one-off: nine of the seventeen mounts were in neither half.The pin the conformance suite already carries asserts the
source: 'objectstack'set exactly, so it fails when a row disappears. What it structurally cannot do is fail when a mount appears with no row, because both of its sides are hand-written: the mount list in that assertion is a copy of the truth, not a reading of it, and nobody who adds route 18 has to touch it.pnpm check:auth-mount-ledgersupplies the missing half: it enumerates the mounts fromauth-plugin.tssource and diffs them against both halves of the ledger.Clause-② — declared
no, and it holdsA gate adds no runtime surface and changes no route's mounting, behaviour, or accept/reject set. The only
packages/**edit is a comment-only change to the conformance pin, whose text still told readers this gate did not exist. Zeropackages/spec, zerocontent/docs/releases/**.Nothing in the gate's failure text or its requirements can force a runtime change to make
maingreen — the ninth mount is carried by a declared, issue-bearingPENDING_DISPOSITIONentry, not by demanding a row that does not yet exist.Population re-measured on current
mainbbe643c08,--report: still 17 — 12 accounted for by a reviewed ledger row, 4 shadowing a vendor-declared path (BETTER_AUTH_MOUNTED_SURFACE), and 1 pending. That reproduces #10534's census a third time, across a third commit.The four measured constraints
1. The match carries a right boundary. Accounting is exact string equality on
METHOD /full/wire/path. #10534's own leg 1 read "5 undocumented" when the truth was 6, because it matched by substring and/admin/sso/registeris a strict prefix of/admin/sso/register-saml— the shorter route was scored accounted-for on the strength of its longer sibling's URL. When an unaccounted mount does stand in a prefix relation to a ledgered route, the failure text says so, so the property is observable in the output rather than implicit in a comparison operator.2.
rawApp.allandrawApp.useare excluded — the catch-all and the IP gate are lanes, not routes. Counted and reported, so the exclusion is visible rather than silent.3. A row alone does not satisfy it. A disposition cannot be inferred mechanically, and a gate that accepts a pasted row teaches the next author to paste a row. An
source: 'objectstack'row must carry the evidence its disposition claims —client:forsdk, a substantivenote:forserver-only/disabled/public. The failure text names the peer-group discriminator and theset-initial-passwordprecedent. The note floor is a floor, not a proof, and the script says so; what it buys mechanically is that adding three words is no longer the cheapest path.4. A partial read is never reported as a complete one. Any
rawAppmounting form the census cannot read per-route — an unrecognised verb (rawApp.on(...)), a non-literal path, an unresolved interpolation — is a finding. A missing file, a moved anchor, an underivablebasePath, or a parse that yields zero of anything exits 2 and printsNOT MEASURED. Exit 2 is a refusal, not a pass.That refusal earned its keep during development: the first spelling of the array parser looked for
];at column 0, and both arrays inauth-route-ledger.tsclose as,];on the last row's own line. The gate refused (exit 2) rather than reporting an empty population as a clean tree.Remedy authority (#8435) — and why
marked, notrefusedCI at
b86bd9e76was red oncheck:ratchet-remedy-authority, correctly. Reproducing it locally showed two findings, and the first is the one that matters:That is not a paperwork gap. The gate was telling an author who could not decide a disposition to add their own route to a shrink-only exemption list — the parking-space move this card has already ruled against once, offered by the gate itself as a co-equal option.
The classification is a real question and was answered against the convention's own vocabulary, not by picking the quietest word:
AUTH_ROUTE_LEDGER, which grows as routes are added and is not a ratchet at all. The detector agrees: it anchored only onPENDING_DISPOSITION. So there is no split the vocabulary is failing to express — the convention classifies only the ratchet-expanding path.PENDING_DISPOSITION— adding a route, and raisingPENDING_MAX— expand a shrink-only exemption list. Neither is the landing author's.refusedis the stronger shape and would be false here: the list holds a legitimate entry, granted by the maintainer ruling of 2026-08-22 on this card. There is a real act, with a real owner. Naming the owner is honest; denying the act is not.check-skills-token-ratchet.mjs(#10473) records exactly this reading for exactly this shape — a new gate with two remedy paths,markedbecause "there IS a legitimate act, with an owner". Reached independently here, then checked against it.Both author-facing messages now carry
⛔ MAINTAINER-ONLY, andCONTROLrecords the gate asmarkedwith the split written into itswhy. Observed, not assumed: the sweep movedunmarked (1) → unmarked (0),marked (7) → marked (8).const— leavescheck:ratchet-remedy-authorityat exit 0, still counting this gate among the 8 marked, while the author reads nothing. Only the four new placement pins catch it. Adding theconstand theCONTROLrow alone would have satisfied CI and declared something untrue.Both directions pinned
Predictions were written before every mutation; all seven matched.
rawApp.postfor/admin/zzz-ablation-probeunaccounted-mount, scope 18scope: 18 rawApp mount(s)rawApp.all+rawApp.useunderbasePath17 ... mount(s),4 lane(s)POST /api/v1/auth/admin/sso/registerrow, leavingregister-samlNOT CREDITED, DELIBERATELY: ... is a strict PREFIX of POST /api/v1/auth/admin/sso/register-samlset-initial-password(simulating #10975 landing)reconcileto credit by substring--self-testRED on the boundary assertionsa strict-prefix mount was CREDITED to its longer sibling--self-testRED on 1 pin; farm sweep greenconst--self-testRED on 2 pins; farm sweep still greenE and G are the two worth reading. Under substring accounting the production run of
check:auth-mount-ledgerstays green on a clean tree — only--self-testcatches it. Under a stripped token the farm sweep stays green — only the per-gate pins catch it. In both cases the instrument that fails is the self-test, which is why this repo's--self-test-first convention is load-bearing rather than ceremonial.Restores proven byte-identical by
git hash-object, then re-run to a real verdict:auth-plugin.ts56c783b059d81e058c540079db786c204bc8351f,auth-route-ledger.ts123e1a87dcedf63dc188cf680c2fc3ed08417913, conformance testd4c9cb0dfffc25cbef248afa78195c60c2b1647b,check-auth-mount-ledger.mjs496075b88cb1b4d116d7574d93280afc16bcd14a(at the new head);git diff --quietexit 0; self-test 42/42 and both gates green afterwards.No rebuild is involved, and that is argued from the files, falsifiably. The gate
readFileSyncs two.tspaths underpackages/plugins/plugin-auth/src/— no import of the package, noexportsresolution, nodist/. The single occurrence of the stringdistin the script is the header sentence saying so. Demonstrated in both states: green whenpackages/plugins/plugin-auth/distdid not exist at all, and green again after the full workspace closure was built.Gate union — derived on the final head
47ced12bfnode scripts/pm/dispatch-gates.mjswith no path arguments: 6 paths, 28 families. Re-derived after the second commit, and the second commit changed the union —check:ratchet-remedy-authorityis the one added family (27 → 28). All exit codes captured before any pipe.All 30 run, all exit 0:
check:ratchet-remedy-authority·check:auth-mount-ledger·check:route-envelope·check:dispatcher-error-vocabulary·check:nul-bytes·check:entry-guard·check:parse-guard·check:changeset-gate-self-tests·check:objectui-changeset·check:node-version·check:pnpm-filter-targets·check:required-contexts·check:shard-attestation·check:slot-lookup·check:test-source-alias·check:type-source-resolution·check:workflow-status-functions·check:cross-package-test-inputs·check-adr-0087-registration·check-aggregator-roster·check-changeset-no-major·check-ci-filter-parity·check-empty-changeset·check-plugin-teardown-shape·check-step-collectors·docs-audit/check-affected-docs·check:query-options-erasure·check:engine-double-contract·check:where-matcher·check:type-check-coverage, pluscheck:type-check-debt.Verdict lines, as printed on this head:
check-auth-mount-ledger --self-test: 42 assertions OK (right boundary, lane exclusion, rationale, pending ratchet).check-auth-mount-ledger: OK -- 17 ObjectStack auth mount(s), all accounted for (12 by a reviewed ledger row, 4 shadowing a vendor-declared path, 1 pending a disposition).OK check-ratchet-remedy-authority: 122 scripts swept (scripts/*.{mjs,mts}); 8 mark the expanding remedy ⛔ MAINTAINER-ONLY, 4 turn it down outright, 110 hand out no ratchet-expanding remedy. Control corpus: 21 hand-classified scripts, set-equality audited both ways.check-nul-bytes: OK (scanned 6454 text file(s) ... no raw ASCII control bytes).check-type-check-coverage --re-measure: OK — 33 ledger entr(ies) re-measured in 247.3s, 1895 raw tsc error(s) total, none above its recorded number.pnpm --filter @objectstack/plugin-auth test→Test Files 69 passed (69) / Tests 1449 passed (1449);typecheckexit 0.Class #10309, seventh confirmation — and the first that cost a red. The 27-family union at
b86bd9e76did not namecheck:ratchet-remedy-authority, and nobody named it by hand, so it ran for the first time in CI. It is named now only because this PR edits the sweep's own file; measured on47ced12bf,dispatch-gatesstill returns 0 hits for it againstscripts/check-auth-mount-ledger.mjsor any hypothetical new gate path, with a positive control confirming the expression works (check:entry-guardis named for both).--residueputs it in the undetermined bucket — its sources name no path at all, because its population is built byreaddirSyncand its only filename literals are bareCONTROLbasenames, whichextractWatchHintsrefuses as too generic. A gate that sweeps every script in the repo is derivable for none of them. Filed as #11155, unassigned, with the remedy the residue note itself names; not fixed here, being a different defect class with its own landing surface.Recorded, not claimed as coverage:
check:driver-memory-censusandcheck-test-completenessare unreachable by construction on this tree.TEST_DEBT (#10615): untouched. Number not edited,
--lowernot run. The ratchet reports@objectstack/plugin-auth: TEST_DEBT records 109, tsc now reports 97 (-12) -- the entry can be lowered. Not an error— pre-existing surplus, left exactly as found.The test-file trap was checked explicitly.
packages/plugins/plugin-auth/tsconfig.jsonexcludes**/*.test.ts, so the packagetypecheckcannot see the only file this PR touches underpackages/**. A test-inclusive tsc program was run on both sides: 97 errors with this branch's file, 97 withorigin/main's — identical, and the diff of that file contains zero non-comment changed lines.One measurement error caught and corrected rather than reported: a first pass of the union on the new head showed five gates red with
ERR_MODULE_NOT_FOUND. The worktree had been recreated withoutpnpm install. Reinstalled, re-run, all green — recorded here because a red read from an uninstalled tree is exactly the kind of number that gets reported as a finding.Not touched
scripts/docs-audit/affected-docs.mjs— follow-up 3 is a design fork on its own card. #10975 and #10974 are separately tracked and this PR neither anticipates nor blocks them;PENDING_MAXwas not raised.Generated by Claude Code