Skip to content

fix(qa-checklist): re-point nine bad-citation anchors and drain their residual rows - #19181

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-18104-drain-bad-citation-residual
Sep 19, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-18104-drain-bad-citation-residual

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Part of #18104

Clause-②: no

The slice, and why these three

SHARED_RESOLVER_RESIDUAL carries 47 bad-citation rows across 12 area files. The card
allows landing per area file, so this is the first slice: areas/access-security.json,
areas/api-backend.json and areas/automation.json — 9 rows, 10 anchor occurrences.

They were picked because they are one reading, not three: 8 of the 9 cite a route
ledger
packages/rest/src/rest-route-ledger.ts, packages/runtime/src/route-ledger.ts
and packages/triggers/trigger-api/src/trigger-api-route-ledger.ts — and every one of them
named something a route TABLE carries as data (a client-method name, a route path
parameter) rather than something the file declares. Repairing them is one judgement applied
nine times, which keeps the PR reviewable; the remaining 38 rows are untouched and stay on
the ledger.

Per row: which kind it was (acceptance item 2)

All nine are genuinely wrong citations, re-pointed. None of them is an accept-set case,
so none of them belongs to #18101.
Each old symbol was checked against
scripts/symbol-anchors.mjs#symbolResolutionClass directly and returns null; each new one
returns declaration.

area file old anchor what the old symbol actually was in that file re-pointed to
access-security rest-route-ledger.ts#saveItem CLIENT METHOD name, inside a client: string value #REST_ROUTE_LEDGER
access-security rest-route-ledger.ts#shareId route PATH PARAMETER, inside a route string #REST_ROUTE_LEDGER
api-backend rest-route-ledger.ts#REST (2 occurrences, 1 row) the bare word REST, a substring of longer tokens #REST_ROUTE_LEDGER
api-backend runtime/route-ledger.ts#getLegalNextStates CLIENT METHOD name, inside a dotted string value #ROUTE_LEDGER
api-backend trigger-api-route-ledger.ts#flowName route PATH PARAMETER, inside the route string #TRIGGER_API_ROUTE_LEDGER
automation runtime/route-ledger.ts#getScreen CLIENT METHOD name, inside a dotted string value #ROUTE_LEDGER
automation runtime/route-ledger.ts#runId route PATH PARAMETER, inside the route string #ROUTE_LEDGER
automation runtime/route-ledger.ts#getRuntimeStatus CLIENT METHOD name, inside a dotted string value #ROUTE_LEDGER
automation objectstack.config.ts#ConnectorRestPlugin an IMPORTED class — the file USES it, its own package declares it #plugins

The eight ledger rows are not renames. Each citation's prose already named the routes or the
families it means; what it was missing was a symbol the cited file declares, and in a route
ledger that is the exported table. This is the corpus's own established spelling — the
line two entries above one of the repaired ones already reads
packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER.

The ninth is a different reading. objectstack.config.ts imports the three connector plugin
classes and constructs them; the declaration the item is about — "this host wires these
connectors" — is the host's own plugins list, which is an object-literal key at the start
of a line and resolves as a declaration. The original parenthetical naming all three
plugin classes is kept intact.

No #symbol was dropped, and no floor moved

--anchor-census is byte-identical before and after, all 17 family files:

node scripts/check-platform-checklist.mjs --anchor-census   (before vs after: no differences, 17/17 files)

That is the mechanical statement of it: the floor population is resolved + residual, so a
repair moves an occurrence from one side to the other and leaves every per-file count where
it was. Ten occurrences moved: 577/633 resolved -> 587/633, residual 56 -> 46.

scripts/checklist-symbol-anchor-baseline.json is untouched.

Rows left by repair, and the ceiling came down with them

SHARED_RESOLVER_RESIDUAL 55 rows -> 46. SHARED_RESOLVER_RESIDUAL_CEILING 55 -> 46, in
the same edit. The header's shape tallies are re-counted with the rows
(string-substring 29 -> 21, import-only 9 -> 8, bad-citation 47 -> 38); accept-set
stays 8 and is untouched.

The binding measurement in that header ("56 of 633, at #16898") is left standing as the
dated reading it is, with a note saying so and pointing a reader at
SHARED_RESOLVER_RESIDUAL.length and the console line for the live count.

Positive control (acceptance item 3)

Two legs, each mutating the committed tree, proving the mutation landed on disk before
reading any verdict, then restoring with git checkout HEAD -- the mutated path and proving the
restore by blob hash against HEAD plus an empty git diff HEAD — never by an exit code.
Control run first: bare gate exit 0, zero ABSENT SYMBOL lines.

Leg A — a repaired anchor is still being judged, and it resolves. One repaired citation
in api-backend.json was re-pointed to REST_ROUTE_LEDGER_ABLATION_NOT_DECLARED (on-disk
proof: target text before=1, injected marker after=1). Gate exit 1:

areas/api-backend.json: ABSENT SYMBOL - `...#REST_ROUTE_LEDGER_ABLATION_NOT_DECLARED`:
... is not declared in packages/rest/src/rest-route-ledger.ts by
`scripts/symbol-anchors.mjs#symbolResolutionClass`

Restored (blob 64486cd5... == HEAD, git diff HEAD empty), gate back to exit 0. So
the green on these citations is the shared resolver answering declaration, not the gate
having gone quiet on them.

