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

8.6 KiB

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.