Delete merged feature branches (005–037) that inflated the auto-increment counter in create-new-feature.sh, and renumber the undo-redo spec to follow the existing 001–005 sequence. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.0 KiB
Implementation Plan: Undo/Redo
Branch: 006-undo-redo | Date: 2026-03-26 | Spec: spec.md
Input: Feature specification from /specs/006-undo-redo/spec.md
Summary
Add undo/redo capability for all encounter state changes using the memento pattern. Before each state transition, the current Encounter is pushed to an undo stack (capped at 50 entries). Undo restores the previous snapshot and pushes the current state to a redo stack; any new action clears the redo stack. Stacks are persisted to localStorage. Triggered via UI buttons (disabled when empty) and keyboard shortcuts (Ctrl+Z / Ctrl+Shift+Z, Cmd on Mac), suppressed during text input focus.
Technical Context
Language/Version: TypeScript 5.8 (strict mode, verbatimModuleSyntax)
Primary Dependencies: React 19, Vite 6, Tailwind CSS v4, Lucide React (icons)
Storage: localStorage (existing key "initiative:encounter", new keys for undo/redo stacks)
Testing: Vitest (v8 coverage)
Target Platform: Web browser (desktop + mobile)
Project Type: Web application (monorepo: apps/web + packages/domain + packages/application)
Performance Goals: Undo/redo operations complete in < 1 second (per SC-001)
Constraints: Undo stack capped at 50 snapshots; localStorage quota is best-effort
Scale/Scope: Encounters have tens of combatants; 50 snapshots of ~2-5 KB each = ~100-250 KB
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Status | Notes |
|---|---|---|
| I. Deterministic Domain Core | PASS | Stack management (push, pop, cap) is pure logic with no I/O. Domain functions remain unchanged. |
| II. Layered Architecture | PASS | Stack operations are pure functions in domain. Persistence is in the adapter layer (localStorage). Hook orchestrates via application pattern. |
| II-A. Context-Based State Flow | PASS | Undo/redo state exposed via existing EncounterContext. No new props needed on components beyond the context consumer. |
| III. Clarification-First | PASS | No ambiguities remain; issue #16 and spec fully define behavior. |
| IV. Escalation Gates | PASS | All requirements come from the spec; no scope expansion. |
| V. MVP Baseline Language | PASS | No permanent bans introduced. |
| VI. No Gameplay Rules | PASS | Undo/redo is infrastructure, not gameplay. |
Result: All gates pass. No violations to justify.
Project Structure
Documentation (this feature)
specs/006-undo-redo/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
└── tasks.md # Phase 2 output (/speckit.tasks)
Source Code (repository root)
packages/domain/src/
├── undo-redo.ts # Pure stack operations (push, pop, cap, clear)
├── __tests__/undo-redo.test.ts # Unit tests for stack operations
packages/application/src/
├── undo-use-case.ts # Orchestrates undo via EncounterStore + UndoRedoStore
├── redo-use-case.ts # Orchestrates redo via EncounterStore + UndoRedoStore
├── ports.ts # Extended with UndoRedoStore port interface
apps/web/src/
├── hooks/use-encounter.ts # Modified: wrap actions with snapshot capture, expose undo/redo
├── persistence/undo-redo-storage.ts # localStorage save/load for undo/redo stacks
├── contexts/encounter-context.tsx # Modified: expose undo/redo + stack emptiness flags
├── components/turn-navigation.tsx # Modified: add undo/redo buttons (inboard of turn step buttons)
├── hooks/use-undo-redo-shortcuts.ts # Keyboard shortcut handler (Ctrl+Z, Ctrl+Shift+Z)
Structure Decision: Follows existing layered architecture. Pure stack operations in domain, use cases in application, persistence and UI in web adapter. No new packages or structural changes needed.