Uh oh!
There was an error while loading. Please reload this page.
chore(scripts): record a measured behaviour for every remaining comment-mask adoption row - #12832
Conversation
…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-zhuang
commented
Aug 28, 2026
✅ ACCEPT — PM 复核( |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#12475
The 19 unconverted rows in
scripts/check-comment-mask-adoption.mjswere 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-identicalwhytext 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.mjsover 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 charactersscanSource()calls code?Populations were read off each guard rather than assumed. 17 are exact. Two are resolver-dependent and were measured over a declared superset —
serve-cluster-host-resolution.test.ts's sibling-module limb andrate-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.tsand overpackages/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.tsfiles 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):
cli/src/utils/console-route-ledger.conformance.test.ts.tsunderpackages/cli/srcdev.ts:169,serve.ts:3021,start.ts:460,start.ts:475examples/app-showcase/test/inert-wirings.test.ts.tsunderapp-showcase/srcplugins/plugin-auth/src/rate-limit-storage-isolation.test.tsauth-manager.tsincludeddrivers/driver-sql/src/live-dialect-matrix.isolation.test.ts*.test.tsruntime/src/error-envelope.conformance.test.tslint/scripts/check-doc-formula-expressions.mjs.ts/.tsxunderpackages/spec/srcComment 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.tsis a negative control — its real guard ists.createSourceFileand the block regex exists to demonstrate the text scan missing the write. Itswhynow says so.Agrees with the shared mask (9):
serve-cluster-host-resolution.test.ts,serve-multi-node-cap-advisory.pin.test.ts, the fourlint/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.tswas 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:i18nis not in the real family and was not run.All run under
scripts/pm/os-verify-lock.sh, on the final commit433bc18ec, each exit code captured before any pipe:Their own verdict lines, not a bare status:
OK check:comment-mask-adoption — 20 private comment-stripper(s) ... (19 unconverted, 1 specimen)andPASS 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