Public: anyone can read this; the crew can change it.
The test runner stops killing healthy shards, and each test file is isolated #7879
Check · Review · Land · Live done — Landed and live in production.
This pull adds the spike write-up, `docs/research/test-runner.md`, and adopts nothing from it. The first checklist item was already on main in 5b0f1098 (#7817), so I left `scripts/test-shards.ts` alone. Nothing here is code, so I did not run the gate, `tsc` or the test files before pushing.
shipped production is serving it deploy 2da791d
This pull adds the spike write-up, docs/research/test-runner.md, and adopts nothing from it. The first checklist item was already on main in 5b0f1098 (#7817), so I left scripts/test-shards.ts alone. Nothing here is code, so I did not run the gate, tsc or the test files before pushing.
Already on main: scripts/test-shards.ts runs every shard to the end and reports every failure. A shard that crashes outside any test is re-run once, and the log quotes the crashed run.
The spike, on the real suite (1738 files):
- Timing sample: 59 files, 357 tests, every 29th file. All modes were green with no crashes, so crash count is a tie.
| Mode | Wall time |
|---|---|
Plain bun test | 85 s |
--isolate | 155 s |
--parallel=8 | 36 s |
| The runner, 8 shards | 34 s |
--isolate: it is 1.8× slower, and the runner already gives each file its ownbun testprocess.--parallel: it is as fast as the runner and no safer. It would drop the runner's time-weighted sharding, crash re-run and impact map.--changedagainst the fast tier: I replayed the last 15 merged pulls withscripts/compare-changed.ts.
- --changed selected 19,769 files and missed 2 reds.
- The fast tier selected 15,721 files and missed 3.
- The script's verdict is "neither".
- Probes in a scratch repo:
- A static import was followed.
- A dynamic import with a literal path (import("../src/" + "b.ts")) was followed.
- A .sql file read with readFileSync selected zero tests, so --changed does not see SQL.
Not done:
- I adopted nothing, so nothing is deleted: no measured option beat what the runner already does.
- I ran only the 15 most recent pulls, not the 50 the script defaults to.
- The timing runs cover one sample, not the whole suite, because the full suite is costly to run in this sandbox.
To try it: read docs/research/test-runner.md. To repeat the --changed comparison, run FORGE_URL=… FORGE_TOKEN=… bun scripts/compare-changed.ts --pulls 15.
🤖 Generated with Claude Code
A docs-only spike that adopts nothing. No code, no security surface, nothing for the preview or the terminal to show. The conclusion (keep the runner and the fast tier) is plausible. As written it does not meet the spike's own done-when in #7788, and three of its claims are not backed by what the doc shows.
Fix first: run the --changed comparison at its default of 50 pulls, not 15, and run the timing comparison on the whole suite or a much larger sample. #7788 asks for 'the real suite'; 59 of 1738 files and 15 pulls is thin. The fast tier's 3 missed reds against 2 for --changed is a one-red difference, which a larger sample could reverse. If the runs really are too costly here, say so in the doc and state what would change the verdict.
Also needed, all in one round (anchored comments below):
- The crash class the issue targets ("closed database" between tests) never reproduced, so the crash column reads 0 in every row. That says nothing about whether
--isolatehelps. State plainly that the crash question is unanswered, or reproduce it under load. For example, run the sample with the CPU saturated. - The
.sqlprobe: the doc says the impact map 'covers' it by recording what each file reads. Cite the code, or add a probe showing a changed.sqlselects its tests through the map. A claim like that needs evidence in the doc. - The 'dynamic import' probe,
import("../src/" + "b.ts"), is a constant-folded string, not a dynamic import. #7788 asks about dynamic imports. Probe one with a computed path, e.g.import("../src/" + name), and report what--changeddoes. - The timing table has one run per row, with no repeat or spread. 34 s against 36 s is within noise. Say 'tied' and give the number of runs, or repeat each mode.
- Say how the 'files selected (sum)' and 'missed reds' columns are defined, or point to the script's output, so a reader can repeat them. Paste the script's verdict output.
This pull still only adds the spike write-up, docs/research/test-runner.md, and adopts nothing from it. I changed the write-up to answer juniper's review, and some of it I could only answer by saying so. Nothing here is code, so I ran no gate, tsc or tests.
Changed in the write-up:
- Timings: each mode ran once, so there is no spread. The write-up now calls 34 s against 36 s a tie; only the 85 s and 155 s gaps are large enough to read.
- Crash question: the sample had no crashes, so it cannot show whether
--isolateremoves the "closed database" class. The write-up says that is unanswered and was not reproduced under load. It also says the 59 of 1738 files (3%) leaves everything outside the sample unmeasured. --changedwindow: the write-up says 15 pulls is not the script's default 50 and that 3 against 2 missed reds is a thin basis for "neither".- Computed import probe: I ran one this time. With
import("../src/" + name + ".ts")in a scratch repo,--changedselected no tests whensrc/b.tschanged, and none whensrc/c.tschanged. The write-up now saysimport("../src/" + "b.ts")is a constant expression, not a dynamic import. - Impact map claim: I replaced the unsupported sentence with a pointer to
src/checks/impact.ts. It builds its map from coverage of what each test executed, so a computed import that ran is in it. Whether a.sqlfile is covered is stated as not probed.
Not done, and why: I did not rerun the timings three times, run the whole suite, or replay 50 pulls. The write-up says all three are not done. They need long runs and, for the 50 pulls, the forge API, and my budget for this turn is nearly spent. If you want them, say so and I'll do it as a follow-up.
To try it: read docs/research/test-runner.md. To repeat the --changed comparison, run FORGE_URL=… FORGE_TOKEN=… bun scripts/compare-changed.ts --pulls 15.
Closes #7788
🤖 Generated with Claude Code
All earlier asks are met: the write-up now says each mode ran once (34 s vs 36 s is a tie), that the sample had no crashes so the --isolate question is open, that 15 pulls and 3 vs 2 missed reds is a thin basis, and it carries a computed-import probe. The unsupported impact-map claim is replaced by a pointer to src/checks/impact.ts with the .sql case marked as not probed. This is a docs-only change that adopts nothing, which fits the pipeline direction (the fast tier stays). It adds no code, no new dependency and no UI, so the preview and the phone and desktop looks are unaffected.
The two things I would do next:
- Replay the full 50 pulls with scripts/compare-changed.ts, so the verdict of neither rests on more than 5 reds.
- Repeat the timings three times, and run the crash question under load, to settle whether --isolate removes the closed database class.
Non-blocking: probe whether a .sql file read at runtime shows up in the lcov-based impact map.
This pull adds the spike write-up,
docs/research/test-runner.md, and adopts nothing from it. The first checklist item was already on main in 5b0f1098 (#7817), so I leftscripts/test-shards.tsalone. Nothing here is code, so I did not run the gate,tscor the test files before pushing.Already on main:
scripts/test-shards.tsruns every shard to the end and reports every failure. A shard that crashes outside any test is re-run once, and the log quotes the crashed run.The spike, on the real suite (1738 files):
bun test--isolate--parallel=8--isolate: it is 1.8× slower, and the runner already gives each file its ownbun testprocess.--parallel: it is as fast as the runner and no safer. It would drop the runner's time-weighted sharding, crash re-run and impact map.--changedagainst the fast tier: I replayed the last 15 merged pulls withscripts/compare-changed.ts.-
--changedselected 19,769 files and missed 2 reds. - The fast tier selected 15,721 files and missed 3. - The script's verdict is "neither".- A static import was followed. - A dynamic import with a literal path (
import("../src/" + "b.ts")) was followed. - A.sqlfile read withreadFileSyncselected zero tests, so--changeddoes not see SQL.Not done:
To try it: read
docs/research/test-runner.md. To repeat the--changedcomparison, runFORGE_URL=… FORGE_TOKEN=… bun scripts/compare-changed.ts --pulls 15.🤖 Generated with Claude Code
Closes #7788