Atomic addCombatant with optional initial state #15

Closed
opened 2026-03-25 15:37:39 +01:00 by dostulata · 0 comments
Owner

Summary

The addCombatant domain function currently only accepts (encounter, id, name), forcing the hook layer to compose multiple sequential domain calls and direct store.save() mutations to set initial stats when adding from bestiary or player characters. This makes combatant creation non-atomic, bypasses domain validation for some fields, and produces no events for fields set via the bypass. Extending addCombatant to accept an optional CombatantInit bag makes creation atomic and moves all validation into the domain.

Acceptance Criteria

  • addCombatant domain function accepts an optional CombatantInit parameter (maxHp, ac, initiative, creatureId, color, icon, playerCharacterId)
  • Initial fields are validated in the domain using the same rules as existing set functions (setHp, setAc, setInitiative)
  • A single CombatantAdded event is emitted containing the full initial state
  • addFromBestiary in the hook uses the new atomic addCombatant instead of multi-step composition
  • addFromPlayerCharacter in the hook uses the new atomic addCombatant instead of multi-step composition
  • No direct store.save() bypass remains in either compound operation
  • Existing tests pass; new tests cover addCombatant with CombatantInit

Context

  • Research: docs/agents/research/2026-03-25-combat-state.md (see "Follow-up Analysis" section)
## Summary The `addCombatant` domain function currently only accepts `(encounter, id, name)`, forcing the hook layer to compose multiple sequential domain calls and direct `store.save()` mutations to set initial stats when adding from bestiary or player characters. This makes combatant creation non-atomic, bypasses domain validation for some fields, and produces no events for fields set via the bypass. Extending `addCombatant` to accept an optional `CombatantInit` bag makes creation atomic and moves all validation into the domain. ## Acceptance Criteria - [x] `addCombatant` domain function accepts an optional `CombatantInit` parameter (maxHp, ac, initiative, creatureId, color, icon, playerCharacterId) - [x] Initial fields are validated in the domain using the same rules as existing set functions (setHp, setAc, setInitiative) - [x] A single `CombatantAdded` event is emitted containing the full initial state - [x] `addFromBestiary` in the hook uses the new atomic `addCombatant` instead of multi-step composition - [x] `addFromPlayerCharacter` in the hook uses the new atomic `addCombatant` instead of multi-step composition - [x] No direct `store.save()` bypass remains in either compound operation - [x] Existing tests pass; new tests cover `addCombatant` with `CombatantInit` ## Context - Research: `docs/agents/research/2026-03-25-combat-state.md` (see "Follow-up Analysis" section)
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dostulata/initiative#15