8.4 KiB
Tasks: Set Initiative
Input: Design documents from /specs/005-set-initiative/
Prerequisites: plan.md (required), spec.md (required), research.md, data-model.md, contracts/domain-api.md, quickstart.md
Tests: Tests are included as this project follows TDD conventions (test files exist for all domain functions).
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, US3)
- Include exact file paths in descriptions
Phase 1: Setup (Shared Infrastructure)
Purpose: No new project setup needed — existing monorepo. This phase covers foundational type and event changes shared across all user stories.
- T001 Add optional
initiativeproperty toCombatantinterface inpackages/domain/src/types.ts - T002 Add
InitiativeSetevent type (withcombatantId,previousValue,newValuefields) toDomainEventunion inpackages/domain/src/events.ts
Checkpoint: Types compile, existing tests still pass (pnpm check)
Phase 2: User Story 1 + User Story 2 — Set Initiative & Automatic Ordering (Priority: P1) MVP
Goal: Users can set/change/clear initiative values on combatants, and the encounter automatically reorders combatants from highest to lowest initiative.
Independent Test: Set initiative on multiple combatants and verify the combatant list is sorted descending by initiative value.
Tests for User Stories 1 & 2
NOTE: Write these tests FIRST, ensure they FAIL before implementation
- T003 [US1] Write acceptance tests for setting initiative (set, change, reject non-integer) in
packages/domain/src/__tests__/set-initiative.test.ts - T004 [US2] Write acceptance tests for automatic ordering (descending sort, stable sort for ties, reorder on change) in
packages/domain/src/__tests__/set-initiative.test.ts - T005 Write invariant tests (determinism, immutability, event shape, roundNumber unchanged) in
packages/domain/src/__tests__/set-initiative.test.ts
Implementation for User Stories 1 & 2
- T006 [US1] [US2] Implement
setInitiative(encounter, combatantId, value)domain function inpackages/domain/src/set-initiative.ts— validate combatant exists, validate integer, update initiative, stable-sort descending, emitInitiativeSetevent - T007 Export
setInitiativeand related types frompackages/domain/src/index.ts - T008 Implement
setInitiativeUseCase(store, combatantId, value)inpackages/application/src/set-initiative-use-case.tsfollowing existing use case pattern (get → call → check error → save → return events) - T009 Export
setInitiativeUseCasefrompackages/application/src/index.ts
Checkpoint: Domain tests pass, pnpm check passes. Core initiative logic is complete.
Phase 3: User Story 3 — Combatants Without Initiative (Priority: P2)
Goal: Combatants without initiative appear after all combatants with initiative, preserving their relative order.
Independent Test: Create a mix of combatants with and without initiative and verify ordering (initiative-set first descending, then unset in insertion order).
Tests for User Story 3
- T010 [US3] Write acceptance tests for unset-initiative ordering (unset after set, multiple unset preserve order, setting initiative moves combatant up) in
packages/domain/src/__tests__/set-initiative.test.ts
Implementation for User Story 3
- T011 [US3] Verify that sort logic in
packages/domain/src/set-initiative.tsalready handlesundefinedinitiative correctly (combatants without initiative sort after those with initiative, stable sort within each group) — add handling if not already present in T006
Checkpoint: All ordering scenarios pass including mixed set/unset combatants.
Phase 4: User Story 4 — Active Turn Preservation During Reorder (Priority: P2)
Goal: The active combatant's turn is preserved when initiative changes cause the combatant list to be reordered.
Independent Test: Set active combatant, change another combatant's initiative causing reorder, verify active turn still points to the same combatant.
Tests for User Story 4
- T012 [US4] Write acceptance tests for active turn preservation (reorder doesn't shift active turn, active combatant's own initiative change preserves turn) in
packages/domain/src/__tests__/set-initiative.test.ts
Implementation for User Story 4
- T013 [US4] Verify that
activeIndexidentity-tracking inpackages/domain/src/set-initiative.tsworks correctly when reordering occurs — the logic (record active id before sort, find new index after sort) should already exist from T006; add or fix if needed
Checkpoint: Active turn is preserved through all reorder scenarios. pnpm check passes.
Phase 5: Web Adapter Integration
Purpose: Wire initiative into the React UI so users can actually set initiative values.
- T014 Add
setInitiativecallback touseEncounterhook inapps/web/src/hooks/use-encounter.ts— callsetInitiativeUseCase, handle errors, append events - T015 Add initiative input field next to each combatant in
apps/web/src/App.tsx— numeric input, display current value, clear button, callsetInitiativeon change
Checkpoint: Full feature works end-to-end in the browser. pnpm check passes.
Phase 6: Polish & Cross-Cutting Concerns
Purpose: Edge case coverage and final validation.
- T016 Write edge case tests (zero initiative, negative initiative, clearing initiative, all same value) in
packages/domain/src/__tests__/set-initiative.test.ts - T017 Run
pnpm check(format + lint + typecheck + test) and fix any issues - T018 Verify layer boundary compliance (domain imports no framework/adapter code)
Dependencies & Execution Order
Phase Dependencies
- Phase 1 (Setup): No dependencies — types and events first
- Phase 2 (US1+US2 MVP): Depends on Phase 1
- Phase 3 (US3): Depends on Phase 2 (extends sort logic)
- Phase 4 (US4): Depends on Phase 2 (extends activeIndex logic)
- Phase 5 (Web Adapter): Depends on Phases 2–4 (needs complete domain + application layer)
- Phase 6 (Polish): Depends on all previous phases
User Story Dependencies
- US1 + US2 (P1): Combined because sorting is inherent to setting initiative — they share the same domain function
- US3 (P2): Extends the sort logic from US1+US2 to handle
undefined. Can be developed immediately after Phase 2. - US4 (P2): Extends the
activeIndexlogic from US1+US2. Can be developed in parallel with US3.
Parallel Opportunities
- T001 and T002 can run in parallel (different files)
- T003, T004, T005 can run in parallel (same file but different test groups — practically written together)
- US3 (Phase 3) and US4 (Phase 4) can run in parallel after Phase 2
- T014 and T015 can run in parallel (different files)
Parallel Example: Phase 2 (MVP)
# Tests first (all in same file, written together):
T003: Acceptance tests for setting initiative
T004: Acceptance tests for automatic ordering
T005: Invariant tests
# Then implementation:
T006: Domain function (core logic)
T007: Domain exports
T008: Application use case (after T006-T007)
T009: Application exports
Implementation Strategy
MVP First (User Stories 1 + 2)
- Complete Phase 1: Type + event changes
- Complete Phase 2: Domain function + use case with tests
- STOP and VALIDATE:
pnpm checkpasses, initiative setting and ordering works - Optionally wire up UI (Phase 5) for a minimal demo
Incremental Delivery
- Phase 1 → Types ready
- Phase 2 → MVP: set initiative + auto-ordering works
- Phase 3 → Unset combatants handled correctly
- Phase 4 → Active turn preserved through reorders
- Phase 5 → UI wired up, feature usable in browser
- Phase 6 → Edge cases covered, quality verified
Notes
- US1 and US2 are combined in Phase 2 because the domain function
setInitiativeinherently performs both setting and sorting — they cannot be meaningfully separated - US3 and US4 are separable extensions of the sort and activeIndex logic respectively
- All domain tests follow existing patterns: helper functions for test data, acceptance scenarios mapped from spec, invariant tests for determinism/immutability
- Commit after each phase checkpoint