Skip to content

fix(chat): show cold-boot feedback instead of a silent placeholder - #11739

Merged
lalalune merged 3 commits into
developfrom
fix/chat-cold-boot-feedback
Jul 3, 2026
Merged

lalalune merged 3 commits into
developfrom
fix/chat-cold-boot-feedback

Conversation

@standujar

Copy link
Copy Markdown
Collaborator

What

A dedicated agent's container takes 30–120s+ to warm. During that window the chat composer showed only a static placeholder (Ask X — waking up…) + an sr-only hint — a sighted user got no spinner, no progress, no timeout escape for minutes. Found in the staging e2e: the composer just sat there, silent, while the agent booted. The open-sheet spinner is gated on conversationLoading and the turn-status on responding, both false during a fresh pre-send cold boot, so nothing filled the gap.

Fix

A resting-state BootStatusIndicator banner — the structural twin of the existing model-download banner (same centered glass pill, text-accent spinner, aria-live="polite", reduced-motion aware):

  • indeterminate spinner + live "Waking {agent}…" while booting,
  • escalates after 90s to "{agent} is taking longer than usual to wake…" with an Open settings escape, so a stuck boot never reads as a silent hang.

The post-send path (optimistic user bubble + inline "Waking the agent" turn-status) is untouched — this only fills the silent pre-send window.

Design-review points folded in (workflow + /review)

  • No warm-agent flash. phase === "booting" is true on first paint before the status fetch resolves, even for a warm agent — so the banner is gated on a 600ms grace window; a warm agent flips ready within a frame and never crosses it. This anti-flash gate is the load-bearing part and is now tested end-to-end via the overlay harness.
  • Honest escape label. The action opens settings, so it's labelled "Open settings" — not "Check status" / any retry it doesn't perform (a review caught the over-promise; the test locks the exact label).
  • Comments deduped (the rationale had been restated 4×); the test-only exports are marked as a seam (cf. __renderThreadLineForParity).

Scope

This is the only real code bug of the 4 UX issues the e2e surfaced — the other three (/ "lands on settings", "Loading billing" hang, "no Send button") were confirmed to be guest/first-run session artifacts of the e2e, not defects for a normal signed-in user (the workflow root-caused each against HEAD: / resolves to chat, a labelled Send button already exists and enables on text, and "Loading billing" only persists while unauthenticated). No speculative PRs for those.

Test

standujar added 2 commits July 3, 2026 03:27
A dedicated agent's container takes 30-120s+ to warm. During that window
the composer showed only a static placeholder ('Ask X — waking up…') + an
sr-only hint — a sighted user got no spinner, no progress, no timeout escape
for minutes (found in the staging e2e). The open-sheet spinner is gated on
conversationLoading and the turn-status on responding, both false during a
fresh pre-send cold boot.

Add a resting-state BootStatusIndicator banner (sibling of the model-download
banner, same glass pill + text-accent spinner + aria-live + reduced-motion):
an indeterminate 'Waking {agent}…' while booting, escalating after 90s to
'taking longer than usual' with an Open-settings escape so a stuck boot never
reads as a silent hang. The post-send path (optimistic bubble + inline
'Waking the agent' turn-status) is untouched.

Two review points folded in: the banner is gated on a 600ms grace delay so a
warm agent — where phase is momentarily 'booting' on first paint before the
status fetch resolves — never flashes it; and the escape is labelled 'Open
settings' (its handler opens settings) rather than implying a retry it
doesn't do.

Test: BootStatusIndicator states (waking → slow escalation via fake timers),
the settings-escape callback, no-handler omission, reduced-motion. 5/5.
Sibling suites: 3 pre-existing draft-parity failures on clean develop too
(unrelated); +5 new pass. typecheck + biome clean.
…y exports

Folds the 3 WARNs from the /review pass:
- Tests: add parent-level grace-gate tests (the load-bearing anti-flash was
  untested — only the isolated BootStatusIndicator was). Uses the existing
  makeController harness: warm agent that leaves booting <600ms never shows
  the banner; a cold boot past 600ms does; readiness hides it immediately.
- Slop: the cold-boot rationale was restated 4x — collapse to one authoritative
  spot (the parent effect for the invariant, a short JSDoc for the component),
  drop the PR-narration + the duplicated render-site block.
- Dead code: BootStatusIndicator/BOOT_SLOW_AFTER_MS are exported only for the
  test — note them as a test-only seam (cf __renderThreadLineForParity) so they
  don't read as public API.

3 grace-gate + 5 component tests green; the 3 failing draft-parity tests in the
sibling suite are pre-existing on develop (#9148), unrelated.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d923df21-5391-4af1-a438-4e8a306a022c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/chat-cold-boot-feedback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@lalalune
lalalune merged commit 5399126 into develop Jul 3, 2026
17 of 64 checks passed
@lalalune
lalalune deleted the fix/chat-cold-boot-feedback branch July 3, 2026 01:39
@lalalune

lalalune commented Jul 3, 2026

Copy link
Copy Markdown
Member

Post-merge verification (this PR was merged mid-review; reviewed + verified the develop tip 5399126, whose tree is identical to the PR head):

  • ContinuousChatOverlay.boot-status.test.tsx — 5/5 pass (waking state, 90s escalation, Open-settings callback, no-handler omission, reduced motion).
  • Full ContinuousChatOverlay.test.tsx — 135/135 pass, including the 3 new grace-gate tests (mutation-checked: removing the 600ms gate fails the warm-flip test).
  • Interaction with fix(ui): don't evict a user message sent during local-model warm-up (#11670) #11698 warm-up eviction: bun run test:warmup-eviction-e2e — PASS 8/8 (optimistic bubble survives the 503 + reconcile, Retry chip, exactly-once retry, reconcile-away). useChatSend suites 50/50. No regression to restoreEvictedUserTurn.
  • tsc --noEmit -p packages/ui clean; biome clean on touched files.

Code review: gating on phase === "booting" + 600ms grace is sound (booting = !ready in useShellController.ts, true on first paint even for warm agents — the grace window is load-bearing and now tested). Component mirrors the model-download banner pattern; pointer-events-none shell with pointer-events-auto escape button matches the audio-unlock precedent; testid unique; agentName safely interpolated.

One nit, not a defect: since booting stays true post-send, a message sent during a cold boot shows both this banner and the inline "Waking the agent" turn status. The wording is consistent and it matches the model-download banner's stay-visible precedent, so leaving as-is seems fine — flagging in case anyone wants to suppress the banner while responding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants