3.3 KiB
Research: Set Initiative
R-001: Stable Sort for Initiative Ordering
Decision: Use JavaScript's built-in Array.prototype.sort() which is guaranteed stable (ES2019+). Combatants with equal initiative retain their relative order from the original array.
Rationale: All modern browsers and Node.js engines implement stable sort. No external library needed. The existing codebase already relies on insertion-order preservation in array operations.
Alternatives considered:
- Custom merge sort implementation — unnecessary since native sort is stable.
- Separate "sort key" field — over-engineering for the current requirement.
R-002: Active Turn Preservation Through Reorder
Decision: After sorting, find the new index of the combatant who was active before the sort (by CombatantId identity). Update activeIndex to point to that combatant's new position.
Rationale: The existing removeCombatant function already demonstrates the pattern of adjusting activeIndex to track a specific combatant through array mutations. This approach is simpler than alternatives since we can look up the active combatant's id before sorting, then find its new index after sorting.
Alternatives considered:
- Store active combatant as
activeCombatantIdinstead ofactiveIndex— would require changing theEncountertype and all downstream consumers. Too broad for this feature. - Compute a position delta — fragile and error-prone with stable sort edge cases.
R-003: Initiative as Optional Property on Combatant
Decision: Add readonly initiative?: number to the Combatant interface. undefined means "not yet set."
Rationale: Matches the spec requirement for combatants without initiative (FR-005). Using undefined (optional property) rather than null aligns with TypeScript conventions and the existing codebase style (no null usage in domain types).
Alternatives considered:
- Separate
InitiativeMapkeyed byCombatantId— breaks co-location, complicates sorting, doesn't match the existing pattern where combatant data lives on theCombatanttype. number | null— adds a second "empty" representation alongsideundefined; the codebase has no precedent fornullin domain types.
R-004: Clearing Initiative
Decision: Clearing initiative means setting it to undefined. The setInitiative function accepts number | undefined as the value parameter. When undefined, the combatant moves to the end of the order (per FR-003, FR-005).
Rationale: Reuses the same function for set, change, and clear operations. Keeps the API surface minimal.
Alternatives considered:
- Separate
clearInitiativefunction — unnecessary given the value can simply beundefined.
R-005: Integer Validation
Decision: Validate that the initiative value is a safe integer using Number.isInteger(). Reject NaN, Infinity, and floating-point values. Accept zero and negative integers (per FR-009).
Rationale: Number.isInteger() handles all edge cases: returns false for NaN, Infinity, -Infinity, and non-integer numbers. Allows the full range of safe integers.
Alternatives considered:
- Branded
Initiativetype — adds type complexity without significant safety benefit since validation happens at the domain boundary.