Uh oh!
There was an error while loading. Please reload this page.
fix(docs-audit): admit only leaf symbols into the route bridge — a container name in a handler is not that route's implementation - #9431
Merged
Conversation
A symbol derived from a CONTAINER declaration (class / interface / type / enum / namespace / key-owning const) is a doc anchor but not a route's implementation, so it no longer feeds the symbol -> route -> sdk bridge. Measured on 9e2e682: a 27-line edit confined to `RestServer.probeMcpServeable` (17 of them its doc comment, which attributes to the enclosing class) put `RestServer` in the anchor set; two handlers ~1350 lines away call `RestServer.` statics, and the bridge's bare-identifier handler scan read that qualifier as "this handler implements the changed symbol". Result: `/book/:name/tree`, `/:type/:name/layers`, `getBookTree` and `meta.getBookTree`. Two routes is under MAX_ROUTES_PER_SYMBOL, so the cross-cutting cap never fired. The `RestServer (symbol)` row is correct and survives untouched — only the bridge hop is cut. Self-test 197 -> 212, pinned in both directions including a counterfactual that the raw anchor set still selects the book route. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
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 18, 2026
os-steve
marked this pull request as ready for review
August 18, 2026 01:16
Uh oh!
There was an error while loading. Please reload this page.
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.
Fixes#9294
Mechanism — measured, and it is neither candidate the card named
The card offered two hypotheses with different fixes and asked for a measurement first. Both are wrong, and the real chain is a third thing:
routeAnchorsto their declared client method. And the literal-route derivation (literalAnchorsFromLines) is already strictly line-scoped — it reads route literals off changed lines only./book/:name/treenever entered through either.declarationOnrefuses comment bodies), and the indent walk then climbs past every sibling member to the class. So a doc-comment edit above a private method attributes toRestServer— correctly, per the card's own ruling on that row.The defect is one hop later, in PHASE 2 of the bridge.
parseRegistrarSourcetests the premise "this symbol IS some route's implementation" by scanning a registrar handler window for the bare identifier. A container name satisfies that scan without satisfying the premise. Measured on9e2e68206(the squash-merge of PR #9291):Three wrong rows off a static-call qualifier ~1350 lines from any changed line. Two routes is under
MAX_ROUTES_PER_SYMBOL(3), so the cross-cutting cap never fired.Fix
A symbol derived from a container declaration (class, interface, type, enum, namespace, or a
constobject that owns its keys) is admitted as a doc anchor exactly as before, but no longer enters the route bridge. It is the same shape of carve-out the file already applies toSCREAMING_SNAKEconstants one line above, and it generalises the reason: a container is the scope a route's implementation lives in, never the implementation.documentableDeclarationsAtnow reportscontaineralongside the name, andsymbolAnchorsFromSourcereturns{ names, bridgeable }—bridgeablepositive rather than subtractive, so a name that reached the set through a leaf derivation anywhere stays bridgeable.Nothing else moves: most-specific-wins already anchors a changed method body on the method, and a method is a leaf, so
auditMetaItemto/:type/:name/audittometa.getAuditstill bridges.Measured, before and after — verified at
f05810a75Tool generations: coarse = the pre-#9192 package-mention predicate · main =
origin/mainata4331227b· fixed = this branch.9e2e68206(the card's specimen)api/client-sdk.mdx,releases/v14.mdx30b1c636a(#9192 headline)3851f87f0(#9192 headline)ui/public-data-collection.mdx07ad42463(#9192 headline)On the specimen, all three wrong rows are gone and so is a fourth wrong anchor nobody had noticed —
/:type/:name/layers (route), which matched no page and so never showed up in the advisory.RestServer (symbol)survives on all three release pages, which is the row the card ruled correct.07ad42463reads 1 rather than the card's 0 because #9230 later added thecommandanchor kind; that is #9230's recall win, unchanged here.The one other row that moved is a SECOND instance of the same defect, not a regression
3851f87f0lostcontent/docs/ui/public-data-collection.mdx, whose only anchor was/forms/:slug/submit (route). Tracing it:SecurityPluginreached the anchor set from 17 changed doc-comment lines (the JSDoc atsecurity-plugin.ts:5514, the identical doc-comment-attributes-to-the-class path), and then bridged because two lines inside that route's handler window are English prose comments —The page has zero occurrences of
maskingRule,FieldMasker,keepHead,keepTailormask— it documents nothing that diff touched. Measured independently and months apart from the card's specimen, so the blast radius is wider than one PR.Self-test — 197 to 212, pinned in both directions
The removal direction alone would pass just as happily on an over-correction that also drops the correct row, so the new fixture pins four things at once: the class stays a symbol anchor, the class is not bridgeable, the method stays bridgeable, and the identifier scan still sees the qualifier — that last one is what stops the block going green because the fixture drifted into deriving no route at all. Plus a counterfactual holding the pre-fix behaviour: the raw anchor set still selects
/book/:name/tree, so the test cannot pass for the wrong reason.Verification
Run after the final commit, at
f05810a75:Gate family re-derived from the actual changed path with
node scripts/pm/dispatch-gates.mjs scripts/docs-audit/affected-docs.mjs; it named exactly the two above and nothing new.Scope
One file.
skip-changeset:scripts/docs-audit/is repo tooling, not a published package, so this PR releases nothing.#9331 is not addressed here and nothing in this diff goes near it — that card is about validating an anchor against its target page at report time; this one is about which anchors a diff is entitled to produce on the source side. No overlap in the code paths touched.
Two things deliberately left alone, both worth a separate look rather than a rider on this PR:
SCREAMING_SNAKErule nor this container rule publishes what it withheld, while the cross-cutting cap publishescrossCuttingSymbolsand the drift comment renders it. Adding a field would needdocs-drift-check.ymlto render it, which is outside this card's file surface.parseRegistrarSourcescans handler windows for identifiers including inside comments, which is what let an English sentence carrySecurityPlugininto a route. This fix removes the class of symbol that made that reachable; it does not make the scan comment-aware.Generated by Claude Code