Repository navigation
Native chat: a message is never marked not delivered after a crash, and reopening a chat stops reading the transcript - #30580
Conversation
…ing a chat stops reading the transcript After a crash or restart, attach read a window of the agent's saved log and marked any unconfirmed message missing from it as rejected "not delivered". Absence from a log Orca does not own is not proof: the window's anchor moves every turn (STA-7416) and its text filters drop tagged prompts (STA-7453), so messages the agent received were marked undelivered and retyping them duplicated the question. The read also ran on every attach (STA-7434). Delete the inference: the provider history window and its adapter hooks (Claude window and branch proof, OpenCode stored-messages reader), the submission matcher, and the attach step. A send the crash boundary leaves unconfirmed stays an ordinary sent message; the interrupted turn still ends through the existing settlement. Explicit live refusals are unchanged. A queued card whose hand-off a restart left unconfirmed no longer counts as able to return to the queue, so it stops keeping an idle chat loaded.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. ℹ️ Recent review info
Walkthrough
Merge Risk:
|
|
After a crash during a chat send, Orca could search an incomplete agent log and incorrectly label a received message “not delivered.” Sending it again could repeat the request. Recovered messages now remain ordinary sent bubbles. Reopening neither resends them nor guesses delivery from the agent log; the interrupted reply settles separately. Explicit live refusals and previously saved rejection records retain their behavior. Full review: round 1. The source, whole-mechanism comparison with the common pattern, readiness and performance review passed; obsolete fixtures and the saved Rewind boundary were fixed. Intended edges remain: Copy to CLI refuses a crash-cut first-send-only chat until saved content is established; a recovered message without a saved native boundary has no Rewind offer, while earlier accepted targets remain; an older peer that omits submission facts retains a provisional client offer with host validation. Pre-existing queue-sweep cost belongs to the send-lifecycle lane. ACP’s earlier local acceptance remains distinct from provider acknowledgment; provider receipt is never inferred here. Verified for real on Claude upgrade, recovery, subsequent real replies, saved options and desktop Copy evidence carry from Verified current head Evidence carry and changes after the carried Claude runMain merges Post-QA merge For Brennan’s review Codex crash recovery and a real new reply — QA head 6771709Recovered message, one ordinary sent bubble: A distinct new prompt received a real reply (6m14s; the cause of that latency was not established): Rewind menus — recovered message has no offer; earlier accepted message retains it
Screenshots only; Rewind was not selected or executed. One OpenCode entry: crash recovery and a real new reply — QA head 6771709Recovered message, one ordinary sent bubble: A distinct new prompt received a real compass reply: Carried Claude upgrade/recovery proof — PR head 15d5ab8 (historical evidence)
Real subsequent replies after reopen: These are retained earlier-head results, not a new Claude run on 6771709. Three source spots: reopen preserves the unknown outcome, saved Rewind identities, strict Copy content check. |









