Expand description
Restore-on-relaunch (Feature 1 of
docs/specs/SPEC_SESSION_RESTORE_AND_SAVED_LAYOUTS_2026_08_13.md).
A graceful window close today deliberately cascades a full delete of the
workspace/tabs/blocks (e3a6f85c2, wired to the last-window “main” case
by 4cbf856b7 — see docs/retro/retro-pane-layout-restore-was-a-leak-not-a-feature-2026-08-13.md),
so the next cold launch always finds Client.windowids empty and reseeds
the hardcoded default 3-pane layout (window_create::default_three_pane_tree).
This module adds an independent, durable “what was open last” record —
written just before that destroy cascade runs (window_close::handle_close_window)
and consulted by the cold-launch path (window_create::handle_create_window)
before it falls back to the hardcoded seed. It deliberately does NOT touch
the destroy cascade itself (that fix is correct and must stay — orphaned
shell processes were the original bug) and does NOT reuse Pillar 1’s
crash-reproject machinery (that’s scoped to crash-only recovery from rows
a graceful close is specifically supposed to remove — see
docs/specs/SPEC_PILLAR1_HOST_REPROJECT_DESIGN_2026_06_30.md §3).
Stored as a JSON blob under Client.meta["session:last_topology"] —
Client is already a durable singleton row with a generic meta sidecar
(the same “per-entity loosely-typed sidecar” pattern Pillar 1 Step 2 used
for floating-pane placement on Block.meta), so this needs no new
StoreObj type, table, or migration.
Structs§
- Replay
Tab 🔒 - One tab to rebuild: its blocks’ meta, and a split tree whose leaves name
those blocks by position (
placeholder(i)↔blocks[i]). - Replayed
Tab 🔒 - A tab that
replay_tabsactually rebuilt, with its blocks’ new ids in the order they were created.
Constants§
Functions§
- apply_
and_ 🔒publish - clear_
last_ 🔒session_ snapshot - Consume the durable “last session” record after a fully successful
restore (called only once
window_create::handle_create_window’s final window read-back succeeds — see that call site’s comment for why not any earlier). Best-effort, same assave_last_session_snapshot: a failure to clear just means a future stray/misused restore call could replay this snapshot again, whichclient_windowids_empty’s server-side check (handle_create_window) already independently guards against — this is defense in depth, not the only thing preventing duplicates. - current_
workspace_ 🔒id - The workspace backing one of this client’s windows, if any.
- find_
error 🔒 - handle_
save_ 🔒session_ snapshot - Attempt to replay the durable “last session” snapshot (if any) into a
fresh workspace:
CreateWorkspace→ per-tabCreateTab+ per-blockCreateBlock(reusing each block’s savedmeta, so a restored agent pane relaunches the same way opening a fresh one does) →LayoutSetTreewith the saved split tree (block ids remapped from placeholders to the newly created ones). - load_
last_ 🔒session_ snapshot - placeholder 🔒
- placeholder_
idx 🔒 - placeholderize 🔒
- Replace every leaf’s real block id (in
data.block_id,block_stack,active_block_id) with a positional placeholder, in place. - replay_
tabs 🔒 - Rebuild
tabsinside an existing workspace: per tabCreateTab, each blockCreateBlock(its saved meta), thenLayoutSetTreewith the tree’s placeholders resolved to the new block ids. Shared by restore-on-relaunch (into a fresh workspace) and Layouts → Open layout… (into the current window’s) —SPEC_LAYOUT_FILES_2026_09_25.md§1.1. - resolve_
placeholders 🔒 - Replace every leaf’s positional placeholder with the corresponding freshly
created block id, in place. A placeholder with no matching entry (should
not happen —
new_idsis built 1:1 from the same snapshot’sblocksarray — but tolerated defensively) is left as-is; such a leaf simply won’t resolve to a real block and the frontend already handles unknown block ids in a layout leaf as an empty pane, matching how a manually-crafted or corrupted layout degrades today. - restore_
last_ 🔒session - save_
last_ 🔒session_ snapshot - Persist a snapshot as the durable “last session” record, overwriting whatever was there before. Best-effort: a write failure is logged, never propagated — this must never block the close it rides alongside.
- snapshot_
workspace 🔒 - Read the given workspace’s tabs/blocks/layout directly from the store and
build a durable, block-id-independent snapshot (real block ids are
replaced with positional placeholders —
CreateBlockalways assigns a fresh id, so the snapshot can never reference one that will exist again). ReturnsNonefor an empty/unknown workspace (nothing worth persisting).