Skip to content

Prune the test lanes that don't pay for themselves, and add the checks we're missing #1781

Description

@thymikee

Follow-up to #1412. CI costs about 100k billed minutes a month, mostly on macOS runners. Some lanes are not paying for themselves, and a few kinds of bugs have no test looking for them at all.

The rule

Every test lane answers four questions in writing before it lands, and keeps answering them:

  1. What bug does it catch that nothing else catches?
  2. What has it caught, or which real bug made us want it?
  3. What does it cost — harness code, minutes a month, time added to a PR?
  4. When would we delete it?

No answers, no lane. Delete condition met, lane goes. Three notes so the rule doesn't delete the wrong things: a cheap lane guarding code that is currently correct is fine — "caught nothing" is not "worth nothing" when it costs under a minute; a preventive guarantee (a layering rule, a coverage floor on new lines) is removed only when something else enforces the same thing or the thing it guards is gone — never because it was quiet; and a nightly that is just a bigger version of a PR lane has to say what the extra runs found.

~~We also start reporting how much test-harness code we own (about 25k lines, ~15% of product code) next to the size report.~~ (dropped at close, by this issue's own rule: no consumer was ever named for the number and it has no delete condition — a standing report line nobody reads is the thing this issue prunes. The figure is one wc -l away when an audit wants it, and #1843's test-file-size ratchet guards growth where it actually hurts.)

Prune or fix what we already run

Not reviewed, cheap by construction: size, build cache, deploy/preview/release wrappers, conformance lanes.

Add

Not doing

A sanitizer XCTest lane — no evidence of native races to catch; run it once by hand after A7 and see. Coverage-guided fuzzing as its own lane. HWASan/MTE, E-core budgets, new LLM-judge suites. Details in the first comment.

Do first

Wave 2 CLOSED 2026-08-18: #1822 (A3+A5), #1827 (A4), #1825 (A6), #1828 (#1457 → report-only) all merged; decisions in the wave-2 comment; side issues #1823 #1824 #1837. Wave 3 handoff in the comment below.

Wave 1 (2026-08-17): A2 merged (#1787); A1 fix #1793 + park #1794, A9-1 #1791, B4 #1790 ready for review; A7 #1789 draft pending the dispatch decision; A9 measured (routing on hold); events.ndjson → #1788; follow-ups #1792, #1796. Boxes get ticked as PRs merge.

  1. Delete A2 — one line.
  2. Fix or switch off A1 — both merged (test(android): restore full-tier lifecycle and observability scenarios (#1781 A1) #1793, ci: move parked device replay suites to a dispatch-only workflow (#1781 A1) #1794).
  3. Run the A9 measurement — done twice; ship the paths-ignore fix now (A9-1), hold routing (A9-2) until the selector can express Apple ownership.
  4. Get the 116 XCTests running somewhere (A7) — merged ci(ios): run the full XCTest suite nightly and check the PR test list (#1781 A7) #1789; the classify/delete pass is wave 3.
  5. Do B4 (merged test: assert the specific error code instead of any failure (#1781 B4) #1790), then the scoped B1.
  6. Decide A3; audit A4 per entry — merged (ci: park perf-nightly to dispatch and stop the coverage-gate cascade double-red (#1781 A3, A5) #1822, chore(test): remove the contention retry (0 fires since 07-29) and shrink the subprocess-stub project to its 3 real spawners (#1781 A4) #1827).
  7. Instrument A5/A6 — measured and kept (ci: park perf-nightly to dispatch and stop the coverage-gate cascade double-red (#1781 A3, A5) #1822, chore(layering): document R12/R18/R19, retire R8, make R9 shrink mandatory (#1781 A6) #1825).
  8. File the events.ndjson rotation bugdaemon: events.ndjson has no size/rotation cap #1788.
  9. Wave 3 (as of 2026-08-20): done — A9-2 routing (ci: give check:affected real Apple ownership rules and route ios.yml on them (#1781 A9-2) #1857), B2 (test(fuzz): structured CLI/Maestro generators that reach command validation and assert error codes (#1781 B2) #1866 → ledger Parser fuzz validation targets: findings ledger and kill criterion (#1781 B2) #1869), B3 (go, corrected comment), B5 (test: make hard-coded caps overridable behind seams (#1781 B5) #1858), daemon: events.ndjson has no size/rotation cap #1788, check:layering R10 names the wrong file when a zone exceeds its type-cycle ceiling #1837, changed-line mutation experiment (verdict: bar not cleared, no lane; chore(mutation): shrink to report-only — drop the ratchet, baseline and graduation (#1457, #1781) #1828 harness untouched, kill date 2026-11-16 stands). Also done — B1 (test: catch daemon lifecycle and durable-state leaks (#1781 B1) #1859 merged 2026-08-20; test: deterministic boundary fault-injection matrix for daemon HTTP and subprocess seams #1431 pairs with it and stays open). A7-classify shipped as test: classify the runner XCTests — pure decisions to a macOS host lane, simulator semantics gated os(iOS) (#1781 A7) #1861 (2026-08-19: host lane on every PR) and independently confirmed 2026-08-20 (comment below). In observation — Coverage job: "Worker exited unexpectedly" kills one fork in the last ~40s of the run (4 of 17 recent CI failures) #1824 (one of two causes fixed by test: refuse foreign-pid signals from unit-test workers (Coverage fork death, #1824) #1854, open on its 20-run criterion). Every wave-3 work item is now done. Nothing left on the umbrella itself — everything still open has its own tracker: Coverage job: "Worker exited unexpectedly" kills one fork in the last ~40s of the run (4 of 17 recent CI failures) #1824 (observation window), test(ios): runner coverage gaps from the A7 pass — TvRemote has zero tests, ScreenRecorder.append monotonicity untested #1897 (A7 coverage gaps), Parser fuzz validation targets: findings ledger and kill criterion (#1781 B2) #1869 (fuzz ledger), subprocess-stub vitest project: members and kill criterion (#1781 A4) #1823 (stub-project kill criterion), and the carried-forward tail test: deterministic boundary fault-injection matrix for daemon HTTP and subprocess seams #1431 / bench: falsification fixtures for oracles + typed runner outcomes #1481 / iOS gesture pan duration has no automated guard; the nightly gesture gate cannot catch a #1562 regression #1584 / test: platform command-coverage manifests — web, macOS, Linux, tvOS (+ visionOS/watchOS decision) #1426.

Carried forward from #1412: #1431 (pairs with B1), #1457 (closed by #1828: shrunk to report-only), #1481, #1584 (blocked on A1), #1426 (rescope to the non-Android platforms).

Views: Test Atlas · Test Topology

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions