Skip to content

chore(devx): migrate the scripts/** line citations that name no tracked file to file-level anchors (#15809) - #16301

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-15809-scripts-line-citations-migration
Sep 6, 2026
Merged

chore(devx): migrate the scripts/** line citations that name no tracked file to file-level anchors (#15809)#16301
baozhoutao merged 5 commits into
mainfrom
claude/issue-15809-scripts-line-citations-migration

Conversation

@claude

@claude claude Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Part of #15809.

The card measured 128 live line citations in scripts/** comment prose, of
which 96 named no tracked file and so were declined by the corpus registered in
PR #15806 (judgeUntrackedLineAnchors: false). This migrates 81 of them by that
PR's own method, enumerates the rest, and leaves the flag alone. #15809 is not
closed here — the residual belongs to triage.

1. The enumeration came first

The corpus counted the declined citations and printed only a number, so nobody
could work the residual down and a residual that MOVED read exactly like one
that shrank. sweepCorpus now returns declined beside findings and
counts — file, line, citation text and a shape — and

node scripts/check-scripts-symbol-anchors.mjs --list-unresolvable

prints them with a tally. It is a listing, never a verdict: it exits 0 whatever
it prints, exactly as --list does, and runCheck() is still the only failing
arm.

Re-derived on this tree (the card's shape table was taken on 5315098df, before
the corpus landed):

shape card, on 5315098df measured here, on bda7b7c83
bare filename 66 63
continuation with no path of its own 22 18
directory-qualified but untracked 11 14
tilde form 1 1
total 96 96

The total reproduces exactly; the split does not, which is why it was
re-derived. declinedShape classifies by how a citation was WRITTEN, never by
the path it borrowed — a continuation and a tilde form both inherit whatever
path preceded them on the line, so classifying by path first files them under a
file their author never wrote.

⚠️ One correction to the dispatch brief: the largest single concentration —
23 rows — is scripts/check-durability-degradation-log-level.mjs, NOT
scripts/check-system-context-census.mjs (which carries 4). The 23 were free to
edit and are migrated.

2. The migration

file before migrated residual (held elsewhere)
scripts/check-durability-degradation-log-level.mjs 23 23 0
scripts/symbol-anchors.mjs 15 15 0
scripts/doc-line-anchors.mjs 11 11 0
scripts/pr-labels.mjs 8 8 0
scripts/check-system-context-census.mjs 4 0 4 — PR #16215
scripts/check-docs-section-name.mjs 3 0 3 — in-flight #15776
scripts/check-runtime-services-index.mjs 3 3 0
scripts/check-tenant-audit-census.mjs 3 3 0
scripts/cross-package-test-inputs.mjs 3 0 3 — PR #16215
scripts/docs-audit/affected-docs.mjs 3 0 3 — in-flight #15776
scripts/check-cli-test-child-env.mjs 2 2 0
scripts/check-dispatcher-error-vocabulary.mjs 2 2 0
scripts/check-settings-bind-window.mjs 2 2 0
scripts/audits/14096-tenancy-ledger-namespace-regexp-census.mjs 1 1 0
scripts/audits/14423-unbound-declarations-before-count.mjs 1 1 0
scripts/check-adr-links.mjs 1 1 0
scripts/check-changeset-no-major.mjs 1 1 0
scripts/check-console-injection.mjs 1 1 0
scripts/check-doc-anchors.mjs 1 1 0
scripts/check-engine-double-contract.mjs 1 1 0
scripts/check-live-db-isolation.mjs 1 1 0
scripts/check-overlay-whitelist-table.mjs 1 1 0
scripts/check-platform-checklist.mjs 1 1 0
scripts/check-type-check-coverage.mjs 1 0 1 — in-flight #12511
scripts/check-workflow-status-functions.mjs 1 1 0
scripts/objectui-changeset-digest.mjs 1 1 0
scripts/pm/check-half-states.mjs 1 0 1 — PR #16202
total 96 81 15

Four repairs, one per shape, all of them PR #15806's method:

  • Dated census rows name the file as a file-level anchor and keep the number
    beside it as data. The durability gate's two seam tables gain a try line
    column of their own, and a bare engine.ts becomes
    packages/objectql/src/engine.ts — never a guess, because the prose beside
    every one of them already said which package.
  • Tracked targets whose prose names the symbol too become symbol anchors the
    gate now resolves:
    packages/objectql/src/plugin.ts#runGovernanceInventory,
    packages/plugins/plugin-audit/src/audit-writers.ts#resolveWriteLocale,
    packages/objectql/src/engine.ts#cascadeDeleteRelations,
    scripts/check-system-context-census.mjs#UNENFORCED_TEXT_COUNTS.
    Resolved symbol anchors in the corpus: 21 before, 27 after.
  • Illustrations take the angle-bracket placeholder spelling
    scripts/symbol-anchors.mjs#ANCHOR_GRAMMAR already uses.
    scripts/symbol-anchors.mjs and scripts/doc-line-anchors.mjs are the two
    files that DEFINE what a line citation looks like, so every example in them
    was a citation of its own; they now exhibit the shape without writing one, and
    each says so in a ⚠️ line so a later author does not "correct" it back.
  • Third-party and dependency sources (codelytv/pr-size-labeler,
    actions/labeler, @oclif/core, @changesets/pre) name the repo, the file
    and the pinned line as prose. No in-repo resolver could ever check them, and a
    pinned upstream line is provenance rather than a pointer.

Not one number is repaired or repointed. Every digit that was inside an
anchor is still on its page, as data — that is the whole of the #15806 method
and the reason it loses nothing.

3. The flag decision, and its fence

judgeUntrackedLineAnchors stays false.

The fence this work was dispatched under: flip it only if the residual after
migration is ZERO and the corpus self-test pins the flip. The residual is 15,
so the fence does not open. Reading it row by row matters more than the number:

scripts/check-docs-section-name.mjs:1470   concept.mdx:426          [bare-filename]
scripts/check-docs-section-name.mjs:1508   doc-pages.mdx:257        [bare-filename]
scripts/check-docs-section-name.mjs:1564   forms.mdx:183            [bare-filename]
scripts/check-system-context-census.mjs:1387  rest-server.ts:1267   [bare-filename]
scripts/check-system-context-census.mjs:1443  `:274`                [continuation]
scripts/check-system-context-census.mjs:1570  rest-server.ts:1267   [bare-filename]
scripts/check-system-context-census.mjs:2127  `:3`                  [continuation]
scripts/check-type-check-coverage.mjs:353  engine.test.ts:2547/2577 [bare-filename]
scripts/cross-package-test-inputs.mjs:164  `:102`                   [continuation]
scripts/cross-package-test-inputs.mjs:166  `:92`                    [continuation]
scripts/cross-package-test-inputs.mjs:167  `:484-485`               [continuation]
scripts/docs-audit/affected-docs.mjs:4709  rest-server.ts:5324,5376 [bare-filename]
scripts/docs-audit/affected-docs.mjs:4710  rest-server.ts:5694,5722 [bare-filename]
scripts/docs-audit/affected-docs.mjs:4784  rest-server.ts:5661      [bare-filename]
scripts/pm/check-half-states.mjs:16407     `:234`                   [continuation]

Every one of the 15 is residual by EXCLUSION, not by ambiguity. All six
files are held open by another lane right now — three of them by PR #16215, one
by PR #16202, three by the in-flight work on #15776, one by the in-flight work
on #12511 — and this card's file surface excludes them by name. Zero citations
were left behind because the prose did not say which file they meant.

That distinction is the whole decision. Flipping the flag today would make this
gate red for the length of somebody else's pull request, over citations this PR
was told not to touch — the permanently-red gate the card itself argued against.
Flipping it after those six files are migrated is a one-line change with a case
to pin it, and --list-unresolvable is the worklist that gets it there.

4. Corpus readings

before, bda7b7c83 after, this head
unresolvableLineCitation 96 15
anchors resolved 2813 2872
symbol anchors 21 27
file-level anchors 2792 2845
line anchors on tracked targets surviving 0 0
scripts swept 222 223

⚠️ The swept population moves 222 to 223 because origin/main was merged in
mid-branch and brought scripts/sync-release-index-currency.mjs with it. That
file adds no declined citation — the residual read 15 both immediately before
and immediately after the merge — so the 96 to 15 delta is this PR's alone.

5. Tests

The pin is exercised, not assumed. Three cases hold the enumeration equal to the
counter, to the file/line/text a residual list needs, and to the shape
classification (self-test floor 26 → 29); four more hold each arm of
declinedShape (floor 63 → 67).

Ablation — mutation proven on disk, restore proven byte-identical to HEAD,
each leg anchored on a grep count of the text injected and the text removed:

removed-text count: 1 → 0     injected-text count: 0 → 1
mutated blob a1272fe9d != HEAD blob 408722486
ABLATED  EXIT=1  ❌ the declined ENUMERATION must equal the declined COUNT, got 0 vs 2
restored blob 408722486 == HEAD blob 408722486   (git diff HEAD empty)
RESTORED EXIT=0  ✅ check-scripts-symbol-anchors --self-test

Direction as predicted: turns red, and names the case. A first attempt at the
same ablation was a no-op — perl -0pi with a \Q…\E block matched nothing and
still exited 0 — and was caught by the on-disk blob comparison rather than by
the run's colour, which is exactly why that check runs before the verdict is
read.

6. Gates

Derived on the final tree with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
(54 commands over the 22-path change set, three-dot against the merge base) and
reconciled with --ran:

Run reconciliation — 54 derived, 54 run, 0 NOT-MEASURED, 0 UNRUN.
✓ dispatch-gates --ran: 54 derived famil(ies) accounted for — 54 run, 0 NOT-MEASURED.

All 54 exit 0. The list is the derivation's own, not a hand-kept one, and
includes every gate whose family this diff touches — among them
check:durability-log-level, check:platform-checklist, check:doc-anchors,
check:comment-mask-corpus, check:nul-bytes, check:cross-package-test-inputs,
check:pm-dispatch-gates and both self-tests of the two files carrying the
mechanism (check-scripts-symbol-anchors.mjs --self-test,
symbol-anchors.mjs --self-test).

Every touched gate is a gate whose own plain run and --self-test are in that
54, and all of them pass. The edits are confined to // and /* */ comment
text; the one file whose header moved most
(check-durability-degradation-log-level.mjs, 23 citations) reads
packages/** TypeScript sources for its census and its own comments for
nothing, and its verdict is unchanged.

The repo-wide scan ran too, not just the derived families:
pnpm lint (eslint . --no-inline-config) exits 0 with no output over the
whole tree. It ran at 5e66dc83b; the one commit after it is comment-only in a
single file, re-linted on its own at this head, also 0.

No changeset: this PR publishes nothing from any package — 22 files, all under
scripts/**, all comment prose plus one listing flag. skip-changeset applied.
⛔ No file under content/docs/releases/ is touched.


🤖 Generated with Claude Code

https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8


Generated by Claude Code

…s, not just their count

`judgeUntrackedLineAnchors: false` waives a citation that names no tracked
file, and until now the only trace was a number on the green line. A number
says a residual exists without saying where: it cannot be worked down, and a
residual that MOVED reads exactly like one that shrank.

`sweepCorpus` now returns `declined` beside `findings` and `counts` — one row
per waived citation, carrying the file, the line, the citation text and a
shape (`bare-filename` / `directory-qualified` / `continuation` / `tilde`).
`declinedShape` classifies by how the citation was WRITTEN, never by the path
it borrowed: a continuation and a tilde form inherit whatever path preceded
them on the line, so classifying by path first would file them under a file
their author never wrote.

`check-scripts-symbol-anchors.mjs --list-unresolvable` prints those rows and a
tally by shape. It is a listing, never a verdict — it exits 0 whatever it
prints, exactly as `--list` does, and `runCheck()` remains the only failing
arm.

Pinned: three cases hold the enumeration equal to the counter, to the
file/line/text a residual list needs, and to the shape classification
(floor 26 → 29); four more hold each arm of `declinedShape` (floor 63 → 67).

Part of #15809.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
…st carriers

`check-durability-degradation-log-level` (23), `symbol-anchors` (15),
`doc-line-anchors` (11) and `pr-labels` (8) carried more than half the
citations that name no tracked file, and each shape gets the repair its own
kind admits:

- DATED CENSUS ROWS name the file as a file-level anchor and keep the number
  beside it as data, losing no digit — the `#15806` method. The durability
  gate's two seam tables gain a `try line` column of their own, and `objectql
  engine.ts` / `metadata-protocol protocol.ts` become the full tracked paths
  the gate's own output actually prints. One of them binds tighter still:
  `packages/objectql/src/engine.ts#cascadeDeleteRelations` is now a resolved
  symbol anchor.
- ILLUSTRATIONS take the angle-bracket placeholder spelling `ANCHOR_GRAMMAR`
  already uses. `symbol-anchors.mjs` and `doc-line-anchors.mjs` are the two
  files that DEFINE what a line citation looks like, so every example in them
  was a citation of its own; they now exhibit the shape without writing one,
  and say why in a ⚠️ line so a later author does not "fix" it back.
- THIRD-PARTY SOURCES (`codelytv/pr-size-labeler`, `actions/labeler`) name the
  repo, the file and the pinned line as prose. No in-repo resolver could ever
  check them, and a pinned upstream line is provenance rather than a pointer.

⛔ No number is repaired or repointed anywhere in this commit: every digit that
was in an anchor is still on the page, as data.

Corpus reading: 96 → 39 unresolvable citations.

Part of #15809.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
… residual

The rest of the population #15809 measured, one repair per shape:

- TRACKED TARGETS the surrounding prose already names become file-level
  anchors, and where the prose names the symbol too they become symbol anchors
  the gate now resolves — `packages/objectql/src/plugin.ts#runGovernanceInventory`,
  `packages/plugins/plugin-audit/src/audit-writers.ts#resolveWriteLocale`,
  `scripts/check-system-context-census.mjs#UNENFORCED_TEXT_COUNTS`. A bare
  `engine.ts` was never ambiguous where the prose said which package.
- THIRD-PARTY AND DEPENDENCY SOURCES (`@oclif/core`, `@changesets/pre`) name
  the package, the file and the pinned line as prose. Nothing in this tree can
  resolve them, and a pinned upstream line is provenance, not a pointer.
- ILLUSTRATIONS take the angle-bracket placeholder spelling.

⛔ Again, no number is repaired or repointed: every digit is still on its page.

The residual is 15 citations across six files, and every one of them is a file
another lane holds OPEN — three by PR #16215, one by PR #16202, three by the
in-flight #15776, one by #12511. NOT ONE is a genuinely ambiguous abbreviation.

⚠️ `judgeUntrackedLineAnchors` therefore stays `false`. The fence this work was
dispatched under flips it only when the residual is ZERO and a self-test pins
the flip; flipping it over 15 citations in files this PR may not touch would
make the gate permanently red for the length of somebody else's pull request —
the exact shape the card argued against. `--list-unresolvable` now prints that
residual, so the next author inherits a worklist rather than a count.

Part of #15809.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
`--list-unresolvable` is the live instrument; a count written in prose is a
dated record, and this file is the one arguing that a number in prose outlives
the measurement it quoted.

Part of #15809.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 6, 2026
@github-actions github-actions Bot added the size/m label Sep 6, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 6, 2026 13:20
@baozhoutao
baozhoutao enabled auto-merge September 6, 2026 13:20
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit 2e8a708 Sep 6, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-15809-scripts-line-citations-migration branch September 6, 2026 14:13
baozhoutao pushed a commit that referenced this pull request Sep 6, 2026
…vel anchors

Second round of the scripts/** unresolvable-citation migration PR #16301
started. Two of the six held files freed since that PR landed --
check-docs-section-name.mjs and docs-audit/affected-docs.mjs (PR #16300),
check-type-check-coverage.mjs (PR #16295) -- so their 7 citations migrate
now by the same method: the file named as a file-level anchor, the number
kept beside it as data, no digit repaired or repointed.

- check-docs-section-name.mjs: concept.mdx:426, doc-pages.mdx:257 and
  forms.mdx:183 each resolve to exactly one tracked file under
  content/docs/** (forms.mdx is ambiguous by basename alone -- two files
  share it -- but only content/docs/ui/forms.mdx has a line 183 carrying
  the cited "sections": [/* ... */] shape).
- check-type-check-coverage.mjs: engine.test.ts:2547/2577 resolves to
  packages/services/service-automation/src/engine.test.ts, named by the
  surrounding prose ("service-automation's note").
- docs-audit/affected-docs.mjs: three rest-server.ts citations resolve to
  packages/rest/src/rest-server.ts, the only tracked file of that name.

The corpus residual (scripts/check-scripts-symbol-anchors.mjs
--list-unresolvable) drops from 15 to 8, all 8 still held by open PRs
(#16215, #16202) -- none an ambiguity. judgeUntrackedLineAnchors stays
false per the #15809 fence (flips only at residual zero). Header prose
updated to record both dated readings.

Part of #15809.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m 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