Skip to content

perf(persistence): persist a matching terminal binding without re-applying it - #31033

Open
AmethystLiang wants to merge 1 commit into
mainfrom
perf-binding-design
Open

AmethystLiang wants to merge 1 commit into
mainfrom
perf-binding-design

Conversation

@AmethystLiang

@AmethystLiang AmethystLiang commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​287 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​286
Prod 5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​66 $\color{#cf222e}{\Huge{\mathbf{−}}}$​12 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​54

ELI5

When a terminal reattaches and Orca already knows the right answer, it was still making two full backup copies of your whole saved session "just in case it had to undo", then saving. Now it skips the pointless copies and just saves.

What Changed

Before: a terminal reattach whose binding already matched memory, but whose session had not yet reached disk (for example, right after an unrelated settings edit), was treated like a real change. It scanned for conflicts, cloned the whole selected-host session, re-applied equal values, and cloned it again to keep for rollback.

After: that case is recognised as "already correct, only needs saving". It marks the selected session domain dirty and lets the existing writer persist it. No apply, no conflict scan, and no binding snapshots. Anything that actually changes a binding takes the old path unchanged.

Mechanism:

  • pty-binding-fast-lane.ts: new defaults_not_applied miss, so a binding without the defaults guard still goes through the repair path (clean and dirty requests alike).
  • pty-binding-persistence.ts + new pty-binding-durability-only.ts: when the only miss is not_durable, mark workspaceSession (local) or workspaceSessionsByHostId (SSH/runtime) dirty and return a success result with a no-op rollback. The no-op rollback keeps the writer's failure publication to listeners without restoring anything.
  • pty-binding-owner-conflict-report.ts: the existing report-only conflict scan, moved out unchanged to keep pty-binding-persistence.ts under the line limit.
  • pty-binding-span.ts: bounded binding.path attribute (durable_match, durability_only, mutation); successful dirty matches share the existing sampling budget with clean fast-lane hits.

Unchanged: the writer, queue, generation semantics, serializers, notification order and scope, finalization, and actual-mutation rollback.

Why

The cost scales with total session size, not with the one terminal being reattached, because both snapshots clone every workspace and every saved scrollback buffer, and both stay alive for the whole disk wait.

Alternatives not taken: awaiting pendingWrite (it swallows errors and may cover older work, so it could acknowledge a binding that was never saved) and enqueueing a flush from inside the operation (it would wait behind itself). Reusing the existing in-operation capture keeps the writer's failure and acknowledgement result.

Measured impact

Dirty-match reattach, real writer worker and SQLite, baseline a282409d20f vs this change, alternating runs, median of runs, 20 trials each:

Session Reattach p50 before → after Memory churned per request
Copy of a real profile (1075 workspaces, 2205 tabs, 7 MB, local only) about 160 → 55 ms about 200 → 29 MB
10000 minimal workspaces 37.6 → 17.8 ms 20 → 8 MB
1059 minimal workspaces no measurable change 2.5 → 1.1 MB
1 workspace no change none
40 tabs holding 16 MiB of scrollback 100–114 → 71–91 ms local 94 → 63 MB
  • Full-session copies per request: 2 → 0 in every case. Data written to disk is unchanged (for example 7.0 MB both ways), and a 100-request burst still does one captured write.
  • Typical users with a small session will not notice a difference. The gain is for large or tab-heavy sessions.
  • Caveats: run under vitest (not Electron) on one development machine with other apps running, so absolute numbers are noisy. Main-thread stall, remote partitions of the real profile, and Electron-hosted runs were not measured. The benchmark harness is not part of this PR.

Linked Issue

N/A. Maintainer performance work, no pre-existing issue.

Visual Proof

N/A. No UI or interaction change; this is persistence-internal.

Testing

  • pnpm tc:node, pnpm lint, and pnpm run check:code-quality:changed pass.

  • Tests pass for the fast-lane predicate, flush and save scheduling, durable writes (including the new matching-durability suite), maintenance contracts, host-partitioned SSH bindings, SSH replay, and the binding span.

  • New coverage: defaults-guard miss on clean and dirty requests; a dirty match on local and SSH hosts clones nothing and ends up durable; getter edits with settings-only dirty intent are captured under paused acknowledgement; later state and failure publication are preserved; span sampling keeps failures and refusals.

  • Platforms: persistence logic only, with no path or process handling, so it is platform-independent. SSH and runtime partitions are covered by tests. I did not launch the app.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

Notes

  • Security: no new data leaves the process; span attributes stay low-cardinality with no ids or paths.
  • Remote SSH / folder workspaces: host partitions stay separate; folder-workspace ids are matched exactly.
  • Backwards compatibility: no persisted-schema, wire, or RPC change.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered
  • pnpm lint, pnpm typecheck, and the relevant tests pass locally

…lying it

A reattach whose binding already matches memory but is not yet on disk now
only marks the selected session domain dirty and relies on the writer to
persist it, instead of cloning the whole session twice for rollback and
re-applying equal values. Adds a defaults-guard miss to the fast-lane
predicate and a binding.path span attribute.
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b1b2940c-9ee6-429a-9bdd-9a52375bcf89
📥 Commits

Reviewing files that changed from the base of the PR and between db6b3fd and c49d758.

📒 Files selected for processing: 10
  • src/main/persistence-flush-and-save-scheduling.test.ts
  • src/main/persistence/loading-store/profile-state-durable-writes.test.ts
  • src/main/persistence/loading-store/pty-binding-durability-only.ts
  • src/main/persistence/loading-store/pty-binding-fast-lane.test.ts
  • src/main/persistence/loading-store/pty-binding-fast-lane.ts
  • src/main/persistence/loading-store/pty-binding-matching-durability.spec.ts
  • src/main/persistence/loading-store/pty-binding-owner-conflict-report.ts
  • src/main/persistence/loading-store/pty-binding-persistence.ts
  • src/main/persistence/loading-store/pty-binding-span.test.ts
  • src/main/persistence/loading-store/pty-binding-span.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

The change adds a defaults-applied guard to PTY binding fast-lane eligibility. It handles durability-only matches by marking the relevant workspace-session domain dirty without mutating the binding. Persistence spans now classify durable matches, durability-only operations, and mutations, with sampling for flushed durability-only spans. Tests cover these paths and related persistence scheduling behavior.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to c49d7

No identified issue blocks merging after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 10 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main performance change: persisting an already-matching terminal binding without re-applying it.
Description check Passed The description is complete and relevant. It covers the user-facing behavior, implementation, rationale, measured impact, testing, platform considerations, linked-issue exception, and checklist items.…
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 is complete and relevant. It covers the user-facing behavior, implementation, rationale, measured impact, testing, platform considerations, linked-issue exception, and checklist items. The omitted manual test checkbox and lack of a separate Review section do not prevent approval because automated coverage and maintainer context are documented.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant