Files
initiative/specs/025-display-initiative/tasks.md

6.2 KiB
Raw Blame History

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.

  • T001 Add initiativeProficiency: number field to Creature interface in packages/domain/src/creature-types.ts
  • T002 Create calculateInitiative and formatInitiativeModifier pure functions in packages/domain/src/initiative.ts
  • T003 Export new function and types from packages/domain/src/index.ts
  • 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)
  • 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

  • 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

  • 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.

  • T008 Run pnpm check to verify knip, format, lint, typecheck, and all tests pass
  • 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 (T001T005)
  • 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

# 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 (T001T005)
  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