Skip to content

check-entry-guard.mjs cannot see an entry guard written inside a template literal — the percent-encoding spelling its own header documents passes the gate #11838

Description

@yinlianghui-tw

Filed unassigned by the dev seat porting this gate to objectui (objectui#6092, branch claude/issue-6092-entry-guard-gate, session session_019b5UBNMtTzKbVtZZGvFuxe). Out of that card's scope — recording it, not acting on it.

What was measured

On 644ad5043, driving this repository's own scripts/check-entry-guard.mjs directly:

upstream scanFile findings for the percent-encoding spelling: 0
upstream scanFile findings for the plain spelling: 1

The two inputs were:

if(import.meta.url===`file://${process.argv[1]}`){main();}// → 0 findingsif(process.argv[1]===x){}// → 1 finding

So a hand-typed entry guard written inside a template literal is invisible to the gate, and lands green.

Why

codeOnly() masks comment || literal, and js-comment-mask.mjs's scanSource reports an interpolation's bytes as the enclosing template's literal content. That is its documented contract and it is the right answer for its other callers — a process.argv[1] inside a string payload for a spawned child is not a guard, which run-with-stall-guard.mjs:607 relies on. But it makes ${...} — which the language executes — prose as far as this gate is concerned.

Why it matters more than the shape suggests

`file://${process.argv[1]}` is not a hypothetical spelling. It is the one invoked-as.mjs's header singles out as the worst of the family, because it goes inert with no symlink involved at all: it percent-encodes apart from argv[1] in any directory whose name needs encoding. Measured in objectui in a directory named a#b c:

INERT file:///…/a%23b%20c/enc.mjs vs /…/a#b c/enc.mjs

The gate exists to stop the next spelling. This is the one spelling it cannot stop, and the failure is silent in the direction that matters: the gate reports a clean scan.

Not currently live here — git grep 'process.argv[1]' -- scripts/ on 644ad5043 returns only prose and one string payload, so nothing in this tree is written this way today. This is a hole in the gate, not an outage.

Measured in objectui, where the same tree is not yet swept: the straight port of this gate listed 28 of that repo's 29 hand-typed guards and omitted exactly the template-written one (scripts/check-node-esm-load.mjs:847).

The fix that was made downstream, for reference

objectui's port (PR objectui#6133) adds a third array to scanSource, interpolation, marking the bytes an interpolation contributes as code. comment and literal are unchanged, so every existing caller keeps the mask it had; a caller that wants the executed view subtracts. Two exclusions are load-bearing and are pinned there:

  • the ${ and its closing } stay masked, so a caller counting brackets stays balanced;
  • a nested template's body inside the interpolation stays masked, because those bytes really are content.

The second is not theoretical. A first cut that un-masked the whole span put a nested interpolation's inner } into the outer span's interior while its ${ stayed masked, and the unmatched brace desynced check-entry-guard.mjs's top-level statement slicer badly enough that four files whose dispatch really is guarded were reported as running on import.

Whether this repository wants the same shape, a different one, or judges the hole acceptable given the tree is currently clean, is the call to make — this is a report, not a proposal.

Refs: objectui#6092 (the port) · objectui#6133 (the downstream fix) · objectstack#10427 (the last time scanSource's template handling cost something)


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions