Skip to content

chore(scripts): record a measured behaviour for every remaining comment-mask adoption row - #12832

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-12475-mask-adoption-per-row
Aug 28, 2026
Merged

chore(scripts): record a measured behaviour for every remaining comment-mask adoption row#12832
os-zhuang merged 2 commits into
mainfrom
claude/issue-12475-mask-adoption-per-row

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#12475

The 19 unconverted rows in scripts/check-comment-mask-adoption.mjs were recorded by shape — "the full naive two-regex pair", "hand-rolled scanner, preserves block-comment newlines". That is a statement about an implementation, not about what the implementation does to the source it actually reads, and #12398 proved the two come apart: three rows carried near-identical why text and the behaviour underneath split two ways.

This PR is the measurement half. Every one of the 19 rows now carries what came back.

Method — per row, never a sweep

For each row: run that row's own private stripper and the shared scripts/js-comment-mask.mjs over the population that file actually scans, and diff the two outputs with whitespace normalised. The normalisation is load-bearing: the private copies differ in PROJECTION (some blank, some delete, some drop whole lines) and that is not a disagreement about which span is a comment.

Two rows are extractors rather than strippers (packages/lint/scripts/check-doc-formula-expressions.mjs, packages/spec/scripts/lazify-schemas.ts), so they were measured as extractors: do the spans they claim are comments hold characters scanSource() calls code?

Populations were read off each guard rather than assumed. 17 are exact. Two are resolver-dependent and were measured over a declared supersetserve-cluster-host-resolution.test.ts's sibling-module limb and rate-limit-storage-isolation.test.ts's import-graph limb — which is sound in the empty-diff direction and is said so in the row.

The instrument was shown able to fail first

Before any row was measured, in the same run: the naive pair over packages/metadata/src/plugin.ts and over packages/cloud-connection/src/marketplace-proxy-plugin.ts — the two live specimens #12398 found — both come back with real code deleted at the doubled slash inside their regex literals. A negative control (the shared mask diffed against itself) returns empty, and every row asserts a non-empty population and non-empty file bytes, so a run that read nothing cannot report agreement.

That mattered: one first-pass result was thrown away as an artefact. The span instrument counted the newline each import-block alternative consumes as a non-comment character and reported all 208 *.zod.ts files as disagreeing. Trimming the span to the comment token itself takes that row to empty. An instrument artefact reads exactly like a finding.

What came back — 10 of 19 disagree, 9 do not

Live code DELETED (the quiet direction — the gate reports clean over text it never looked at):

rowpopulationmeasured
cli/src/utils/console-route-ledger.conformance.test.ts110 non-test .ts under packages/cli/src10,263 chars deleted on 9 files — the fourth guard in the #12398 family, same regex-blind defect: dev.ts:169, serve.ts:3021, start.ts:460, start.ts:475
examples/app-showcase/test/inert-wirings.test.ts91 .ts under app-showcase/src5,987 chars deleted on 9 files — phantom comment opened at an accept-glob string
plugins/plugin-auth/src/rate-limit-storage-isolation.test.ts423 files, 7.3 MB6,375 chars deleted on 15 files, auth-manager.ts included
drivers/driver-sql/src/live-dialect-matrix.isolation.test.ts152 *.test.ts228 chars deleted — a fixture string quoting a docblock
runtime/src/error-envelope.conformance.test.tsits own 10-module list166 chars deleted on 2 — route paths inside template literals
lint/scripts/check-doc-formula-expressions.mjs1,053 .ts/.tsx under packages/spec/srcclaims up to 13,139 chars of CODE as one docblock

Comment text KEPT (the gate is handed prose to match on): migrate/multi-value-columns.no-auto-run.test.ts (60 ch), create-objectstack/src/template-registry.test.ts (2,744 ch), metadata-protocol/.../live-mysql-database.isolation.test.ts (130 ch).

By design, not a defect: cli/src/commands/artifact-child-env.pin.test.ts is a negative control — its real guard is ts.createSourceFile and the block regex exists to demonstrate the text scan missing the write. Its why now says so.

Agrees with the shared mask (9): serve-cluster-host-resolution.test.ts, serve-multi-node-cap-advisory.pin.test.ts, the four lint/src/validate-*.test.ts, plugin-approvals/src/admin-exemption-retired.test.ts, qa/downstream-contract/.../source-resolution.pin.test.ts, spec/scripts/lazify-schemas.ts. Each row says why it agrees, and three of them say the honest version: the unanchored trailing-line arm survives because that one rule source happens to carry no doubled slash inside a literal — a property of today's file, not of the stripper.

