Description
Version: v2 (main, reproduced at 07a2b4b)
Affected client: clients/tui (test infrastructure; Windows only)
Symptom
On Windows 11, npm run test:coverage in clients/tui fails with exactly one test failing per run — but a different one each time, always in App.test.tsx > App (OAuth result branches):
- run 1:
shows insufficient-scope message when step-up OAuth stays insufficient - run 2:
completes a standard step-up authorize when OAuth succeeds - run 3 (clean upstream tree): same as run 2
npx vitest run __tests__/App.test.tsx without coverage passes 80/80 every time. The failures only appear under v8 instrumentation, which slows the Ink render loop enough for these waitFor-style OAuth-branch assertions to race.
What's known
- Pre-exists unrelated work: reproduced identically on the upstream tip with no local changes.
- Linux CI is green, so it's Windows-manifested (slower instrumented renders under the runner here).
- 3/3 instrumented runs failed; 0 failures uninstrumented.
Impact
coverage:tui → root coverage → npm run ci fails on Windows even on a clean tree. Together with #1939 (verify scripts can't spawn npx) and #1941 (CLI worker teardown crash), the mandatory pre-push gate currently cannot pass on a Windows machine.
Context
Found while validating the fix for #1852 on a Windows machine.
Activity
olaservo commentedon Aug 12, 2026
Investigated on Windows against current
v2/main(57d6e0d). The flake did not reproduce as filed (0 failures across 4 fulltest:coverageruns, 5 single-file coverage runs, 2 runs under CPU load, and 3 runs at the original repro commit 07a2b4b — the relevant files and installed deps are byte-identical to HEAD, so the failures were machine-condition-dependent). The underlying race is real, though, and can be made deterministic:Root cause — test synchronization, not a product bug. In ink 6 a visible frame does not imply armed input handlers: the frame is written during React's commit, but
useInputhandlers re-subscribe in the passive-effect flush (asetImmediate). The test helper'swaitUntilpolls onsetTimeout, and Node runs timers before the check phase — so a test can see the step-up prompt and pressabefore the new handlers exist. The key dispatches into the previous commit's stale closures and is silently swallowed; there's no retry, so the success frame never renders. v8 instrumentation widens the window, hence "coverage only".Deterministic proof: a probe pressing at the earliest frame observation fails 10/10 (10/10 pass with one
setImmediateyield), and shrinkingwaitUntil's poll to 1ms makes exactly the three step-up tests fail 3/3 runs — green with the fix.Planned fix (test-only, ~15 lines): await one
setImmediateturn after awaitUntilpredicate passes — check-queue FIFO guarantees React's already-scheduled effect flush runs first. Verified with 3 consecutive full green coverage runs.[-]TUI coverage gate flakes on Windows: App.test.tsx OAuth step-up tests fail under v8 instrumentation only[/-][+]TUI coverage gate flakes: App.test.tsx OAuth step-up tests fail under v8 instrumentation only[/+]cliffhall commentedon Aug 12, 2026
Updated this one to remove Windows from the title, the same flake has been observed in CI.
fix: state every test-gate timeout instead of inheriting a library de…