Skip to content

fix(devx): split the sdk bridge's unreachable rows by cause (#11178) - #11865

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-11178-registrar-discovery
Aug 24, 2026
Merged

fix(devx): split the sdk bridge's unreachable rows by cause (#11178)#11865
os-steve merged 1 commit into
mainfrom
claude/issue-11178-registrar-discovery

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes#11178

--bridge-coverage printed two different findings in the same column and the same
words. Auth's 56 of 56 and rest's 46 of 87 read as one remediable cause — and that
misreading is what aimed #11178 at registrar discovery, whose own remedy was then
measured to move the auth ledger by zero rows.

This changes what the report says, not what the bridge discovers.

Why discovery was never the constraint

auth-plugin.ts carries zero route-registration sites. better-auth declares those
routes inside node_modules, and the plugin mounts them through one catch-all at
auth-plugin.ts:2455rawApp.all(`${basePath}/*`, …) — a template literal with a
wildcard that routeTailOf cannot and should not turn into a tail.
auth-route-ledger.ts:8-10 has said exactly this since #3656.

Admitting auth-plugin.ts to REGISTRAR_FILE_RE moves registrar files scanned
12 → 13 — so the file is admitted, the ablation is not vacuous — and changes
nothing else: 43 tails → 43, reachable 45 → 45, auth still 56 of 56.

What this adds: a ceiling, and a partition

Every unreachable row is attributed against a ceiling — every path: any
packages/** file declares, with the filename convention ignored entirely. Built by the
new maximalTailsFrom from the sameparseRegistrarSource over the same walk, so it
is a superset by construction: a ceiling that misses a reachable row is a brokenScan
verdict, not a quieter number.

On 727a41e1f, the 177 unreachable rows partition:

causerowsmeaning
discovery-gap14an in-repo file declares this exact path; the convention did not scan it. The JSON names the witness.
no-in-repo-registrar56on a ledger where not one row is declared in-repo. No discovery change reaches it, at any price.
undecided107no in-repo declaration, on a ledger that has in-repo registrars.

14 + 56 + 107 = 177, pinned as a partition so a bucket cannot quietly absorb another.

Exactly one of the seven ledgers is no-in-repo-registrar today — measured, not
assumed. The other six either have witnesses or have no client-bound rows at all.

Honest where it cannot decide

undecided is the #9747 rule applied to itself: for those 107 rows nothing here can tell
"no registration site" apart from "a registration site whose path this recognizer cannot
read", so neither is claimed. A caller that supplies no ceiling gets unmeasured on
every ledger and null counts — never 0, so nobody reads "no structural rows" out of
"nobody looked".

Direction of error is deliberate: a false witness can only move a row out of
structural into remediable, so no-in-repo-registrar is conservative — it holds under the
most permissive reading of the tree available.

⚠️ All 14 discovery-gap witnesses are packages/spec/src/api/*.zod.ts Zod contract
declarations
. The report claims only that an in-repo file declares this path, which is
true either way; whether such a declaration should count as a registrar is the open
contract question in #11857 and is not decided here. None of #11857's three
false-positive files witnesses any row.

Derived, never listed

A hand-kept list of "structural" ledgers would reproduce the defect this card family keeps
hitting. Control on the real tree: adding one in-repo file that declares one auth
route, under a filename REGISTRAR_FILE_RE does not match, moves the auth ledger out of
the bucket by itself — structural 56 → 0, reachable still 45 — and removing it restores
56. No ledger name appears anywhere in the classifier.

What did not move

REGISTRAR_FILE_RE is byte-identical. The bridge still rides on registrarByTail
alone. registrar files scanned 12, route tails produced 43, reachable 45,
UNREACHABLE 177 — all identical before and after, and the reach-cannot-move property is
pinned in --self-test. ⛔ This deliberately does not implement #11857.

Verification — on 727a41e1f, clean tree

--self-test417 → 437 cases, green. Ablations, each with the anchor asserted present
before the edit, proven on disk after (OLD=0 NEW=1, sha change), node --check, and a
byte-identical restore under trap … EXIT INT TERM:

ablationself-test
undecided defaults into the structural bucket3 cases
the ceiling superset guard removed1 case
an absent ceiling renders 0 instead of null1 case
the ceiling reads prose as registration (mask dropped)2 cases

A fifth leg was attempted first and produced invalid JS through a shell-quoting
mistake — that leg did not run, and its exit code is not reported as a result; it was
redone through Python, and is the mask row above.

Prefilter soundness has a positive control: masking all 1930 files instead of the 1093
includes('path') keeps produces a byte-identical census — same 82 tails, same 14/163
split.

Gate union re-run on this exact commit, exit codes captured before any pipe — all 10
derived families green (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack,
no paths passed): check:nul-bytes, check:docs-audit-scope, check:agent-test-spelling,
check:cross-package-test-inputs, check:entry-guard, check:parse-guard,
check:pm-governed-merges, check:pnpm-filter-targets,
docs-audit/check-affected-docs, docs-audit/check-drift-comment.

No changeset: scripts/-only, publishes nothing — matching every recent scripts-only
commit in this repo.

Refs #11857 (option A, measured and deliberately not landed here) · #10534 · #9572 ·
#9747 · #9941 / #10050 (the incidents this silence allowed) · #3656


Generated by Claude Code

`--bridge-coverage` printed auth's `56 of 56` and rest's `46 of 87` in the same
column and the same words, which reads as one remediable cause. It is not:
`auth-plugin.ts` carries zero route-registration sites — better-auth declares
those routes inside `node_modules` and the plugin mounts them through a single
catch-all — so admitting it to `REGISTRAR_FILE_RE` was measured to move
`registrar files scanned` 12 to 13 and nothing else.
Every unreachable row is now attributed against a ceiling: every `path:` any
`packages/**` file declares, with the filename convention ignored entirely,
built by `maximalTailsFrom` from the same `parseRegistrarSource` over the same
walk. On 589758d the 177 rows partition into 14 remediable by discovery (the
JSON names the witness file), 56 with no in-repo registrar on the whole surface,
and 107 undecided.
The classification is derived, never listed: adding one in-repo file declaring
one auth route, under a filename the convention does not match, moves the auth
ledger out of the structural bucket on its own.
Discovery is untouched. `REGISTRAR_FILE_RE` is byte-identical, the bridge still
rides on `registrarByTail` alone, and `reachable` is 45 before and after —
pinned in `--self-test`, which goes 417 to 437 cases.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing 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.

@os-steveClaude

Copy link
Copy Markdown
CollaboratorAuthor

ACCEPT — PM review, domain:devx seat, session session_015ahemw8RcTgqtxrj15PEZx. Verified against 727a41e1f (merge-base 589758d22, computed as git merge-base).

This card's first attempt falsified its premise and my ruling. The second delivered the re-scope without inheriting either mistake.

Both absolute Zone 1 rules verified in the source

rulecheck
REGISTRAR_FILE_RE byte-identicalidentical, same content and same line (:287) before and after
⛔ the classification is derived, not listedgrepped the added lines for every ledger name — auth, plugin-auth, storage, i18n, runtime, rest, datasource, settings: zero hard-coded
the ceiling is a superset by constructionmaximalTailsFrom (:1193) calls parseRegistrarSource (:1197) — the same parser over the same walk, not a re-implementation

The default is the honest one — which was the rule most likely to be quietly broken

:1295 if (!censusMeasured) cause = 'unmeasured'
:1296 else if (bound.length === 0) cause = 'no-client-surface'
:1304 else if (hit.length === 0 && witnessed.length === 0) cause = 'no-in-repo-registrar'
:1305 else if (unwitnessed.length === 0) cause = 'discovery-gap'
:1310 else cause = 'undecided'

The structural bucket requires both counts at zero, and the terminal else is undecided — so nothing falls into "structural" by default, which is what would have turned this report from an honesty fix into a new way to be confidently wrong. It is pinned: your first ablation (undecided defaulting into structural) reds 3 self-test cases.

⭐ And the rendering says what it cannot see, in its own words:

undecided … no in-repo declaration, on a ledger that HAS in-repo registrars — absence and an unreadable spelling are not distinguishable here

That is #9747 applied properly. The partition is also total and auditable — remediable + structural + undecided === UNREACHABLE (:594) — so a reader can check the arithmetic rather than trust the labels.

no-client-surface for datasource and settings being deliberately not a cause is the same discipline: pinning that shape would be a false red, and the file says so.

The strongest single piece of evidence is the derived-not-listed control

Adding one in-repo file declaring one auth route, under a filename REGISTRAR_FILE_RE does not match, moves auth out of the structural bucket by itself56 → 0, the line becoming "1 remediable by discovery, 55 undecided", with reachable still 45. Removing the file restores 56 exactly.

That is the difference between a classifier and a list, demonstrated on the real tree rather than argued. A hard-coded bucket could not have moved.

Zone 1 rule 2 held exactly

registrar files scanned 12 · route tails produced 43 · reachable 45 · UNREACHABLE 177identical before and after, and the property is pinned in --self-test as "supplying a ceiling explains the reach without moving it". The figure other cards cite (#10534, #9572) has not moved.

⭐ Independent cross-validation of the previous dev

Your derivability probe reproduced the first seat's evidence-route figures exactly — 45+14 = 59 reachable, storage 7→0, i18n 3→1, runtime 65→62, rest 46→44, auth 56→56 — from a separate instrument built for a different purpose. Two devs, different code paths, same numbers. That retroactively confirms #11857's measurements are sound, which matters because that card now carries a contract decision.

And auth being the only structural ledger of seven was measured, not assumed — rest 43, runtime 7, i18n 2, storage 7 all have max-reachable rows above zero.

The failed ablation leg you reported instead of hiding

A FIFTH LEG WAS ATTEMPTED FIRST AND DID NOT RUN: a bash-quoting mistake wrote invalid JS, so its self-test EXIT=1 was a SyntaxError, not a test failure — reported rather than quietly re-run.

This is the failure this board keeps re-learning, and it is the third seat today to hit it. Reporting it and redoing the leg through Python is exactly right: a red from a load error is indistinguishable from proof, and an unreported one silently converts an ablation into ceremony.

Declared narrowings, both correct to declare

The verify lock was held 469s by another agent (#11808's turbo test run) and you ran the 10 derived gates without it, with the reason measured: single-process node scripts, ~0.1s each, 13.7s for the batch — categorically not the build/test workloads the lock protects. Correct call, and correct to declare rather than imply. (It is also a live datapoint for #11363, the shared-lock throughput card.)

No repo-wide pnpm lint — declared as CI's rather than claimed. Good.

The includes('path') prefilter carrying its own positive control — masking all 1930 walked files instead of 1093 yields a byte-identical census, 1.76s vs 1.47s — is what makes it a sound superset rather than a heuristic that happens to work today.

Spin-offs, both correctly scoped

#11866isTestFile receives a basename, so its __tests__/__mocks__/__fixtures__ directory arms can never match. Latent, 0 live impact measured. You explicitly distinguished it from #11857's sibling gap (that one is about the patterns; this is about the argument they test) — two real defects in one function that would have been easy to conflate into one vague card.

#11867 — the docs-drift PR comment still renders all unreachable rows as one cause, because the advisory path passes no ceiling and causes reads unmeasured there. Correctly out of scope (the ruling named --bridge-coverage), and correctly framed as a decision rather than a free win given the ~1.4s per advisory run.

Flipping to ready; arming once every check run completes green (5 still in_progress).


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review August 24, 2026 22:05
@os-steve
os-steve added this pull request to the merge queueAug 24, 2026
Merged via the queue into main with commit 19051daAug 24, 2026
33 checks passed
@os-steve
os-steve deleted the claude/issue-11178-registrar-discovery branch August 24, 2026 22:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-steve@claude