Skip to content

[frontend] Loading state with phase indicator (replace generic spinner) #7

Description

@gapilongo

Problem

Per-turn latency is 3-30 seconds (playbook-heavy turns + regen attempts push this higher). The current loading UX is presumably a generic spinner — the operator has no signal of what's happening, which feels broken when a 25-second turn drags on.

The backend pipeline has clear phase boundaries that we can surface:

  1. Routing (intent + knowability + scope filter) — ~50ms
  2. Substrate fetch (catalog match + playbook match + RAG retrieve + tool calls) — 100-2000ms
  3. Model generation (vLLM streaming) — 2-20s
  4. Verification (provenance verifier runs) — ~10ms
  5. Regen attempt (if hard_failures) — repeats phases 3+4

A phase indicator turns dead time into useful signal.

Acceptance criteria

  • Build a <PhaseIndicator> component shown in place of the current spinner:
    • 4-5 phase steps with icons (lucide-react: Route, Database, Cpu, ShieldCheck)
    • Current phase highlighted, completed phases checked, pending phases dimmed
    • On regen, the indicator restarts from "Model generation" with a small "(attempt 2/3)" badge
  • Phase transitions driven by either:
    • Option A (simpler): time-based pseudo-progression — advance phases on a heuristic timer; not accurate but better than a spinner
    • Option B (proper, preferred): backend SSE / WebSocket emits phase events; frontend listens. Requires backend change — coordinate with backend folks before going down this path.
  • If Option B requires backend work, scope this issue to Option A and open a separate issue for the SSE plumbing
  • Should be visually integrated with the chat message bubble (not a modal)
  • Reduce-motion friendly (prefers-reduced-motion: reduce → no animations, just static state)

Constraints

  • No new dependencies — use existing lucide-react + Tailwind
  • Keep it understated — this is operator UX, not a marketing animation
  • Accessible — aria-live="polite" so screen readers announce phase transitions

Pointers

  • Current chat component: frontend/src/components/chat/ (find the message-pending render)
  • vLLM streaming is supported on the backend (see src/agent/model_adapter.py streaming path) — check whether the case_server currently relays it
  • Phase definitions on the backend: walk src/agent/skills.py → _skill_answer_freeform for the canonical phase order

Difficulty

S (2-3 hours) for Option A (time-based heuristic), L (1-2 days) for Option B (real backend streaming). Recommend starting with A.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfrontendReact/TS in frontend/ (components, AuditPanel, chat UI, design system)good first issueGood for newcomers

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions