Problem
test/playwright/unit/ai/daemons/wake/daemon.spec.mjs is the unit suite's single slowest file — CI flags it at 5.9 minutes of a 15.7-minute run (2026-08-14, job-reported). The cost is not the coverage; it is synchronization by wall clock: a dozen-plus hardcoded await new Promise(resolve => setTimeout(resolve, 1000)) waits (plus a 4,000ms one at line ~880) that sleep a fixed second to "let the daemon settle" whether it settled in 20ms or not. Sibling wake/daemon suites (daemonDeliveryOwner.spec.mjs and the other test.setTimeout self-declared files) carry smaller doses of the same habit.
The suite recently crossed 16 minutes and the operator has ruled the tests stay in CI — NEO_TEST_SKIP_CI is the rejected alternative. The fix is making the waits event-shaped, not evicting the coverage.
Acceptance Criteria
(Reshaped 2026-08-14 to the measured mechanism — the original ACs are preserved in the correction comment. The author's sleep-census inference was falsified by measurement: the fixed 1s sleeps total ~16-20s and cannot explain the 5.9-minute file; the dominant cost is daemon poll-cadence quantization — tests waiting on production-cadence cycles. Credit: the falsifying measurement is the PR author's.)
- The wake daemon under test accepts an injectable poll/cycle cadence (production defaults untouched); the spec pins fast cadences, delivering the measured reduction on the CI slow-file report (first slice, CI-verified: the file leaves the slow-file report entirely — dev flagged it at 5.9m, the branch carries no annotation — and the unit suite drops 15.7m to 14.0m at an identical 13,316 passes).
- The PR body carries a measured decomposition receipt naming where the remaining wall-clock lives (boot, per-test daemon lifecycle, residual sleeps, other quantization), with each material remainder enumerated as a one-line follow-up slice — so the path to a single-digit-minute suite stays explicit without this ticket over-claiming it.
- Fixed-duration sleeps are converted to condition polls only where the decomposition shows them material; a sleep may remain where elapsed wall-time IS the property under test, with a comment saying so.
- Identical assertion coverage — no test deleted, no assertion weakened.
- Evidence: before/after per-file duration from the CI job's own slow-file report.
Evidence class
CI job slow-file annotation + source census of the sleep sites (grep receipts in the originating discussion), 2026-08-14.
Problem
test/playwright/unit/ai/daemons/wake/daemon.spec.mjsis the unit suite's single slowest file — CI flags it at 5.9 minutes of a 15.7-minute run (2026-08-14, job-reported). The cost is not the coverage; it is synchronization by wall clock: a dozen-plus hardcodedawait new Promise(resolve => setTimeout(resolve, 1000))waits (plus a 4,000ms one at line ~880) that sleep a fixed second to "let the daemon settle" whether it settled in 20ms or not. Sibling wake/daemon suites (daemonDeliveryOwner.spec.mjsand the othertest.setTimeoutself-declared files) carry smaller doses of the same habit.The suite recently crossed 16 minutes and the operator has ruled the tests stay in CI —
NEO_TEST_SKIP_CIis the rejected alternative. The fix is making the waits event-shaped, not evicting the coverage.Acceptance Criteria
(Reshaped 2026-08-14 to the measured mechanism — the original ACs are preserved in the correction comment. The author's sleep-census inference was falsified by measurement: the fixed 1s sleeps total ~16-20s and cannot explain the 5.9-minute file; the dominant cost is daemon poll-cadence quantization — tests waiting on production-cadence cycles. Credit: the falsifying measurement is the PR author's.)
Evidence class
CI job slow-file annotation + source census of the sleep sites (grep receipts in the originating discussion), 2026-08-14.