# @suaveplan/undo — Specification **Package path:** `universal/control-flow/undo` **Version:** `0.1.0` **Status:** Shipped 2026-04-24 --- ## Purpose Enterprise-grade undo/redo engine for state management. Supports synchronous linear stacks, asynchronous stacks, branching history (alternate timelines), selective undo by command ID, history compression, and command merging. --- ## Requirements ### ADDED Requirements - **R01** `UndoStack` — synchronous linear undo/redo with optional `maxEntries` and `maxMemoryBytes` trimming, EventBus integration, transaction support. - **R02** `BranchingHistory` — forks a new branch when a push diverges from the redo stack (`branchOnDiverge: true` default), preserving alternate timelines. - **R03** `AsyncUndoStack` — async variants of push/undo/redo. Command failures wrapped in `UndoError(COMMAND_FAILED)`. - **R04** `HistoryCompressor` / `compressHistory` — squashes older entries by label into composite commands, respects `maxHistorySize`. - **R05** `SelectiveUndoStack` — extends `UndoStack` with `undoById(commandId)`, dependency checking, and conflict detection. - **R06** `CommandMerger` — merges consecutive compatible commands within a time/count window into a single composite. - **R07** `createCommand` — factory for synchronous closure commands with injectable `clock` and `idGenerator`. - **R08** `createPatchCommand` — factory that diffs old/new state via `@suaveplan/diff` to produce a reversible patch command. - **R09** `createAsyncCommand` — factory for async closure commands; errors wrapped in `UndoError(COMMAND_FAILED)`. - **R10** `composeCommands` / `composeAsyncCommands` — compose multiple commands into a single atomic command. - **R11** `executeCommand` / `undoCommand` — delegates to `command.execute(state)` / `command.undo(state)`. - **R12** `estimateCommandSize` — approximates command memory usage via JSON serialization with fallback. - **R13** `UNDO_CODES` — 6 stable error codes: `EMPTY_STACK`, `AT_BRANCH_ROOT`, `DEPENDENCY_CONFLICT`, `COMMAND_FAILED`, `TRANSACTION_ACTIVE`, `TRANSACTION_INACTIVE`. - **R14** `UndoError` — extends `SuaveplanError` with structured `UndoErrorContext`. - **R15** Zod schemas (strict) for all option types: `UndoStackOptionsSchema`, `BranchingOptionsSchema`, `HistoryCompressorOptionsSchema`, `CommandMergerOptionsSchema`, `SelectiveUndoOptionsSchema`. - **R16** OTel counters and histograms: `undo.push.total`, `undo.undo.total`, `undo.redo.total`, `undo.compress.total`, `undo.stack.depth`, `undo.compress.ratio`. - **R17** Property-based tests via `fast-check` covering round-trips, invariants, branch isolation, compression idempotency, merge associativity. - **R18** 100% istanbul coverage on all source files. - **R19** All class members `protected` (not `private`) for extensibility. - **R20** `compressionDepth: 0` is valid (means "compress all entries"). --- ## Dependencies - `@suaveplan/error workspace:^` - `@suaveplan/types workspace:^` - `@suaveplan/events workspace:^` - `@suaveplan/diff workspace:^` - `zod catalog:forms` - `@opentelemetry/api catalog:observability` - `tslib catalog:build`