Repository navigation
fix(window_panel): dispose outgoing tree tabs in clearAllPanels - #1344
Conversation
|
CI note: the only red on this PR is a pre-existing macos timing flake — expected to clear on a failed-job re-run.
Everything else: 8/10 checks green, MERGEABLE. A re-run of the failed job should clear it (PR-author tokens cannot re-run repo workflows). |
bdcf620 to
bc9aa3b
Compare
clearAllPanels replaced the split tree wholesale, dropping the old root's BossTabsComponents without destroying their tabs' lifecycles. For browser and terminal tabs those lifecycle destroys are what release the Chromium process and the shell process, so every applyWorkspace over an unpreserved tree leaked one native process per open tab - compounding across workspace restores and applies (risa-labs-inc#1310). The outgoing tree is now disposed through clearAllTabs() on every panel before the fresh main panel is assigned - the same path closeCurrentWorkspace already uses - guarded by an identity check: a tree still held by preserveCurrentState is exempt, because it has to survive to be restored on switch-back and keeps moving live tabs through moveTabToWorkspace while preserved. Tests use a destroy-counting tab component to cover disposal of an unreferenced tree, survival of a preserved one, and disposal across a split outgoing tree. Fixes risa-labs-inc#1310
93ee88e to
8cbad70
Compare
|
Fresh CI on 8cbad70: build-test (macOS/Ubuntu/Windows), code quality, compatibility, database, contracts, version, and shell checks all passed. Ready for re-review. |
|
Merged to dev (squash). Gate: full CI green on the merge preview (10/10 checks) + maintainer diff verification - clearAllPanels now disposes the outgoing tree's tabs before reassigning _rootNode, releasing browser/terminal native processes (#1310), and the exemption for a tree still held by preserveCurrentState is explicit so switch-back keeps working. The new test pins both the disposal and the preserved-tree survival. No follow-ups filed. Thanks @Mihir-Rabari! |
Root cause
SplitViewState.clearAllPanelsreset the split tree by assigning a freshSplitNode.Panel("main")to_rootNodeand nothing else. The outgoing root'sBossTabsComponents were simply dereferenced: their tabs'LifecycleRegistrys stayed RESUMED, soonDestroynever fired - and for browser and terminal tabs those handlers are what release the Chromium process and the shell process. SinceWorkspaceApplier.applyWorkspacecallsclearAllPanels()between every apply (#1310), each restore over an unpreserved tree leaked one native process per open tab, compounding across session restores and workspace applies.Design
The outgoing tree is disposed before the fresh main panel is assigned, using the exact primitive
closeCurrentWorkspacealready uses -clearAllTabs()on every panel - so per-tab lifecycle destruction (removeTab(i, recordForOpen = false)->tabLifecycles.remove(it.id)?.destroy()) finally fires for the dropped tree.One guard makes this safe: disposal is skipped when the outgoing root is still identity-held by
preservedWorkspaceStates. A tree kept bypreserveCurrentStatemust survive to be restored on switch-back, and its live tabs keep moving throughmoveTabToWorkspaceandcollectAllActiveTabswhile preserved - destroying them would break the cross-workspace switch thatSplitViewWorkspaceTransferTestandSplitViewActiveTabsTestpin. The identity check (it.rootNode === outgoingRoot) distinguishes the two cases without touching any preserved-state semantics.getAllPanels()is read before_rootNodeis reassigned, so it walks exactly the outgoing tree.Tests
New
SplitViewClearAllPanelsDisposalTestwith a destroy-counting tab component (lifecycleonDestroy-> counter):clearAllPanels destroys outgoing tree tabs when no preserved state holds it- both tabs of the old root destroyed exactly once; fresh main panel starts empty.clearAllPanels keeps a preserved outgoing tree alive for switch-back- a tree recorded bypreserveCurrentStatekeeps its tab undestroyed and reachable throughpanelsInWorkspace.clearAllPanels disposes every panel of a split outgoing tree- disposal covers both panes of a vertical split.Gates
One
gradlew --offline ktlintCheck :composeApp:detekt :composeApp:desktopTest --tests 'ai.rever.boss.components.window_panel.*' --max-workers=2invocation:Full
ai.rever.boss.components.window_panel.*filter green - 222 tests completed, 0 failures (all pre-existing suites unchanged, including the preserved-workspace and transfer pins).Fixes #1310