Skip to content

refactor(devx): check-registry-log-declared consumes js-comment-mask's maskComments instead of a private wrapper - #15595

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-15561-registry-log-shared-masker
Sep 4, 2026
Merged

refactor(devx): check-registry-log-declared consumes js-comment-mask's maskComments instead of a private wrapper#15595
baozhoutao merged 2 commits into
mainfrom
claude/issue-15561-registry-log-shared-masker

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #15561

The card's premise, narrowed

The card reads "carries private maskComments/maskCode copies instead of js-comment-mask.mjs". On main that overstates the finding in one direction and understates the remedy in the other, so this PR does the narrow, provable half:

  • scripts/check-registry-log-declared.mjs:130 already imported { blank, scanSource } from ./js-comment-mask.mjs. There was never a second scanner here.
  • Its local maskComments was return blank(source, scanSource(source).comment);character-for-character the body of the module's own maskComments export (scripts/js-comment-mask.mjs:540). A private wrapper, not a private copy of the scanner. That one is deleted and the export imported.
  • Its local maskCode has no shared export to consume: js-comment-mask.mjs publishes scanSource, blank, stripComments and maskComments, and no comments+literals projection. It stays local, and its docblock now says why in one sentence — it composes scanSource's comment and literal flags through blank and carries no scanning logic of its own. Hoisting a shared maskCommentsAndLiterals is filed separately as [finding] hoist maskCommentsAndLiterals (comments+literals blank) into js-comment-mask.mjs + .d.mts #15594 (it changes a module three gates read; it is not a rider on a one-line refactor).

So premise_still_valid is partly: the maskComments half is real and fixed here; the maskCode half is a missing shared export, not a private copy.

Byte-identical proof

The point of the swap is that nothing about the gate's behaviour moves. Both of the gate's runs were captured on origin/main (954cb0b) and again on the refactor commit (1a49ea8), and diffed:

run diff vs main exit
node scripts/check-registry-log-declared.mjs 0 lines 0
node scripts/check-registry-log-declared.mjs --self-test 0 lines 0

main and the refactor commit both print, verbatim:

OK: 72 vitest-running package(s) walked, 8 selected as engine-booting, every one declares a recognised registry log level (debug/info/warn/error/silent).
self-test OK: 15 cases + level-vocabulary read + population declaration + real-tree selection floor.

The self-test control added — and one measured correction

The card's dispatch asked for a control where the boot signal spelled only in a string literal and in a comment is NOT selected, and the same spelling in code IS. Measured first, on main, before writing it:

fixture selected?
new SchemaRegistry() inside a string literal no
new SchemaRegistry() inside line + block comments no
bare word bootStack inside a string literal no
real new SchemaRegistry() in code yes, S1
a whole import … from '@objectstack/verify' statement spelled inside a string literal yes, S2

That last row is deliberate, not a bug: maskComments leaves string content intact precisely so S2/S3 can read import specifiers, and the gate says so at the call site. Asserting "a string-literal spelling never selects" as a blanket rule would therefore have pinned a falsehood. The case added pins the direction that is true, and it is the one that exercises maskCode — the function this PR leaves local:

a code signal spelled only in a string or a comment does not SELECT — two packages in one case: package a carries the non-code spellings (string literal + line comment + block comment, plus a bare bootStack word in a string), package b carries the real code. Expected: 1 selected, 1 finding. A mask that stopped blanking either span surfaces as a second selected package rather than as a silent widening of the population.

The existing 15 cases do not already pin this: prose naming bootStack does not SELECT the package (the packages/cli shape) covers the comment direction for S2 only, and no row covers the string-literal direction or maskCode's masking at all.

Roster and floor moved with it: the row is declared in SELF_TEST_BATTERIES and SELF_TEST_BATTERY_FLOOR goes 15 to 16. The only self-test output delta from main is that count:

< self-test OK: 15 cases + level-vocabulary read + population declaration + real-tree selection floor.
> self-test OK: 16 cases + level-vocabulary read + population declaration + real-tree selection floor.

The plain run is still a 0-line diff at head.

Ablation of the new case

Trap-guarded, mutating maskCode to stop OR-ing the literal flags (flags[i] = comment[i]), on the committed state:

  • mutation confirmed on disk: injected spelling grep -c = 1, removed spelling grep -c = 0; HEAD blob e4620d5… vs mutated blob 94b65b5… (differ).
  • self-test exit 1, and the new row is named in the failure — in the predicted direction:
self-test FAIL: a code signal spelled only in a string or a comment does not SELECT
  expected 1 finding(s), got 2
  expected 1 selected, got 2
  • restore leg: git checkout HEAD -- <abs path>; restored blob e4620d5… equals the HEAD blob, git diff HEAD empty, git status --porcelain empty.

No rebuild leg applies — this gate is plain .mjs executed from source by node, with no dist/ between the edit and the run.

Verification

All at head 4edcadcb2. Exit codes captured before any pipe (cmd > file 2>&1; EXIT=$?).

Derived family, not guessed: node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack — exit 0, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit 4edcadc", change set "1 path(s) vs merge base 954cb0b". 26 commands emitted, all 26 run, all exit 0.

