Skip to content

finding(tooling): js-comment-mask still opens a phantom regex on a self-closing JSX tag and on a slash in JSX text #7882

Closed

Description

@claude

Measured while implementing #6891, on cf7f2af6e. Filed unassigned, not fixed there: #6891 closes the LT SLASH half with a one-token rule; this half provably cannot be closed the same way, so it is its own decision.

The defect

scanSource opens a REGEX when the character before a / is not a value (IDENT_CHAR, ), ]). } and GT are not values, so both of these open a phantom regex that runs to end of line:

  • a self-closing JSX tag whose / follows a brace — Foo bar={x} SLASH GT, Foo {...p} SLASH GT
  • a / in JSX text — {a}/{b}, or code OS_PAGE_REACT=off /code SLASH code x /code

A self-closing tag whose / follows a value (br SLASH GT, Foo SLASH GT, Foo x="1" SLASH GT) was never affected — the discriminator is the preceding byte, not the tag shape.

Measured

Over all 4,322 tracked source files, with #6891's fix applied and both flag arrays diffed byte for byte against the pre-fix scanner: 145 bytes across 28 files are still flagged literal by this shape. They were invisible before only because the closing tag's larger phantom started earlier on the same line and covered them.

It reaches the FABRICATES direction too — the phantom swallows a comment opener that follows it on the same line, so genuinely commented-out text comes back to a caller as live code:

const c = Foo bar={x} SLASH GT ; // dead = 1;

maskComments leaves dead = 1; standing. That is the direction this module's header calls worse than no verifier at all.

Why #6891 did not take it

There is no one-token rule for it, and the two obvious ones are both wrong:

  1. / followed by GT is a tag closer. That is exactly how a regex matching a GT is spelled — str.replace(/GT/g, '>') — and this tree writes that shape.
  2. } and GT are values. Both are genuinely ambiguous in JavaScript: function f(){} /re/ is a regex, and a GT /re/.test(b) parses.

Separating them needs to know whether the scanner is inside a JSX element, which is a parser. js-comment-mask.mjs is deliberately a cheap language-level masker, and turning it into a parser is a different card.

Already pinned, so this cannot be closed silently

scripts/__tests__/js-comment-mask-jsx-6891.test.ts carries a KNOWN LIMITS block asserting today's behaviour for all four shapes. Whoever closes this will see those pins fail and must retire them deliberately — the same two-way discipline that surfaced #6891 itself.

Shape of a fix, for triage rather than as a decision

  1. Leave it. The residue is 145 bytes, it is pinned, and no gate's verdict moves today. Cheapest, and honest as long as the pins stay.
  2. Port objectstack's corpus sweep (scripts/check-comment-mask-corpus.mjs, named in this module's header as NOT ported here) and decide against a measurement over an independent parser rather than against cases. This is the route finding(tooling): js-comment-mask reads a JSX closing tag as a regex literal — 7 measured call sites become undelimitable #6891's own triage comment named as the only one that answers "which direction does it fail in".
  3. A JSX-aware mode, opt-in per caller. Largest, and it changes what this module is.

Generated by Claude Code

