Skip to content

fix(native-chat): preserve structured chat across rollback - #17439

Merged
brennanb2025 merged 2 commits into
mainfrom
brennanb2025/reland-chat-ui-rollback-compat
Aug 30, 2026
Merged

brennanb2025 merged 2 commits into
mainfrom
brennanb2025/reland-chat-ui-rollback-compat

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 4 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​254 $\color{#cf222e}{\Huge{\mathbf{−}}}$​2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​252
Prod 10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​141 $\color{#cf222e}{\Huge{\mathbf{−}}}$​38 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​103

Summary

  • Preserve visible structured Codex chat session identities in the durable agent-session store.
  • Restore from that identity index when an older profile parser drops contentType: agent-session tabs.
  • Remove the visibility reference on chat close while retaining the durable record and journal.
  • Await handoff reveal persistence so a failed compatibility write is observable.

Root cause

The workspace profile tab list was treated as the sole restoration identity for structured sessions. The pinned base release rejects the newer agent-session discriminator and salvages those entries away; after the base release rewrites the profile, re-upgrade can no longer discover the surviving records/journals.

This is a persistence ownership/lifecycle issue, not a reason to revert the structured-chat feature. The visible-tab reference now lives with the structured-session store, which older builds do not rewrite. Closed historical journals remain lazy and are not resurrected on startup.

Regression coverage

  • Automated target → pinned-base → target profile fixture.
  • Verifies target parsing, legacy discriminator salvage, durable record/journal survival, and target re-upgrade recovery identity.
  • Verifies deliberate close removes only the visible reference.
  • Verifies runtime startup prefers the durable visible-session index after profile tab loss.

Validation

  • pnpm tc
  • Focused Vitest suites (61 tests)
  • Changed-code quality gate
  • Oxlint
  • Oxfmt

ELI5

An older Orca build can erase structured-chat tabs it does not understand when it rewrites the profile. The visible chat IDs now live in the durable agent-session store, which the older build leaves alone, and that list is used when the app returns. Closing removes only the visible-tab pointer; the record and journal stay available, and open/close waits for the durable write.

Performance Measurement

This is a persistence-compatibility fix, not a throughput optimization, so no speedup is claimed. In the deterministic target-to-pinned-base-to-target fixture, profile-only restoration returns 0 session IDs after the base round-trip, while the durable index restores 1 ID and preserves the journal; closing leaves the durable record and an empty visible index. No timing claim is made.

User-Facing Trade-offs

There is no visible data-loss trade-off. Each visibility change now waits for one small durable whole-store transaction, which can add a little open/close latency; closed chats remain in history but are not resurrected. Stores without the new field retain the legacy profile fallback.

@greptile-apps

greptile-apps Bot commented Aug 30, 2026 •

Copy link
Copy Markdown

Greptile Summary

The PR adds a durable visible-session identity index so structured Codex chats can survive profile rewrites by older releases.

  • Stores visible structured-session IDs alongside durable agent-session records.
  • Uses the durable index during startup restoration and removes entries when chats close.
  • Awaits reveal and publication persistence so compatibility-write failures propagate.
  • Adds rollback, close, restoration, and serialization regression coverage.

Confidence Score: 4/5

The PR is not yet safe to merge because an interrupted startup can leave a partial durable index that hides otherwise recoverable structured chats on subsequent launches.

The startup path still treats any present durable visibility index as authoritative, while visibility entries are committed one session at a time during sequential publication; a failure after an earlier commit leaves later profile-backed sessions outside the index and therefore excluded from the next restoration.

Files Needing Attention: src/main/runtime/orca-runtime.ts

Important Files Changed

Filename Overview
src/main/runtime/orca-runtime.ts Selects the durable visibility index during startup and persists visibility around tab publication and closure; the previously reported partial-index restoration defect remains.
src/main/runtime/agent-session-record-store.ts Adds transactional APIs for reading and updating durable visible-session identities.
src/main/runtime/agent-session-record-store-file.ts Loads and saves the new optional visibility index within the durable session store.
src/main/runtime/agent-session-store-transaction-queue.ts Extends transaction change detection and rollback snapshots to include visibility state.
src/main/runtime/rpc/methods/structured-agent-session.ts Awaits visibility persistence during session publication and clears visibility after close.
src/main/native-chat/agent-session-wire/structured-agent-session-handoff-reverse.ts Awaits native-session reveal so persistence failures propagate through handoff.
src/main/runtime/structured-agent-session-rollback-compatibility.test.ts Exercises durable identity survival across target-to-base-to-target profile compatibility transitions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  P[Workspace profile session IDs] --> R[Startup restoration]
  I[Durable visible-session index] --> R
  R --> S[Restore readable sessions]
  S --> T[Publish structured tabs]
  T --> I
  C[Close structured chat] --> D[Remove durable visibility reference]
  D --> I
Loading

Reviews (2): Last reviewed commit: "fix(native-chat): preserve rollback visi..." | Re-trigger Greptile

: []
const profileIds = collectSavedStructuredAgentSessionIds(
this.store?.getWorkspaceSession?.(LOCAL_EXECUTION_HOST_ID) ?? null
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Partial index suppresses profile sessions

When startup restores legacy profile-backed sessions and publication fails after persisting only some visibility entries, the next startup selects that incomplete durable index instead of merging it with profileIds, causing the omitted structured chats to disappear even though their records and profile tabs remain durable.

Knowledge Base Used:

@coderabbitai

coderabbitai Bot commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 94032ad9-6fc9-45fd-af16-93ebd6a2815a

📥 Commits

Reviewing files that changed from the base of the PR and between 99aa616 and 12368f6.

📒 Files selected for processing (12)
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/runtime/agent-session-record-store-file.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/agent-session-recovery-publish-fault.test.ts
  • src/main/runtime/agent-session-store-serialization.ts
  • src/main/runtime/agent-session-store-transaction-queue.ts
  • src/main/runtime/agent-session-visible-tab-index.ts
  • src/main/runtime/orca-runtime-structured-session-restore.test.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/rpc/methods/structured-agent-session.test.ts
  • src/main/runtime/rpc/methods/structured-agent-session.ts
  • src/main/runtime/structured-agent-session-rollback-compatibility.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/main/runtime/agent-session-record-store-file.ts
  • src/main/runtime/structured-agent-session-rollback-compatibility.test.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/agent-session-store-serialization.ts
  • src/main/runtime/rpc/methods/structured-agent-session.ts
  • src/main/runtime/orca-runtime.ts

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


📝 Walkthrough

Walkthrough

The agent-session store now persists visible session IDs with schema-aware parsing, conditional serialization, change detection, and transactional rollback. The session host exposes the visibility index and updates. Runtime publication and closure await visibility changes. Native-session handoff and RPC publication await asynchronous operations. Restoration uses persisted visible session IDs when the index is present. Tests cover empty indexes, RPC closure, and rollback round trips.

Merge Risk: 🟡 Moderate · up to 12368

Closing a structured chat can currently hide a session using a caller-supplied ID without an established ownership check, and one failed visibility write during startup can prevent the remaining chats from being restored for that launch. The underlying records remain retained, but these bounded security and availability risks should be addressed or explicitly accepted before merging.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the root cause, implementation, regression coverage, and validation. However, it omits required template sections, including the linked issue, visual proof or an N/A explanati… Add the missing template sections. Include a valid linked issue after “Fixes #”. For this behavior change, attach before-and-after visual proof or write “N/A” with a reason. Complete the testing, review, boundary, notes, and checklist secti…
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 13 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: preserving structured chat across rollback. It is concise and specific.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the root cause, implementation, regression coverage, and validation. However, it omits required template sections, including the linked issue, visual proof or an N/A explanation, testing checkboxes, AI disclosure, review, boundary, notes, and checklist.

Resolution

Add the missing template sections. Include a valid linked issue after “Fixes #”. For this behavior change, attach before-and-after visual proof or write “N/A” with a reason. Complete the testing, review, boundary, notes, and checklist sections.

Full details: Docstring Coverage

Explanation

Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 13 files. (1 skipped: 1 too large.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 81078d31-bbab-4359-94ee-f51355ad0ed4

📥 Commits

Reviewing files that changed from the base of the PR and between c539b38 and 99aa616.

📒 Files selected for processing (13)
  • src/main/native-chat/agent-session-wire/structured-agent-session-handoff-reverse.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-handoff-types.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/runtime/agent-session-record-store-file.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/agent-session-recovery-publish-fault.test.ts
  • src/main/runtime/agent-session-store-serialization.ts
  • src/main/runtime/agent-session-store-transaction-queue.ts
  • src/main/runtime/agent-session-visible-tab-index.ts
  • src/main/runtime/orca-runtime-structured-session-restore.test.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/rpc/methods/structured-agent-session.ts
  • src/main/runtime/structured-agent-session-rollback-compatibility.test.ts

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

Comment on lines +10241 to +10249
private async closeStructuredAgentSessionTab(
worktreeId: string,
snapshot: RuntimeMobileSessionTabsSnapshot,
tab: RuntimeMobileSessionAgentTab
): void {
): Promise<void> {
const host = getStructuredAgentSessionHost()
if (typeof host?.setSessionTabVisibility === 'function') {
await host.setSessionTabVisibility(tab.sessionId, false)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- repository conventions and learnings ---'
find /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4 -maxdepth 2 -type f -name '*.md' -print
printf '%s\n' '--- relevant source symbols ---'
rg -n -C 8 \
  'closeMobileSessionTab|closeStructuredAgentSessionTab|setSessionTabVisibility|restoreStructuredAgentSessionTabsOnce|listPersistedVisibleSessionIds|collectSavedStructuredAgentSessionIds|publishStructuredAgentSessionTab' \
  src/main/runtime/orca-runtime.ts src

Repository: stablyai/orca

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- applicable conventions ---'
cat /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4/conventions/repo-wide.md
cat /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4/conventions/src.md
cat /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4/conventions/mobile.md
printf '%s\n' '--- runtime learnings ---'
cat /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4/learnings/src-main-runtime.md
printf '%s\n' '--- close caller and helper ---'
sed -n '9883,10145p' src/main/runtime/orca-runtime.ts
printf '%s\n' '--- visibility store implementation ---'
sed -n '1,180p' src/main/runtime/agent-session-record-store.ts
printf '%s\n' '--- host binding and type ---'
sed -n '1,220p' src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
rg -n -C 5 'getStructuredAgentSessionHost|StructuredAgentSessionHost' src/main

Repository: stablyai/orca

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- transaction failure semantics ---'
rg -n -C 12 'class AgentSessionStoreTransactionQueue|transact\(|persist|readOnly|setSessionTabVisibility' \
  src/main/runtime/agent-session-store-transaction-queue.ts \
  src/main/runtime/agent-session-record-store.ts \
  src/main/runtime/*test.ts
printf '%s\n' '--- structured-tab close tests and failure cases ---'
rg -n -C 12 'agent-session|structured.*close|visibility|setSessionTabVisibility|closeMobileSessionTab' \
  src/main/runtime/orca-runtime.test.ts \
  src/main/runtime/*test.ts | head -n 1200
printf '%s\n' '--- host accessor and notifier contract ---'
rg -n -C 8 'function getStructuredAgentSessionHost|const getStructuredAgentSessionHost|export .*getStructuredAgentSessionHost|closeSessionTab:' \
  src/main

Repository: stablyai/orca

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- transaction queue files ---'
fd -i 'transaction.*queue|agent-session.*store.*test|orca-runtime.test' src/main/runtime
printf '%s\n' '--- transaction queue implementation ---'
sed -n '1,260p' src/main/runtime/agent-session-store-transaction-queue.ts
printf '%s\n' '--- exact structured-session close test matches ---'
rg -n -i -C 6 'structured agent session|agent session tab|session tab visibility|setSessionTabVisibility' \
  src/main/runtime/orca-runtime.test.ts \
  src/main/native-chat/agent-session-wire \
  src/main/runtime/agent-session-record-store*.test.ts
printf '%s\n' '--- host accessor definitions ---'
rg -n -C 10 'getStructuredAgentSessionHost' src/main/runtime/orca-runtime.ts src/main/native-chat

Repository: stablyai/orca

Length of output: 20101


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- close-session notifier contract and implementations ---'
rg -n -C 12 'closeSessionTab|setNotifier\(' src/main/runtime/orca-runtime.ts src/main
printf '%s\n' '--- compatibility and failure-policy comments ---'
rg -n -i -C 8 'compatibility-write|compatibility.*fail|write.*fail|durable.*fail|retry.*close|close.*retry|visibility' \
  src/main/runtime src/main/native-chat/agent-session-wire \
  --glob '*.ts' --glob '*.md' | head -n 1600
printf '%s\n' '--- focused runtime tests near structured-session support ---'
rg -n 'setStructuredAgentSessionHost|StructuredAgentSessionHost|publishStructuredAgentSessionTab|structuredAgentSessionTab' \
  src/main/runtime/orca-runtime.test.ts src/main/runtime/*.test.ts

Repository: stablyai/orca

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- focused structured-session restore tests ---'
sed -n '1,330p' src/main/runtime/orca-runtime-structured-session-restore.test.ts
printf '%s\n' '--- relevant runtime comments and persistence calls ---'
rg -n -C 10 'compatibility|durable|visibility|publishStructuredAgentSessionTab|closeStructuredAgentSessionTab' \
  src/main/runtime/orca-runtime.ts
printf '%s\n' '--- persistence failure tests ---'
rg -n -C 8 'saveAgentSessionStore|mockRejected|reject|readOnly|transaction' \
  src/main/runtime/agent-session-record-store.test.ts \
  src/main/runtime/agent-session-record-store-security.test.ts \
  src/main/runtime/agent-session-store-transaction-queue.ts

Repository: stablyai/orca

Length of output: 50369


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- non-test closeSessionTab implementations ---'
rg -n -C 10 'closeSessionTab' src --glob '*.ts' --glob '*.tsx' --glob '!*.test.ts'
printf '%s\n' '--- durable-commit ordering precedent ---'
sed -n '32455,32478p' src/main/runtime/orca-runtime.ts
printf '%s\n' '--- exact transaction rollback lines ---'
sed -n '72,145p' src/main/runtime/agent-session-store-transaction-queue.ts

Repository: stablyai/orca

Length of output: 18528


Commit durable visibility before closing the renderer tab

When setSessionTabVisibility fails, closeMobileSessionTab has already closed the renderer tab, but closeStructuredAgentSessionTab has not removed the runtime tab. AgentSessionStoreTransactionQueue also restores visibleSessionIds when the transaction fails. The next restore can therefore republish the closed tab. Commit the durable hide before the renderer close, or reconcile the close after a failed write.

Comment thread src/main/runtime/orca-runtime.ts Resolved
sessionId = sessionId.slice('agent-session:'.length)
}
this.publishStructuredAgentSessionTab({
await this.publishStructuredAgentSessionTab({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Isolate per-session failures in the startup restore loop.

This call now awaits publishStructuredAgentSessionTab, which itself awaits a durable write (host.setSessionTabVisibility). The enclosing for loop has no try/catch. If the write rejects for one session, the rejection propagates out of restoreStructuredAgentSessionTabsOnce, and every subsequent session in host.listSessionTabs() is skipped for the rest of this startup.

A single failing write during startup restoration should not block restoring every other structured chat session. Wrap this call in a try/catch so one failure logs a warning and lets the loop continue.

🛡️ Proposed fix to isolate per-session restore failures
     for (const session of host?.listSessionTabs() ?? []) {
       if (session.agent !== 'codex') {
         continue
       }
       let sessionId = session.sessionId
       while (sessionId.startsWith('agent-session:')) {
         sessionId = sessionId.slice('agent-session:'.length)
       }
-      await this.publishStructuredAgentSessionTab({
-        ...session,
-        agent: 'codex',
-        sessionId,
-        activate: false,
-        notify: false
-      })
+      try {
+        await this.publishStructuredAgentSessionTab({
+          ...session,
+          agent: 'codex',
+          sessionId,
+          activate: false,
+          notify: false
+        })
+      } catch (error) {
+        console.warn('[structured-agent-session] failed to restore session tab', {
+          sessionId,
+          error
+        })
+      }
     }
📝 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.

Suggested change
await this.publishStructuredAgentSessionTab({
for (const session of host?.listSessionTabs() ?? []) {
if (session.agent !== 'codex') {
continue
}
let sessionId = session.sessionId
while (sessionId.startsWith('agent-session:')) {
sessionId = sessionId.slice('agent-session:'.length)
}
try {
await this.publishStructuredAgentSessionTab({
...session,
agent: 'codex',
sessionId,
activate: false,
notify: false
})
} catch (error) {
console.warn('[structured-agent-session] failed to restore session tab', {
sessionId,
error
})
}
}

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The fix is sound for the happy path, but its rollback guarantee rests on an assumption that is not enforced anywhere: that the pinned base release never rewrites agent-sessions.json. One section below explains, plus two smaller error-ordering points inline.

Reviewed changes

A single commit that moves the "which structured chat sessions are visible" identity out of the rollback-rewritten profile and into the durable agent-session store, so a pinned-base → target round trip no longer loses the visible-tab index.

  • Durable visible-session index — AgentSessionStoreState gains a visibleSessionIds set, parsed (parseVisibleSessionIds) and serialized (agent-session-store-serialization.ts) with schema-tolerant validation.
  • Store API — listVisibleSessionIds (filtered to surviving records) and setSessionTabVisibility (throws agent_session_identity_required when marking a missing record visible).
  • Runtime wiring — restore prefers the durable index when non-empty, close clears the visibility reference, publish and handoff-reveal now await the persistence.
  • Regression coverage — a target → pinned-base → target fixture plus a restore-preference unit test.

⚠️ visibleSessionIds rides on schema v2, so the read-only protection never engages

The new field is added to AGENT_SESSION_STORE_SCHEMA_VERSION = 2 without a bump. The store's existing forward-compat safety net (readOnly = schemaVersion > AGENT_SESSION_STORE_SCHEMA_VERSION, which makes an older build "read but never write") is therefore not triggered: any build that shares schema v2 but predates this PR will parse the file, ignore the unknown visibleSessionIds key, and — on its next lease renewal or journal write — serialize the store without it, silently erasing the index this PR depends on.

The entire fix hinges on the pinned base release having no agent-session-record-store code at all (so it never touches the file). That may well be true given the reland history, but nothing in this PR enforces or tests it: pinnedBaseRoundTrip in the compatibility test only rewrites the profile (unifiedTabs) and never simulates an older build rewriting the store file, so the load-bearing assumption is unverified.

Technical details
# visibleSessionIds durability across rollback

## Affected sites
- src/main/runtime/agent-session-record-store-file.ts:32 — schema version stays 2 while a new durable field is introduced
- src/main/runtime/agent-session-store-serialization.ts:15 — writes the new field under schema v2
- src/main/runtime/structured-agent-session-rollback-compatibility.test.ts:102 — simulates base only via profile rewrite, never a store rewrite

## Required outcome
- Confirm the pinned base release contains no agent-session-record-store code (it can never rewrite agent-sessions.json), and document that assumption, or
- Bump AGENT_SESSION_STORE_SCHEMA_VERSION and add a v2 → v3 migration, so every older build treats the file as read-only and cannot drop the field.

## Suggested approach (optional)
- Note parseState rejects schemaVersion < current (returns null → agent_session_store_corrupt), so a bump requires a migration that admits v2 files and rewrites them as v3.

## Open questions for the human
- Between the pinned base and this PR, is there any released build that has schema-v2 store code but not visibleSessionIds? If so, a user rolling back through it loses the index today.

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

}
context.releaseOwner(sessionId)
deps.transport?.revealNativeSession?.({
await deps.transport?.revealNativeSession?.({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

revealNativeSession is now awaited after the durable handoff has already committed (reserveStoredAgentSessionHandoffOwner + acquireNative succeeded and releaseOwner ran). If the visibility write inside it fails, this throws and reports a failed handoff even though the record is already native-owned — and the retry path then re-reads a record whose handoffStage no longer matches a retryable state, which can wedge the session. Since the durable handoff is already complete here, consider logging the reveal failure instead of propagating it, or move the visibility persistence before the final commit.

}): Promise<void> {
const host = getStructuredAgentSessionHost()
if (typeof host?.setSessionTabVisibility === 'function') {
await host.setSessionTabVisibility(input.sessionId, true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

setSessionTabVisibility(true) is awaited before the duplicate-tab early return and can now throw (agent_session_identity_required, or a store write failure) where publishStructuredAgentSessionTab was previously a fire-and-forget void. That propagates into two places that used to be infallible: the agentSession.create RPC (session already attached, so the client sees an error for a successful create) and the restoreStructuredAgentSessionTabsOnce loop (one failure aborts restoration of all remaining tabs). Confirm that's the intended failure surface — for the RPC path especially, the create has already durably succeeded, so failing it over the secondary visibility write is a surprising outcome.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review completed on commit 12368f6306 (fix(native-chat): preserve rollback visibility state).

Findings addressed:

  • Persisted visible-tab state now distinguishes an absent legacy index from an explicitly empty index, preserving rollback semantics.
  • agentSession.close clears durable visibility for terminal-disposal paths that bypass session-tab retirement.
  • Added focused regression coverage.

Validation:

  • Focused runtime/structured-session tests: 27 passed.
  • pnpm tc: passed.
  • Changed-file oxlint and pre-commit hooks: passed.
  • Start readiness-checklist: no proven P0/P1/P2 issues; no mobile-facing surface.
  • Final readiness pass could not complete because the replacement worker stopped delivering; no new issue was observed in the final diff.
  • Electron/Grok validation was attempted with the Electron skill, but CDP endpoints timed out, so no rendered screenshot was attached. Computer-use fallback was not used.

Recommendation: land after acknowledging the Electron validation gap; CI checks are still completing.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ Increment reviewed — the present flag cleanly fixes the empty-index fallback and the close path now clears visibility. No new issues in these commits; the three previously-flagged concerns (schema-v2 durability, and the two error-ordering points) are unchanged by this delta and remain open.

Reviewed changes

  • Absent-vs-empty durable index — AgentSessionStoreState.visibleSessionIdsIndexPresent records whether the visibleSessionIds field was ever committed, and serialization emits the field only once set, so startup can distinguish a never-written index (migrate from profile tabs) from an intentionally empty one (closed sessions stay closed).
  • Close clears the durable visibility reference — agentSession.close additionally calls setSessionTabVisibility(sessionId, false), covering terminal-disposal closes that skip the session-tabs retirement RPC.
  • Regression coverage — the target → pinned-base → target fixture now asserts the present transitions, alongside an empty-index-authoritative restore test and an RPC-close-clears-visibility test.

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

@brennanb2025

Copy link
Copy Markdown
Contributor Author

CI update for commit 12368f6306: the run has one substantive failure, package (windows), in the unrelated src/main/cursor/hook-service.test.ts. The test timed out spawning cmd.exe (spawnSync cmd.exe ETIMEDOUT) while 206 other Windows-boundary tests passed. The verify job failed only because it requires package (windows) to succeed.

All native-chat-focused tests, typecheck, static analysis, wire compatibility, package, and Linux test shards are passing. This PR does not touch the Cursor hook path, so this currently looks like a Windows CI/environment flake rather than a regression. I have not changed code or expanded scope.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Readiness update: the failed Windows check was rerun successfully. package (windows) passed, verify passed, and GitHub now reports the PR as CLEAN and mergeable.

The PR is attached to Linear ticket STA-5930.

@brennanb2025
brennanb2025 merged commit cad9206 into main Aug 30, 2026
59 of 61 checks passed
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Electron validation (landed commit 12368f6306)

Validated in this worktree’s Orca Dev instance via Playwright CDP (no computer-use). Identity: permit @ brennanb2025/reland-chat-ui-rollback-compat on renderer 127.0.0.1:5178 / CDP 9335. Dock tile Orca/ brennanb2025-reland-chat-ui-rollback-compat was present.

Visible behavior: enabled Chat UI + structured native chat in Settings, launched Codex from New tab, got a Codex Chat tab with the native empty state and composer, then closed that tab through the tab-bar close control. After close, only Terminal 1 remained.

Backing state: while visible, agent-sessions.json had visibleSessionIds: ["codex_3a5722a5_…"] and the workspace profile had contentType: "agent-session". After close, visibleSessionIds stayed present as [], the durable record and journal remained, and the profile tab was gone. Matches the intended close/visibility contract.

Gap: live target → pinned-base → target binary rollback was not exercised (needs the older profile parser). No product regression found on the exercised create/close path.

Codex Chat visible (uncropped)

02-codex-chat-visible.png

After close (uncropped)

03-codex-chat-closed.png

enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…17439)

* fix(native-chat): preserve structured tabs across rollback

* fix(native-chat): preserve rollback visibility state

---------

Co-authored-by: Merge Sim <sim@local>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant