What happened
Plain codeaf feels stalled before its first screen, and starting or opening a conversation can freeze the terminal UI. Audited dev@e7976208e and release build 14a7fdfac on 2026-09-28.
Observed first screen: 2.73 s on an initial launch, 0.90 s on a second launch. /new took approximately 0.9 s before started a fresh conversation behind home. A controlled two-second catalog response held launch assembly for the same two seconds. A controlled 250 ms conversation-opening callback blocked the UI caller for the full 250 ms.
Home typing sometimes feels frozen in the field, but the severe typing stall has not yet been reproduced. A profile with 62 conversations showed roughly 83–105 ms to display typed text in a coarse terminal probe.
Replication
Deterministic (no model).
- Run
make test-focus PKGS=./cmd/codeaf RUN='TestThe(SubharnessWiringAsksTheCatalogNothingThatWaits|LaunchesBlockingCatalogReadsDoNotGrow)$'. The tests pass while allowing eleven blocking catalog reads during launch.
- In the same launch fixture, hold the catalog HTTP response behind a channel before calling
openV3Launch. Launch cannot finish until that channel is released.
- Provide a held
Options.Start or Options.Open callback to the TUI fixture and invoke new/open through home. The callback is invoked on the update path, preventing drawing/input while held.
Field (real terminal).
Build with make build, then run bin/codeaf chat --model deepseek/deepseek-v4.1-flash --one-model with OpenRouter configured. Open home, type a draft, start a new conversation, and reopen an inactive conversation. No model request is needed to observe launch and blank /new; budget two minutes for manual interaction.
Where
v3Subharnesses, leafBuild.contextLength, and eager v3RunHarness tool bridge construction.
openBeside, startBeside, renewRefusing, and their home callers.
importForeignSkillsBeforeFirstMessage, called synchronously by every openV3Launch.
homeView.buildWorld, which recalculates matching scores inside the sort comparator.
homeBeat/furnishHome, whose remaining synchronous work requires profiling separately from cached hosted reads.
The fix
Draw and accept input independently of catalog discovery and conversation opening. Keep the draft and destination stable while opening; submit only after the intended conversation is ready. Avoid repeated search scoring and unnecessary initialization. Preserve skill availability before the first message and existing conversation ownership semantics.
Acceptance
- e2e: real terminal launch, home typing,
/new, and reopening remain usable; an OpenRouter turn uses deepseek/deepseek-v4.1-flash for every model role and reaches a completed answer in the intended conversation.
- Regression: a held catalog request does not block launch assembly; held new/open callbacks do not block input or repaint and cannot send a draft to the previous conversation.
- Regression: refused/cancelled openings retain the draft, and delayed results cannot replace a newer conversation selection.
- Performance: record before/after timings, distinguishing actual improvement from unconfirmed typing-stall causes.
- Update the manual and changelog for the resulting behavior; do not claim unresolved paths are fixed.
What happened
Plain
codeaffeels stalled before its first screen, and starting or opening a conversation can freeze the terminal UI. Auditeddev@e7976208eand release build14a7fdfacon 2026-09-28.Observed first screen: 2.73 s on an initial launch, 0.90 s on a second launch.
/newtook approximately 0.9 s beforestarted a fresh conversation behind home. A controlled two-second catalog response held launch assembly for the same two seconds. A controlled 250 ms conversation-opening callback blocked the UI caller for the full 250 ms.Home typing sometimes feels frozen in the field, but the severe typing stall has not yet been reproduced. A profile with 62 conversations showed roughly 83–105 ms to display typed text in a coarse terminal probe.
Replication
Deterministic (no model).
make test-focus PKGS=./cmd/codeaf RUN='TestThe(SubharnessWiringAsksTheCatalogNothingThatWaits|LaunchesBlockingCatalogReadsDoNotGrow)$'. The tests pass while allowing eleven blocking catalog reads during launch.openV3Launch. Launch cannot finish until that channel is released.Options.StartorOptions.Opencallback to the TUI fixture and invoke new/open through home. The callback is invoked on the update path, preventing drawing/input while held.Field (real terminal).
Build with
make build, then runbin/codeaf chat --model deepseek/deepseek-v4.1-flash --one-modelwith OpenRouter configured. Open home, type a draft, start a new conversation, and reopen an inactive conversation. No model request is needed to observe launch and blank/new; budget two minutes for manual interaction.Where
v3Subharnesses,leafBuild.contextLength, and eagerv3RunHarnesstool bridge construction.openBeside,startBeside,renewRefusing, and their home callers.importForeignSkillsBeforeFirstMessage, called synchronously by everyopenV3Launch.homeView.buildWorld, which recalculates matching scores inside the sort comparator.homeBeat/furnishHome, whose remaining synchronous work requires profiling separately from cached hosted reads.The fix
Draw and accept input independently of catalog discovery and conversation opening. Keep the draft and destination stable while opening; submit only after the intended conversation is ready. Avoid repeated search scoring and unnecessary initialization. Preserve skill availability before the first message and existing conversation ownership semantics.
Acceptance
/new, and reopening remain usable; an OpenRouter turn usesdeepseek/deepseek-v4.1-flashfor every model role and reaches a completed answer in the intended conversation.