Conversation
70e9736 to
7a50f62
Compare
zxch3n
left a comment
There was a problem hiding this comment.
Summary
Layer 3’s journal receipt boundary is sound: HistoryWriter prepares on a fork, IndexedDB put of exact bytes happens before live import, replay is idempotent, original-replica snapshot import is a Loro merge (not a replace), submission/delivery use separate per-session locks, Guide checkpoints offered before RPC and will not send a second offer, logout/cache-clear retain unresolved records, and Electron drains renderers before CLI shutdown.
One P1 remains. Queue admission now journals under the queue item’s userTurnId. Native queue-steer still promotes by calling addHistory with that same id and a pending_apply entry. insert treats the different entry JSON as an identity conflict, so steer-capable agents cannot promote a queued message.
Issues
bug — queued userTurnId cannot be promoted to history
pushMessageQueue admits a journal record keyed by userTurnId with default status: 'pending' and a queue payload. handleNativeSteerQueuedMessage then calls useSessionDoc.addHistory with the same id and status: 'pending_apply'. All user addHistory calls now go through acceptSessionUserTurn → storage.insert, which throws Submission identity conflicts with saved content when the entry JSON differs. Native queue-steer (acknowledgedSteer) therefore fails every time instead of activate/retry on the original record. CLI mq promotion is unaffected.
Suggestion: If sendJournal.read(userTurnId) already exists, activate to guide/dispatch and retry instead of admitting a second history write.
| throw new Error('Runtime not ready'); | ||
| } | ||
| const entry = { ...item, id: item.id ?? uuidv4() } as SessionHistory; | ||
| if (entry.role === 'user') { |
There was a problem hiding this comment.
P1: This new user-turn gate journals every addHistory under entry.id. pushMessageQueue already admitted that id as a queue record (status: 'pending' plus queue payload). Native queue-steer (handleNativeSteerQueuedMessage) reuses the same userTurnId with status: 'pending_apply' and no queue payload, so storage.insert throws Submission identity conflicts with saved content.
Steer-capable agents therefore cannot promote a visible queued message; retry hits the same conflict. Reuse the existing record via activate({ kind: 'guide', expectedTurnId }) + retry instead of a second admission.
Model: gpt-6-astra
4effefc to
ef0faa6
Compare
Model: gpt-6
ef0faa6 to
95a68c7
Compare
Model: gpt-6
Model: gpt-6
786a877 to
8bcd872
Compare
Problem / pressure
A lost write receipt can leave a message authored but invite a duplicate append. Route, account and app teardown also need a durable owner for messages that have not reached their target transport.
Summary
Stack 3/4, based on #707. Introduce account/workspace-scoped IndexedDB submission records, separate per-session submission and delivery locks, and recovery controls. The existing writers prepare history or queue operations on a temporary fork; exact bytes are saved before live import. Recovery replays those bytes and merges the original replica baseline. The saved source is the window that actually prepares the operations, including cross-window takeover. Explicit target synchronization publishes imported operations. Guide uncertainty reconciles the original turn without another offer.
Electron asks before draining renderer work and stopping the CLI. Browser navigation, logout and cache/reset paths retain unresolved messages. Transfer timing remains unchanged; complete attachment drafts follow in layer 4.
Visual explanation
Before / after
Test plan
TMPDIR=/private/tmp NODE_ENV=test pnpm checkpasses completely (components: 479 files / 3,671 tests).pnpm formatandpnpm run docs checkcompleted; docs report zero errors. Packaged desktop/mobile acceptance is still outstanding.Context handoff
Instructions for reviewing agents
Authoring context