Skip to content

Fix flaky diff_pipeline_computes_added_lines_and_ghost_blocks TUI test#13683

Draft
warp-dev-github-integration[bot] wants to merge 1 commit into
masterfrom
fix/flaky-diff-pipeline-test
Draft

Fix flaky diff_pipeline_computes_added_lines_and_ghost_blocks TUI test#13683
warp-dev-github-integration[bot] wants to merge 1 commit into
masterfrom
fix/flaky-diff-pipeline-test

Conversation

@warp-dev-github-integration

Copy link
Copy Markdown
Contributor

Description

Fixes the flaky TUI test diff_pipeline_computes_added_lines_and_ghost_blocks in crates/warp_tui/src/tui_file_edits_view_tests.rs (e.g. it flaked on a CI run for #13486, failing assert_eq!(ghosts.len(), 1) with left: 0).

Root cause

Two races combined to make the test flaky:

1. Bounded spinning raced the async layout channel (dominant race).
Ghost blocks travel through RenderState's layout channel, and spawn_stream_local polls that channel on the background executor before forwarding each item to a foreground dispatch task (crates/warpui_core/src/core/app.rs, spawn_stream_local). So after expand_diffs, ghost delivery makes a round trip through a background thread and its latency is unbounded under load. The test's wait — for _ in 0..100 { ... yield_now().await } — spins through the foreground executor in microseconds and gives up long before the background thread forwards the LayoutTemporaryBlock action, leaving ghosts empty. Instrumented traces confirmed failing runs where refresh_diff_state produced the ghost block but set_temporary_blocks never ran before the loop exhausted.

2. Stale diff computations could clobber newer results.
reset_content schedules its own diff computation (the buffer reset emits ContentChanged, recomputing against the just-set base), and the recompute triggered by apply_diffs only best-effort aborts it: ctx.spawn starts the future on the background executor immediately, and compute_diff_internal yields per diff op, so the two in-flight computations interleave on the background worker and can complete in either order. A superseded computation that already completed still delivered its result, overwriting the newer diff status and emitting a misleading DiffUpdated (which, with diff nav expanded, re-runs refresh_diff_state with the stale status and can clear the ghost blocks).

Fix

  • DiffModel::compute_diff (app/src/code/editor/diff.rs): the completion callback now drops results that are no longer the latest requested computation (compared against the version stored alongside the abort handle), so stale results never clobber a newer diff. This also hardens the production diff pipeline, where last-write-wins by completion order was incorrect.
  • The test (crates/warp_tui/src/tui_file_edits_view_tests.rs): both waits are now event-driven instead of bounded spinning. It subscribes to DiffUpdated/LayoutInvalidated on an unbounded channel, waits until the diff model actually contains the applied hunk before expanding, and then re-checks for ghosts after each LayoutInvalidated (emitted right after the render state stores the temporary blocks) rather than spinning a fixed number of iterations.

Linked Issue

N/A — flaky-test fix; no tracked issue.

Testing

  • Reproduced the flake at the base commit: 20/300 failures with all CPU cores saturated (always ghosts.len(): left: 0).
  • With the fix: 0 failures in 1100 runs (500 + 300 under full CPU load, 300 unloaded).
  • cargo nextest run -p warp_tui --lib: 102/102 passed.
  • cargo nextest run -p warp_editor: 458/458 passed.
  • cargo nextest run -p warp code::editor: 95/95 passed (covers diff_tests and editor model_tests).
  • ./script/format clean; cargo clippy -p warp -p warp_tui --all-targets --features tui -- -D warnings clean.

This is a headless-test/infrastructure change with no user-visible behavior, so no manual ./script/run testing or screenshots.

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-NONE

Conversation: https://staging.warp.dev/conversation/b96d06d2-7f01-4e47-acef-6039567955c8
Run: https://oz.staging.warp.dev/runs/019f5d59-095b-7b38-a79c-8cc11cf4b5c6

This PR was generated with Oz.

Two races made this test flaky:

1. The test's bounded ghost wait (100x yield_now) raced the async layout
   channel: spawn_stream_local polls the layout stream on the background
   executor before dispatching back to the foreground, so ghost-block
   delivery latency is unbounded while the yield loop spins out in
   microseconds. The waits are now event-driven (DiffUpdated /
   LayoutInvalidated) instead of bounded spinning.

2. DiffModel::compute_diff aborts a superseded computation only
   best-effort; a computation that already completed on the background
   thread still delivered its stale result, clobbering a newer diff and
   re-triggering refresh_diff_state with the stale status. The completion
   callback now drops results that are no longer the latest requested
   computation.

Verified with 1100 runs of the test (800 under full CPU load): 0 failures,
versus 20/300 failures for the original test under the same load.

Co-Authored-By: Oz <oz-agent@warp.dev>
@cla-bot cla-bot Bot added the cla-signed label Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant