Implement the 005-set-initiative feature that adds initiative values to combatants with automatic descending sort and active turn preservation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-04 17:26:41 +01:00
parent a9df826fef
commit fea2bfe39d
17 changed files with 1107 additions and 1 deletions

View File

@@ -0,0 +1,57 @@
# Domain API Contract: Set Initiative
## Function Signature
```
setInitiative(encounter, combatantId, value) → Success | DomainError
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| encounter | Encounter | Current encounter state |
| combatantId | CombatantId | Target combatant to update |
| value | integer or undefined | New initiative value, or undefined to clear |
### Success Result
| Field | Type | Description |
|-------|------|-------------|
| encounter | Encounter | New encounter with updated combatant and reordered list |
| events | DomainEvent[] | Array containing one `InitiativeSet` event |
### Error Codes
| Code | Condition |
|------|-----------|
| `combatant-not-found` | No combatant with the given id exists |
| `invalid-initiative` | Value is defined but not an integer |
### Ordering Contract
After a successful call, `encounter.combatants` is sorted such that:
1. All combatants with `initiative !== undefined` come before those with `initiative === undefined`
2. Within the "has initiative" group: sorted descending by initiative value
3. Within the "no initiative" group: original relative order preserved
4. Equal initiative values: original relative order preserved (stable sort)
### Active Turn Contract
The combatant who was active before the call remains active after:
- `encounter.activeIndex` points to the same combatant (by identity) in the new order
- This holds even if the active combatant's own initiative changes
### Invariants Preserved
- INV-1: Empty encounters remain valid (0 combatants allowed)
- INV-2: `activeIndex` remains in bounds after reorder
- INV-3: `roundNumber` is never changed by `setInitiative`
## Use Case Signature
```
setInitiativeUseCase(store, combatantId, value) → DomainEvent[] | DomainError
```
Follows the standard use case pattern: get encounter from store, call domain function, save on success, return events or error.