fix: address Copilot review round 2, and drop the asyncUtilTimeout raise

The inline finding was a real bug: main() never called the discovery check, so
the deny-by-default claim rested on test:scripts happening to run the same
comparison — a different command, which `npm run verify:test-timeouts` does not
invoke. `failures` is now seeded from it, and a probe config under clients/ was
observed to fail the guard.

Three suppressed findings, all correct. The afterEach in oauth-interactive
restated the shared hookTimeout and labelled it as a round trip, when it only
stops a server and unlinks a file; it now carries no budget. The file-lock
constants were named for the opposite of what they bound — 90s covers retries
running out against a holder that never yields, 60s covers the stale-lock
takeover that succeeds — so they are LOCK_RETRIES_EXHAUSTED_MS and
STALE_LOCK_TAKEOVER_MS. The browser-timeouts header said 15 budgets; it is 19.

Separately, and more importantly: the asyncUtilTimeout raise is reverted, on
measurement. Verifying round 2 turned up intermittent 15s timeouts across
unrelated unit files, so three arms of three full unit runs were taken in this
worktree at comparable load — unmodified v2/main 3/3 green, this change with
5000 producing 1, 4 and 0 timing-out files, and the same change with that one
line reverted 3/3 green. A wait that is MEANT to expire spends its whole budget
on the happy path, so a 5x raise is a 5x cost on exactly those tests and
saturates the worker pool, starving tests that were never slow.

Both web setup files therefore state asyncUtilTimeout at the library's own
value rather than raising it, which is what #2323's rule actually asks for: a
budget nobody chose is the defect, not a budget that is small. The tests that
assert absence by letting a wait expire are the real problem and are #2335.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PsmUAZ6aLUAFqenjJKSSRp
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-12 11:49:30 -04:00
commit eff0368491

View file

@ -423,6 +423,14 @@ free to run a full `local:gate`). Raising a budget nobody chose hides no race.
then it says so: real cross-process lock contention (`file-lock.test.ts`), a
full interactive OAuth round trip (`oauth-interactive.test.ts`). Name the
constant and state the reason at the site.
- **A budget is stated, which is not the same as raised.** Testing Library's
`asyncUtilTimeout` is pinned at its own default in both web setup files
because raising it was *measured worse*: a wait that is meant to expire —
a test asserting something never appears, a poll allowed to run out — spends
its whole budget on the happy path, so a raise is a proportional cost on
exactly those tests and starves the worker pool. Measure before raising a
budget that a passing test can spend in full; the call-site comment records
the three-arm run.
- **Never nest a budget inside an equal-or-larger one.** `waitFor({ timeout: N })`
inside a test whose own budget is `N` can never win, and it reports as a
timeout naming neither the wait nor its subject (#2292). Two bounds on the