fix(window): preserve scoped session delivery across window transitions - #935
Merged
Merged
Conversation
Keep unknown-owner observations out of unrelated windows and retain bounded, ordered delivery only for recognized view lifetimes. Revisioned claims protect reload, handoff and delayed cleanup; recovery grants a display claim only after backend target admission. Read-only repair reseeds observable state and scoped history while keeping transient loss visible. Refs #920 Refs #918
Two conflicts, both from the unified stage (#1013): - PaneHeader: main deleted the related-agent strip and with it this header's only store read. The routing-gap notice this branch adds is the remaining reader, so it keeps the store import and subscribes to exactly one rare object on the displayed session. - ARCHITECTURE 8.2.1: main rewrote the section around a per-channel IPC table and kept the old sentence saying a session without recorded ownership is broadcast to every window. That fallback is the thing this branch removes, so its paragraphs replace that sentence and the table stays. Also: the routing-recovery test's WorkspaceState fixture still named `dispatchMode`, `detachedSessions` and `buried`, all gone with the unified stage, and `stage` is now required. Verified on the merge: npx tsc -b clean; the branch's six suites pass (78 tests) and the tile-tree suites pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ent repair stops offering itself Codex review of #935, two findings: 1. P1. session:kill-owned released the display claim whatever the manager answered. killOwned returns false for two different situations: nothing left to close, and "you do not own that backend" — a stale pane whose saved cwd or provider no longer matches. In the second, releasing revoked a RUNNING session's only owner, and since this branch removes the broadcast fallback its output was quarantined with no owner left to even show the gap: the pane went quiet. The release now needs the close to have happened, or the backend to be gone, which is the same evidence killOwned checks. The composition test drives the real manager through a refused close and then a real one. 2. P2. A successful refresh acknowledges and DELETES the main-process gap ticket, so pressing "Refresh view" again could only return stale — permanently so once an ordinary recovery (a terminal remount) minted a new ownership revision. The pane keeps the warning, because that output is gone for good, but stops offering a repair it cannot perform; a later incident issues a new ticket and the control returns with it. The existing refresh test asserted a second click re-ran the repair, which held only because its resync mock ignores the ticket. It now pins the real contract: no control after a spent repair, the control back on a new gap, and no duplicated entries when the repair replays. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ent only on a finished repair Codex delta review of #935: 1. P1. My previous fix asked for a backend snapshot to decide "nothing left to close". Mid-handoff a Codex predecessor HAS no snapshot while its replacement reservation still owns it, and if the successor's startup then fails, compensation restores the predecessor — whose display claim had already been released, so its output went nowhere. SessionManager now answers the question directly: retainsSessionOwnership consults the same four tables killOwned does (live entries, recoveries in flight, replacement reservations, redirects). 2. P2. The resync handler acknowledged — and therefore DELETED — the repair ticket before the renderer had read saved history. A failed read then left the pane on "refresh is unavailable" with a button whose ticket was gone, and an ordinary recovery rotated ownership so every later press returned stale. The ticket is now spent where the repair actually completes: on a seed with no history to read, or on a successful history read. Tests: a reserved-but-snapshotless session keeps its claim through a refused close; the seed keeps the ticket and the failed read keeps it while the successful read spends it. Both fail against the previous behaviour. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A session without a window owner previously broadcast its content to every window. Closing/reloading windows and delayed cleanup could also lose final output or release a newer owner. This change requires an explicit claim for session delivery and makes unrecoverable observation gaps visible in the affected pane.
Validation:
npm run test:packagepassed on the final implementation, including desktop/remote builds, the universal hotkey helper and required-entry-point verification.Limits: no live multi-window/PTY smoke was performed. Queue byte limits are admission estimates, not measured heap. Native source evidence uses the current manager's observable fields; unobserved native resets, in-place transcript rewrites and producer epochs across the remaining coalescers are still B12 work under #918. History is a bounded suffix, and missing transient output remains explicit. Runtime archives were not downloaded, so build verification is not a signed-release smoke test. No package pin changed.
Fixes #920
Refs #918
Independent B01 slice of #931, based on
552914f5; does not include or assume merge of tmux PR #933. The focused implementation plan is the branch's first commit. Main subsequently advanced to115e26fcvia the skills/TLDR features; the changed composition lines were inspected and do not overlap this routing wiring. CI must verify the current PR merge revision. Nothing is merged by this PR creation.CI verification: both
quality-gateandminimum-node-fixture-gatepassed on head150328459a6ac392e54070e4a66e4c7d340c2c65, run 34718213663. Review-ready; no merge performed.