Created Started Cancelled
Make controls sparser and cheaper to run Stacked on #156, whose `writeChildTask` it does not depend on but whose driver version and changelog it would otherwise collide with. Rebase onto `development` once that merges. A control is a no-op mutation that is expected to survive, so unlike a real mutation its child cannot stop at the test that kills it: it runs every covering test it is given, to the end. That makes the cheapest kind of mutation to produce the most expensive kind to run. Measured on a large project's mutation phase, after #156 removed the per-child manifest parse. Per-child wall over 150 random mutations: median 1.05 s, mean 5.64 s, p99 91 s, max 155 s — and the top 5 of those 150 are 62% of the time. Four of those five are controls or mutations that run out their budget; the two most expensive are controls covered by 150 and 178 tests, at 155 s and 130 s each. Charging each child's suite setup once rather than once per test, the run's controls came to roughly 6300 of its 16100 slot-seconds at eight jobs: **a fourteenth of the mutations, well over a third of the phase**. ### What changes - One control every hundred mutations rather than every twelve (`controlInterval`). - Each control is checked against ten of its covering tests rather than all of them (`controlCoveringTestLimit`). Not the ten cheapest: the fastest tests are the least likely to be the ones a suite cannot be relied on for, so taking those every time would aim the canary away from what it is watching for. Which ten follows from the mutation's own id, so different controls sample different parts of their covering sets while a rerun of the same coverage picks the same tests. The cap lives in the coverage phase, so the record says what the child will run and the child's budget is derived from it. - Every module gets a control at its first mutation site. It did not need one before: at one per twelve, every module of any size got one anyway, and at one per hundred a project of small modules gets none. That also keeps this repository's own example — whose modules are far smaller than a hundred mutations — exercising controls at all; without it the example's goldens lose every control. On the manifest measured above, 213 controls become 46 (15 from the interval, the rest from the per-module floor), each bounded at ten tests instead of up to 934. ### What this trades Fewer controls and fewer tests per control is less flakiness insurance. What a control is for is noticing a suite that cannot be relied on under the mutation phase's own concurrency, and 46 children running up to ten tests each still sample that; what goes away is re-running the same covering sets dozens of times over. The cap is also what makes the per-module floor affordable. ### Tests `CoverageSpec` is new and covers `annotateRecord` directly: an ordinary mutation keeps every covering test and gets a budget from all of them; a control keeps the cheapest ten and gets a budget from those ten. Each fails without the change. `mutation-manifest-example`'s goldens are refreshed, and the plugin suite and the example mutation checks pass.