118 lines
4.9 KiB
Markdown
118 lines
4.9 KiB
Markdown
# Tasks: Remove Combatant
|
||
|
||
**Input**: Design documents from `/specs/003-remove-combatant/`
|
||
**Prerequisites**: plan.md, spec.md, research.md, data-model.md
|
||
|
||
**Tests**: Included — spec requires all six acceptance scenarios as automated tests (SC-002).
|
||
|
||
**Organization**: Tasks grouped by user story for independent implementation and testing.
|
||
|
||
## 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)
|
||
- Exact file paths included in descriptions
|
||
|
||
## Phase 1: Foundational (Event Type)
|
||
|
||
**Purpose**: Add the CombatantRemoved event type that all subsequent tasks depend on.
|
||
|
||
- [x] T001 Add `CombatantRemoved` interface and extend `DomainEvent` union in `packages/domain/src/events.ts`
|
||
- [x] T002 Export `CombatantRemoved` type from `packages/domain/src/index.ts`
|
||
|
||
**Checkpoint**: CombatantRemoved event type available for domain function and UI event display.
|
||
|
||
---
|
||
|
||
## Phase 2: User Story 1 - Remove Combatant Domain Logic (Priority: P1) MVP
|
||
|
||
**Goal**: Pure `removeCombatant` domain function that removes a combatant by ID, adjusts activeIndex correctly, preserves roundNumber, and emits CombatantRemoved.
|
||
|
||
**Independent Test**: Call `removeCombatant` with various encounter states and verify combatant list, activeIndex, roundNumber, events, and error cases.
|
||
|
||
### Tests for User Story 1
|
||
|
||
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
|
||
|
||
- [x] T003 [US1] Write acceptance tests for `removeCombatant` in `packages/domain/src/__tests__/remove-combatant.test.ts` covering all 6 spec scenarios: remove after active (AS-1), remove before active (AS-2), remove active combatant mid-list (AS-3), remove active combatant at end/wrap (AS-4), remove only combatant (AS-5), ID not found error (AS-6). Also test: event shape (CombatantRemoved with id+name), roundNumber invariance, and determinism.
|
||
|
||
### Implementation for User Story 1
|
||
|
||
- [x] T004 [US1] Implement `removeCombatant` pure function and `RemoveCombatantSuccess` type in `packages/domain/src/remove-combatant.ts` — find combatant by ID, compute new activeIndex per data-model rules, filter combatant list, emit CombatantRemoved event, return DomainError for not-found
|
||
- [x] T005 [US1] Export `removeCombatant` and `RemoveCombatantSuccess` from `packages/domain/src/index.ts`
|
||
|
||
**Checkpoint**: All 6 acceptance tests pass. Domain function is complete and independently testable.
|
||
|
||
---
|
||
|
||
## Phase 3: User Story 2 - Application + UI Wiring (Priority: P2)
|
||
|
||
**Goal**: Wire removeCombatant through application use case and expose via minimal UI with a remove button per combatant.
|
||
|
||
**Independent Test**: Render encounter UI, click remove on a combatant, verify it disappears from the list and event log updates.
|
||
|
||
### Implementation for User Story 2
|
||
|
||
- [x] T006 [P] [US2] Create `removeCombatantUseCase` in `packages/application/src/remove-combatant-use-case.ts` — follows existing pattern: `store.get()` → `removeCombatant()` → `store.save()` → return events or DomainError
|
||
- [x] T007 [US2] Export `removeCombatantUseCase` from `packages/application/src/index.ts`
|
||
- [x] T008 [US2] Add `removeCombatant(id: CombatantId)` callback to `useEncounter` hook in `apps/web/src/hooks/use-encounter.ts` — call use case, append events to log on success
|
||
- [x] T009 [US2] Add remove button per combatant and `CombatantRemoved` event display case in `apps/web/src/App.tsx`
|
||
|
||
**Checkpoint**: Full vertical slice works — GM can remove combatants from UI, initiative order updates correctly, event log shows removal.
|
||
|
||
---
|
||
|
||
## Phase 4: Polish & Cross-Cutting Concerns
|
||
|
||
- [x] T010 Run `pnpm check` (format + lint + typecheck + test) and fix any issues
|
||
|
||
---
|
||
|
||
## Dependencies & Execution Order
|
||
|
||
### Phase Dependencies
|
||
|
||
- **Phase 1 (Foundational)**: No dependencies — start immediately
|
||
- **Phase 2 (US1 Domain)**: Depends on Phase 1 (needs CombatantRemoved type)
|
||
- **Phase 3 (US2 App+UI)**: Depends on Phase 2 (needs domain function)
|
||
- **Phase 4 (Polish)**: Depends on Phase 3
|
||
|
||
### Within Each Phase
|
||
|
||
- T001 → T002 (export after defining)
|
||
- T003 (tests first) → T004 (implement) → T005 (export)
|
||
- T006 → T007 (export after creating use case file)
|
||
- T008 depends on T006+T007 (needs use case)
|
||
- T009 depends on T008 (needs hook callback)
|
||
|
||
### Parallel Opportunities
|
||
|
||
- Within T003, individual test cases are independent
|
||
|
||
---
|
||
|
||
## Implementation Strategy
|
||
|
||
### MVP First (User Story 1 Only)
|
||
|
||
1. Complete Phase 1: Event type (T001–T002)
|
||
2. Complete Phase 2: Domain tests + function (T003–T005)
|
||
3. **STOP and VALIDATE**: All 6 acceptance tests pass
|
||
4. Domain is complete and usable without UI
|
||
|
||
### Full Feature
|
||
|
||
1. Phase 1 → Phase 2 → Phase 3 → Phase 4
|
||
2. Each phase adds a testable increment
|
||
3. Commit after each phase checkpoint
|
||
|
||
---
|
||
|
||
## Notes
|
||
|
||
- [P] tasks = different files, no dependencies
|
||
- [Story] label maps task to specific user story
|
||
- Tests written first (TDD) per spec requirement SC-002
|
||
- Commit after each phase checkpoint
|
||
- Total: 10 tasks across 4 phases
|