gate exit verdict line
node scripts/check-registry-log-declared.mjs 0 OK: 72 vitest-running package(s) walked, 8 selected as engine-booting, …
node scripts/check-registry-log-declared.mjs --self-test 0 self-test OK: 16 cases + level-vocabulary read + population declaration + real-tree selection floor.
pnpm check:pm-dispatch-gates 0 dispatch-gates self-test: 1415 cases pass.
pnpm check:nul-bytes 0 check-nul-bytes: OK (scanned 7557 text file(s) …; no raw ASCII control bytes).
pnpm check:entry-guard 0 check:entry-guard: 214 scripts/ file(s) — every entry guard goes through invoked-as.mjs; …
node scripts/check-comment-mask-corpus.mjs 0 comment-mask corpus sweep: 5961 files, 0 disagree, 0 unparseable, 73.1s
the other 20 derived commands 0 each

Two run beyond the derived family, because this diff is about mask adoption:

gate exit verdict line
node scripts/check-comment-mask-adoption.mjs 0 OK check:comment-mask-adoption — 14 private comment-stripper(s) …, all 14 recorded and every recorded row still reached
node scripts/check-comment-mask-corpus.mjs (re-run at head) 0 as above

This gate has no vitest suitegit grep -l check-registry-log-declared names only lint.yml, package.json, four vitest.config.ts files and the script itself, so its --self-test is its test suite and it is in the table above.

pnpm lint was narrowed, and the narrowing is measured, not assumed. pnpm exec eslint --no-inline-config --format json scripts/check-registry-log-declared.mjs — exit 0, 1 file linted, 0 errors, 0 warnings (count read from the JSON output, not estimated). Nothing untouched can have moved: eslint.config.mjs:327 states, of this repo, that it "runs one eslint.config.mjs, which never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file, test or not" — with no cross-file program, a one-file diff cannot change any other file's verdict. The whole-repo sweep is CI's run, and it was not in the derived list.

NOT MEASURED: none. No command returned exit 3, PREREQUISITE NOT MET, ERR_MODULE_NOT_FOUND, or a queue timeout.

Scope

One file: scripts/check-registry-log-declared.mjs. No changeset — scripts/** publishes nothing from any package; skip-changeset applied and read back. Follow-up filed as #15594 (unassigned, finding); #15594 remains open and is not addressed here.

🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

…s maskComments instead of a private wrapper (#15561)

The local `maskComments` was `blank(source, scanSource(source).comment)` —
character-for-character the module's own export — so it was a private wrapper,
not a second scanner. Import the export and delete the wrapper; every call site
is unchanged.

`maskCode` stays local (the module publishes no comments+literals projection
yet) and its docblock now says so: it composes `scanSource`'s `comment` and
`literal` flags through `blank` and carries no scanning logic of its own.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…g-declared's self-test (#15561)

The existing prose row pins the COMMENT direction for S2 only. This row adds
the code mask's other direction: a signal spelled inside a string literal or a
comment must not select, and the same spelling in real code still must. Two
packages in one case, so a mask that stopped blanking either span shows up as a
second selected package rather than as a silent widening of the population.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026
@github-actions github-actions Bot added the size/s label Sep 4, 2026
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

ACCEPT — PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk.

Reviewed against the three-dot diff origin/main...claude/issue-15561-registry-log-shared-masker (head 4edcadcb2, two commits; one file, scripts/check-registry-log-declared.mjs, +40/−10), not the self-report. The narrowed premise (correction 5547170727) is what shipped.

  • The private maskComments wrapper (byte-for-byte the module's export body) is deleted and maskComments joins the import at :130; all five call sites unchanged. maskCode stays local — the module publishes no comments+literals projection — with its docblock stating it composes scanSource's flags through blank and carries no scanning logic; the hoist is filed as [finding] hoist maskCommentsAndLiterals (comments+literals blank) into js-comment-mask.mjs + .d.mts #15594 (three re-derivations named).
  • One self-test row, a code signal spelled only in a string or a comment does not SELECT, exercising maskCode in both directions (package a: new SchemaRegistry() in a line comment, a block comment and a string plus a bare bootStack word in a string → 0 selected; package b: the real code → 1 selected, S1 constructs a SchemaRegistry); roster + SELF_TEST_BATTERY_FLOOR 15 → 16.
  • Deviation accepted, and it is the correct one: the dispatch asked for "a string-literal bootStack is not selected", but a WHOLE import { bootStack } from '@objectstack/verify' statement inside a string IS selected by S2 on main, deliberately (maskComments leaves string content so S2/S3 can read import specifiers). Pinning the blanket rule would have pinned a falsehood; the row pins the true direction.

Dev's verification quoted (on 4edcadcb2): plain run diff vs main 954cb0bbf 0 lines (OK: 72 vitest-running package(s) walked, 8 selected as engine-booting …), --self-test diff exactly 15 cases16 cases; trap-guarded ablation (drop the literal OR in maskCode) reds the new row expected 1 selected, got 2, restore proved by blob e4620d52 == HEAD + empty git diff HEAD; derived family 26 commands all exit 0 (1415 cases pass, corpus sweep 5961 files, 0 disagree), plus check-comment-mask-adoption OK; NOT MEASURED none.

Flipping ready + enabling auto-merge (MCP rate-limited since ~22:45Z — retried each tick with #15590 and #15593). Fixes #15561.


Generated by Claude Code

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

2 participants