Phase E.5.5 — apply a BlockMoved event to SQLite.
Handles both cross-tab moves and intra-tab repositioning.
Idempotent on re-delivery (checks current parent before mutating).
Apply one reducer event to the on-disk store. Idempotent: each
arm checks for the entity’s current SQLite state before writing
so duplicate events (from at-least-once delivery semantics) don’t
produce duplicate rows or wcore errors.
Phase E.4 (Option A) — write the reducer-emitted focused node id
onto the tab’s LayoutState.focusednodeid column. Tab→layout is
a join through Tab.layoutstate. Idempotent: silent no-op when the
tab is unknown (deleted concurrently), the layout row is missing
(legacy tab without one), or the value already matches. Other
LayoutState fields stay on their existing wcore-direct path until
Option B lands.
SPEC_864 Phase 4 — apply a LayoutBackendActionsQueued event:
APPEND the reducer-validated actions to
LayoutState.pendingbackendactions. The queue is a backend→frontend
mailbox: the backend appends here; the frontend drains it by pushing
a full slice without the processed actions (the REPLACE path in
apply_layout_tree_replaced).
Phase E.4.B — apply a LayoutCleared event: wipe the tab’s persisted
layout tree and the focus/magnify ids (and the leaforder cache — an
empty tree has no leaves). Mirrors
reducer::layout::handle_layout_clear. Idempotent: silent no-op when
the tab is unknown, the layout row is missing, or it is already clear
(so a double-apply — once synchronously from the RPC handler, once
from the broadcast — does not churn the version).
Phase E.4.B — apply a LayoutTreeReplaced event: write the reducer-
supplied tree onto LayoutState.rootnode. Mirrors
reducer::layout::handle_layout_set_tree — when the new tree is
empty, also clear the focus/magnify ids (and leaforder) so they don’t
dangle at nodes that no longer exist.
Phase E.4 (Option A) — write the reducer-emitted magnified node id
onto the tab’s LayoutState.magnifiednodeid column. Same shape as
apply_focused_node_changed.
Phase E.5 — delete the persisted Window row + remove the id
from Client.windowids. Mirrors wcore::close_window’s order:
prune client.windowids FIRST (so any read between the two ops
doesn’t see a dangling id), then delete the Window row.
(codex P1 #619.)
Phase E.5 — record/update a window’s workspace pointer on the
persisted Window row. Idempotent: inserts if missing, updates
if workspaceid differs, no-ops if identical.
Phase E.5.5 — apply a TabMoved event to SQLite.
Idempotent: detects already-moved state (tab in dst, not in src)
and returns Ok(()) without re-mutating.
Phase E.5.3 — replace the workspace’s tabids with the new
list and drain any legacy pinnedtabids rows. Pinning was a
Waveterm feature removed from AgentMux; bootstrap merges legacy
pinned tabs into the reducer’s tab_ids, so the next reorder
is the canonical full ordering. Leaving stale pinnedtabids
in SQLite would cause UI double-insertion (workspace.tsx
builds the displayed tab list as [...pinnedtabids, ...tabids]).
Phase E.5.x (issue #855) — apply a meta-patch to a window’s meta
map. Same shape as apply_workspace_meta_updated. Silent no-op if
the window doesn’t exist in mstore (preserves the idempotency
contract — duplicate or stale events fold to no-op).
Phase E.5.3 — apply a meta-patch to a workspace’s meta map.
Reducer doesn’t track meta in WorkspaceRecord; this subscriber
is the sole authority that mutates persisted meta. Patch is a
JSON object that merges shallow-key-by-shallow-key on top of the
existing meta. null values in the patch delete the key.
Phase E.5.3 — shallow merge a JSON object patch into a
MetaMapType. Mirrors backend::obj::merge_meta semantics so
UpdateObjectMeta keeps behaving the same way after the reducer
migration:
Snapshot state.workspaces and reconcile against SQLite —
INSERT/UPDATE only, no deletes. Workspace-scoped (tab/block
resync expands here as each entity’s RPC layer migrates).
Spawn the persist subscriber task. Runs until the broadcast
channel closes (i.e., the reducer’s bus is dropped at process
shutdown). The state handle is used for workspace-scoped
full-resync after a RecvError::Lagged.