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,83 @@
# Implementation Plan: Set Initiative
**Branch**: `005-set-initiative` | **Date**: 2026-03-04 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/005-set-initiative/spec.md`
## Summary
Add an optional integer initiative property to combatants and a `setInitiative` domain function that sets/changes/clears the value and automatically reorders combatants descending by initiative (unset last, stable sort for ties). The active combatant's turn is preserved through reorders by tracking identity rather than position.
## Technical Context
**Language/Version**: TypeScript 5.x (strict mode, verbatimModuleSyntax)
**Primary Dependencies**: React 19, Vite
**Storage**: In-memory React state (local-first, single-user MVP)
**Testing**: Vitest
**Target Platform**: Web browser (localhost:5173 dev)
**Project Type**: Web application (monorepo: domain → application → web adapter)
**Performance Goals**: N/A (local in-memory, trivial data sizes)
**Constraints**: Pure domain functions, no I/O in domain layer
**Scale/Scope**: Single-user, single encounter
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
| Principle | Status | Notes |
|-----------|--------|-------|
| I. Deterministic Domain Core | PASS | `setInitiative` is a pure function: same encounter + id + value → same result. No I/O, randomness, or clocks. |
| II. Layered Architecture | PASS | Domain function in `packages/domain`, use case in `packages/application`, UI in `apps/web`. Dependency direction preserved. |
| III. Agent Boundary | N/A | No agent layer involvement in this feature. |
| IV. Clarification-First | PASS | Spec has no NEEDS CLARIFICATION markers. All design decisions are spec-driven. |
| V. Escalation Gates | PASS | Feature scope matches spec exactly. No out-of-scope additions. |
| VI. MVP Baseline Language | PASS | Spec uses "MVP baseline does not include" for secondary tiebreakers. |
| VII. No Gameplay Rules | PASS | Constitution contains no gameplay mechanics; initiative logic is in the spec. |
All gates pass. No violations to justify.
**Post-Design Re-check**: All gates still pass. The `setInitiative` domain function is pure, layering is preserved, and no out-of-scope additions were introduced during design.
## Project Structure
### Documentation (this feature)
```text
specs/005-set-initiative/
├── spec.md
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── contracts/ # Phase 1 output
│ └── domain-api.md
├── checklists/
│ └── requirements.md
└── tasks.md # Phase 2 output (via /speckit.tasks)
```
### Source Code (repository root)
```text
packages/domain/src/
├── types.ts # Modified: add initiative to Combatant
├── events.ts # Modified: add InitiativeSet event
├── set-initiative.ts # New: setInitiative domain function
├── index.ts # Modified: export setInitiative
└── __tests__/
└── set-initiative.test.ts # New: tests for setInitiative
packages/application/src/
├── set-initiative-use-case.ts # New: setInitiativeUseCase
└── index.ts # Modified: export use case
apps/web/src/
├── hooks/
│ └── use-encounter.ts # Modified: add setInitiative callback
└── App.tsx # Modified: add initiative input field
```
**Structure Decision**: Follows existing monorepo layered structure. Each new domain operation gets its own file per established convention.
## Complexity Tracking
No constitution violations. Table not needed.