3.0 KiB
Research: 023-clear-encounter
R1: Empty Encounter State in Domain
Decision: Introduce a clearEncounter domain function that returns an empty encounter ({ combatants: [], activeIndex: 0, roundNumber: 1 }) directly, bypassing createEncounter() which enforces the at-least-one-combatant invariant.
Rationale: The domain already handles empty combatant lists at runtime — removeCombatant can produce an encounter with 0 combatants (tested in AS-5 of remove-combatant tests). The createEncounter invariant prevents construction of empty encounters but the Encounter type itself has no minimum constraint. A dedicated clearEncounter function makes the intent explicit.
Alternatives considered:
- Relax
createEncounter()to allow empty combatants — rejected because it would weaken the invariant for normal encounter creation flows. - Use a separate
EmptyEncountertype — rejected as over-engineering; the existingEncountertype already supports the shape.
R2: Persistence of Cleared State
Decision: Update loadEncounter() to handle empty combatant arrays by constructing the empty encounter directly (without routing through createEncounter()). The existing saveEncounter() serializes the empty encounter as normal JSON.
Rationale: The spec requires cleared state to persist across page refreshes (FR-007). If we remove the localStorage key, initializeEncounter() falls back to the demo encounter, which violates the requirement. Storing and loading the empty encounter is the simplest approach.
Alternatives considered:
- Remove localStorage key + add a "cleared" flag — rejected as unnecessary complexity.
- Store a sentinel JSON value — rejected as non-standard and fragile.
R3: Confirmation UI Pattern
Decision: Use browser-native window.confirm() for the destructive action confirmation.
Rationale: No dialog component currently exists in the project. Building a custom dialog for a single confirmation prompt would be over-engineering for MVP. Browser confirm() is synchronous, universally supported, and clearly communicates the destructive nature of the action. The confirmation logic lives in the adapter layer (React hook or component), keeping the domain pure.
Alternatives considered:
- Custom AlertDialog component (shadcn-style) — rejected for MVP; can be added later if a richer confirmation UX is needed.
R4: Clear Button Placement
Decision: Add a clear/reset button in the TurnNavigation component, near the existing round/turn controls.
Rationale: The TurnNavigation bar is the encounter-level control area (advance turn, retreat turn, round counter). A "clear encounter" action is encounter-level, so it belongs here. Placing it near the round counter reinforces that it resets the entire encounter state.
Alternatives considered:
- ActionBar (bottom) — rejected; ActionBar is for adding combatants, not encounter-level management.
- Separate menu/dropdown — rejected as over-engineering for a single action.