Phase E.2 — create a new workspace. Reducer assigns the OID
(UUID), inserts into canonical state, emits WorkspaceCreated.
NOT idempotent on retry: each invocation generates a fresh UUID
and inserts a new row, so a saga that double-fires CreateWorkspace
would create two distinct workspaces. Saga-side dedup (correlation
IDs / saga state machine) is responsible for at-most-once delivery
when sagas land in E.5+.
Phase E.2 — delete a workspace from canonical state. Idempotent:
deleting a missing workspace is a silent no-op. Cascades to the
workspace’s tabs (E.2b) and through to each tab’s blocks (E.3):
every tab whose workspace_id matches is removed from
state.tabs, and each block in those tabs is removed from
state.blocks, before the workspace itself goes away. Cascade
events are NOT emitted individually — subscribers observing
WorkspaceDeleted are expected to drop dependent state (mirrors
how wcore::delete_workspace cascades in SQLite).
Phase E.5.3 — pass-through validation + emit for workspace
meta updates. The reducer does NOT mutate meta in state (it
doesn’t track meta in WorkspaceRecord); the persist subscriber
applies the patch directly to wstore. This keeps the reducer’s
state shape unchanged while still routing every meta mutation
through the broadcast bus for observers.