Skip to content

fix(census): the continuation-scope docblocks stop crediting a guard that cannot fire there - #9632

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-9216-continuation-scope-guard
Sep 16, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-9216-continuation-scope-guard

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Fixes #9216

What was wrong

carryScope in scripts/cross-file-line-citation-census.mjs ends continuation scope with line.trim() === ''. A JSDoc separator is * and a line-comment separator is //; neither trims to the empty string, so the guard cannot fire inside a block comment — which is where syntax 5's population actually lives.

Two docblocks nevertheless credited that guard for a blindness distance alone causes. The card graded this (b) violates a declared contract, and the contract is the guard's own sentence:

A BLANK line ends it: a citation and its continuation belong to one piece of prose, and crossing a paragraph is how a filename in one sentence captures a port number in the next.

Measured, not read — with a firing control in the same run

Three legs, one run, the middle one a firing control, so the empty result is a barrier and not a dead scanner:

truly-blank separator (markdown)  -> []
NO separator (FIRING CONTROL)     -> ["continuation apps/console/vite.config.ts:3000"]
JSDoc '   *' separator            -> ["continuation apps/console/vite.config.ts:3000"]
JSDoc ' *'   separator            -> ["continuation apps/console/vite.config.ts:3000"]
line-comment '//' separator       -> ["continuation apps/console/vite.config.ts:3000"]

trim('   *') === ''  ->  false
trim('//')   === ''  ->  false

⇒ the separator changes nothing. That identity is the finding.

The second half, on the fixture this repo itself pins. The DOCBLOCK fixture contains zero lines that trim to empty, so there is no paragraph break there for any guard to act on. Two ablations, both directions:

fixture as pinned            -> [601, 625, 640, 747, 865]
separator line deleted       -> [601, 625, 640, 747, 865]
separator made a REAL blank  -> [601, 625, 640, 747, 865]

:613 sits 8 lines below the only filename; CONT_WINDOW is 2.

⇒ :613 is out of scope on distance and on nothing else. "past a paragraph break" described something that never happened.

Tree-wide, since the census runs again

Baseline population is stable across this change (1271 rows before and after, every verdict bucket identical); only carvedOutSelf moves, 112 to 119, which is this file's own new fixture text being counted and printed by the self carve-out exactly as designed.

Two readings the card listed as not measured, now measured:

  1. What the guard removes today: 3 rows, all of them Markdown, none a block comment — ablate the guard tree-wide and the population goes 1271 to 1274. The three are two ports in AGENTS.md and a cron minute in content/docs/guide/ci-cd-pipeline.md. ⇒ the guard's entire measured yield is Markdown; inside JSDoc it contributes nothing.
  2. What extending it to delimiter-only lines would cost today: zero rows. Swapping the predicate for a delimiters-only one leaves the census output byte-identical (same md5 over --json --list-all). Positive control on that same comparison instrument, so the identity is a reading: widening CONT_WINDOW from 2 to 5 in the same harness moves the output (1271 to 1289).

What this PR changes — and what it deliberately does not

⛔ Behaviour is unchanged. The guard's code is byte-identical. The card reserved the question of whether the guard should reach a *-prefixed line as "a judgement with a cost, ⛔ not a repair to make on the way past", and this PR does not make it. It is now priced (item 2 above) for whoever does.

What changes is that the file's self-description is true, and the facts it asserts are re-derived by tests instead of remembered:

  • carryScope's docblock states the Markdown / block-comment split, names the reserved judgement, and points at NON_SUBSTANTIVE in the same file as the delimiters-only predicate such a change would need.
  • The syntax-5 docblock separates the two scope rules, which it had written as one mechanism.
  • CONT_WINDOW's docblock names distance as the sole cause of the blind sixth address.
  • New pin: the guard fires on a real blank line and does NOT fire on a JSDoc or // separator, each leg beside a firing control — so a later change to the predicate goes red here rather than being discovered by its effect on the census.
  • New pin: the fixture has zero lines that trim to empty, and deleting or blanking its separator does not move the reading.

⚠️ One in-place repair beyond the card's two halves, flagged rather than slipped in

CONT_WINDOW's docblock also carried a written-down count of what widening to 5 would admit. Re-derived here, it has moved in both size and composition while reading as live — the exact hazard AGENTS.md rule 9 names. Per that rule the figure is replaced by the command that re-derives it, not by a new figure.

⛔ This takes no position on the width. objectui#9083 owns that decision and is untouched here; it now reads a live instrument instead of a stale number.

Verification

