You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
TUI coverage gate flakes: App.test.tsx OAuth step-up tests fail under v8 instrumentation only #1942
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.tsxwithout 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).
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.
Investigated on Windows against current v2/main (57d6e0d). The flake did not reproduce as filed (0 failures across 4 full test:coverage runs, 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 useInput handlers re-subscribe in the passive-effect flush (a setImmediate). The test helper's waitUntil polls on setTimeout, and Node runs timers before the check phase — so a test can see the step-up prompt and press a before 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 setImmediate yield), and shrinking waitUntil'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 setImmediate turn after a waitUntil predicate passes — check-queue FIFO guarantees React's already-scheduled effect flush runs first. Verified with 3 consecutive full green coverage runs.
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…