Apply a fallible structural mutation to a tabβs layout tree atomically:
operate on a clone, run balance_node, and commit back to
tab.rootnode only if both succeed. On any error the tabβs tree is left
untouched β no partial mutation is visible to a later snapshot or to the
next operation. [codex P2 #1868]
Clear the tabβs focus/magnify ids when they no longer resolve to a node
in its (already-edited) tree, given their values from BEFORE the edit.
Returns (was_focused, was_magnified): whether each one was cleared.
Shared by every edit that can remove a leaf β a node delete, and a pane
tab move that empties its source pane β see handle_layout_delete_node
for the two ways an id can dangle after a delete.
Create a block and place it in a paneβs tab stack in one step. Placement
is validated FIRST: if no pane holds target_block_id, nothing is created
β a block never exists without a pane.
SPEC_864 site #6 β delete the layout node holding block_id.
Resolution happens here because the reducer owns the tree; the
caller (the delete_block saga) only knows the block id.
SPEC_864 Phase 4 β append backend actions to a tabβs
pendingbackendactions queue. The reducer does NOT model the queue
in TabRecord (it is a transient backendβfrontend mailbox the
frontend drains via REPLACE-clear slices, not layout-tree state), so
this arm only validates and passes the payload through; the persist
subscriber APPENDs it to LayoutState.pendingbackendactions.
Reorder block_id within its own pane, or move it into a different
pane β a same-leaf reorder never changes which member is visible unless
activate is set. Refuses (an Error event, tree untouched) when either
block doesnβt exist in the tabβs tree.
Phase E.4 (Option A) β set the focused layout-node id on a tab.
Errors (non-fatal) if the tab is unknown to the reducer; no-op
short-circuit when the value is already current. Empty node_id
clears the field. Bumps the version only on real changes so a
burst of identical sets doesnβt churn the event stream.
Phase E.4 (Option A) β set the magnified layout-node id on a tab.
Same shape as handle_set_focused_node. Empty node_id is the
toggle-off / clear case.
Clear focused/magnified ids that no longer resolve in the (post-op,
post-balance) tree. balance_nodeβs single-leaf collapse can rewrite a
parentβs id and structural ops can remove nodes, so every structural arm
reconciles β same intent as handle_layout_delete_nodeβs post-walk.
Event::Error for an unknown tab.
Apply a pane-tab edit to the tabβs tree and emit the tree-only
LayoutTreeReplaced (no slices: focus, magnify, leaf order and the
pending-action queue are untouched). edit returns false when it found
nothing to act on.