Repository navigation
fix(sessions): a reloaded child keeps its pointer to a closed, restorable parent - #1387
Merged
Merged
Conversation
…1373) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ew id Undo Close remapped pointers only on the rows it restored, so a restored parent's live orchestration and linked children kept the dead id and the parent could not list, read or prompt them. Both restore commits now map every live session through the restore's lineage (remapMetaLineage keeps unmapped ids, so a child of another still-closed pane keeps its link). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…torable parent (#1379) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…able parent #1379 (from #1374 review c): replace and Reload Agents dropped any relationship pointer whose target was neither live nor in their idMap; a parent closed but still on the undo stack is neither, so reloading its live child erased the link and undoing the parent later had nothing to relink. Both commits now treat the undo stack's restorable session ids as known (UndoCloseStack.restorableSessionIds, pruned like pop). A pointer to a parent nothing can restore is still dropped. Red before; each call site pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace now consults refs.undoStackRef for restorable parents (#1379); production refs always carry it, this test's partial mock did not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e the parent can never come back #1387 review a: - (major) keeping the pointer only helps if restoring the parent relinks it: #1374 is merged in (Depends on #1374) and an end-to-end test closes P, reloads its live child, undoes P and asserts the child names P' (red without #1374's remap). - (minor) a kept pointer lingered as a ghost when P's entry left the stack without a restore. dropPointersTo drops pointers to exactly those ids (never unrelated or cross-window ones) when an entry is consumed as stale/failed, expires or is evicted; the stack notifies on a microtask because prune can run inside a setState updater. Each path is pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sed-parent-pointer
…members restored after them #1387 review a, round 2: undo replays a group newest-first, so a parent consumed as stale (folder gone) could precede its child in the same group; the child then came back carrying pointers to a parent that can never return. The group remembers consumed ids and drops pointers to them once it has replayed. Review b, round 2: a hook-level test now proves the stack's expiry notification reaches the workspace (red without the listener). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a member the group consumed #1387 review a, round 3: when a group consumed parent P as stale and then hit a transient failure on child C, C went back on the stack with its entry metadata still naming P, and the retry restored that dead pointer. The leftover's metadata now drops pointers to the replay's consumed ids (dropEntryPointersTo). Red before, on the reviewer's exact sequence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Review disposition (head
Fixed
Every fix was red before it landed, on the reviewer's own sequence. Each guard was removed on its own, and each removal fails a test. Merge order: #1369, then #1374, then this PR. 🤖 Generated with Claude Code |
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.
Fixes #1379. Depends on #1374 (merged into this branch; merge #1374 first). Keeping the pointer only helps if restoring the parent relinks it, and that relink is #1374's.
Plan:
docs/plans/2026-09-27-replace-keeps-closed-parent-pointer.md(first commit).Problem
Replace (reload, provider switch, resume, rewind) and Reload Agents commit through
remapSessionsRelationships(sessions, idMap). That drops anylinkedParentId/orchestrationParentId/orchestrationRootIdwhose target is neither live nor in the idMap. A parent that is closed but still on the undo stack is neither. So reloading its live child erased the child's link, and undoing the parent later (#1374's relink) found nothing to relink: two live panes, permanently unlinked. Found by review c of #1374.What merges
UndoCloseStack.restorableSessionIds(): every session id a waiting entry could bring back (session, project and group members). It is pruned first, likepop(), so an expired entry never counts.knownSessionIds= live ids ∪ restorable ids, throughknownOrRestorable.dropPointersTodrops live pointers to exactly those ids, and never touches unrelated or cross-window pointers. That covers an entry consumed as stale or failed, one that expired, and one evicted past the cap. The stack reports expiry and eviction on a microtask, becauseprunecan run inside asetStateupdater.Tests
closedParentPointer.renderer.test.tsx:lib/undoClose.test.ts:restorableSessionIdsover session, tab and group entries, with expiry.undoCloseGhostPointers.renderer.test.tsx): a child restored after its parent was consumed, and a leftover pushed back for retry, both drop the dead pointer. An expiry notification reaches the workspace.dropPointersToand the stack's expiry and eviction notifications have unit tests.sessionRecovery.renderer.test.tsx: one hand-built refs mock now carriesundoStackRef. Production refs always do.02e03d92,npx tsc -bis clean, andsrc/renderer/src/workspace/hook+src/renderer/src/libpass (72 files, 476 tests).Related
🤖 Generated with Claude Code