From 09e11397b4bfa50b06bdd80fc5dbd162ce0a21a9 Mon Sep 17 00:00:00 2001 From: ScreenTinker Date: Wed, 8 Jul 2026 17:31:27 -0500 Subject: [PATCH] test: widen CI-fragile event-loop-gap timing bars (flaky prune/storm asserts) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI flaked on the 300k-row prune non-blocking assert: a healthy chunked prune hit a 417ms max event-loop gap on a shared runner, over the strict 250ms bar (the same test passed on the prior commit; the release bump changed no logic). These probes exist to catch a MULTI-SECOND freeze (the pre-fix whole-table sort froze 40-48s) — not to enforce a sub-300ms latency SLA — so a strict bar is fragile under runner contention/GC. Widen both to <1500ms: still << "seconds" (catches any real regression) but robust on CI. No production code changed. Co-Authored-By: Claude Opus 4.8 (1M context) --- server/test/status-log-prune-hardening.test.js | 9 ++++++--- server/test/storm-harness.test.js | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/server/test/status-log-prune-hardening.test.js b/server/test/status-log-prune-hardening.test.js index 53a1f0d..01cc449 100644 --- a/server/test/status-log-prune-hardening.test.js +++ b/server/test/status-log-prune-hardening.test.js @@ -55,8 +55,11 @@ test('non-blocking: 300k-row single-device backlog trims in many batches, loop s assert.equal(count('flapper'), 300000, 'seeded 300k'); // Event-loop responsiveness probe: a 10ms ticker; the max gap between ticks is the - // worst synchronous block during the prune. A single unbatched DELETE would freeze - // it for seconds; chunked+yield keeps every gap small. + // worst synchronous block during the prune. A single unbatched DELETE of 300k rows would + // freeze it for SECONDS; chunked+yield keeps every gap well under a second. The bar is set to + // catch that multi-second freeze while tolerating shared-CI-runner noise (a strict sub-300ms + // bar flakes under runner contention/GC — the intent is "not a seconds-long freeze", not a + // fixed-latency SLA). let maxGap = 0, last = Date.now(); const ticker = setInterval(() => { const n = Date.now(); maxGap = Math.max(maxGap, n - last); last = n; }, 10); @@ -65,7 +68,7 @@ test('non-blocking: 300k-row single-device backlog trims in many batches, loop s assert.equal(count('flapper'), 500, 'trimmed to the cap'); assert.ok(deleted >= 299000, `deleted the backlog (${deleted})`); - assert.ok(maxGap < 250, `no long freeze — max event-loop gap ${maxGap}ms (would be seconds if unbatched)`); + assert.ok(maxGap < 1500, `no seconds-long freeze — max event-loop gap ${maxGap}ms (an unbatched 300k DELETE would be multiple seconds)`); }); test('band-gate: interval run is a no-op when loaded; startup/normal runs', async () => { diff --git a/server/test/storm-harness.test.js b/server/test/storm-harness.test.js index ce9855c..2a6a407 100644 --- a/server/test/storm-harness.test.js +++ b/server/test/storm-harness.test.js @@ -64,8 +64,10 @@ test('storm: bloated-table sweep + flapper + OTA flood — loop stays responsive clearInterval(ticker); // 1) THE REAL INVARIANT — NO multi-second freeze. The old whole-table sort would - // freeze the ticker for tens of seconds here. - assert.ok(maxGap < 300, `loop never froze — max event-loop gap ${maxGap}ms (was 40-48s pre-fix)`); + // freeze the ticker for tens of seconds here (40-48s). The bar catches that while + // tolerating shared-CI-runner noise — the intent is "not seconds", not a sub-300ms SLA + // (a strict bar flakes under runner contention/GC, e.g. an observed 417ms on a healthy prune). + assert.ok(maxGap < 1500, `loop never froze — max event-loop gap ${maxGap}ms (was 40-48s pre-fix)`); // #146 P3.9: the exact tick count is environment-timing-sensitive; assert only that // the ticker sampled enough to have MEASURED a real gap (>=2), not a brittle count. assert.ok(ticks >= 2, `ticker sampled the run (${ticks} ticks) — max-gap measurement is meaningful`);