docs: fix broken refs, generate control manifest, update systems-index

- Fixed 22 broken references to design/accessibility-requirements.md → design/ux/ across 9 files
- Generated docs/architecture/control-manifest.md from ADR-0000..0014 (212 lines, 5 layers)
- Updated systems-index.md: systems 19/20/22 now show 'design ' alongside ' No iniciado'
- Added dead-king-reveal.md reference to Dead King Input/Reveal UI row
- Bumped game-concept.md status from Draft to Approved
This commit is contained in:
2026-08-17 02:29:50 -03:00
parent 86d4b144b1
commit 0cdf08e6f3
12 changed files with 290 additions and 27 deletions
+1 -1
View File
@@ -145,7 +145,7 @@ phases:
name: "Accessibility Requirements"
required: true
artifact:
glob: "design/accessibility-requirements.md"
glob: "design/ux/accessibility-requirements.md"
description: "Commit accessibility tier (Basic/Standard/Comprehensive/Exemplary) and feature matrix. UX specs (Phase 4) reference this tier."
pre-production:
+5 -5
View File
@@ -106,7 +106,7 @@ Note: in `solo` mode, director spawns (CD-PHASE-GATE, TD-PHASE-GATE, PR-PHASE-GA
- [ ] Master architecture document exists at `docs/architecture/architecture.md`
- [ ] Architecture traceability index exists at `docs/architecture/architecture-traceability.md`
- [ ] `/architecture-review` has been run (a review report file exists in `docs/architecture/`)
- [ ] `design/accessibility-requirements.md` exists with accessibility tier committed
- [ ] `design/ux/accessibility-requirements.md` exists with accessibility tier committed
- [ ] `design/ux/interaction-patterns.md` exists (pattern library initialized, even if minimal)
**Quality Checks:**
@@ -163,7 +163,7 @@ A depends on B). If any cycle is detected (e.g. A→B→A, or A→B→C→A):
- [ ] **Core loop fun is validated** — playtest data confirms the central mechanic is enjoyable, not just functional. Explicitly check the Vertical Slice playtest report.
- [ ] UX specs cover all UI Requirements sections from MVP-tier GDDs
- [ ] Interaction pattern library documents patterns used in key screens
- [ ] Accessibility tier from `design/accessibility-requirements.md` is addressed in all key screen UX specs
- [ ] Accessibility tier from `design/ux/accessibility-requirements.md` is addressed in all key screen UX specs
- [ ] Sprint plan references real story file paths from `production/epics/`
(not just GDDs — stories must embed GDD req ID + ADR reference)
- [ ] **Vertical Slice is COMPLETE**, not just scoped — the build demonstrates the full core loop end-to-end. At least one complete [start → challenge → resolution] cycle works.
@@ -211,7 +211,7 @@ A depends on B). If any cycle is detected (e.g. A→B→A, or A→B→C→A):
- [ ] Difficulty curve matches the Difficulty Curve design doc (if one exists at `design/difficulty-curve.md`)
- [ ] All implemented screens have corresponding UX specs (no "designed in-code" screens)
- [ ] Interaction pattern library is up-to-date with all patterns used in implementation
- [ ] Accessibility compliance verified against committed tier in `design/accessibility-requirements.md`
- [ ] Accessibility compliance verified against committed tier in `design/ux/accessibility-requirements.md`
---
@@ -463,12 +463,12 @@ Based on the verdict, suggest specific next steps:
- **No UX specs?** → `/ux-design [screen name]` to author specs, or `/team-ui [feature]` for full pipeline
- **UX specs not reviewed?** → `/ux-review [file]` or `/ux-review all` to validate
- **No accessibility requirements doc?** → Use `AskUserQuestion` to offer to create it now:
- Prompt: "The gate requires `design/accessibility-requirements.md`. Shall I create it from the template?"
- Prompt: "The gate requires `design/ux/accessibility-requirements.md`. Shall I create it from the template?"
- Options: `Create it now — I'll choose an accessibility tier`, `I'll create it myself`, `Skip for now`
- If "Create it now": use a second `AskUserQuestion` to ask for the tier:
- Prompt: "Which accessibility tier fits this project?"
- Options: `Basic — remapping + subtitles only (lowest effort)`, `Standard — Basic + colorblind modes + scalable UI`, `Comprehensive — Standard + motor accessibility + full settings menu`, `Exemplary — Comprehensive + external audit + full customization`
- Then write `design/accessibility-requirements.md` using the template at `.claude/docs/templates/accessibility-requirements.md`, filling in the chosen tier. Confirm: "May I write `design/accessibility-requirements.md`?"
- Then write `design/ux/accessibility-requirements.md` using the template at `.claude/docs/templates/accessibility-requirements.md`, filling in the chosen tier. Confirm: "May I write `design/ux/accessibility-requirements.md`?"
- **No interaction pattern library?** → `/ux-design patterns` to initialize it
- **GDDs not cross-reviewed?** → `/review-all-gdds` (run after all MVP GDDs are individually approved)
- **Cross-GDD consistency issues?** → fix flagged GDDs, then re-run `/review-all-gdds`
+3 -3
View File
@@ -45,7 +45,7 @@ Before designing anything, read and synthesize:
- `design/player-journey.md` — player's state and context when they reach this screen
- All GDD UI Requirements sections relevant to this feature
- `design/ux/interaction-patterns.md` — existing patterns to reuse (not reinvent)
- `design/accessibility-requirements.md` — committed accessibility tier (e.g., Basic, Enhanced, Full)
- `design/ux/accessibility-requirements.md` — committed accessibility tier (e.g., Basic, Enhanced, Full)
**If `design/ux/interaction-patterns.md` does not exist**, surface the gap immediately:
> "interaction-patterns.md does not exist — no existing patterns to reuse."
@@ -102,7 +102,7 @@ Delegate to **ui-programmer**:
- **UI NEVER owns or modifies game state** — display only; emit events for all player actions
- All text through the localization system — no hardcoded player-facing strings
- Support both input methods (keyboard/mouse AND gamepad)
- Implement accessibility features per the committed tier in `design/accessibility-requirements.md`
- Implement accessibility features per the committed tier in `design/ux/accessibility-requirements.md`
- Wire up data binding to game state
- **If any new interaction pattern is created during implementation** (i.e., something not already in the pattern library), add it to `design/ux/interaction-patterns.md` before marking implementation complete
- Output: implemented UI feature
@@ -112,7 +112,7 @@ Delegate to **ui-programmer**:
Delegate in parallel:
- **ux-designer**: Verify implementation matches wireframes and interaction spec. Test keyboard-only and gamepad-only navigation. Check accessibility features function correctly.
- **art-director**: Verify visual consistency with art bible. Check at minimum and maximum supported resolutions.
- **accessibility-specialist**: Verify compliance against the committed accessibility tier documented in `design/accessibility-requirements.md`. Flag any violations as blockers.
- **accessibility-specialist**: Verify compliance against the committed accessibility tier documented in `design/ux/accessibility-requirements.md`. Flag any violations as blockers.
All three review streams must report before proceeding to Phase 5.
+3 -3
View File
@@ -85,7 +85,7 @@ section. UX layout must align with the aesthetic commitments already made.
### 2g: Accessibility Requirements
Check for `design/accessibility-requirements.md`. If found, read it. The spec
Check for `design/ux/accessibility-requirements.md`. If found, read it. The spec
must satisfy the accessibility tier committed to there.
### 2h: Input Method (from Project Config)
@@ -621,7 +621,7 @@ Present the data requirements as a table:
#### Section G: Accessibility
Cross-reference `design/accessibility-requirements.md` if it exists.
Cross-reference `design/ux/accessibility-requirements.md` if it exists.
Walk through the ux-designer agent's standard checklist for this screen:
- Keyboard-only navigation path through all interactive elements
@@ -846,7 +846,7 @@ it for addition to the pattern library:
navigation map in any related specs? Flag mismatches.
**4. Accessibility coverage**: Does the spec address the accessibility tier
committed to in `design/accessibility-requirements.md`? If not, flag open questions.
committed to in `design/ux/accessibility-requirements.md`? If not, flag open questions.
**5. Empty states**: Does every data-dependent element have an empty state defined?
Flag any that don't.
+1 -1
View File
@@ -50,7 +50,7 @@ Before validating any spec, load:
extract `## Input & Platform`. This is the authoritative source for which input
methods the game supports — use it to drive the Input Method Coverage checks in
Phase 3A, not the spec's own header. If unconfigured, fall back to the spec header.
2. The accessibility tier committed to in `design/accessibility-requirements.md`
2. The accessibility tier committed to in `design/ux/accessibility-requirements.md`
(if it exists)
3. The interaction pattern library at `design/ux/interaction-patterns.md` (if
it exists)
@@ -122,7 +122,7 @@ with verdict COMPLETE / BLOCKED and handoffs to `/design-review`, `/dev-story`,
**Fixture:**
- Steps 13 complete successfully
- `design/accessibility-requirements.md` committed tier: Enhanced
- `design/ux/accessibility-requirements.md` committed tier: Enhanced
- accessibility-specialist (Step 4, parallel) flags a BLOCKING concern: the critical path through the forest dungeon requires players to distinguish between two environmental hazards (toxic pools vs. shallow water) using color alone — no shape, icon, or audio cue differentiates them
**Input:** `/team-level forest dungeon`
@@ -27,7 +27,7 @@ with verdict COMPLETE / BLOCKED and handoffs to `/ux-review`, `/code-review`,
- [ ] UX Review Gate (Phase 1c) is defined as a blocking gate — skill must not proceed to Phase 2 without APPROVED verdict
- [ ] Team Composition lists all five roles (ux-designer, ui-programmer, art-director, engine UI specialist, accessibility-specialist)
- [ ] References the interaction pattern library (`design/ux/interaction-patterns.md`) — ui-programmer must use existing patterns
- [ ] Phase 1a reads `design/accessibility-requirements.md` before design begins
- [ ] Phase 1a reads `design/ux/accessibility-requirements.md` before design begins
---
@@ -39,7 +39,7 @@ with verdict COMPLETE / BLOCKED and handoffs to `/ux-review`, `/code-review`,
- `design/gdd/game-concept.md` exists with platform targets and intended audience
- `design/player-journey.md` exists
- `design/ux/interaction-patterns.md` exists with relevant patterns
- `design/accessibility-requirements.md` exists with committed tier (e.g., Enhanced)
- `design/ux/accessibility-requirements.md` exists with committed tier (e.g., Enhanced)
- Engine UI specialist configured in `.claude/docs/technical-preferences.md`
**Input:** `/team-ui inventory screen`
@@ -123,7 +123,7 @@ with verdict COMPLETE / BLOCKED and handoffs to `/ux-review`, `/code-review`,
- `design/ux/inventory-screen.md` exists (APPROVED)
- Visual design spec complete
- Implementation complete
- `design/accessibility-requirements.md` committed tier: Enhanced
- `design/ux/accessibility-requirements.md` committed tier: Enhanced
**Input:** `/team-ui inventory screen` (resuming from Phase 3 complete)
@@ -133,14 +133,14 @@ with verdict COMPLETE / BLOCKED and handoffs to `/ux-review`, `/code-review`,
3. Each stream operates independently:
- ux-designer: verifies implementation matches wireframes, tests keyboard-only and gamepad-only navigation, checks accessibility features function
- art-director: verifies visual consistency with art bible at minimum and maximum supported resolutions
- accessibility-specialist: audits against the Enhanced accessibility tier in `design/accessibility-requirements.md`; any violation flagged as a blocker
- accessibility-specialist: audits against the Enhanced accessibility tier in `design/ux/accessibility-requirements.md`; any violation flagged as a blocker
4. Skill waits for all three results before proceeding to Phase 5
5. `AskUserQuestion` presents all three review results before Phase 5 begins
**Assertions:**
- [ ] All three Task calls issued before any result is awaited (parallel, not sequential)
- [ ] Phase 5 does NOT begin until all three Phase 4 agents have returned
- [ ] Accessibility-specialist explicitly reads `design/accessibility-requirements.md` for the committed tier
- [ ] Accessibility-specialist explicitly reads `design/ux/accessibility-requirements.md` for the committed tier
- [ ] Accessibility violations flagged as BLOCKING (not merely advisory)
- [ ] `AskUserQuestion` shows all three review streams' results together before Phase 5 approval
- [ ] No Phase 4 agent's output is used as input for another Phase 4 agent
+1 -1
View File
@@ -1,7 +1,7 @@
# Game Concept: Ajedrez Purgatorio
*Created: 2026-04-12*
*Status: Draft*
*Status: Approved*
*Canon note (2026-06-17): este documento describe la **Línea Atemporal I**
(Ricardo Valdés) dentro de la cosmología unificada del Purgatorio. Ver
`design/narrative/purgatorio-cosmology.md` para cómo coexiste con la Línea
+4 -4
View File
@@ -46,10 +46,10 @@ de duplicarla.
| 16 | Game State Manager | Core | **Vertical Slice** | ✅ Implementado (Sprint 1) | — | Scene Management |
| 17 | Save/Load System | Persistence | **Vertical Slice** | ⚠️ Parcial (CampaignState SO) | — | Game State Manager |
| 18 | HUD | UI | **Vertical Slice** | ⚠️ Parcial (PieceTooltip) | design/ux/hud.md | Piece Identity, Turn System |
| 19 | Main Menu | UI | **Vertical Slice** | ❌ No iniciado | design/ux/main-menu.md | Scene Management |
| 20 | Dialogue UI | UI | **Vertical Slice** | ❌ No iniciado | design/ux/dialogue-ui.md | Dialogue System |
| 19 | Main Menu | UI | **Vertical Slice** | ❌ No iniciado (design ✅) | design/ux/main-menu.md | Scene Management |
| 20 | Dialogue UI | UI | **Vertical Slice** | ❌ No iniciado (design ✅) | design/ux/dialogue-ui.md | Dialogue System |
| 21 | Dice UI | UI | **Vertical Slice** | ✅ Implementado (Sprint 3) | design/ux/dice-ui.md | Dice System |
| 22 | Dead King Input UI | UI | **Vertical Slice** | ❌ No iniciado | design/ux/dead-king-input.md | Dead Kings System |
| 22 | Dead King Input UI | UI | **Vertical Slice** | ❌ No iniciado (design ✅) | design/ux/dead-king-input.md, design/ux/dead-king-reveal.md | Dead Kings System |
| 23 | Music Manager | Audio | Alpha | ❌ No iniciado | — | Scene Management |
| 24 | SFX System | Audio | Alpha | ❌ No iniciado | — | — |
| 25 | Board Themes | Presentation | Alpha | ❌ No iniciado | — | Campaign System |
@@ -96,7 +96,7 @@ de duplicarla.
2. **HUD** ⚠️ (Parcial: PieceTooltip implementado Sprint 1) — depende de: Piece Identity, Turn System
3. **Dialogue UI** ❌ — depende de: Dialogue System
4. **Dice UI** ✅ (Sprint 3: 3 UI screens — Offer, Roll, Result) — depende de: Dice System
5. **Dead King Input UI** ❌ — depende de: Dead Kings System
5. **Dead King Input/Reveal UI** (design ✅: dead-king-input.md, dead-king-reveal.md) — depende de: Dead Kings System
6. **Music Manager** ❌ — depende de: Scene Management
### Polish Layer
+2 -2
View File
@@ -524,7 +524,7 @@ staleness can be detected.
### Step 3.5: Accessibility Requirements
Create `design/accessibility-requirements.md` using the template. Commit to a
Create `design/ux/accessibility-requirements.md` using the template. Commit to a
tier (Basic / Standard / Comprehensive / Exemplary) and fill the 4-axis feature
matrix (visual, motor, cognitive, auditory).
@@ -543,7 +543,7 @@ reference this tier — it is a design prerequisite, not a UX deliverable.
- At least 3 ADRs exist and are Accepted
- Architecture review report exists
- `docs/architecture/control-manifest.md` exists
- `design/accessibility-requirements.md` exists
- `design/ux/accessibility-requirements.md` exists
---
+263
View File
@@ -0,0 +1,263 @@
# Control Manifest: Ajedrez Purgatorio
> **Status**: Active
> **Manifest Version**: 2026-08-17
> **Generated From**: ADR-0000 through ADR-0014 (all Accepted), technical-preferences.md, engine reference
> **Engine**: Unity 6.3 LTS (6000.3.13f1)
---
## Layer: Foundation (no dependencies)
_Covers: global infrastructure patterns, singleton lifecycle, persistence, event communication, naming, forbidden patterns._
_Sources: ADR-0000, ADR-0003, ADR-0004, ADR-0005, technical-preferences.md_
### Must Do
| ID | Rule | Source |
|----|------|--------|
| F-01 | Use the **Awake-explicit** singleton pattern for every cross-scene `MonoBehaviour` manager: `public static T Instance { get; private set; }` assigned in `Awake()` with duplicate guard + `DontDestroyOnLoad`. | ADR-0000 §Decision, ADR-0004 |
| F-02 | Implement `OnDestroy()` in every singleton to null the `Instance` reference when the object is the current instance: `if (Instance == this) Instance = null;` | ADR-0000 §Key Interfaces |
| F-03 | Keep business logic in **POCO service classes** without any `using UnityEngine`. Inject dependencies via constructor or method parameters from the owning `MonoBehaviour` in `Awake()`. | ADR-0000 §Decision, ADR-0001 §Decision |
| F-04 | Use **ScriptableObjects as data containers only** — no business logic inside SO classes. SOs hold design data (PieceIdentity, BalanceConfig, CampaignConfig) and runtime state snapshots. | ADR-0005 §Implementation Guidelines |
| F-05 | Persist runtime state with **`JsonUtility`** to `Application.persistentDataPath/*.json`. Use explicit `[Serializable]` wrapper classes (JsonUtility does not serialize `[SerializeField]` privates or dictionaries). | ADR-0000 §Decision, ADR-0013 §Decision |
| F-06 | Load ScriptableObjects from `Resources/` via a **single centralized API** (e.g., `Resources.Load<T>()` inside the owning singleton). Never call `Resources.Load` from consumer code. | ADR-0004, ADR-0000 §Implementation Guidelines |
| F-07 | Cross-system communication uses **C# events** (`event Action<T>`) declared on the producer. Never use direct manager-to-manager method calls for state notifications. | ADR-0000 §Decision, ADR-0003 §Decision |
| F-08 | Prefix all event names with **`On`** (e.g., `OnPieceCaptured`, `OnCheckmate`, `OnTurnChanged`). Use `EventHandler` or `Action` suffix where applicable. | ADR-0000 §Key Interfaces, ADR-0003 §Implementation Guidelines |
| F-09 | **Unsubscribe** from all events in `OnDisable()` or `OnDestroy()` — never leave dangling subscriptions. | ADR-0000 §Implementation Guidelines, ADR-0003 §Implementation Guidelines |
| F-10 | Maintain **one manager per responsibility** — no duplicates. If a second implementation appears for the same concern, consolidate into the canonical one. | ADR-0000 §Decision (estancia 5), ADR-0009 |
| F-11 | Reference `Manager.Instance` **only from `Awake()`, `Start()`, or `OnEnable()`** — never from field initializers, constructors, or property getters. | ADR-0000 §Neutral |
| F-12 | Use **PascalCase** for classes, public fields/properties, files, scenes, prefabs, constants. Use **`_camelCase`** for private fields. Use PascalCase + `EventHandler`/`Action` suffix for signals/events. | technical-preferences.md §Naming Conventions |
| F-13 | Ensure gameplay logic stays within **≤ 4 ms/frame** of the 16.6 ms budget (60 FPS lock). | technical-preferences.md §Performance Budgets |
| F-14 | Keep draw calls **≤ 200** (2D sprite game, board + UI; UGUI batched). | technical-preferences.md §Performance Budgets |
| F-15 | Stay within **≤ 1.5 GB** memory ceiling (PC). No Addressables yet — use Resources + ScriptableObjects. | technical-preferences.md §Performance Budgets |
### Must Never Do
| ID | Rule | Source |
|----|------|--------|
| F-N01 | **Never use the lazy-getter singleton** pattern (`if (_instance == null) { _instance = new GameObject(...); }`). All three remaining instances (`AudioManager`, `SaveSystem`, former `UI/SceneTransitionManager`) must migrate to Awake-explicit. | ADR-0000, technical-preferences.md §Forbidden Patterns |
| F-N02 | **Never duplicate a manager** across scenes for the same responsibility. One `SceneTransitionManager`, one `GameStateManager`, one `AudioManager`, etc. | ADR-0000 (estancia 5), ADR-0009, technical-preferences.md §Forbidden Patterns |
| F-N03 | **Never store piece lifecycle state (Alive/Captured/Dead/etc.) inside the `PieceIdentity` ScriptableObject.** Lifecycle is owned exclusively by `CampaignState`. | ADR-0010, technical-preferences.md §Forbidden Patterns |
| F-N04 | **Never use `BinaryFormatter` or `PlayerPrefs`** for structured game save data. | ADR-0000 §Alternatives Considered |
| F-N05 | **Never use a global event bus** (UnityEvent routing, message system). Use direct C# events on the producer. | ADR-0003 §Alternatives Considered |
| F-N06 | **Never use `lazy_getter_singleton`** anywhere in the codebase. | technical-preferences.md §Forbidden Patterns |
---
## Layer: Core (depends on Foundation)
_Covers: AI strategy, pause/timescale, overlay UI, scene transitions, position hashing._
_Sources: ADR-0002, ADR-0006, ADR-0007, ADR-0008, ADR-0009_
### Must Do
| ID | Rule | Source |
|----|------|--------|
| C-01 | AI uses the **Strategy pattern**: implement `IAIStrategy` interface with `Move SelectMove(BoardState board, Color side, float timeoutSec)`. Select strategy at runtime from `AIController`. | ADR-0002 §Decision |
| C-02 | Provide three difficulty implementations: `AIStrategyEasy` (random + capture priority), `AIStrategyMedium` (1-ply evaluation), `AIStrategyHard` (minimax alpha-beta depth 2, 5 s timeout). | ADR-0002 §Decision, §Implementation Guidelines |
| C-03 | AI strategies must **consume shared POCO services** (`CheckDetector`, `DrawDetector`, `MoveValidator` from ADR-0001) — never duplicate chess rules in the AI layer. | ADR-0002 §Implementation Guidelines |
| C-04 | AI strategies must hold **no persistent state between turns** (or state that is resettable per game). | ADR-0002 §Implementation Guidelines |
| C-05 | `AIStrategyHard` must **abort and return the best move found** if the 5 s timeout is exceeded — never block the game. | ADR-0002 §Risks |
| C-06 | Pause gameplay with **`Time.timeScale = 0`**; resume with `Time.timeScale = 1` (or restore previous value). | ADR-0007 §Decision |
| C-07 | All coroutines that must run **during a pause** (overlay UI, typewriter, dice animations) use **`WaitForSecondsRealtime`** — never `WaitForSeconds`. | ADR-0007 §Implementation Guidelines, ADR-0012 §Risks |
| C-08 | **Restore `timeScale` in `OnDestroy()`/`OnDisable()`** of the pausing controller if the scene might be unloaded while paused. | ADR-0007 §Implementation Guidelines |
| C-09 | Overlay flows (Purgatory: Offer → Dice → Result) must be **Canvas overlays within the same scene** — never `LoadScene` during the flow. The board and its state remain in memory. | ADR-0006 §Implementation Guidelines |
| C-10 | **Block board input** while any overlay is active. | ADR-0006 §Validation Criteria |
| C-11 | The **sole canonical `SceneTransitionManager`** is the `Core/` version with API `LoadScene(string, Action)`. It auto-creates `FadeCanvas`/`CanvasGroup`/`FadeImage` at runtime if missing. | ADR-0009 §Decision |
| C-12 | Generate position hashes using the **FEN-like string** format: piece layout + side to move + castling rights + en passant target (not Zobrist). Regenerate only on move, not per frame. | ADR-0008 §Implementation Guidelines |
| C-13 | Normalize the FEN hash to a **canonical form** (invariant culture, consistent row order) to avoid false negatives in repetition detection. | ADR-0008 §Risks |
### Must Never Do
| ID | Rule | Source |
|----|------|--------|
| C-N01 | **Never hardcode AI difficulty** with if/switch inside `AIController`. Add difficulty by implementing `IAIStrategy`. | ADR-0002 §Alternatives Considered |
| C-N02 | **Never use `WaitForSeconds` in overlay/UI coroutines** that must survive a `timeScale = 0` pause. | ADR-0007 §Implementation Guidelines |
| C-N03 | **Never load a separate scene** for Purgatory/dice/promotion overlays. | ADR-0006 §Alternatives Considered |
| C-N04 | **Never use the deleted `UI/SceneTransitionManager`** class (`AjedrezPurgatorio.UI.SceneTransitionManager`). Only `Core/SceneTransitionManager` exists. | ADR-0009 §Decision |
| C-N05 | **Never use Zobrist hashing** for position repetition. Use the FEN-like string approach. | ADR-0008 §Alternatives Considered |
| C-N06 | **Never assume `Time.timeScale` is always 1 on resume.** Save and restore the previous value. | ADR-0007 §Risks |
---
## Layer: Feature (depends on Core)
_Covers: Piece Identity lifecycle, Dice System, Dialogue System, Dead Kings System._
_Sources: ADR-0010, ADR-0011, ADR-0012, ADR-0013_
### Must Do
| ID | Rule | Source |
|----|------|--------|
| FT-01 | `PieceIdentity` SOs hold **static identity data only**: `characterName`, `role`, `relationship`, `quotes[]`, `pieceType`. No `isAlive` field as source of truth. | ADR-0010 §Decision |
| FT-02 | Piece lifecycle state (Alive, Captured, In Purgatory, Recovered, Dead) is owned **exclusively by `CampaignState`** — the single writer. Query via `CampaignState.IsPieceAlive(name)`. | ADR-0010 §Decision |
| FT-03 | `PieceIdentityManager.AssignIdentities()` assigns identities **by piece type** at the start of each board, filtering by `CampaignState` availability. | ADR-0010 §Implementation Guidelines |
| FT-04 | The **King is never sent to Purgatory** — skip the dice flow entirely when the captured piece is the King. | ADR-0010, ADR-0011 §Implementation Guidelines |
| FT-05 | Dice logic lives in **`DiceSystem` as pure logic** (no MonoBehaviour dependency). Methods: `Roll2d6()`, `RollForPlayer(PieceIdentity, int visits)`, `RollForDeath()`, `DetermineWinner(int, int)`. | ADR-0011 §Decision |
| FT-06 | Dice formula: `player_roll = 2d6 + piece_bonus + desperation_bonus - purgatory_penalty`; `death_roll = 2d6`; **tie goes to Death**; clamp minimum total to **2**. | ADR-0011 §Context, §Key Interfaces |
| FT-07 | Dice modifiers: Queen **+2**, Rook/Bishop/Knight **+1**, Pawn **0**. Desperation bonus = number of white pieces lost. Penalty = **1 per purgatory visit** on the same board. | ADR-0011 §Context |
| FT-08 | Enforce **max 3 purgatory visits per board**. On 4th capture → direct `MarkPieceDead` (permanent death, no dice). | ADR-0011 §Implementation Guidelines |
| FT-09 | **Closing the overlay during purgatory = "No"** (anti-exploit). The piece is lost for the current board (not permanently, unless quota exhausted). | ADR-0011 §Implementation Guidelines |
| FT-10 | Only the **last capture in a sequence** offers purgatory. | ADR-0011 §Implementation Guidelines |
| FT-11 | `PurgatoryManager` (singleton Awake-explicit) orchestrates the flow: event → guard → offer (timeScale=0) → dice coroutine (**WaitForSecondsRealtime**) → apply result via `CampaignState.MarkPieceRecovered/MarkPieceDead` → resume (timeScale=1). | ADR-0011 §Decision |
| FT-12 | Dice UI animations use **`WaitForSecondsRealtime`** to avoid freezing during `timeScale = 0`. | ADR-0011 §Implementation Guidelines, ADR-0007 |
| FT-13 | Target probabilities: base **~42%**, Queen **~58%**, Pawn 3rd visit **~28%**. Validate with distribution tests. | ADR-0011 §Implementation Guidelines |
| FT-14 | Dialogue content is loaded from **TextAsset JSON files** via `JsonUtility`. Never hardcode dialogue text in C#. | ADR-0012 §Decision |
| FT-15 | DialogueNode schema: `{ id, speaker, portrait, text, next, conditions[] }` where each condition has `{ type, param, nextNode }`. Valid types: `piece_alive`, `chapter_complete`, `pieces_lost_count`, `default`. | ADR-0012 §Decision |
| FT-16 | Anti-skip dialogue: **first click completes** the current typewriter node, **second click advances** to the next node. | ADR-0012 §Implementation Guidelines |
| FT-17 | Branching evaluation order: evaluate conditions in list order; `default` is the explicit fallback; if no condition matches and no `default` exists, follow the node's `next` field. | ADR-0012 §Implementation Guidelines |
| FT-18 | Fail-safes: nonexistent piece → `false` + default node; missing portrait → text without portrait; invalid JSON → `try/catch` + log error per file + skip that file. | ADR-0012 §Risks, §Decision |
| FT-19 | In-game **quotes** (from piece capture): display as a brief **overlay (12 s) without pausing** the game (`timeScale` stays at 1). | ADR-0012 §Implementation Guidelines, ADR-0006 |
| FT-20 | `OnDialogueComplete` must fire an event to **notify Game State** for state transitions (intro→board, outro→next chapter/memorial). | ADR-0012 §Implementation Guidelines |
| FT-21 | `DialogueSystem` (singleton Awake-explicit) loads all dialogue TextAssets into a `Dictionary<string, DialogueData>` on `Awake()`. | ADR-0012 §Current State |
| FT-22 | `DeadKingPool` persists as **JSON** in `Application.persistentDataPath/dead_kings.json` using `JsonUtility` with wrapper `DeadKingPoolData { List<DeadKingData> }`. | ADR-0013 §Decision |
| FT-23 | Pool enforces **FIFO with max 100 entries**. On insert when full, remove the oldest entry by `date`. | ADR-0013 §Implementation Guidelines |
| FT-24 | **Content filtering**: replace profanity (case-insensitive) with `***` using regex. Never block the submission. | ADR-0013 §Implementation Guidelines |
| FT-25 | Spawn probability: `ShouldSpawnDeadKing(chapterIndex)` returns `Random.value < base + chapterIndex × multiplier` **AND** `pool.Count > 0`. Pool empty → use predefined standard king. | ADR-0013 §Decision |
| FT-26 | Corrupt pool file → log warning + create **new empty pool** (graceful degradation, never crash). | ADR-0013 §Implementation Guidelines |
| FT-27 | Dead King input screen: name max **20 chars**, message max **100 chars**, **500 ms debounce** on submit button, empty name → `"Anónimo"`. | ADR-0013 §Decision |
| FT-28 | `DeadKingPool` is loaded via `Resources.Load<DeadKingPool>("DeadKingPool")` inside the singleton (centralized, ADR-0004). Consumers never call `Resources.Load` directly. | ADR-0004, ADR-0013 |
### Must Never Do
| ID | Rule | Source |
|----|------|--------|
| FT-N01 | **Never read `PieceIdentity.isAlive`** as source of truth for piece lifecycle. Always use `CampaignState.IsPieceAlive(name)`. | ADR-0010 §Implementation Guidelines |
| FT-N02 | **Never put business logic inside a ScriptableObject.** Dice math lives in `DiceSystem`, not in `BalanceConfig`. | ADR-0005, ADR-0011 §Decision |
| FT-N03 | **Never block or reject** a Dead King submission due to profanity. Always replace and submit. | ADR-0013 §Implementation Guidelines |
| FT-N04 | **Never hardcode dialogue text** in C# classes. All dialogue must come from JSON TextAssets. | ADR-0012 §Alternatives Considered |
| FT-N05 | **Never allow the King to enter the Purgatory dice flow.** Guard in `PurgatoryManager.OnPieceCaptured`. | ADR-0010, ADR-0011 |
| FT-N06 | **Never use `WaitForSeconds`** in dice UI coroutines during purgatory (timeScale=0). Use `WaitForSecondsRealtime`. | ADR-0011 §Implementation Guidelines |
| FT-N07 | **Never let `DiceSystem` reference `GameManager.Instance` directly** for desperation calculation. Pass the piece count as a parameter (debt, migrate when able). | ADR-0011 §Risks |
---
## Layer: Presentation (depends on Features)
_Covers: Audio system integration, UI consumption of events._
_Sources: ADR-0014, ADR-0003 (UI consumption), ADR-0006 (overlay UI rendering)_
### Must Do
| ID | Rule | Source |
|----|------|--------|
| P-01 | `AudioManager` is a **singleton MonoBehaviour** using the **Awake-explicit** pattern (migrate from current lazy-getter). `Instance { get; private set; }` + guard in `Awake()` + `DontDestroyOnLoad`. | ADR-0014 §Implementation Guidelines |
| P-02 | AudioManager exposes **two internal buses**: `_sfxSource` (one-shot via `PlayOneShot`, default volume 0.7) and `_musicSource` (loop via `Play()`, default volume 0.5). Both with `playOnAwake = false`. | ADR-0014 §Decision |
| P-03 | SFX API per event: `PlayMove()`, `PlayCapture()`, `PlayCheck()`, `PlayCheckmate()`, `PlayPromotion()`, `PlayInvalidMove()`, `PlaySFX(AudioClip, float volumeMultiplier)`. | ADR-0014 §Key Interfaces |
| P-04 | Music API: `PlayMusic(AudioClip, bool loop)`, `StopMusic()`. Scene music is **decided by Scene Management** (ADR-0009) after each transition. | ADR-0014 §Implementation Guidelines |
| P-05 | Volume controls: `SetSFXVolume(float)`, `SetMusicVolume(float)` — independent, adjustable at runtime. | ADR-0014 §Decision |
| P-06 | Maintain exactly **one active `AudioListener`** in the scene (on the main camera). Disable any extra listeners. | ADR-0014 §Constraints |
| P-07 | SFX clips are assigned as **`[SerializeField]`** in the inspector — never loaded by code. | ADR-0014 §Implementation Guidelines |
| P-08 | Optionally use **AudioMixer** (Master → SFX, Music) for volume grouping and ducking during dialogue. Not required for Vertical Slice. | ADR-0014 §Implementation Guidelines |
| P-09 | UI event subscribers (GameHUD, PurgatoryOfferUI, DiceRollUI, DiceResultUI, DialogueUI) **subscribe in `OnEnable()`** and **unsubscribe in `OnDisable()`**. | ADR-0003 §Key Interfaces |
| P-10 | Overlay Canvas renders at **sortingOrder 999** (set by `SceneTransitionManager` auto-creation). | ADR-0009 §Architecture |
### Must Never Do
| ID | Rule | Source |
|----|------|--------|
| P-N01 | **Never auto-create the `AudioManager` GameObject in the singleton getter** (lazy pattern). The AudioManager must exist in the initial scene or be explicitly instantiated at boot. | ADR-0014 §Implementation Guidelines |
| P-N02 | **Never call `AudioSource.Play()` for SFX** — use `PlayOneShot()` so sounds can overlap. | ADR-0014 §Alternatives Considered |
| P-N03 | **Never have multiple `AudioListener` components active** simultaneously (causes audio artifacts). | ADR-0014 §Risks |
| P-N04 | **Never subscribe to manager events from `Awake()`** — use `OnEnable()` so subscriptions align with the Unity lifecycle and can be cleanly paired with `OnDisable()` unsubscriptions. | ADR-0003 §Key Interfaces |
---
## Layer: Polish
_Covers: testing requirements, validation, regression coverage._
_Sources: technical-preferences.md §Testing, all ADR Validation Criteria_
### Must Do
| ID | Rule | Source |
|----|------|--------|
| PL-01 | Write unit tests using **Unity Test Framework (NUnit)** in `Tests/Unit/`. | technical-preferences.md §Testing |
| PL-02 | Achieve **100% test coverage** for all balance formulas: dice rolls, effective difficulty, spawn chance, desperation bonus, penalty accumulation, clamp minimum. | technical-preferences.md §Testing |
| PL-03 | Write tests for **gameplay system pure logic**: Piece Identity lifecycle transitions, Dice results distribution, Dead Kings pool FIFO/sanitization, dialogue branching conditions. | technical-preferences.md §Testing |
| PL-04 | Validate AI difficulty scaling: `Hard` never exceeds the **5 s timeout** per move (verify in playtest). | ADR-0002 §Validation Criteria |
| PL-05 | Run **`grep -l "if (_instance == null)"`** across `Assets/Game/Scripts` — must return **0 results** (confirming no lazy-getters remain). | ADR-0000 §Validation Criteria |
| PL-06 | Verify every POCO service (`CheckDetector`, `DrawDetector`, `MoveValidator`) **does not import `UnityEngine`**. | ADR-0001 §Validation Criteria |
| PL-07 | Verify `PieceIdentity.isAlive` is **not read outside the SO** (grep returns 0, excluding editor cache). | ADR-0010 §Validation Criteria |
| PL-08 | Verify the FEN hash is **stable between calls** (normalized, culture-invariant). Two identical positions must produce the same string. | ADR-0008 §Validation Criteria |
| PL-09 | Verify dialogue anti-skip: first click **completes** typewriter, second click **advances** node. | ADR-0012 §Validation Criteria |
| PL-10 | Verify Dead Kings FIFO: pool **never exceeds 100**; oldest entry removed on insert when full. | ADR-0013 §Validation Criteria |
| PL-11 | Verify single `AudioListener` active; `AudioManager` grep for `if (_instance == null)` returns **only the Awake guard** (no auto-creation). | ADR-0014 §Validation Criteria |
### Must Never Do
| ID | Rule | Source |
|----|------|--------|
| PL-N01 | **Never mark a story complete** without running the smoke check gate (`/smoke-check`) and confirming PASS. | CLAUDE.md (smoke-check skill) |
| PL-N02 | **Never skip Edit Mode unit tests** for any new POCO service or balance formula change. | technical-preferences.md §Testing |
---
## Cross-Cutting Rules
_These rules apply across all layers._
### Performance Budgets
| Metric | Budget | Source |
|--------|--------|--------|
| Target framerate | **60 FPS** (locked) | technical-preferences.md |
| Frame budget | **16.6 ms** total; gameplay logic **≤ 4 ms** | technical-preferences.md |
| Draw calls | **≤ 200** (2D sprites + UGUI batched) | technical-prepreferences.md |
| Memory ceiling | **≤ 1.5 GB** (PC) | technical-preferences.md |
| AIStrategyHard timeout | **≤ 5 s** per move (abort + best-found fallback) | ADR-0002 |
| Dice UI overlay duration | Deterministic (coroutine-driven, not timed by frame) | ADR-0011 |
| Dead Kings pool max | **100 entries** (FIFO) | ADR-0013 |
### Naming Conventions
| Element | Convention | Example | Source |
|---------|-----------|---------|--------|
| Classes | PascalCase | `CheckDetector`, `PurgatoryManager` | technical-preferences.md |
| Public fields / properties | PascalCase | `MoveSpeed`, `Instance` | technical-preferences.md |
| Private fields | `_camelCase` | `_moveSpeed`, `_sfxSource` | technical-preferences.md |
| Events / signals | PascalCase + `On` prefix | `OnPieceCaptured`, `OnCheckResolved` | ADR-0000, ADR-0003 |
| Files | PascalCase matching class | `CheckDetector.cs` | technical-preferences.md |
| Scenes / Prefabs | PascalCase matching root object | `Chapter1.unity` | technical-preferences.md |
| Constants | PascalCase or UPPER_SNAKE_CASE | `MaxPoolSize`, `MAX_VISITS` | technical-preferences.md |
### Forbidden Patterns (all layers)
| ID | Pattern | Replacement | Source |
|----|---------|-------------|--------|
| X-01 | `lazy_getter_singleton` (auto-creates GameObject in getter) | Awake-explicit singleton (F-01) | technical-preferences.md, ADR-0000 |
| X-02 | Duplicate manager per responsibility | Single canonical manager (F-10) | technical-preferences.md, ADR-0009 |
| X-03 | Piece lifecycle state in SO (`PieceIdentity.isAlive`) | `CampaignState` as single writer (FT-02) | technical-preferences.md, ADR-0010 |
| X-04 | `BinaryFormatter` / `PlayerPrefs` for saves | `JsonUtility` + `persistentDataPath` (F-05) | ADR-0000 |
| X-05 | Global event bus (UnityEvent routing / messages) | Direct C# `event Action<T>` on producer (F-07) | ADR-0003 |
| X-06 | `WaitForSeconds` in coroutines during `timeScale=0` | `WaitForSecondsRealtime` (C-07) | ADR-0007 |
| X-07 | `Resources.Load` called from consumer code | Centralized load API inside owning singleton (F-06) | ADR-0004, ADR-0005 |
| X-08 | Business logic inside ScriptableObject classes | POCO services (F-03, F-04) | ADR-0005 |
| X-09 | Hardcoded dialogue text in C# | TextAsset JSON + JsonUtility (FT-14) | ADR-0012 |
### Engine Constraints
| Constraint | Detail | Source |
|-----------|--------|--------|
| Engine version | Unity 6.3 LTS (6000.3.13f1) — pinned | VERSION.md |
| Rendering | URP 17.3.0 (2D) | technical-preferences.md |
| Deprecated APIs in use (accepted for VS) | `Input` legacy (DialogueUI, PauseMenuController), `Resources.Load` (DeadKingPool) | ADR-0000 §Constraints |
| UI framework | UGUI + TextMeshPro (deprecated but maintained) | ADR-0000 §Constraints |
| Serialization | `JsonUtility` — does not serialize `[SerializeField]` privates or dictionaries; requires explicit `[Serializable]` wrappers | ADR-0000, ADR-0005 |
### Mandatory Test Coverage
| System | What to test | Framework | Source |
|--------|-------------|-----------|--------|
| Balance formulas | Dice rolls, effective_difficulty, spawn_chance, desperation_bonus, penalty, clamp | NUnit (Edit Mode) | technical-preferences.md |
| Campaign state rules | Piece lifecycle transitions, GetAvailablePiecesForNextBoard | NUnit (Edit Mode) | technical-preferences.md |
| Dice system | DetermineWinner (incl. tie→Death), modifiers, 3-visit cap, close="No" | NUnit (Edit Mode) | ADR-0011 |
| Dead Kings pool | FIFO rotation, sanitization (profanity→***), ShouldSpawnDeadKing formula, fallbacks | NUnit (Edit Mode) | ADR-0013 |
| Dialogue branching | piece_alive/chapter_complete/pieces_lost_count/default evaluation, fail-safes | NUnit (Edit Mode) | ADR-0012 |
| Position hashing | FEN normalization, repetition count, invariant culture | NUnit (Edit Mode) | ADR-0008 |
| POCO services | No UnityEngine import; CheckDetector, DrawDetector, MoveValidator pure logic | Edit Mode grep + tests | ADR-0001 |
---
_Generated: 2026-08-17 — from 15 Accepted ADRs (00000014), technical-preferences.md, VERSION.md._
@@ -18,7 +18,7 @@
- [x] Master architecture — `docs/architecture/architecture.md`
- [x] Traceability index — `traceability-index.md` + alias `architecture-traceability.md`
- [x] Architecture review — reporte PASS (15 ADRs, ✅118/⚠️13/❌14)
- [x] Accessibility — `design/accessibility-requirements.md` (tier Standard)
- [x] Accessibility — `design/ux/accessibility-requirements.md` (tier Standard)
- [x] Interaction patterns — `design/ux/interaction-patterns.md` (11 patrones)
- [x] Architecture DAG — 0 ciclos, 15/15 validados