2.0 KiB
2.0 KiB
Data Model: Remove Combatant
Feature: 003-remove-combatant Date: 2026-03-03
Existing Entities (no changes)
Encounter
| Field | Type | Description |
|---|---|---|
| combatants | readonly Combatant[] | Ordered list of participants |
| activeIndex | number | Index of the combatant whose turn it is |
| roundNumber | number | Current round (≥ 1, never changes on removal) |
Combatant
| Field | Type | Description |
|---|---|---|
| id | CombatantId (branded string) | Unique identifier |
| name | string | Display name |
New Event Type
CombatantRemoved
| Field | Type | Description |
|---|---|---|
| type | "CombatantRemoved" (literal) | Event discriminant |
| combatantId | CombatantId | ID of the removed combatant |
| name | string | Name of the removed combatant |
Added to the DomainEvent discriminated union alongside TurnAdvanced, RoundAdvanced, and CombatantAdded.
New Domain Function
removeCombatant
| Parameter | Type | Description |
|---|---|---|
| encounter | Encounter | Current encounter state |
| id | CombatantId | ID of combatant to remove |
Returns: RemoveCombatantSuccess | DomainError
RemoveCombatantSuccess
| Field | Type | Description |
|---|---|---|
| encounter | Encounter | Updated encounter after removal |
| events | DomainEvent[] | Exactly one CombatantRemoved event |
DomainError (existing, reused)
Returned with code "combatant-not-found" when ID does not match any combatant.
State Transition Rules
activeIndex Adjustment
Given removal of combatant at index removedIdx with current activeIndex:
| Condition | New activeIndex |
|---|---|
| removedIdx > activeIndex | activeIndex (unchanged) |
| removedIdx < activeIndex | activeIndex - 1 |
| removedIdx === activeIndex, not last in list | activeIndex (next slides in) |
| removedIdx === activeIndex, last in list | 0 (wrap) |
| Only combatant removed (list becomes empty) | 0 |