Skip to content

fix(orchestration): let mail wake a slept agent, and make slept agents visible - #18731

Open
brennanb2025 wants to merge 38 commits into
mainfrom
brennanb2025/impl-agent-sleep-wake
Open

brennanb2025 wants to merge 38 commits into
mainfrom
brennanb2025/impl-agent-sleep-wake

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 34 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​3772 $\color{#cf222e}{\Huge{\mathbf{−}}}$​208 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​3564
Prod 88 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​2654 $\color{#cf222e}{\Huge{\mathbf{−}}}$​352 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​2302

What this fixes

Agent sleep kills an orchestration coordinator pane while the worker it dispatched is still running. The worker finishes, its worker_done lands in a durable mailbox, nothing can deliver it because the pane has no process, and nothing wakes the pane. The run deadlocks and every surface reports success.

Reproduced end to end in a live instance: the dispatch was still dispatched and its worker still running when the coordinator was killed; the completion message then sat read=0 delivered_at=NULL until the tab was clicked, at which point both queued messages delivered within the same second. The mail was deliverable throughout — only the wake was missing.

Approach

Rather than trying to prevent the sleep, this makes an arriving message able to wake the pane.

Preventing the sleep was the first design and it was abandoned on evidence: the list of things that count as "still owed work" would not close. Coordinators, pending decision gates (which by construction leave no unsettled dispatch), the window right after a worker reports done, a task flipped back to ready by gate resolution, a new run holding ready tasks — each review round found another. A fix that only works when that list is complete fails silently, which is how this bug shipped. Waking needs no such list: the message arriving is the evidence.

Three parts:

  1. A slept pane is visible as asleep, not absent. It previously vanished from orca terminal list entirely, so a sender could not tell "asleep, will read later" from "gone". It now lists with an additive resumable marker. connected keeps its existing meaning (the process really did exit), and the host-liveness vocabulary (live/unverifiable/exited) is deliberately not reused for it.
  2. Addressing a slept agent succeeds. orchestration send to one is accepted and queued with a recipient_asleep warning, instead of failing with terminal_not_found — the same answer a handle that never existed gets.
  3. An incoming message wakes an auto-slept pane. Every message type wakes; there is no allowlist. A pane the user deliberately slept is never auto-woken.

Plus one cheap guard: a pane supervising an actively dispatched worker is no longer sleep-eligible. That is belt-and-braces, not the mechanism — correctness rests on the wake path.

Also fixes a pre-existing bug on main

The in-place wake this depends on was unreachable. Its listener subscribed to orca:wake-hibernated-agents-worktree while the dispatcher fired orca-wake-hibernated-agents-worktree — a colon for a dash, shipped in 286c210. The event has never been received on any build, so the path its own docstring calls "the primary wake mechanism" for already-mounted slept panes was dead. The listener now uses the shared constant and lives in its own module.

A second defect surfaced only once waking worked: kill-time delivery sweeps for an empty mailbox woke the pane Orca had just put to sleep (observed live — slept 21:39:35, self-woke 21:39:37), which would have made agent sleep self-defeating. The wake is now gated on unread mail.

Verification

Unit and integration tests, ablation-proven (removing the fix turns the new assertions red). Typecheck clean. Changed-code quality gate: 0 findings across native, type-aware and React Doctor over 48 files.

Verified end to end in a live instance with a real agent, on the same rig that found the bug:

assertion result
pane sleeps and stays asleep while idle pass — no self-wake
slept pane listed as asleep pass — connected: false, resumable: true
sending to it succeeds pass — ok: true, recipient_asleep
mail wakes it pass — process back within ~7s
woken pane is a real resumed agent pass — prior turn intact via --resume

The user-slept protection is covered by an ablated unit test (removing the guard fails only that test) and by the code path that sets the flag, but was not exercised live — there is no CLI for the workspace-sleep gesture.

Known follow-up, not fixed here

Bare term_ direct mail wakes the pane but stays unread: the handle re-mints on wake and mailbox resolution matches only the current handle string, while the pointer push is run:-only. Such a message therefore re-wakes the pane on every later sleep — a slow wake loop. run: and dispatch: mail delivers normally. This is pre-existing behaviour of terminal-only mailboxes and wants its own ticket.

Merge Sim added 6 commits September 3, 2026 22:44
Listing slept panes as resumable re-registers their terminal handle, so
`resolveTerminalHandle` now answers for a pane with no process and
`getLiveLeafForHandle` returns its PTY-less leaf instead of throwing. Both
wake branches were therefore skipped, and delivery fell to the idle-status
check — which reads the same for a slept pane as for a busy one — and
returned silently. The send promised a wake ("recipient_asleep") that never
came, for bare `term_` handles and for `run:` mailboxes alike, since a run
resolves through its coordinator handle into that same exit.

Treat "no PTY" as wake evidence before the status check: no idle edge is
ever coming from a pane with no process. A live-but-busy pane still waits
for its idle edge, and `resolveSleepingPaneWakeTarget` remains the wake
authority, so a `restoreOnTabOpenOnly` pane is still never auto-woken.

The unit tests each half already had could not catch this: listing knows
nothing about delivery, and the delivery test hands its dependency a handle
that does not resolve. The new runtime-level test exercises both halves
together — list the slept pane, address the handle the listing minted, and
assert the wake IPC, then the delivery once the pane is back and idle.
Mail arriving for an agent-slept pane resolved a wake and sent
terminal:requestTabMount, but a pane agent sleep kills in a running app
still has its tab mounted, so the renderer refused the mount by design
and nothing happened. The mounted case needs the in-place armed cold
restore instead.

That path was itself unreachable: its listener subscribed to
'orca:wake-hibernated-agents-worktree' while the dispatcher fired
'orca-wake-hibernated-agents-worktree' (286c210), so the event has
never been received on any build. The listener now uses the shared
constant and lives in its own module.

Also gate the wake on unread mail. Kill-time delivery sweeps for an
empty mailbox otherwise woke the pane Orca had just put to sleep -
observed live at 21:39:35 slept, 21:39:37 self-woken - which made agent
sleep self-defeating as soon as waking started working.

Verified end to end in a live instance with a real agent: the pane
sleeps and stays asleep while idle, a send wakes it, and the agent cold
restores with its prior turn intact.
@coderabbitai

coderabbitai Bot commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 67e52ca8-2407-48d7-87d5-384b07806e08

📥 Commits

Reviewing files that changed from the base of the PR and between 0013746 and 990e8bd.

📒 Files selected for processing (2)
  • src/renderer/src/components/status-bar/PortsStatusSegment.render-stability.test.tsx
  • src/renderer/src/runtime/use-worktree-runtime-target.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds resumable slept-pane records to terminal listings and marks them as asleep(resumable). Mailbox delivery resolves sleeping recipients, requests scoped wakes, and redrives queued messages after remount. Wake requests are paced, deduplicated, and retried after renderer readiness. Renderer mount handling distinguishes client subscriptions from inbound-message wakes and supports pane-scoped restores. Recipient routing reports sleeping status. Hibernation excludes supervisors with unsettled worker dispatches.

Merge Risk: 🔵 Low · up to 990e8

Mail routing can expose an untranslated new recipient-status message to users. This is a bounded presentation consistency issue, but it should be localized before merge or explicitly accepted.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the problem, approach, behavior changes, testing, live verification, and known follow-up. It does not satisfy required template items: the Linked Issue section contains only `… Add a valid linked issue number, such as Fixes #123``. Add before-and-after screenshots or a video, or include N/A with a brief reason only if there is no visual or interaction change. Complete the required Testing, AI Disclosure, Review,…
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 66 functions across 60 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary changes: mail can wake slept agents, and slept agents remain visible.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the problem, approach, behavior changes, testing, live verification, and known follow-up. It does not satisfy required template items: the Linked Issue section contains only Fixes #, and the required Visual Proof section is missing for behavior changes. Several checklist and review sections are also absent.

Resolution

Add a valid linked issue number, such as Fixes #123``. Add before-and-after screenshots or a video, or include N/A with a brief reason only if there is no visual or interaction change. Complete the required Testing, AI Disclosure, Review, Agent skill upstream boundary, Notes, and Checklist sections.

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 81d7e17a-1d54-4ddb-964d-0367ec4e0923

📥 Commits

Reviewing files that changed from the base of the PR and between 264c9ed and 148b09a.

📒 Files selected for processing (48)
  • src/cli/terminal-format.ts
  • src/main/runtime/orca-runtime-stop-requested-pty-ids.ts
  • src/main/runtime/orca-runtime-sync-window-graph.ts
  • src/main/runtime/orca-runtime-test-fixtures.spec.ts
  • src/main/runtime/orca-runtime-wait-for-leaf-pty-id.ts
  • src/main/runtime/orca-runtime-write-orchestration-pointer-pty.ts
  • src/main/runtime/orchestration/mailbox-pointer-delivery.ts
  • src/main/runtime/orchestration/mailbox-pointer-stage.ts
  • src/main/runtime/orchestration/mailbox-pointer-submit.ts
  • src/main/runtime/orchestration/mailbox-sleeping-recipient-wake.test.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-scheduler.test.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-scheduler.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-target.test.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-target.ts
  • src/main/runtime/resumable-slept-pane-listing.test.ts
  • src/main/runtime/resumable-slept-pane-listing.ts
  • src/main/runtime/rpc/methods/orchestration-recipient-routing-slept.test.ts
  • src/main/runtime/rpc/methods/orchestration-recipient-routing.ts
  • src/main/runtime/rpc/methods/terminal/terminal-legacy-subscribe-snapshot.ts
  • src/main/runtime/rpc/methods/terminal/terminal-multiplex-subscribe-resolution.ts
  • src/main/runtime/rpc/methods/terminal/terminal-subscribe-method.ts
  • src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts
  • src/main/runtime/rpc/terminal-subscribe-blank-mount.test.ts
  • src/main/runtime/runtime-terminal-list-slept-panes.test.ts
  • src/main/runtime/runtime-terminal-list.ts
  • src/main/runtime/runtime-workspace-session-controller.ts
  • src/main/runtime/sleeping-pane-record-lookup.test.ts
  • src/main/runtime/sleeping-pane-record-lookup.ts
  • src/main/runtime/slept-pane-mail-wake.test.ts
  • src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.ts
  • src/renderer/src/components/terminal-pane/wake-hibernated-agents-listener.test.ts
  • src/renderer/src/components/terminal-pane/wake-hibernated-agents-listener.ts
  • src/renderer/src/constants/terminal.ts
  • src/renderer/src/hooks/ipc-events/terminal-presentation-ipc-bridge.ts
  • src/renderer/src/lib/agent-hibernation-pane-eligibility.ts
  • src/renderer/src/lib/agent-hibernation-planner-supervised-runs.test.ts
  • src/renderer/src/lib/agent-hibernation-planner.ts
  • src/renderer/src/lib/agent-hibernation-supervised-runs.test.ts
  • src/renderer/src/lib/agent-hibernation-supervised-runs.ts
  • src/renderer/src/lib/mobile-terminal-tab-mount.test.ts
  • src/renderer/src/lib/mobile-terminal-tab-mount.ts
  • src/renderer/src/lib/wake-sleeping-agents-in-background.test.ts
  • src/renderer/src/lib/wake-sleeping-agents-in-background.ts
  • src/renderer/src/store/slices/agent-status-sleeping-records.ts
  • src/shared/agent-session-resume.ts
  • src/shared/pane-agent-identity-inventory.test.ts
  • src/shared/runtime-terminal-contracts.ts
  • src/shared/terminal-tab-mount-intent.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 1 remains after this review.

Comment thread src/main/runtime/orca-runtime-sync-window-graph.ts Outdated
pane: ResumableSleptPane,
worktreesById: Map<string, ResolvedWorktree>
): RuntimeTerminalSummary {
const worktree = worktreesById.get(pane.worktreeId)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🤖 get_repo_knowledge executed:

get_repo_knowledge stablyai/orca /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4/learnings

Length of output: 24301


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- target context ---'
sed -n '1,230p' src/main/runtime/orca-runtime-write-orchestration-pointer-pty.ts
printf '%s\n' '--- related definitions and callers ---'
rg -n -C 4 'runtimeWorktreeIdsEqual|collectResumableSleptPanes|worktreesById|worktreePath|branch' src

Repository: stablyai/orca

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- target file outline ---'
wc -l src/main/runtime/orca-runtime-write-orchestration-pointer-pty.ts
sed -n '1,190p' src/main/runtime/orca-runtime-write-orchestration-pointer-pty.ts
printf '%s\n' '--- exact equality symbol locations ---'
rg -n -l 'runtimeWorktreeIdsEqual|collectResumableSleptPanes' src/main src/shared
printf '%s\n' '--- exact symbol context ---'
rg -n -C 8 'runtimeWorktreeIdsEqual|collectResumableSleptPanes' src/main/runtime src/shared

Repository: stablyai/orca

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- worktree identity implementation ---'
sed -n '1,125p' src/main/runtime/runtime-worktree-path-identity.ts
printf '%s\n' '--- resumable pane collector ---'
sed -n '1,220p' src/main/runtime/resumable-slept-pane-listing.ts
printf '%s\n' '--- summary caller and worktree map construction ---'
rg -n -C 6 'buildSleptPaneTerminalSummary|worktreesById' src/main/runtime/orca-runtime-write-orchestration-pointer-pty.ts src/main/runtime --glob '*.ts' | head -n 260

Repository: stablyai/orca

Length of output: 29901


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- shared worktree ID comparison ---'
sed -n '1,220p' src/shared/worktree/id.ts
printf '%s\n' '--- resolved worktree map implementation ---'
rg -n -C 10 'getResolvedWorktreeMap|getWorktreeMap' src/main/runtime --glob '*.ts' | head -n 220

Repository: stablyai/orca

Length of output: 25720


Use an identity-aware lookup for slept-pane worktree metadata.

collectResumableSleptPanes admits equivalent IDs with runtimeWorktreeIdsEqual, but line 148 performs an exact Map lookup. A non-identical equivalent ID can therefore produce empty worktreePath and branch values. Resolve the matching ResolvedWorktree with the same equality rule and add a regression test.

Comment thread src/main/runtime/orchestration/sleeping-pane-wake-target.ts Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ One rough edge worth a look, otherwise solid.

Reviewed changes

  • Slept panes become visible — an additive resumable field on RuntimeTerminalSummary makes terminal list (and the CLI) show auto-slept and quit-captured panes as asleep-but-resumable instead of absent, deliberately keeping connected: false for its execution-host meaning.
  • Addressing a slept agent succeeds — resolveBareOrchestrationRecipient resolves a slept pane through its resume record and returns an accepted, queued send with a recipient_asleep warning rather than the terminal_not_found a nonexistent handle gets.
  • Inbound mail wakes an auto-slept pane — delivery requests a wake at every no-process give-up point, gated on unread mail and routed run: → coordinator pane, dispatch: → assignee pane, bare handle → remembered pane; a SleepingPaneWakeScheduler paces and suppresses repeat wakes.
  • User-sleep protection — mayBackgroundWakeSleepingAgentSession fails closed on restoreOnTabOpenOnly / interrupted / automaticResumeBlockedBy, enforced on both the main-process mount path and the renderer in-place wake.
  • Dead wake listener fixed — the in-place wake listener now subscribes to the shared event constant (the colon-for-dash typo from 286c21005b0 had made it unreachable).
  • Sleep-eligibility guard — a pane supervising a still-dispatched/pending worker is no longer sleep-eligible.

The tests are real (exact-value assertions, ablation-proven), and the cross-cutting concerns — SSH host partitions, remote-wire additivity of resumable/recipient_asleep, kill-time self-wake — are all handled deliberately.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/runtime/runtime-terminal-list.ts Outdated
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — sleep/wake on real Codex + Claude CLIs

Isolated Electron on this PR worktree (window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-sleep-wake, CDP 9334, unique user-data). Hibernation on, idle 60s. Real agent processes, not mocks. Auto-sleep was idle hibernation (switched to a shell tab); tabs were not closed/reopened to fake it.

Lifecycle tested

Step Codex CLI Claude CLI
Working → done PINEAPPLE then TCP/UDP/BANANA; store working→done; session 01a06eaa-76e3-… MANGO; store working→done; session b398029c-…
Auto-slept connected:false, resumable:true, ptyId:null, origin worktree-sleep same + list title ◐ Claude Code
Empty mailbox stayed slept; no process return stayed slept until mail
Mail to slept handle ok:true + recipient_asleep (“queued and the pane will be woken”) same
Reawakened codex … resume 01a06eaa-76e3-… (same session); prior turns visible claude … --resume b398029c-…; MANGO still on screen
Consumed bare term_ wake mail stayed read=0 delivered_at=NULL after handle remint (known follow-up). After wake, dispatch --inject to the reminted live handle: injected:true, Codex replied KIWI in that same session same remint non-delivery on the wake mail
User-slept tab was foreground at shutdown so it remounted (restoreOnTabOpenOnly on the open tab) send warning: “slept deliberately and is never woken automatically”; 8s later still connected:false, resumable:true; no resume process

Visible states

Codex working/done (real TUI, prior turns used as resume proof):

02-codex-working.png

Claude working/done:

07-claude-working.png

Both auto-slept (shell tab foreground; agent tabs still in the strip, processes gone):

09-both-slept.png

Codex reawakened with prior PINEAPPLE/BANANA context (mail-wake, not tab-click):

10-codex-woken.png

Claude reawakened with prior MANGO context:

11-claude-woken.png

Woken Codex handled a later injected dispatch (KIWI):

13-codex-kiwi-consumed.png

User-slept Claude did not auto-wake after mail:

14-user-slept-claude-stays-asleep.png

Backing checks

  • terminal list: slept panes listed with resumable:true (no longer vanish).
  • Send to auto-slept handle: recipient_asleep wake promise; process back with --resume of the same provider session.
  • Send to user-slept handle: recipient_asleep never woken automatically.
  • No empty-mailbox self-wake. Wake spacing ~1.5s between Codex and Claude (no burst spawn). No duplicate QA-session processes.
  • Inbox: wake term_ messages remained undelivered after remint.

Gaps

  • Bare term_ mail wakes but stays unread after handle remint (already called out in the PR). dispatch: inject on the live reminted handle did deliver/handle.
  • “Working” screenshots often landed on done because turns were ~1s; store working was observed for both.
  • Isolated-instance status-bar overlay crashed at first paint (Maximum update depth exceeded on ports). Independent of sleep/wake; not bisected.
  • SSH/WSL/remote not exercised.

Verdict: pass, with the documented remint-delivery gap. Auto-sleep, listed-as-asleep, mail-wake with real --resume + prior context, empty-mailbox no self-wake, and user-slept Claude not auto-woken all held on live Codex and Claude CLIs.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes

Since the prior pullfrog review (148b09ac), commit 959116f hardens the slept-agent mail wake end to end:

  • Wake scheduler learns success/failure — SleepingPaneWakeScheduler.wake now returns a boolean; a failed wake is retried once, then parked in a failed set that markGraphReady drains via retryPending(). The 64-entry queue cap was dropped in favor of one queued wake per distinct slept pane, and per-pane suppression now self-prunes after its TTL instead of living forever.
  • mayBackgroundWakeSleepingPane made fail-closed — it now returns false when no sleeping record exists, closing the previous !record || … gap that treated a missing record as wakeable.
  • PTY ownership ambiguity guard — adoptFirstPtyForLeafHandle refuses to adopt a first PTY when the incoming graph names that PTY on two leaves, so a pending leaf handle never aliases an ambiguously owned process.
  • Remint-stable slept-pane dedup — RuntimeTerminalList keys sleeping records by leaf identity (stablePaneLeafKey) rather than the exact tabId:leafId string, resolving the double-list concern from the prior review.
  • Terminal-only slept mailbox refused — resolveBareOrchestrationRecipient now returns terminal_not_found + recipient_unreachable for a slept pane with no durable run:/dispatch: mailbox, instead of accepting it as recipient_asleep (which queued mail no resumed reader could consume).
  • Split-pane wake scoping — paneKey threads through terminal:requestTabMount and the in-place wake event, so a mail wake addresses one pane in a split tab rather than the whole tab.

Tests remain exact-value and ablation-proven, with new coverage for the retry/park lifecycle, graph-ready retry, ambiguous-PTY rejection, reminted-tab dedup, and the terminal-only refusal. The prior dedup thread is addressed by the stablePaneLeafKey change.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 7b1c77cd-6f3a-49fd-9f71-0ca2fb8a468b

📥 Commits

Reviewing files that changed from the base of the PR and between 148b09a and 959116f.

📒 Files selected for processing (25)
  • src/main/runtime/orca-runtime-bind-pty-incarnation-handle.ts
  • src/main/runtime/orca-runtime-stop-requested-pty-ids.ts
  • src/main/runtime/orca-runtime-sync-window-graph.ts
  • src/main/runtime/orca-runtime-wait-for-leaf-pty-id.ts
  • src/main/runtime/orca-runtime-write-orchestration-pointer-pty.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-scheduler.test.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-scheduler.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-target.test.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-target.ts
  • src/main/runtime/rpc/methods/orchestration-recipient-routing-slept.test.ts
  • src/main/runtime/rpc/methods/orchestration-recipient-routing.ts
  • src/main/runtime/runtime-terminal-list-slept-panes.test.ts
  • src/main/runtime/runtime-terminal-list.ts
  • src/main/runtime/slept-pane-mail-wake.test.ts
  • src/main/runtime/terminal-mobile-subscribe-tab-mount.test.ts
  • src/preload/api/ui-bridge-terminal-and-session-tabs.ts
  • src/preload/api/ui-command-event-api.ts
  • src/renderer/src/components/terminal-pane/pty-connection/pane-pty-binding.ts
  • src/renderer/src/components/terminal-pane/pty-connection/session-reconcile-dispose.ts
  • src/renderer/src/components/terminal-pane/wake-hibernated-agents-listener.test.ts
  • src/renderer/src/components/terminal-pane/wake-hibernated-agents-listener.ts
  • src/renderer/src/constants/terminal.ts
  • src/renderer/src/hooks/ipc-events/terminal-presentation-ipc-bridge.ts
  • src/renderer/src/lib/wake-sleeping-agents-in-background.test.ts
  • src/renderer/src/lib/wake-sleeping-agents-in-background.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/renderer/src/constants/terminal.ts
  • src/main/runtime/rpc/methods/orchestration-recipient-routing-slept.test.ts
  • src/main/runtime/orca-runtime-sync-window-graph.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-target.test.ts
  • src/main/runtime/orchestration/sleeping-pane-wake-target.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 2 remain after this review.

code: 'legacy_terminal_recipient',
recipient: handle,
message: `${handle} is a live terminal-only mailbox. Delivery is not durable after that terminal closes; prefer run:<id> or dispatch:<id>.`
}
}
}

if (sleptPane) {
const message = `${handle} is asleep but has no durable Run/Dispatch mailbox. Use a canonical run:<id> or dispatch:<id> address.`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localize the new unreachable-recipient message.

Line 121 adds a user-facing message directly in source. Move it to the localization catalog and pass handle through a named interpolation placeholder. Apply the same pattern to the new asleep-warning messages.

Based on learnings: new user-facing strings must use intent-named localization IDs with named interpolation placeholders.

Source: Learnings

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No critical issues — one minor suggestion inline.

Reviewed changes

Since the prior pullfrog review (959116f), commit fae2acc closes the remaining wake-recovery gaps:

  • Refuses inbound-message mounts while the graph is not ready — requestRendererTerminalTabMountForPane returns false when graphStatus !== 'ready', so a wake arriving during a renderer reload is reported as failure and parked for the markGraphReady → retryPending() redrive instead of being silently swallowed by webContents.send.
  • Remint-stable sleeping-record lookup — the renderer's getSleepingRecordForPane matches a sleeping record by stable leaf id across a reminted tab, resuming when one provider session is unambiguous and declining when sessions conflict.
  • Manual sleep marks retained durable records lazy — removeSleepingRecordsReplacedByManualWorktreeSleep now sets restoreOnTabOpenOnly: true on a retained done durable record, matching the lazy-restore semantics a freshly captured manual-sleep record already gets.

The new tests are exact-value and cover the reload race (wake parked, then redelivered after markGraphReady), the remint resume, and the conflict-decline case.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/runtime/orca-runtime-wait-for-leaf-pty-id.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes

Since the prior pullfrog review (fae2acc), commit 0013746 closes the last wake-recovery gap:

  • Redrives parked wakes on the reload-cancelled ready transition — retrySleepingPaneWakesWhenGraphReady was extracted from the markGraphReady override into a shared protected helper and is now also invoked from markRendererReloadCancelled, so a wake parked in failed during a reload that ends in cancellation (e.g. did-fail-provisional-load) is redriven instead of stranded until an unrelated message arrives.
  • New regression test — "redrives a parked wake when a renderer graph reload is cancelled" asserts the exact wake count after cancellation, and the existing reloading test now drives requestSleepingRecipientWake directly.

The prior review's single open thread is addressed. The test is exact-value and would fail without the base-class call; I confirmed the new test and the surrounding reload-cancel and wake-scheduler suites pass.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment)

Exact SHA 00137468ba5d59b587273155c2974e90065cf948. Isolated Electron from this worktree only (Playwright CDP, no computer-use). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-v2-sleep-wake, isDev=true, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9336, renderer 127.0.0.1:5178, unique user-data. Hibernation on. Real installed Codex CLI 0.152.1 and Claude Code 2.1.261, not mocks.

This comment supersedes the earlier QA at #18731 (comment). That run sent to bare term_ handles and used post-wake dispatch --inject. This run required durable run: ownership, unowned term_ rejection, and native --resume.

Method

  • Fresh profile + temp git fixture folder workspace. Seeded completed onboarding. No product/lockfile edits.
  • Spawned real Codex via product launchAgentInNewTab (YOLO). Claude product launch hit the folder-trust TUI and exited; relaunched with claude --dangerously-skip-permissions after adding only this fixture path to Claude trust (cleaned after).
  • Bound coordinator Runs while live: Codex run_76c352bcdcd7, Claude run_ef8a92a1c0a0.
  • Unowned LEMON Codex auto-slept on idle (origin=worktree-sleep, connected:false, resumable:true, ptyId:null).
  • Run-bound Codex/Claude did not idle-sleep after 60s / 15s while they owned a Run; hibernated through shutdownCompletedAgentPaneForHibernation (same capture/kill path as auto-hibernate).

Results

Assertion Codex Claude
Genuine working TUI Yes. Real Codex TUI, YOLO, counted 1–12, PINEAPPLE. Process later resumed as codex … resume 01a06ee4-3b93-7e32-a364-a6dcd7df3f15. Partial. Product launch died on trust TUI. After trust, pane titled Claude Code / agentIdentity=claude, session da10b8ce-e1c9-4341-844f-8b327b9492da. No durable Claude conversation was captured.
Completion Store done; PINEAPPLE visible. Store done with empty prompt (no completed turn).
Sleep, process gone, pane listed Unowned LEMON: idle auto-sleep, listed resumable:true. Run-bound Codex did not idle-sleep; hibernation API then native-resumed. Hibernation API: listed connected:false, resumable:true, ptyId:null, origin worktree-sleep.
Durable run: mail orchestration send --to run:run_76c352bcdcd7 --type status ok. to_handle=run:run_76c352bcdcd7. send --to run:run_ef8a92a1c0a0 --type status ok. Woke the slept pane (new PTY @@d80189a5).
Native resume + prior context Yes. codex --dangerously-bypass-approvals-and-sandbox resume 01a06ee4-3b93-7e32-a364-a6dcd7df3f15. PINEAPPLE still on screen. Wake launched claude … --resume da10b8ce-…. CLI: No conversation found with session ID: da10b8ce-e1c9-4341-844f-8b327b9492da.
Queued mail consumed/acted in resumed session Mail accepted and queued. Agents did not reply KIWI. delivered_at stayed NULL. (A later CLI check marked read=1; that was the QA CLI, not the agent.) Same. Resume failed, so no agent to consume.

Unowned slept bare term_ rejected (required):

ok: false
code: terminal_not_found
message: term_a6fd75d9-302b-442d-9d69-3af98cfdcc04 is asleep but has no durable Run/Dispatch mailbox. Use a canonical run:<id> or dispatch:<id> address.

Same rejection for the pre-remint handle term_6fa08641-….

Visible states

Codex working/done (real TUI, PINEAPPLE):

02-codex-working.png

Slept panes still in the tab strip (shell foreground; LEMON + Claude slept):

11-both-slept.png

Claude reawakened by run: mail; native --resume of captured session id failed:

12-claude-woken.png

Codex reawakened with prior PINEAPPLE context (provider-native resume of the same session):

13-codex-woken.png

Honest gaps

  • Claude never completed a real turn (trust TUI on first launches; captured session id was not a Claude conversation). Native --resume was attempted and failed as shown.
  • Run-bound coordinators did not idle-sleep; only the unowned LEMON Codex did. Hibernation API was used for the run-bound pair.
  • Queued run: status mail woke Claude and was durable, but neither agent acted on KIWI. Idle-push of orca orchestration check into the TUI was not observed.
  • Isolated-instance status-bar overlay still crashes at first paint (Maximum update depth exceeded / PortsStatusSegment). Independent of sleep/wake; same as prior QA.
  • SSH / WSL / remote not exercised. dispatch: ownership not separately exercised (run: was).

Verdict: partial pass. Unowned slept term_ rejection, run: send to a slept coordinator, listed-as-resumable, and Codex provider-native resume with preserved PINEAPPLE are proven on this SHA. Claude same-session resume and in-session consumption of queued mail are not proven.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment) and #18731 (comment)

Exact SHA 00137468ba5d59b587273155c2974e90065cf948. Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-v3-sleep-wake, isDev=true, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9337, renderer 127.0.0.1:5179, unique user-data. Hibernation on, idle 60000ms (valid minimum). Real installed Codex CLI 0.152.1 and Claude Code 2.1.261, not mocks.

This comment supersedes both:

Method

  • Fresh profile + temp git fixture folder workspace. Seeded completed onboarding. No product/lockfile edits.
  • Product launchAgentInNewTab with YOLO defaults. Claude trusted only this fixture path (cleaned after).
  • Bound durable Runs while live: Codex run_36e14736b598, Claude run_962d9bc60116.
  • Switched to a shell tab (agents not foreground). Automatic idle hibernation (coordinator tick, not the hibernation API): both panes connected:false, resumable:true, ptyId:null, origin worktree-sleep. Recorded PIDs gone.
  • While slept, orchestration send --to run:… --type status accepted (delivered_at null at accept). Then native --resume of the same provider sessions.

Results

Assertion Codex Claude
Genuine working TUI Yes. Real Codex TUI, YOLO, PINEAPPLE. Session 01a06ef8-7d5b-75d1-9adf-67066fdaf243. Yes. Real Claude Code 2.1.261, bypass permissions, MANGO. Session e0b56441-556c-417e-b43e-0f4e76f4d43a with a real ~/.claude/projects/…jsonl conversation (this was the v2 miss).
Completion Store done. Store done with completed turn.
Automatic idle sleep, process gone, pane listed Yes. connected:false, resumable:true, ptyId:null, origin worktree-sleep. PIDs 23788/23790 gone. Yes. Same + list title ◐ Claude Code. PID 35591 gone.
Durable run: mail while slept send --to run:run_36e14736b598 ok. msg_441927fc63fb, delivered_at null at accept. send --to run:run_962d9bc60116 ok. msg_ee466122f06b.
Native resume + prior context Yes. codex --dangerously-bypass-approvals-and-sandbox resume 01a06ef8-7d5b-75d1-9adf-67066fdaf243. PINEAPPLE still on screen. Yes. claude --dangerously-skip-permissions --resume e0b56441-556c-417e-b43e-0f4e76f4d43a. --- session restored ---, MANGO still on screen. No No conversation found.
Queued mail consumed/acted in resumed session Not proven. Idle-push of orca orchestration check never appeared. msg_441927fc63fb stayed read=0 delivered_at=NULL. After resume Codex published no agent-status (lastAgentStatusObservedLive never set), so the live-idle gate did not inject the pointer. Did not CLI-check that mailbox. Yes. Pointer You have 1 orchestration message. Run orca orchestration check --run run_962d9bc60116. Claude ran the check (delivery_62dac27096b6 / msg_ee466122f06b) and replied KIWI in the same resumed session.

Visible states

Codex working/done (real TUI, PINEAPPLE):

02-codex-working.png

Claude working/done (real TUI, MANGO):

03-claude-working.png

Automatic idle sleep (shell foreground; agent tabs still listed; processes gone):

05-both-slept.png

Claude reawakened by run: mail; native --resume of e0b56441-…; prior MANGO visible; queued mail consumed; replied KIWI:

06-claude-woken.png

Codex reawakened with prior PINEAPPLE (provider-native resume of the same session). Queued KIWI mail not consumed:

07-codex-woken.png

Honest remaining gap

  • Codex queued-mail consumption after resume is still missing. Mail was accepted to run:run_36e14736b598 while slept and the pane native-resumed the same session, but idle-push never typed orca orchestration check into the Codex TUI. After resume the Codex pane had no agentStatusByPaneKey row (Claude did: state=done). Bounded wait (~6 min) did not change that. This is the only required proof still open from 5548002377.
  • Isolated-instance status-bar overlay still crashes at first paint (React render error in overlay / The status bar hit an error). Independent of sleep/wake; same as prior QA.
  • SSH / WSL / remote not exercised. dispatch: ownership not separately exercised (run: was).

Verdict: Claude same-session resume + queued-mail consumption is now proven on this SHA. Codex native resume + prior context is proven. Codex in-session consumption of queued run: mail is not. Not a full pass.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found in the incremental change.

Reviewed changes

Since the prior pullfrog review (0013746), one commit landed:

  • Memoizes the status-bar runtime-target selector — useWorktreeRuntimeTarget now selects the stable executionHostId primitive and derives the RuntimeClientTarget object via useMemo, instead of returning a fresh object from the zustand selector on every render (which drove useSyncExternalStore into a Maximum update depth exceeded loop).
  • Adds a render-stability regression test — PortsStatusSegment.render-stability.test.tsx renders the segment under its real RecoverableRenderErrorBoundary and asserts no render-loop crash was logged. It passes now and would fail with the pre-fix selector; confirmed passing locally.

ℹ️ This commit duplicates a fix already on main

The entire delta is byte-for-byte identical to 5412276776 (Fix status bar runtime target render loop (#18685), merged to main independently by another author). git diff main..HEAD over both files is empty, so the merge will be clean — but the branch's merge-base (79d5fb4) predates that commit, making 990e8bd a redundant cherry-pick on a branch that is 70 commits behind main. Rebasing onto current main would drop 990e8bd and leave the PR carrying only its sleep/wake work; as-is it is harmless.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The statusless Codex delivery path has no reliable post-wake trigger, so a single worker_done to a Codex coordinator can still strand — the silent deadlock this PR set out to fix.

Reviewed changes

  • Proved a statusless Codex pane idle before delivering — deliverForHandle now routes a run: mailbox whose leaf has a PTY but no observed agent status through a new OrchestrationMailboxStatuslessCodexProofCoordinator, which drives proveStatuslessCodexIdle (a tui-idle wait bounded by the 5-minute default timeout, validated against the process incarnation before and after) and only then stages the pointer.
  • Threaded the idle proof through stage and submit — statuslessIdleProof flows through stageOrchestrationMailboxPointer and submitOrchestrationMailboxPointer, re-validated against the current leaf and process incarnation at each step so a status that turns live or a recycled PTY aborts the injection.
  • Extracted the shared candidate query — getOrchestrationMailboxPointerCandidates now lives in its own module, used by both the pre-proof gate and deliver.

⚠️ Statusless Codex wake has no reliable delivery trigger

The proof only runs when deliverForHandle is called, but after a mail-driven wake of a statusless Codex pane nothing re-invokes it. The three automatic delivery triggers — the graph sync (orca-runtime-sync-window-graph.ts:307-319), the OSC-title transition (orca-runtime-apply-tracked-pty-title.ts:116-118), and the prompt-submission restore (orca-runtime-serialize-agent-prompt-submission.ts:104-106) — are all gated on lastAgentStatus === 'idle' && lastAgentStatusObservedLive, which a statusless Codex never emits. The only remaining trigger is the one-shot 2-second MailPointerRepointScheduler repoint scheduled at message-arrival time; it fires mid cold-restore (wake mount settle is 10s) and hits proveStatuslessCodexIdle's fail-fast (the leaf is not yet connected/writable), with no retry. A single worker_done to a Codex coordinator therefore strands until a second message or an explicit check — the same deadlock, narrowed to a timing window. The new test (slept-pane-mail-wake.test.ts:343-396) only passes because it manually calls deliverPendingMessagesForHandle('run:run_test'), whereas the status-reporting case auto-delivers off the idle title edge.

Technical details
# Statusless Codex delivery needs a reliable post-wake trigger

## Affected sites
- src/main/runtime/orchestration/mailbox-pointer-delivery.ts:89 — `statuslessCodexProofs.runWhenProven(...)` is the only entry to the proof; it runs solely inside `deliverForHandle`.
- src/main/runtime/orca-runtime-sync-window-graph.ts:307-319 — the graph-sync delivery trigger, gated on `idle && observedLive` (never set for statusless Codex).
- src/main/runtime/orca-runtime-apply-tracked-pty-title.ts:116-118 — title-idle delivery trigger, unreachable for statusless Codex.
- src/main/runtime/orchestration/mail-pointer-repoint-scheduler.ts:8-21 — one-shot 2s repoint, fires before the ~7s Codex cold-restore completes.

## Required outcome
- After a statusless Codex pane is woken by inbound `run:` mail and becomes writable, mailbox pointer delivery must be attempted without depending on a new message arriving.

## Suggested approach (optional)
- Re-schedule the `mailPointerRepointScheduler` repoint (or an equivalent redrive) when the woken pane's graph sync marks it writable/connected while unread `run:` mail remains, or make `proveStatuslessCodexIdle` wait on pane readiness rather than failing fast when not yet `connected`/`writable`.

## Open questions for the human (optional)
- Is a 2s repoint + `tui-idle` wait intended to cover in-place (still-mounted) wakes only, with full-remount Codex wakes acknowledged as deferred until the next message? If so, that limitation should be documented rather than left implicit.

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment), #18731 (comment), and #18731 (comment)

Exact SHA a793f51f3f5e7a87b504f1e867fe0ef6d8be2b30 (fix(orchestration): deliver mail after Codex wake). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-v4-sleep-wake, isDev=true, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9338, renderer 127.0.0.1:5177, unique user-data. Hibernation on, idle 60000ms (valid minimum). Real installed Codex CLI 0.153.4 and Claude Code 2.1.261. Fixture was a non-git folder workspace.

This comment supersedes:

Method

  • Fresh profile + temp folder workspace (not a git repo). Dev onboarding suppressed. No product/lockfile edits.
  • Product launchAgentInNewTab with YOLO defaults. Claude trusted only this fixture path (cleaned after).
  • Distinctive working prompts: Codex STARFRUIT, Claude HONEYDEW.
  • Bound durable Runs while live: Codex run_adf510f2da8f, Claude run_73b987070ac7.
  • Switched to a shell tab (agents not foreground). Automatic idle hibernation via coordinator tick (not hibernation API / tab close): both panes connected:false, resumable:true, ptyId:null, origin worktree-sleep. Recorded PIDs gone.
  • While slept, orchestration send --to run:… --type status accepted (delivered_at null at accept). Did not QA-CLI-check the agent mailboxes or post-wake dispatch --inject.

Results

Assertion Codex Claude
Genuine working TUI Yes. Real Codex TUI 0.153.4, YOLO, STARFRUIT. Session 01a06f74-6473-7301-951d-0dfb4a0b0aa6. PIDs 78853/78865. Yes. Real Claude Code 2.1.261, bypass permissions, HONEYDEW. Session 2182d49d-a38f-427e-8cc6-d537dfeca052 with a real ~/.claude/projects/…jsonl. PID 84642.
Completion Store done. Store done with completed turn.
Automatic idle sleep, process gone, pane listed Yes. Shell tab foreground. connected:false, resumable:true, ptyId:null, origin worktree-sleep, listed as Codex ready. PIDs 78853/78865 gone. Handle reminted term_0bbfa032-6535-40c6-ba56-de321057483f. Yes. Same + list title ◐ HONEYDEW token reply. PID 84642 gone. Handle reminted term_a1e33cf5-12bf-48d5-9366-4ce084a83ac1.
Durable run: mail while slept send --to run:run_adf510f2da8f ok. msg_310b2b3359fd, delivered_at null at accept. Token requested: NIGHTJAR. send --to run:run_73b987070ac7 ok. msg_b26c05d5ef14, delivered_at null at accept. Token requested: QUINCE.
Native resume + prior context Yes. codex --dangerously-bypass-approvals-and-sandbox resume 01a06f74-6473-7301-951d-0dfb4a0b0aa6 (PIDs 10665/10666). STARFRUIT still on screen. Yes. claude --dangerously-skip-permissions --resume 2182d49d-a38f-427e-8cc6-d537dfeca052 (PID 10862). --- session restored ---, HONEYDEW still on screen. No No conversation found.
Queued mail consumed/acted; token reply in resumed session Not proven. Idle-push of orca orchestration check never appeared. msg_310b2b3359fd stayed read=0 delivered_at=NULL for a bounded ~6 min after native resume. After resume Codex published no agentStatusByPaneKey row (lastAgentStatusObservedLive never set). Did not CLI-check that mailbox. Partial. Pointer You have 1 orchestration message. Run orca orchestration check --run run_73b987070ac7 was idle-pushed. Claude itself ran the check (delivery_6afddefcadb9 / msg_b26c05d5ef14 acknowledged, read=1). It did not reply QUINCE: it treated --type status as “needed no action / expect no reply” and stopped.

Visible states

Codex working/done (real TUI, STARFRUIT):

02-codex-working.png

Claude working/done (real TUI, HONEYDEW):

03-claude-working.png

Automatic idle sleep (shell foreground; agent tabs still listed; processes gone):

05-both-slept.png

Claude reawakened by run: mail; native --resume of 2182d49d-…; prior HONEYDEW visible; idle-push pointer; Claude ran orchestration check and consumed msg_b26c05d5ef14. Token QUINCE was not emitted:

06-claude-woken.png

Codex reawakened with prior STARFRUIT (provider-native resume of the same session). Queued NIGHTJAR mail not consumed; no orchestration check pointer:

07-codex-woken.png

IDs / PID evidence

  • Codex session 01a06f74-6473-7301-951d-0dfb4a0b0aa6, run run_adf510f2da8f, live handle term_a8f5be17-2def-4587-8418-abe329727103, pane 8d600982-1b0b-43b6-8572-a0db457c0b3d:c44950cc-2908-49ef-a3bb-7f4db790a2d6. Live PIDs 78853 (node wrapper) / 78865 (codex binary) gone after sleep; resume PIDs 10665/10666 codex … resume 01a06f74-….
  • Claude session 2182d49d-a38f-427e-8cc6-d537dfeca052, run run_73b987070ac7, live handle term_ea94b2e5-28af-4a73-9dd7-4ac1fb5204da, pane 5dc4efd4-00ae-49ed-99dc-e4f52b5655e9:5f7b264c-87be-4e07-a730-5a3783f307ed. Live PID 84642 gone after sleep; resume PID 10862 claude … --resume 2182d49d-….
  • Mail: Codex msg_310b2b3359fd (unread); Claude msg_b26c05d5ef14 / delivery_6afddefcadb9 (acknowledged).

Honest remaining gaps

  • Codex queued-mail consumption after resume is still missing on this SHA. Native --resume of the same session and prior STARFRUIT are proven. The statusless Codex idle-push path (proveStatuslessCodexIdle / tui-idle) never typed orca orchestration check into the resumed TUI. Mail stayed unread. This is the same open proof as 5548152366, now re-checked against a793f51f3f5 (“deliver mail after Codex wake”). Bounded wait ~6 min after native resume, Codex tab foreground for the latter half. Did not CLI-check or --inject.
  • Claude token reply is missing even though consume is proven. Idle-push + in-session orchestration check + ack of the asleep-queued run: mail are proven. Claude then decided a --type status message “needed no action” and did not emit QUINCE. This is agent interpretation of status mail, not a failed wake/resume. Previous QA on 00137468 did get a KIWI reply from the same --type status shape.
  • First Claude launch hit host PTY exhaustion (kern.tty.ptmx_max=511, ~525 /dev/ttys*; DaemonProtocolError: cannot allocate any more pty devices). Recovered by closing an extra shell tab in this instance only; second Claude launch succeeded. Unrelated host contention; no other processes were killed.
  • SSH / WSL / remote not exercised. dispatch: ownership not separately exercised (run: was).

Verdict: not a full pass. Claude same-session resume + idle-push + self-check + consume is proven. Claude requested-token reply is not. Codex native resume + prior context is proven. Codex in-session consumption of queued run: mail is not — the SHA’s stated Codex-after-wake delivery fix is not evidenced on this live run.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes

Since the prior pullfrog review (a793f51), commit 31aeb74 closes the statusless-Codex delivery gap that review flagged as must-address:

  • Graph-sync delivery trigger for statusless Codex — syncWindowGraph now redrives deliverPendingMessagesForHandle when a leaf whose agent is Codex and has never emitted a status transitions to writable (becameWritable && lastAgentStatus === null && !observedLive). This is exactly the reliable post-wake trigger the prior finding asked for: it fires on the ptyId transition for both in-place and full-remount wakes, independent of a second message arriving.
  • Regression test drives the real trigger — delivers queued run mail after a statusless Codex provider reattach now spies on deliverPendingMessagesForHandle and asserts the graph sync invokes it after a simulated Codex reattach, then still asserts the full end-to-end write and delivered_at; it no longer calls delivery by hand.
  • becameWritable extraction — the shared writable-transition predicate is hoisted into a variable and reused by both the status-reporting branch and the new Codex branch.

I confirmed the delivery guard (deliver still re-checks leaf.writable/leaf.ptyId at mailbox-pointer-delivery.ts:160), so the slight relaxation of the status-reporting if condition (the previousLeaf.status terms no longer require leaf.writable) is a no-op in practice — non-writable leaves short-circuit before any write. Both the slept-pane and statusless delivery suites pass (20 tests).

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) v5 — supersedes #18731 (comment), #18731 (comment), #18731 (comment), and #18731 (comment)

Exact SHA a793f51f3f5e7a87b504f1e867fe0ef6d8be2b30. Isolated Electron from this worktree (Playwright CDP only, no computer-use / mocks). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-v5-sleep-wake. CDP 127.0.0.1:9339, renderer 127.0.0.1:5178, unique user-data. Hibernation on, idle 60000ms. Real Codex CLI 0.153.4, Claude Code 2.1.261. Temp git fixture. v3 methodology reused (YOLO launchAgentInNewTab, bind run: while live, shell-tab foreground, coordinator-tick sleep, send --to run: --type status, no QA-CLI check / --inject).

Results

Assertion Codex Claude
Genuine working TUI Yes. YOLO, WATERMELON. Session 01a06f85-0816-7192-888a-edd914fec0f6. PIDs 74030/74111. Yes. Bypass permissions, PAPAYA. Session 73eb1025-22e2-4623-9e20-c5e32de38dc4. PID 74152.
Completion Store done. Store done.
Automatic idle sleep, process gone, pane listed Yes. Shell foreground. connected:false, resumable:true, ptyId:null, title Codex ready, origin worktree-sleep. PIDs 74030/74111 gone. Handle reminted term_30740666-6787-40dd-ad2f-791d5acf0a0f. Not observed before mail. Stayed connected:true with PID 74152 for ~12 min after done + shell foreground. Did not list asleep(resumable) before send.
Durable run: mail while target slept send --from QA-shell --to run:run_b6c02e9cb882 ok while slept. msg_0a0ee39a70b4, delivered_at null at accept. Token BLUEBIRD. Mail accepted msg_56f9b2d4acf9 → run_0703ac4a141a, but Claude was still live at send. Token FIREFLY.
Native resume + prior context Yes. codex --dangerously-bypass-approvals-and-sandbox resume 01a06f85-0816-7192-888a-edd914fec0f6 (PIDs 77133/77140). --- session restored ---, WATERMELON on screen. Yes, later. claude --dangerously-skip-permissions --resume 73eb1025-22e2-4623-9e20-c5e32de38dc4. --- session restored ---, PAPAYA on screen. This remount was after mail, not proven as auto-sleep-then-mail-wake.
Queued mail consumed in resumed session Not proven. No idle-push orca orchestration check. msg_0a0ee39a70b4 stayed read=0 delivered_at=NULL for a bounded ~6 min after native resume. Partial / live. Pointer + orchestration check --run run_0703ac4a141a ran; delivery delivery_7339956fe6d3 / msg_56f9b2d4acf9 visible. Claude saw FIREFLY and treated --type status as “nothing to act on” (did not emit FIREFLY as a reply).

Visible states

Codex working/done (WATERMELON):

02-codex-working.png

Claude working/done (PAPAYA):

03-claude-working.png

Shell foreground after Codex auto-sleep (Claude tab still listed live at this frame):

05-both-slept.png

Claude native --resume of 73eb1025-…; PAPAYA visible; idle-push check of FIREFLY mail; no FIREFLY reply:

06-claude-woken.png

Codex native --resume of 01a06f85-…; WATERMELON visible; no orchestration check / BLUEBIRD:

07-codex-woken.png

Honest blockers vs acceptance bar

  • Both-agent automatic sleep was not met. Codex auto-slept (process gone, listed resumable). Claude did not auto-sleep before mail despite state=done, hibernation on, 60s idle, and shell tab foreground.
  • Codex queued run: mail consumption after wake is still missing on this SHA (same gap as 5548152366 / 5548899765). Native resume + prior context are proven.
  • Claude check/consume is visible, but not as mail-wake-from-sleep, and it refused to output FIREFLY because the message type was status.

Verdict: not a full pass. No product files changed.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment)

Exact SHA 31aeb74aa087467f660eab0a1ee2cad1e44496c4 (fix(orchestration): redrive mail on Codex reattach). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks / store-only substitutes). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-v6-sleep-wake, isDev=true, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9335, renderer 127.0.0.1:5176, unique user-data. Hibernation on, idle 60000ms (valid minimum). Real installed Codex CLI 0.153.4 and Claude Code 2.1.261. Fixture was a non-git folder workspace.

This comment supersedes #18731 (comment).

This run specifically checked the SHA's Codex writable-PTY redrive: mail was queued while slept, wake/remount were left to the product, and deliverPendingMessagesForHandle was not invoked from QA.

Method

  • Fresh profile + temp folder workspace (not a git repo). Dev onboarding suppressed. No product/lockfile edits.
  • Product launchAgentInNewTab with YOLO defaults. Claude trusted only this fixture path (cleaned after).
  • Distinctive working prompts: Codex POMEGRANATE, Claude LYCHEE.
  • Bound durable Runs while live: Codex run_4bb7df4990e5, Claude run_2651dd2f9088.
  • Switched to a shell tab (agents not foreground). Automatic idle hibernation via coordinator tick (not hibernation API / tab close): both panes connected:false, resumable:true, ptyId:null, origin worktree-sleep. Recorded PIDs gone.
  • While slept, orchestration send --to run:… --type dispatch with an unambiguous "emit this exact token" instruction. Accepted with delivered_at null. Did not QA-CLI-check either agent mailbox or post-wake dispatch --inject.

Results

Assertion Codex Claude
Genuine working TUI Yes. Real Codex TUI 0.153.4, YOLO, POMEGRANATE. Session 01a06f97-b137-7d22-9363-f63c0ecc6621. Live PIDs 16235 (node wrapper) / 16287 (codex binary), tty ttys233. Yes. Real Claude Code 2.1.261, bypass permissions, LYCHEE. Session 33ffb7b1-4ea1-44aa-ac01-ed1a46cacf03 with a real ~/.claude/projects/…jsonl. PID 16322, tty ttys284.
Completion Store done, last assistant POMEGRANATE. Store done with completed turn, last assistant LYCHEE.
Automatic idle sleep, process gone, pane listed Yes. Shell tab foreground. connected:false, resumable:true, ptyId:null, origin worktree-sleep, listed as Codex ready. PIDs 16235/16287 gone. Handle reminted term_e49810a3-318e-435e-a071-a3615dca354f. Yes. Same + list title ◐ Claude Code. PID 16322 gone. Handle reminted term_e50ad674-c034-45a5-9c40-f8e126736874.
Durable run: mail while slept send --to run:run_4bb7df4990e5 --type dispatch ok. msg_45f4a4715c7a, delivered_at null at accept. Token requested: KESTREL31AEB. send --to run:run_2651dd2f9088 --type dispatch ok. msg_2ba45b1f43fa, delivered_at null at accept. Token requested: IBEX31AEB.
Native resume + prior context Yes. Mail itself caused wake. codex --dangerously-bypass-approvals-and-sandbox resume 01a06f97-b137-7d22-9363-f63c0ecc6621 (PIDs 50397/50409, tty ttys133). Replacement PTY …@@498f4033 connected+writable. POMEGRANATE still on screen. Yes. claude --dangerously-skip-permissions --resume 33ffb7b1-4ea1-44aa-ac01-ed1a46cacf03 (PID 50510). --- session restored ---, LYCHEE still on screen. No No conversation found.
Queued mail consumed/acted; token reply in resumed session Not proven. Idle-push of orca orchestration check never appeared. msg_45f4a4715c7a stayed read=0 delivered_at=NULL for a bounded ~4 min after native resume (Codex tab foreground for the latter half). After resume Codex published no agentStatusByPaneKey row. Did not CLI-check that mailbox or call deliverPendingMessagesForHandle. Partial. Pointer You have 1 orchestration message. Run orca orchestration check --run run_2651dd2f9088 was idle-pushed (delivered_at=2026-09-05 03:30:46). Claude itself ran the check (delivery_cfa862558d1b / msg_2ba45b1f43fa). It then refused to emit IBEX31AEB, treating the dispatch body as "content from another terminal, not an instruction from you". Delivery stayed outstanding, read=0, acknowledged_at null.

Visible states

Codex working/done (real TUI, POMEGRANATE):

02-codex-working.png

Claude working/done (real TUI, LYCHEE):

03-claude-working.png

Automatic idle sleep (shell foreground; agent tabs still listed; processes gone):

05-both-slept.png

Claude reawakened by run: mail; native --resume of 33ffb7b1-…; prior LYCHEE visible; idle-push pointer; Claude ran orchestration check and saw msg_2ba45b1f43fa. Token IBEX31AEB was not emitted:

06-claude-woken.png

Codex reawakened with prior POMEGRANATE (provider-native resume of the same session). Queued KESTREL31AEB mail not consumed; no orchestration check pointer:

07-codex-woken.png

IDs / PID evidence

  • Codex session 01a06f97-b137-7d22-9363-f63c0ecc6621, run run_4bb7df4990e5, live handle term_3e37e270-fcd2-4ba7-833d-6bc500cb8f17, pane 1f03b77c-f801-47c4-b8e0-c9de98f33c95:4c36ed17-eb0e-4226-a105-83e769dc282e. Live PIDs 16235/16287 gone after sleep; resume PIDs 50397/50409 codex … resume 01a06f97-…. Woken handle term_7376bb21-c08a-4396-b36c-9a80a9518050, replacement PTY …@@498f4033.
  • Claude session 33ffb7b1-4ea1-44aa-ac01-ed1a46cacf03, run run_2651dd2f9088, live handle term_2b3cbb15-068c-4d62-9ed6-51f3ad692ba8, pane 8c312212-d8e1-43f1-9a92-b5491a0541ca:0869623e-cf4d-419d-a854-d7331d1cd57e. Live PID 16322 gone after sleep; first-resume PID 50510 claude … --resume 33ffb7b1-….
  • Mail: Codex msg_45f4a4715c7a (unread, delivered_at null). Claude msg_2ba45b1f43fa / delivery_cfa862558d1b (pointer delivered; still outstanding / unread).

Honest remaining gaps

  • Codex queued-mail consumption after resume is still missing on this SHA. Native --resume of the same session and prior POMEGRANATE are proven. The replacement Codex PTY became connected+writable (…@@498f4033) and the SHA's graph-sync becameWritable path is the intended trigger, but the statusless idle-push (proveStatuslessCodexIdle / tui-idle) never typed orca orchestration check into the resumed TUI. Mail stayed unread. Same open proof as 5548899765, now re-checked against 31aeb74 without artificially invoking deliverPendingMessagesForHandle. Bounded wait ~4 min after native resume; Codex tab foreground for the latter half. Did not CLI-check or --inject.
  • Claude token reply is missing even though idle-push + self-check are proven. --type dispatch with an unambiguous "MUST emit IBEX31AEB" instruction. Claude ran orchestration check, quoted delivery_cfa862558d1b / msg_2ba45b1f43fa, then refused to act because the body came "from another terminal". Delivery remained outstanding (read=0). This is agent interpretation, not a failed wake/resume.
  • After Claude finished that refusal, it auto-slept again (Codex tab was foreground) and later remounted on a newer PTY (…@@e6e427a3, PID 66583, same --resume 33ffb7b1-…). The consume screenshot above is from the first resumed session, before that second sleep.
  • SSH / WSL / remote not exercised. dispatch: ownership not separately exercised (run: was).

Verdict: not a full pass. Claude same-session resume + idle-push + self-check of asleep-queued run: dispatch mail is proven. Requested-token reply is not. Codex native resume + prior context + mail-caused wake is proven. Codex in-session consumption of queued run: mail is not — the SHA's writable-PTY redrive did not produce a live idle-push on this run.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No critical issues — one minor suggestion inline.

Reviewed changes

Since the prior pullfrog review (31aeb74), commit 2122edbc closes the remaining ordering gap in the statusless-Codex wake-delivery trigger:

  • Redrives delivery when the Codex reattach identity lands — registerPty now calls deliverPendingMessagesForHandle when a PTY's launchAgent transitions to codex while its leaf is already writable and statusless. This covers the ordering where the renderer publishes the writable graph before main receives the provider-owned reattach identity — the case the 31aeb74 becameWritable trigger (gated on launchAgent === 'codex') could not reach, since launchAgent is still null at graph-sync time.
  • Regression test reproduces the production ordering — remountStatuslessCodex now syncs the graph before registerPty and asserts the delivery handle, so the test fails if the registerPty redrive is removed.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/runtime/slept-pane-mail-wake.test.ts Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta — the browser-safety extraction is correct, minimal, and guarded by a real regression test. Not an approval: three minor test-coverage threads from earlier reviews remain open.

Reviewed changes

Since the prior pullfrog review (b27c54b), one commit landed:

  • Moved the process-table staleness constant into a browser-safe module — PROCESS_TABLE_SNAPSHOT_MAX_STALENESS_MS now lives in src/shared/process-table-snapshot-timing.ts, a pure module with no Node imports. agent-completion-poll-interval.ts (a renderer module consumed by agent-completion-poll-scheduler.ts) previously imported it from process-table-snapshot-reader.ts, which transitively pulls node:child_process/node:util/node:fs/promises and breaks the renderer's platform: browser bundle.
  • Preserved the value and public surface — process-table-snapshot-reader.ts still re-exports the constant and sets DEFAULT_SNAPSHOT_TTL_MS = PROCESS_TABLE_SNAPSHOT_MAX_STALENESS_MS, so the 500 ms TTL is unchanged for existing importers; the cadence benchmark script follows the same import.
  • Added a browser-only bundle regression test — agent-completion-poll-interval.test.ts builds the entry point with esbuild under platform: browser and asserts errors: []. I ablated it: bundling the reader under platform: browser fails with three Could not resolve "node:…" errors, so the test genuinely guards against the Node-only import creeping back.

The three open minor threads (missing becameWritable coverage, the malformed PTY-root mock, the untested output-triggered redrive) sit in files this commit does not touch and remain open.

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta — the origin/main merge is clean and subsumes the browser-safe extraction from the prior commit with main's stricter fix. Not an approval: three minor test-coverage threads from earlier reviews remain open.

Reviewed changes

Since the prior pullfrog review (c939764), one merge landed:

  • Merged origin/main, which independently fixed the same blank-window bug (#18742) — main's version moves PROCESS_TABLE_SNAPSHOT_MAX_STALENESS_MS into the pure process-table-snapshot.ts module and adds a graph-walking ratchet, renderer-node-builtin-boundary.test.ts, that walks every renderer production entry (lazy routes included) and refuses any node: builtin. The branch's process-table-snapshot-timing.ts module and esbuild bundle test are therefore dropped from the PR delta, superseded by main's broader guard.
  • Resolved the two conflicts correctly — agent-completion-poll-interval.ts now imports the constant from the pure process-table-snapshot module (with an explanatory comment), process-table-snapshot-reader.ts re-exports it, and the 500 ms TTL is unchanged. The boundary ratchet and poll-interval suites pass, and pnpm tc:web is clean.

The three open minor threads (missing becameWritable coverage, the malformed PTY-root mock, the untested output-triggered redrive) sit in files this merge does not touch and remain open.

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes earlier QA comments on this PR

Exact SHA 5db91a4e6231bcf5fa8bdbdfd000a589a656d668 (Merge remote-tracking branch 'origin/main' into brennanb2025/impl-agent-sleep-wake). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks / store-only substitutes / post-wake typing / dispatch --inject / deliverPendingMessagesForHandle). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-5db91a4e, isDev=true, devBranch=brennanb2025/impl-agent-sleep-wake, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9338, renderer 127.0.0.1:5176, unique user-data /tmp/orca-qa-18731-5db91a4e/profile. Hibernation on, idle 60000ms. Real installed Claude Code 2.1.261 (/Users/brennanbenson/.local/bin/claude → …/claude/versions/2.1.261) and Codex CLI 0.153.4 (/opt/homebrew/bin/codex → @openai/codex; also /Users/brennanbenson/.local/bin/codex). Fixture was a non-git folder workspace (/tmp/orca-qa-18731-5db91a4e/fixture). Sequential: Claude first, then Codex.

This comment supersedes earlier QA comments on #18731, including the blank-renderer FAIL on b27c54b (#18731 (comment)) and the Codex-pointer FAIL on f529dee (#18731 (comment)). No product files were edited, committed, or pushed. Screenshots are artifacts only.

The previous SHA's renderer-blank (node:fs/promises in client graph) is fixed on this SHA: #root mounts, settings hydrate, folder workspace adds.

Method

  • Fresh profile, completed onboarding seeded, temp folder workspace (not a git repo).
  • Product launchAgentInNewTab (New tab path) with YOLO defaults (claude --dangerously-skip-permissions, codex --dangerously-bypass-approvals-and-sandbox). Codex submit-after-ready prompt delivery failed (nativeChatLaunchPrompt.failed=true); phase-one prompt was then delivered with product orca terminal send --enter before sleep (allowed). No post-wake typing.
  • Ordinary provider terminals with no Dispatch. Phase-one prompts pre-authorized later session-restored orchestration pointers.
  • Tokens: Claude LEMON5DB9 / FINCH5DB9. Codex MANGO5DB9 / HERON5DB9.
  • Shell tab foreground for idle. Claude auto-slept on the real 60s coordinator interval (origin=worktree-sleep). After the isolated window later became document.visibilityState=hidden (getWindowParkVisible()=false, which pauses the interval), Codex was slept by invoking the same runAgentHibernationTick function the interval uses — not shutdownCompletedAgentPaneForHibernation from QA, not a process kill, not a tab close.
  • After each pane slept, run-create --from <slept handle> only (no Dispatches). Bind did not wake them.
  • Ordinary orchestration send --from <shell> --to <slept handle> --type handoff. Accepted with recipient_asleep and delivered_at null.

No QA-side orca orchestration check as a stand-in for the resumed provider.

Assertion table

Assertion Codex CLI 0.153.4 Claude Code 2.1.261
1. Genuine working TUI, phase-one token Yes. Real Codex 0.153.4 YOLO. Wrote qa-codex-phase1.txt = MANGO5DB9, printed ACK-MANGO5DB9. Session 01a070fb-3fda-76a3-b94d-dc12240c9ab5. Handle term_da68de61-…, pane 80453832-…:fd0e90be-…, PTY …@@f6a52a47. PIDs 83896/83899/91699. Store done. No Dispatch. Yes. Real Claude 2.1.261, LEMON5DB9, ACK-LEMON5DB9, turn done. Session e0801715-251f-4b65-9ab8-b369b7132893. Handle term_b7f5482d-…, pane 531ca8f2-…:34fdfbed-…, PTY …@@6488292e. PID 12556. No Dispatch.
2–3. Automatic idle sleep; original PID/tree gone; listed ptyId null, resumable true; UI shows slept Yes. connected:false, resumable:true, ptyId:null, title Codex ready, handle reminted term_418cb213-…. PIDs 83896/83899/91699 gone. Origin worktree-sleep. Yes. Interval sleep with shell foreground. connected:false, resumable:true, ptyId:null, title ✳ qa-claude-phase1.txt LEMON5DB9 marker, handle reminted term_05dee3d3-…. PID 12556 and parent zsh 12533 gone. Origin worktree-sleep.
4. Ordinary durable mail while slept wakes, with recipient_asleep at accept Yes. send --to term_418cb213-… (msg_77a7af818f81, to_handle=run:run_ba2c96ece1f2, delivered_at null at accept; warning recipient_asleep). Bind run_ba2c96ece1f2 did not wake. Yes. send --to term_05dee3d3-… (msg_747af639506d, to_handle=run:run_c499374601f7, delivered_at null at accept; warning recipient_asleep). Bind run_c499374601f7 did not wake.
5. Replacement PTY launches native resume with same session id, new PID, phase-one context intact Yes. codex --dangerously-bypass-approvals-and-sandbox resume 01a070fb-… (PIDs 26598/26605), replacement PTY …@@c8363203, handle term_f9d2d4ce-…. --- session restored ---. MANGO/ACK-MANGO still on screen. Yes. claude --dangerously-skip-permissions --resume e0801715-… (PID 48025), replacement PTY …@@e80726e1, handle term_bc056c9b-…. --- session restored ---. LEMON still on screen.
6. Without QA typing after wake: provider receives pointer, runs orca orchestration check, reads/acks mail, does phase two, displays phase-two token No. Bounded wait ~4 min with Codex foreground. Composer stayed Ask Codex to do anything. Pointer text You have 1 orchestration message never appeared. HERON5DB9 was not emitted. qa-codex-phase2.txt was not created. msg_77a7af818f81.delivered_at stayed null (read=0). Did not type Enter / --inject / deliverPendingMessagesForHandle. Partial. Pointer You have 1 orchestration message. Run orca orchestration check --run run_c499374601f7 was submitted. Claude ran 4 shell commands, read msg_747af639506d (delivered_at=2026-09-05T09:45:49Z). It then refused phase two (argued the restore condition was not met). FINCH5DB9 was not written. qa-claude-phase2.txt missing. read stayed 0; no ack reply.
7. No duplicate pointer or duplicate prompt N/A (pointer never submitted). No. After the pointer turn completed, a second composer prompt appeared: Go ahead and run phase two. QA did not type it and did not press Enter.

First failed assertion

Claude did not produce the phase-two token FINCH5DB9 after a genuine pointer submit and orca orchestration check on SHA 5db91a4e. The provider TUI shows the pointer as a completed turn, the check output, and an explicit refusal to write qa-claude-phase2.txt. A second unsent composer prompt (Go ahead and run phase two) then appeared without QA input.

Codex independently failed the idle-push pointer after native resume of 01a070fb-… (same class as the f529dee FAIL): wake + same-session restore + MANGO context are proven; the required positive (pointer submitted → provider check → HERON5DB9) did not happen. delivered_at remained null.

Visible states

Folder workspace fixture (non-git) before agents:

01-folder-workspace.png

Claude phase-one (Claude Code v2.1.261, LEMON5DB9, ACK-LEMON5DB9, bypass permissions):

02-claude-phase1.png

Claude automatic idle sleep (shell foreground; slept tab listed; original PID gone):

04-claude-asleep.png

Claude native resume of e0801715-…; LEMON visible; pointer submitted; check ran; FINCH not written:

05-claude-woken.png

Claude after pointer turn: refusal of phase two; duplicate composer prompt Go ahead and run phase two (not typed by QA):

06-claude-after-pointer.png

Codex slept (shell foreground; Codex tab listed asleep; original PIDs gone):

08-codex-asleep.png

Codex native resume of 01a070fb-…; --- session restored ---; YOLO; MANGO/ACK-MANGO intact; empty composer; no pointer; no HERON:

10-codex-final.png

IDs

  • Isolated Electron PID 97723 (CDP 9338), renderer node 97239 (5176), launch PID 97202 (node config/scripts/run-electron-vite-dev.mjs -c /tmp/orca-qa-18731-5db91a4e/electron.vite.qa.mjs). Profile /tmp/orca-qa-18731-5db91a4e/profile. Folder repo 634407d3-297c-47b2-9af8-6e99e3d63e87 / worktree 634407d3-…::/tmp/orca-qa-18731-5db91a4e/fixture.
  • Claude session e0801715-251f-4b65-9ab8-b369b7132893, run run_c499374601f7, live handle term_b7f5482d-dea1-42f9-8aa4-b5a12ad8f83b, slept handle term_05dee3d3-2f8a-4e3e-a92b-d4fc6ec2186b, woken handle term_bc056c9b-dbc0-464a-a952-7099c20f9973. Live PID 12556 gone; resume PID 48025 claude --dangerously-skip-permissions --resume e0801715-…. Mail msg_747af639506d (delivered_at=2026-09-05T09:45:49Z, read=0).
  • Codex session 01a070fb-3fda-76a3-b94d-dc12240c9ab5, run run_ba2c96ece1f2, live handle term_da68de61-b7be-4292-adcf-cc821c97ca3f, slept handle term_418cb213-e725-4a4c-b493-5cc79dd3ba37, woken handle term_f9d2d4ce-bf77-4d79-bc97-42442d5113ff. Live PIDs 83896/83899/91699 gone; resume 26598/26605 codex --dangerously-bypass-approvals-and-sandbox resume 01a070fb-…. Mail msg_77a7af818f81 (delivered_at null at +4m, read=0).

Verdict

FAIL. Renderer boots on this SHA (the b27c54b blank-window gate is cleared). Claude visibly passed sleep/wake/native resume/pointer submit/check, then failed the required phase-two token and showed a duplicate composer prompt. Codex visibly passed sleep/wake/native same-session resume, then failed idle-push pointer submission (HERON never emitted). No product files changed.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta — the resumed-Codex wake fix is correct and ablation-proven. Not an approval: two minor test-coverage threads from earlier reviews remain open.

Reviewed changes

Since the prior pullfrog review (5db91a4), commit 2293df1 fixes mail wake for a resumed Codex pane by removing the liveness gate that rejected it:

  • Dropped the lastAgentStatusObservedLive gate from statusless-Codex delivery — a resumed Codex emits its working spinner title (flipping observedLive to true) before clearing to the ready composer, so every statusless-Codex predicate (the proof candidate, the registerPty redrive, the becameWritable trigger, and deliverForHandle) now keys on lastAgentStatus === null alone. The relaxation stays scoped to Codex by the launchAgent === 'codex' check at the proof candidate, so a live working/permission status is still rejected.
  • Relaxed the idle-proof revalidation — isStatuslessIdleProofCurrent accepts the ready-composer state (status === null) regardless of liveness, while still rejecting a live non-idle status.
  • Added a Codex working → null delivery trigger — applyTrackedPtyTitle now delivers pending mail when a Codex pane's title clears from working to a plain cwd title (the ready composer), the signal the graph-sync and registration triggers can miss on an in-place wake.
  • Parameterized the reattach test over ordering — remountStatuslessCodex now emits a braille-spinner working title and takes a graphBeforeRegistration flag, driving both the title-transition and becameWritable paths and asserting lastAgentStatusObservedLive: true.

The reattach regression test is genuine — reverting the deliverForHandle gate fails 4 of the 12 cases, and the full suite passes (12). This also closes the prior becameWritable coverage thread (the false case registers the Codex identity before the graph goes writable).

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment) and earlier QA

Exact SHA 2293df1878a2eceed25d03650f2072f451979812 (fix orchestration mail wake for resumed Codex). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks / store-only substitutes / post-wake typing / dispatch --inject / deliverPendingMessagesForHandle / QA-side orca orchestration check as a stand-in / forced hibernation tick). window.api.app.getIdentity(): Orca: QA-18731-2293df18, devLabel=QA-18731-2293df18, isDev=true, devBranch=brennanb2025/impl-agent-sleep-wake, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9334, renderer 127.0.0.1:5176, unique user-data /tmp/orca-qa-18731-2293df18/profile. ORCA_E2E_FOREGROUND=1; getWindowParkVisible() stayed true and document.visibilityState=visible for the whole run. Hibernation on, idle 60000ms. Real installed Claude Code 2.1.261 (/Users/brennanbenson/.local/bin/claude → …/claude/versions/2.1.261) and Codex CLI 0.153.4 (/opt/homebrew/bin/codex → @openai/codex). Fixture was a non-git folder workspace (/tmp/orca-qa-18731-2293df18/fixture). Sequential: Claude first, then Codex.

This comment supersedes #18731 (comment) and earlier QA on this PR. No product files were edited, committed, or pushed. Screenshots are artifacts only.

Method

  • Fresh profile, completed onboarding seeded, temp folder workspace (not a git repo).
  • Product launchAgentInNewTab (New tab path) with YOLO defaults (claude --dangerously-skip-permissions, codex --dangerously-bypass-approvals-and-sandbox). promptDelivery=submit-after-ready delivered both phase-one prompts. No post-wake typing.
  • Ordinary provider terminals with no Dispatch. Phase-one prompts pre-authorized later session-restored orchestration pointers without naming the phase-two token or file.
  • Tokens: Claude LEMON2293 / FINCH2293. Codex MANGO2293 / HERON2293. Phase-two tokens existed only in durable mail after sleep.
  • Shell tab foreground for idle. Automatic sleep came only from the running idle coordinator (origin=worktree-sleep) while the window was park-visible. No runAgentHibernationTick from QA, no process kill, no tab close.
  • After each pane slept, run-create --from <slept handle> only (no Dispatches). Bind did not wake them.
  • Ordinary orchestration send --from <shell> --to <slept handle> --type handoff. Accepted with recipient_asleep and delivered_at null.

No QA-side orca orchestration check as a stand-in for the resumed provider.

Assertion table

Assertion Codex CLI 0.153.4 Claude Code 2.1.261
1. Genuine working TUI, phase-one token Yes. Real Codex 0.153.4 YOLO. Wrote qa-codex-phase1.txt = MANGO2293, printed ACK-MANGO2293. Session 01a0713f-09ce-7c73-82b1-1ac0619ead41. Handle term_bdf0c7de-…, pane 87ba5107-…:fb0fecc8-…, PTY …@@35fd5618. PIDs 88443/88448/88910. Store done. No Dispatch. Yes. Real Claude 2.1.261, LEMON2293, ACK-LEMON2293, turn done. Session ef7b3aed-c7ec-46cd-ad67-6f21cd11bbe5. Handle term_bca4feb8-…, pane 016fd1bc-…:c26059d5-…, PTY …@@86461ba8. PID 47605. No Dispatch.
2–3. Automatic idle sleep; original PID/tree gone; listed ptyId null, resumable true; UI shows slept Yes. Interval sleep with shell foreground, park-visible. connected:false, resumable:true, ptyId:null, title Codex ready, handle reminted term_c6216439-…. PIDs 88443/88448/88910 gone. Origin worktree-sleep. Yes. Interval sleep with shell foreground, park-visible (~128s). connected:false, resumable:true, ptyId:null, title ✳ qa-claude-phase1.txt with LEMON2293, handle reminted term_99a40187-…. PID 47605 and parent zsh 47591 gone. Origin worktree-sleep.
4. Run bind alone does not wake; ordinary durable mail while slept returns recipient_asleep and delivered_at null Yes. Bind run_ba6df95dc463 did not wake. send --to term_c6216439-… (msg_b556561c0d6a, to_handle=run:run_ba6df95dc463, delivered_at null at accept; warning recipient_asleep). Yes. Bind run_0119c67f5a00 did not wake. send --to term_99a40187-… (msg_b395f12bf5c4, to_handle=run:run_0119c67f5a00, delivered_at null at accept; warning recipient_asleep).
5. Replacement PTY launches native resume with same session id, new PID, phase-one context intact Yes. codex --dangerously-bypass-approvals-and-sandbox resume 01a0713f-… (PIDs 16643/16644/17091), replacement PTY …@@d0535236, handle term_7d2825e8-…. --- session restored ---. MANGO/ACK-MANGO still on screen. Yes. claude --dangerously-skip-permissions --resume ef7b3aed-… (PID 80622), replacement PTY …@@30885c2a, handle term_29facb81-…. --- session restored ---. LEMON still on screen.
6. Without QA typing after wake: provider receives pointer, runs orca orchestration check, reads/acks mail, does phase two, displays phase-two token Yes. Pointer You have 1 orchestration message. Run orca orchestration check --run run_ba6df95dc463 was submitted. Codex ran orca-dev orchestration check --run run_ba6df95dc463 (and --ack delivery_80459baf045a). Wrote qa-codex-phase2.txt = HERON2293, printed ACK-HERON2293. msg_b556561c0d6a.delivered_at=2026-09-05T11:14:00Z, read=1. Yes. Pointer You have 1 orchestration message. Run orca orchestration check --run run_0119c67f5a00 was submitted. Claude ran the check, acked delivery_8e88d1005c61, wrote qa-claude-phase2.txt = FINCH2293, printed ACK-FINCH2293. msg_b395f12bf5c4.delivered_at=2026-09-05T11:03:51Z, read=1.
7. No duplicate pointer or duplicate prompt Yes. Composer returned to empty Ask Codex to do anything. Pointer submitted once. Yes. Pointer submitted once and completed. Composer showed only an unsubmitted Claude suggestion (check for more orchestration messages), not a second pointer and not the previous-SHA Go ahead and run phase two prompt.

Visible states

Folder workspace fixture (non-git) before agents:

01-folder-workspace.png

Claude phase-one (Claude Code v2.1.261, LEMON2293, ACK-LEMON2293, bypass permissions):

02-claude-phase1.png

Claude automatic idle sleep (shell foreground; slept tab listed; original PID gone):

04-claude-asleep.png

Claude native resume of ef7b3aed-…; LEMON visible; pointer submitted; check ran; FINCH2293 written:

05-claude-woken.png

Codex phase-one (Codex CLI v0.153.4, YOLO, MANGO2293, ACK-MANGO2293):

07-codex-phase1.png

Codex slept (shell foreground; Codex tab listed asleep; original PIDs gone):

08-codex-asleep.png

Codex native resume of 01a0713f-…; --- session restored ---; pointer check ran; HERON2293 written; empty composer:

10-codex-final.png

IDs

  • Isolated Electron PID 94414 (CDP 9334), renderer node 94364 (5176), launch PID 94132 (node config/scripts/run-electron-vite-dev.mjs -c /tmp/orca-qa-18731-2293df18/electron.vite.qa.mjs). Profile /tmp/orca-qa-18731-2293df18/profile. Folder repo e48b3f2f-3004-4898-a572-82767235e73d / worktree e48b3f2f-…::/tmp/orca-qa-18731-2293df18/fixture. Runtime d6f422f4-9ed2-479c-9040-26cb9c444035.
  • Claude session ef7b3aed-c7ec-46cd-ad67-6f21cd11bbe5, run run_0119c67f5a00, live handle term_bca4feb8-44d5-43de-9258-12d4c44f87db, slept handle term_99a40187-24a9-43e4-9dd1-b7fe1ae84a2f, woken handle term_29facb81-7351-4b65-b93f-04a681070be9. Live PID 47605 gone; resume PID 80622 claude --dangerously-skip-permissions --resume ef7b3aed-…. Mail msg_b395f12bf5c4 (delivered_at=2026-09-05T11:03:51Z, read=1).
  • Codex session 01a0713f-09ce-7c73-82b1-1ac0619ead41, run run_ba6df95dc463, live handle term_bdf0c7de-5c40-423b-82bc-b96e0ec7e0a7, slept handle term_c6216439-2aaf-4ff2-b157-1b167bf651eb, woken handle term_7d2825e8-ff29-4f59-89fa-00eec4850f43. Live PIDs 88443/88448/88910 gone; resume 16643/16644 codex --dangerously-bypass-approvals-and-sandbox resume 01a0713f-…. Mail msg_b556561c0d6a (delivered_at=2026-09-05T11:14:00Z, read=1).

Verdict

PASS. On SHA 2293df1878a, both real installed providers completed the required sleep → bind-does-not-wake → durable mail recipient_asleep → native same-session resume → idle-push pointer → provider orchestration check → phase-two token path with no QA typing after wake. This clears the previous SHA's Claude phase-two refusal and Codex idle-push pointer miss. No product files changed.

@greptile-apps

greptile-apps Bot commented Sep 5, 2026 •

Copy link
Copy Markdown

Too many files changed for review (114 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta — the split-pane wake scoping is correct and well tested. Not an approval: two minor test-coverage threads from earlier reviews remain open.

Reviewed changes

Since the prior pullfrog review (2293df1), commit de55469a scopes a mail-driven wake to the addressed split pane and wakes already-mounted slept panes in place:

  • Slept-pane wake scoped to the addressed split leaf — main now includes intent: 'inbound-message' in the terminal:requestTabMount payload (orca-runtime-wait-for-leaf-pty-id.ts), and resolveMobileTerminalTabMount attaches a coldRestorePaneKeysByTabId restriction for inbound-message mounts. That restriction threads through the parking/overlay/pty-dep layers (via the new background-terminal-cold-restore-scope.ts merge/apply/prune set) so a mail mount cold-restores only the pane the message named instead of every slept agent in the tab.
  • Already-mounted slept panes wake in place — resolveMobileTerminalTabMount now distinguishes already-mounted from "tab does not resolve", and the IPC bridge routes the former to a new wakeMountedSleptPaneInPlace, which fires a tab- and pane-scoped WAKE_HIBERNATED_AGENTS_WORKTREE_EVENT (gated on mayBackgroundWakeSleepingAgentSession) because mounting an already-mounted tab is a no-op.
  • Unaddressed sleeping siblings stay inert — deferUnaddressedMailScopedColdRestore (first step of runDeferredSessionAttach) arms a hibernatedWakeTarget and skips the SSH attach for any slept pane outside the mail scope, so restoring the split layout does not revive siblings that received no mail.
  • Listener and intent plumbing — installWakeHibernatedAgentsListener now filters by tabId, PanePtyBinding exposes paneKey = session.cacheKey, and a shared terminal-tab-mount-intent.ts keeps the field additive (absent = permissive, so the mobile client-subscribe path stays unscoped).

The scoping coalesces correctly — an unscoped request dominates a mail-scoped one in both mergeBackgroundMountColdRestorePaneScopes and applyBackgroundMountColdRestorePaneRestriction — and the new tests are exact-value (assert connect/attach never fire for the inert sibling, exact merged-detail structures, per-pane listener dispatch). I confirmed the affected renderer suites pass (84 tests).

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment) and earlier QA

Exact SHA de55469a865264604d3d680a6bbbcde21482615c (fix terminal wake scope for sleeping split panes). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks / store-only substitutes / post-wake typing / dispatch --inject / deliverPendingMessagesForHandle / QA-side orca orchestration check as a stand-in / runAgentHibernationTick / forced hibernation tick). window.api.app.getIdentity(): Orca: QA-18731-de55469a, devLabel=QA-18731-de55469a, isDev=true, devBranch=brennanb2025/impl-agent-sleep-wake, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9335, renderer 127.0.0.1:5176, unique user-data /tmp/orca-qa-18731-de55469a/profile. ORCA_E2E_FOREGROUND=1; getWindowParkVisible() stayed true and document.visibilityState=visible for the whole run. Hibernation on, idle 60000ms. Real installed Claude Code 2.1.261 (/Users/brennanbenson/.local/bin/claude → …/claude/versions/2.1.261) and Codex CLI 0.153.4. Fixture was a non-git folder workspace (/tmp/orca-qa-18731-de55469a/fixture).

This comment supersedes #18731 (comment) and earlier QA on this PR. No product files were edited, committed, or pushed. Screenshots are artifacts only.

Method

  • Fresh profile, completed onboarding seeded, temp folder workspace (not a git repo).
  • Claude launched through product launchAgentInNewTab (New tab path) with YOLO (claude --dangerously-skip-permissions) and promptDelivery=submit-after-ready.
  • Same-split topology was then constructed via the product CLI orca terminal split --terminal <claude> --direction vertical --command "codex --dangerously-bypass-approvals-and-sandbox" (the documented product surface for a sibling-leaf command). Codex YOLO TUI came up in the sibling leaf. Phase-one prompt was delivered with product pasteDraftToAgentPtyWhenReady (PTY-specific).
  • A second Codex was later launched through New-tab (launchAgentInNewTab, codex --dangerously-bypass-approvals-and-sandbox, submit-after-ready) because the split-leaf Codex never became sleep-eligible (see first failed assertion).
  • Tokens: Claude CEDARDE55 / OSPREYDE55. Codex MAPLEDE55 / PUMADE55. Phase-two tokens existed only in durable mail after sleep (Codex) / after bind (Claude).
  • Shell tab foreground for idle. Automatic sleep came only from the running idle coordinator (origin=worktree-sleep) while the window was park-visible. No runAgentHibernationTick from QA, no process kill, no tab close.
  • Ordinary provider terminals with no Dispatch on launch. Phase-one prompts pre-authorized later session-restored orchestration pointers without naming the phase-two token or file.

No QA-side orca orchestration check as a stand-in for the resumed provider.

Assertion table

Assertion Codex CLI 0.153.4 Claude Code 2.1.261
1. Genuine working TUI, phase-one token Yes (New-tab). Real Codex 0.153.4 YOLO. Wrote qa-codex-phase1.txt = MAPLEDE55, printed ACK-MAPLEDE55. Session 01a07192-35ac-7900-8d43-6f493cb99232. Handle term_45b114dd-…, tab 9abb1850-…, leaf c7e8ee62-…, PTY …@@0acf98b9. PIDs 52147/52162/52172. Store done. No Dispatch. Split-leaf Codex (term_69d1ff8d-…, session 01a07184-473a-7071-b8c1-64afe1b8eb76, PIDs 9016/9052/9067) also completed MAPLEDE55 in the sibling leaf. Yes (New-tab). Real Claude 2.1.261, CEDARDE55, ACK-CEDARDE55, bypass permissions, turn done. Session 2ad8aa73-202b-4037-999b-461c2f11a0a5. Handle term_a908eb5f-…, tab 5a3d22e7-…, leaf 92441edc-…, PTY …@@17caaccb. PID 2902 (claude --dangerously-skip-permissions), parent zsh 2886. No Dispatch.
2–3. Automatic idle sleep; original PID/tree gone; listed ptyId null, resumable true; UI shows slept Yes (New-tab). Interval sleep with shell foreground, park-visible (~2 min). connected:false, resumable:true, ptyId:null, title Codex ready, handle reminted term_e5f954fb-7525-46f0-b3fe-9ddbb06adcd2. PIDs 52147/52162/52172 gone. Yes (first cycle). Interval sleep with shell foreground, park-visible (~128s after shell FG). connected:false, resumable:true, ptyId:null, title ✳ qa-claude-phase1.txt with CEDARDE55 marker, handle reminted term_2aecbf99-40cc-401b-b464-cddc6144aec5. PID 2902 and parent zsh 2886 gone. Origin worktree-sleep. Later remounted live when a New-tab Codex was created in the same folder workspace (unscoped background mount), so the slept cycle was not the one used for phase-two mail.
4. Run bind alone does not wake; ordinary durable mail while slept returns recipient_asleep and delivered_at null Yes. Bind run_8abae0ff6b3d did not wake (connected:false, resumable:true, ptyId:null after bind). send --to term_e5f954fb-… (msg_127b921a335b, to_handle=run:run_8abae0ff6b3d, delivered_at null at accept; warning recipient_asleep). Not on the phase-two send. First sleep was not used for bind/mail. Later send to remounted-live handle term_68ae4a81-… (msg_7fab5478f046, run run_684f8b24577a) had no recipient_asleep warning; delivered_at=2026-09-05T12:45:43Z (same second as created_at).
5. Replacement PTY launches native resume with same session id, new PID, phase-one context intact Yes. codex --dangerously-bypass-approvals-and-sandbox resume 01a07192-… (PIDs 67036/67064), replacement PTY …@@28d3d896, handle term_7731eb1a-…. --- session restored ---. MAPLE/ACK-MAPLE still on screen. First-cycle original PID/tree exited. Remount reused leaf 92441edc-… / PTY suffix @@17caaccb rather than a proven --resume 2ad8aa73-… replacement from the slept cycle.
6. Without QA typing after wake: provider receives pointer, runs orca orchestration check, reads/acks mail, does phase two, displays phase-two token Yes. Pointer check ran orca orchestration check --run run_8abae0ff6b3d (and --ack delivery_2753d4621d2a). Wrote qa-codex-phase2.txt = PUMADE55, printed ACK-PUMADE55, replied msg_87b9e01cd2ad. msg_127b921a335b.delivered_at=2026-09-05T12:42:47Z, read=1. No QA typing/Enter after wake. Phase two ran, but not from a slept wake. Live/remounted Claude received pointer Run orca orchestration check --run run_684f8b24577a, wrote qa-claude-phase2.txt = OSPREYDE55, ACK-OSPREYDE55. msg_7fab5478f046.read=1. This does not prove the slept-pane wake path.
7. No duplicate pointer or duplicate prompt Yes. Composer returned to empty Ask Codex to do anything. Pointer/check ran once. Pointer submitted once on the live pane. Composer showed an unsubmitted Claude suggestion, not a second pointer.

Split-sibling isolation (this SHA)

First proven failed assertion: both real provider sibling leaves did not auto-sleep together, so the scoped cold-restore isolation (mail to one addressed provider; sibling stays ptyId null / resumable true with no replacement PID) could not be executed.

What was constructed via the product surface:

  • Claude New-tab leaf 92441edc-… and Codex split-CLI leaf e616ce86-… in the same tab 5a3d22e7-… (vertical split). Visible: Claude v2.1.261 + Codex v0.153.4 YOLO as sibling leaves.
  • Claude auto-slept (worktree-sleep) while that split tab was backgrounded (shell foreground).
  • Split-leaf Codex never became hibernation-eligible. lastTerminalInputAt 1788611096797 fell inside the working segment (startedAt=1788611095849), so lastInputBlocksHibernation stayed true. That stamp came from pasteDraftToAgentPtyWhenReady after orca terminal split --command. New-tab prompt delivery does not stamp the same way (New-tab Codex inputAt was before working and did sleep).
  • New-tab launchAgentInNewTab always creates a new tab, not a sibling leaf. The product surface that can put a command in a sibling leaf is orca terminal split --command, which is how the topology was built.

Adjacent observations (not a substitute for the failed assertion):

  • Mail addressed only to Claude (run_684f8b24577a / pane 5a3d22e7-…:92441edc-…) made Claude run phase two. The Codex sibling in the same split stayed on MAPLEDE55 / empty composer and kept PIDs 9016/9052/9067 (it was never slept, so this is not cold-resume isolation).
  • Creating a New-tab Codex in the same folder workspace remounted the background split and brought Claude back to connected:true without a phase-two mail. That is a worktree-mount wake, not the mail-scoped cold restore this commit targets.

Visible states

Folder workspace fixture (non-git) before agents:

01-folder-workspace.png

Claude phase-one (Claude Code v2.1.261, CEDARDE55, ACK-CEDARDE55, bypass permissions):

02-claude-phase1.png

Same-split siblings (Claude left + Codex v0.153.4 YOLO right, both phase-one tokens):

03-split-siblings.png

Codex split-leaf phase-one (MAPLEDE55, ACK-MAPLEDE55, YOLO):

05-codex-phase1.png

Codex New-tab phase-one (required New-tab path, YOLO launch command visible):

08-codex-newtab-phase1.png

Shell foreground while New-tab Codex is listed asleep (Codex ready):

09-codex-newtab-asleep.png

Codex native resume of 01a07192-…; --- session restored ---; check ran; PUMADE55 written; empty composer:

10-codex-woken-phase2.png

Split tab after Claude phase two (OSPREYDE55) while Codex sibling stayed on phase one:

11-claude-phase2-split.png

IDs

  • Isolated Electron PID 96001 (CDP 9335), renderer node 95943 (5176), launch PID 95763 / PGID 95763 (node config/scripts/run-electron-vite-dev.mjs -c /tmp/orca-qa-18731-de55469a/electron.vite.qa.mjs). Profile /tmp/orca-qa-18731-de55469a/profile. Folder repo d860130f-88c9-4cff-a957-64ad6c1e5b5d / worktree d860130f-…::/tmp/orca-qa-18731-de55469a/fixture. Runtime 34dd7e9e-eb24-495d-b245-a269da315b94.
  • Claude session 2ad8aa73-202b-4037-999b-461c2f11a0a5, run run_684f8b24577a, live handle term_a908eb5f-2b83-4dd5-b125-247685647f04, slept handle term_2aecbf99-40cc-401b-b464-cddc6144aec5, later remounted handle term_68ae4a81-0229-48d9-87a0-c7305df27321. Live PID 2902 gone at first sleep. Mail msg_7fab5478f046 (delivered_at=2026-09-05T12:45:43Z, read=1).
  • Codex New-tab session 01a07192-35ac-7900-8d43-6f493cb99232, run run_8abae0ff6b3d, live handle term_45b114dd-429d-4c4d-ac24-4f287fa0a90e, slept handle term_e5f954fb-7525-46f0-b3fe-9ddbb06adcd2, woken handle term_7731eb1a-7705-4e80-bb4c-0a6f48785e6d. Live PIDs 52147/52162/52172 gone; resume 67036/67064 codex --dangerously-bypass-approvals-and-sandbox resume 01a07192-…. Mail msg_127b921a335b (delivered_at=2026-09-05T12:42:47Z, read=1).
  • Split-leaf Codex session 01a07184-473a-7071-b8c1-64afe1b8eb76, handle term_69d1ff8d-5eae-4ff1-9ae4-caaca9cfc364, PIDs 9016/9052/9067 still live at end of run (never slept).
  • Shell handle term_519e16f7-ec6d-4d9d-b6ec-39b469a7b911 (tab b82ba9a5-…).

Verdict

FAIL. First proven failed assertion: same-split sibling auto-sleep + scoped cold-resume isolation. Both real provider leaves of tab 5a3d22e7-… were never ptyId null / resumable true at the same time, so this SHA’s “mail to one slept sibling; the other stays slept with no replacement PID” path was not executed. Split-leaf Codex was blocked from automatic sleep by lastInputBlocksHibernation (input inside the working segment after product split --command + PTY paste). New-tab cannot place two agents as sibling leaves.

Codex New-tab completed the required sleep → bind-does-not-wake → durable mail recipient_asleep → native same-session resume → idle-push pointer → provider orchestration check → phase-two token path with no QA typing after wake. Claude New-tab auto-slept once (worktree-sleep) and later executed phase two from mail without QA typing, but that mail was sent after remount (connected:true, no recipient_asleep). No product files changed.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment) and all earlier QA

Exact SHA de55469a865264604d3d680a6bbbcde21482615c (fix terminal wake scope for sleeping split panes). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks / store-only substitutes / post-wake typing / dispatch --inject / deliverPendingMessagesForHandle / QA-side orca orchestration check as a stand-in / runAgentHibernationTick / forced hibernation tick / orca terminal split --command). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-r2, isDev=true, devBranch=brennanb2025/impl-agent-sleep-wake, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9340, renderer 127.0.0.1:5180, unique user-data /tmp/orca-qa-18731-r2/profile. ORCA_E2E_FOREGROUND=1; document.visibilityState=visible for the whole run. Hibernation on, idle 60000ms. Real installed Claude Code 2.1.261 (/Users/brennanbenson/.local/bin/claude → …/claude/versions/2.1.261) and Codex CLI 0.153.4. Fixture was a non-git folder workspace (/tmp/orca-qa-18731-r2/fixture).

This comment supersedes #18731 (comment) and all earlier QA on this PR. No product files were edited, committed, or pushed. Screenshots are artifacts only.

Method

  • Fresh profile, completed onboarding seeded, temp folder workspace (not a git repo). Group QA-18731-r2 / folder workspace bf08db45-bcd1-4840-ad52-985c49b185c1.
  • Claude launched through product launchAgentInNewTab (New tab path) with YOLO (claude --dangerously-skip-permissions) and promptDelivery=submit-after-ready. Prompt delivered (delivered: true). No Dispatch.
  • Codex launched separately through the same New-tab path (codex --dangerously-bypass-approvals-and-sandbox, submit-after-ready). Prompt delivered. No Dispatch. Not launched with orca terminal split --command.
  • After both genuine New-tab launches were recognized, done, and had written their phase-one tokens, the already-launched Codex pane was moved into Claude’s tab as a sibling leaf using the product split event orca-split-terminal-pane (dispatchTerminalPaneSplitRequest) with the existing Codex ptyId / leafId (no new command, no synthetic process). Original Codex tab was then closed with localPtyTeardownOwnedExternally: true so the PTY was not killed. Layout after the move: one tab 2599877e-… with vertical sibling leaves f7b9594d-… (Claude) and 911a5aa7-… (Codex), both original PTYs.
  • Tokens: Claude CEDARR2QA / phase-two OSPREYR2QA (phase-two never sent; not present in phase-one prompts). Codex MAPLER2QA / phase-two PUMAR2QA (never sent).
  • Shell tab e230ba4e-… moved to the foreground so the containing split tab was unmounted/backgrounded. Automatic sleep came only from the running idle coordinator. No runAgentHibernationTick from QA, no process kill, no tab close of the split.

Phase-two mail / native resume / no-QA-input pointer handling was not started, because the required both-siblings-asleep precondition failed.

Assertion table

Assertion Codex CLI 0.153.4 Claude Code 2.1.261
1. Genuine New-tab TUI, phase-one token Yes. Real Codex 0.153.4 YOLO. Wrote qa-codex-phase1.txt = MAPLER2QA, printed ACK-MAPLE-R2QA. Session 01a071ae-5e8b-7191-8172-4d97f9de6761. Handle term_db1fa5f7-291f-4ac7-b58c-f99aaa9f7917. Tab 2f98da78-… then sibling leaf 911a5aa7-… of tab 2599877e-…. PTY …@@7ea0c524. PIDs 52259/52260/52285/52286. Store done before the move. No Dispatch. Yes. Real Claude 2.1.261, CEDARR2QA, ACK-CEDAR-R2QA, bypass permissions, turn done. Session d34e6980-baa7-4e4d-9400-72e3b874a7ef. Handle term_54fdaa11-ee1e-462d-b72f-76c084729077. Tab/leaf 2599877e-…:f7b9594d-…. PTY …@@ca0456b0. PIDs 43256/43260/43284. Store done. No Dispatch.
2–3. Automatic idle sleep of both sibling leaves in the same tab; original PID/tree gone; listed ptyId null, resumable true No. After shell foreground (~2 min, park-visible), Codex stayed connected:true, resumable absent, ptyId=…@@7ea0c524, same handle term_db1fa5f7-…, same leaf 911a5aa7-…. PIDs 52259/52260/52285/52286 still live. Renderer agentStatusByPaneKey had no Codex row after the pane move (main agentStatus.getSnapshot() also Claude-only). Idle planner therefore never considered this sibling. Yes. Interval sleep with shell foreground, park-visible. Runtime list: connected:false, resumable:true, ptyId:null, handle reminted term_086b89de-fbf9-4d7e-8e36-ab0227eacd35, same tab/leaf 2599877e-…:f7b9594d-…. PIDs 43256/43260/43284 gone. Origin worktree-sleep.
4. Run bind alone does not wake; ordinary durable mail while slept returns recipient_asleep and delivered_at null Not reached. Codex never slept. Not reached. Both-siblings-asleep precondition failed, so phase-two mail was not sent.
5–7. Native same-session resume / provider check / phase-two token / no duplicate pointer / no QA input after wake Not reached. Not reached.

Split-sibling isolation (this SHA)

First proven failed assertion: both real provider sibling leaves of tab 2599877e-5814-41dd-aac3-f6bbadbbf26f were never ptyId null / resumable true at the same time, so this SHA’s “mail to one slept sibling; the other stays slept with no replacement PID” path was not executed.

What was constructed (New-tab first, then product split/move — not split --command):

  • Claude New-tab leaf f7b9594d-… and Codex New-tab leaf 911a5aa7-… were moved into the same tab 2599877e-… (vertical split) via orca-split-terminal-pane with the existing Codex PTY. Visible: Claude v2.1.261 + Codex v0.153.4 YOLO as sibling leaves, original processes preserved (Claude 43284 and Codex 52285/52286 still the same PIDs after the move).
  • Claude auto-slept (origin=worktree-sleep) while that split tab was backgrounded (shell foreground).
  • Split-leaf Codex never became hibernation-eligible after the move. closeTab(..., { localPtyTeardownOwnedExternally: true }) of the original Codex New-tab kept the PTY/process alive (required: do not synthesize/replace the pane) but retired renderer + main agent-status for that session. transferAgentPaneAuthority / restorePaneAuthority / transferPaneAuthority after the close did not republish a done+providerSession row on 2599877e-…:911a5aa7-…. Runtime terminal list still reported agentIdentity=codex on the live sibling, but the idle planner keys off agent status, not that list field.

Scoped cold-resume isolation (mail to one slept sibling; the other stays ptyId null) was therefore not executed.

Visible states

Folder workspace fixture (non-git) before agents:

01-folder-workspace.png

Claude phase-one (Claude Code v2.1.261, CEDARR2QA, ACK-CEDAR-R2QA, bypass permissions):

02-claude-phase1.png

Codex New-tab phase-one (Codex CLI v0.153.4 YOLO, MAPLER2QA, ACK-MAPLE-R2QA):

03-codex-phase1.png

Same-split siblings after product pane move (Claude left + Codex right, original processes, both phase-one tokens):

05-split-siblings.png

Shell tab foreground (split tab backgrounded/unmounted):

06-shell-foreground.png

After idle coordinator: Claude leaf slept (worktree-sleep); Codex sibling still live in the same split tab:

07-shell-after-claude-sleep.png

IDs

  • Isolated Electron PID 36523 (CDP 9340), renderer node 36370 (5180), launch PID 36358 (node config/scripts/run-electron-vite-dev.mjs -c /tmp/orca-qa-18731-r2/electron.vite.qa.mjs). Profile /tmp/orca-qa-18731-r2/profile. Folder workspace bf08db45-bcd1-4840-ad52-985c49b185c1 / worktree key folder:bf08db45-….
  • Claude session d34e6980-baa7-4e4d-9400-72e3b874a7ef, live handle term_54fdaa11-ee1e-462d-b72f-76c084729077, slept handle term_086b89de-fbf9-4d7e-8e36-ab0227eacd35. Live PIDs 43256 (login) / 43260 (zsh) / 43284 (claude --dangerously-skip-permissions) gone at sleep. Origin worktree-sleep.
  • Codex session 01a071ae-5e8b-7191-8172-4d97f9de6761, handle term_db1fa5f7-291f-4ac7-b58c-f99aaa9f7917 (unchanged; never slept). PIDs 52259/52260/52285/52286 still live at end of observation. Original New-tab 2f98da78-… closed after PTY-preserving move into leaf 911a5aa7-….
  • Shell handle term_ec3567a2-d72c-4617-8659-50354af5c923 (tab e230ba4e-…).

Verdict

FAIL. First proven failed assertion: same-split sibling auto-sleep + scoped cold-resume isolation. Both real provider leaves of tab 2599877e-… were never ptyId null / resumable true at the same time. Claude New-tab → sibling leaf did auto-sleep (worktree-sleep, original PID tree gone). Codex New-tab → sibling leaf stayed live because the product move (orca-split-terminal-pane + closeTab preserving PTY) dropped Codex agent-status, so the idle coordinator never selected that leaf.

This run did launch both providers through genuine New-tab launchAgentInNewTab (no split --command) and did place the already-launched processes as sibling leaves of one tab. Phase-two mail / native resume / no-QA-input pointer handling was not started, because the both-asleep precondition failed. No product files changed.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed changes

Since the prior pullfrog review (de55469a), commit d3662d154a adds cross-tab PTY authority transfer for terminal-pane moves:

  • Added transferExistingPtyAgentPaneAuthority — a fail-closed helper (terminal-split-existing-pty-authority.ts) that locates a unique leaf in another tab of the same worktree whose ptyIdsByLeafId maps to the split's ptyId, then moves that leaf's agent status and sleeping record via the existing transferAgentPaneAuthority store action.
  • Wired it into the split handler — installTerminalPaneMountEvents now invokes the transfer when a non-command split adopts an existing PTY (createdPane && detail.ptyId).
  • Added two exact-value tests — one drives the real event routing and asserts the exact transfer args; the other drives the real store and asserts the completed-resumable-agent record survives the source tab's retirement, plus the "do not guess on two claiming leaves" case.

⚠️ The authority transfer appears to have no production trigger

transferExistingPtyAgentPaneAuthority is only reachable from a split request whose detail.ptyId is set, but I could not find a production code path that populates that field with a PTY owned by a different tab. The single production dispatch that sets ptyId (terminal-presentation-ipc-bridge.ts:172-186, the onCreateTerminal split-reveal branch) always carries a freshly spawned PTY revealed into the source leaf's own tab, so the cross-tab scan finds no owner in another tab and returns false — the transfer never fires. The other split producer (ui:splitTerminal → routeRuntimeTerminalSplitRequest) does not forward ptyId at all. If so, the move-to-existing-tab authority loss this commit's title targets is not actually fixed by it.

Technical details
# transferExistingPtyAgentPaneAuthority has no production reachable trigger

## Affected sites
- src/renderer/src/components/terminal-pane/terminal-pane-mount-events.ts:73-81 — the only call site, guarded on `createdPane && detail.ptyId`.
- src/renderer/src/components/terminal-pane/terminal-split-existing-pty-authority.ts:26-44 — scans `candidateTabId !== args.tabId` for a leaf owning `args.ptyId`; no cross-tab owner → `false`.
- src/renderer/src/hooks/ipc-events/terminal-presentation-ipc-bridge.ts:172-186 — only production dispatch that sets `detail.ptyId`; its `ptyId` is the `onCreateTerminal` payload's `ptyId`.
- src/main/runtime/orca-runtime-split-pty-backed-terminal.ts:52,101-113 — `revealSplit` forwards `ptyId: result.id` from `ptyController.spawn(...)` and `tabId: parentTabId` (same tab as the source leaf), so `detail.ptyId` is always brand-new and always in the source leaf's own tab.
- src/renderer/src/hooks/ipc-events/terminal-ui-routing-ipc-bridge.ts:91-100 — the `ui:splitTerminal` path constructs `detail` without `ptyId`; the `splitTerminal` notifier (runtime-window-lifecycle.ts:152-163) never sends `ptyId` either.

## Required outcome
- Confirm the production "move a terminal pane into an existing tab" flow that is supposed to emit a split request whose `ptyId` is another tab's existing PTY, and that it reaches `installTerminalPaneMountEvents`; or acknowledge the transfer is currently unreachable and land it together with (or after) the flow that triggers it.

## Open questions for the human (optional)
- Is there a move-to-existing-tab gesture (drag onto a sibling tab, mobile, CLI/runtime) that emits a split with an existing PTY but does not yet run through `installTerminalPaneMountEvents`? If it runs through `detachTerminalPaneToTab` instead, that path already transfers authority via `syncPaneDetachPtyOwnership` — is this commit intended to cover a second, distinct mechanism?

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment) and all earlier QA

Exact SHA d3662d154a01b2963af47472430a7320ff70cabe (fix: preserve agent authority when moving terminal panes). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks / store-only substitutes / post-wake typing / dispatch --inject / deliverPendingMessagesForHandle / QA-side orca orchestration check as a stand-in / runAgentHibernationTick / forced hibernation tick / orca terminal split --command). window.api.app.getIdentity(): Orca: QA-18731-d3662d15, devLabel=QA-18731-d3662d15, isDev=true, devBranch=brennanb2025/impl-agent-sleep-wake, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9334, renderer 127.0.0.1:5176, unique user-data /tmp/orca-qa-18731-d3662d15/profile. ORCA_E2E_FOREGROUND=1; document.visibilityState=visible for the whole run. Hibernation on, idle 60000ms. Real installed Claude Code 2.1.261 (/Users/brennanbenson/.local/bin/claude → …/claude/versions/2.1.261) and Codex CLI 0.153.4. Fixture was a non-git folder workspace (/tmp/orca-qa-18731-d3662d15/fixture).

This comment supersedes #18731 (comment) and all earlier QA on this PR. No product files were edited, committed, or pushed. Screenshots are artifacts only.

Method

  • Fresh profile, completed onboarding seeded, temp folder workspace (not a git repo). Folder repo 030b74f9-21da-4f6b-bbec-54bf50c9d35e / worktree 030b74f9-…::/tmp/orca-qa-18731-d3662d15/fixture.
  • Claude launched through product launchAgentInNewTab (New tab path) with YOLO (claude --dangerously-skip-permissions) and promptDelivery=submit-after-ready. Prompt delivered (delivered: true). No Dispatch.
  • Codex launched separately through the same New-tab path (codex --dangerously-bypass-approvals-and-sandbox, submit-after-ready). Prompt delivered. No Dispatch. Not launched with orca terminal split --command.
  • After both genuine New-tab launches were recognized, done, and had written their phase-one tokens, the already-launched Codex pane was moved into Claude’s tab as a sibling leaf using the product split event orca-split-terminal-pane (dispatchTerminalPaneSplitRequest) with the existing Codex ptyId / new leafId (no new command, no synthetic process). Original Codex tab was then closed with localPtyTeardownOwnedExternally: true so the PTY was not killed. Layout after the move: one tab d1e860c0-… with vertical sibling leaves 357b02c4-… (Claude) and fc15f0db-… (Codex), both original PTYs. This SHA’s transferExistingPtyAgentPaneAuthority did republish Codex agent-status onto the new pane key (the previous SHA’s first failure).
  • Tokens: Claude CEDARD366 / phase-two OSPREYD366 (phase-two never sent in phase-one prompts). Codex MAPLED366 / phase-two PUMAD366 (never sent; Codex phase two not executed).
  • Shell tab fe00ac93-… moved to the foreground so the containing split tab was unmounted/backgrounded. Automatic sleep came only from the running idle coordinator. No runAgentHibernationTick from QA, no process kill, no tab close of the split.

Assertion table

Assertion Codex CLI 0.153.4 Claude Code 2.1.261
1. Genuine New-tab TUI, phase-one token Yes. Real Codex 0.153.4 YOLO. Wrote qa-codex-phase1.txt = MAPLED366, printed ACK-MAPLED366. Session 01a071cf-5d4e-75d2-813f-403bb2904fe4. Handle term_af290dcc-… then sibling leaf fc15f0db-… of tab d1e860c0-…. PTY …@@4bb2cc9b. PIDs 59301/59302/59317/59318/59606. Store done before the move. No Dispatch. Yes. Real Claude 2.1.261, CEDARD366, ACK-CEDARD366, bypass permissions, turn done. Session 8c054ca6-8148-4a4e-ab81-612c8c5134b8. Handle term_c8cc9c64-…. Tab/leaf d1e860c0-…:357b02c4-…. PTY …@@4f4ed2f6. PIDs 55880/55881/55895. Store done. No Dispatch.
2–3. Automatic idle sleep of both sibling leaves in the same tab; original PID/tree gone; listed ptyId null, resumable true Yes (first cycle). Interval sleep with shell foreground, park-visible (~2 min). Runtime list: connected:false, resumable:true, ptyId:null, handle reminted term_8132d2da-7c74-4583-aa86-8d9a5b5d4bef, same tab/leaf d1e860c0-…:fc15f0db-…. PIDs 59301/59302/59317/59318/59606 gone. Origin worktree-sleep. Yes (first cycle). Interval sleep with shell foreground, park-visible (~2 min). Runtime list: connected:false, resumable:true, ptyId:null, handle reminted term_34e8dd68-e1b0-4bb9-85e3-a63cccf27fe1, same tab/leaf d1e860c0-…:357b02c4-…. PIDs 55880/55881/55895 gone. Origin worktree-sleep.
4. Run bind alone does not wake; ordinary durable mail while slept returns recipient_asleep and delivered_at null Bind run_bb5f59b464c0 did not wake (connected:false, resumable:true, ptyId:null after bind). Mail to slept Codex was not sent (see first failed assertion). Yes. Bind run_5daa3864a787 did not wake. send --to term_34e8dd68-… (msg_378683d9e8a8, to_handle=run:run_5daa3864a787, delivered_at null at accept; warning recipient_asleep for term_34e8dd68-…).
5–6. Native same-session resume / provider check / phase-two token / no QA input after wake; Codex sibling stays slept Stayed slept for the Claude mail-wake. After Claude send, Codex remained connected:false, resumable:true, ptyId:null, handle term_8132d2da-…, no replacement PID. Later user-open of the split tab remounted it (see fail). Yes. Native claude --dangerously-skip-permissions --resume 8c054ca6-… (PIDs 9895/9896/9928), replacement PTY …@@8c272544, handle term_b73df074-…. Claude itself ran orca orchestration check --run run_5daa3864a787 --ack delivery_9935ca533ac7. Wrote qa-claude-phase2.txt = OSPREYD366, printed ACK-OSPREYD366. msg_378683d9e8a8.read=1, delivered_at=2026-09-05T13:48:41Z. Delivery delivery_9935ca533ac7 status acknowledged. No QA typing/Enter after wake.
7. Separate ordinary durable mail to slept Codex; native resume; provider check; unique phase two; no duplicate pointer Not reached. After the Claude phase-two screenshot mounted the split tab, Codex remounted live (codex … resume 01a071cf-…, PIDs 31756/31759/31828/31831, PTY …@@52161528) and never republished agentStatusByPaneKey. A later idle wait (~5 min, shell foreground) auto-slept Claude again (term_e7171ddd-…, ptyId:null, resumable:true, origin worktree-sleep) but Codex stayed connected:true with the remount PIDs still live. n/a (Claude re-slept; not the Codex mail path)

Split-sibling isolation (this SHA)

First proven failed assertion: mail to a slept Codex sibling (hard criterion 7). Both real provider leaves did auto-sleep together on the first idle cycle, and Claude-only durable mail did native-resume Claude while Codex stayed ptyId:null / resumable:true with no replacement PID. That scoped cold-restore was observed on the runtime list immediately after msg_378683d9e8a8 (recipient_asleep) and through Claude phase two (file qa-claude-phase2.txt written while Codex PIDs were still gone).

What then failed:

  • Capturing the required uncropped Claude phase-two screenshot required activating split tab d1e860c0-…. That user-open remount launched codex --dangerously-bypass-approvals-and-sandbox resume 01a071cf-… in sibling leaf fc15f0db-… (new PTY …@@52161528, handle term_93e9d3c6-…). Codex stayed on MAPLED366 / empty composer (no PUMAD366 — Claude mail did not drive Codex phase two).
  • After that remount, renderer agentStatusByPaneKey was Claude-only. Codex sleepingAgentSessionsByPaneKey was gone. The idle planner therefore never selected the Codex sibling. ~5 min of shell-foreground idle auto-slept Claude again and left Codex live.
  • Criterion 7 (ordinary durable mail to a slept Codex leaf, recipient_asleep, native resume from sleep, provider orchestration check, unique phase-two token, no QA input) was therefore not executed. Sending mail to the remounted-live Codex handle would not have been the slept path.

What this SHA did fix vs #18731 (comment): New-tab → product split/move of the existing Codex PTY kept Codex agent-status on d1e860c0-…:fc15f0db-…, so the first idle cycle slept both siblings. The remaining gap is user-open remount of a slept split sibling not republishing agent-status (so it cannot auto-sleep again) plus the inability to show Claude phase two in the split without remounting the unaddressed sibling.

Visible states

Folder workspace fixture (non-git) before agents:

01-folder-workspace.png

Claude phase-one (Claude Code v2.1.261, CEDARD366, ACK-CEDARD366, bypass permissions):

02-claude-phase1.png

Codex New-tab phase-one (Codex CLI v0.153.4 YOLO, MAPLED366, ACK-MAPLED366):

03-codex-phase1.png

Same-split siblings after product pane move (Claude left + Codex right, original processes, both phase-one tokens):

05-split-siblings.png

Shell tab foreground (split tab backgrounded/unmounted):

06-shell-foreground.png

After idle coordinator: both sibling leaves slept (worktree-sleep); shell still foreground:

07-slept-state.png

Claude phase two after native --resume 8c054ca6-… (OSPREYD366, ACK-OSPREYD366, pointer orca orchestration check --run run_5daa3864a787). Codex sibling is the later user-open remount (codex … resume 01a071cf-…), still on MAPLED366 / empty composer — not a slept pane:

08-claude-phase2-codex-asleep.png

Second idle wait: Claude re-slept; Codex remount stayed live (no agent-status, not selected by idle planner):

09-claude-reslept-codex-live.png

IDs

  • Isolated Electron PID 50420 (CDP 9334), renderer node 50380 (5176), launch PID 50120 / PGID 50110 (node config/scripts/run-electron-vite-dev.mjs -c /tmp/orca-qa-18731-d3662d15/electron.vite.qa.mjs). Profile /tmp/orca-qa-18731-d3662d15/profile. Folder repo 030b74f9-21da-4f6b-bbec-54bf50c9d35e / worktree 030b74f9-…::/tmp/orca-qa-18731-d3662d15/fixture. Runtime c345d7db-b7a6-4c12-9fc7-e3873443196d.
  • Claude session 8c054ca6-8148-4a4e-ab81-612c8c5134b8, run run_5daa3864a787, live handle term_c8cc9c64-3b93-4a94-8afe-005d75a3b2ac, slept handle term_34e8dd68-e1b0-4bb9-85e3-a63cccf27fe1, woken handle term_b73df074-bc20-45d6-a9a7-136f4eb8c373, later re-slept handle term_e7171ddd-290b-4759-96c6-562dc81e812a. Live PIDs 55880/55881/55895 gone at first sleep. Resume PIDs 9895/9896/9928 claude --dangerously-skip-permissions --resume 8c054ca6-…. Mail msg_378683d9e8a8 (delivered_at=2026-09-05T13:48:41Z, read=1). Delivery delivery_9935ca533ac7 acknowledged at 2026-09-05 13:48:57.
  • Codex session 01a071cf-5d4e-75d2-813f-403bb2904fe4, run run_bb5f59b464c0, live handle term_af290dcc-… then term_25ca1d64-… after the pane move, slept handle term_8132d2da-7c74-4583-aa86-8d9a5b5d4bef, later remount handle term_93e9d3c6-d617-4221-add2-cb8ad65997eb. Live PIDs 59301/59302/59317/59318/59606 gone at first sleep. Remount PIDs 31756/31759/31828/31831 codex --dangerously-bypass-approvals-and-sandbox resume 01a071cf-… still live at end of observation. Original New-tab eb567595-… closed after PTY-preserving move into leaf fc15f0db-….
  • Shell handle term_bfe33b77-cbfb-49e6-a2ea-7c1b13a847ea (tab fe00ac93-…, leaf ad5de01b-…).

Verdict

FAIL. First proven failed assertion: mail to a slept Codex sibling (criterion 7). The first idle cycle did auto-sleep both real provider leaves of tab d1e860c0-… (ptyId:null, resumable:true, original PID trees gone, origin worktree-sleep). Claude-only durable mail returned recipient_asleep / delivered_at:null, then native same-session resume + provider orca orchestration check --ack delivery_9935ca533ac7 wrote OSPREYD366 with no QA input, while Codex stayed slept with no replacement PID. Activating that split tab to capture Claude phase two remounted Codex without republishing agent-status, so Codex could not auto-sleep again and the slept-Codex mail path was not run. No product files changed.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta — the cold-resume status restoration is correct, fail-closed, and well tested. Not an approval: two minor test-coverage threads from earlier commits remain open (the malformed PTY-root mock in agent-foreground-process-confirmation.test.ts and the untested output-triggered redrive in mailbox-statusless-codex-delivery.test.ts), neither touched by this commit.

Reviewed changes

Since the prior pullfrog review (d3662d154a), commit 9953541 restores a resumed agent's completed status so a mounted cold resume can sleep again:

  • New restoreCompletedAgentStatusAfterColdResume — re-establishes the retained done status plus launch config after a sleeping-record-based resume, guarded on matching agent/provider session, isPassiveCompletedHibernationEvidence, and a non-interrupted retained done entry whose worktree/agentType match.
  • clearSleepingRecordAfterColdRestoreSpawn gains a resumeConfirmed gate — the restore runs only when the resume actually succeeded (agentResumeUnavailable !== true); a dropped resume argv skips it at both call sites, so a brand-new session is never mislabeled as its resumed predecessor.
  • Alias / move recovery — when the sleeping record's pane key differs from the resumed pane, the completed status and launch config re-register under the new key and the retained completion is dismissed under the old one.
  • Tests — a new 3-case unit suite drives the real store (exact status restore, fail-closed on provider-session mismatch, alias recovery), plus session/store fixtures and resume-banner assertions in the two cold-restore suites.

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Independent QA (Grok) — supersedes #18731 (comment) and all earlier QA

Exact SHA 9953541b8465504115515448026966481a64c7ba (fix(agent-hibernation): restore status after cold resume). Isolated Electron from this worktree only (Playwright CDP, no computer-use / OS-level input / mocks / store-only substitutes / post-wake typing / dispatch --inject / deliverPendingMessagesForHandle / QA-side orca orchestration check as a stand-in / runAgentHibernationTick / forced hibernation tick / orca terminal split --command). window.api.app.getIdentity(): Orca: brennanb2025/impl-agent-sleep-wake, devLabel=QA-18731-9953541b, isDev=true, devBranch=brennanb2025/impl-agent-sleep-wake, repo root …/impl-agent-sleep-wake. CDP 127.0.0.1:9334, renderer 127.0.0.1:5176, unique user-data /tmp/orca-qa-18731-9953541b/profile. ORCA_E2E_FOREGROUND=1; document.visibilityState=visible for the whole run. Hibernation on, idle 60000ms. Real installed Claude Code 2.1.261 (/Users/brennanbenson/.local/bin/claude) and Codex CLI 0.153.4. Fixture was a non-git folder workspace (/tmp/orca-qa-18731-9953541b/fixture).

This comment supersedes #18731 (comment) and all earlier QA on this PR. No product files were edited, committed, or pushed. Screenshots are artifacts only.

Method

  • Fresh profile, completed onboarding seeded, temp folder workspace (not a git repo). Folder repo 2000ec8a-03f0-44b9-bdbb-38da0ac5641f / worktree 2000ec8a-…::/tmp/orca-qa-18731-9953541b/fixture. Runtime b322d52f-bc6c-4ce2-9351-e40acfdcabb2.
  • Claude launched through product launchAgentInNewTab (New tab path) with YOLO (claude --dangerously-skip-permissions) and promptDelivery=submit-after-ready. Prompt delivered (delivered: true). No Dispatch.
  • Codex launched separately through the same New-tab path (codex --dangerously-bypass-approvals-and-sandbox, submit-after-ready). Prompt delivered. No Dispatch. Not launched with orca terminal split --command.
  • After both genuine New-tab launches were recognized, done, and had written their phase-one tokens, the already-launched Codex pane was moved into Claude’s tab as a sibling leaf using the product split event orca-split-terminal-pane (dispatchTerminalPaneSplitRequest) with the existing Codex ptyId / new leafId (no new command, no synthetic process). Original Codex tab was then closed with localPtyTeardownOwnedExternally: true so the PTY was not killed. Layout after the move: one tab bae35d04-… with vertical sibling leaves 34849bdd-… (Claude) and 67272929-… (Codex), both original PTYs. Agent-status transferred onto the new Codex pane key.
  • Tokens: Claude CEDAR9953 / phase-two OSPREY9953 (phase-two never sent in phase-one prompts). Codex MAPLE9953 / phase-two PUMA9953 (never sent in phase-one prompts).
  • Shell tab 7b772ad9-… moved to the foreground so the containing split tab was unmounted/backgrounded. Automatic sleep came only from the running idle coordinator. No runAgentHibernationTick from QA, no process kill, no tab close of the split.
  • After first sleep: bind Runs without waking, then ordinary durable mail to slept Claude only while the split stayed unmounted. After Claude phase two, ordinary durable mail to slept Codex while the split stayed unmounted. Split was opened only after both phase-two files existed. Then shell was foregrounded again for a second idle auto-sleep of the remounted/resumed processes.

Assertion table

Assertion Codex CLI 0.153.4 Claude Code 2.1.261
1. Genuine New-tab TUI, phase-one token Yes. Real Codex 0.153.4 YOLO. Wrote qa-codex-phase1.txt = MAPLE9953, printed ACK-MAPLE9953. Session 01a07203-2585-7363-a902-e7c159c307b8. Handle term_f887e054-… then sibling leaf 67272929-… of tab bae35d04-… (term_9ea5667c-…). PTY …@@5f72a476. PIDs 65933/65940/65960/65978/66110/66525. Store done before the move. No Dispatch. Yes. Real Claude 2.1.261, CEDAR9953, ACK-CEDAR9953, bypass permissions, turn done. Session a2029779-7e66-47f3-9fc4-946451ab89af. Handle term_0c4b21b4-…. Tab/leaf bae35d04-…:34849bdd-…. PTY …@@3b15d6e6. PIDs 17255/17256/17270. Store done. No Dispatch.
2–3. Automatic idle sleep of both sibling leaves in the same tab; original PID/tree gone; listed ptyId null, resumable true Yes (first cycle). Interval sleep with shell foreground, park-visible (~3 min from unmount). Runtime list: connected:false, resumable:true, ptyId:null, handle reminted term_1ff65b95-10dd-413c-b85e-c7e4340e96e0, same tab/leaf bae35d04-…:67272929-…. PIDs 65933/65940/65960/65978/66110/66525 gone. Origin worktree-sleep. Yes (first cycle). Interval sleep with shell foreground, park-visible. Runtime list: connected:false, resumable:true, ptyId:null, handle reminted term_ede560d5-2545-4ead-9c76-900eb4894461, same tab/leaf bae35d04-…:34849bdd-…. PIDs 17255/17256/17270 gone. Origin worktree-sleep.
4. Run bind alone does not wake; ordinary durable mail while slept returns recipient_asleep and delivered_at null Bind run_c70d04773263 did not wake (connected:false, resumable:true, ptyId:null after bind; no replacement PID). Later mail msg_6e07bae817e3 (to_handle=run:run_c70d04773263, delivered_at null at accept; warning recipient_asleep for term_1ff65b95-…). Yes. Bind run_305e0d32d1f8 did not wake. send --to term_ede560d5-… (msg_6ceec240bd25, to_handle=run:run_305e0d32d1f8, delivered_at null at accept; warning recipient_asleep for term_ede560d5-…).
5–6. Native same-session resume / provider check / phase-two token / no QA input after wake; Codex sibling stays slept for Claude mail Stayed slept for the Claude mail-wake. After Claude send, Codex remained connected:false, resumable:true, ptyId:null, handle term_1ff65b95-…, no replacement PID. Split stayed unmounted. Yes. Native claude --dangerously-skip-permissions --resume a2029779-… (PIDs 79132/79137/79164), replacement PTY …@@7af209c4, handle term_2d8d9c59-…. Product pointer: You have 1 orchestration message. Run \orca orchestration check --run run_305e0d32d1f8`. Wrote qa-claude-phase2.txt= **OSPREY9953**, printed ACK-OSPREY9953.msg_6ceec240bd25.read=1, delivered_at=2026-09-05 14:46:13. Reply msg_bcf4581ce838`. No QA typing/Enter after wake.
7. Separate ordinary durable mail to slept Codex; native resume; provider check; unique phase two; no duplicate pointer Yes. Split still unmounted. Native codex --dangerously-bypass-approvals-and-sandbox resume 01a07203-… (PIDs 61284/61426/62873/62941/67757), replacement PTY …@@d5bffea0, handle term_9e3fb618-…. Product pointer: You have 1 orchestration message. Run \orca orchestration check --run run_c70d04773263`. Codex itself ran orca-dev orchestration check --run run_c70d04773263 --ack delivery_94e3d7064f0e --json. Wrote qa-codex-phase2.txt= **PUMA9953**, ACK-PUMA9953.msg_6e07bae817e3.read=1, delivered_at=2026-09-05 14:47:58. Delivery delivery_94e3d7064f0e**acknowledged** at2026-09-05 14:48:53`. One handoff only. No QA input. n/a (Claude already complete; later auto-slept again while unmounted, then remounted for the split screenshot)
8. After both phase-two results, open split; then foreground another tab and wait for both remounted/resumed real agents to naturally auto-sleep a second time Yes (this SHA’s prior-failure fix). User-open of tab bae35d04-… kept Codex on the mail-wake PTY …@@d5bffea0 and republished agentStatusByPaneKey (done/codex). After shell foreground (~2.5 min idle coordinator), Codex slept again: term_ee858304-…, connected:false, resumable:true, ptyId:null, origin worktree-sleep. Mail-wake PIDs 61284/61426/62873/62941/67757 gone. Yes. User-open remount launched claude --dangerously-skip-permissions --resume a2029779-… (PIDs 84402/84419/84441, PTY …@@7049e66f, handle term_478e7870-…) and republished agentStatusByPaneKey (done/claude). After the same idle wait, Claude slept again: term_649e1983-…, connected:false, resumable:true, ptyId:null, origin worktree-sleep. Remount PIDs gone.

Split-sibling isolation + second sleep (this SHA)

What #18731 (comment) failed: opening the split to show Claude phase two remounted Codex without republishing Codex agentStatusByPaneKey, so Codex could not auto-sleep again and slept-Codex mail was never run.

This SHA:

  • Kept the split unmounted through both targeted mail wakes and both phase-two files.
  • Claude-only mail native-resumed Claude; Codex stayed ptyId:null / resumable:true with no replacement PID.
  • Codex-only mail then native-resumed Codex (codex … resume 01a07203-…) with provider orchestration check --ack delivery_94e3d7064f0e.
  • Opening the split afterwards remounted Claude (user-open cold resume) while Codex stayed on its mail-wake PTY. Both panes had agentStatusByPaneKey (done/claude and done/codex).
  • A second idle wait with the shell foreground auto-slept both remounted/resumed processes (ptyId:null, resumable:true, replacement PID trees gone, origin worktree-sleep). That is the prior failure, retested at this SHA.

Pane isolation held: Claude mail did not drive Codex; Codex mail did not duplicate Claude’s pointer. Folder workspace throughout.

Visible states

Folder workspace fixture (non-git) before agents:

01-folder-workspace.png

Claude phase-one (Claude Code v2.1.261, CEDAR9953, ACK-CEDAR9953, bypass permissions):

02-claude-phase1.png

Codex New-tab phase-one (Codex CLI v0.153.4 YOLO, MAPLE9953, ACK-MAPLE9953):

03-codex-phase1.png

Same-split siblings after product pane move (Claude left + Codex right, original processes, both phase-one tokens):

05-split-siblings.png

Shell tab foreground (split tab backgrounded/unmounted):

06-shell-foreground.png

After idle coordinator: both sibling leaves slept (worktree-sleep); shell still foreground:

07-slept-state.png

After both unmounted mail-wakes: split opened showing reawakened Claude (OSPREY9953, pointer orca orchestration check --run run_305e0d32d1f8) and Codex (PUMA9953, orca-dev orchestration check --run run_c70d04773263 --ack delivery_94e3d7064f0e):

08-both-phase2-split.png

Shell tab foreground again after the remounted split:

08b-shell-after-phase2.png

Second idle wait: both remounted/resumed real agents auto-slept again (ptyId:null, resumable:true, origin worktree-sleep):

09-second-sleep.png

IDs

  • Isolated Electron PID 10642 (CDP 9334), renderer node 10568 (5176), launch PID 10555 / PGID 10537 (node config/scripts/run-electron-vite-dev.mjs -c /tmp/orca-qa-18731-9953541b/electron.vite.qa.mjs). Profile /tmp/orca-qa-18731-9953541b/profile. Folder repo 2000ec8a-03f0-44b9-bdbb-38da0ac5641f / worktree 2000ec8a-…::/tmp/orca-qa-18731-9953541b/fixture. Runtime b322d52f-bc6c-4ce2-9351-e40acfdcabb2.
  • Claude session a2029779-7e66-47f3-9fc4-946451ab89af, run run_305e0d32d1f8, live handle term_0c4b21b4-7b4d-406c-9d8b-befbc772d743, first-slept handle term_ede560d5-2545-4ead-9c76-900eb4894461, mail-woken handle term_2d8d9c59-945d-499e-8e68-9e16deaa0fdd, remount handle term_478e7870-0d2a-4fce-bbf9-7c272ecca1f1, second-slept handle term_649e1983-b27d-4d99-8d54-f0544f1e9e9f. Live PIDs 17255/17256/17270 gone at first sleep. Resume PIDs 79132/79137/79164 claude --dangerously-skip-permissions --resume a2029779-…. Remount PIDs 84402/84419/84441 same --resume. Mail msg_6ceec240bd25 (delivered_at=2026-09-05 14:46:13, read=1). Delivery delivery_adaaf8daece7 remained outstanding after Claude used orchestration reply (msg_bcf4581ce838) rather than check --ack; the product pointer was still orca orchestration check --run run_305e0d32d1f8 and the file/token were written by that Claude process.
  • Codex session 01a07203-2585-7363-a902-e7c159c307b8, run run_c70d04773263, live handle term_f887e054-… then term_9ea5667c-0425-41ef-8917-4e6e95484cf9 after the pane move, slept handle term_1ff65b95-10dd-413c-b85e-c7e4340e96e0, woken handle term_9e3fb618-5463-4d44-8a6c-4fb4ce0b01f3, second-slept handle term_ee858304-88fb-498b-bdda-de4b23ca7d04. Live PIDs 65933/65940/65960/65978/66110/66525 gone at first sleep. Resume PIDs 61284/61426/62873/62941/67757 codex --dangerously-bypass-approvals-and-sandbox resume 01a07203-…. Mail msg_6e07bae817e3 (delivered_at=2026-09-05 14:47:58, read=1). Delivery delivery_94e3d7064f0e acknowledged at 2026-09-05 14:48:53. Original New-tab 93768a46-… closed after PTY-preserving move into leaf 67272929-….
  • Shell handle term_77463b2d-a998-4dd5-bac2-919eec817b46 (tab 7b772ad9-…, leaf 18d9734d-…).

Verdict

PASS. First idle cycle auto-slept both real provider leaves of tab bae35d04-… (ptyId:null, resumable:true, original PID trees gone, origin worktree-sleep). Bind did not wake. Claude-only durable mail returned recipient_asleep / delivered_at:null, then native same-session resume + provider orca orchestration check --run run_305e0d32d1f8 wrote OSPREY9953 with no QA input, while Codex stayed slept with no replacement PID. Codex-only durable mail (split still unmounted) returned recipient_asleep / delivered_at:null, then native codex … resume 01a07203-… + provider orchestration check --ack delivery_94e3d7064f0e wrote PUMA9953. Opening the split remounted both with agentStatusByPaneKey republished. A second idle wait auto-slept both remounted/resumed processes again (ptyId:null, resumable:true, replacement PID trees gone, origin worktree-sleep), which is the failure from comment 5552311351 retested at this SHA. No product files changed.

@brennanb2025

brennanb2025 commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Final review status — CLEAN

Reviewed exact final SHA 85fccd2c18f99e9e9fea744f20ff597b5bfa97ab.

Review and fixes

  • Ran the exhaustive readiness checklist at the start and again at the end.
  • Repeated same-model, same-effort adversarial review/fix loops until the exact result was CLEAN.
  • Kept the PR focused. Meaningful fixes cover durable mailbox ownership, pane-scoped wake authority and sibling isolation, bounded wake scheduling/deduplication, existing-PTY preservation when moving into a split, passive cold-resume status restoration, and stale pane-key cleanup.
  • The final commit is a one-line test-fixture correction only. Production code is byte-identical to the Electron-validated SHA 9953541b8465504115515448026966481a64c7ba.
  • OSS precedent review supports the resulting design: durable session identity, pane-scoped authority, incarnation fencing, and bounded dedupe. No polling, subprocess fanout, unbounded growth, new timers, or remote-wire compatibility change was introduced.

Verification

  • 136 focused lifecycle/planner/SSH/split tests passed.
  • 31 provider-ownership reliability tests passed.
  • pnpm tc, changed-code quality, oxlint/oxfmt, and diff checks passed.
  • Closing readiness: no P0, P1, or P2 findings; no scope expansion; no proven performance regression.
  • PR is mergeable and local HEAD matches the pushed PR head.

Real-agent Electron proof

Grok validated actual installed Claude Code 2.1.261 and Codex CLI 0.153.4 in an isolated Orca Electron instance using Playwright CDP. This was a non-git folder workspace with genuine product launch/move behavior—no mocks, fake TUIs, forced hibernation ticks, direct wake APIs, QA-side mailbox substitution, or post-wake QA typing.

Both agents performed real work, became sibling split leaves with their original PTYs, naturally auto-slept, independently woke from durable mail while the other remained asleep, consumed the mail and wrote unique results (OSPREY9953 / PUMA9953), appeared together reawakened, then naturally auto-slept a second time.

Full uncropped screenshot evidence and process/session IDs: #18731 (comment)

CI status

At the time of this comment, exact-head CI has 22 successful checks, 11 expected skips, and 2 E2E jobs still running. Unit shard 7 passed all assertions and then hit a pre-existing timing-sensitive test-cleanup race: an unchanged test closes its DB before an unchanged queued setImmediate reconciliation. The test/harness/owner/coordinator blobs predate this PR and CI history alternates pass/fail with identical code; production keeps the DB open. The aggregate verify failure is downstream of that shard. Previous SSH E2E timeouts were likewise isolated to a pre-existing stale-connected synchronization flake in source byte-identical to main; this PR does not expand into either unrelated fix.

Verdict: CLEAN and ready from code-review, readiness, performance, and real-agent Electron QA perspectives.

Merge Sim and others added 7 commits September 6, 2026 13:43
Port the sleep/wake + statusless-Codex delivery onto #16904's durable
mailbox pointer subsystem. Primary wake paths in deliverForHandle are
unchanged; the post-write Enter path wakes on a refused WriteSettlement
and leaves unverifiable on preserveAmbiguousWrite (loss of contact is
not evidence of process death).
…nt-sleep-wake

# Conflicts:
#	src/main/providers/agent-foreground-process.test.ts
#	src/main/runtime/orca-runtime-register-pty.ts
#	src/main/runtime/orca-runtime-sync-window-graph.ts
#	src/main/runtime/orchestration/mailbox-delivery-target.ts
#	src/main/runtime/orchestration/mailbox-pointer-submit.ts
#	src/renderer/src/lib/agent-hibernation-pane-eligibility.ts
#	src/renderer/src/store/slices/agent-status-manual-sleep-capture.test.ts
#	src/shared/process-table-snapshot-reader.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in the port onto #16904 — one minor test-coverage gap inline.

Reviewed changes

Since the prior pullfrog review, the branch's only new commits are five Merge origin/main merges, and they are not inert: main had independently refactored the mailbox pointer subsystem (#16904), so the merges port the sleep/wake and statusless-Codex delivery onto the new architecture.

  • Ported delivery onto OrchestrationMailboxPointerHandleDelivery — deliverForHandle's body moves to a new mailbox-pointer-handle-delivery.ts, preserving the three wake-on-no-process sites (!terminalHandle, !leaf.ptyId, catch), and mailbox-pointer-delivery.ts delegates to it.
  • Re-threaded the idle proof and wake request — statuslessIdleProof now flows through deliver/stage/submit/park, and mailbox-pointer-submit.ts gains getTerminalProcessIncarnation and requestSleepingRecipientWake, waking on proven-absent and on a refused Enter but never on unverifiable.
  • Reconciled the runtime triggers — registerPty redrives a Codex identity transition (priorLaunchAgent is captured at orca-runtime-register-pty.ts:91, before the reassignments at :115/:127), syncWindowGraph keeps the becameWritable Codex branch, mailbox-delivery-target prefers a live coordinator_pane_key handle, and the withdrawn automaticResumeBlockedBy fence is dropped from the sleep/wake guards (no producer remains; hydration strips it; a legacy persisted fence is deliberately ignored).
  • Adapted the renderer listener — new isWakeDetail/isWakeablePaneBinding guards in wake-hibernated-agents-listener.ts, with split-pane paneKey scoping and the user-sleep gate intact.

Two independent specialist passes (mailbox wake parity; renderer pane-scope parity) both found the port faithful. The only open item is the inline test-coverage gap below.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment on lines +145 to +148
// Refused is a positive "no byte left" verdict, so the recipient can
// be treated as gone; unverifiable must not wake (loss of contact is
// never evidence of process death — ssh-execution-boundary.md).
deps.requestSleepingRecipientWake?.(input.mailboxHandle)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The new refused/unverifiable wake arms are load-bearing and untested: nothing pins that a refused Enter requests a wake, and nothing pins that an unverifiable Enter (a lost SSH settlement) leaves it unrequested. The neighbouring cases already stub writePty with settledWriteStub(), so both are cheap to add. The comment also reads stronger than the verdict proves — refused includes live-pane declines (transport_queue_full, write_gate_denied, provider_refused_write), so "treated as gone" holds only because the downstream unread + durable-sleeping-record gates reject a live pane.

Technical details
# Pin the refused/unverifiable Enter wake arms

## Affected sites
- `src/main/runtime/orchestration/mailbox-pointer-submit.ts:143-148` — new wake on a `refused` Enter; the `unverifiable` arm deliberately does not wake.
- `src/main/runtime/orchestration/mailbox-pointer-submit.test.ts` — `writePty: vi.fn(settledWriteStub())` can already yield non-accepted outcomes; no case covers these arms.

## Required outcome
- A case that drives `submitOrchestrationMailboxPointer` with a `refused` Enter settlement and asserts `requestSleepingRecipientWake` fires with the mailbox handle.
- A case that drives an `unverifiable` Enter settlement and asserts it does not (the `ssh-execution-boundary` invariant: loss of contact is never evidence of process death).

## Open questions for the human (optional)
- Should the wake be reachable from a live pane's `refused` reasons (`transport_queue_full`, `write_gate_denied`), or restricted to absence-proving reasons?

resolveMobileTerminalTabMount took over its last production caller; the
wrapper survived only for its own tests. Retarget those tests at the
resolver and delete it.

This branch has not been deployed

No deployments
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