Leg B — an unrelated row still reds. The un-repaired
areas/studio-authoring.json / rest-route-ledger.ts#getHistory row was deleted from the
ledger without repairing its citation (on-disk proof: row before=1, after=0). Gate
exit 1 with ABSENT SYMBOL naming that anchor; restored (blob b52b00f3... == HEAD),
back to exit 0. So the nine rows left this ledger by repair — the population is still
firing for everything that was not repaired.

Gates

node scripts/pm/dispatch-gates.mjs --commands re-derived against the real changed set
(4 paths, committed) yields 31 families, matching the dispatch's derivation.
All 31 were run and all 31 exited 0 — reconciled with
dispatch-gates --ran RECORDFILE --repo objectstack-ai/objectstack:
31 derived, 31 run, 0 NOT-MEASURED, 0 UNRUN, with an exit code recorded per command so
that zero is derived rather than claimed.

scripts/check-platform-checklist.mjs is itself a gate, so both halves were run
separately
, not just the aggregate: bare invocation exit 0 (OK - 15 areas, 264 items ... 587/633 resolved ... 46 on the named #16898 residual, 17 file floors held) and
--self-test exit 0 (221 assertions). pnpm check:platform-checklist, which chains
checklist-select --self-test in front of both, also exits 0.

One family first reported exit 3 — PREREQUISITE NOT MET, not a finding:
@objectstack/lint run check:doc-formula-expressions wants @objectstack/formula and
@objectstack/lint built. Built them (under the shared verify lock) and re-ran: exit 0.

No import relationship changed and no TypeScript program's view moved — the diff is one
ESM gate script's data plus three JSON documents — so no per-package typecheck is owed
beyond what the derivation already places.

"All 31 derived families green" is not "CI green". The derivation itself names what sits
outside those 31: 53 artifact-roster families, 11 declared-wide-population families, 14
families that apply once a changeset exists, and 1 path-scheduled CI job. CI is the
authority on those.

Changeset

No changeset: nothing published moves. Measured rather than assumed — the root package is
private, and no package manifest in the tree declares a files[] entry escaping its own
directory, while this diff touches only repo-root scripts/ and docs/qa/, neither of
which is inside any package. skip-changeset applies.

Acceptance notes

  • The baseline JSON's $comment is now inaccurate, and this PR deliberately does not fix
    it.
    It reads "Each entry is the count of anchors that RESOLVED in that family file";
    since [finding] the platform-checklist corpus resolves symbol anchors with its OWN rule, not the shared resolver — a permissive token match where the ruling says there is to be exactly one implementation #16898 an entry is resolved + residual, which the gate's own --anchor-census
    footer states outright. scripts/checklist-symbol-anchor-baseline.json line 3 declares
    itself ⛔ MAINTAINER-ONLY, and reading that authority narrowly — as scoping only to
    lowering a floor — is the move the line exists to stop. Reported, not touched. It is a
    one-sentence maintainer edit.
  • The detector-artifact row is not in this slice, and the card's repair instruction for
    it does not survive contact with the tree at eeaa88245.
    The card says "repairing it
    means fixing the detector, not the citation". But platform-checklist reuses the shared resolver's RULE but is still not a registered corpus — the anchor grammar stays forked, and the two copies have already drifted (23 extensions vs 8) #18107 moved this corpus's detector into
    the shared core: scripts/check-platform-checklist.mjs imports extractAnchors,
    sweepCorpus and ANCHORABLE_EXTENSIONS from scripts/symbol-anchors.mjs and carries no
    anchor grammar of its own — its own --self-test asserts exactly that. The phantom
    #access is produced by SYMBOL in the shared module, whose character class admits no
    hyphen. So "fix the detector" is now a change to scripts/symbol-anchors.mjs, which all
    three cards in this split forbid by name. Whoever takes areas/identity-auth.json needs
    either a maintainer ruling on that widening or a citation-side repair — and the
    citation-side repair on the current bytes is not obvious either, because the anchor there
    is written ...access-security.json#access followed by a space, with the item-id
    access-security.scope-depth-asymmetry in the parenthetical after it. Noted for triage,
    not filed as a separate card from here.

Generated by Claude Code

…ng route-ledger anchors

First slice of the SHARED_RESOLVER_RESIDUAL drain. Nine `bad-citation` rows
across three area files are repaired at the citation, not at the resolver:
each anchor named a client-method name, a route path parameter or an imported
class, none of which is a declaration site in the cited file. Every one is
re-pointed at the declaration the item actually means -- the route table the
file exports, or the host plugin list -- following the convention this corpus
already uses for `auth-route-ledger.ts#AUTH_ROUTE_LEDGER`.

No `#symbol` is dropped, so the floor population is byte-identical: the
anchor census prints the same per-file counts before and after, with ten
occurrences moving from `residual` to `resolved` (577/633 -> 587/633).

The ledger's ceiling comes down with the rows, 55 -> 46, and the shape and
verdict tallies in its header are re-counted in the same edit.

Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
@os-try-charles os-try-charles added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 19, 2026 — with Claude
@os-try-charles
os-try-charles marked this pull request as ready for review September 19, 2026 09:09
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 19, 2026
Merged via the queue into main with commit 82b3225 Sep 19, 2026
37 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-18104-drain-bad-citation-residual branch September 19, 2026 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants