Implement the 003-remove-combatant feature that adds the possibility to remove a combatant from an encounter
This commit is contained in:
71
specs/003-remove-combatant/plan.md
Normal file
71
specs/003-remove-combatant/plan.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Implementation Plan: Remove Combatant
|
||||
|
||||
**Branch**: `003-remove-combatant` | **Date**: 2026-03-03 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `/specs/003-remove-combatant/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Add a `removeCombatant` pure domain function that removes a combatant by ID from an Encounter, correctly adjusts `activeIndex` to preserve turn integrity, keeps `roundNumber` unchanged, and emits a `CombatantRemoved` event. Wire through an application-layer use case and expose via a minimal UI remove action per combatant.
|
||||
|
||||
## 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 (localhost:5173 dev, production build via Vite)
|
||||
**Project Type**: Web application (monorepo: packages/domain, packages/application, apps/web)
|
||||
**Performance Goals**: N/A (local-first, small data sets)
|
||||
**Constraints**: Domain must be pure (no I/O); layer boundaries enforced by automated script
|
||||
**Scale/Scope**: Single-user, single encounter at a time
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Principle | Status | Evidence |
|
||||
|-----------|--------|----------|
|
||||
| I. Deterministic Domain Core | PASS | `removeCombatant` is a pure function: same input → same output, no I/O |
|
||||
| II. Layered Architecture | PASS | Domain function → use case → React hook/UI. No layer violations. |
|
||||
| III. Agent Boundary | N/A | No agent layer involved in this feature |
|
||||
| IV. Clarification-First | PASS | Spec fully specifies all activeIndex adjustment rules; no ambiguity |
|
||||
| V. Escalation Gates | PASS | All functionality is within spec scope |
|
||||
| VI. MVP Baseline Language | PASS | No permanent bans introduced |
|
||||
| VII. No Gameplay Rules | PASS | Removal is encounter management, not gameplay mechanics |
|
||||
|
||||
**Gate result**: PASS — no violations.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/003-remove-combatant/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
packages/domain/src/
|
||||
├── remove-combatant.ts # Pure domain function
|
||||
├── events.ts # Add CombatantRemoved to DomainEvent union
|
||||
├── types.ts # Existing types (no changes expected)
|
||||
├── index.ts # Re-export removeCombatant
|
||||
└── __tests__/
|
||||
└── remove-combatant.test.ts # Acceptance scenarios from spec
|
||||
|
||||
packages/application/src/
|
||||
├── remove-combatant-use-case.ts # Orchestrates store.get → domain → store.save
|
||||
└── index.ts # Re-export use case
|
||||
|
||||
apps/web/src/
|
||||
├── hooks/use-encounter.ts # Add removeCombatant callback
|
||||
└── App.tsx # Add remove button per combatant + event display
|
||||
```
|
||||
|
||||
**Structure Decision**: Follows the existing monorepo layered architecture (packages/domain → packages/application → apps/web) exactly mirroring the addCombatant feature's file layout.
|
||||
Reference in New Issue
Block a user