Skip to content

fix(mention): tie pending match requests to the file index generation - #374

Merged
srothgan merged 1 commit into
mainfrom
fix/mention-pending-match-generation
Sep 7, 2026
Merged

srothgan merged 1 commit into
mainfrom
fix/mention-pending-match-generation

Conversation

@srothgan

@srothgan srothgan commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Summary

@-file autocomplete can hang permanently on "Searching files…" when the file index restarts while a match request is in flight. This ties an in-flight request to the file index generation it was issued against, so a request voided by a restart can no longer block the refresh that would recover the menu.

MentionState tracked in-flight match requests as a bare pending_match_sequence: Option<u64>. A file index restart bumps file_index.generation, and the matcher drops stale-generation requests in complete_query without sending a reply — so that sequence is never answered. apply_match_result also rejects any result whose generation moved, returning early and leaving the sequence set. request_match_for_active_mention then reads that dead promise as "a request is in flight" and defers every non-UserQuery refresh, including the one issued by the restart itself. The menu stays at Searching forever.

The fix makes generation part of the request identity:

  • PendingMatch { sequence, generation } replaces the bare sequence
  • Only a pending request from the current generation may defer a refresh
  • Applying a result requires both sequence and generation to match the pending request; the existing explicit result.generation != app.file_index.generation check is kept, since an old result can still match an old PendingMatch

Why

This is a general bug, not a macOS one. It was found via the Nightly macOS failures, where FSEvents coalescing reliably lands a .gitignore-triggered rebuild inside the query window, but any generation bump during an in-flight query reproduces it. Other triggers on every platform:

  • config/edit.rs — toggling respect_gitignore
  • events/session.rs — session start and cwd change
  • state/session_reset.rs — session reset
  • file_index.rs — watcher-driven RebuildRequested on .gitignore / .ignore / .git/info/exclude changes

Root cause was established by measurement, not inference — debug tracing on a macOS runner produced:

mention_match_result_rejected
  result_generation=1 current_generation=2
  result_index_version=2 current_index_version=0
  sequence=3 pending_sequence=3 query_matches=true result_count=2

The matcher had computed the correct result for the correct query with a matching sequence. It was discarded solely because the generation moved in flight.

Closes

Fixes the recurring Nightly app::mention failures on macos-latest.

Validation

Automated

  • cargo fmt --all -- --check — clean
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo test — 1813 passed, 0 failed
  • New regression test index_restart_replaces_a_request_left_pending_by_the_previous_generation: issues a real request, restarts the index before the result is drained, runs the normal refresh path, and asserts the new pending request carries the new generation and that the search settles. Deterministic and platform-independent.
  • Verified the test fails without the fix: reverting the deferral guard to pending_match.is_some() makes it fail with left: 1, right: 2 — the pending request stays pinned to the dead generation.

Manual

A macOS Nightly run is dispatched on this branch to confirm on the real runner. Note that the original failure is a race, so a single green run is supporting evidence rather than proof; the regression test failing without the fix is what demonstrates the mechanism.

Screenshot

n/a

Notes

  • Breaking changes: none — PendingMatch is a private struct in src/app/mention.rs
  • Docs updated: n/a
  • Governance/release impact: none

Out of scope, noted for follow-up: request_match logs a query-channel send failure without reporting it back to MentionState, which could theoretically strand a current-generation pending request. Separate robustness issue; it does not weaken this fix.

- Track in-flight match requests as `PendingMatch { sequence, generation }`
  instead of a bare sequence number
- Only defer a refresh when the pending request belongs to the current
  generation, so a request voided by an index restart no longer blocks it
- Validate both sequence and generation when applying a match result
- Add a deterministic regression test that restarts the index while a
  request is in flight and asserts the search still settles
@srothgan srothgan self-assigned this Sep 7, 2026
@srothgan srothgan added type: fix Fixes a bug or regression area: tui Terminal UI, rendering, input, and keymap labels Sep 7, 2026
@srothgan
srothgan merged commit 38a4b2c into main Sep 7, 2026
35 checks passed
@srothgan
srothgan deleted the fix/mention-pending-match-generation branch September 7, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: tui Terminal UI, rendering, input, and keymap type: fix Fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant