Skip to content

Flash red lights and speak a snarky line when an order genuinely faults#256

Open
Daniel Botros (danielbotros) wants to merge 1 commit into
mainfrom
fault-lights-and-snark
Open

Flash red lights and speak a snarky line when an order genuinely faults#256
Daniel Botros (danielbotros) wants to merge 1 commit into
mainfrom
fault-lights-and-snark

Conversation

@danielbotros

@danielbotros Daniel Botros (danielbotros) commented Jul 15, 2026

Copy link
Copy Markdown
Member

On a genuine fault the machine now reacts in the room:

  • Snarky Cappuccina line — new orderFailed templates spoken through the existing speech_service_name path via sayAlways, so it plays regardless of the conversational setting (same as the drink-ready announcement). Best-effort, detached from the queue goroutine, 10s timeout.
  • Red LED flash (indirect — this service knows nothing about LEDs) — the coffee service raises a transient fault_active: true in its Status() for 5 seconds. voice-command, which already watches this service's Status() as its command_status resource, folds the flag into its lifecycle state as error; the existing led-bridge poller forwards the state change and the firmware flashes red until the window lapses and the state reverts. See the companion PR Surface command-status faults as an "error" LED state viam-modules/conversation-bundle#20.

This design keeps exactly one LED state owner (voice-command) and one serial writer (the led-bridge poller) — no arbitration logic, no magic service names, and no new config fields in this repo.

Both reactions hook into the existing failure fan-out (notifyOrderReading). Tests cover the fault/cancel/success gating, the fault window expiry, the Status flag, the spoken snark payload, and the failure-line templates. go test ./... passes.

🤖 Generated with Claude Code

Comment thread coffee/api.go Outdated
"is_busy": s.running.Load(),
"current_step": step,
"can_serve_decaf": s.cfg.CanServeDecaf,
"fault_active": s.faultActive(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think we need faultActive() and lastFaultAt since we run s.reactToOrderFailure(r) on failure (similar to the Salck notification

On a genuine fault (not an operator cancel, which keeps its calmer
spoken announcement), speak a snarky Cappuccina failure line through
speech_service_name via sayAlways (best-effort, detached from the queue
goroutine, 10s timeout) and raise a transient fault_active flag in
Status() for a few seconds. The conversation-bundle stack
(voice-command → led-bridge) renders the flag as a red LED flash; this
service knows nothing about LEDs and gains no new config.

Co-Authored-By: Claude Fable 5 <[email protected]>
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