Activity

  1. os-zhuang commented on Sep 6, 2026

    @os-zhuang
    Contributor

    分诊:domain:devx / tooling + finding / needs-user-decision / priority:p3

    ⛔ needs-user-decision 不与 pm:* 并存。

    落点核实(origin/main)

    scripts/js-comment-mask.mjs:302
        if (c === '/' && source[i - 1] !== '<' && !(IDENT_CHAR.test(prev) || prev === ')' || prev === ']')) {
    

    ⇒ #6891 的 LT SLASH 规则已落地(source[i - 1] !== '<'),而判别式仍是「前一字节是不是一个值」:IDENT_CHAR / ) / ] 是值,⇒ } 与 > 都不是 ⇒ 卡片描述的两种幻影(自闭合标签的 / 跟在 } 后、JSX 文本里的 /)在这条判别式下确实仍然开启。

    scripts/__tests__/js-comment-mask-jsx-6891.test.ts:178
      describe('KNOWN LIMITS — the half this change does not close', () => {
    

    ⇒ 那一块 pin 确实在,⇒ 卡片那句「已被钉住,因此不能被静默关闭」成立。

    ⚠️ 本席未复现 4,322 个文件 / 145 字节 / 28 个文件的实测。⛔ 不当作已复现继承。


    ⭐ 卡片最重要的一段:它到达了 FABRICATES 方向

    the phantom swallows a comment opener that follows it on the same line, so genuinely commented-out text comes back to a caller as live code:

    const c = Foo bar={x} SLASH GT ; // dead = 1;
    

    maskComments leaves dead = 1; standing. That is the direction this module's header calls worse than no verifier at all.

    ⇒ ⭐ 这不是「漏报」,是「捏造」——一段被注释掉的代码被交还给调用方当作活代码。⛔ 这条把本卡与一个普通的覆盖面缺口区分开了,而它正是该模块自己的档头判定为「比没有验证器更糟」的那个方向。

    ⚠️ 而卡片诚实地记下了为什么这 145 字节此前不可见:「它们此前不可见,只是因为闭合标签那个更大的幻影在同一行上更早开始并覆盖了它们。」 ⇒ 修好一半反而让另一半显形 —— 这是一个诚实的、非直觉的读数。

    为什么定 p3(尽管方向危险)

    • 今天没有任何门的判决因此移动(卡片自陈);
    • 残留是 145 字节 / 28 个文件,且已被 pin 钉住 ⇒ 它是一条被声明的边界,不是一个静默盲区;
    • ⛔ 不升 p2:FABRICATES 方向虽然危险,但尚未有任何一次实际误判被记录(卡片未主张有)。
    • ⛔ 不降更低:它是被这个模块自己的档头判定为最坏方向的那一类,且 pin 的存在意味着关闭它必须是刻意的。

    为什么是决定箱

    卡片列了三支,并且证明了没有便宜的一票解:

    There is no one-token rule for it, and the two obvious ones are both wrong:

    1. 「/ 后跟 GT 是标签闭合」 —— 那正是一个匹配 GT 的正则的写法(str.replace(/GT/g, '&gt;')),而这棵树里就有这种写法。
    2. 「把 } 与 GT 当作值」 —— 两者在 JavaScript 里确实歧义:function f(){} /re/ 是正则,而 a GT /re/.test(b) 也能解析。
      Separating them needs to know whether the scanner is inside a JSX element, which is a parser.

    ⇒ ⭐ 两条显而易见的规则各自被一个树内反例否掉 —— 这不是「还没想到办法」,是已经证明了廉价规则不存在。⇒ 决定箱成立。⛔ 本席不裁决(本会话 claude-opus-5,CONTRACT_REVIEW_TIER 硬门要求 fable)。

    四facet

    ① 事实(已核) js-comment-mask.mjs:302 的判别式以「前一字节是否为值」决定是否开启正则;} 与 > 不在值集里 ⇒ 自闭合 JSX 标签(/ 跟在 } 后)与 JSX 文本里的 / 仍开启一个跑到行尾的幻影。实测残留 145 字节 / 28 文件,且到达 FABRICATES 方向。四种形状已被 js-comment-mask-jsx-6891.test.ts:178 的 KNOWN LIMITS 钉住。

    ② 分叉

    1. 不动。残留 145 字节,已钉住,今天无门的判决移动。
    2. 移植 objectstack 的语料 sweep(scripts/check-comment-mask-corpus.mjs,本模块档头明说尚未移植到这里),对着一个独立的 parser 做测量再决定,而不是对着用例决定。
    3. 一个 JSX-aware 模式,按调用方 opt-in。

    ③ 各支的代价

    1. 最便宜,且只要 pin 留着就是诚实的。⚠️ 但 FABRICATES 方向留在树上。
    2. ⭐ finding(tooling): js-comment-mask reads a JSX closing tag as a regex literal — 7 measured call sites become undelimitable #6891 自己的分诊已经点名这是唯一能回答「它往哪个方向失败」的路线 ⇒ 它不是三支之一,它是回答另外两支所需的前置测量。
    3. 最大,且它改变了这个模块是什么(卡片:js-comment-mask.mjs 刻意是一个廉价的语言级 masker,把它变成 parser 是另一张卡)。

    ④ 需要裁决者提供的东西
    一句话:js-comment-mask 是否应当保持为一个廉价的语言级 masker? 答「是」⇒ 1 或 2(且 2 只是把边界测清楚,不改性质);答「否」⇒ 3,但那是重新定义这个模块。

    ⚠️ 本席补一条:路线 2 与另外两支不互斥,且它是唯一能把「145 字节」这个数字变成「往哪个方向、影响哪些门」的东西。⇒ 建议裁决者无论最终选 1 还是 3,都先批准 2。

    ⭐ 一条不可省的约束

    Already pinned, so this cannot be closed silently. … Whoever closes this will see those pins fail and must retire them deliberately — the same two-way discipline that surfaced #6891 itself.

    ⇒ ⛔ 任何一支(包括「不动」)都不得在不处理那四条 pin 的情况下关闭本卡。 ⭐ 而「双向纪律」正是本轮同批 #7883 里那条反着写的钉子所示范的东西——同一个模块族,同一条纪律,第二次生效。

    Related:#6891(已落地的 LT SLASH 那一半)· #7883(因 #6891 而冗余的那个下游变通,本轮已判 pm:queue / p3)· objectstack 的 scripts/check-comment-mask-corpus.mjs(路线 2 的来源)。


    ⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box。


    Generated by Claude Code

  2. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Ruling recorded — option 2, with a standing principle (director seat, decision batch #72, 2026-09-07)

    Maintainer reply, verbatim: 「7749 已加入队列,其他同意」 — this card was presented with option 2 recommended and is covered by 「其他同意」.

    Ruling:

    1. js-comment-mask stays a cheap, language-level masker. ⛔ Option 3 (a JSX-aware mode) is ruled out: it changes what the module is, and a parser is a different card if one is ever wanted.
    2. Port objectstack's corpus sweep (scripts/check-comment-mask-corpus.mjs, named in this module's own header as not yet ported) and measure the residue against an independent parser — which direction it fails in, and which gates' verdicts it can move. That measurement is the deliverable; it turns "145 bytes / 28 files" into a reading a decision can be made on.
    3. The four KNOWN LIMITS pins in scripts/__tests__/js-comment-mask-jsx-6891.test.ts stay until a fix retires them deliberately. ⛔ Nothing closes this card silently.

    After the sweep: if it shows the FABRICATES direction actually moves a gate's verdict, the card comes back to the decision box with that reading; if it shows no gate is affected, option 1 (leave it, pinned) is the standing answer and the card can close on the measurement.

    needs-user-decision → pm:queue.


    Generated by Claude Code

  3. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round R46 — domain:devx @ objectui execution seat.
    Session: session_01FhBNJcLRZLe8M87VcUgpKr
    Branch: claude/issue-7882-comment-mask-corpus-sweep
    Worktree: /home/user/objectui-issue-7882
    Domain: domain:devx
    File surface: new scripts/check-comment-mask-corpus.mjs (ported from objectstack) plus its test under scripts/__tests__/, a check:* line in the root package.json, and the header paragraph of scripts/js-comment-mask.mjs that says the sweep is not ported. ⛔ Not the masker's scanner, not the four KNOWN LIMITS pins, not .github/workflows/**.
    Dispatch: one os-dev subagent of this session (mode:subagent, model: opus); the dispatch note with the brief follows on this card. Labels pm:queue → pm:dispatched and assignee set in one write, read back at 2026-09-07T07:23Z.


    Generated by Claude Code

  4. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Dispatched — domain:devx @ objectui execution seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-07T07:25Z. Batch 3 of 3 in flight (with #5174 batch 35 in CI on PR #8271 and #7964; disjoint file surfaces).

    Dev. One os-dev subagent of this session on branch claude/issue-7882-comment-mask-corpus-sweep, worktree /home/user/objectui-issue-7882, base origin/main at b6f821a8b or newer. Race re-read at 07:23Z: the newest Claim: on this card is 5566735980, naming that branch.

    Ruling applied, verbatim in the brief: comment 5565859060 (director seat, decision batch #72, maintainer 「其他同意」): the masker stays a cheap language-level masker (option 3 ruled out); port objectstack's scripts/check-comment-mask-corpus.mjs and measure the residue against an independent parser — direction, and which gates' verdicts it can move; the four KNOWN LIMITS pins stay; nothing closes the card silently. The PR is the port (Part of #7882, no closing keyword); the measurement is posted on this card, and this seat decides on it whether the card closes on option 1 or returns to the decision box.

    Premise check (read 07:22Z on b6f821a8b). The discriminator at js-comment-mask.mjs line ~302 is as the triage read it (/ after } or > still opens a phantom); the header (lines ~64–70) still says the sweep "is not ported to objectui and nothing in this repository runs it"; KNOWN LIMITS at the test's line 189; objectstack's script is at blob dd50cb13a and imports a helper (import-prerequisite.mjs) objectui lacks. Whether @typescript-eslint/parser is a root devDependency here is the first assumption tested: present → use; transitive only → declare at the lockfile's version; absent → measured stop (a new dependency is the maintainer's call).

    Mechanism assumptions the dev tests first: objectui's scanSource exposes a per-byte comment flag the comparator can diff; the ported --self-test is green on the unchanged masker and the --masker control is red, both by exit code; the sweep bounds in time over this tree; the card's 145 bytes / 28 files re-derive (not inherited); "which gates it can move" is answered by running the masker's importers under scripts/ on the base against the FABRICATES files.


    Generated by Claude Code

  5. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    os-dev-report

    The measurement (the deliverable the ruling asked for)

    Taken on b6f821a8b, whole tree, @typescript-eslint/parser 8.67.0 as the independent oracle.

    files swept 4,418
    unparseable 0
    files disagreeing with the parser 1
    FABRICATES bytes (parser says comment, mask says code) 0
    OVER-MASKS bytes (mask says comment, parser says code) 1,517
    wall clock 32.0-33.4 s

    Which direction it fails in: OVER-MASKS, exclusively. There is not one fabricated byte anywhere in the tree. That is the direction js-comment-mask.mjs's own header calls the better one to fail in.

    The one disagreement

    apps/console/src/pages/DocsIndex.tsx, one contiguous span, lines 63 to EOF (1,517 bytes, 37 lines).

    It is objectui#7882's "slash in JSX text" half, reaching a worse case than the card describes. The JSX text src/docs/*.md puts a / immediately before a *, so the masker opens a phantom block comment -- not the phantom regex the card leads with -- and since no terminator follows anywhere in the file, it swallows the entire remainder of the file. Every gate that masks this file reads 37 lines of live JSX as prose.

    Which gates' verdicts it can move: NONE, measured

    Seven gates under scripts/ import the masker. Which of them actually open that file was measured with a readFileSync probe rather than reasoned from their globs:

    gate reads the file verdict moves
    check-vi-mock-inherit yes no
    check-vi-mock-specifiers yes no
    check-doc-example-shared-reader no n/a
    check-docs-route-eager-closure no n/a
    check-element-data-source-declaration no n/a
    check-entry-guard no n/a
    check-pre-install-import-graph no n/a

    For the two that read it: each was run against the tree as-is and against a copy in which the phantom is closed by a one-character edit to the JSX text. Both exit 0 in both conditions with byte-identical output. The mutation was verified on disk (blob hash moved, marker counts flipped) and the restore verified by an empty git diff HEAD plus a matching blob hash.

    The card's own numbers, re-derived rather than inherited

    claim re-derived equal
    145 literal bytes 145 yes
    across 28 files 28 yes
    0 comment bytes changed by the objectui#6891 fix 0 yes

    WARNING -- these are a different measurement from the sweep's, and neither supersedes the other. The card's 145/28 is a diff of the LITERAL flag arrays between today's masker and the pre-objectui#6891 one. The sweep diffs the COMMENT array against a parser. Because the two maskers differ by zero comment bytes tree-wide, a comment-array comparator is blind to the objectui#6891 / objectui#7882 phantom by construction, except where that phantom happens to swallow a comment opener -- which in this tree happens exactly once, in the file above.

    Consequence worth carrying into the decision: the ported sweep is not an instrument for the literal-flag half of this card. A green run must not be read as coverage of it. This is stated in both headers rather than left to be discovered.

    Against the ruling's own decision rule

    if it shows the FABRICATES direction actually moves a gate's verdict, the card comes back to the decision box with that reading; if it shows no gate is affected, option 1 (leave it, pinned) is the standing answer and the card can close on the measurement.

    FABRICATES is zero bytes, and no gate's verdict moves. On the ruling's own terms that is the option 1 branch: leave it, pinned. The four KNOWN LIMITS pins are untouched and still pass.

    One qualification for the PM, offered rather than acted on: the reading is clean in the FABRICATES direction but not clean overall -- 37 lines of a real component are currently invisible to two gates. That costs nothing today because neither gate has anything to say about that file, and it is the quiet direction by design. It is a fact with a shelf life, not a property, which is what the ported script exists to re-take.

    The instrument

    Draft PR: #8277 -- Part of #7882, no closing keyword, left in draft.

    {
      "issue": 7882,
      "status": "done",
      "branch": "claude/issue-7882-comment-mask-corpus-sweep",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8277",
      "base_sha": "b6f821a8b7feda5636521b603c3e974fa52d5db3",
      "final_head": "4e28c0dae66384f38416522863b5575c4b7a4151",
      "premise_still_valid": true,
      "assumptions": {
        "A1_parser_resolves_from_root": "FALSIFIED as stated, and routed around without a new dependency. '@typescript-eslint/parser' is NOT a root devDependency here (only the 'typescript-eslint' meta-package, ^8.67.0) and does not resolve from the repo root at all under pnpm isolated node_modules (measured: ERR_MODULE_NOT_FOUND). The dispatch's remedy was to declare it at the lockfile version; a cheaper one exists and was taken: 'typescript-eslint' re-exports the identical parser at the identical version and is already declared, so the port adds NO dependency and moves NO lockfile line. Cost: the re-export exposes parseForESLint rather than parse, adapted in one function (adaptParse).",
        "A2_scanSource_exposes_comment_array": "HELD. objectui's scanSource returns { comment, literal } as same-length Uint8Arrays; the comparator needed no adaptation.",
        "A3_selftest_green_and_masker_control_red": "HELD, but NOT via the masker the dispatch suggested. --self-test passes unchanged (23 cases, exit 0). The positive control is a blind masker in a temp dir: exit 1, 4,370 of 4,418 files, 21,602,924 fabricated bytes. The pre-objectui#6891 masker does NOT work as a control here -- measured, it produces an IDENTICAL reading and exits 0, because that defect moves zero comment bytes. Recorded in the header as a property of the instrument.",
        "A4_bounded_time": "HELD. 4,418 files in 32.0-33.4 s wall clock across five runs; 0 unparseable.",
        "A5_card_numbers_rederived": "HELD and re-derived, not inherited: 145 literal bytes across 28 files, and 0 comment bytes changed, all exact. But the sweep CANNOT derive them -- they are a literal-array masker-vs-masker diff, taken with a separate one-off instrument. FABRICATES is reachable in principle (the KNOWN LIMITS pin proves the shape) yet measures ZERO in this tree."
      },
      "sweep_reading": {
        "files_scanned": 4418,
        "wall_clock_s": 32.0,
        "unparseable": 0,
        "fabricates": { "files": 0, "bytes": 0 },
        "over_masks": { "files": 1, "bytes": 1517 },
        "card_claim_rederived": "equal -- 145 bytes / 28 files / 0 comment bytes moved, all exact, via a separate literal-array instrument"
      },
      "gates_that_read_fabricates_files": [],
      "gates_that_read_the_disagreeing_file": [
        { "gate": "check-vi-mock-inherit", "reads": true, "verdict_moves": false, "evidence": "exit 0 both before and after the phantom is closed; stdout byte-identical (diff empty)" },
        { "gate": "check-vi-mock-specifiers", "reads": true, "verdict_moves": false, "evidence": "exit 0 both before and after; stdout byte-identical (diff empty)" },
        { "gate": "check-doc-example-shared-reader", "reads": false, "verdict_moves": false, "evidence": "readFileSync probe: never opens the file" },
        { "gate": "check-docs-route-eager-closure", "reads": false, "verdict_moves": false, "evidence": "readFileSync probe: never opens the file" },
        { "gate": "check-element-data-source-declaration", "reads": false, "verdict_moves": false, "evidence": "readFileSync probe: never opens the file" },
        { "gate": "check-entry-guard", "reads": false, "verdict_moves": false, "evidence": "readFileSync probe: never opens the file" },
        { "gate": "check-pre-install-import-graph", "reads": false, "verdict_moves": false, "evidence": "readFileSync probe: never opens the file" }
      ],
      "files_changed": [
        "scripts/check-comment-mask-corpus.mjs (new)",
        "scripts/__tests__/check-comment-mask-corpus.test.ts (new)",
        "scripts/js-comment-mask.mjs (header only)",
        "package.json (one check: script line)"
      ],
      "gates": {
        "vitest scripts/__tests__/check-comment-mask-corpus.test.ts": 0,
        "vitest scripts/__tests__/js-comment-mask*.test.ts": 0,
        "vitest scripts/__tests__/ (whole suite, 116 files / 3443 tests)": 0,
        "check-comment-mask-corpus.mjs --self-test": 0,
        "check-comment-mask-corpus.mjs (the sweep)": 0,
        "check-comment-mask-corpus.mjs --masker BLIND (positive control)": 1,
        "check-comment-mask-corpus.mjs --no-such-flag (usage)": 2,
        "pnpm check:phantom-deps": 0,
        "pnpm check:entry-guard": 0,
        "pnpm check:control-bytes": 0,
        "pnpm check:upstream-port-parity": 0,
        "pnpm type-check:scripts": 0,
        "pnpm lint:root": 0,
        "node scripts/check-changeset-presence.mjs": 0,
        "node scripts/check-governed-queue-guard.mjs --test (4 paths)": 0
      },
      "deviations": [
        "Oracle reached through the already-declared 'typescript-eslint' instead of declaring '@typescript-eslint/parser' at the root as the dispatch proposed. Strictly smaller: no new dependency, no lockfile movement, same package and version underneath. Declared in the script header as divergence 1.",
        "The sweep's posture is REPORT-with-a-ceiling rather than blanket exit 0. The dispatch said to make it REPORT because objectstack has no known-residue posture (verified: upstream fails on ANY disagreement, no allowlist). This copy exits 0 on today's tree -- so no new red, the stated constraint -- while a FABRICATED byte (currently zero) or an over-mask above the declared ceiling still reds. A gate that can never fail would have been a phantom check.",
        "Upstream's '.cache' skip entry dropped (objectstack-only: its console build materialises an objectui checkout there; this repo has no such directory) and this tree's own generated dirs added. 'apps/site/.source' really was in the corpus before this entry -- 4 generated files.",
        "objectstack's 1,448-line scripts/import-prerequisite.mjs was NOT ported; its one needed behaviour is inlined in ~15 lines. Cited in the header.",
        "The port is deliberately NOT enrolled in scripts/upstream-port-pin.json. That pin verifies by reversing declared divergences to a byte-exact reconstruction, which cannot pay off for a port with four structural divergences. Flagged as an open question rather than decided here.",
        "objectstack's scripts/pm/dispatch-gates.mjs does not exist in objectui, so the gate list was derived by hand from this repo's package.json and the importer graph, not machine-derived."
      ],
      "out_of_scope_findings": [
        "filed as objectstack#16540: check-comment-mask-corpus swallows an unknown FIRST option -- with --masker absent, indexOf returns -1 so the filter drops argv[0] instead of the flag pair, and an unknown flag runs a full sweep and exits 0 instead of the usage error. Found by this port's own test on its first run; the port carries the guard, objectstack does not."
      ],
      "open_questions": [
        {
          "question": "Should the ported sweep be enrolled in scripts/upstream-port-pin.json?",
          "options": [
            "A -- leave it unenrolled (what this PR does): the four divergences are structural, so a reversal would reconstruct most of the file and the pin would assert almost nothing while adding a re-sync ritual to every upstream edit.",
            "B -- enrol it: objectstack keeps fixing this script (the argv defect above is one), and today nothing tells objectui that upstream moved."
          ],
          "recommendation": "A for now, and B is a real card once the divergences settle. On the business-need axis the pin's demonstrated value was catching 3,600 lines of silent drift in a near-verbatim copy; this copy is not near-verbatim, so that mechanism does not fit it. On the startup-focus axis an enrolment costs a ritual on every upstream edit for an instrument run by hand today. The cost of A is real and named: upstream fixes will not arrive on their own."
        },
        {
          "question": "Is the ceiling posture the right long-term shape, or should the sweep be wired into CI?",
          "options": [
            "A -- leave it a hand-run instrument (what this PR does; no workflow edits were permitted).",
            "B -- wire it into lint.yml so the FABRICATES-zero assertion is actually enforced on every PR."
          ],
          "recommendation": "B eventually, as a separate card with the workflow change. On the anti-AI-error axis the FABRICATES assertion is exactly the contract-tightening kind -- it is at zero today, so enforcing it is free and it fails loudly rather than tolerantly. But it needs a ~33 s CI step and a workflow edit this dispatch forbids, so it is a decision, not a rider."
        }
      ],
      "mcp_calls": 2,
      "summary": "Ported objectstack's corpus sweep to objectui as scripts/check-comment-mask-corpus.mjs with a test, a package.json script line, and the js-comment-mask.mjs header paragraph that claimed the sweep was unported. scanSource, the discriminator and the four KNOWN LIMITS pins are untouched. The measurement: 4,418 files, ONE disagreement, ZERO fabricated bytes, 1,517 over-masked bytes, all of it objectui#7882's slash-in-JSX-text shape in apps/console/src/pages/DocsIndex.tsx, where a slash before a star opens a phantom block comment that runs to EOF. No gate's verdict moves -- measured by running the two gates that actually read the file against a copy with the phantom closed. The card's 145 bytes / 28 files re-derives exactly, but via a separate literal-array instrument: the comment-array sweep is blind to that half by construction, which is recorded in both headers so a green run is not misread as coverage.",
      "tests": "vitest scripts/__tests__/check-comment-mask-corpus.test.ts -> exit 0, 28 tests. vitest on both mask test files -> exit 0, 50 tests (KNOWN LIMITS pins intact). Whole scripts suite -> exit 0, 116 files / 3,443 tests (via the shared verify lock: VERDICT command-exit 0, held the lock 117s). Self-test -> exit 0, 23 cases. Sweep -> exit 0 (REPORT). Positive control, blind masker in a temp dir -> exit 1, 4,370 of 4,418 files, 21,602,924 fabricated bytes, with the temp fixture removed by a trap. Verdict-move experiment -> source mutation proven on disk (blob 40900c7b to 00f29056, marker counts 1 to 0 and 0 to 1), both gates byte-identical, restore proven by empty git diff HEAD and a blob hash matching HEAD. All exit codes captured by redirect, never through a pipe."
    }

    Generated by Claude Code

  6. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    LANDED and CLOSED on the measurement — domain:devx @ objectui seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, 2026-09-07T08:29Z.

    PR #8277 merged at 08:28:37Z as 3c6394cb2; content probe on re-fetched origin/main passed (the check:comment-mask-corpus script line, KNOWN_RESIDUE with the 1,517-byte ceiling, the masker header updated; control line present).

    The reading, per the ruling (5565859060) — "if it shows no gate is affected, option 1 (leave it, pinned) is the standing answer and the card can close on the measurement":

    reading value
    files swept 4,418
    FABRICATES bytes (parser says comment, mask says code) 0
    OVER-MASKS bytes 1,517, one file (apps/console/src/pages/DocsIndex.tsx, the slash-in-JSX-text shape reaching a phantom block comment to EOF)
    gates that read that file check-vi-mock-inherit, check-vi-mock-specifiers — both byte-identical output before and after the phantom is closed
    gate verdicts moved none
    the card's 145 bytes / 28 files re-derived exactly, by a separate literal-array instrument; the corpus sweep is blind to that half by construction (stated in both headers)

    So: option 1 stands. The four KNOWN LIMITS pins in scripts/__tests__/js-comment-mask-jsx-6891.test.ts stay, untouched by this PR, and remain the deliberate record; the masker stays a cheap language-level masker (option 3 ruled out). Closed as completed: the measurement the card was reopened for is taken and on record. State: pm:dispatched removed, assignee cleared in the same write.

    Follow-ups the dev left as open questions, routed: (1) wiring the sweep into CI so the FABRICATES-zero assertion is enforced on every PR (a ~33 s step and a workflow edit) → filed as its own finding; (2) enrolling the port in upstream-port-pin.json → recorded in the same card as the second question, since the same instrument is at stake. Upstream's argv defect found by the port's test is objectstack#16540 (finding).


    Generated by Claude Code

  7. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Follow-up filed: #8286 (finding) carries both open questions from the report — wiring the sweep into CI so the FABRICATES-zero assertion is enforced, and whether the port tracks upstream via upstream-port-pin.json. — domain:devx @ objectui seat, 2026-09-07T08:32Z.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repofindingpriority:p3tooling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions