You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
finding: check-cross-package-test-inputs counts a template-literal argument as ONE descent, so it is LESS safe than an argument the scan cannot fold #11487
Observed while implementing #11093 (PR #11486); measured on origin/main at 7f30b6be, not reasoned.
The claim the file makes
scripts/check-cross-package-test-inputs.mjs states, twice, that an argument it cannot read costs the NAME and keeps the DEPTH, because the escape verdict is a lower bound:
An argument this scan cannot read leaves the DEPTH walk where it was — deliberately, since the escape verdict is a lower bound and has always been computed this way — but the NAME is gone
and lists a template-literal path among the shapes that yield "NO name — never a wrong one".
What is measured
PATH_LITERAL is /^(['"])([^'"]*)\1$/. A BACKTICK-delimited argument whose content holds no quote characters matches it — which includes an interpolating template such as `${someVar}`. walkLiteral() then treats ${someVar} as an ordinary segment and walks it as one descent.
That is not a lower bound. It biases the walk upward, and it can hide an escape that the documented trade catches. Same climb, same file, only the unreadable middle argument differs:
FLAGGED unreadable argument (documented trade: depth unchanged) -> [{"name":"P","depth":-1}]
NOT SEEN template literal argument (counted as ONE descent) -> []
produced by
constHERE=dirname(fileURLToPath(import.meta.url));constP=join(HERE,someVar,'../../other-pkg/src/y.ts');// flagged, depth -1constP=join(HERE,`${someVar}`,'../../other-pkg/src/y.ts');// NOT flagged
both at hereDepth = 1, through the exported escapingBindings().
The NAME half is currently harmless in practice but for a reason one level away from the resolver: pathExpression() does hand back segments containing the literal text ${someVar}, and it is findEscapingPackages()'s statSync(...).isFile() filter that drops the resulting roster entry. So "never a wrong name" holds today by a downstream filesystem check, not by the resolver the sentence is written against.
Why this is a finding rather than a defect card
No test in the tree spells a path this way today, so nothing is currently mis-verdicted — this is a property of the detector, not an outage. It is filed because the shape is the exact inverse of the trade the file relies on everywhere else: an unreadable argument is safe, and a template literal reads as readable while being less safe than unreadable.
Two dispositions, for triage rather than a recommendation:
Reject an interpolating template in PATH_LITERAL (a backtick literal containing ${), so it falls into the existing unreadable-argument branch — depth held, name dropped. Smallest change; makes the stated lower bound true.
Either way it wants a --self-test case per the header's own rule.
Refs: #9763 (the reconstruction that added the RESOLVED half and wrote the lower-bound sentence) · #11093 / PR #11486 (the line-spanning spelling, same resolver).
Observed while implementing #11093 (PR #11486); measured on
origin/mainat7f30b6be, not reasoned.The claim the file makes
scripts/check-cross-package-test-inputs.mjsstates, twice, that an argument it cannot read costs the NAME and keeps the DEPTH, because the escape verdict is a lower bound:and lists a template-literal path among the shapes that yield "NO name — never a wrong one".
What is measured
PATH_LITERALis/^(['"])([^'"]*)\1$/. A BACKTICK-delimited argument whose content holds no quote characters matches it — which includes an interpolating template such as`${someVar}`.walkLiteral()then treats${someVar}as an ordinary segment and walks it as one descent.That is not a lower bound. It biases the walk upward, and it can hide an escape that the documented trade catches. Same climb, same file, only the unreadable middle argument differs:
produced by
both at
hereDepth = 1, through the exportedescapingBindings().The NAME half is currently harmless in practice but for a reason one level away from the resolver:
pathExpression()does hand back segments containing the literal text${someVar}, and it isfindEscapingPackages()'sstatSync(...).isFile()filter that drops the resulting roster entry. So "never a wrong name" holds today by a downstream filesystem check, not by the resolver the sentence is written against.Why this is a finding rather than a defect card
No test in the tree spells a path this way today, so nothing is currently mis-verdicted — this is a property of the detector, not an outage. It is filed because the shape is the exact inverse of the trade the file relies on everywhere else: an unreadable argument is safe, and a template literal reads as readable while being less safe than unreadable.
Two dispositions, for triage rather than a recommendation:
PATH_LITERAL(a backtick literal containing${), so it falls into the existing unreadable-argument branch — depth held, name dropped. Smallest change; makes the stated lower bound true.Either way it wants a
--self-testcase per the header's own rule.Refs: #9763 (the reconstruction that added the RESOLVED half and wrote the lower-bound sentence) · #11093 / PR #11486 (the line-spanning spelling, same resolver).
Generated by Claude Code