ELI5
If Orca crashed or restarted while a chat message was on its way to Claude, Orca later tried to work out whether Claude had got it by searching Claude's own log for it. When the search missed (and it often did), Orca marked the message in red "This message was not delivered. Send it again to continue." even though Claude had received it, and sending it again asked Claude the same thing twice. Orca now stops guessing: a message you sent stays a normal sent message, and the reply that the crash cut off ends the same way it does today.
What Changed
Before
<system-reminder>(STA-7453).After
Mechanism. On reopen, Orca already marks every message whose outcome it never heard as "unconfirmed" (shown as a plain sent message, never "Working", never blocking a new send), and already ends the interrupted turn in one settlement step. After that, attach used to read a window of Claude's saved log, anchored at the chat's last saved position, and matched each unconfirmed message by a fingerprint of its text. A message missing from that window was marked rejected "not delivered", and a message found there was marked accepted. This PR deletes that second step and everything it needed: the window reader, the log branch-proof code it ran on, the matcher, the per-agent history hooks (Claude, plus a stored-messages reader for OpenCode), and the attach step that called them. The unconfirmed state set at reopen is now the final answer.
Current main already keeps a queued message sent once it has been handed over, including after a crash, and lets an idle chat unload when no other work is waiting. This PR removes the later history-based delivery guess for those messages too; it no longer changes how the queue stores or settles them. A genuine later acknowledgment from the agent can still update the message’s saved identity.
Why
The bug class. Orca was deciding whether a message reached the agent from its absence in a log Orca does not own, read through a window whose anchor moves every turn and through text filters. Missing from that window is never proof the message wasn't delivered. Every anchor move, filter, compaction, fork, rewind or log-format change turned into a wrong "not delivered" that invites a duplicate question. STA-7416 and STA-7453 are two samples of that one cause, and STA-7434 is its cost: the read had to run on every reopen because nothing could cheaply tell whether there was anything to decide. Five earlier changes patched the same window.
Why delete rather than fix the window. The common pattern never infers delivery after a crash. The user's message stays as sent, unfinished work is cancelled or interrupted because the process ended, and a message is marked rejected only when the agent or runtime explicitly refuses it. An unknown outcome records nothing. Fixing the window (anchor at the oldest unconfirmed message, keep tagged prompts, skip the read when nothing is unconfirmed) would fix these two cases but keep the assumption that absence is proof, so the next anchor or format change would bring the same bug back. The only thing the guess bought was a red line on a message that truly never arrived. In that case the cut-off turn already shows no reply, and the user sends again.
Differences from the common pattern, all intended:
Compatibility. No new saved field, no wire change, no capability. A host on this build publishes no new state, only fewer narrowed answers. Older clients already render an unconfirmed recovered message today: every Codex and Pi crash produces one, and so does every Claude message the guess couldn't decide. Works the same over SSH, on remote and paired servers, on mobile and on all three desktop platforms, since nothing here is platform-specific.
Smaller side effects, matching Codex chats today:
Intended crash edge: If a chat contains only a first send cut off by a crash and no reply, Copy to CLI can refuse even when the agent saved that message. The existing check requires an accepted send or an agent reply; Orca no longer guesses that acceptance from saved logs. Ordinary completed chats still copy, and receiving an ordinary reply permits copying this chat. Keeping this crash edge is intended under the decision to adopt the common pattern without delivery guessing. Targeted real Codex/OpenCode crash-recovery QA and both message-menu screenshots passed on 6771709; Claude evidence carries from 15d5ab8. Review and targeted QA are complete, with final CI passing on the corrected head.
Rewind review correction: The old menu offered Rewind on any visible turn opener, including recovered prompts the host could never cut. The menu and host now share saved native identity resolution, and genuine late acknowledgments refresh the menu without a new send. No new saved field or wire requirement is added, and prepared Rewind recovery, ordinary sends and Copy to CLI keep their existing checks.
Linked Issue
Tracked in Linear: STA-7416, STA-7453, STA-7434.
Visual Proof
Codex crash recovery and a real new reply — QA head 6771709
Recovered message, one ordinary sent bubble:
A distinct new prompt received a real reply (6m14s; the cause of that latency was not established):
Rewind menus — recovered message has no offer; earlier accepted message retains it
Screenshots only; Rewind was not selected or executed.
One OpenCode entry: crash recovery and a real new reply — QA head 6771709
Recovered message, one ordinary sent bubble:
A distinct new prompt received a real compass reply:
Carried Claude upgrade/recovery proof — PR head 15d5ab8 (historical evidence)
Real subsequent replies after reopen:
These are retained earlier-head results, not a new Claude run on 6771709.
Testing
The restart-resume test now pins STA-7416: a send cut off by a restart stays
unknown/recovered, is never rejected, and the chat's continuation still runs.The attach-level test now checks that reopening after a crash keeps the send as sent and still lists it as unconfirmed for older peers.
The crash-boundary journal test checks that the message is kept once, in doubt, never re-sent and never shown as still working.
Deleted the tests for the window reader, branch proofs, matcher and the OpenCode stored-messages reader.
The Rewind regression carries a real journal through close/reopen, checks the recovered prompt has no action without a saved boundary, and restores the action after a genuine native acknowledgment while retaining earlier history. It also checks incomplete client observation remains provisional.
Targeted real Codex and one OpenCode entry passed on
6771709a: one actual pre-ack crash each, same-profile reopen with an ordinary single bubble and no replay, then a distinct new prompt with a real reply. Both Codex Rewind menus were captured; no Rewind action ran. Claude upgrade/recovery/reply and desktop Copy evidence carry from15d5ab8. Phone, worker-start unknown, linked queue/idle consumers and Rewind behavior use the approved integration/renderer contracts; no new native phone or worker timing run is claimed.Conflict-only main merge
e2a05bfapassed the required direct lint-staged check and 7 named files / 174 tests through tc-gate. Incoming main Rewind lifetime fencing and agent changes were retained. Two unchanged types moved into the existing Rewind host module with identical runtime output. Test-only correctionb04d74739f61126fc4d13fbebaa0902f2fa68599supplies main’s required presentation callback to the existing regression fixture, with assertions and all production blobs unchanged; that regression passed again. Fresh full PR CI and aggregate verify job120785232570passed on this corrected head, attempt 1. All six workflows succeeded, with 25 checks SUCCESS and 16 SKIPPED, none pending or failed; Mobile, persistence and all three WSL distros passed.All test-copy/driver/watcher processes stopped, ports cleared and real-config hashes stayed unchanged. Shared qa-drive was used without an override or pin. Codex’s new reply completed after 6m14s; the cause of that latency was not established.
Automated tests added/updated, or explained why not below
Review
Agent skill upstream boundary
Notes
The final main merge reformatted eight files the main branch had left unformatted (whitespace and separators only, done by the required pre-commit formatter); no behavior change.
Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
Checklist
Author: @BrennanKB5