# Data Model: Set Initiative ## Entity Changes ### Combatant (modified) | Field | Type | Required | Description | |-------|------|----------|-------------| | id | CombatantId (branded string) | Yes | Unique identifier | | name | string | Yes | Display name (non-empty, trimmed) | | initiative | integer | No | Initiative value for turn ordering. Unset means "not yet rolled." | **Validation rules**: - `initiative` must be an integer when set (no floats, NaN, or Infinity) - Zero and negative integers are valid - Unset (`undefined`) is valid — combatant has not rolled initiative yet ### Encounter (unchanged structure, new ordering behavior) | Field | Type | Required | Description | |-------|------|----------|-------------| | combatants | readonly Combatant[] | Yes | Ordered list. Now sorted by initiative descending (unset last, stable sort for ties). | | activeIndex | number | Yes | Index of the active combatant. Adjusted to follow the active combatant's identity through reorders. | | roundNumber | number | Yes | Current round (≥ 1). Unchanged by initiative operations. | **Ordering invariant**: After any `setInitiative` call, `combatants` is sorted such that: 1. Combatants with initiative come first, ordered highest to lowest 2. Combatants without initiative come last 3. Ties within each group preserve relative insertion order (stable sort) ## New Domain Event ### InitiativeSet Emitted when a combatant's initiative value is set, changed, or cleared. | Field | Type | Description | |-------|------|-------------| | type | "InitiativeSet" | Event discriminant | | combatantId | CombatantId | The combatant whose initiative changed | | previousValue | integer or undefined | The initiative value before the change | | newValue | integer or undefined | The initiative value after the change | ## State Transitions ### setInitiative(encounter, combatantId, value) **Input**: Current encounter, target combatant id, new initiative value (integer or undefined to clear) **Output**: Updated encounter with reordered combatants and adjusted activeIndex, plus events **Error conditions**: - `combatant-not-found`: No combatant with the given id exists in the encounter - `invalid-initiative`: Value is not an integer (when defined) **Transition logic**: 1. Find target combatant by id → error if not found 2. Validate value is integer (when defined) → error if invalid 3. Record the active combatant's id (for preservation) 4. Update the target combatant's initiative value 5. Stable-sort combatants: initiative descending, unset last 6. Find the active combatant's new index in the sorted array 7. Return new encounter + `InitiativeSet` event