Uh oh!
There was an error while loading. Please reload this page.
fix(tooling): see entry guards written inside template interpolations - #11854
Conversation
…e to the gate
Port objectui's landed scanSource shape (objectui PR 6133): a third
interpolation array marks the bytes a ${...} interpolation contributes as
code, with both load-bearing exclusions — the ${ / } delimiters stay
masked so bracket counters stay balanced, and a nested template's body
stays masked because those bytes really are content. comment and literal
are byte-identical before and after (swept over the corpus gate's 5,028
files), so every existing caller keeps the mask it had.
check-entry-guard.mjs's codeOnly() now subtracts the interpolation span,
so the percent-encoding spelling — a guard written inside a template
literal, the one invoked-as.mjs's header singles out as going inert with
no symlink at all — is seen (measured: 0 findings before, 1 after), while
string payloads for spawned children (run-with-stall-guard.mjs) stay
masked. Full-tree gate verdict is byte-identical before and after.
Issue: 11838 (port of the downstream fix for the gate hole recorded there)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZxos-steve
commented
Aug 24, 2026
ACCEPT — PM review, The additivity is structural, which is stronger than the sweep that confirms itThis was the property I said had to be proven, not asserted, because 24 modules import this masker and four of them are being edited by concurrent work right now. The one line that carries it: both[i]=comment[i]||(literal[i]&&!interpolation[i]);
⭐ And The 5,028-file sweep (0 comment mismatches, 0 literal mismatches, positive control at index 20809) confirms what the shape already guarantees. Belt and braces, in the right order. The corpus gate I named as first-class judge, ran and passed
The compatibility pin holds by construction, not by luckI checked ' require("fs").writeFileSync(process.argv[1], String(process.pid));\n'+Not an interpolation. So it is masked as Why the unchanged verdict is the correct result, not a missing effectThe gate's full-tree verdict is byte-identical before and after ( Two judgments worth namingYou refused an import that would have been plausible. objectui's port carries Ablation B corrected its own prediction. You predicted removing the delimiter-zeroing pass would red the simple-delimiter pin; it did not, because simple delimiters are never marked by the interior pass — only the nested case discriminates, and its failure detail shows the leaked inner brace. Reporting the refined direction rather than the predicted one is what makes the ablation evidence instead of ceremony. It also independently confirms why objectui's first cut desynced the statement slicer: the nested case is the only one that can. Flipping to ready. Arming waits — 5 checks still
Generated by Claude Code |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32782637285 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11838
What
scripts/check-entry-guard.mjscould not see an entry guard written inside a template literal:codeOnly()maskscomment || literal, andscanSourcereports an interpolation's bytes as the enclosing template's literal content. That is the documented contract and right for the mask's other callers, but it made the percent-encoding guard spelling — the oneinvoked-as.mjs's own header singles out as going inert with no symlink at all — prose as far as the gate is concerned. Measured on this tree at644ad5043(and re-measured at branch basea1c804bc9): 0 findings for the template spelling, 1 for the plain one.How — the landed downstream shape, ported, not re-derived
Ported from objectui's
mainat/after0c25598(objectui PR objectstack-ai/objectui#6133, part of objectstack-ai/objectui#6092), then adapted to this repo's callers:scripts/js-comment-mask.mjs—scanSourcereturns a third array,interpolation, marking the bytes a${...}interpolation contributes as code.commentandliteralare unchanged, so every existing caller keeps the mask it had. Both load-bearing exclusions are ported with their tests:${and its closing}stay masked, so a caller counting brackets stays balanced — including a nested interpolation's delimiters, which is the case that desynced the downstream statement slicer badly enough to report four genuinely-guarded files as running on import;literaltaken before the blanket flush), because those bytes really are content.scripts/check-entry-guard.mjs—codeOnly()subtracts the interpolation span:comment[i] || (literal[i] && !interpolation[i]). No other caller of the mask is touched.process.argv[1]in a template BODY outside any interpolation is still not a guard.This repo's gate has no
KNOWN_HAND_TYPED_GUARDSbaseline (upstream was swept first); none was imported.Evidence (all commands at
9baa4f055unless stated; verdicts quoted from each gate's own output)Fail-before / pass-after — driving
scanFileon the card's exact inputs: template spelling0 -> 1findings across the change; plain spelling1 -> 1.Additivity proven, not asserted — swept the corpus gate's own file list (
collectSources(), 5,028 files):commentandliteralbyte-identical between the base (a1c804bc9) and new implementations — 0 mismatches in either array, with a positive control (a single flipped byte is detected by the same comparator). The new array is non-vacuous: 2,751 files carry interpolation-flagged bytes (418,043 bytes).Corpus gate (first-class judge, exists only in this repo) —
✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 5028 files, 0 disagree, 0 unparseable, 36.1s (comparator self-test: 12 cases pass).Full-tree gate verdict invariance —
node scripts/check-entry-guard.mjsand--listoutput byte-identical before/after (diff empty; 148 files, 105 exporters, 10 known-unsafe unchanged), so no previously-reported file changed verdict.Ablations (from the committed state, mutation proven on disk by anchor counts,
node --checkon each mutant, byte-identical restore by sha, trap-guarded):codeOnlytocomment || literal→ gate self-test RED exactly on the new pin (the percent-encoding guard is seen THROUGH the template it is written in, 1 of 54);a NESTED interpolation contributes NO unbalanced brace to the code view(1 of 35) — the nested case is the discriminating one, since simple delimiters are never marked by the interior pass; the failure detail shows the leaked inner brace, the exact measured desync shape.Compatibility pin preserved —
run-with-stall-guard.mjs's spawned-child payload (process.argv[1]inside a plain string at:607) stays masked: strings areliteral-only, neverinterpolation; pinned by the existing STRING-payload case plus the newa STRING quoted inside an interpolation is not codecase.Derived gate union at
9baa4f055(node scripts/pm/dispatch-gates.mjs, no hand-fed paths, 8 matched families) — all green:js-comment-mask --self-test(35),check:entry-guard(54 + full tree), comment-mask corpus (5028/0/0),check:parse-guard(147 files),check:agent-test-spelling,check:cross-package-test-inputs(116 self-test + 16 packages OK),check:pnpm-filter-targets(134/167 resolved),check-nul-bytes(6,598 files clean).Changeset
None — CI-internal gate tooling only, releases nothing;
skip-changesetapplies (lint.yml's own prescription for this class of PR).Generated by Claude Code