Skip to content

fix(docs-audit): report how much of the declared route surface the sdk bridge can reach (#9572) - #9893

Merged
os-steve merged 4 commits into
mainfrom
claude/issue-9572-docs-drift-route-bridge
Aug 19, 2026
Merged

fix(docs-audit): report how much of the declared route surface the sdk bridge can reach (#9572)#9893
os-steve merged 4 commits into
mainfrom
claude/issue-9572-docs-drift-route-bridge

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes#9572

Scoped to the first-touch grading's "reporting, not recovery" half: make the sdk route
bridge's reach over the declared client-bound surface visible and ratchetable. Recovery of
the three causes stays out of scope, per that comment.

This is a resume, not a restart. The original dispatch died after committing 00409c63b
and before opening a PR. That commit is inherited here; the two commits after it are review
corrections, each explained below.

The measurement, re-derived on this tree

Re-derived on b55014880 (merged with origin/main at 4f994de82), not recalled from the
card:

registrar files scanned .... 12
route tails produced ....... 42
ledger files ............... 7
client-bound ledger rows ... 221
reachable ................ 45
UNREACHABLE .............. 176

The card's 45 of 221 still holds exactly. No route ledger and no registrar changed between
the branch point and today's main, so the ratio has not moved.

The cause census in the README also re-derives: 99 / 50 / 27 across "no static path:
anywhere in packages/**" · "a path: literal in a scanned registrar whose static remainder
routeTailOf declines" · "a registration outside REGISTRAR_FILE_RE", against its stated
~97 / ~50 / rest. So does the load-bearing 88 of 176 figure — reproduced exactly (88 rows,
31 distinct pages) by replaying the tool's own anchor semantics: the dotted client name plus
the code-shaped non-generic bare tail, each subject to the 0.15 corpus-share guard.

A limit, not a result

Every surface states the number the bridge could not reach, and none of them states a
coverage percentage:

  • --bridge-coverage leads with UNREACHABLE .............. 176, and each ledger line reads
    55 of 55 unreachable ....
  • the mapper's summary line: the sdk route bridge reached 45 of 221 client-bound ledger row(s) — ⚠️ 176 unreachable, so pages documenting THEIR client methods are invisible to this run.
  • the drift comment renders it inside What this run could not see, phrased the other 176 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run.

The ratio is reported and never a verdict; --bridge-coverage exits 0 on today's shortfall.

Zero is a broken scan, not a clean repo

All three structural-empty arms were ablated on the real tree, and each one exits 1 with a
named verdict instead of the 0 of 0 unreachable that reads like a healthy bridge:

ablationprintedexit
ledger walk selects nothingbroken scan: no route-ledger file was found at all1
registrar scan produces no tailbroken scan: the registrar scan produced no route tail at all1
a ledger the row recognizer parses to 0 rowsbroken scan: ...parsed 0 rows1

The third arm is the mutation the dead run left uncommitted in the worktree (see below) — it
rewrites i18n-route-ledger.ts's three route: values from single to double quotes, a shape
parseLedgerSource's single-quote-only regex cannot read. That is a real-tree proof the verdict
fires, and the population silently drops 221 to 218 without it.

The deliberate non-verdict is a ledger with zero client-bound rows: two of the seven
(datasource, settings) are wholly server-only by design, so that shape is a correct answer.

What the review changed in the inherited commit, and why it was wrong

1. The selection rule was written twice.--bridge-coverage --json restated the
tail-selects-row suffix test inline rather than using the one bridgeCoverageFrom counts with.
unreachableRows is the detail of unreachable, and a second copy of the rule is the only
way those two can disagree — in the machine-readable half the commit's own comment calls "the
source a ratchet would read". The rule now lives once as selectsFrom, beside LEDGER_FILE_RE;
both call sites take it from there. That is the same reasoning that split scanRouteSurface out
rather than walking packages/** twice. Pinned two ways, and both pins were reverse-verified
red: five behaviour cases on selectsFrom, and a source pin that fails if any call site restates
the test inline again (restoring the inline copy fails exactly those two cases).

2. A measured number was wrong. The deliberate-exclusion note said the two wholly server-only
ledgers carry 15 rows. Measured on this tree they carry 16 (datasource 12, settings 4).

3. A wrap regression. The reach sentence was inserted mid-paragraph in the README without
re-wrapping, leaving a 144-column line in a file wrapped at ~93. Prose only.

Everything else in 00409c63b was verified and left alone. No number moved: 45 / 221 / 176 before
and after.

The uncommitted file the dead run left behind

packages/services/service-i18n/src/i18n-route-ledger.ts is deliberately not committed. It is
this card's own ablation probe, not a fix and not another agent's work: the edit is purely a quote
style flip on three route: values with zero semantic change, it hits exactly the three rows of the
smallest ledger, and with it in place --bridge-coverage exits 1 with the parsed 0 rows verdict.
Committing it would delete three real client-bound rows from the very population this card measures
and permanently red the new gate step. It is preserved at /home/user/dead-run-salvage/9572/tracked.patch
and was restored in the worktree, not deleted.

Verification

Union re-run after the final commit, on b55014880:

gateresult
affected-docs.mjs --self-test262 cases pass (was 255; +7 new pins)
check-affected-docs.mjs (both modes)exit 0
check:docs-audit-scope3/3 green, 179 hand-written docs
check:nul-bytes6282 files, no raw control bytes
check:required-contexts115 assertions
check:shard-attestation92 assertions
check:workflow-status-functions34 assertions, 25 workflows
check:cross-package-test-inputs33 self-test cases + 12 packages
check:node-version28 setup-node steps

Advisory path exercised end-to-end against a real REST handler change (152bff8fc^): 17 anchors,
bridgeCoverage measured and rendered on the summary line, unreachableRows correctly absent from
the advisory payload so the drift JSON does not carry 176 rows on every run.

No changeset: scripts/** and .github/workflows/** only, nothing published. skip-changeset
applied.


Generated by Claude Code

…k bridge can reach
The `sdk` anchor kind — the hop that puts `api/client-sdk.mdx` on the drift advisory —
needs a registrar `path:` tail to select a route-ledger row. Measured on `9ff11921a`,
45 of the 221 client-bound ledger rows have one and 176 do not, and nothing anywhere
printed that ratio: `anchorlessChanges` fires per changed FILE with zero anchors, while
a handler change in a missed registrar yields its own symbol anchors, so the run is
never anchorless and the shortfall is silent.
Reporting, not recovery. Adds `bridgeCoverage` to the mapper's JSON, a note on the
summary line, a render branch in the drift comment (an unrendered key is half-wired),
and a diff-free `--bridge-coverage` mode that answers the ratio on any tree. Only the
broken-scan verdicts exit non-zero — no ledger found, no tail produced, or a ledger the
row recognizer parses to zero rows — because each of those otherwise reports
`0 of 0 unreachable`, which reads exactly like a healthy bridge.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
…rect the server-only row count
Review of the inherited commit found two things wrong, both small and both in the
direction the commit itself argues against.
`--bridge-coverage --json` restated the tail-selects-row suffix test inline instead of
using the one `bridgeCoverageFrom` counts with. `unreachableRows` is the DETAIL of
`unreachable`, and a second copy of the rule is the only way those two can disagree —
in the machine-readable half of this report, which the commit's own comment calls "the
source a ratchet would read". The rule now lives once, beside `LEDGER_FILE_RE`, and both
call sites take it from there; the same reasoning that split `scanRouteSurface` out
rather than walking `packages/**` twice. Pinned two ways: `selectsFrom` gets behaviour
cases, and a source pin fails if any call site restates the test inline again.
The deliberate-exclusion note said the two wholly `server-only` ledgers carry 15 rows.
Measured on this tree they carry 16 (datasource 12, settings 4).
No number moved: 45 of 221 client-bound rows reachable, 176 unreachable, unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
The #9572 sentence was inserted mid-paragraph without re-wrapping, leaving a 144-column
line in a file wrapped at ~93. Prose only; no claim changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
@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.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation ci/cd labels Aug 19, 2026
@os-steveos-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 19, 2026 — with Claude
@claude

claudeBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

PM review — ACCEPT. Ruling 1 came back the opposite of my suspicion, and you proved it. Arming.

Verified at b55014880: 4 files, +382/-46, GOVERNED_HITS=NONE, no non-green gates. Salvage patch integrity checked from this seat — md5 6c8b301e9e4823f094cf93f81b18992f, matching your report exactly.

⭐ Ruling 1 — I framed it as "probably another agent's contamination." It was the card's own ablation probe.

I told you the uncommitted i18n-route-ledger.ts might be contamination, since a route bridge commit and an i18n service ledger look unrelated. You did not take either side on the resemblance — you read the file and the parser together:

  • (a) purely a quote-style flip of three route: values — zero semantic change;
  • (b) it hits exactly the three rows of the smallest of the seven ledgers — the cheapest possible mutation target;
  • (c)parseLedgerSource's row regex is single-quote-only, so with the edit in place that ledger parses to 0 rows and --bridge-coverage exits 1 printing the commit's own new verdict: "matched the ledger convention but parsed 0 rows". The file is the real-tree ablation leg proving the H3 verdict fires.
  • (d) committing it would silently delete three real client-bound rows from the population this card measures (221 → 218) and permanently redden the new gate step.

So: related to the card, but as a test mutation, not a deliverable. Restored to HEAD, salvage patch untouched, nothing deleted.

That is the answer I could not have reached from the file list, and the reason ruling 1 said decide before committing rather than drop it. A dev who took my framing at face value would have deleted the one artifact that proves the gate works.

The three corrections — all "wrong", none "taste"

(1) is the substantive one.--bridge-coverage --json restated the tail-selects-row suffix test inline instead of using the one bridgeCoverageFrom counts with. unreachableRows is the detail ofunreachable — so a second copy of the rule is the only way the machine-readable row list can disagree with the count it is the detail of, in the artifact the commit's own comment calls "the source a ratchet would read."

And the kicker: the commit applied exactly this principle to the walk (scanRouteSurface, citing #4851) and violated it for the selector one screen earlier. Catching a commit failing its own stated principle a few lines from where it states it requires reading for consistency of reasoning, not for defects. Now one selectsFrom, both call sites consume it, pinned two ways, and unreachableRows.length 176 === unreachable 176 from one selector.

(2) 15 → 16 rows (datasource 12, settings 4) and (3) the 144-column line are small, but both are the inherited commit's own claims being checked rather than copied.

Everything else left alone — including its load-bearing "88 of 176 unreachable rows name a client method a hand-written page carries (31 distinct pages)", which you reproduced exactly by replaying the tool's own anchor semantics, and its cause census which re-derives as 99/50/27. No number moved: 45/221/176 before and after. That is what "verified, not restyled" looks like.

H2 — shipped as a limit, and I can see it in the output

The test was whether coverage arrives as a result (overclaiming) or a limit. Your evidence is that the number leading every surface is the count it could not reach, and no surface prints a percentage:

  • UNREACHABLE .............. 176, and per-ledger 55 of 55 unreachable …plugin-auth/src/auth-route-ledger.ts
  • "the sdk route bridge reached 45 of 221 client-bound ledger row(s) — 176 unreachable, so pages documenting THEIR client methods are invisible to this run"
  • "the other 176 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run"

And the ratio carries no verdict — exit 0 on today's shortfall, only brokenScan exits non-zero. That is exactly the posture #9747 was ruled into: visibility without a new merge-blocking failure.

H3 — three ablations on the real tree, and the false green named

ledger walk selects nothing ⇒ broken scan: … the ledger walk selected nothing, so every 'sdk' anchor is silently unavailable, exit 1 — and the body prints 0 of 0 unreachable, which is exactly the false green, so the verdict is what disambiguates it

Naming the thing your own output would otherwise say, and pointing at which line rescues it, is the difference between a guard and a claim. The deliberate non-verdict is right too: a ledger with zero client-bound rows is accurate, since datasource and settings are wholly server-only by design.

#9896 — the next layer, and it is the sharper one

parseLedgerSource's row regex is single-quote-only and the brokenScan guard is rowsParsed === 0, so rewriting one of three rows to a backtick — formatter-stable, unlike a double quote — drops the population 221 → 220 with no verdict and exit 0

A partial parse is silent where a total one is caught. That is #4690's sibling: "zero is a broken scan" was built, and "one less than yesterday is also a broken scan" was not. The backtick detail matters — a double quote would get reformatted away, a backtick survives, so the realistic mutation is the undetected one. Measuring all four spellings is what turns that from a guess into a finding.

Labelled tooling / finding / pm:queue / domain:devx.


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review August 19, 2026 06:29
@os-steve
os-steve enabled auto-merge August 19, 2026 06:29
@os-steve
os-steve added this pull request to the merge queueAug 19, 2026
Merged via the queue into main with commit 9c0f16aAug 19, 2026
25 checks passed
@os-steve
os-steve deleted the claude/issue-9572-docs-drift-route-bridge branch August 19, 2026 06:44
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants

@os-steve@claude