Repository navigation
Sonny: what failed in the background is a red ✗ in the footer and first in /background - #419
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
…st in /background A nightly run that failed while the laptop was offline or a login had expired failed unseen: the trigger recorded "sent" and the turn it sent then failed. Now the window asks the daemon how each trigger's last sent turn ended (one `wait` with timeout 0, every ten seconds, for turns not known yet), and counts as failed: - a trigger whose fire failed, or whose sent turn failed (a turn the person interrupted or steered is not a failure); - a server the nightly memory cleanup could not read, by its `unreadable-SERVER` fact (#411). The footer says `✗ N failed` in red, left of `↻`; the margin glance has a red `✗ N` beside `↻`; both open /background, which lists what failed first with the error under it. The person's own agents' failures (no project in the name, such as memory-cleanup) show in every window. The triggers tool's rows say how the turn their last fire sent ended (`last.turn_status`, `last.turn_error`), so an agent sees what the person sees. No daemon or protocol change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 854d2c7b0c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ead only for this store's triggers A one-shot that did not deliver, or a trigger stopped by an error, keeps its row when its job goes; /background now lists such rows, scoped by the store id each row now records, so the failure stays until `d` removes it. The triggers tool asks this daemon only about triggers made on its store: a turn handle names a bot and a turn, which another store's daemon has its own of. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
…'s mark `›` sat against the row's mark (`›✗`, `›↻`), which read as a glitch. It now takes two columns, as the composer's `› ` does, and every line after a row's first starts under its name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1d78a99b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let mut items = read(&self.turns); | ||
| let unended = background::unended(&items, &self.turns); | ||
| if !unended.is_empty() { | ||
| let ended = trigger::ended(&self.client, unended).await; |
There was a problem hiding this comment.
Retain sent one-shots until their turn outcome is known
When a one-shot trigger successfully submits a turn that subsequently fails, the new outcome lookup never sees its handle: trigger::settle immediately calls retire with keep = false for a successful send, deleting both the job and its state row. Consequently, neither read_around nor the triggers tool can discover that failure, even if Sonny remains open throughout. The same applies to the final successful submission of a --runs trigger. Preserve those handles until their turn outcomes can be checked so these failures also reach /background and the red footer count.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
This is a real gap, but I'm not fixing it in this PR. The path: a one-shot, or a --runs trigger on its last run, sends its turn, settle deletes its row, and the turn fails afterwards. The recurring triggers this PR is for, such as the nightly cleanup, keep their rows and are covered. Fixing it means keeping sent rows past retirement, which changes the trigger lifecycle. Every finished one-shot would then stay in the agent's triggers list until something removes it. That needs a design call, so I filed it as #422.
Generated by Claude Code
…and a start trigger stays its adder's once it ends A turn that went well but whose answer could not be passed on now counts as failed, with the delivery error. A retired `--start` trigger's row keeps the agent that added it (`by`), so its failure stays in that project's windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
🤖 Generated with Claude Code
https://claude.ai/code/session_013jkdGEbQZnXUy1kATtYcQ6
Why
A nightly run that failed while the laptop was offline or a login had expired failed without anyone seeing it. The trigger recorded
sent, and the turn it sent failed afterwards. George picked a status-bar line so that failed background work reaches him. He also asked that an agent be able to see the same failure he sees.What
waitwithtimeout_ms: 0, only for turns it doesn't know yet, in batches of 64. It caches the answers and drops them once the fire is gone.unreadable-SERVERfact (memory-cleanup: a server it cannot read holds the night open #411), for the person and the project.✗ N failedin red and not dimmed, left of↻. A click opens/background.✗ Nbeside↻, as a button to/background./background. Failed rows are listed first under "Failed". Each has a red✗mark, with the error in the default foreground under it. A server row can't be fired or removed, because the cleanup removes the fact once the server reads again.memory-cleanup, show in every window.last.turn_statusandlast.turn_error, so an agent sees what the person sees.maininto the next item.There is no daemon or protocol change. The design follows the visual-system thread (#405): the ✗ mark, its wording and placement, and failed rows first.
Screenshots
These come from the real daemon, using a turn that actually failed against an offline provider and a saved
unreadable-chatfact.Tests
a_fire_that_went_out_fails_when_its_turn_didcovers a failed turn, an interrupted turn, a completed turn, and a turn not asked yet.what_fails_for_the_person_shows_in_every_window_and_a_server_by_its_factcovers the scope rules and the server facts from both the user and project scopes.the_card_lists_what_failed_first_marked_with_its_errorwhat_failed_in_the_background_is_red_left_of_what_runs, for the footer.cargo test -p sonnypasses (507), and clippy and fmt are clean.The README, docs/SONNY.md and the FEATURES row for
/backgroundare updated.Generated by Claude Code