# Tasks: Display Initiative **Input**: Design documents from `/specs/025-display-initiative/` **Prerequisites**: plan.md, spec.md, research.md, data-model.md, quickstart.md **Tests**: Tests are included — the spec requires a pure domain function verified by layer boundary checks, and the project convention places tests in `packages/*/src/__tests__/`. **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: Setup (Shared Infrastructure) **Purpose**: No new project setup needed — this feature extends existing packages. Skip to foundational. --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Domain types and pure functions that both user stories depend on. **⚠️ CRITICAL**: No user story work can begin until this phase is complete. - [x] T001 Add `initiativeProficiency: number` field to `Creature` interface in `packages/domain/src/creature-types.ts` - [x] T002 Create `calculateInitiative` and `formatInitiativeModifier` pure functions in `packages/domain/src/initiative.ts` - [x] T003 Export new function and types from `packages/domain/src/index.ts` - [x] T004 Write unit tests for `calculateInitiative` and `formatInitiativeModifier` in `packages/domain/src/__tests__/initiative.test.ts` covering: positive modifier, negative modifier, zero modifier, no proficiency (multiplier 0), single proficiency (multiplier 1), expertise (multiplier 2), passive initiative calculation, sign formatting with U+2212 minus, and a guard test verifying the function is not called / returns no result for combatants without bestiary creature data (FR-006) - [x] T005 Parse `initiative.proficiency` from raw 5etools JSON in `apps/web/src/adapters/bestiary-adapter.ts` — add `initiative?: { proficiency?: number }` to `RawMonster` interface and map `m.initiative?.proficiency ?? 0` to `Creature.initiativeProficiency` **Checkpoint**: Domain function works and adapter provides initiative data. `pnpm check` passes. --- ## Phase 3: User Story 1 — View Initiative in Stat Block (Priority: P1) 🎯 MVP **Goal**: Display calculated initiative modifier and passive initiative in the stat block header area. **Independent Test**: Select any creature from the bestiary; verify the initiative line appears with correct calculated value (e.g., Aboleth shows "Initiative +7 (17)"). ### Implementation for User Story 1 - [x] T006 [US1] Add initiative display to `apps/web/src/components/stat-block.tsx` — call `calculateInitiative` with creature data, render "Initiative +X (Y)" using `formatInitiativeModifier`, and conditionally hide the line when the combatant has no bestiary data **Checkpoint**: Creatures display initiative in stat block. Aboleth shows "Initiative +7 (17)". `pnpm check` passes. --- ## Phase 4: User Story 2 — Initiative Position Matches MM 2024 Layout (Priority: P2) **Goal**: Initiative appears adjacent to AC on the same line, matching the Monster Manual 2024 stat block layout. **Independent Test**: Compare stat block layout to MM 2024 screenshot; initiative appears on the AC line before HP. ### Implementation for User Story 2 - [x] T007 [US2] Refine initiative positioning in `apps/web/src/components/stat-block.tsx` — adjust CSS/layout to place the initiative text on the same line as AC with appropriate spacing, matching the "AC 17 Initiative +7 (17)" format from MM 2024 **Checkpoint**: Layout matches MM 2024 format. `pnpm check` passes. --- ## Phase 5: Polish & Cross-Cutting Concerns **Purpose**: Final validation across all stories. - [x] T008 Run `pnpm check` to verify knip, format, lint, typecheck, and all tests pass - [x] T009 Spot-check initiative values for several creatures against D&D Beyond: Aboleth (+7), and at least two creatures with no initiative proficiency and one with single proficiency --- ## Dependencies & Execution Order ### Phase Dependencies - **Foundational (Phase 2)**: No dependencies — can start immediately - **User Story 1 (Phase 3)**: Depends on Phase 2 completion (T001–T005) - **User Story 2 (Phase 4)**: Depends on Phase 3 completion (T006) — refines the layout from US1 - **Polish (Phase 5)**: Depends on all user stories being complete ### User Story Dependencies - **User Story 1 (P1)**: Depends only on foundational phase. Core MVP. - **User Story 2 (P2)**: Depends on US1 — refines the positioning of the initiative display added in US1. ### Within Each User Story - Foundational types/functions before UI integration - Tests written alongside domain functions (T004 with T002) ### Parallel Opportunities - T002 and T005 can run in parallel (different packages, no dependencies between them) - T001 must complete before T002 and T005 (type definition needed by both) - T003 must follow T002 (exports the new function) - T004 can run in parallel with T005 (different packages) --- ## Parallel Example: Foundational Phase ```bash # After T001 (type change) completes, launch in parallel: Task T002: "Create calculateInitiative in packages/domain/src/initiative.ts" Task T005: "Parse initiative.proficiency in apps/web/src/adapters/bestiary-adapter.ts" # After T002, launch in parallel: Task T003: "Export from packages/domain/src/index.ts" Task T004: "Write tests in packages/domain/src/__tests__/initiative.test.ts" ``` --- ## Implementation Strategy ### MVP First (User Story 1 Only) 1. Complete Phase 2: Foundational (T001–T005) 2. Complete Phase 3: User Story 1 (T006) 3. **STOP and VALIDATE**: Aboleth displays "Initiative +7 (17)" in stat block 4. Run `pnpm check` ### Incremental Delivery 1. Foundational → Domain function + adapter parsing ready 2. Add US1 → Initiative visible in stat block → Validate (MVP!) 3. Add US2 → Layout matches MM 2024 → Validate 4. Polish → Cross-creature spot-checks --- ## Notes - [P] tasks = different files, no dependencies - [Story] label maps task to specific user story for traceability - US2 intentionally depends on US1 since it refines the same UI element - Commit after each task or logical group - The entire feature is 9 tasks — small enough for sequential execution