Studio: pin what the trailing-placeholder window does with nested placeholders - #9091
Conversation
The module comment says the window's guarantee is about what is removed rather than about leaving an oversized fragment whole, and gives nested placeholders as the case where those two readings come apart. Nothing pinned it, so changing the behaviour to match the looser reading would have gone unnoticed. The test kills both directions: widening the window so the outer opener comes back into range, and declining to strip whenever an opener predates the window, which is the change a review of #9012 asked for.
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
Independent merge-worthiness check on this branch, since a characterization test is only The two mutants in the description are already coveredBoth rows in the table above do turn the new test red, but neither is a gap the branch
The first two are caught for cost, not for meaning: both add an unbounded backward scan, The mutant that this test, and only this test, catchesThe "leave the oversized fragment whole" reading is implementable without giving up the if (from > 0) {
const back = text.slice(Math.max(0, from - 2 * window), from);
if (back.includes("${")) {
return text;
}
}
const tail = text.slice(from);Full frontend suite, that mutant applied:
So it is the only guard in the suite against that change. That is the row the description Per assertion
The 4,208 assertion reads only the reference regex defined in the test file, so no change Why the input class is not an enumeration artefactThe shape is reachable from ordinary prose. A reply that mentions an unterminated 8,370 characters. The unbounded pattern removes 8,354 of them and leaves Other checks
|

Follow-up to #9012, which is merged. One test, no behaviour change.
Why
#9012 bounded the trailing
${...}strip to a 4096 character window. The guarantee it makes is about what is removed: the bounded scan never removes more than the unbounded pattern would, and always returns a prefix of the input. "The oversized fragment is left whole" is the usual consequence of that, but it is not the rule, and nested placeholders are where the two readings come apart.For
"answer ${" + "a".repeat(4196) + "${nested}"the outer${sits further back than the window, so the bounded scan does not see it as an opener, and the trailing${nested}is an ordinary complete fragment at the end of the buffer. It gets stripped and the outer text stays:answer)${nested})That is the correct outcome, and it is the direction that matters: on this input the unbounded pattern deletes 4,208 characters of model-written text and the bounded scan deletes 9. The module comment describes it, but nothing pinned it, so a later change to match the looser "left whole" reading would have passed the suite.
The test
Asserts that exactly
${nested}is removed, that the two removal counts are 4,208 and 9, and that the result stays a prefix of the input.Checked against deliberately broken trees rather than assumed to discriminate:
Worth recording that the first mutant I wrote for the second row used
lastIndexOf("${"), which finds the inner opener and therefore never triggered, so the mutant passed and briefly looked like a gap in the test. The row above usesindexOf.npm test3,588 passing, 0 failing.npm run typecheckclean.biome checkon the file is unchanged at 4 diagnostics, all pre-existing.