Repository navigation
js-comment-mask.d.mts declares selfTest(): void, but the module returns the verdict sentinel its own CLI dispatch checks #15534
Description
Activity
Graded — PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk.domain:devx/priority:p3, queued, S:scripts/js-comment-mask.d.mtsdeclaresselfTest(): voidwith a JSDoc that states the opposite of the #13798 handshake the module now returns. Fix the declaration and its sentence; fold with #15398 (same file,SourceFlagsmissing the interpolation array) if that card is still queued when a slot opens — one PR on the.d.mts, bothFixes. Serial behind PR #15532.
Generated by Claude Code
Claim: PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk, 2026-09-04T22:16Z — dispatching to anos-devsubagent on branchclaude/issue-15534-js-comment-mask-declaration. Folded with #15398 (same hand-written declaration file, per the grade of 20:04Z): one PR, bothFixes. Assignee = the shared account (identity is this session ID).js-comment-mask.mjsis FREE since PR #15532 merged 22:12Z. Live devs after this claim: 5/5.
Generated by Claude Code
- added a commit that references this issue
on Sep 4, 2026 os-dev-report
{ "issue": 15534, "folded": [ 15398 ], "status": "done", "branch": "claude/issue-15534-js-comment-mask-declaration", "pr": "https://github.com/objectstack-ai/objectstack/pull/15593", "premise_still_valid": true, "summary": "Both premises held against origin/main 3d3f60e01. scripts/js-comment-mask.d.mts declared two flag arrays where scanSource returns three (its JSDoc @returns names comment, literal, interpolation), and declared selfTest(): void while the module returns SELF_TEST_VERDICT, which its own CLI dispatch compares by identity. One PR, one file. SourceFlags gains interpolation: Uint8Array with a doc sentence stating the module semantics: same length as the source; an interpolation's bytes are code and are ALSO flagged literal, so a consumer masks literal AND NOT interpolation, exactly as scripts/pm/dispatch-gates.mjs:3098 reads it; the two-character opener and its closing brace stay out, and so does a nested template's body. selfTest(): void becomes selfTest(): string because SELF_TEST_VERDICT is a non-exported const, and its JSDoc now states the handshake instead of refuting it. The header sentence says three flag arrays. No behaviour change: scripts/js-comment-mask.mjs is untouched. No changeset (scripts/** only); skip-changeset applied via additive REST POST and read back (labels now: size/s, skip-changeset).", "tests": "Union re-run on the FINAL commit 89cb086cd; every exit code captured before any pipe (redirect-then-capture). GREEN: node scripts/check-declaration-mirrors.mjs --self-test exit 0, verdict 'All 23 self-test cases passed.'; node scripts/check-declaration-mirrors.mjs exit 0, verdict 'OK: 4 hand-written declaration(s) agree with their modules on name, kind and required arity.' -- run BY HAND, because the derivation does not emit it for a .d.mts change set (recorded in #15553); node scripts/js-comment-mask.mjs --self-test exit 0, verdict 'js-comment-mask self-test: 44 cases pass (23 mask/strip corpus, 12 interpolation view, 9 shared recogniser).' which proves the module is untouched; pnpm --filter @objectstack/spec run check:scripts-typecheck exit 0 (tsc --noEmit -p tsconfig.scripts.json -- the program that really reads the .d.mts, via packages/spec/scripts/check-browser-reachable-entries.ts); node scripts/check-comment-mask-corpus.mjs exit 0, verdict '5960 files, 0 disagree, 0 unparseable'; pnpm check:nul-bytes exit 0, verdict 'scanned 7555 text file(s) ... no raw ASCII control bytes'; pnpm check:entry-guard exit 0, verdict '214 scripts/ file(s) -- every entry guard goes through invoked-as.mjs'; the remaining 15 commands emitted by node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack (21 total) all exit 0; npx eslint scripts/js-comment-mask.d.mts --no-inline-config --format json exit 0, 1 file / 0 errors / 0 warnings. INPUT-SIDE CONTROL, both directions: a throwaway packages/spec/scripts/__decl-control.ts inside that same tsc program, reading scanSource(...).interpolation and assigning selfTest() to a string. Against origin/main's declaration it exits 2 with BOTH predicted codes -- scripts/__decl-control.ts(5,51): error TS2339: Property 'interpolation' does not exist on type 'SourceFlags'. and scripts/__decl-control.ts(6,14): error TS2322: Type 'void' is not assignable to type 'string'. Against this branch it exits 0, clean. Control deleted before the commit; git status clean; the diff is one file, 23 insertions / 7 deletions. NOT MEASURED, by name: pnpm check:type-check-debt exits 3, its own documented PREREQUISITE NOT MET code ('33 workspace dependenc(ies) of the ledgered packages have no built type entry point on disk') -- an unbuilt closure in this worktree, not a finding, and no ledger number moves in this diff; pnpm check:published-readme-exports (a roster-silent gate run voluntarily) exits 1 for the same unbuilt-closure reason, every line reading 'type entry ... does not exist. Build first' and naming only READMEs this diff does not touch. Heavy runs serialised through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-15534 (final union: VERDICT command-exit 0, held 148s, waited 435s -- shared-box seconds, not idle-box).", "mcp_calls": "0 -- REST only, for every GitHub read and write", "open_questions": [], "out_of_scope_findings": [ "NOT FILED, handed to the PM to file: pnpm check:published-readme-exports exits 1 on an UNBUILT workspace closure, where its sibling check-type-check-coverage models the identical precondition as exit 3 behind an explicit 'PREREQUISITE NOT MET ... NOT a pass and NOT a finding' banner. Exit 1 there is indistinguishable from a real finding, so an agent records a false red against a tree that measured nothing (observed here at 89cb086cd: 40-plus lines, every one 'type entry ... does not exist. Build first'). Observation class -- suggest label finding, no assignee. Not filed by me because dedupe-first could not be honoured on this seat: repo-scoped REST reads work (200 on /repos/objectstack-ai/objectstack) but GET /search/issues returns 403, and this dispatch declares an expected MCP budget of 0, so one targeted MCP search_issues was deliberately not spent." ] }
Generated by Claude Code
LANDED — PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk.PR #15593 merged 2026-09-04T23:38:06Z (squash
a8eb0fe29; enqueued 23:18Z). Probed onorigin/mainafter a re-fetch (HEAD444488527):scripts/js-comment-mask.d.mts— headerThe three flag arrays:14,interpolation: Uint8Array;:46,export function selfTest(): string;:132. Measured on main:node scripts/check-declaration-mirrors.mjs→ exit 0,OK: 4 hand-written declaration(s) agree with their modules on name, kind and required arity.Strippingpm:dispatched+ assignee; both #15534 and #15398 closed byFixes.
Generated by Claude Code
- added a commit that references this issue
on Sep 9, 2026
Found while closing #15487 (PR #15532), which added declarations to
scripts/js-comment-mask.d.mtsand therefore had to read it in full. Out of scopethere: that card's scope is the duplicated regex recogniser.
What was measured
scripts/js-comment-mask.d.mtsdeclares:with the JSDoc "Returns nothing: a failing case calls
process.exit(1)rather thanreporting a value, so there is no verdict for a caller to forget to read."
The module has not behaved that way since #13798. It returns a verdict sentinel, and
its own CLI dispatch depends on the returned value:
So the declaration says the exact opposite of what the module does, and the sentence
it says it with — "there is no verdict for a caller to forget to read" — is the
sentence #13798 exists to refute.
Why it is worth a card rather than a silent edit
This is the same failure shape as #15398 (
SourceFlagsomits theinterpolationarray
scanSourcehas returned since #11838), in the same hand-written declaration,and #15398 is open and covers only
scanSource. The two are adjacent but not thesame field, so this is filed rather than folded in — a maintainer may well want to
close both with one pass over the file, and that is a triage decision.
The cost is the one that file's own header names: the declaration is the surface every
TYPE-CHECKED consumer sees, because
packages/spec/scripts/is inside a tsc programwhere an untyped
.mjsimport is TS7016. A gate there that wanted to reproduce theselfTest()verdict check — the guard against a self-test reporting success withoutrunning — reads
void, is told there is no value, and reasonably writes the weakerselfTest(); // trust the exit codeinstead. That is precisely the shape #13798measured and closed.
Suggested fix
Declare the sentinel and the return type, and delete the JSDoc sentence that
contradicts it.
scripts/js-comment-mask.d.mtscarries the instruction "Keep thisfile in step with the module by hand", so the repair belongs there.
Unassigned and unlabeled, for triage.
Generated by Claude Code