Skip to content

fix(qa-checklist): re-point thirteen identity-auth bad-citation anchors and drain their residual rows - #19196

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-18104-drain-identity-auth
Sep 19, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-18104-drain-identity-auth

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Part of #18104

Clause-②: no

The slice

The second slice of the SHARED_RESOLVER_RESIDUAL drain: areas/identity-auth.json — 13 rows, 13 anchor occurrences. It is the largest single-file block of the 38 bad-citation rows the first slice (#19181, landed at 82b322585) left behind, and it is one file, so every judgement in it is made against one item ledger.

⚠️ This file is NOT empty of residual rows afterwards, and that is correct

areas/identity-auth.json also carries 2 accept-set rowspackages/spec/src/kernel/public-auth-features.ts#sys_user and #sys_invitation, both the dotted-string-head shape. They are #18101's, not this card's, and they stay exactly where they are. Reaching them means widening scripts/symbol-anchors.mjs, which is the red line #18104 / #18101 / #18107 share by name. After this slice the ledger carries 33 rowsbad-citation 25 + accept-set 8 — and areas/identity-auth.json accounts for 2 of them.

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

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

# old anchor what the old symbol actually was in the cited file re-pointed to
1 areas/access-security.json#access not a key that JSON declares at all #items
2 seed-approval-demo.ts#PHONE_DEMO_USER IMPORTED — the constant lives elsewhere demo-personas.ts#PHONE_DEMO_USER (the path moved, the symbol did not)
3 sys-member.object.ts#BUILTIN_MEMBERSHIP_ROLE_OPTIONS IMPORTED from @objectstack/spec/identity #SysMember
4 sys-oauth-application.object.ts#OAuth the bare word, only inside label / description strings #SysOauthApplication
5 auth-route-ledger.ts#bootstrapStatus CLIENT METHOD name, inside a dotted string value #AUTH_ROUTE_LEDGER
6 auth-route-ledger.ts#linkSocial CLIENT METHOD name, inside a dotted string value #AUTH_ROUTE_LEDGER
7 auth-route-ledger.ts#revokeOthers CLIENT METHOD name, inside a dotted string value #AUTH_ROUTE_LEDGER
8 auth-route-ledger.ts#sendVerificationEmail CLIENT METHOD name, inside a dotted string value #AUTH_ROUTE_LEDGER
9 auth-route-ledger.ts#setActive CLIENT METHOD name, inside a dotted string value #AUTH_ROUTE_LEDGER
10 auth-route-ledger.ts#updateUser CLIENT METHOD name, inside a dotted string value #AUTH_ROUTE_LEDGER
11 security-plugin.ts#__referentialFieldClear a CONTEXT KEY, read only as a member access on opCtx.context #SecurityPlugin
12 membership-role-vocabulary.dogfood.test.ts#PermissionSet in a comment and an it(...) title #CLOSED_VOCABULARY
13 rest-route-ledger.ts#describeDelegableScope CLIENT METHOD name, inside a client: string value #REST_ROUTE_LEDGER

Six of them (5–10) are the first slice's reading applied again: a route ledger's client field is DATA the table carries, and the declaration the item means is the exported table. That spelling is already this corpus's own — areas/api-backend.json has read auth-route-ledger.ts#AUTH_ROUTE_LEDGER since before this card.

Three needed a reading of their own:

  • Row 1 is the detector-artifact row, and it was repaired citation-side, per the PM's ruling in comment 5740561848. The ledger's own fields say why: detector-artifact is the shape (why the withdrawn permissive rule used to resolve it), while the verdict has always read bad-citation. Reading the shape as the disposition sends the next author at the detector, which since 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 IS scripts/symbol-anchors.mjs — the file this card forbids by name. And the truncation is not happening on today's bytes anyway: the citation's fragment is followed by a SPACE, so the symbol was simply what the author wrote. What they meant is the item id in the parenthetical, which the checklist JSON carries as a VALUE, never a key — so the citation now names the items block and the item id stays in the prose beside it. The ledger header records this so the next reader is not sent the same way.
  • Row 2 is a MOVE, not a rename. seed-approval-demo.ts says so in its own header: the demo identities "now live in demo-personas.ts, because the SEED needs them too". The file only imports the persona and provisions it; the constant, phone_number included, is declared next door. The path is what was stale, so the path is what moved. This is the one change that adds a cited source (309 → 310).
  • Row 3 is the mirror of row 2 and went the other way, deliberately. The same item ALREADY anchors packages/spec/src/identity/membership-role.ts#BUILTIN_MEMBERSHIP_ROLES two rows above, so re-pointing this one at the spec too would have been a duplicate. This citation is about the object's role select, and what sys-member.object.ts declares is the object.

No #symbol was dropped, and no floor moved (acceptance item 3)

areas/identity-auth.json's census is 83 against a floor of 82 — one of headroom — so this was measured, not assumed. The per-file census is identical before and after, 17/17 files:

node scripts/check-platform-checklist.mjs --anchor-census
  before vs after: the 17 per-file counts are byte-identical; only the summary line moves
  587/633 resolved, plus 46 on the named residual   ->   600/633 resolved, plus 33

That is the mechanism, not luck: the floor population is resolved + residual, so a repair moves an occurrence from one side to the other and leaves the per-file count where it was. The bare gate says it in its own words — 17 file floors held. scripts/checklist-symbol-anchor-baseline.json is untouched.

Rows left by repair, and the ceiling came down with them (acceptance items 1 and 4)

SHARED_RESOLVER_RESIDUAL 46 rows → 33; SHARED_RESOLVER_RESIDUAL_CEILING 46 → 33, in the same edit. The header's tallies are re-counted off the surviving rows rather than adjusted by hand: string-substring 21 → 12, import-only 8 → 6, member-access 3 → 2, detector-artifact 1 → 0, bad-citation 38 → 25; accept-set stays 8 and is untouched.

The detector-artifact block is kept at zero rows on purpose, carrying the ruling above — the shape reading is what a future author needs, and deleting it would delete the reason this row is not a detector bug.

Positive control (acceptance item 3) — two legs, opposite directions

Both legs mutate the committed tree, prove the mutation landed on disk before any verdict is read, restore with git checkout HEAD -- PATH under an EXIT INT TERM trap on an absolute path, and prove 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 through the shared resolver. Row 1's repaired citation was re-pointed to a symbol areas/access-security.json does not declare (on-disk proof: target text before=1 after=0, injected marker before=0 after=1). Gate exit 1:

areas/identity-auth.json: ABSENT SYMBOL - `docs/qa/platform-checklist/areas/access-security.json#itemsAblationNotDeclared`:
  `itemsAblationNotDeclared` is not declared in docs/qa/platform-checklist/areas/access-security.json
  by `scripts/symbol-anchors.mjs#symbolResolutionClass`

Restored (blob f6baec3c... == 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 on THIS SAME FILE still reds. One of the two accept-set rows this slice deliberately leaves behind (public-auth-features.ts#sys_user) 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 4ae200e4... == HEAD, git diff HEAD empty), back to exit 0. So areas/identity-auth.json is still swept and its residual rows still fire — the 13 left this ledger by repair, not because the document went dark.

Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack re-derived against the real changed set (2 committed paths, +42/-33) yields 31 families — the same count as the first slice, on a different path set.

scripts/check-platform-checklist.mjs is itself a gate, so both halves were run separately, not only the aggregate:

  • bare invocation exit 0OK — 15 areas, 264 items … symbol anchors: 600/633 resolved … 33 on the named residual, 17 file floors held
  • --self-test exit 0 — 221 assertions
  • pnpm check:platform-checklist (which chains checklist-select --self-test in front of both) exit 0

One family reported exit 3 — PREREQUISITE NOT MET, which is not a finding: @objectstack/lint run check:doc-formula-expressions wants @objectstack/formula and @objectstack/lint built.

No import relationship changed and no TypeScript program's view moved — the diff is one ESM gate script's data and comments plus one JSON document, neither of which any tsconfig includes — so no per-package typecheck is owed beyond what the derivation already places.

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

Changeset

No changeset: nothing published moves. Measured rather than assumed — the diff touches only repo-root scripts/ and docs/qa/, neither of which is inside any package directory, so no package manifest's files[] can ship either path. skip-changeset applies.

Acceptance notes


Generated by Claude Code

…rs and drain their residual rows

The second slice of the SHARED_RESOLVER_RESIDUAL drain:
areas/identity-auth.json, 13 rows, 13 anchor occurrences — the largest
single-file block of the bad-citation rows the first slice left behind.

All 13 are genuinely wrong citations, re-pointed. None is an accept-set
case; that file's 2 accept-set rows are deliberately left standing and
are a different card's.

SHARED_RESOLVER_RESIDUAL 46 rows -> 33 and
SHARED_RESOLVER_RESIDUAL_CEILING 46 -> 33 in the same edit. The header's
shape and verdict tallies are re-counted with the rows. No file floor
moved and no anchor was dropped: the per-file census is identical, 17/17.

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 10:58
@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 de20633 Sep 19, 2026
37 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-18104-drain-identity-auth branch September 19, 2026 11:29
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