run result
vitest run scripts/__tests__/cross-file-line-citation-census.test.ts 48 passed
same, plus check-new-cross-file-line-citations.test.ts (the only other consumer, by import) 82 passed
vitest run scripts/__tests__/markdown-test-inputs.test.ts 24 passed
pnpm lint:root exit 0, 0 errors over 367 files (count read from --format json; both changed files are in that population)
pnpm check:control-bytes exit 0
pnpm check:new-line-citations exit 0, 0 new citations added by this branch
pnpm check:comment-mask-corpus exit 0
pnpm check:test-path-roots exit 0
pnpm check:entry-guard exit 0
node scripts/check-changeset-presence.mjs exit 0 — its own verdict line: no source or published contract of a released package changed, so no changeset is owed
node scripts/check-governed-queue-guard.mjs --test NOT GOVERNED, 2 paths against 5 governed surfaces
census itself 6 of 6 control(s) passed -- this run IS a reading

⛔ ABLATION of the new pin, so it is not a green that cannot go red. Mutate the guard on disk to a delimiters-only predicate, prove the mutation landed, run the suite, restore:

old predicate occurrences: 1 -> 0
new predicate occurrences: 0 -> 1
mutated blob differs from HEAD: yes

Tests  1 failed | 47 passed (48)
FAIL  ... > that paragraph guard is INERT inside a block comment, and the docblocks may not claim it
AssertionError: expected [] to deeply equal [ Array(1) ]

RESTORED: byte-identical to HEAD (ac67128f32c5446ba36fbb363908c4a1266ada45)

Exactly one test moves, and it is the new one. Direction predicted before the run and observed: red.

Verification union run at 97b437565.

apps/console/vite.config.ts appears in the card's text and in this PR's fixtures as a cited example only; ⛔ it is not edited here.

维护者速读(草稿)

改了什么 — 一个普查脚本的三段自述文字,加两条新的 pin 测试。代码行为一个字节都没动。

为什么改 — 那个「空行结束引用作用域」的守卫,在 JSDoc 里根本触发不了( * 不会 trim 成空串),而两处文档偏偏把「跨段落」写成了某个地址读不到的原因 —— 真正的原因只是距离。门禁的自述必须为真,否则下一个读它的人会据此推理,而这已经发生过两次。

风险与代价(含回滚) — 风险极低:普查的输出前后逐项相同。回滚就是 revert 这一个 commit。唯一需要留意的是我顺手修掉了同一段文档里一个已经过期的数字,它是 objectui#9083 决策的输入 —— 我没有替它做任何决定,只是把「写死的数字」换成了「重新测量的命令」。

席位意见 — (留空,待席位定稿)

你要做的 — 确认一点:把那个过期数字换成「去重新测量」的写法,而不是换成新数字,是否符合你对 AGENTS.md rule 9 的意图。


🤖 Generated with Claude Code

https://claude.ai/code/session_015h79niBMyoB1xcaQje3uiz


Generated by Claude Code

…that cannot fire there

The blank-line paragraph guard in `carryScope` tests `line.trim() === ''`.
A JSDoc separator is `   *` and a line-comment separator is `//`; neither
trims to the empty string, so the guard is structurally inert inside a
block comment -- which is where syntax 5's population actually lives.

Two docblocks nevertheless credited it for a blindness that distance
alone causes. The pinned `DOCBLOCK` fixture contains ZERO lines that trim
to empty, so "past a paragraph break" describes nothing the scanner did:
`:613` is out of scope on distance 8 against `CONT_WINDOW` 2, and on
nothing else.

Behaviour is unchanged -- the guard's code is byte-identical. What
changes is that the file's self-description is now true, and the facts it
asserts are re-derived by tests rather than remembered:

- `carryScope`'s docblock states the Markdown/block-comment split and
  names the reserved judgement instead of implying coverage.
- The syntax-5 docblock separates the two scope rules, which were written
  as one.
- `CONT_WINDOW`'s docblock names distance as the sole cause of the sixth
  address, and drops a one-time count of what widening would admit --
  re-derived here and found to have moved in size and composition, per
  AGENTS.md #9. objectui#9083 still owns the width.
- New pin: the guard fires on a real blank line and does NOT fire on a
  JSDoc or `//` separator, each leg beside a firing control.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015h79niBMyoB1xcaQje3uiz
@github-actions github-actions Bot added the tests label Sep 16, 2026
@os-try-charles
os-try-charles marked this pull request as ready for review September 16, 2026 16:07
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 16, 2026
Merged via the queue into main with commit 15f0122 Sep 16, 2026
35 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-9216-continuation-scope-guard branch September 16, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants