Files
initiative/specs/013-hp-status-indicators/plan.md

3.6 KiB

Implementation Plan: HP Status Indicators

Branch: 013-hp-status-indicators | Date: 2026-03-05 | Spec: spec.md Input: Feature specification from /specs/013-hp-status-indicators/spec.md

Summary

Add visual HP status indicators to combatant rows. A pure domain function derives the HP status ("healthy", "bloodied", "unconscious") from currentHp and maxHp. The UI applies color treatments: amber for bloodied HP text, red + muted row for unconscious/dead combatants. No new stored state -- status is computed on render.

Technical Context

Language/Version: TypeScript 5.8 (strict mode, verbatimModuleSyntax) Primary Dependencies: React 19, Vite 6, Tailwind CSS v4, shadcn/ui-style components, Lucide React (icons) Storage: N/A (no storage changes -- purely derived state, existing localStorage persistence unchanged) Testing: Vitest (unit tests for domain function, existing layer boundary test) Target Platform: Modern browsers (Vite dev server, production build) Project Type: Web application (monorepo: domain + application + web adapter) Performance Goals: Synchronous render -- indicator updates in the same React render cycle as HP changes Constraints: Domain layer must remain pure (no UI imports); adapter layer handles all visual presentation Scale/Scope: Single new domain function + UI changes to one component (combatant-row)

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Principle Status Notes
I. Deterministic Domain Core PASS deriveHpStatus is a pure function: same inputs always produce the same output. No I/O, randomness, or clocks.
II. Layered Architecture PASS Domain exports the pure function; UI adapter calls it in the component. No reverse dependency.
III. Agent Boundary N/A No agent involvement in this feature.
IV. Clarification-First PASS No ambiguity -- thresholds are defined in spec (bloodied = 0 < currentHp < maxHp/2, unconscious = currentHp <= 0).
V. Escalation Gates PASS All behavior is within spec scope.
VI. MVP Baseline Language PASS Assumptions section uses "MVP baseline does not include" language.
VII. No Gameplay Rules in Constitution PASS Bloodied/unconscious thresholds are in feature spec, not constitution.
Development Workflow PASS pnpm check must pass before commit. Domain testable via pure-function assertions.

No violations. Complexity Tracking section not needed.

Project Structure

Documentation (this feature)

specs/013-hp-status-indicators/
├── plan.md              # This file
├── research.md          # Phase 0 output
├── data-model.md        # Phase 1 output
├── quickstart.md        # Phase 1 output
└── tasks.md             # Phase 2 output (/speckit.tasks command)

Source Code (repository root)

packages/domain/src/
├── hp-status.ts                    # NEW: deriveHpStatus pure function + HpStatus type
├── __tests__/hp-status.test.ts     # NEW: unit tests for deriveHpStatus
├── index.ts                        # MODIFIED: export new function and type

apps/web/src/components/
├── combatant-row.tsx               # MODIFIED: apply status-based styling

Structure Decision: Follows existing monorepo layout. New domain function in its own module (consistent with adjust-hp.ts, set-hp.ts pattern). UI changes confined to the existing combatant-row component. No new application-layer code needed since status is derived at render time, not via a use case.