Skip to content

Failure taxonomy & status pill #32

Description

@jpka

Parent

Part of #25 (Screen Solver v1: implementation spec), itself under the map #1.

What to build

What the app does, specifically, for each way things can go wrong beyond the plain happy path — so a user always gets an honest answer about app health, not silence or a stuck spinner. This layers the full failure taxonomy from the spec on top of the basic solve loop:

Condition Spends a call? Surface
Window gone/unresolvable, minimized/off-desktop, black/zero-size frame No Silent — button flash only, no SSE event
Bail (# No exercise on screen) Yes Normal done stream, low-emphasis in the client
Auth rejection (key revoked after startup) Yes error{kind: 'auth'}; flips the standing status pill sticky
Transient error, retries exhausted Yes error{kind: 'transient'}
Stream dies mid-answer Partially Partial pane text stays with an appended error marker
Mid-run target loss N/A Deliberate pause → ignored; unexpected loss → one silent re-resolution, then fallback to the picker; renderer crash → auto-restart, escalating on repeat
Port-bind failure N/A Refuse to start (already covered by ticket 1)

A standing status pill escalates silent → auto-recovering → sticky. Sticky states also print one line to the host's console. There is no push/toast/notification for anyone not currently looking at an open client — the pill only speaks to whichever client is currently open, over the existing SSE channel.

Acceptance criteria

  • An auth rejection produces error{kind: 'auth'} on the wire and the status pill goes sticky, staying sticky across subsequent unrelated solves until explicitly resolved.
  • A transient failure that exhausts its retries produces error{kind: 'transient'} and does not flip the pill sticky (auto-recovering, not sticky).
  • A stream that dies mid-answer (simulated connection drop from the provider) leaves the partial text visible to a connected client with a distinguishable error marker appended, rather than vanishing.
  • An unexpected mid-run target loss (window closed without the user pausing) triggers exactly one silent re-resolution attempt before falling back to showing the window picker.
  • A deliberate pause (user-initiated) does not trigger the re-resolution/fallback flow.
  • A sticky status transition prints one line to the host's console/terminal output.
  • Every condition in the table above is covered by a test or a documented manual verification step where automation isn't feasible (e.g. simulating a renderer crash).

Blocked by

#29 (Solve loop over HTTP + SSE) — this ticket layers failure handling onto that baseline.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentImplementation-ready spec, ready to be picked up by an agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions