Repository navigation
Bots on phones: status line, Steer/Queue, instant actions (bot chat activity D, Remote rev 30) - #479
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… with shared fixtures Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A Stop from the Mac or a phone now goes through one process-wide botTurnIntents emitter. A Stop that fails takes "Stopping" back (stopCancelled), and Resume is announced only from the session's onResumed, after it actually resumed. The desktop live projection listens through wireBotLiveTurnIntents, an electron-free seam tested in live-projection.test.ts. liveRunKey is exported for the Remote projector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…test A listener that throws while hearing Stop, a failed Stop or Resume is now reported through an optional onError dep (logged as a bots warning in the process-wide emitter) instead of being swallowed, and the other listeners still hear the intent. A two-Bot case pins that a Stop for one Bot never reads Stopping on another Bot's running reply. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r and Queue
Devices holding bot:activity get the turn's phase ({phase, app?,
startedAt}) and the person's waiting messages in the session snapshot and
as activity and queued frames; every other device gets its current state
at those seqs, so seqs stay gapless and revision-29 parsers never see the
new keys. A host projects them, and accepts whenBusy (steer -> steer,
queue -> followUp), only with both turn intents and the Bot service's
Chat activity gate.
Queued inputs show only once the session classified them as the
person's own (quietInputs, fail closed, throttled retry on the
projector's lane); photo-only inputs are left out. Stop, a failed Stop
and Resume are scoped to one run, which restarts on a new run key too.
The shared derivation now holds "Picking up where it left off" until the
resumed run's first live event, so a killed run's partial text no longer
reads as writing after a crash, on the Mac and on phones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… bot:activity opt-in Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…us words Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…t bot:activity Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…Queue in the session model Optimistic send with an outbox, instant Stopping, reconcile against the Mac's entries and Queued bubbles, skeleton/connecting state and a memory-only transcript cache (R14). Folds the Task 4 review: snapshot activity/queued, bot:activity opt-in tests, one queued-list decoder, no unreachable display fallback, startedAt 2^53-1 accepted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…faces The Bot chat draws the status line, the Steer/Queue busy pill beside Stop, the Mac's Queued bubbles and the person's own outgoing messages (Sending…, Queued, Couldn't send · Try again). It never blocks on the connection: the composer works at once, a chat with no cached transcript shows skeleton bubbles, and a quiet Connecting… hint replaces the spinner and the blocking load error. Working Bots' faces glance in Bots home, replacing the green dot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vity devices The person's own `message` entries (role user) now carry the optional `submissionId` they were sent as, so phones settle optimistic sends exactly. - BotSessionRuntime.placedSubmissions(botId) maps each placed input's pi.user entry to its submission id, using the same quiet-input check as quietInputs, so routine inputs and the self-intro are never listed. - The Remote projector looks placements up on its serial lane once per new pi.user entry and keeps a projector-lifetime memo of the newest 64, so reconnect snapshots still name a finished turn's send. - Only `user` transcript entries are tagged: routine inputs and question answers never are. Devices without bot:activity get every snapshot and entry frame without the key, at the same seq. - Protocol type, strict parser (user role only, wire id shape), OpenAPI, contract fixture samples and a non-holder privacy sample; iOS decodes the optional key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ontrols Reconcile by submissionId (R16), with text only for entries without it, unsettled sends and queued-before-receipt; entries are claimed once per epoch. The outbox (R17) never drops an unsettled message, holds later messages behind a deferred one, survives leaving the chat (session cache) and relaunch (protected file, 24h), retries with bounded backoff while connected, is purged on unpair and access loss, and never blocks listen(). Retry, Resume, Dismiss, answers, approvals and routine proposals apply at once and roll back on failure (R18). Receipts apply only if the session didn't move; a new run clears Stop; a clean close no longer flashes Reconnecting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A bounded 64-entry memo evicted old ids, so the next publish re-sent the old bubble as an entry frame to every device; phones that no longer held it appended a ghost bubble at the bottom, shipped revision-29 phones too. - The memo is keyed by entry id and pruned only when the entry leaves the session window (either audience's), so it is bounded by the window. - A tag change alone is never an entry frame: a bubble is tagged when it first shows and only loses the tag once it is out of view. - A failed placement lookup is reported through the projector's report. - The parser (TS and iOS) refuses submissionId together with label, with a rejected fixture sample. - Tests: more than a window of messages never re-sends an old bubble and every bubble in view keeps its id; a reported lookup failure; a real durable steer and follow-up placed mid-turn, two at one boundary, each take their queued id in the publish that drops them from Queued. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…status words Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…eer/Queue in the session controller Optimistic sends through a durable outbox (R14, R16, R17): exact reconcile by submissionId with text only as a fallback, per-epoch claims, head-of-line ordering, bounded backoff, failed (never dropped) on exhaustion or 24h TTL, noBackup disk persistence keyed by pairing with owner-guarded writes and per-record decode, purged on unpair, 401/403 and accessChanged. Stop, Resume, Retry, Dismiss, answers, approvals and proposals apply at once and roll back only what nothing newer replaced (R18). Status line per R7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Failed Resume, Dismiss, answers and approvals roll back whatever the Mac hasn't written since the tap, even across unrelated frames. A message unsent after 24 hours, or out of tries, says Couldn't send instead of vanishing, on restore and in memory. A stream 401/403 purges with the notice and a failed refresh keeps it. Outbox writes are owner-guarded on disk as in the cache, coalesced, ordered before a purge, and stop on release; load() sends structurally. The outbox file is keyed by the pairing's deviceId, decodes record by record, refuses a 21st message visibly and is excluded from backup. An echo settles only on a receipt with its submissionId; 409 idempotency_in_flight keeps the message key; Stop clears on a new run's first activity; Retry waits for a load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- aidenProgressCapabilitiesToRequest: the opt-in grants as one table, each asked only from a Mac announcing its feature and only when not held. - whenBusy and PATCH chatActivity go only to a Mac that supports bot-activity-v1; the session transport reads that from serverInfo. - aidenBotChatActivity gates a cached detail's chatActivity on support now. - A turn leaving running drops its activity, so an optimistic Stop/Resume or the next turn never shows the run before's phase. - Fixture frames also decode through AidenBotSessionEventStream.decodeFrame; tautological grant-list assertions dropped; two-Mac grant persist/drop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd glancing faces The chat draws the R14 outbox (Sending, Queued, Couldn't send with Try again and remove at 48dp), the cached transcript or still/shimmering skeletons with a Connecting / Try again hint, and the status line with a 2 s throttled word-only announcement that resets when the line hides. Waiting bubbles use the opaque primaryContainer pair (>=4.5:1), not alpha. Bots home replaces the green dot with glancing faces; Reduce Motion, battery saver and photos wear the glance badge (R19). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ns offline Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ead off main - The session transport sends whenBusy exactly as the controller froze it, so a retry under the same key is byte-identical. - Exhausted retries remove a message only when an untagged entry stands for it; an entry naming another submission leaves it Couldn't send, key kept, claim given back, and never settles a failed message. - The outbox is read on the store's io thread from start(); deliveries wait for it and restored messages go first. Writes made before the read wait in memory and merge. Unpair keeps purged chats read and empty. - stopFollowing cancels the delivery under way; a refused store write ends sending. AtomicFile (fsync before rename); enqueue refused past the byte budget; any activity after a Resume tap clears Resume. - Typed exception for a chatActivity-only patch to an older Mac. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picks apply at once and save in the background: taps during a save coalesce onto the returned revision, a failure or conflict rolls back to the saved choice, a connecting Mac holds a pick for 8 s, and each request is bounded to 12 s. Previews replay what each level shows on the Mac, pause when not resumed or off-screen, and hold a level-specific still frame under Reduce Motion. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…uts, Mac step wording Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…box writes An echoed message out of tries is removed only when its echo names no submission; otherwise it fails with its key, gives the claim back and never settles on that foreign id again. Message POSTs, Stop and the R18 controls are bounded at 12 s and a timeout keeps the key. The store owns one ordered writer per chat, held strongly, ordered with the unpair purge so a late write never recreates a purged file. The outbox has a 10 MB budget sized for 20 worst-case messages and refuses past it; oversized files are kept. Cancelled sends spend no try; release cancels the real sending task; expiry and state-reason failures release echo claims and keep frozen keys; responses apply by stateWrites; Resume follows the Mac's first activity. TestGate is a bounded latch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n, Profile, Home) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ndex and memory Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ffline row Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…urvives relaunch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
botActivityPrivacy.rejectedNullLiterals holds activities (app: null), sessions (queued: null), events (a queued frame with queued: null) and entries (label: null with submissionId). Each decoder must refuse them; the TS parser does, and the protocol test pins each reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pens New Bot Instrumented (headless AVD): the Creating… row shows from the start of a create, a failure removes it and says so, and Try Again reopens New Bot with the same answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Bot chat's Files sheet was the last Bot surface still showing
ProgressView("Loading files…") on a cold load (R15). The Files section now
shows file-shaped skeleton rows built from AidenBotSkeletonBlock (still under
Reduce Motion and Low Power), read by VoiceOver as one "Loading files".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y Again As iOS 9685204: the create flow lived only in memory, so a process death mid-create lost the answers and the Idempotency-Key. The ask (answers, the frozen request body and its key) is now on disk per pairing before anything goes out, beside the pairing's chat outboxes in noBackupFilesDir (AtomicFile), so an unpair purges it and nothing is written for that pairing after; a 401/403 on the create drops it. On relaunch Bots home shows it as not made: within a day Try Again sends the same request on the same key, so the Mac replays its one Bot; after that, or after a refusal, it reopens New Bot as it was. A Bot the Mac's list already shows clears it quietly; OK, or closing the reopened New Bot, lets it go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The scripted saves in AidenBotChatActivityTests waited on bare continuations, and one on an unbounded while-sleep loop, so a test that failed before letting its save go left the pick hanging until the execution allowance. They now wait on a Hold that fails the test after 5 seconds (checked by leaving one held: it fails in 5.05 s instead of hanging); the polls for a save to start were already bounded by untilSaving. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pped A timeout (or a conflict) re-reads the Bot, and a save that landed counts as saved. The pick made while that save was in flight was cleared before the re-read, so when the refresh showed the first pick had landed the second one was silently lost: the page showed the first choice with no error. It is now cleared only when the save rolls back, so it goes out next on the revision the refresh read. A pairing that changed during the refresh gives up quietly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om its page AidenBotChatActivityReport held a confirmed pick while Advanced was open and reported it when Advanced's onDisappear ran. Advanced had already disappeared when Chat activity was pushed over it, so closing the Profile sheet (or popping back to the chat) straight from the Chat activity page never closed the report: the held pick, and every later one, never reached the screens behind (the Bot cache still got them). The report now tracks both pages. Pushing Chat activity hands the hold over, the last page to leave reports what is held once, and later saves go straight behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A create an earlier launch left behind replays its frozen request when Try Again is chosen. If that replay failed again (the Mac unreachable, or an answer lost), the next failure reopened New Bot instead, which rebuilds the ask from the current catalog and could miss the frozen key. A restored attempt now keeps replaying until it is made or let go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The new Create recovery can target the wrong Mac, replay an expired operation, or lose its retry identity across a crash. These need fixes before merging.
Reviewed changes since 7744dd3, covering the complete incremental artifact, affected full-diff regions, and their host/native consumers. This focused delta review relies on the initial whole-PR review for unchanged implementation rather than repeating the 98-file review.
- Added durable Create recovery on both phones, retaining answers, frozen requests and idempotency keys across relaunch, with pairing-local storage and cleanup.
- Changed Android New Bot to close immediately, show a Creating row on Home, and offer retry/reopening after failure.
- Separated Android optimistic cache state from confirmed disk writes, rejected the shared fixture's optional null literals, and improved Bot error-text contrast.
- Preserved iOS Chat activity picks during timeout recovery and reported confirmed saves when the sheet closes directly from that page.
- Replaced iOS Files loading with skeleton rows, bounded held test saves, and contained editor-test pipe errors.
- Verified available checks: passed 47 host Bot/ledger tests, 20 Ruby and 30 Node iOS release-policy cases, and syntax parsing of eight changed Swift files. Independently confirmed that the default host ledger executes an identical Create key again after 25 hours.
- Checked native verification limits: local XCTest is unavailable without
xcodebuild; Android stopped atPlugin [id: 'org.gradle.toolchains.foojay-resolver-convention', version: '1.0.0'] was not found, and the online retry returnedTool 'shell' timed out after 120000ms.The exact-head hosted Android verification step succeeded; Compose execution was still running and iOS was queued when checked. The worktree IO suite returns early on Linux, so it does not verify the EPIPE change here.
gpt-6.1-sol | 𝕏
… disk Create and a restored Try Again queued the pending-create write and sent at once, so a slow disk queue plus a process death after the Mac committed lost the recovery identity. The store's save now answers once the AtomicFile write has synced and landed on its io queue (checking the sync and rename that finishWrite only logs), and send waits for that answer. A write that fails sends nothing and offers Try again with the same answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pending create now belongs to one pairing: the Mac, this phone's device id there and when they were paired. The store records the pairing's time, and a record an earlier pairing of the same Mac left behind is dropped rather than restored. The create flow starts, restores and retries nothing while another pairing is in use: a restore that lands after a switch shows nothing and is read again on the pairing's next visit, so Try Again never sends one Mac's answers to another. The Bot save and Chat activity hosts take only the client made for their pairing, so the moment between a switch and the new client can't hand one pairing's work the other's client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Mac keeps a settled Create key for 24 hours, and the same key after that makes a second Bot. A New Bot now replays its key only within 23 hours of when it began on the phone's clock (and not when the clock has moved back more than an hour), checked on restore, on Try Again from a prompt left open across the boundary, and for this launch's own uncertain attempts. Past it, the store forgets the key on disk while keeping the answers and request, so no later launch can replay it. Try Again then reopens New Bot with the answers and says the Bot may already be on the Mac; only the person's own Create sends a new request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mac A's restore could land after a switch to Mac B and show its prompt there, and Try Again built its request from the active pairing, so A's answers could become a new Bot on B. The create flow now keeps failures and retained attempts per pairing, Bots home shows only the active pairing's failure and Creating... row, and Try Again (and the New Bot it reopens) sends only to the failure's own Mac; otherwise the failure waits for that Mac. The restore is fenced like Chat activity's isCurrent: a look that lands after its task was cancelled, or after the request context (instance, device, activation generation) stopped being current, shows nothing and is looked for again when that Mac is active. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Mac's idempotency ledger forgets a Create key 24 hours after it answers and then runs the same key again, but every restored frozen request replayed on Try Again however old it was, and the store kept an ambiguous record forever. As on Android, a frozen request now replays on its key only within a 23-hour window (an hour short of the Mac's, for the two clocks; a clock that went back counts as past it). Past it the store keeps the answers and what was sent but drops the keys; Try Again first looks in the Mac's list for a Bot with the same name and subtitle made since the request went out (allowing two minutes of clock skew) and lets the failure go quietly if it is there, and otherwise reopens New Bot with the answers, where Create is a new request. This holds for a prompt left open across the boundary and for an attempt kept in memory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Android review asked for a disk-before-network barrier on Create. iOS already awaited the pending-create write before the request went out, for Create and Try Again alike, but it ignored whether the write succeeded, so a full disk or an unwritable folder still sent a mutation that a relaunch could not recover. savePendingCreate now reports whether the record is on disk, the flow's write chain carries that result, and a create (new or replayed) whose answers or keys couldn't be written stops before anything reaches the Mac, with "couldn't store this Bot" and Try Again. The test checks against a second store that each request's exact body and key are on disk as it leaves, and that nothing goes out when the write fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nswers With failures kept per pairing, Mac B's interrupted create can come back while a Bot is still on its way to Mac A. Its Try Again then reached submit's one-at-a-time guard and returned, dropping B's failure from memory. A Try Again (or the New Bot it reopened) that can't go out now keeps its answers as they were, for the same pairing or another, and Bots home holds the failure prompt until no Bot is on its way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found in this delta. The three previous findings are addressed; exact-head native CI is not yet complete.
Reviewed changes since 9c35409, covering the complete seven-commit incremental artifact, affected full-diff regions, and relevant host/native consumers. This focused re-review relies on the initial whole-PR review for unchanged implementation rather than repeating the 98-file review.
- Added disk-before-network barriers: Both phones now require successful persistence of the exact Create request/key before sending, including recovered retries, and report write failures without sending.
- Isolated pairing authority: Checked iOS per-pairing attempts/failures, cancelled or stale restore rejection, and retry-origin validation; checked Android persisted pairing identity and client-ownership fences during installation switches.
- Bounded ambiguous Create replay: Checked the 23-hour replay window against the host's 24-hour retention, expiry while a prompt remains open, preservation of answers without unsafe keys, and explicit new-creation intent after expiry.
- Preserved busy retry answers: Checked that an iOS Try Again rejected while another Create is pending retains its recovery state for a later retry.
- Verified available checks: Passed 47 host Bot/ledger tests, 20 Ruby and 30 Node release-policy cases, and syntax parsing of all four changed Swift files. These do not execute or type-check XCTest; this Linux runner lacks
xcodebuild. - Checked Android and hosted verification: Local Android tests stopped at
Plugin [id: 'org.gradle.toolchains.foojay-resolver-convention', version: '1.0.0'] was not found; the dependency-enabled retry returnedTool 'shell' timed out after 120000ms.The exact-head Android verification step succeeded, while Compose execution remained in progress and the iOS job remained queued. This review does not establish green overall CI.
gpt-6.1-sol | 𝕏
Revisiting a running chat starts the local run watcher. When the route-detached run then ended (Stop, or its reply landed), the watcher reported the run's end after the terminal had already cleared the detached marker, and that marker was the only proof the run was this window's own. The run came back as an observed (phone-style) run, so the composer re-locked with "Waiting for the response…" right after it had unlocked, and a text-only reply could flash a second streaming row and Stop. Remember the streams this document starts (bounded) and never mirror them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stop and the Steer/Queue pill appear as soon as a send begins, but two things made the pill unreliable until main had finished starting the run: - handleSend awaited the chat:start acknowledgement, which kept the composer in its sending state. The pill could not submit, so picking Steer or Queue only switched the mode and left the draft. The send now finishes at the durable append; a start rejection still sets the error. - Pi opens its run-input queue at agent_start. Before that main answers run_not_active, which the composer reported as "The current response has ended". Admission now retries that answer, with a bound, while the pane's own run is still live. A rejected attempt writes nothing, so a retry cannot duplicate guidance. Detached runs are not retried. Under a six-worker load the Steer specs in chat-message-queue failed 8 of 30 runs before and 0 of 60 after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two hosted flakes in chat-message-queue (Stop missing after a revisit; no request with the edited queue text) predate Bot slice C2 and have not reproduced locally or in a Linux container. Make the next hosted failure explain itself: - On failure the fixture prints the on-screen alerts, status lines and toasts, plus the dev log's warn and error records, to stderr. Hosted artifacts keep only the sanitized receipt, and the reporter truncates the dev-log attachment to two lines. - The queue-editor spec checks that the first reply saved and the queue is not paused before it saves the edit. A response that failed upstream now fails at that step instead of reading as an editor bug. - The rejected-steer spec waits for the closing menu to return focus to its trigger before typing. Radix restores that focus a task later, and under load an Enter sent straight to the composer could land on the trigger and reopen the menu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found in this delta. Exact-head CI is still incomplete.
Reviewed changes since 492eb1a, covering the complete four-commit incremental artifact, affected full-diff hunks, and lifecycle/admission/composer consumers. This focused re-review relies on prior reviews for unchanged implementation; commit artifacts supplied patches omitted from the full diff.
- Preserved run ownership after settlement: Checked that delayed observer updates cannot mirror this document's own run after detached cleanup, while subsequent phone/window runs remain visible.
- Enabled Steer/Queue during startup: Checked completion at the durable append and bounded admission retries, including Stop, terminal, committed-refusal and unknown-outcome boundaries.
- Improved failure diagnostics: Reviewed bounded notice/log output and the queue spec's focus and saved-reply assertions.
- Verified available checks: Passed 133 focused tests, project and E2E type-checks, and changed-file lint; collected all 19 queue specs. Electron execution requires macOS under the repository's E2E skill, so collection does not establish runtime acceptance. Exact-head CI remains pending.
gpt-6.1-sol | 𝕏
On Stop the harness reports each journal write it stops waiting for to onJournalError as a PiManagedCancellationError, so every Stop logged "Could not append Pi session messages" at error level, usually three times. The write is detached and may still land, but the visible-turn lease rolls the turn back and re-journals the visible chat, so the session stays intact. Keep marking the journal unhealthy, log the Stop once at info, and keep real write failures at error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… without awaiting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found in this delta. Exact-head CI is still incomplete.
Reviewed changes since f7b919c, covering both new commits, all four changed files, and their cancellation, persistence-recovery and send-path consumers. This focused incremental review relies on prior reviews for unchanged implementation rather than repeating the 111-file review; commit artifacts supplied the three Pi patches omitted from the full diff.
- Distinguished Stop from write failure: Checked the exported cancellation classifier and once-per-stream info logging while preserving unhealthy-journal marking, real-failure error logs, and rollback/resync recovery.
- Extended journal recovery coverage: Checked cancellation during streaming, detached-write settlement, exact lease rollback and visible-history reconstruction, plus the existing fail-closed write-failure case.
- Corrected transition-test expectations: Checked that the existing assertions follow the non-awaited generation start and guarded asynchronous error callback without changing production send behavior.
- Verified focused checks: Passed 287 tests across seven harness, durability, compaction and renderer suites, project type-check, and changed-file lint. Four initial compaction failures were resolved by building the required VCC worker before rerunning that suite; Electron and native mobile execution were not performed for this desktop logging/test-only delta. Exact-head CI remains pending, so this review does not establish green CI or merge readiness.
gpt-6.1-sol | 𝕏
…g send 4813a5c settles a send once its message is saved, so Steer and Queue work while main is still starting the response. The image-queue spec held only the start receipt and expected Attach to stay disabled through it. That expectation followed from the old send settling at the start acknowledgement. Locally it still passed because its first check landed before the save finished. On Linux CI the save was already done, and it failed both attempts (run 38692828176). The attach gate exists so that a failed send can restore its own payload without merging in newly added files. Once the message is saved, a start failure no longer restores anything, so intake may reopen during start like Steer and Queue. The spec now holds the save receipt and then the start receipt. Attach is disabled until the save lands and enabled while the start is still held. The image and text are queued in that window, and Stop still pauses both without sending either. Each phase is now deterministic: the old send path fails the new check every time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found in this delta. Exact-head CI is still incomplete.
Reviewed changes since fee9ae3, covering the complete one-commit, one-file delta and its composer, send-lifecycle, IPC-handler and mock-provider consumers. This focused incremental review used the authoritative incremental/full-diff hunks and commit artifact, relying on prior reviews for unchanged implementation rather than repeating the 111-file review.
- Added separate receipt gates: Held the first-message save and generation-start acknowledgements independently, checking attachment intake stays closed before save acknowledgement and reopens while start acknowledgement remains held.
- Preserved queue and Stop coverage: Queued image and text follow-ups during the held-start window, then retained the checks that Stop leaves both paused without sending either to the model.
- Verified available local checks: Passed E2E type-checking, changed-file lint, collection of all 19 queue specs, and 60 focused attachment/composer, queue and transition tests. These checks do not execute the changed Electron test; Electron execution was not attempted on Linux under the repository's macOS-only E2E guidance. Exact-head CI was queued when checked, so this review does not establish green CI or merge readiness.
gpt-6.1-sol | 𝕏

Slice D of Bot chat activity: Bot chat activity on iPhone and Android, over Aiden Remote revision 30. Slices A, B, C1 and C2 (#475, #477, #476, #478) are already merged.
Plan:
docs/superpowers/plans/2026-10-14-bot-chat-activity-d-phones.md. Every ruling (R1–R22), deviation and parked item is recorded in spec §11/§12/§17 and.memory/bot-chat-activity.md.What changes for people
Contract (revision 30, provisional; main is still 29)
bot:activity, plus thebot-activity-v1token. Phones that haven't opted in get a no-opstateframe at the same seq, so legacy streams stay gapless.{ phase, app?, startedAt }.submissionIdon the person's user entries, for exact reconciliation.whenBusy(steer or queue).chatActivity, stripped for non-holders on every detail route.stopping,stopCancelledandresuming, so the Mac and phones agree.docs/aiden-remote-api-v1.mdare updated. TS, iOS and Android decode the shared fixture strictly.Verification
tsc,lint,test:ci-policy,test:bot-runtime(194),test:bots(820)test:aiden-remote: all pass exceptaiden-remote-service.test.ts"single-transport profiles lease…", which fails locally withAidenRemotePortInUseError. An unrelated outbound socket holds one of its fixed ports on this Mac; the file is untouched by this PR. CI is the arbiter.-test-timeouts-enabled YES:app:testDebugUnitTest(892),:app:lintDebug, and Bot instrumented tests 12/12 on a headless AVDKnown open items (spec §17)
CI notes
tests/e2e/chat-message-queue.spec.ts:584"Stop after revisiting cancels the detached response and permits a new message" flaked. The first attempt timed out after 10 s onexpect(stop()).toBeEnabled()(element not found) at line 617, then passed on retry Use catalog-driven runtime model limits #1. The "Linux x64/arm64" gates failed downstream of it. The same spec flaked at line 481 on Bots: Bots-only sidebar and the Bot side panel (bot chat activity C2) #478. It predates this stack: the same specs failed on Oct 9, 10 and 13 (runs 38020507256 and 38452403485), so C2 did not cause it. It has not reproduced in about 1,300 local runs plus 360 Linux/xvfb runs. This PR fixes two real bugs in that path: a window's own run was mirrored back as a phone run after Stop (69f5c2f), and Steer/Queue failed while a response was starting (4813a5c). On failure the spec now prints on-screen errors and app error logs (a702a26), so a future failure names its cause. The whole spec passed 570/570 with--repeat-each 30and--fail-on-flaky-tests. No retries were added and no timeouts raised.scripts/worktree-file-io.test.mjs(seen on Bot chat activity 3/5: Extract a reusable workbench shell from the environment panel #476 and Bots: Bots-only sidebar and the Bot side panel (bot chat activity C2) #478) is fixed in this PR.Built task by task with subagents. Each task went through its own review and fix rounds, then a final whole-branch Opus review and a final fix wave, with each part re-reviewed.
🤖 Generated with Claude Code