Summary
useAtCompletion has no transition out of its ERROR state on a pattern change. Once an @ completion search fails, continuing to type never retries — the suggestion list stays permanently empty for that working directory until the completion is torn down entirely.
Found while adding completion coverage for #2019. Filing separately because #2019 is a test-only issue and this is a production state-machine fix.
Root cause
usePatternChangeHandler in packages/cli/src/ui/hooks/useAtCompletion.ts only starts work from three statuses:
if (state.status === AtCompletionStatus.IDLE) {
dispatch({ type: 'INITIALIZE' });
} else if (
(state.status === AtCompletionStatus.READY ||
state.status === AtCompletionStatus.SEARCHING) &&
normalizedPattern !== state.pattern
) {
...
}
ERROR is absent, so a new pattern while in ERROR dispatches nothing. The only ways out are RESET, which is reached by disabling the hook, passing a null pattern, or changing cwd/config via useResetOnCwdChange.
Evidence
Probe against the real hook: force FileSearch.initialize to reject once, let the hook settle into the failed state, then change only the pattern (same cwd) to one that would match a real file.
PROBE: entered error state, factory calls = 1
PROBE: after pattern change -> suggestions = [] factoryCalls = 1
No second FileSearchFactory.create, no new search, no suggestions. Changing cwd instead does recover, which is what the existing coverage in useAtCompletion.test.ts exercises.
User-visible effect
If the initial file-system crawl fails once (transient I/O error, permissions hiccup, a directory removed mid-crawl), @ completion appears silently broken for the rest of that session in that directory. Typing more characters looks like it should retry, and does not. The user has to delete the @ entirely and start over, which is not discoverable.
Suggested fix
Allow ERROR to re-enter initialization on a pattern change, so a subsequent attempt retries rather than being dropped. Worth deciding whether every keystroke should retry or whether the retry should be bounded, since a genuinely broken directory would otherwise retry on each character.
Acceptance
A test that drives the hook into ERROR, then changes only the pattern with cwd unchanged, and asserts suggestions populate and isLoadingSuggestions is false. That test fails on main today.
Related
Summary
useAtCompletionhas no transition out of itsERRORstate on a pattern change. Once an@completion search fails, continuing to type never retries — the suggestion list stays permanently empty for that working directory until the completion is torn down entirely.Found while adding completion coverage for #2019. Filing separately because #2019 is a test-only issue and this is a production state-machine fix.
Root cause
usePatternChangeHandlerinpackages/cli/src/ui/hooks/useAtCompletion.tsonly starts work from three statuses:ERRORis absent, so a new pattern while inERRORdispatches nothing. The only ways out areRESET, which is reached by disabling the hook, passing a null pattern, or changingcwd/configviauseResetOnCwdChange.Evidence
Probe against the real hook: force
FileSearch.initializeto reject once, let the hook settle into the failed state, then change only the pattern (samecwd) to one that would match a real file.No second
FileSearchFactory.create, no new search, no suggestions. Changingcwdinstead does recover, which is what the existing coverage inuseAtCompletion.test.tsexercises.User-visible effect
If the initial file-system crawl fails once (transient I/O error, permissions hiccup, a directory removed mid-crawl),
@completion appears silently broken for the rest of that session in that directory. Typing more characters looks like it should retry, and does not. The user has to delete the@entirely and start over, which is not discoverable.Suggested fix
Allow
ERRORto re-enter initialization on a pattern change, so a subsequent attempt retries rather than being dropped. Worth deciding whether every keystroke should retry or whether the retry should be bounded, since a genuinely broken directory would otherwise retry on each character.Acceptance
A test that drives the hook into
ERROR, then changes only the pattern withcwdunchanged, and asserts suggestions populate andisLoadingSuggestionsis false. That test fails onmaintoday.Related
cwd-change recovery precisely because same-directory recovery does not currently work.