mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 00:03:52 +00:00
fix(ssh): hoist copies of partition panes, not references to them
The hoist spread the partition's own tab and layout objects into the local session, so both planes held the SAME objects. That defeats `arbitratedFrom: 'local'`, which exists precisely so a decision read from one plane cannot mutate the other: `tab.ptyId = null` scoped to local silently cleared the partition's binding too, and the next flush persisted it — stranding a shell whose owner never voted on that decision. The alias became permanent when the partition delete was replaced with a per-tab stamp. Double-mutation itself was benign (every both-plane mutator is idempotent); the harm is the leak of plane isolation. Cloning also stops each hoisted tab being serialized twice. Nothing depends on cross-plane object identity — lease comparisons key on lease objects the hoist never touches, and tab/layout lookups go by id or leafId. Mutation-proofed: restoring the alias reddens the new isolation test.
This commit is contained in:
+13
-2
@@ -2908,7 +2908,14 @@ export function hoistSshPartitionsIntoLocalSession(
|
||||
if (missing.length === 0) {
|
||||
continue
|
||||
}
|
||||
local.tabsByWorktree = { ...local.tabsByWorktree, [worktreeId]: [...existing, ...missing] }
|
||||
// Cloned, not aliased. Spreading the partition's own tab objects in leaves both planes
|
||||
// holding the SAME object, so a mutation scoped to `local` — the whole point of
|
||||
// `arbitratedFrom` — silently rewrites the partition too, stranding a shell whose owner
|
||||
// never voted on that decision.
|
||||
local.tabsByWorktree = {
|
||||
...local.tabsByWorktree,
|
||||
[worktreeId]: [...existing, ...missing.map((tab) => structuredClone(tab))]
|
||||
}
|
||||
for (const tab of missing) {
|
||||
alreadyHoisted.add(tab.id)
|
||||
}
|
||||
@@ -2925,7 +2932,11 @@ export function hoistSshPartitionsIntoLocalSession(
|
||||
if (!hasTab) {
|
||||
continue
|
||||
}
|
||||
local.terminalLayoutsByTabId = { ...local.terminalLayoutsByTabId, [tabId]: layout }
|
||||
// Cloned for the same reason: a shared layout leaks `ptyIdsByLeafId` edits across planes.
|
||||
local.terminalLayoutsByTabId = {
|
||||
...local.terminalLayoutsByTabId,
|
||||
[tabId]: structuredClone(layout)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
for (const [paneKey, incarnationId] of Object.entries(
|
||||
|
||||
@@ -373,4 +373,26 @@ describe('an SSH pane whose membership was persisted into the ssh partition', ()
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// The hoisted pane must not ALIAS the partition's objects. `arbitratedFrom: 'local'` exists so a
|
||||
// decision read from one plane cannot mutate the other; a shared object defeats it silently and
|
||||
// strands a shell whose owner never voted on that decision.
|
||||
it('hoists copies, so mutating the local pane leaves the partition alone', async () => {
|
||||
const before = await createStore()
|
||||
before.setWorkspaceSession(paneSession() as never, SSH_PARTITION)
|
||||
before.flushOrThrow()
|
||||
stripHoistMarker()
|
||||
|
||||
const store = await reopenStore()
|
||||
const localTab = (store.getWorkspaceSession().tabsByWorktree?.[WORKTREE] ?? [])[0]
|
||||
expect(localTab, 'the pane was not hoisted, so aliasing cannot be observed').toBeDefined()
|
||||
|
||||
// A mutation scoped to the local plane.
|
||||
localTab!.ptyId = null
|
||||
|
||||
expect(
|
||||
store.getWorkspaceSession(SSH_PARTITION).tabsByWorktree?.[WORKTREE]?.[0]?.ptyId,
|
||||
'a local-only edit reached through into the ssh partition'
|
||||
).toBe(PTY)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user