Repository navigation
Keep native chat /clear in the same conversation - #26579
Conversation
5c6a2cd to
bda2c6d
Compare
|
Clearing a native chat used to create a second conversation and move its tab, so drafts, queued cards, phone rows and orchestration addresses depended on replacement bookkeeping. The maintainer decision removed the requirement for older desktop builds to read the new storage form, so #26545 is closed. This rework uses the ordinary chain and ownership index without an archive or parallel ownership rules; the record boundary remains only where fresh launch, suffix rewind and mail need the clear’s identity. Earlier lifecycle review fixes for rollback/replay, queue pause/lift and bounded mail remain; the fresh rework review found no blocking issues, and its dead stored-card pause fallback is removed. After the single main sync, the final review found zero P0–P3 issues and independently passed 1,351 tests across 111 files, excluding five inherited todos. Accepted temporary limitation: a desktop app built from main between v1.4.222 and this change, connected to a newer host, can keep Send disabled for up to two minutes after rewinding past a Author validation on the final head: 1,092 root tests in 91 files, 168 mobile tests in ten files, all four fresh queued project typechecks and 13 tests in the two required real-Claude suites pass. Local pre-push checks pass 21 of 22; the five unchanged mobile import-cycle warnings reproduce on exact synced main with the same dependencies. Hidden stand-in live QA verifies the same tab/session, earlier transcript, one divider and a fresh provider thread; screenshots are embedded in the body. The permitted configuration hashes match and all recorded rig processes/profiles were cleaned up. Live draft/image/queue Resume, Run/mail/custody/read/stop, SSH/paired, phone-device and Windows/Linux UI flows are not claimed. Update after the last main sync (head
Resolution review of the merge ( All CI checks finished on head |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (34)
💤 Files with no reviewable changes (2)
🚧 Files skipped from review as they are similar to previous changes (6)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthrough
Priority: ⬇️ Low Merge Risk: 🔵 Low · up to Rewind may appear available while a dispatch is unsettled, but the host rejects it safely. This is a bounded usability risk rather than a blocker to merging. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)✅ Passed checks (4 passed)Full details: Docstring CoverageExplanation Docstring coverage is 34.38% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 64 functions across 68 files. (6 skipped: 6 unsupported.)
✨ 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: 2
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
ab38699b-e6b7-468e-b42f-3d70c51e1ded
📒 Files selected for processing (143)
config/scripts/vitest-sqlite-database-runtime-files.mjsconfig/scripts/vitest-sqlite-runtime-files.mjsmobile/src/session/MobileNativeChatMessage.test.tsmobile/src/session/MobileNativeChatMessage.tsxmobile/src/session/mobile-native-chat-message-styles.tssrc/main/acp/acp-structured-context-clear.test.tssrc/main/acp/acp-structured-launch-resolution.test.tssrc/main/claude/claude-structured-effort-default-at-rest.test.tssrc/main/claude/claude-structured-launch-resolution.test.tssrc/main/claude/claude-structured-launch-resolution.tssrc/main/claude/claude-structured-session-id.tssrc/main/codex/codex-structured-launch-resolution.test.tssrc/main/native-chat/agent-session-attachments/agent-session-attachment-claims.test.tssrc/main/native-chat/agent-session-journal/journal-context-clear.tssrc/main/native-chat/agent-session-journal/journal-context-controller.tssrc/main/native-chat/agent-session-journal/journal-context-rewind.tssrc/main/native-chat/agent-session-journal/journal-derived-turn-scope.tssrc/main/native-chat/agent-session-journal/journal-epoch-replacement.tssrc/main/native-chat/agent-session-journal/journal-queued-messages.tssrc/main/native-chat/agent-session-journal/journal-reducer.tssrc/main/native-chat/agent-session-journal/journal-restart-reconciliation.tssrc/main/native-chat/agent-session-journal/journal-rewind-submission-retirement.tssrc/main/native-chat/agent-session-journal/journal-row-schema.tssrc/main/native-chat/agent-session-journal/journal-row-writer.tssrc/main/native-chat/agent-session-journal/journal-stop-and-resume-rows.tssrc/main/native-chat/agent-session-journal/journal-stop-turn-end.tssrc/main/native-chat/agent-session-journal/journal-store.tssrc/main/native-chat/agent-session-journal/queued-message-context-clear.test.tssrc/main/native-chat/agent-session-journal/queued-message-pause.test.tssrc/main/native-chat/agent-session-journal/queued-message-pause.tssrc/main/native-chat/agent-session-journal/queued-message-table.tssrc/main/native-chat/agent-session-wire/structured-agent-session-at-rest-commands.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-attach.tssrc/main/native-chat/agent-session-wire/structured-agent-session-attachment-admission.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-child-exit.tssrc/main/native-chat/agent-session-wire/structured-agent-session-clear-rewind.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-ended-child-failure.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-stop-event.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-plans.tssrc/main/native-chat/agent-session-wire/structured-agent-session-operation-settlement.tssrc/main/native-chat/agent-session-wire/structured-agent-session-options-read.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-options-read.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-card-holds.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-command.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig-provider.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-messages.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-mutations.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-stop-row.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-registered-definition.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-context-clear.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-resume-set.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-block.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-cause.tssrc/main/native-chat/agent-session-wire/structured-agent-session-unsent-send-hold.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-working-at-teardown.tssrc/main/native-chat/agent-session-wire/structured-conversation-command-admission.test.tssrc/main/native-chat/agent-session-wire/structured-conversation-command-admission.tssrc/main/native-chat/agent-session-wire/structured-conversation-command-controller.tssrc/main/native-chat/agent-session-wire/structured-conversation-command.test.tssrc/main/native-chat/agent-session-wire/structured-conversation-command.tssrc/main/native-chat/agent-session-wire/structured-conversation-replacements.test.tssrc/main/native-chat/agent-session-wire/structured-rewind-journal-body.tssrc/main/native-chat/agent-session-wire/structured-rewind-recovery.tssrc/main/pi/rpc-launch-resolution.test.tssrc/main/runtime/agent-session-conversation-clear-commit.test.tssrc/main/runtime/agent-session-conversation-command-record.tssrc/main/runtime/agent-session-conversation-receipts.tssrc/main/runtime/agent-session-provider-handle-transition.test.tssrc/main/runtime/agent-session-record-store.tssrc/main/runtime/agent-session-rewind-completion.tssrc/main/runtime/agent-session-tab-table.tssrc/main/runtime/claude-structured-startup-unanswered-control-request.test.tssrc/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.tssrc/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.tssrc/main/runtime/orca-runtime-runtime-id.tssrc/main/runtime/orca-runtime-structured-session-restore.test.tssrc/main/runtime/orchestration/agent-facing-parity.test.tssrc/main/runtime/orchestration/structured-mailbox-pointer-delivery.test.tssrc/main/runtime/orchestration/structured-mailbox-pointer-delivery.tssrc/main/runtime/orchestration/structured-mailbox-pointer-host.test.tssrc/main/runtime/orchestration/structured-mailbox-pointer-host.tssrc/main/runtime/orchestration/structured-pointer-operation-id.test.tssrc/main/runtime/orchestration/structured-pointer-operation-id.tssrc/main/runtime/rpc/methods/structured-agent-session.tssrc/main/runtime/rpc/methods/structured-chat-tab-table.test-fixture.tssrc/main/runtime/rpc/methods/structured-chat-tab-table.test.tssrc/main/runtime/structured-agent-session-startup-tab-restore.test.tssrc/main/runtime/structured-chat-coordinator-mail-rig.test-fixture.tssrc/main/runtime/structured-chat-coordinator-mail.test.tssrc/main/runtime/structured-chat-dispatch-worker-lifecycle.test.tssrc/main/runtime/structured-chat-dispatch-worker-mail.test.tssrc/main/runtime/structured-claude-pending-rewind.test.tssrc/main/runtime/structured-claude-scripted-runtime-test-support.tssrc/main/runtime/structured-conversation-tab-replacement.test.tssrc/main/runtime/structured-conversation-tab-replacement.tssrc/renderer/src/components/native-chat/NativeChatAutocompleteMenus.tsxsrc/renderer/src/components/native-chat/NativeChatNoticeRow.tsxsrc/renderer/src/components/native-chat/NativeChatTranscriptRow.tsxsrc/renderer/src/components/native-chat/structured-agent-session-message-projection.tssrc/renderer/src/components/native-chat/use-native-chat-rewind.test.tsxsrc/renderer/src/components/native-chat/use-native-chat-rewind.tssrc/renderer/src/components/native-chat/use-structured-agent-session-command-write.tssrc/renderer/src/components/native-chat/use-structured-agent-session-context-usage.tssrc/renderer/src/components/native-chat/use-structured-agent-session-rewind.tssrc/renderer/src/components/native-chat/use-structured-agent-session-thread-goal.tssrc/renderer/src/components/native-chat/use-structured-agent-session-transport-state.tssrc/renderer/src/components/native-chat/use-structured-agent-session.tssrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.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/shared/agent-session-context-clear.test.tssrc/shared/agent-session-context-clear.tssrc/shared/agent-session-conversation-command.tssrc/shared/agent-session-journal-schemas.tssrc/shared/agent-session-journal-types.tssrc/shared/agent-session-provider-context.test.tssrc/shared/agent-session-provider-context.tssrc/shared/agent-session-record.tssrc/shared/agent-session-resume-marker.tssrc/shared/agent-session-rewind.tssrc/shared/agent-session-thread-goal.tssrc/shared/agent-session-wire.tssrc/shared/native-chat-context-usage.tssrc/shared/native-chat-provider-retry-runs.tssrc/shared/native-chat-types.tssrc/shared/structured-agent-session-composer.tssrc/shared/structured-agent-session-context-usage.tssrc/shared/structured-agent-session-live-turn.tssrc/shared/structured-agent-session-message-projection.tssrc/shared/structured-agent-session-owed-work.tssrc/shared/structured-agent-session-projection.tssrc/shared/structured-agent-session-status-block.tstests/e2e/cross-version-wire/agent-session-clear-old-client.unit.test.tstests/e2e/cross-version-wire/agent-session-clear-old-tab-mirror.unit.test.ts
💤 Files with no reviewable changes (7)
- src/main/native-chat/agent-session-wire/structured-conversation-replacements.test.ts
- src/main/runtime/structured-conversation-tab-replacement.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
- src/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.ts
- src/main/runtime/orca-runtime-runtime-id.ts
- src/main/runtime/structured-conversation-tab-replacement.ts
- src/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.
| * derive for it. | ||
| */ | ||
| show(sessionId: string, tabId?: string): void { | ||
| if (this.tabBySession.has(sessionId)) { | ||
| return | ||
| } | ||
| const derived = structuredAgentSessionTabId(sessionId) | ||
| const held = (candidate: string): boolean => this.sessionByTab.has(candidate) | ||
| this.put(tabId ?? (held(derived) ? reopenedTabId(sessionId, held) : derived), sessionId) | ||
| this.put(tabId ?? derived, sessionId) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Keep a fallback when another session holds the derived tab ID.
This change removes the fallback in show() that minted a -reopened ID when the derived ID was already in use. A held derived ID was the normal case for data written by earlier builds. On those builds, /clear ran move(source, replacement), which gave the source's tab ID structured-agent-session-<source> to the replacement session. The store loads that persisted mapping into AgentSessionTabTable. If a user then reveals the old source conversation from history, show(source) passes the derived ID to put(). put() finds that the replacement owns the ID and throws agent_session_conflict / tabIdTaken. Before this change, the source got a reopened tab. Now the reveal fails for every conversation an earlier build cleared. The new tests do not cover this path, because every clear now keeps the same session.
Restore the fallback, but only for the case without a reserved ID.
🐛 Proposed fix
show(sessionId: string, tabId?: string): void {
if (this.tabBySession.has(sessionId)) {
return
}
const derived = structuredAgentSessionTabId(sessionId)
- this.put(tabId ?? derived, sessionId)
+ if (tabId !== undefined) {
+ this.put(tabId, sessionId)
+ return
+ }
+ // Records from earlier builds can hold this id on a /clear replacement.
+ let candidate = derived
+ for (let suffix = 1; this.sessionByTab.has(candidate); suffix++) {
+ candidate = suffix === 1 ? `${derived}-reopened` : `${derived}-reopened-${suffix}`
+ }
+ this.put(candidate, sessionId)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| * derive for it. | |
| */ | |
| show(sessionId: string, tabId?: string): void { | |
| if (this.tabBySession.has(sessionId)) { | |
| return | |
| } | |
| const derived = structuredAgentSessionTabId(sessionId) | |
| const held = (candidate: string): boolean => this.sessionByTab.has(candidate) | |
| this.put(tabId ?? (held(derived) ? reopenedTabId(sessionId, held) : derived), sessionId) | |
| this.put(tabId ?? derived, sessionId) | |
| * derive for it. | |
| */ | |
| show(sessionId: string, tabId?: string): void { | |
| if (this.tabBySession.has(sessionId)) { | |
| return | |
| } | |
| const derived = structuredAgentSessionTabId(sessionId) | |
| if (tabId !== undefined) { | |
| this.put(tabId, sessionId) | |
| return | |
| } | |
| // Records from earlier builds can hold this id on a /clear replacement. | |
| let candidate = derived | |
| for (let suffix = 1; this.sessionByTab.has(candidate); suffix++) { | |
| candidate = suffix === 1 ? `${derived}-reopened` : `${derived}-reopened-${suffix}` | |
| } | |
| this.put(candidate, sessionId) |
| const boundary = | ||
| getStructuredAgentSessionHost()?.deps.store.getRecord(sessionId)?.providerContextBoundary | ||
| return { | ||
| submissions: boundary | ||
| ? snapshot.submissions.filter((submission) => submission.fence > boundary.afterFence) | ||
| : snapshot.submissions | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
#!/bin/bash
# Find how a submission's fence is assigned at accept vs. handover.
rg -nP -C4 '\bfence\b' src/main/native-chat/agent-session-journal/journal-submission*.ts src/main/native-chat/agent-session-journal/journal-reducer.ts | head -200
rg -nP -C3 'handedOverAt|handoverRecorded' src/main/native-chat/agent-session-journal | head -80Repository: stablyai/orca
Length of output: 22740
🏁 Script executed:
set -o pipefail
printf '%s\n' '--- relevant definitions and references ---'
rg -n -F --glob '*.ts' -- 'readPointerSessionFacts' src/main
rg -n -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main
rg -n -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/main
rg -n -F --glob '*.ts' -- 'appendSubmission' src/main/native-chat/agent-session-journal
rg -n -F --glob '*.ts' -- 'resolveDispatch' src/main/native-chat/agent-session-journal
printf '%s\n' '--- journal submission and dispatch implementations ---'
sed -n '1,190p' src/main/native-chat/agent-session-journal/journal-submission-fold.ts
sed -n '1,180p' src/main/native-chat/agent-session-journal/journal-dispatch-reducer.ts
printf '%s\n' '--- pointer host and decision logic ---'
sed -n '1,180p' src/main/runtime/orchestration/structured-mailbox-pointer-host.ts
rg -n -C8 -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main
printf '%s\n' '--- current-context filtering ---'
rg -n -C12 -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/mainRepository: stablyai/orca
Length of output: 42350
🏁 Script executed:
set -o pipefail
printf '%s\n' '--- references ---'
rg -n -F --glob '*.ts' -- 'readPointerSessionFacts' src/main || true
rg -n -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main || true
rg -n -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/main || true
printf '%s\n' '--- journal submission fold ---'
sed -n '1,190p' src/main/native-chat/agent-session-journal/journal-submission-fold.ts
printf '%s\n' '--- dispatch reducer ---'
sed -n '1,180p' src/main/native-chat/agent-session-journal/journal-dispatch-reducer.ts
printf '%s\n' '--- pointer host ---'
sed -n '1,180p' src/main/runtime/orchestration/structured-mailbox-pointer-host.ts
printf '%s\n' '--- pointer decision context ---'
rg -n -C12 -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main || true
printf '%s\n' '--- current context context ---'
rg -n -C16 -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/main || trueRepository: stablyai/orca
Length of output: 42668
🏁 Script executed:
printf '%s\n' '--- caller and fence flow ---'
rg -n -C10 -F --glob '*.ts' -- 'appendSubmission({' src/main
rg -n -C10 -F --glob '*.ts' -- 'resolveDispatch({' src/main/native-chat src/main/runtime
rg -n -C10 -F --glob '*.ts' -- 'acquire' src/main/native-chat/agent-session-journal src/main/runtime/orchestration
printf '%s\n' '--- pointer symbols ---'
rg -n -C20 -F --glob '*.ts' -- 'readPointerSessionFacts' src/main
rg -n -C20 -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main
rg -n -C20 -F --glob '*.ts' -- 'currentContextClearOperationId' src/main
printf '%s\n' '--- boundary and accepted-sequence symbols ---'
rg -n -C14 -F --glob '*.ts' -- 'providerContextBoundary' src/main
rg -n -C12 -F --glob '*.ts' -- 'acceptedSequence' src/main/native-chat/agent-session-journalRepository: stablyai/orca
Length of output: 45663
🏁 Script executed:
set -o pipefail
printf '%s\n' '--- pointer decision implementation ---'
sed -n '1,190p' src/main/runtime/orchestration/structured-pointer-operation-id.ts
printf '%s\n' '--- context-clear implementation ---'
sed -n '1,220p' src/shared/agent-session-context-clear.ts
printf '%s\n' '--- submission writer and store append contract ---'
sed -n '1,180p' src/main/native-chat/agent-session-journal/journal-submission-writer.ts
sed -n '70,125p' src/main/native-chat/agent-session-journal/journal-store-contracts.ts
sed -n '300,370p' src/main/native-chat/agent-session-journal/journal-store.ts
printf '%s\n' '--- send path and fence inputs ---'
rg -n -C12 -F --glob '*.ts' -- 'expectedRuntimeFence' src/main/native-chat src/main/runtime/orchestration
rg -n -C12 -F --glob '*.ts' -- 'appendSubmission(submission' src/main/native-chat src/main/runtime
rg -n -C12 -F --glob '*.ts' -- 'runtimeFence' src/main/native-chat/agent-session-wire | head -240
printf '%s\n' '--- boundary creation and fields ---'
rg -n -C14 -F --glob '*.ts' -- 'providerContextBoundary' src/main/native-chat src/main/runtime src/sharedRepository: stablyai/orca
Length of output: 45661
🏁 Script executed:
set -o pipefail
printf '%s\n' '--- exact pointer decision file ---'
nl -ba src/main/runtime/orchestration/structured-pointer-operation-id.ts | sed -n '35,175p'
printf '%s\n' '--- exact context-clear file ---'
nl -ba src/shared/agent-session-context-clear.ts | sed -n '1,180p'
printf '%s\n' '--- exact append implementation ---'
nl -ba src/main/native-chat/agent-session-journal/journal-store.ts | sed -n '325,360p'
nl -ba src/main/native-chat/agent-session-journal/journal-submission-writer.ts | sed -n '1,115p'
printf '%s\n' '--- send path definitions ---'
rg -n -F --glob '*.ts' -- 'function sendAgentTurn' src/main
rg -n -F --glob '*.ts' -- 'function performSend' src/main
rg -n -F --glob '*.ts' -- 'handoverRecorded' src/main/native-chat/agent-session-wireRepository: stablyai/orca
Length of output: 17821
🏁 Script executed:
set -o pipefail
printf '%s\n' '--- pointer resolver callers ---'
rg -n -C18 -F --glob '*.ts' -- 'resolveStructuredPointerOperation(' src/main/runtime
printf '%s\n' '--- current fence and pointer host contract ---'
rg -n -C14 -F --glob '*.ts' -- 'currentFence(sessionId' src/main
rg -n -C14 -F --glob '*.ts' -- 'expectedRuntimeFence:' src/main/runtime/orchestration
printf '%s\n' '--- send context fence assignment ---'
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-turns.ts | sed -n '130,180p'Repository: stablyai/orca
Length of output: 42039
Keep post-clear pointer submissions visible until handover.
structured-mailbox-pointer-delivery.ts reads the lease fence before sending, and performSend records that fence before the dispatch row updates it. While the cleared chat is at rest, that fence can equal boundary.afterFence. The filter then removes the pending submission.
decideStructuredPointerAttempt returns park only when it finds the matching pending submission. If the filter removes it, the resolver can mint another operation for the same batch.
Use the accepted-sequence current-context boundary for submissions after the clear. Retain the existing fence fallback when a rewind removed the clear marker, so older submissions remain excluded.
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:
0fe97197-992c-4f0c-8672-217a82d13ffd
📒 Files selected for processing (2)
src/main/native-chat/agent-session-wire/structured-agent-session-host.tssrc/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts
💤 Files with no reviewable changes (1)
- src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.
| queueSendsNext, | ||
| backgroundTasks | ||
| backgroundTasks, | ||
| conversationBusy: Boolean(turnId || backgroundTasks.isMonitoring) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
#!/bin/bash
# Inspect unanswered-dispatch and background-task state calculations, plus their renderer use.
rg -n -C 6 '\bhasUnansweredStructuredAgentSessionDispatch\b|\bstructuredSessionBackgroundTasksView\b|\bconversationBusy\b' \
src/shared src/renderer/src/components/native-chatRepository: stablyai/orca
Length of output: 39133
🏁 Script executed:
set -o pipefail
printf '%s\n' '--- transport state ---'
nl -ba src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts | sed -n '1,110p'
printf '%s\n' '--- session state construction and rewind call ---'
nl -ba src/renderer/src/components/native-chat/use-structured-agent-session.ts | sed -n '130,245p'
printf '%s\n' '--- unanswered dispatch rule ---'
nl -ba src/shared/structured-agent-session-unanswered-dispatch.ts | sed -n '1,100p'
printf '%s\n' '--- main-agent working rule ---'
nl -ba src/shared/structured-agent-session-main-agent-working.ts | sed -n '1,60p'
printf '%s\n' '--- rewind definitions and callers ---'
rg -n -C 8 --glob '*.{ts,tsx}' 'useStructuredAgentSessionRewind|rewind.*blocked|blocked.*rewind|rewindBehind|rewind' src/renderer src/shared src/main 2>/dev/null | head -n 500
printf '%s\n' '--- host admission/rewind terms ---'
rg -n -C 8 --glob '*.{ts,tsx}' 'conversation.*rewind|rewind.*conversation|rewind.*busy|busy.*rewind|rewind.*admission' src 2>/dev/null | head -n 300Repository: stablyai/orca
Length of output: 42325
🏁 Script executed:
printf '%s\n' '--- target hook ---'
nl -ba src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts | sed -n '1,90p'
printf '%s\n' '--- rewind hook references ---'
rg -n -C 10 --glob '*.{ts,tsx}' 'useStructuredAgentSessionRewind|rewindBehind|rewind.*blocked|blocked.*rewind' src/renderer src/shared
printf '%s\n' '--- host rewind handlers and admission ---'
rg -n -C 10 --glob '*.{ts,tsx}' 'rewind|rewindBehind|conversationBusy|hasUnansweredStructuredAgentSessionDispatch|isStructuredAgentSessionMainAgentWorking' src/main src/shared src/renderer | head -n 800Repository: stablyai/orca
Length of output: 42301
Include unanswered dispatches in conversationBusy.
An unanswered dispatch can make isWorking true before a provider turn exists. conversationBusy can still be false when no background task is monitoring, so the renderer leaves rewind unblocked.
Suggested fix
--- "a/src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts"
+++ "b/src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts"
@@ -71,6 +71,6 @@
/** Working only because the queue is about to send: nothing is in flight to stop yet. */
queueSendsNext,
backgroundTasks,
- conversationBusy: Boolean(turnId || backgroundTasks.isMonitoring)
+ conversationBusy: Boolean(isWorking || backgroundTasks.isMonitoring)
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| conversationBusy: Boolean(turnId || backgroundTasks.isMonitoring) | |
| conversationBusy: Boolean(isWorking || backgroundTasks.isMonitoring) |
Main's #26579 keeps a native chat in the same session across /clear, so a message's sender id still names the live chat. Remove the host's orchestration-root projection, the optional status field, and the renderer's lineage lookup and feed capability probe that only served it.
…e, clickable on the queued card too (#26357) * feat(native-chat): name an agent's message by its current title, and open it from the queued card The sender line on another agent's message and on its queued card now shows the name Orca shows for that agent right now (its sidebar agent row or chat tab name), falling back to the name recorded when it was sent. The queued card's names open the sender, as the transcript row's already do. * fix(orchestration): name a CLI agent sender by its tab's own name, not just its agent A terminal agent's recorded sender name used only a manual tab rename, else the agent type, so mail from CLI agents read as "Codex" or "Claude". The host now names every sender the way Orca shows it: a chat by its rename or saved name, a terminal agent by its sidebar agent row's name (rename, quick command, generated or meaningful live title; a split pane only by its own title). The task title and generic agent label are fallbacks. The renderer shows the live own name, else the recorded one. * fix(orchestration): preserve known sender names in message snapshots * Preserve sender names across chat clears and terminal reuse * fix: keep sender links on the recipient host across older runtimes * test: type sender naming fixtures with their declared identities * Fix sender ownership publication after clearing a chat * Drop /clear sender lineage now that /clear keeps the same conversation Main's #26579 keeps a native chat in the same session across /clear, so a message's sender id still names the live chat. Remove the host's orchestration-root projection, the optional status field, and the renderer's lineage lookup and feed capability probe that only served it.
ELI5
Clearing a native chat currently creates another conversation and moves its tab, changing the addresses used by drafts, queued cards and phone rows. The replacement bookkeeping makes a simple context reset depend on relocating the conversation.
/clearnow keeps the same chat and tab. Earlier messages remain above one “Context cleared” divider, and the next send starts a fresh agent context. Drafts, attachments, tab placement and queued-card IDs keep their existing keys.What Changed
Clear refuses while the agent is working or awaiting an answer. Once idle, it releases the provider, proves its release and rechecks admission, then commits an empty provider handle chain, the record boundary, divider, exact ordinary-message-card pause, waiting-command withdrawal and completed command in one transaction. Fresh provider proof creates the first link in that new chain without replacement ancestry. The previous provider session is no longer owned by this chat and can be adopted from provider history elsewhere.
Provider readers use the chain head. The boundary remains for Claude’s stable fresh-context ID and interrupted-start transcript check, suffix-only rewind, restart offers, goal and usage resets, and bounded mail delivery after an in-flight clear. Codex starts a new thread; ACP starts a new session. Rewind preserves the earlier journal and divider, and changes only the current context. Waiting command cards, including
/compact, are withdrawn inside that transaction. Ordinary message cards keep their IDs and order and need the next accepted user turn, Resume or Send now; rewinding that accepted turn does not revive the pause.A
/compactarriving during clear waits behind the same conversation lane and receives the existing in-flight-operation refusal; replay still returns a previously recorded answer.Removed replacement conversation creation, tab moves, queued-card copying, current replacement publication and permanent cleared-chat send refusal. Current-host orchestration forwarding is removed separately in #26610. Existing client readers for older hosts’ replacement results remain because remote hosts and clients update independently.
Why
Conversation identity and provider context have separate lifetimes. Resetting the chain releases the discarded provider context directly and uses the ordinary record codec and ownership index, without an archive, another stored copy or new stream operation. The record boundary still answers which clear owns rewind and mail delivery; the journal supplies its visible divider.
Linked Issue
N/A — maintainer follow-up from a native chat audit.
Visual Proof
Isolated hidden-renderer Codex stand-in: the same tab/session and earlier messages remain above one divider, then the next turn uses a new thread. Durable storage goes from an empty chain after clear to one fresh creation without replacement ancestry; the stand-in records two starts and zero resumes. The captures precede the final main sync, which preserves this visible flow and is covered by the final automated checks. They include unrelated first-launch tips.
Before:
After:
Testing
5f2c39efb62dincludes semantic merge594b078af979, the rewind mock-target correction and the module splits needed to keep existing line limits, and incorporates fixed mainff4a51c872e, including queued/compact. Focused tests pass 66/66 across four files: ordinary cards around a compact card retain exact pause membership, withdrawal and the context reset roll back together, connected/reconnecting client publications drop the command, clear refuses Working before provider release, and compact arriving during clear is serialized and refused without a card or send.ff4a51c872ewith the same installed dependencies; all five file/line/column keys match. Both lockfiles are restored to verified committed bytes and the worktree is clean. Frozen installs succeeded in the owned root and mobile directories; both lockfiles remain unchanged.Review
The earlier complete review of
6cf1a71a320found zero P0–P3 issues. Its P3 dead stored-card pause fallback had been removed; the accepted older-app two-minute rewind hold remains disclosed and bounded. Subsequenta0ff6c2f5d8resolution review was clean and completed CI had 21 successful and 14 skipped checks; skips are not passes. Main then landed queued/compactand made that head conflict. The coordinator authorized this semantic merge onto fixedff4a51c872e; local gates are complete with only the proven main mobile-cycle warnings. The resolution review of5f2c39efb62found no issues, and its CI finished with 21 passed, 14 skipped and none failed (run); skips are not passes.Agent skill upstream boundary
Notes
Differences from the common pattern:
Temporary: a desktop app built from main between v1.4.222 and this change, connected to a newer host, can keep Send disabled for up to 2 minutes after rewinding past a
/clear; updating the app removes it. The existing timeout releases the hold and preserves its returned draft and history; the supported-client-floor cleanup removes this limitation.Intended: the current provider context lives in the record’s ordinary chain; a clear releases every earlier handle while the journal keeps visible conversation history. The boundary stays only for operations that need the identity of that clear.
Intended: earlier messages remain visible and rewind cannot cross the divider, per the product decision.
Intended: clear preserves the existing refusal while the agent is working and releases only an idle provider before resetting context.
Intended: ordinary waiting message cards require user action after clear, with exact membership and existing acceptance/Resume settlement; waiting command cards are withdrawn as in main.
Intended: the existing compact separator renders one completed boundary without another notice.
Intended: clearing a supervised worker discards its provider instruction preamble while task and custody identity remain; automatic reinjection is outside this change.
Temporary: old-host replacement readers remain for mixed remote client/host versions; remove them when supported hosts include in-place clear. Older clients can ignore the optional context floor and retain earlier goal/usage until new facts arrive; remove that limit when the supported-client floor advances.
Checklist