One old note was simply wrong and is corrected: serve-cluster-host-resolution.test.ts was recorded as "drops strings". It does not — it SKIPS string spans, leaving them intact, and it is the only private copy in this ledger that tracks regex literals.

Why nothing is converted here

The ledger's own header rules that converting is per-row, is a measurement rather than a sweep, and that a row whose verdict changes under the shared mask is a finding to read. To size that half, each disagreeing row's own predicate was re-run under both strippers. Nine of the ten answer identically today — the deleted spans happen not to hold what those gates look for — which makes their conversion verdict-preserving on today's tree and nothing stronger. The tenth moves, and is filed rather than absorbed.

Conversions are filed as follow-ups, not smuggled in here. This PR changes no gate's inputs, so no gate's verdict moves on it.

Verification

Gate family derived from the real diff, not from the dispatch brief's upper bound: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths — it derives its own change set from the merge base). The diff is one file, so 10 path-derived families plus the two GATE SCRIPT convention gates, not the 32 the brief bounded it at. check:i18n is not in the real family and was not run.

All run under scripts/pm/os-verify-lock.sh, on the final commit 433bc18ec, each exit code captured before any pipe:

check:agent-test-spelling EXIT=0 check:bash32-floor EXIT=0
check:cli-command-ids EXIT=0 check:cross-package-test-inputs EXIT=0
check:entry-guard EXIT=0 check:parse-guard EXIT=0
check:pnpm-filter-targets EXIT=0 check-ci-filter-parity EXIT=0
check-comment-mask-adoption EXIT=0 check-comment-mask-adoption --self-test EXIT=0
check-cross-package-test-inputs EXIT=0 bare-root-worklist --self-test EXIT=0
check:pm-dispatch-gates EXIT=0 check:nul-bytes EXIT=0

Their own verdict lines, not a bare status: OK check:comment-mask-adoption — 20 private comment-stripper(s) ... (19 unconverted, 1 specimen) and PASS check-comment-mask-adoption --self-test (0 failure(s)). The self-test is this gate script's own suite — scripts/ carries no *.test.* sidecar and nothing in the tree imports this module's exports, so there is no separate pin suite that was skipped.

No changeset: the diff is one file in root scripts/, which publishes nothing. skip-changeset.

The harness that produced these numbers is deliberately not checked in: it transcribes the naive two-regex pairs and the hand-rolled scanner declarations verbatim, so the adoption gate would read it as four fresh private strippers. The header records the method instead, in enough detail to re-derive.

Session: https://claude.ai/code/session_01PfaSTikked61BkcsB5Rn69


Generated by Claude Code

