vary mutate --fast-mode narrows the per-mutant test filter on top of the existing coverage-guided selection. It trades a controlled amount of accuracy for speed, and runs a continuous validation pass every run so that accuracy stays within a threshold you set. When the measured miss rate exceeds the threshold, every non-sampled mutant is re-run with the broader filter and the report is rewritten with the conservative result.
For the basics, see Introduction. For how fast mode composes with other strict-mode optimisations, see Strict mode.
Fast mode is heuristic. Without continuous validation it would be a silently-lossy classification engine, turning a survivor the conservative filter would have killed into "test gap" noise in the report even though the test exists and works. Continuous validation is the contract that lets Vary ship a faster mode and still defend the per-mutant killed / survived classification.
The validation compares (fast-mode classification, broad classification) on a sample of mutants. A "miss" is a sampled mutant where the two classifications disagree in either direction.
| Disagreement | Meaning |
|---|---|
fast=survived, broad=killed | Fast mode missed a kill |
fast=killed, broad=survived | Fast mode reported a phantom kill |
If miss rate > threshold, fast mode auto-falls back: every remaining survivor is re-run with the conservative filter and the result list is rewritten. Every mutant in the final report is then labeled by the conservative truth.
For each mutant, the conservative test filter is the set of tests that exercise the mutated method (from the stats-phase coverage map). Fast mode takes the first max(1, ceil(N * narrowFactor)) tests in deterministic sort order.
narrowFactor | Effect |
|---|---|
0.5 (default) | Keeps half the conservative filter |
0.25 | Keeps a quarter |
1.0 | No-op |
When a mutant has no coverage filter (stats phase did not run, or the method has no covering tests), fast mode does not narrow. Conservative behaviour applies.
| Flag | Default | Range | Purpose |
|---|---|---|---|
--fast-mode | off | flag | Enable narrowing + validation |
--fast-mode-narrow-factor | 0.5 | [0.0, 1.0] | Fraction of conservative filter kept |
--fast-mode-sample-size | 10 | >= 0 | Mutants re-run with the broader filter |
--fast-mode-miss-threshold | 0.10 | [0.0, 1.0] | Miss rate above which auto-fallback fires |
The threshold rule is strictly greater than: a miss rate that equals the threshold does not trigger fallback. This makes the boundary deterministic so a workload sitting exactly on the line stays in fast mode.
mutation.json per-file block:
{
"file": "src/util.vary",
"fastMode": {
"enabled": true,
"narrowFactor": 0.5000,
"sampleSize": 10,
"sampledMutants": 10,
"missCount": 3,
"missRate": 0.3000,
"missRateThreshold": 0.1000,
"fallbackTriggered": true
},
"mutants": [...]
}
The same six fields are surfaced as columns in telemetry.json and telemetry.csv (fastModeEnabled, fastModeNarrowFactor, fastModeSampledMutants, fastModeMissRate, fastModeMissRateThreshold, fastModeFallbackTriggered). These columns are emitted unconditionally so downstream consumers can read the same shape every run.
| Feature | Interaction |
|---|---|
Incremental inference (--incremental-infer) | Fast mode narrows the test filter that is stored as each entry's testsFingerprint. Switching between fast mode and conservative invalidates prior entries, which is correct because the stored result was produced under a different test filter. |
| Mutant grouping | The grouping plan is computed from the conservative covering-tests map. Fast mode's narrowing applies on top of the group's selectedTests, so members of a group still share the same narrowed filter. |
| Survivor tail | The post-loop flake-detection rerun runs before the fast-mode validation pass and uses the same (narrowed) filter the main loop used. The validation pass is a separate, accounted-for cost and adds to executionTimeMs but is not part of the survivor tail. |
| Bytecode backends | Fast mode is wired into the AST-level runner only. The bytecode backends (fresh-loader, hot-swap, redefine) do not apply fast-mode narrowing. |
| Non-goal | Detail |
|---|---|
| Automatic per-workload narrow-factor selection | Start with a hand-tuned value, watch the miss rate, adjust |
| Persisting fast-mode validation history across runs | Each run re-validates |
| Replacing strict mode as the truth source | Fast mode is an opt-in; strict mode (the no-narrowing path) remains the default |