Initial Commit
This commit is contained in:
50
openspec/specs/undo/spec.md
Normal file
50
openspec/specs/undo/spec.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# @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<T>` — synchronous linear undo/redo with optional `maxEntries` and `maxMemoryBytes` trimming, EventBus integration, transaction support.
|
||||
- **R02** `BranchingHistory<T>` — forks a new branch when a push diverges from the redo stack (`branchOnDiverge: true` default), preserving alternate timelines.
|
||||
- **R03** `AsyncUndoStack<T>` — async variants of push/undo/redo. Command failures wrapped in `UndoError(COMMAND_FAILED)`.
|
||||
- **R04** `HistoryCompressor<T>` / `compressHistory` — squashes older entries by label into composite commands, respects `maxHistorySize`.
|
||||
- **R05** `SelectiveUndoStack<T>` — extends `UndoStack<T>` with `undoById(commandId)`, dependency checking, and conflict detection.
|
||||
- **R06** `CommandMerger<T>` — merges consecutive compatible commands within a time/count window into a single composite.
|
||||
- **R07** `createCommand<T>` — factory for synchronous closure commands with injectable `clock` and `idGenerator`.
|
||||
- **R08** `createPatchCommand<T>` — factory that diffs old/new state via `@suaveplan/diff` to produce a reversible patch command.
|
||||
- **R09** `createAsyncCommand<T>` — factory for async closure commands; errors wrapped in `UndoError(COMMAND_FAILED)`.
|
||||
- **R10** `composeCommands<T>` / `composeAsyncCommands<T>` — compose multiple commands into a single atomic command.
|
||||
- **R11** `executeCommand<T>` / `undoCommand<T>` — delegates to `command.execute(state)` / `command.undo(state)`.
|
||||
- **R12** `estimateCommandSize<T>` — 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`
|
||||
Reference in New Issue
Block a user