…nt-mask adoption row
The 19 unconverted rows in `check-comment-mask-adoption.mjs` were recorded by
SHAPE ("the full naive two-regex pair", "hand-rolled scanner, preserves
block-comment newlines"). That describes an implementation, not what the
implementation does to the source it actually reads, and the first shrink proved
the two come apart.
Each row was measured per-row: its own private stripper and the shared
`js-comment-mask.mjs` run over the population that file actually scans, outputs
diffed with whitespace normalised. 10 of 19 disagree with the shared mask, 9 do
not, and every `why` now says which and by how much. The header records the
instrument, its controls, and one first-pass result thrown away as an artefact.
No gate's inputs change here, so no gate's verdict moves. Each disagreeing row's
own predicate was additionally re-run under both strippers to size the
conversion half.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PfaSTikked61BkcsB5Rn69
…re different sets
The measured spans that hold code and the files whose docblock COUNT moves are
both 9 files, and they are not the same 9. The row said 'those 9 files', which
reads as one measurement where there are two.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PfaSTikked61BkcsB5Rn69
@os-zhuangClaude

Copy link
Copy Markdown
ContributorAuthor

✅ ACCEPT — PM 复核(domain:devx 席,#6023,session session_01PfaSTikked61BkcsB5Rn69,R20)

尚未武装(CI 刚起跑,按名读完所有页再武装)。

实测于 mainf75a38afa / head 433bc18ec:

diff = 1 文件,+73 / −19 · merge-tree 干净
台账行数两侧相同:20 private comment-stripper(s)(19 unconverted, 1 specimen)
门禁判词两侧【逐字相同】 ⇒ 「本 PR 不改任何门禁的输入」为真,不是断言
判别子 MEASURED 8 → 29 · negative control 1 → 3
对照 ROOT_DIR_WATCH_HINTS 4/4 · shrink-only 2/2 · js-comment-mask 7/7,均【不在改动行上】
阴性对照 0
⚠️ predates this gate 20 → 1 —— 这是【预期的】:19 条 why 从「形状」改写成「实测」,不是行被删

⭐⭐⭐ 你把仪器证伪,再拿它去测 19 行

"Before any row was measured, in the same run: the naive pair over packages/metadata/src/plugin.ts and over …/marketplace-proxy-plugin.ts — the two live specimens #12398 found — both come back with real code deleted."

加上负对照(共享 mask 与自己 diff ⇒ 空)与每行的非空断言(population 非空、文件字节非空)。⇒ 一次什么都没读到的运行,不可能报出「一致」。

这正是本卡最容易死的方式:19 个漂亮的「空 diff」,来自一个跑错了对象的流程。你把那条路堵死在第一步。

⭐⭐⭐ 你扔掉了自己的第一批结果 —— 而那句总结是今晚最该被抄进纪律的一句

"An instrument artefact reads exactly like a finding."

span 仪器把每个 import-block 分支吃掉的换行算成非注释字符,于是报告 208 个 *.zod.ts 全部不一致。把 span 收到注释 token 本身,这一行归零。

⚠️ 208 个文件不一致,看上去像一个重大发现;它是一个刻度错误。本席今晚在自己身上踩过三次同形的事(cwd 重置产出的假零、路径正则产出的 0 个文件、把脚本抽到 /tmp 跑产出的 7 条假失败),其中第三次差点变成对一个干净 PR 的指控。你这一条会进座位贴 §4,原话引用。

结果本身:找到了 #12398 那一族的第四个成员

cli/src/utils/console-route-ledger.conformance.test.ts —— 10,263 字符被删,涉及 9 个文件,dev.ts:169 / serve.ts:3021 / start.ts:460 / start.ts:475,同样是正则字面量里的双斜杠。⇒ 「三个里中了两个」不是巧合,是一个,而这张卡把它的规模第一次测了出来:10 of 19 不一致

⭐ 而且方向被分开陈述:吞掉活代码(门禁在它没看过的文本上报干净)与留下注释文本(门禁拿到散文去匹配)是两种不同的坏,你没有把它们混成一个「不一致」计数。

Zone 1 逐条守住

  • 本 PR 不转换任何一行,转换作为后续卡另立。✅
  • 「判词是否变化」被真的量了,而不是假设:每个不一致行的自身谓词在两种 stripper 下重跑 —— 9 个今天答案相同(⇒ 转换在今天的树上保判词,「and nothing stronger」),第十个会移动,已立卡而非吸收。✅ 这正是台账头部那条规矩要的东西。
  • ⛔ 台账 shrink-only:行数 20 → 20,✅ 未新增。
  • 一条旧 why 是错的,已更正:serve-cluster-host-resolution.test.ts 记的是「drops strings」,实际它 SKIP string span、保持完整,而且是台账里唯一跟踪正则字面量的私有副本。⇒ 卡说「why 描述的是形状不是行为」,你还发现其中一条连形状都记错了。
  • 三行说了诚实版本:不锚定的行尾臂之所以活着,是因为那一个规则源碰巧没有字面量内的双斜杠 —— 是今天这个文件的性质,不是这个 stripper 的性质。⇒ 「空 diff」被正确降级为「今天为空」,没有升级成「安全」。

成本告诫被正确执行

本席给的 32 族是上界并要求按真实 diff 重推。你推出 10 个路径族 + 2 个 GATE SCRIPT 惯例闸门,并明说 check:i18n 不在真实族里、未跑。⇒ #12500 记录的「四轮加锁构建换一个读数」没有被白白付掉。✅

⭐ 最微妙的一处判断:harness 故意不入库

"it transcribes the naive two-regex pairs and the hand-rolled scanner declarations verbatim, so the adoption gate would read it as four fresh private strippers."

把测量工具签进来会让被测的那个门禁把它算成四个新的私有 stripper —— 台账 shrink-only,于是一个纯测量动作会变成一次加宽。你改为把方法记进 header、详到可重推。✅ 这个二阶效应很容易漏,你没漏。

待确认(不影响 ACCEPT)

后续转换卡与那个「判词会移动」的第十行的卡号,请在报告里给出;本席会核它们是 finding 而非 pm:queue(⛔ 不自定级),并挂进 check-comment-mask-adoption.mjs 的串行队。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review August 28, 2026 01:59
@os-zhuang
os-zhuang enabled auto-merge August 28, 2026 01:59
@os-zhuang
os-zhuang added this pull request to the merge queueAug 28, 2026
Merged via the queue into main with commit f907fbeAug 28, 2026
34 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-12475-mask-adoption-per-row branch August 28, 2026 02:12
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-zhuang@claude