Files
initiative/specs/009-combatant-hp/spec.md

123 lines
8.6 KiB
Markdown

# Feature Specification: Combatant HP Tracking
**Feature Branch**: `009-combatant-hp`
**Created**: 2026-03-05
**Status**: Draft
**Input**: User description: "Track max HP and current HP per combatant with quick +/- controls (clamp 0..max); keep the design extensible for later richer damage/heal UI."
## User Scenarios & Testing
### User Story 1 - Set Max HP for a Combatant (Priority: P1)
As a game master, I want to assign a maximum HP value to a combatant so that I can track their health during the encounter.
**Why this priority**: Max HP is the foundation for all HP tracking. Without it, current HP has no upper bound and the feature has no value.
**Independent Test**: Can be fully tested by adding a combatant and setting their max HP, then verifying the value is stored and displayed.
**Acceptance Scenarios**:
1. **Given** a combatant exists in the encounter, **When** the user sets a max HP value (positive integer), **Then** the combatant's max HP is stored and displayed.
2. **Given** a combatant has no max HP set yet, **When** the combatant is displayed, **Then** both Current HP and Max HP fields are visible (Current HP is disabled until Max HP is set).
3. **Given** a combatant has a max HP of 20, **When** the user changes max HP to 30, **Then** the max HP updates to 30.
4. **Given** a combatant has max HP of 20 and current HP of 20, **When** the user lowers max HP to 15, **Then** current HP is clamped to the new max HP of 15.
5. **Given** a combatant has max HP of 20 and current HP of 20 (full health), **When** the user increases max HP to 30, **Then** current HP increases to 30 (stays at full health).
6. **Given** a combatant has max HP of 20 and current HP of 12 (not full health), **When** the user increases max HP to 30, **Then** current HP remains at 12 (unchanged).
---
### User Story 2 - Quick Adjust Current HP (Priority: P1)
As a game master, I want to quickly increase or decrease a combatant's current HP using +/- controls so that I can reflect damage and healing during combat without typing exact values.
**Why this priority**: This is the primary interaction loop during combat -- adjusting HP as damage/healing occurs. Equally critical as setting max HP.
**Independent Test**: Can be fully tested by setting a combatant's max HP, then using +/- controls and verifying the current HP changes correctly within bounds.
**Acceptance Scenarios**:
1. **Given** a combatant has max HP of 20 and current HP of 20, **When** the user presses the "-" control, **Then** current HP decreases by 1 to 19.
2. **Given** a combatant has max HP of 20 and current HP of 15, **When** the user presses the "+" control, **Then** current HP increases by 1 to 16.
3. **Given** a combatant has current HP of 0, **When** the user presses the "-" control, **Then** current HP remains at 0 (clamped to minimum).
4. **Given** a combatant has current HP equal to max HP, **When** the user presses the "+" control, **Then** current HP remains at max HP (clamped to maximum).
---
### User Story 3 - Direct HP Entry (Priority: P2)
As a game master, I want to type a specific current HP value directly so that I can apply large amounts of damage or healing in one action.
**Why this priority**: Complements the quick +/- controls for cases where the delta is large. Less critical than basic +/- since the same outcome can be achieved with repeated presses.
**Independent Test**: Can be fully tested by setting a combatant's max HP, typing a value in the current HP field, and verifying clamping behavior.
**Acceptance Scenarios**:
1. **Given** a combatant has max HP of 50, **When** the user types 35 into the current HP field, **Then** current HP is set to 35.
2. **Given** a combatant has max HP of 50, **When** the user types 60 into the current HP field, **Then** current HP is clamped to 50.
3. **Given** a combatant has max HP of 50, **When** the user types -5 into the current HP field, **Then** current HP is clamped to 0.
---
### User Story 4 - HP Persists Across Reloads (Priority: P2)
As a game master, I want HP values to survive page reloads so that I don't lose health tracking mid-session.
**Why this priority**: Losing HP data on reload would make the feature unreliable during a game session. Important but builds on existing persistence infrastructure.
**Independent Test**: Can be tested by setting HP values, reloading the page, and verifying values are restored.
**Acceptance Scenarios**:
1. **Given** a combatant has max HP of 30 and current HP of 18, **When** the page is reloaded, **Then** both max HP and current HP are restored.
---
### Edge Cases
- What happens when max HP is set to 0? System must reject 0 or negative max HP values; max HP must be a positive integer.
- What happens when a combatant is added without HP? The combatant is displayed without HP tracking. HP is optional -- not all combatants need HP (e.g., environmental effects, lair actions).
- What happens when the user enters a non-numeric value for HP? The input is rejected and the previous value is preserved.
- What happens when max HP is cleared/removed? Current HP is also cleared; the combatant returns to the "no HP" state. Clearing only takes effect on blur/Enter (not while typing), so temporarily emptying the field during editing does not wipe current HP.
- What happens when the user selects all text in the max HP field and retypes a new value? The field uses local draft state; the domain only sees the final committed value on blur/Enter. Current HP is preserved.
- What happens when HP is adjusted by 0? The system rejects a zero delta -- no change is made and no event is emitted.
## Requirements
### Functional Requirements
- **FR-001**: Each combatant MAY have an optional max HP value (positive integer).
- **FR-002**: Each combatant with a max HP MUST have a current HP value, defaulting to max HP when first set.
- **FR-003**: Current HP MUST be clamped to the range [0, max HP] at all times.
- **FR-004**: The system MUST provide "+" and "-" controls to adjust current HP by 1.
- **FR-005**: The system MUST allow direct numeric entry of current HP, applying clamping on confirmation.
- **FR-006**: The system MUST allow the user to set and edit the max HP value for any combatant. The max HP value is committed on blur or Enter (not per-keystroke) so that intermediate editing states (e.g., clearing the field to retype) do not affect current HP.
- **FR-007**: When max HP is reduced below current HP, current HP MUST be clamped to the new max HP.
- **FR-011**: When max HP changes and the combatant is at full health (current HP equals previous max HP), current HP MUST stay synced to the new max HP value.
- **FR-012**: When max HP changes and the combatant is NOT at full health, current HP MUST remain unchanged (unless clamped by FR-007).
- **FR-008**: Max HP MUST be a positive integer (>= 1). The system MUST reject zero, negative, or non-integer values.
- **FR-009**: HP values (max and current) MUST persist across page reloads using the existing persistence mechanism.
- **FR-010**: HP tracking MUST be optional per combatant. Combatants without max HP set have no HP display beyond the empty input fields.
- **FR-013**: Both Current HP and Max HP input fields MUST always be visible in each combatant row. The Current HP field is disabled when Max HP is not set. The +/- buttons only appear when HP tracking is active.
### Key Entities
- **Combatant** (extended): Gains optional `maxHp` (positive integer) and `currentHp` (integer, 0..maxHp) attributes. When `maxHp` is undefined, the combatant has no HP tracking.
## Success Criteria
### Measurable Outcomes
- **SC-001**: A user can set max HP and adjust current HP for any combatant in under 5 seconds per action.
- **SC-002**: Current HP never exceeds max HP or drops below 0, regardless of user input method.
- **SC-003**: HP values survive a full page reload without data loss.
- **SC-004**: Combatants without HP set display correctly with no HP controls cluttering the interface.
## Assumptions
- The increment/decrement step for +/- controls is 1. Larger step sizes (e.g., custom damage amounts) are not in the MVP baseline but the design should not preclude a richer damage/heal UI in the future.
- HP is always an integer (no fractional HP). This aligns with standard tabletop RPG conventions.
- There is no "temporary HP" concept in the MVP baseline.
- There is no death/unconscious state triggered by reaching 0 HP in the MVP baseline. The system simply displays 0.
- The +/- controls and direct entry are the only HP modification methods in the MVP baseline. A richer damage/heal dialog (e.g., entering a damage amount to subtract) is not included but the domain design should be extensible to support it.