# Tasks: Clear Encounter **Input**: Design documents from `/specs/023-clear-encounter/` **Prerequisites**: plan.md, spec.md, research.md, data-model.md, quickstart.md **Tests**: Included — domain tests follow existing patterns (pure function assertions). **Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story. ## Format: `[ID] [P?] [Story] Description` - **[P]**: Can run in parallel (different files, no dependencies) - **[Story]**: Which user story this task belongs to (e.g., US1, US2) - Include exact file paths in descriptions --- ## Phase 1: Foundational (Blocking Prerequisites) **Purpose**: Domain event type and pure function that all subsequent work depends on **⚠️ CRITICAL**: No user story work can begin until this phase is complete - [x] T001 Add `EncounterCleared` event interface (with `type: "EncounterCleared"` and `combatantCount: number` fields) and add it to the `DomainEvent` union type in `packages/domain/src/events.ts` - [x] T002 Create `clearEncounter` pure function in `packages/domain/src/clear-encounter.ts` — takes an `Encounter`, returns `ClearEncounterSuccess` (with `{ encounter: { combatants: [], activeIndex: 0, roundNumber: 1 }, events: [EncounterCleared] }`) or `DomainError` (code `"encounter-already-empty"` when `combatants.length === 0`). Export `ClearEncounterSuccess` type. Follow the pattern in `packages/domain/src/remove-combatant.ts` - [x] T003 Export `clearEncounter`, `ClearEncounterSuccess`, and `EncounterCleared` from `packages/domain/src/index.ts` **Checkpoint**: Domain layer complete — `clearEncounter` is a pure, testable function --- ## Phase 2: User Story 1 — Clear Encounter to Start Fresh (Priority: P1) 🎯 MVP **Goal**: Users can clear all combatants and reset round/turn counters with a single action, with the cleared state persisting across page refreshes. **Independent Test**: Add several combatants, advance through rounds, clear the encounter, verify all combatants removed and counters reset to round 1 / index 0. Refresh the page and verify empty state persists. ### Tests for User Story 1 - [x] T004 [P] [US1] Write domain tests for `clearEncounter` in `packages/domain/src/__tests__/clear-encounter.test.ts` — cover: (1) clearing encounter with multiple combatants at round 3 returns empty encounter with roundNumber 1 and activeIndex 0, (2) clearing encounter with single combatant works, (3) clearing encounter with combatants that have HP/AC/conditions/concentration removes all data, (4) clearing already-empty encounter returns DomainError with code `"encounter-already-empty"`, (5) emits `EncounterCleared` event with correct `combatantCount`, (6) determinism — same input always produces same output ### Implementation for User Story 1 - [x] T005 [P] [US1] Create `clearEncounterUseCase` in `packages/application/src/clear-encounter-use-case.ts` — follow the pattern in `remove-combatant-use-case.ts`: get encounter from store, call `clearEncounter`, check for `DomainError`, save result, return events - [x] T006 [US1] Export `clearEncounterUseCase` from `packages/application/src/index.ts` - [x] T007 [US1] Update `loadEncounter` in `apps/web/src/persistence/encounter-storage.ts` to handle empty combatant arrays — when `combatants` is a valid empty array, return `{ combatants: [], activeIndex: 0, roundNumber: 1 }` directly instead of routing through `createEncounter()` (which rejects empty arrays) - [x] T008 [US1] Add `clearEncounter` callback to `useEncounter` hook in `apps/web/src/hooks/use-encounter.ts` — call `clearEncounterUseCase(makeStore())`, check for `DomainError`, update events. Also reset `nextId.current` to 0 after clearing. Return `clearEncounter` from the hook - [x] T009 [P] [US1] Add `onClearEncounter` prop and clear button (using Trash2 icon from Lucide) to the `TurnNavigation` component in `apps/web/src/components/turn-navigation.tsx` — place it near the round/turn controls, use `variant="ghost"` and `size="icon"` styling consistent with existing buttons - [x] T010 [US1] Wire `clearEncounter` from `useEncounter` hook to `TurnNavigation` as `onClearEncounter` prop in `apps/web/src/App.tsx` **Checkpoint**: User Story 1 is fully functional — clearing works end-to-end and persists across refreshes --- ## Phase 3: User Story 2 — Confirmation Before Clearing (Priority: P1) **Goal**: Users are prompted for confirmation before the encounter is cleared, preventing accidental data loss. The clear button is disabled when there are no combatants. **Independent Test**: Click the clear button, verify a confirmation prompt appears, cancel and verify encounter unchanged, confirm and verify encounter cleared. Verify the button is disabled when the encounter is already empty. ### Implementation for User Story 2 - [x] T011 [US2] Add `window.confirm("Clear the entire encounter? This cannot be undone.")` gate before executing `clearEncounterUseCase` in the `clearEncounter` callback in `apps/web/src/hooks/use-encounter.ts` — if user cancels, return early without modifying state (FR-006) - [x] T012 [US2] Disable the clear encounter button when `encounter.combatants.length === 0` in `apps/web/src/components/turn-navigation.tsx` — pass combatant count or a `disabled` flag via props (FR-008) **Checkpoint**: User Story 2 complete — accidental clears are prevented, button disabled when empty --- ## Phase 4: Polish & Cross-Cutting Concerns **Purpose**: Verify all checks pass and feature is merge-ready - [x] T013 Run `pnpm check` (knip + format + lint + typecheck + test) to verify merge gate passes --- ## Dependencies & Execution Order ### Phase Dependencies - **Foundational (Phase 1)**: No dependencies — can start immediately - **User Story 1 (Phase 2)**: Depends on Phase 1 completion - **User Story 2 (Phase 3)**: Depends on Phase 2 completion (US2 modifies files created/modified in US1) - **Polish (Phase 4)**: Depends on all phases complete ### User Story Dependencies - **User Story 1 (P1)**: Can start after Foundational — no dependencies on other stories - **User Story 2 (P1)**: Depends on User Story 1 — adds confirmation gate to the clearEncounter callback and disabled state to the button created in US1 ### Within Each Phase - Tasks marked [P] can run in parallel (different files) - Sequential tasks depend on prior tasks in the same phase ### Parallel Opportunities - **Phase 1**: T001 must complete before T002 (T002 imports EncounterCleared). T003 depends on both. - **Phase 2**: T004 (tests) and T005 (use case) can run in parallel [P]. T009 (UI) can run in parallel with T005–T008 [P]. T010 depends on T008 and T009. - **Phase 3**: T011 and T012 modify different files but T012 depends on the prop interface from T009, so they should run sequentially. --- ## Parallel Example: User Story 1 ```bash # After Phase 1 completes, launch in parallel: Task T004: "Write domain tests in packages/domain/src/__tests__/clear-encounter.test.ts" Task T005: "Create clearEncounterUseCase in packages/application/src/clear-encounter-use-case.ts" Task T009: "Add clear button to apps/web/src/components/turn-navigation.tsx" # Then sequentially: Task T006: "Export use case from packages/application/src/index.ts" Task T007: "Update loadEncounter in apps/web/src/persistence/encounter-storage.ts" Task T008: "Add clearEncounter to apps/web/src/hooks/use-encounter.ts" Task T010: "Wire clearEncounter in apps/web/src/App.tsx" ``` --- ## Implementation Strategy ### MVP First (User Story 1 Only) 1. Complete Phase 1: Foundational (T001–T003) 2. Complete Phase 2: User Story 1 (T004–T010) 3. **STOP and VALIDATE**: Test clearing end-to-end, verify persistence 4. Feature is usable at this point (clearing works, just no confirmation gate) ### Full Delivery 1. Complete Phases 1–2 → Clear encounter works 2. Complete Phase 3 → Confirmation prevents accidental clears 3. Complete Phase 4 → Merge gate verified 4. Feature is complete and merge-ready --- ## Notes - [P] tasks = different files, no dependencies - [Story] label maps task to specific user story for traceability - US2 is intentionally sequenced after US1 because it modifies the same files (hook, component) - The `window.confirm()` approach keeps the domain pure — confirmation logic stays in the adapter layer - Commit after each phase for clean git history