Demonstrated, not hypothetical: it happened to me while working #8119, and the stray file reached a commit. Filed unassigned.
The window
scripts/check-type-check-coverage.mjs --re-measure measures each ledgered package's TEST_DEBT by writing a scratch tsconfig into that package's own directory:
const REMEASURE_CONFIG = 'tsconfig.debt-remeasure.json';
const configPath = join(ROOT, dir, REMEASURE_CONFIG);
…
writeFileSync(configPath, `${JSON.stringify(project, null, 2)}\n`);
try {
return tscErrorCount(posix.join(dir, REMEASURE_CONFIG));
} finally {
rmSync(configPath, { force: true });
}
The cleanup is correct and the finally is right. The gap is that the path is inside a tracked directory and matches no .gitignore rule, so for the duration of one package's tsc run the repo has an untracked, non-ignored file sitting in packages/<name>/.
The function's own docblock already anticipates the stray-file hazard — "a stray tsconfig.*.json left behind would be picked up by this very script's own tsconfig scan on the next run" — but only from the script's perspective. From git's perspective it is an ordinary new file.
What it costs
The full re-measure is slow (221s in my run, 33 entries, sequential by design), so the aggregate window is minutes. Anything doing git add -A in that worktree during it commits the scratch file. That is not an exotic move here: it is what the standard commit flow does, and this repo runs many agents in parallel.
In my case the sequence was ordinary — start the gate, write an unrelated one-line doc fix while it ran, git add -A && git commit:
2 files changed, 72 insertions(+), 1 deletion(-)
create mode 100644 packages/cli/tsconfig.debt-remeasure.json
71 lines of generated tsconfig in a docs-only commit. It never reached main (that commit was blocked from pushing for an unrelated reason and I caught it when re-applying), but nothing in the toolchain would have stopped it — and the follow-on is worse than the file itself: the gate's finally then deleted it, so git status showed a deleted tracked file, which reads exactly like a real deletion to clean up. Restoring it with git checkout -- (the natural response) re-materialises the junk and makes it look intentional.
Suggested fix
One .gitignore line — tsconfig.debt-remeasure.json, or tsconfig.*.remeasure.json if a pattern is preferred. No behaviour change to the gate, and it makes the accident structurally impossible rather than relying on nobody committing during a several-minute window.
Worth a scan for sibling generators writing scratch files into tracked dirs under names no ignore rule covers; I only checked this one.
Not the same as
Generated by Claude Code
Demonstrated, not hypothetical: it happened to me while working #8119, and the stray file reached a commit. Filed unassigned.
The window
scripts/check-type-check-coverage.mjs --re-measuremeasures each ledgered package's TEST_DEBT by writing a scratch tsconfig into that package's own directory:The cleanup is correct and the
finallyis right. The gap is that the path is inside a tracked directory and matches no.gitignorerule, so for the duration of one package'stscrun the repo has an untracked, non-ignored file sitting inpackages/<name>/.The function's own docblock already anticipates the stray-file hazard — "a stray
tsconfig.*.jsonleft behind would be picked up by this very script's own tsconfig scan on the next run" — but only from the script's perspective. From git's perspective it is an ordinary new file.What it costs
The full re-measure is slow (221s in my run, 33 entries, sequential by design), so the aggregate window is minutes. Anything doing
git add -Ain that worktree during it commits the scratch file. That is not an exotic move here: it is what the standard commit flow does, and this repo runs many agents in parallel.In my case the sequence was ordinary — start the gate, write an unrelated one-line doc fix while it ran,
git add -A && git commit:71 lines of generated tsconfig in a docs-only commit. It never reached
main(that commit was blocked from pushing for an unrelated reason and I caught it when re-applying), but nothing in the toolchain would have stopped it — and the follow-on is worse than the file itself: the gate'sfinallythen deleted it, sogit statusshowed a deleted tracked file, which reads exactly like a real deletion to clean up. Restoring it withgit checkout --(the natural response) re-materialises the junk and makes it look intentional.Suggested fix
One
.gitignoreline —tsconfig.debt-remeasure.json, ortsconfig.*.remeasure.jsonif a pattern is preferred. No behaviour change to the gate, and it makes the accident structurally impossible rather than relying on nobody committing during a several-minute window.Worth a scan for sibling generators writing scratch files into tracked dirs under names no ignore rule covers; I only checked this one.
Not the same as
Generated by Claude Code