Repository navigation
refactor(native-chat): remove the unused terminal handoff - #22783
Conversation
No client ever called agentSession.requestHandoff or mounted the handoff chrome. Delete the handoff coordinator, the terminal-owner runtime, the proof write path and the unmounted UI. Keep agentSession.handoffStatus, which released desktop clients read for worktree activation, and let records an older build left mid handoff reconcile through the ordinary restart and recovery paths.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis change removes structured-session terminal handoff and TUI-owner recovery flows, along with their RPC, wire, and renderer interfaces. Lease reconciliation and session restoration now handle legacy handoff records without restoring terminal ownership. The change also adds a Claude transcript-entry UUID reader and Codex pinned rollout proof, and removes PTY write-gate enforcement. Priority: ⬇️ Low Merge Risk: 🟡 Moderate · up to After an upgrade, sessions left with a dead terminal owner may be unable to use hold/resume. The PR also adds a file outside the shrink-only type-checking baseline without an established approved exception; resolve these risks before merging. Security Architecture ReviewSecurity architecture risk: 🟡 Moderate · up to Legacy chats are designed to remain accessible after the terminal handoff is removed, but the change also removes a write control and spans restart behavior. The remaining uncertainty warrants architecture review; no exploitable path was established. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
Full details: Description checkExplanation The description covers the required scope, rationale, testing, compatibility, visual proof, AI disclosure, and checklist sections. However, the required Linked Issue is missing because it states “No issue” instead of providing an issue link.
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Advanced
Run ID: 2a417c85-54f2-47e2-a7e2-0c76a9770037
⛔ Files ignored due to path filters (1)
src/shared/rpc-contract/rpc-params-catalog.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing (174)
config/ts-nocheck-baseline.txtmobile/src/session/mobile-structured-send-delivery.tsmobile/src/session/use-mobile-structured-agent-session-prompt-cancel.test.tsxsrc/main/claude/claude-structured-session-acquisition.tssrc/main/claude/claude-transcript-entry-uuid.test.tssrc/main/claude/claude-transcript-entry-uuid.tssrc/main/claude/claude-tui-exit.test.tssrc/main/claude/claude-tui-exit.tssrc/main/claude/claude-tui-resume-launch.test.tssrc/main/claude/claude-tui-resume-launch.tssrc/main/claude/claude-tui-resume-proof.test.tssrc/main/claude/claude-tui-resume-proof.tssrc/main/claude/claude-tui-resume-real-binary.integration.test.tssrc/main/codex/codex-resume-process-proof.test.tssrc/main/codex/codex-resume-process-proof.tssrc/main/codex/codex-tui-resume-real-binary.integration.test.tssrc/main/codex/codex-tui-rollout-proof.test.tssrc/main/codex/codex-tui-rollout-proof.tssrc/main/ipc/pty/runtime/controller.tssrc/main/ipc/pty/runtime/operations.tssrc/main/native-chat/agent-session-wire/structured-agent-session-attach.tssrc/main/native-chat/agent-session-wire/structured-agent-session-background-task-channel.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-option-queue.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-command-publication.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-dead-tui-recovery.tssrc/main/native-chat/agent-session-wire/structured-agent-session-eviction.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-admission.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-flow-context.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-flow-runner.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-flow-runner.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-forward.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-operation-guard.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-operation-guard.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-options.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-options.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-owner-close.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-owner-close.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-queue-start.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-queue.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-recover.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-restart-tui.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-restart.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-result.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-revalidation.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-reverse.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-reverse.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-state.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-status.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-test-coordinator.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-test-identities.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-test-requests.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff-types.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-handoff.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-handoff-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-handoff.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-handoff.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-runtime-state.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-runtime-state.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-teardown.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-teardown.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-types.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.tssrc/main/native-chat/agent-session-wire/structured-agent-session-lease-renewer.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-lease-renewer.tssrc/main/native-chat/agent-session-wire/structured-agent-session-legacy-handoff-record.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-live-tui-restart-survival.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-manual-recovery.tssrc/main/native-chat/agent-session-wire/structured-agent-session-native-handoff-acquisition.tssrc/main/native-chat/agent-session-wire/structured-agent-session-option-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-owner-status.tssrc/main/native-chat/agent-session-wire/structured-agent-session-proven-dead-retry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-read-restore.tssrc/main/native-chat/agent-session-wire/structured-agent-session-readable-restorer.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-readable-restorer.tssrc/main/native-chat/agent-session-wire/structured-agent-session-recovery-resolution.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-recovery-resolution.tssrc/main/native-chat/agent-session-wire/structured-agent-session-refusal-retry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-restore.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-restore.tssrc/main/native-chat/agent-session-wire/structured-agent-session-resume-eligibility.tssrc/main/native-chat/agent-session-wire/structured-agent-session-reveal.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-reveal.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-settlement-retry.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subscribers.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subscribers.tssrc/main/native-chat/agent-session-wire/structured-agent-session-surface-lifetime.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-teardown-handoff-drain.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-wire-admission.test.tssrc/main/native-chat/agent-session-wire/structured-tui-transcript-boundary.tssrc/main/native-chat/agent-session-wire/structured-tui-transcript-catchup.test.tssrc/main/native-chat/agent-session-wire/structured-tui-transcript-catchup.tssrc/main/native-chat/agent-session-wire/structured-tui-transcript-close.test.tssrc/main/native-chat/agent-session-wire/structured-tui-transcript-ownership.test.tssrc/main/native-chat/agent-session-wire/structured-tui-transcript-teardown-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-tui-transcript-teardown.test.tssrc/main/native-chat/session-file-resolver.test.tssrc/main/native-chat/session-file-resolver.tssrc/main/runtime/agent-session-handoff-lease-transitions.test.tssrc/main/runtime/agent-session-handoff-lease-transitions.tssrc/main/runtime/agent-session-handoff-record-transitions.tssrc/main/runtime/agent-session-lease-transitions.tssrc/main/runtime/agent-session-pty-write-gate.test.tssrc/main/runtime/agent-session-pty-write-gate.tssrc/main/runtime/agent-session-record-store.test.tssrc/main/runtime/agent-session-restart-handoff-adjudication.test.tssrc/main/runtime/agent-session-restart-handoff-adjudication.tssrc/main/runtime/agent-session-restart-lease-transitions.tssrc/main/runtime/agent-session-resume-args.test.tssrc/main/runtime/agent-session-resume-args.tssrc/main/runtime/claude-structured-session-integration.test.tssrc/main/runtime/orca-runtime-create-terminal-dependencies.tssrc/main/runtime/orca-runtime-create-terminal.tssrc/main/runtime/orca-runtime-get-agent-session-execution-namespace.tssrc/main/runtime/orca-runtime-get-structured-agent-session-create-support.tssrc/main/runtime/orca-runtime-get-worktree-ps.tssrc/main/runtime/orca-runtime-prove-recovered-structured-tui-pty-process.tssrc/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.tssrc/main/runtime/orca-runtime-stop-structured-session-process.tssrc/main/runtime/orca-runtime-structured-agent-session-launch-tui.tssrc/main/runtime/orca-runtime-structured-agent-session-recover-tui-owner.tssrc/main/runtime/orca-runtime-structured-agent-session-reprove-tui-owner.tssrc/main/runtime/orca-runtime-structured-tui-tab-binding.test.tssrc/main/runtime/rpc/methods/orchestration/worker/agent-status-producer-census.test.tssrc/main/runtime/rpc/methods/structured-agent-session-gate-classification.test-fixture.tssrc/main/runtime/rpc/methods/structured-agent-session-gate.tssrc/main/runtime/rpc/methods/structured-agent-session-rpc.test-fixture.tssrc/main/runtime/rpc/methods/structured-agent-session-schemas.tssrc/main/runtime/rpc/methods/structured-agent-session.test.tssrc/main/runtime/rpc/methods/structured-agent-session.tssrc/main/runtime/runtime-extraction-regressions.test.tssrc/main/runtime/runtime-pty-controller-contract.tssrc/main/runtime/runtime-terminal-contracts.tssrc/main/runtime/structured-agent-session-create-adoption.tssrc/main/runtime/structured-agent-session-pty-binding.test.tssrc/main/runtime/structured-agent-session-runtime.tssrc/main/runtime/structured-tui-exit-proof.test.tssrc/main/runtime/structured-tui-exit-proof.tssrc/main/runtime/structured-tui-idle-evidence.test.tssrc/main/runtime/structured-tui-idle-evidence.tssrc/main/runtime/structured-tui-process-identity.test.tssrc/main/runtime/structured-tui-process-identity.tssrc/main/runtime/structured-tui-recovery-claim-match.test.tssrc/main/runtime/structured-tui-recovery-claim-match.tssrc/renderer/src/components/native-chat/StructuredAgentSessionHandoffChrome.test.tsxsrc/renderer/src/components/native-chat/StructuredAgentSessionHandoffChrome.tsxsrc/renderer/src/components/native-chat/use-native-chat-provisional-launch.test.tsxsrc/renderer/src/components/native-chat/use-structured-agent-session-mutate.tssrc/renderer/src/components/native-chat/use-structured-agent-session-provisional.test.tsxsrc/renderer/src/components/terminal-pane/StructuredAgentSessionTerminalReturnButton.tsxsrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/fr.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/renderer/src/lib/worktree-agent-activation-gate.test.tssrc/renderer/src/lib/worktree-agent-activation-gate.tssrc/renderer/src/lib/worktree-agent-structured-inventory.tssrc/renderer/src/runtime/structured-agent-session-handoff-store.tssrc/shared/agent-session-definitive-refusal.test.tssrc/shared/agent-session-lease-adjudication.test.tssrc/shared/agent-session-lease-adjudication.tssrc/shared/agent-session-mutation-envelope.tssrc/shared/agent-session-record.tssrc/shared/agent-session-refusal-retry.tssrc/shared/agent-session-wire.tssrc/shared/rpc-contract/structured-agent-session-params.tssrc/shared/structured-agent-session-coalescer.tssrc/shared/structured-agent-session-outbox.tssrc/shared/structured-agent-session-reducer.tstests/e2e/cross-version-wire/structured-agent-session-host-fixture.tstests/e2e/cross-version-wire/structured-agent-session-surface-manifest.ts
💤 Files with no reviewable changes (113)
- src/shared/structured-agent-session-coalescer.ts
- src/main/runtime/rpc/methods/structured-agent-session-rpc.test-fixture.ts
- src/main/native-chat/agent-session-wire/structured-tui-transcript-ownership.test.ts
- src/main/runtime/structured-tui-exit-proof.test.ts
- src/main/codex/codex-resume-process-proof.test.ts
- src/main/native-chat/agent-session-wire/structured-tui-transcript-catchup.test.ts
- src/renderer/src/i18n/locales/fr.json
- src/renderer/src/components/native-chat/StructuredAgentSessionHandoffChrome.test.tsx
- src/main/ipc/pty/runtime/controller.ts
- src/main/runtime/runtime-pty-controller-contract.ts
- src/main/runtime/orca-runtime-structured-tui-tab-binding.test.ts
- src/main/runtime/structured-tui-idle-evidence.ts
- src/main/claude/claude-tui-exit.test.ts
- src/main/runtime/agent-session-restart-handoff-adjudication.test.ts
- src/main/native-chat/agent-session-wire/structured-tui-transcript-teardown-test-fixture.ts
- src/main/codex/codex-tui-resume-real-binary.integration.test.ts
- src/renderer/src/components/terminal-pane/StructuredAgentSessionTerminalReturnButton.tsx
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-types.ts
- src/renderer/src/components/native-chat/use-native-chat-provisional-launch.test.tsx
- src/main/runtime/structured-tui-recovery-claim-match.test.ts
- src/renderer/src/i18n/locales/en.json
- src/main/native-chat/agent-session-wire/structured-agent-session-live-tui-restart-survival.test.ts
- src/main/runtime/rpc/methods/orchestration/worker/agent-status-producer-census.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-dead-tui-recovery.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-owner-close.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-host-handoff-stop.test.ts
- src/main/native-chat/agent-session-wire/structured-tui-transcript-close.test.ts
- src/main/ipc/pty/runtime/operations.ts
- src/renderer/src/components/native-chat/use-structured-agent-session-provisional.test.tsx
- src/renderer/src/i18n/locales/ja.json
- src/main/runtime/structured-tui-idle-evidence.test.ts
- src/main/native-chat/agent-session-wire/structured-tui-transcript-boundary.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff.test.ts
- src/shared/agent-session-refusal-retry.ts
- src/renderer/src/components/native-chat/StructuredAgentSessionHandoffChrome.tsx
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-flow-runner.test.ts
- src/renderer/src/i18n/locales/ko.json
- src/main/runtime/orca-runtime-create-terminal.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-owner-close.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-options.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-host-handoff.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-recover.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-reverse.test.ts
- src/main/native-chat/session-file-resolver.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-result.ts
- src/main/runtime/agent-session-handoff-lease-transitions.test.ts
- src/main/runtime/agent-session-resume-args.test.ts
- src/main/runtime/agent-session-resume-args.ts
- src/main/claude/claude-tui-resume-launch.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-readable-restorer.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-restart.ts
- src/main/claude/claude-tui-resume-proof.test.ts
- src/main/runtime/structured-tui-process-identity.test.ts
- src/main/runtime/agent-session-pty-write-gate.test.ts
- src/main/claude/claude-tui-resume-real-binary.integration.test.ts
- src/main/runtime/runtime-terminal-contracts.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-operation-guard.test.ts
- src/main/runtime/orca-runtime-structured-agent-session-launch-tui.ts
- src/renderer/src/runtime/structured-agent-session-handoff-store.ts
- tests/e2e/cross-version-wire/structured-agent-session-host-fixture.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-test-requests.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-queue-start.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-reverse.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-flow-runner.ts
- src/main/runtime/orca-runtime-prove-recovered-structured-tui-pty-process.ts
- src/main/runtime/structured-tui-exit-proof.ts
- src/main/runtime/structured-agent-session-pty-binding.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-teardown-handoff-drain.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff.ts
- src/shared/agent-session-mutation-envelope.ts
- src/main/runtime/agent-session-record-store.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-forward.ts
- src/main/native-chat/agent-session-wire/structured-tui-transcript-teardown.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-proven-dead-retry.test.ts
- src/main/runtime/agent-session-restart-handoff-adjudication.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-admission.ts
- src/main/runtime/agent-session-handoff-record-transitions.ts
- src/renderer/src/i18n/locales/zh.json
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-test-coordinator.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-state.ts
- tests/e2e/cross-version-wire/structured-agent-session-surface-manifest.ts
- src/main/claude/claude-tui-resume-proof.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-revalidation.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-host-handoff.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-manual-recovery.ts
- src/main/runtime/agent-session-pty-write-gate.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-operation-guard.ts
- src/main/runtime/orca-runtime-structured-agent-session-recover-tui-owner.ts
- src/main/runtime/rpc/methods/structured-agent-session-schemas.ts
- src/main/runtime/structured-tui-process-identity.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-background-task-channel.ts
- src/main/claude/claude-tui-exit.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-options.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-flow-context.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-native-handoff-acquisition.ts
- src/main/runtime/agent-session-lease-transitions.ts
- src/main/codex/codex-resume-process-proof.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-status.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-test-identities.ts
- src/main/runtime/structured-agent-session-runtime.ts
- src/main/runtime/orca-runtime-stop-structured-session-process.ts
- src/main/runtime/orca-runtime-structured-agent-session-reprove-tui-owner.ts
- src/main/runtime/agent-session-handoff-lease-transitions.ts
- src/main/runtime/structured-tui-recovery-claim-match.ts
- src/main/runtime/rpc/methods/structured-agent-session.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-queue.ts
- src/main/claude/claude-tui-resume-launch.ts
- src/main/native-chat/agent-session-wire/structured-tui-transcript-catchup.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-host-runtime-state.ts
- src/main/runtime/orca-runtime-create-terminal-dependencies.ts
- src/main/runtime/rpc/methods/structured-agent-session-gate-classification.test-fixture.ts
- src/main/codex/codex-tui-rollout-proof.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-handoff-restart-tui.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.
| src/main/runtime/orca-runtime-get-orchestration-dispatch-authority.ts | ||
| src/main/runtime/orca-runtime-get-pty-record-for-pane-key.ts | ||
| src/main/runtime/orca-runtime-get-runtime-id.ts | ||
| src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
#!/bin/bash
# Is the header new in this PR, and does the ratchet check compare against a base?
head -5 src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts
git log --oneline -3 -- src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts
git show HEAD~1:config/ts-nocheck-baseline.txt 2>/dev/null | rg -n 'get-structured-agent-session-create-support' || echo "not in previous baseline"
fd -i 'ts-nocheck' scripts tools . -t f -E node_modules | head
rg -n "ts-nocheck-ratchet" package.jsonRepository: stablyai/orca
Length of output: 1725
🏁 Script executed:
set -e
printf '%s\n' '--- checker ---'
cat -n config/scripts/check-ts-nocheck-ratchet.mjs
printf '%s\n' '--- checker tests (relevant) ---'
rg -n -C 4 'SHRINK|add|baseline|base|ratchet|ts-nocheck' config/scripts/check-ts-nocheck-ratchet.test.mjs
printf '%s\n' '--- baseline diff ---'
git diff --unified=12 fec8fe48225e47b883a90aadf35d6369523f72a7 c867bd2c30d0c21be8365df2a56200d8794d0e57 -- config/ts-nocheck-baseline.txt
printf '%s\n' '--- source diff ---'
git diff --unified=12 fec8fe48225e47b883a90aadf35d6369523f72a7 c867bd2c30d0c21be8365df2a56200d8794d0e57 -- src/main/runtime/orca-runtime-get-structured-agent-session-create-support.tsRepository: stablyai/orca
Length of output: 31373
Do not add a new entry to the ts-nocheck ratchet without an approved exception.
config/ts-nocheck-baseline.txt states that the list may only shrink and that entries must not be added to get CI green. This PR adds src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts and its @ts-nocheck directive.
The ratchet script checks the current files against the checked-in baseline. It does not compare the baseline with the merge base, so CI will not reject this addition automatically. Remove the directive, fix the forward-reference types, and delete the baseline entry. If the suppression is unavoidable, document the reason and obtain reviewer sign-off.
Eviction now drains delivered events before quit's resume-offer snapshot. An unbounded wait there sits ahead of the provider stop, so a sink whose journal write stalls kept the child running until the step deadline aborted the eviction. The offer is advisory: bound the drain and stop the child regardless. Co-Authored-By: Claude <noreply@anthropic.com>
`claudeAuthEnvCarriedForward`, `isPathWithinDirectory` and
`queryWindowsProcessRowsFresh` lost their last caller with the handoff. The
fresh-scan tests now go through `queryWindowsProcessDescendants({ fresh: true })`,
the teardown path that still depends on that contract.
Co-Authored-By: Claude <noreply@anthropic.com>
Six comments still named the handoff coordinator, a handoff suspend, or a terminal-owned session as live participants in the flows they describe. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…ement The removed restart handoff test pinned this branch; nothing else did. Co-Authored-By: Claude <noreply@anthropic.com>
The handoff removal dropped the per-session queue from `handoffStatus`, so a read landing mid-start reported the reservation (no owner) instead of the settled chat owner, and shipped desktop clients blocked worktree activation on it. The read is queued again, as it was before the removal. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
ℹ️ No critical issues — minor suggestions inline.
Reviewed changes
- Removed the unreachable terminal-handoff feature end to end: the host RPC (
agentSession.requestHandoff), the admission/coordinator files (structured-agent-session-handoff-admission,-forward,-revalidation,-result), theStructuredTuiOwner/StructuredTuiHandoff*types, the renderer handoff store +StructuredAgentSessionHandoffChrome/TerminalReturnButton, and thestructured-agent-session-handoff*/structured-tui-transcript-catchuptest suites and fixtures. - Kept the survivors intact:
agentSession.handoffStatusandattach/send, the ownership state machine, the PTY write gate, and the restart/settlement recovery paths. - Legacy-record handling:
'tui'and'preparing'stay in the persisted stage union so older records load; restart reconciliation now routes terminal-owned records torecovering(never stopped as before) and settlement retries no longer special-case terminal owners. - Wire narrowing:
AttachParams.runtimeKindis now'native'only;runtimeKind: 'tui'is rejected at the schema, and attach always adopts the chat owner. - Client cleanup:
worktree-agent-activation-gateno longer offers a terminal-owner skip, dropped thestructuredOwnerargument on resume, and reduced snapshot/batch frames to a single target; i18n and e2e strings for the terminal flow are deleted.
I traced the removed surface for lingering callers (renderer store, i18n keys, status feed, activate/detach paths), checked the narrowed runtimeKind schema and its mobile call site, verified the legacy tui/preparing stage records still load and are retired by restart reconciliation, and re-checked the new structured-agent-session-legacy-handoff-record test against the code it exercises. One spawn-token test comment is now misleading, and four renderer test mocks keep a vestigial handoff: null field.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
The gate only refused a write when a PTY had been bound to a chat session, and the only code that ever bound one was the terminal handoff this branch removes. With it gone, every admit/readmit returned "admitted" unconditionally, so the checks on the renderer write path, the runtime controller backstop, terminal.send, agent prompts, preview input and orchestration pointers, the refusal fields on terminal.send and worker-start receipts, the plugin and CLI refusal copy, and the adopted-pane orchestration routing could no longer run. Ordinary writes take the same path in the same order as before. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — delta since the prior pullfrog review (c867bd2c30 → 12efdefd1f, 6 commits, 15 files):
handoffStatusreads behind an in-flight attach: the owner-status record read is wrapped inthis.serialize(sessionId, …), so a chat that is mid-start answers with its settled owner rather than a transient record. A newstructured-agent-session-host.test.tscase pins the starting-chat behavior.- Pre-stop drain bounded:
snapshot-before-stopnow awaitswithTimeout(context.eventSink.drained(), 1_000, null), so a stalled journal write cannot hold the child's stop behind the advisory resume snapshot. The new eviction test covers the stalled-sink path. - Dead helpers removed:
claudeAuthEnvCarriedForward,queryWindowsProcessRowsFresh, andisPathWithinDirectoryhad no callers outside the removed handoff code — verified zero remaining references acrosssrc/,mobile/,tests/, andconfig/. - Comment cleanups: surviving comments no longer cite the removed handoff coordinator (
agent-session-empty-batch,attach,host-lifetime,status-feed,unexpected-exit,host-types). - Test-only: pins that a start which dies before proving its handle owes no settlement, and drops a cast in the stalled-drain test.
The behavioral changes are correct: withTimeout absorbs rejections, so the dropped drain cannot surface as an unhandled rejection, and the failed barrier still aborts eviction later at drain-published. The serialize wrapper restores the pattern the base already used for this read.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
…alled appendLegacyTranscriptMessages fed the terminal transcript catch-up and proveClaudeTranscriptBranch backed the terminal owner's exit proof. Both lost their last caller with the handoff. Their tests now go through the live entry points instead: the roster bounds through the legacy import, the pinned-read and growth tests through the ancestry replay the history window uses, and the marker rules through the string proof in their own file rather than the session-file resolver's. Co-Authored-By: Claude <noreply@anthropic.com>
A send refused because the chat's owner is not settled showed "The session is mid-handoff (<stage>)." in the composer. With the handoff gone, the stages that reach it are a chat that is still starting, or one whose previous agent process has not yet been confirmed stopped. The message now says which of the two it is. The refusal code is unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — delta since the prior pullfrog review (12efdefd1f → faececed48, 4 commits, 52 files):
- Removed the agent-session PTY write gate: deleted the gate, the shared admission/refusal types, the refusal-copy helper, and the renderer refusal reporter, and stripped the lease check from every byte-entry point (
pty/ipc/write-input, the PTY runtime controller,runtime-terminal-writer, the agent-prompt write, orchestration pointer delivery, pluginsendText,terminal.send, and the preload bridge).RuntimeTerminalSend.agentSessionRefusaland thewrite_gate_deniedsettlement reason are gone with it. - Collapsed the adopted-pane redirect:
resolveAdoptedStructuredMailboxTarget,decideStructuredPointerDelivery,isSettledNativeOwner, and theowner-not-settled-nativeretain reason are deleted; the structured pointer lane now decides solely from the session's gate facts, and every retain reason parks for the next journal edge. - Dropped transcript helpers only the handoff called:
proveClaudeTranscriptBranchandappendLegacyTranscriptMessagesremoved; the marker-branch tests moved into a dedicatedclaude-transcript-marker-branch-proof.test.ts, and the streaming suite now drivesreplayClaudeTranscriptBranchAncestry. - Stopped calling a starting chat "mid-handoff":
refuseUnlessWriterAdmittednow answers "The chat is still starting." fornew-owner-provingand a recovery sentence for the other recorded stages.
I verified the gate was already inert before this commit: git grep bindPty at 12efdef finds agentSessionPtyWriteGate.bindPty(...) only in test files, so enforcing was always false and no production write path could be refused. The replacements are behavior-preserving. The four directly changed suites plus the gate-adjacent suites pass, and pnpm tc is clean.
ℹ️ The PR description still describes the PTY write gate as surviving
The description's "What Changed → After" section states that "The PTY write gate ... remain[s]" and that "every write passes through it unchecked"; commit 42d10eee15 deletes the gate, agentSessionRefusal, and structuredChatPtyWriteRefusalCopy outright. A reviewer reading the description would misjudge the blast radius of the final commit. The claimed-agent PTY owner and SSH claim validation do still remain, so only that portion needs rewording — and the title may want to mention the gate, since the change is no longer just the handoff.
Technical details
# Stale PR description
## Affected sites
- PR body, "What Changed → After" bullet "The terminal-agent pieces stay." — claims the PTY write gate remains and that "every write passes through it unchecked", and that the typed refusal copy is still produced.
## Required outcome
- The description should match `faececed48`: the gate, `AgentSessionPtyWriteRefusal`/`agentSessionRefusal`, and `structuredChatPtyWriteRefusalCopy` are removed. `agentSession.handoffStatus`, the ownership state machine (`handoffStage`/`handoffOperationId`), the claimed-agent PTY owner, and the SSH claim validation still remain.
## Open questions for the human
- Should the title name the PTY write-gate removal, or is it being split into a follow-up?DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
With the terminal handoff gone, the module named codex-tui-rollout-proof holds only the pinned rollout lookup that structured Codex launches use to resume a thread, so the name described code that no longer exists. Rename the module and its options type. Also drop a mobile allowlist assertion that pinned the removed agentSession.requestHandoff method, which no longer exists to allow.
The handoffStatus reply type still listed the terminal handoff's fields and states (terminal placement, host label, proof retry, queued and waiting phases, the to-terminal direction). No host writes them any more and the only client reader parses the reply as unknown, so they described nothing. The reply on the wire is unchanged.
…t decode Nothing in this build writes a terminal owner (`runtimeKind: 'tui'`) or the handoff's `preparing` / `old-owner-stopped` stages, but the in-memory types still admitted them, so readers across the host kept branches for values no path produces and the compiler could not point at them. The store now validates the on-disk shape, which still accepts those values so an older record is not quarantined, and maps them once while parsing: - `preparing` and `old-owner-stopped` become `recovering` - a `tui` lease becomes `native`; when it records a process it also becomes `conflicted`, the claim every build probes but never stops. A plain native owner would be stopped by restart recovery, here and in older builds. Revisions are taken over the normalized state on both sides of every compare, and the mapped record reaches disk with the store's first transaction, the same way the tab-id backfill does. The in-memory types narrow to what this build writes, and the branches that existed only for the removed values go. Structured-worker identity keeps its verdict for a former terminal owner by refusing a conflicted claim rather than a non-native kind.
…ation A reservation only ever names a native owner now, so the request no longer carries a kind and the reserved lease records `native` directly. The attach params keep `runtimeKind`: agentSession.ensure and create accept it, and the operation fingerprint stored in the ledger covers it.
…at changes nothing else Hiding a tab also committed the visibility index, so the no-op transaction wrote the file even when its open-time revision was wrong. Committing the index first leaves the pending rewrite as the only reason to write.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — delta since the prior pullfrog review (b58818524d → 713b126feb, 3 commits, 49 files):
- Normalized legacy terminal-handoff leases at decode: new
agent-session-legacy-handoff-lease.tsmaps a persistedruntimeKind: 'tui'to'native'(a lease naming a process becomes aconflictedclaim; one naming nobody keeps its claim) andhandoffStage: 'preparing' | 'old-owner-stopped'to'recovering'.parseStatenormalizes every record as it parses and flagslegacyHandoffLeasesNormalized, so the rewrite lands with the store's first transaction rather than at open. - Narrowed the in-memory lease types:
AgentSessionOwnerRuntimeKindis now'native'andAgentSessionHandoffStageonly the three live stages; the persisted superset moves behind the newPersistedAgentSession*types, andisAgentSessionRecordbecomesisPersistedAgentSessionRecord. - Stopped threading the owner kind through a reservation:
AgentSessionReserveRequestandAgentSessionReservationdropruntimeKind; every reservation and created record writes'native'. - Dropped the now-impossible runtime-kind guards:
recoveryMayStopOwner,structuredWorkerRecordIsCurrent,observeStructuredWorker,isSurfaceReleasableAgentSessionRecord,settleFailedAgentSessionPostAcquisitionAttachment, and the acquisition stage guard decide onclaimStatus/stage alone. - Tests: new
agent-session-legacy-handoff-leaseandagent-session-record-store-legacy-handoff-leasesuites pin the mapping and the rewrite/revision behavior, and a sharedwriteOlderBuildLeasefixture re-seeds the existing suites with legacy leases.
I traced every persisted shape through the decode gate and its consumers: a recorded terminal owner always normalizes to conflicted, so it is probed but never signalled; live with no owner is rejected before normalization; and no normalized shape becomes a live writer. The focused suites (13 + 27 + 2 + 9 + 4 + 162 tests) pass.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
…ackfill cannot supply its rewrite The seeded record had no surface tab id, so the next open backfilled one and that rewrite alone made the no-op transaction write. The test passed with the legacy-lease rewrite signal removed.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — delta since the prior pullfrog review (713b126feb → 2bd44f5f7d, 1 commit, 1 file):
- Hardened the legacy-lease store test:
persistLiveOwnerinagent-session-record-store-legacy-handoff-lease.test.tsnow passessurfaceTabId: 'tab-alpha'toreserveOwner, so the record on disk no longer needs the open-time surface-tab-id backfill. Without it,backfillAgentSessionSurfaceTabIdswould itself setneedsRewrite, and the first transaction would persist the normalized lease even iflegacyHandoffLeasesNormalizedwere never wired — the flag this commit's predecessor added. The focused suite passes (2/2), and the assertion at line 96 can still fail ifnormalizeLegacyHandoffRecordstops mappingruntimeKind/handoffStage.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
The handoff removal deleted it alongside the terminal-owner tests, but it covers the surfaced-PTY block that still guards resume, including an agent whose ownership is unknown.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.
🟡 Minor · Restore dead-TUI recovery before renewal. · structured-agent-session-lease-renewer.ts:69-86
src/main/native-chat/agent-session-wire/structured-agent-session-lease-renewer.ts:69-86
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winRestore dead-TUI recovery before renewal.
A proven-dead TUI record now enters ordinary renewal.
renewAgentSessionLeaserejects that probe, so the record remainslivewith its old owner. Restart reconciliation skips already reconciled records. The reachablehold/resume path then returnsagent_session_ownership_unknownbecause it accepts only released records. Restore the former dead-TUI recovery or eviction branch and skip ordinary renewal for that probe. Direct attach can replace the dead owner, but hold/resume cannot.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Advanced
Run ID: e824eb07-a779-4bbf-9bf5-48bc4f8ffecf
📒 Files selected for processing (1)
src/main/runtime/agent-session-record-store-legacy-handoff-lease.test.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — delta since the prior pullfrog review (2bd44f5f7d → f79eb9b88f, 1 commit, 1 file):
- Restored an unrelated test the refactor deleted by accident.
test(worktree-activation)puts backdoes not resume OMP when a surfaced %s agent lacks conversation ownershipinworktree-agent-activation-gate.test.ts. The PR's first commit removed it as collateral while deleting two adjacent TUI-owner tests, even though it has nothing to do with the handoff. It guards thehasUnclaimedRecoveryblock (worktree-agent-activation-gate.ts:234-241), asserts an exact'blocked'outcome, and is byte-identical to the base version. The suite passes 32/32 andoxlintreports no warnings.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
Review status: ready for reviewHead Review loops. Six independent review passes, plus a separate architecture review after the third. Each pass that found something fixed it here with a test that goes red without the fix. The last pass found no production issues; its one commit restores, unchanged from What review changed, on top of the original removal:
Readiness checklist. Start of session: pass, with two minor findings (the uncapped quit wait and the Live Electron QA (macOS, background launch, isolated profile). Pass: workspace activation, terminal typing and paste, a Claude chat to completion, restart restore, a message held while a chat starts, upgrade and downgrade on one profile (main → PR → main → PR, history and follow-ups intact each time), and a record hand-edited to the old handoff values. Screenshots are linked in the PR description. Not covered: the mobile test suite (mobile dependencies aren't installed locally; the mobile change is one call-site argument and one fixture), Codex chats in live QA, and live SSH / Windows runs (no SSH- or Windows-specific path changed). Separate, existing issue found during QA (not caused by this PR): quitting with a Claude chat open takes about 15 s on Follow-ups worth considering (all already on |
|
Ready to merge. This is my view as coordinator of the native-chat redesign stack. Why:
Merge order: this is the base of the stacked redesign PRs #22808, #22820, #22811 and #22812, which are all based on this branch. Merge this first. Each of those then needs its base switched to Not blocking:
|
Main removed the terminal handoff (#22783), so its root-exit stop reading and the handoff integration test are dropped with it.
Resolve conflicts with the terminal-handoff removal (#22783): take main's runtime wiring and integration test, and re-apply this branch's Claude child-work evidence wiring and the status-sink child-work test.
Brings in the removal of the structured-chat terminal handoff (#22783): an agent session is now owned natively only, and the agent-session PTY write gate is gone. The next commit removes this branch's remnants of that handoff.
…tream removal Upstream stablyai#22783 deletes the structured-session terminal handoff these fork features were built on. Follow upstream: remove the Chat <-> agent TUI toggle, the handoff status row, Release session, and the stale-handoff-status fix. The top-right cluster keeps Continue in New Session and split. Reverts 4a9be55, 164c08b, 386d474, f52e9dd, 55e1d4a. Co-authored-by: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follows upstream stablyai#22783 (terminal handoff removed; fork handoff features were reverted in the previous commit). Upstream's merged Cursor usage replaces the fork's earlier Cursor usage remnants. Keeps fork prompt suggestions, async question card, Antigravity local quota probe, coordinator identity, and the Windows argv reservation proof (Claude only; upstream dropped TUI leases). Moves the Cursor transcript lookup out of session-file-resolver.ts to stay within max-lines. Co-authored-by: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stage the staged plan existed for. Measured from the post-stage-2 main this cost 78 commits and 14 conflicts (13 in the PTY delivery subsystem) instead of 881 commits and 32 conflicts from the original base. **The PTY wall was not what the 월드맵 feared.** It recorded `pty-project-window-stream-routing` as a ~1,500-line feature-scale re-implantation and deferred it twice. In fact all 14 conflicts come from three upstream commits: - `9700030689` refactor(pty): make renderer delivery optional for headless runtimes (stablyai#23117) — `session.mainWindow` becomes optional and every `isDestroyed()` guard gains a null check. - `82412dab8b` Persist profile state in SQLite with background writes (stablyai#22612). - `d443320af2` refactor(native-chat): remove the unused terminal handoff (stablyai#22783). On the same lines the fork had already replaced the main-window guard with owner-window routing (`resolvePtyOwnerWindow`, `sendToPtyOwner`, `ownerFlowStateForPty`). The fork's guard is strictly finer: in headless mode no window is registered with the router, the owner resolves to null, and the fork takes the same early-return upstream's null check adds — while upstream's coarser guard would drop or misroute project-window delivery when the main window is gone. So most of the cluster resolves to ours, and nothing had to be reimplanted. Conflicts resolved (14) - `pty/delivery/{accept,accounting,exit,flush}.ts`, `pty/provider/bind-listeners.ts`: ours. Verified mechanically — resolving every hunk to ours produced a file byte-identical to main, so upstream has no other change in them. - `pty/delivery/payload.ts`, `pty/runtime/operations.ts`: per hunk, never whole-file. A whole-file ours on operations.ts would have restored imports of two modules `d443320af2` deleted and a 3-arg `writePtyFromRuntimeController` while the merged `runtime/controller.ts` calls the 2-arg form. - `pty/ipc/{resize-visibility,serialize-buffer,spawn-commit-persist,write-input,write}.ts`, `pty/register-handlers.ts`: combined, preserving every per-window router injection. A previous attempt at this merge failed its gates by dropping them. - `persistence/loading-store/store.ts`: combined for `82412dab8b`'s SQLite authority. Edits outside the 14 conflicted files (6) Each one is a defect the conflict list could not show, because the file merged cleanly while the meaning did not. 1. `pty/session.ts` + `pty/delivery/window-flow-state.ts`: `session.ts` merged cleanly into a crash. `mainWindow` is now optional, upstream's `register-headless-runtime.ts` passes `undefined` where it used to pass a fake destroyed window, and the fork's `createWindowFlowState(session, args.mainWindow.webContents)` therefore threw on every `orca serve` and orcad registration. Fixed by narrowing a flow state's `webContents` to `Pick<WebContents, 'id' | 'isDestroyed' | 'send'>` and passing a destroyed stand-in, with no cast. `window-flow-state.ts` stays at 297 of its 300 permitted code lines. 2. `persistence/loading-store/store-domain-composition.ts`: added `SatelliteWindowSessionPersistence &` to `StoreDomainOperations`, without which four satellite-session methods disappear from the `Store` type. 3. `pty/register-without-renderer.test.ts`: two `registerPtyHandlers(renderer as never, …)` casts, matching the shape 274 existing calls in this repo use. This is an upstream-owned file, so the next sync touching it will conflict here. 4. Three usage test fixtures (`usage-custom-range-filters.test.ts`, `UsageNumberFormatToggle.test.tsx`, `usage-pane-test-state.ts`): added the fields upstream `297cfe0cf3` (stablyai#22073) made required. **These were already broken on main**: a fresh worktree at `e0686816e8` reports exactly these 4 type errors. Stage 2's gate missed them because a warm `composite` `.tsbuildinfo` cache under-reported. Typecheck cold before trusting a pass. 5. `pty/register-handlers.ts` + the window-affinity router: `setMainWindowForRouting` widened to `BrowserWindow | null` and called unconditionally as `setMainWindowForRouting(mainWindow ?? null)`. Skipping it when `mainWindow` is undefined left a previously routed live window routed, so a desktop → headless re-registration would send `pty:exit`, `pty:spawned`, `pty:writeUnavailable`, `pty:clearBuffer:request`, `pty:serializeBuffer:request` and `pty:modelRestoreNeeded` to a stale window. Current call order prevents it in production; that is not a guarantee worth depending on. Restores parity with main. Gates (each captured from the command's own exit code) - typecheck, run cold after deleting `config/*.tsbuildinfo`: 0 errors. The same command on a main worktree reports its 4 pre-existing errors. - oxlint: exit 0 on the full tree and on the touched files. - verify-orcinus-identity: OK, upstreamRefs=0. - electron-builder smoke: unsigned, update signature checks disabled. - fork contract tests: 3 files / 24 tests. - `register-without-renderer.test.ts` (upstream's new 231-line headless test): 4/4. - router-referencing tests: 3 files / 70 tests. - Broad conflict-area suite: 122 failures, none attributable. 121 fail identically on a main worktree; the remaining one, upstream's own `profile-state-crash-recovery.test.ts`, times out identically on a `da6d483ab9` worktree. Per-test JSON diff: 0 failures unique to main. Reviewed by an independent critic: APPROVE, no blocking defects, every gate re-measured, every fork-only and upstream-only file confirmed equal to its parent apart from the six edits above, no IPC channel dropped. Non-blocking and deliberately not addressed: `hasUnpricedModels: false` does not match its own fixture's data (behaviour-neutral); the upstream-owned test file will re-conflict; plan-B's satellite-session durability question is still open. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Scope: which chat this affects
experimentalStructuredNativeChatsetting, which is off by default (src/shared/default-global-settings.ts:137).terminal.sendin plain terminals or in the terminal-backed chat.ELI5
Orca had a hidden feature that could move a chat into a terminal running the agent, then back into the chat. No button, command or app ever turned it on. This PR deletes it, along with a terminal safety check that only that feature could ever switch on. Chats saved by any older version still open, and you can still send to them.
What Changed
What the user sees. Almost nothing, because the feature was never reachable. The only visible difference: if a command-line, mobile or remote client sends to a chat that is still starting, the refusal now says "The chat is still starting." instead of "The session is mid-handoff (new-owner-proving)." The desktop app never shows either message, because it holds a message until the chat is ready.
Removed. Every desktop and headless host ran this code, even though no client could start it:
agentSession.requestHandoff), the coordinator that moved the chat between the two and resumed that move after a restart, and the host code that launched a terminal agent and proved it owned the chatterminal.sendand worker start, the CLI and plugin refusal text ("Switch it to Terminal, then retry"), and orchestration's rerouting of mail to a terminal taken over by a chat. Only the handoff ever bound a terminal to a chat, so the gate let every write through.Kept, and why.
agentSession.handoffStatus. Desktop clients that have already shipped call it whenever they open a workspace with a chat tab, and a missing method would make them refuse to activate that workspace. It now reports only which runtime owns the chat, worked out from the saved record. It still waits behind a chat that is mid-start, as before, so it reports the chat as the owner rather than "no owner".handoffStage,handoffOperationIdandruntimeKind. Despite the names, they are the ownership state machine for every chat: each normal chat start writesnew-owner-proving, and failure and restart paths writerecoveringandmanual-recovery. Renaming persisted fields would need a data migration, which belongs in its own change.terminal.createAgentSessionandterminal.ensureAgentSessionuse them; they are not part of the handoff.Records an older build left behind. Only the handoff wrote three values: the stages
preparingandold-owner-stopped, and a terminal owner (runtimeKind: 'tui'). They are now converted once, when a record is read from disk, and the in-memory types no longer allow them, so the compiler flags any code that still branches on them:preparingandold-owner-stoppedbecomerecovering, which the normal restart check then settles.conflicted. That is the existing state that every build, including older ones, checks but never stops, because that terminal is the user's own agent. Once the process is gone, the chat takes the session back. Until then, opening the chat says "Another Orca window or terminal still owns this session. Close it, then retry."One adjacent fix. Quit's resume offer (from #22560) read the sidebar state before the provider's already-delivered events had been applied. It only worked because the removed "drain handoffs" quit step added a delay first. Quit now waits for delivered events before taking that snapshot, for at most 1 second, so a slow journal write can never stop the chat's agent process from being stopped. Without the wait,
offers only unfinished work when an accepted completed event is queued at quitfails.Why
The feature was never reachable.
git log -Sonorigin/main:requestHandoffundersrc/renderer,mobile,src/cli,src/preload: no commits ever. The host method was added in fd9125e (feat(native-chat): Codex structured native chat restructure #16729), and no client has ever called it.StructuredAgentSessionHandoffChrome,StructuredAgentSessionTerminalReturnButton, the store that published handoff status to the terminal, and the strings "Open agent TUI" and "Return to chat" were added in a65332a (feat(claude): move structured native chat onto the Claude Agent SDK and enable it on macOS and Linux #18560) and never imported.agentSession.attachis only called inside the host, always with'native', so no shipped build could have writtenruntimeKind: 'tui'. The only code that bound a terminal to a chat was the handoff's own launch and recovery path.So in practice a leftover handoff record can only exist on a machine where someone called the RPC by hand. The load path handles those records anyway rather than trusting that.
Alternatives considered:
runtimeKind: restart and eviction copy it forward, so a legacy chat that is never reopened would keep'tui'forever, and eight readers would keep branches for a value nothing produces. Converting once at load removes those branches and lets the compiler catch any that remain.handoffStage/handoffOperationId. Both are persisted on every record, so that is a migration and belongs in its own change.Mixed versions (clients and hosts update independently):
handoffStatuskeeps its name and shape, and the client still only treatsowner: 'native'as a chat owner. An old host never sent the removed write refusal in practice (nothing bound a terminal); if one did, the CLI prints the plain "Input refused by …" error.handoffStatusanswers as before for chat-owned sessions.requestHandoffnow returnsmethod_not_found, and no shipped client ever sends it. Snapshot frames no longer include the handoff status, which only the never-mounted handoff UI read.requestHandoff; the cross-version wire suites pass.Linked Issue
No issue; follow-up to an internal decision to remove unused features.
Visual Proof
N/A for the change itself: the removed UI was never mounted, and no reachable desktop screen changes. Screenshots from the regression QA are under Testing.
Testing
Live Electron QA (macOS, background launch, isolated profile, PR build):
mainalike, so this PR does not change it. It is an existing, separate issue in the Claude session shutdown fallback.Automated:
handoffStatuswaiting behind a start, and the new refusal text.tc:node,tc:web,tc:cli), full-fileoxlint,check:code-quality:changed,check:react-doctor:changed, the max-lines, ts-nocheck and runtime-electron ratchets,verify:rpc-params-catalog, and the localization checks pass. The agent-session, orchestration, PTY IPC, terminal RPC and cross-version wire suites pass; the only failures seen were timeouts under parallel load that pass alone.AI Disclosure
Written with Claude (Opus 5.5).
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
handoffStatusstays on the mobile allowlist.structured-agent-session-restart-restore.tsand nearby host files that this PR also changes; whichever lands second needs a small rebase.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)