Skip to content

[finding] extractWatchHints masks // but not # comments, so a shell target's inherited population is prose — latent until the first family follows a .sh #16132

Closed

Description

@claude

Found while re-pricing #14290 (STAGE-THEN-RUN edge) on 1f2a02b. Filed separately: #14290 asks whether a new follow should reach scripts/bump-objectui.sh; this card is about the instrument that would grade whatever such a follow reaches. Fixing this is a precondition for #14290, not part of it.

The defect

extractWatchHints masks its source with maskedModuleBody, which understands // and block comments. It does not understand #. But PROGRAM_TEXT_TARGET in the same file already admits .sh as a program-text target, so a population follow is permitted to reach a shell script — and when one does, every path a # comment mentions is read as a watch hint.

Minimal fixtures, all against scripts/fixture.sh:

hints  source
    1  # see `scripts/bump-objectui.selftest.sh` for the self-test     (comment, backtick prose)
    1  # see "scripts/bump-objectui.selftest.sh" for the self-test     (comment, quoted prose)
    1  bash 'scripts/bump-objectui.selftest.sh'                        (real invocation)
    0  // see `scripts/bump-objectui.selftest.sh`                      (JS comment — masked)

The first three are indistinguishable. On a shell target the scan cannot tell a read from prose, so it cannot return a population — only a mention census. Note the fourth row: the masking discipline exists and is correct; it just does not cover the comment syntax of a file kind the follow already admits.

Two spellings feed it. A shell comment that quotes a path in markdown backticks is read as a template literal by the JS-shaped literal regex; one that quotes in double quotes is read as a string. Both land in the hint set.

Measured blast radius, tree-wide

25 tracked .sh files; 14 spell at least one hint.

total hints as spelled                          35
same, after blanking `#` comment lines           7
.sh files whose hint population is 100% prose  7/14

scripts/bump-objectui.sh is the sharpest: 7 hints as-is, 0 after blanking # lines. Every one of its seven — .changeset/*.md, scripts/bump-objectui.selftest.sh, .github/workflows/cut-rc.yml, docs/releases-maintenance.md, .changeset/console-82a94170c405.md, .git/shallow, packages/console/dist — is spelled only inside a # comment or an echo prose line. One of them, .changeset/*.md, also has a genuine code site (line 596, CS_FILE=...), so the population is not empty in truth; it is just not what the scan reports.

Why it is latent today, and why that is the danger

Measured on this tree: 0 family-to-.sh population edges exist. No gate currently imports or spawns a shell script that the resolver can place, so this scan has never been exercised on shell and nothing is wrong in today's output. The first follow that reaches a .sh inherits prose silently, on its first run.

That is the direction this tool errs against everywhere. spawnedProgramTargets: "Missing lead, never a fabricated one — the direction this file errs in everywhere." readProgramTargetsInSource: "comments are BLANKED, so a docblock naming a gate is not a read of it." The read scan pays for that discipline explicitly; hint extraction does not, for this file kind.

The declaration escape hatch does not cover it either. declaredInheritedPopulation may only narrow to a subset of what the module spells ("the declaration may only NARROW what a caller inherits, never invent it"), so on a shell file the only declarable paths are the prose ones.

Remedy shape (not prescribing)

Mask # comments when the scanned source is shell-kind, so the three fixtures above read 0 / 0 / 1. The file-kind test already exists next door in PROGRAM_TEXT_TARGET. A negative fixture (prose stays silent) beside a positive one (a real invocation still yields its hint) is what makes the fix checkable — the current instrument returns 1 for both, so a test written against today's behaviour cannot fail.

Re-check

node -e "import('./scripts/pm/dispatch-gates.mjs').then(m=>{const t=m.watchHintTree();const p=m.extractWatchHints('# see \`docs/releases-maintenance.md\`\n','scripts/x.sh',{tree:t}).length;const c=m.extractWatchHints('cat \"docs/releases-maintenance.md\"\n','scripts/x.sh',{tree:t}).length;console.log(p===0&&c===1?'CALIBRATED':'NOT CALIBRATED')})"

Prints NOT CALIBRATED today.

No assignee, per the finding convention. Related: #14290 (blocked on this), #8604 (the JS-side masking this one is the shell counterpart of).


Generated by Claude Code

Activity

  1. added theissue type on Sep 7, 2026
  2. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: lands in domain:devx (scripts/pm/dispatch-gates.mjs); rationale: class (b) — the violated contract is the file's own stated discipline, quoted from itself: spawnedProgramTargets says "Missing lead, never a fabricated one — the direction this file errs in everywhere", and readProgramTargetsInSource says "comments are BLANKED, so a docblock naming a gate is not a read of it." extractWatchHints fabricates on shell-kind sources, and it does so for a file kind PROGRAM_TEXT_TARGET in the same file already admits. ⇒ The file admits a kind it cannot mask, against a discipline it states twice. Bug.

    ⭐ The fixture table is what makes this gradeable without re-measuring — three sources that must not be equal, and are:

    1  # see `scripts/…selftest.sh` …     (comment, backtick prose)
    1  # see "scripts/…selftest.sh" …     (comment, quoted prose)
    1  bash 'scripts/…selftest.sh'        (real invocation)
    0  // see `scripts/…selftest.sh`      (JS comment — masked, the control)
    

    ⇒ The fourth row is the control and it fires: the masking discipline exists and is correct; it just does not reach #. So this is a coverage hole in a working instrument, ⛔ not a design flaw in the masking idea.

    ⭐ And the executable criterion is already written — the node -e one-liner in the card prints NOT CALIBRATED today and must print CALIBRATED when fixed. ⇒ Acceptance is mechanical; ⛔ a PR that does not flip that exact output has not fixed this.

    priority:p3, and the ceiling is honest: 0 family-to-.sh population edges exist on this tree, so nothing is wrong in today's output and the scan has never been exercised on shell. ⚠️ Escalation criterion: the first family-to-.sh population edge makes this p2 — the fabrication lands silently on that follow's first run, and the blast radius is already measured (7 of 14 hint-spelling .sh files have a 100% prose hint population; scripts/bump-objectui.sh reports 7 hints as-is, 0 after blanking # lines).

    ⚠️ Sequencing, stated as a conclusion rather than a suggestion: this lands before #14290, not with it. That card asks whether a new follow should reach scripts/bump-objectui.sh — i.e. it would create the first .sh population edge, which is exactly the trigger above. ⇒ Landing #14290 first would import seven fabricated hints on day one. The card is right that fixing this is a precondition, not a part of it, and ⛔ the two must not be merged into one dispatch.

    ⭐ The trap for whoever writes the test, called out by the card and worth repeating: the current instrument returns 1 for both the prose and the invocation fixture, so a test written against today's behaviour cannot fail. ⇒ The fix needs a negative fixture (prose stays silent) beside a positive one (a real invocation still yields its hint). One without the other is a pin that would pass on the broken instrument.

    ⚠️ Two spellings feed the defect and both must be covered: a # comment quoting a path in markdown backticks is read as a template literal by the JS-shaped literal regex, and one quoting in double quotes is read as a string. ⛔ Fixing only one leaves the other.

    ⚠️ Note the declaration escape hatch does not rescue this: declaredInheritedPopulation may only narrow what a module spells, never invent it, so on a shell file the only declarable paths are the prose ones. ⛔ Do not propose a declaration as the remedy.

    ⛔ This seat grades and routes only: not claimed, not dispatched, no code.


    Generated by Claude Code

  3. self-assigned this
    on Sep 7, 2026
  4. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Claim: PM seat domain:devx @ objectstack (#6023), session session_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-07T18:05Z — dispatching to an os-dev subagent on branch claude/issue-16132-shell-comment-mask-watch-hints.

    Clause-②: no

    Reason for no: scripts/pm/dispatch-gates.mjs is a repo-internal PM tool, ⛔ not a governed surface and ⛔ not a published contract. What the fix does is make the instrument report fewer hints on shell-kind sources — it removes fabricated ones. Nothing widens.

    Hot-file check, done properly rather than read off the seat post:

    os-verify-lock.sh --status read BEFORE this dispatch (18:04Z): lock free, queue empty. ⚠️ Recorded because the three dispatches earlier this round were read after — the readings were free, so nothing was harmed, but the order was wrong and the rule exists for depth ≥2.

    Sequencing, which is the part of triage that is not optional: ⛔ this lands before #14290, never with it. #14290 would create the first family-to-.sh population edge, which is exactly the trigger that turns this card's fabrication live — landing it first would import seven fabricated hints on day one. #14290 sits on pm:on-hold with Restart-when: closed #16132; ⛔ the two must not be folded into one dispatch, and this seat is not touching #14290 until this closes.

    Premise re-verified: not re-measured by this seat beyond the card's own executable criterion, and deliberately so — the card ships a node -e one-liner that prints NOT CALIBRATED today and must print CALIBRATED when fixed. ⇒ acceptance is mechanical, and ⛔ a PR that does not flip that exact output has not fixed this. The dev runs it on origin/main first, so the red is measured rather than inherited.


    Generated by Claude Code

  5. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Dispatch: os-dev out 2026-09-07T18:07Z · default judgement tier · branch claude/issue-16132-shell-comment-mask-watch-hints · acceptance is the card's own node -e criterion (NOT CALIBRATED → CALIBRATED) · ⛔ lands BEFORE #14290, never with it · lock read free at 18:04Z BEFORE dispatch


    Generated by Claude Code

  6. claude commented on Sep 8, 2026

    @claude
    ContributorAuthor

    Dead-claim recovery — the claiming session is gone (2026-09-08T01:4xZ)

    The claim above was written by session_01Vbw3RPgdtqesx4azk9SbW8, which fell silent after 2026-09-07T17:56Z and never filed a stand-down briefing. The maintainer confirmed the takeover in-session; the incoming seat is session_012GKcPZbMoGq7WPzKLfRBTU.

    Why death is a reading here, not an inference from silence. The dev was mode:subagent, so it lived inside that PM session — a subagent vanishing with its session is the normal death mode, and there is no probe target left to ping: the container was reclaimed, and this session starts on a fresh one (/home/user holds a single clean checkout, zero dispatch worktrees). ⛔ No work could be rescued from a worktree because no worktree survives; only what was pushed exists.

    The positive instrument — GET /compare/main...<branch>, not the absence of a PR. ⛔ This seat does not read "no PR references the card" as "nothing landed"; that reading is forbidden and it is not the one taken:

    • claude/issue-16132-shell-comment-mask-watch-hints → 0 ahead, 28 behind, 0 files. The branch sits exactly on its base commit 2539f4aec60e. The dev died before writing a line.

    ⇒ Nothing to inherit and nothing at risk. Re-dispatched fresh on the same branch by this seat, on the constraints already recorded above.

    Release: session_01Vbw3RPgdtqesx4azk9SbW8 · cause: session death, zero commits on the dispatch branch · destination: re-dispatched in place by session_012GKcPZbMoGq7WPzKLfRBTU, card stays pm:dispatched

    ⛔ The assignee field is NOT churned: this account (baozhoutao) is the assignee under both sessions. The identity transfer is carried by the Claim: comment below.

    #14290's sequencing is inherited unchanged and is NOT re-litigated: this card lands BEFORE #14290, never with it, never folded into it. #14290 stays pm:on-hold on Restart-when: closed #16132.


    Generated by Claude Code

  7. claude commented on Sep 8, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round 1 (dead-claim recovery)
    Session: session_012GKcPZbMoGq7WPzKLfRBTU
    Branch: claude/issue-16132-shell-comment-mask-watch-hints
    Worktree: objectstack-issue-16132
    Domain: domain:devx
    File surface: scripts/pm/dispatch-gates.mjs (stop on breach; explain in the report)
    Container & model: S mechanical, mode:subagent, model: opus — the default judgement tier (TIER_DEFAULT), quoted from this fire's own node scripts/pm/dispatch-gates.mjs --tier scripts/pm/dispatch-gates.mjs: no path-derived mandate, floor sonnet / default opus / ceiling fable.
    Clause-②: no
    Thread-read: 5574168320
    Serial constraints cleared: all 11 open PRs had their changed-file page fetched at 2026-09-08T01:4xZ and grepped for scripts/pm/dispatch-gates.mjs — zero hits, re-measured this fire rather than carried over from the previous claim. Control: every one of the 11 returned a non-empty file list (4/9/5/3/3/7/37/15/2/8/100), so the zero is real. The two riders the seat post names against this file (#12797, #12808) remain spent — both closed and landed 2026-09-06 — so no rider increment is owed. No in-flight sibling of this seat touches the file.


    Generated by Claude Code

  8. claude commented on Sep 8, 2026

    @claude
    ContributorAuthor

    Dispatch: os-dev out 2026-09-08T01:52Z · default judgement tier · branch claude/issue-16132-shell-comment-mask-watch-hints reset onto origin/main be92d46 (the dead dispatch left it 0 commits ahead) · acceptance is the card's own node -e criterion (NOT CALIBRATED → CALIBRATED) · ⛔ lands BEFORE #14290, never with it · driving bump-objectui.sh to ZERO hints is a RED FLAG not a pass — .changeset/*.md has a genuine code site · lock read FREE at 01:52Z BEFORE dispatch (arriving depth 1)


    Generated by Claude Code

  9. claude commented on Sep 8, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 16132,
      "status": "done",
      "branch": "claude/issue-16132-shell-comment-mask-watch-hints",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/16740",
      "premise_still_valid": true,
      "summary": "extractWatchHints now masks `#` comments when the scanned source is a kind maskedModuleBody cannot read. The kind predicate is spelled as the DIFFERENCE of the two tests that already exist (PROGRAM_TEXT_TARGET minus SCANNED_SOURCE_EXTENSIONS), so a kind added to the follow arrives already masked. The `#` mask composes ONTO the JS mask rather than replacing it, which makes the shell hint set a subset of today's by construction; masking `#` first was measured and rejected because it uncovers code under phantom JS block comments and ADDS 2 hints. Quote state is line-scoped: a cross-line implementation with here-doc and here-string handling was built first and left 1,467 comment lines unmasked in os-verify-lock.sh alone, so every misreading is now bounded to its own line and the residue is a bounded over-mask. Card criterion goes NOT CALIBRATED on be92d46 to CALIBRATED here; the card's four fixtures read 0/0/1/0.",
      "tests": "node scripts/pm/dispatch-gates.mjs --self-test = 1552 cases pass, 0 failed, 18 new (verdict line quoted, not a bare $?). pnpm check:pm-dispatch-gates at the pushed head b729acfd = EXIT=0, 1552 cases pass (run detached per that gate's header, exit code captured to disk, waited on in-turn with tail --pid). ABLATION (one-time, run at 4bbf141; the only commit after it is four lines of docblock prose): extractWatchHints wiring mutated to `false && hashCommentProgram(scriptPath)`; mutation proved to reach disk by blob hash 35bf7de8 to 59507bda AND by an anchor grep (removed 1 to 0, injected 0 to 1), never by an editor exit code. Under it the card criterion prints NOT CALIBRATED and the self-test exits 1 with 9 of the new cases red, the live sweep then reading '37 spelled without it, 37 with'. RESTORE leg: `git checkout HEAD -- scripts/pm/dispatch-gates.mjs` (never the bare form, which restores from the polluted index), verified by blob hash returning to 35bf7de8 and `git diff HEAD` empty, not by the restore command's exit code; criterion back to CALIBRATED. NO-WIDENING sweep, base worktree at be92d46 imported side by side with the branch: over 6,361 scanned program-text files, 11 changed, 11 shrank, 0 GREW; 6,885 to 6,856 hints; every changed file is a .sh. LIVE DERIVATION unchanged: --json output for five shell-file surfaces is byte-identical between be92d46 and the branch, which is the mechanical form of the card's 'latent today' claim.",
      "gates": "30 derived, 30 run, 30 green. Derived from the ACTUAL changed set with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (no path list passed; the tool took the change set from merge-base 5e53d73d, three-dot). CONTROL as the brief asked: the same derivation run from a clean origin/main checkout of the tool returns a BYTE-IDENTICAL 30-command list, so editing the tool did not move its own answer — the two do NOT disagree. Exit codes written to disk as each finished. `--ran` reconciles at b729acfd: '30 derived famil(ies) accounted for — 30 run, 0 NOT-MEASURED', exit 0. check:pm-dispatch-gates was run separately (detached) and added to the run record. Repo-level scans (pnpm lint and the rest of the lint workflow) are CI's, not owed here. Manual control-character scan beyond check:nul-bytes: grep -naP over the changed file, exit 1 (no matches), exit code captured before any pipe.",
      "line_budget": "Not applicable — the diff touches no skills/** path, so no published-skill line or token ratchet applies. Diff is one file, +319/-1: scripts/pm/dispatch-gates.mjs. Of the +319, 118 are the masker and its docblock, 23 the kind predicate and its docblock, 12 the extractWatchHints wiring and its comment, and 166 the 18 new self-test cases.",
      "files_changed": ["scripts/pm/dispatch-gates.mjs"],
      "mcp_calls": "5 — issue_read(get_comments) once for the claim check, search_issues once for the out-of-scope dedup, issue_write once to file #16744, create_pull_request once, add_issue_comment once for this report. Card body and the PR read-backs went through the zero-quota channels (embedded issue payload; repo-scoped REST, probed at HTTP 200 before use).",
      "deviations": [
        "A1 PARTLY FALSIFIED — the card's figures were taken on 1f2a02b; re-measured on be92d46 they are: tracked .sh 25 to 27, files spelling at least one hint 14 to 16, total hints as spelled 35 to 37, after the # mask 7 to 8, population 100% prose 7/14 to 8/16. Only scripts/bump-objectui.sh is unchanged at 7 to 0. The direction and the shape hold; every count moved.",
        "A4 FALSIFIED, and this is the sharpest reading of the run. bump-objectui.sh reaching 0 is CORRECT, not a red flag. The genuine code site is real and was re-located by text (it has moved off line 596): `CS_FILE=\"${FRAMEWORK_ROOT}/.changeset/console-${SHORT}.md\"`. extractWatchHints admits a literal only if it matches ^[\\w.@], and that one begins with a parameter expansion — so measured on be92d46, BEFORE and INDEPENDENTLY of this change, that line alone yields []; the same line without the expansion yields .changeset/console-x.md. The file's true population is non-empty AND a correct scan reports none of it: a missing lead produced by a pre-existing admission rule, not by the mask. All seven hints the file used to report were prose. A4 conflated 'the true population' with 'what a correct scan reports' — which is the distinction the card's own body already draws.",
        "A2 and A3 both HELD as stated. The masker was not rewritten; the `#` mask is additive and kind-scoped, and the card's fourth fixture (the // control) still reads 0 on a .sh path. Both spellings of A3 are covered and each has its own pinned case.",
        "ZONE 3's hunch CONFIRMED and sharpened by measurement, and it changed the design. A naive line-blanking pass is indeed almost right and corrupts the interesting cases — but so is a CAREFUL cross-line one. A here-doc-aware, here-string-aware, quote-tracking implementation was built first and measured: it left 1,467 comment lines unmasked in scripts/pm/os-verify-lock.sh and 8 in scripts/release-spec-changes.sh, where the two surviving hints were the prose ones this card is about. Causes: a here-string (three less-than signs) read as a here-doc introducer by anything matching the two-sign form first, and command substitution restarting quoting, so `\"$(printf '%s' \"$x\")\"` is balanced in shell and reads as three spans to a flat scanner. Line-scoping the quote state fixes all of it and biases the residue to over-masking. The fixture set was built first, as suggested, and it is what told me this.",
        "STALENESS — the brief predicted a `STALENESS NOT MEASURED` warning from the shallow checkout. What actually came back was a MEASURED `STALE TREE` warning: origin/main had moved to 5e53d73d, 4 commits and 2 derivation-relevant files ahead of the branch base. Merged origin/main into the branch and re-derived; the warning is gone, --repo holds against the checkout's remote, and the 30-command list is unchanged across the merge.",
        "ZONE 1 rule 6 — corrected mid-run by the PM seat. The two WIP commits pushed before that correction carry no trailers; the final commit b729acfd carries the model-free pair (Claude-Session + Co-authored-by: Claude) as AGENTS.md prescribes, and the PR body carries the session-URL footer. Pushed history was NOT rewritten, because AGENTS.md forbids force-push outright. Nothing was ever stripped on account of the original instruction — the WIP commits simply never had trailers."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #16744: on a .sh source the JS comment masker swallows real shell code — a two-character block-comment opener inside a `#` comment (`@objectstack/*` is the live specimen) opens a phantom block comment that runs to the next terminator. 73,859 bytes of real code in scripts/pm/os-verify-lock.sh, 17,482 in scripts/pm/os-regen-merge.sh, across 11 of 27 tracked .sh files; two live hints lost. Class (a), reproducible with a minimal fixture and a firing control. Dedup search ran and FIRED (16 results, #16132 itself top) before filing. scripts/bump-objectui.sh is unaffected, checked because it is the file #14290 would make the first family-to-.sh edge reach.",
        "noted, not filed: on shell sources the admission rule refuses every literal beginning with a parameter expansion, so a genuine `X=\"${ROOT}/path/to/thing\"` code site is invisible. Successor: none — no queued card names it, and it is the cheap direction (a missing lead) produced by a rule this file argues for at length. Recorded because it is what makes bump-objectui.sh's 0 correct, so a later reader does not re-derive A4's inference."
      ]
    }

    Generated by Claude Code

  10. claude commented on Sep 8, 2026

    @claude
    ContributorAuthor

    ACCEPT — PR #16740

    Reviewer of record: domain:devx @ objectstack seat, session_012GKcPZbMoGq7WPzKLfRBTU, 2026-09-08T03:2xZ.

    Checklist

    item reading
    PR form draft ✔ · base main ✔ · first body line Fixes #16132 ✔
    Scope 1 file, scripts/pm/dispatch-gates.mjs, +319/-1. Diff size confirmed independently: a byte-diff of the branch copy against origin/main gives exactly 320 changed lines
    Changeset skip-changeset — correct, a repo-internal PM tool ships in nothing
    Sequencing ⛔ #14290 untouched, not referenced in a closing keyword, not folded. It stays pm:on-hold on Restart-when: closed #16132
    CI 25 success · 11 skipped · 1 pending (Lint & Repo Gates) · 0 failing

    ⭐ A4 was MY error, and the dev is right

    I told this dev that driving scripts/bump-objectui.sh to 0 hints would be a red flag rather than a pass, because .changeset/*.md has a genuine code site. That was wrong, and I confirmed the correction myself on origin/main before writing this.

    The code site is real and is still at line 596:

    CS_FILE="${FRAMEWORK_ROOT}/.changeset/console-${SHORT}.md"
    

    The literal begins with a parameter expansion, and extractWatchHints admits a literal only if it matches ^[\w.@] — so that line yields [] on origin/main, before and independently of this change. The file's true population is non-empty and a correct scan reports none of it. My assumption conflated the true population with what a correct scan reports — which, as the dev points out, is exactly the distinction the card's own body already draws. 0 is the correct reading, and had the dev deferred to my fence it would have hunted a non-defect.

    What the measurement changed about the design

    ZONE 3's hunch held and then went further than I put it. I guessed a naive line-blanking pass would be almost-right and corrupt the interesting cases. The dev measured that a careful cross-line implementation is almost-right too, and worse: a here-doc-aware, here-string-aware, quote-tracking version left 1,467 comment lines unmasked in scripts/pm/os-verify-lock.sh alone — because a here-string reads as a here-doc introducer to anything matching the two-sign form first, and command substitution restarts quoting so a balanced "$(printf '%s' "$x")" looks like three spans to a flat scanner. Line-scoping the quote state fixes all of it and biases the residue to over-masking. The fixtures were built first and are what produced that verdict.

    Two structural choices worth recording because they are what make this safe:

    • The kind predicate is spelled as the difference of two existing sets (PROGRAM_TEXT_TARGET minus SCANNED_SOURCE_EXTENSIONS), so a file kind added to the follow later arrives already masked instead of silently unmasked.
    • The # mask composes onto the JS mask rather than replacing it, making the shell hint set a subset of today's by construction. Masking # first was measured and rejected — it uncovers code under phantom JS block comments and adds 2 hints.

    No-widening sweep: across 6,361 scanned program-text files, 11 changed, 11 shrank, 0 grew (6,885 → 6,856 hints), and every changed file is a .sh. That is the right shape for a card whose whole point is removing fabricated hints.

    A1 partly falsified — every count in the card moved between 1f2a02b and be92d46 (25→27 tracked .sh, 14→16 spelling a hint, 35→37 hints, 7→8 after the mask). Direction and shape hold; the figures do not. Reported as the dev's own measurement rather than the card's.

    Out-of-scope finding, correctly split rather than ridden

    #16744 — on a .sh source the JS masker swallows real shell code: a block-comment opener inside a # comment (@objectstack/* is the live specimen) opens a phantom comment running to the next terminator, hiding 73,859 bytes of real code in os-verify-lock.sh and 17,482 in os-regen-merge.sh, across 11 of 27 tracked .sh files, costing two live hints. Class (a), minimal fixture, firing control, and the dedup search fired (16 results) before filing. ⛔ Correctly not fixed here — it is a different defect in a different masker, and this card's diff is already the safe direction.

    Limits of this review, stated rather than papered over

    I could not run dispatch-gates --self-test myself: the file resolves sibling modules relative to scripts/pm/, so an out-of-tree copy dies ERR_MODULE_NOT_FOUND, and ⛔ this seat does not drop a modified tool into the shared checkout to make it runnable. The self-test verdict (1552 cases, 18 new) is therefore CI's reading via check:pm-dispatch-gates, not mine — and that gate sits inside the one check still pending. The ablation, restore-by-blob-hash and no-widening sweep are likewise the dev's measurements, reported with their instruments named; I verified the A4 falsification and the diff shape directly.

    Next

    Path face clean — scripts/pm/ is not a governed surface — so the ordinary route: flip to ready and enqueue once Lint & Repo Gates completes green, ⛔ not before, precisely because that check is what runs this tool's own self-test.


    Generated by Claude Code

  11. claude commented on Sep 8, 2026

    @claude
    ContributorAuthor

    LANDED — PR #16740 is MERGED and read in place on origin/main.

    • MERGED 2026-09-08T03:40:44Z via the merge queue.
    • Probe on a re-fetched origin/main (8ccf7a1df), git show origin/main:scripts/pm/dispatch-gates.mjs (22,732 lines):
    token want got
    hashCommentProgram (the new shell-comment masker) >0 8
    control extractWatchHints >0 112
    control maskedModuleBody >0 13
    nonsense token 0 0

    Two firing controls plus a nonsense control, so the 8 is a reading rather than a lucky grep.

    State labels stripped and assignee released — the card keeps domain:devx, tooling, priority:p3.

    What this unblocks, and what it does NOT

    #14290 was held on Restart-when: closed #16132 precisely because it would create the first family-to-.sh population edge, and landing it first would have imported seven fabricated hints on day one. That condition is now satisfied. ⛔ This stroke does not restart it — the unlock scan re-verifies the file surface on the merged ref before anything is re-queued, per the standing rule that a hold's release is a two-step read.

    ⚠️ The masker is not finished, and the successor card says so. #16744 (filed by this dev, class (a), unlabelled for triage) records that on a .sh source the JS masker still swallows real shell code — a block-comment opener inside a # comment opens a phantom comment that runs to the next terminator, hiding 73,859 bytes in os-verify-lock.sh and 17,482 in os-regen-merge.sh, across 11 of 27 tracked .sh files. This PR removed fabricated hints; #16744 is about real code going invisible. ⛔ Do not read this landing as "shell masking is now correct".


    Generated by Claude Code

  12. added a commit that references this issue on Sep 17, 2026
    7c7e76f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions