@trycore/spec-build-harness 0.2.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/GOVERNANCE.md +24 -5
  3. package/INSTALL.md +11 -6
  4. package/METODOLOGIA.md +18 -4
  5. package/README.md +12 -7
  6. package/VERSION +1 -1
  7. package/agents/build/build-orchestrator.md +6 -1
  8. package/agents/build/dor-dod-gatekeeper.md +13 -6
  9. package/agents/build/ux-fidelity-reviewer.md +61 -0
  10. package/commands/build/onboard.md +20 -4
  11. package/commands/build/reflect.md +163 -0
  12. package/dist/commands/doctor.js +35 -0
  13. package/dist/commands/init.js +32 -9
  14. package/dist/commands/status.js +4 -0
  15. package/dist/commands/uninstall.js +4 -1
  16. package/dist/lib/settings-merge.js +2 -2
  17. package/dist/lib/state-seed.js +1 -0
  18. package/docs/agents.md +2 -1
  19. package/docs/commands.md +10 -4
  20. package/docs/customization/lsp-extensions.md +90 -0
  21. package/docs/customization/mcp-extensions.md +3 -0
  22. package/docs/getting-started.md +14 -5
  23. package/docs/hooks.md +30 -8
  24. package/hooks/build/design-source-guard.sh +52 -0
  25. package/hooks/build/lint-typecheck.sh +21 -1
  26. package/hooks/build/reflect-nudge.sh +29 -0
  27. package/hooks/build-harness.json +8 -0
  28. package/package.json +2 -1
  29. package/skills/building-a-micro-change/SKILL.md +78 -0
  30. package/skills/building-a-slice/SKILL.md +26 -1
  31. package/skills/building-a-slice/references/dod.md +4 -0
  32. package/skills/building-a-slice/references/dor.md +5 -2
  33. package/skills/building-a-slice/references/gitflow.md +3 -1
  34. package/skills/building-a-slice/references/mcp-map.md +1 -0
  35. package/state/README.md +21 -0
  36. package/state/build-state.schema.json +19 -1
  37. package/state/build-state.template.json +8 -0
  38. package/templates/CLAUDE.md.template +8 -1
  39. package/templates/settings-hooks.template.json +1 -1
  40. package/docs/superpowers/specs/2026-06-02-scaffold-gate-design.md +0 -87
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trycore/spec-build-harness",
3
- "version": "0.2.0",
3
+ "version": "0.5.0",
4
4
  "description": "Arnés agéntico de construcción de Trycore para Claude Code: pipeline de dos loops (slice por épica + release gate) con gates de calidad, estado compartido y OpenSpec. Compañero de @trycore/spec-product-flow. Agnóstico al proyecto.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,7 @@
18
18
  "templates/",
19
19
  "internal/",
20
20
  "docs/",
21
+ "!docs/superpowers",
21
22
  "scripts/",
22
23
  "METODOLOGIA.md",
23
24
  "GOVERNANCE.md",
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: building-a-micro-change
3
+ description: Use for genuine maintenance that is NOT new product capability — a typo, a copy/string tweak, a dependency version bump within the stack allowlist, an infra/config/docs change, or a small bug fix of a few lines that adds no new capability. Lightweight lane — branch fix/*|chore/* → change → regression test only if behavior changes → PR — WITHOUT opening active_slice, an epic (EP-XXX), or an OpenSpec change. HARD LIMITS: escalate to building-a-slice (a full epic) if the change adds a new dependency, creates a new public API/endpoint, or changes domain logic or the data model/invariants. The epic stays the unit for product construction; this lane is out-of-band maintenance only.
4
+ ---
5
+
6
+ # Micro-change (mantenimiento) — carril ligero
7
+
8
+ Carril para **mantenimiento que no es construcción de producto nueva**. Espeja la filosofía del
9
+ arnés: la épica es la unidad de **construcción**, pero un typo o un bump de dependencia **no son
10
+ construcción** — forzarlos por las 8 fases de `building-a-slice` es ceremonia desproporcionada. Este
11
+ carril les da una vía corta **sin** diluir los guardarraíles deterministas.
12
+
13
+ > **Si una regla aquí contradice la metodología Trycore (`METODOLOGIA.md`), gana la metodología.**
14
+
15
+ ## Paso 0 · Decision gate (obligatorio) — ¿es esto un micro-change?
16
+
17
+ Un cambio califica como micro-change **solo si cumple TODO**:
18
+
19
+ - **No añade capacidad de producto nueva.** Corrige, ajusta o mantiene algo que ya existe.
20
+ - **Alcance acotado:** pocas líneas / una sola preocupación. No toca múltiples módulos a la vez.
21
+ - **Proyecto en fase `active`** (el scaffold runnable ya existe y está confirmado). El carril **no**
22
+ es para arrancar proyectos (eso es la Fase 0 de `building-a-slice`).
23
+
24
+ Ejemplos típicos (neutros): corregir un typo o un texto visible; ajustar un valor de configuración;
25
+ actualizar la versión de una dependencia **ya presente en la allowlist**; cambios de docs; un fix de
26
+ una a pocas líneas que repara un comportamiento sin introducir nada nuevo.
27
+
28
+ ### Límites DUROS — si el cambio cruza **cualquiera**, STOP: esto es una épica
29
+
30
+ Escala a `building-a-slice` (abre una épica `EP-XXX` con su DoR) si el cambio:
31
+
32
+ 1. **Añade una dependencia nueva** (fuera de `stack-allowlist.json`). *Lo bloquea además
33
+ `stack-guard.sh` de forma determinista.*
34
+ 2. **Crea un endpoint o una API pública nueva.**
35
+ 3. **Cambia lógica de dominio** o el **modelo/invariantes de datos**.
36
+ 4. **Desborda el alcance acotado** (introduce capacidad, toca muchos archivos, mezcla preocupaciones).
37
+
38
+ Ante la duda, **es una épica**. El carril micro-change nunca es un atajo para esquivar gates de
39
+ producto.
40
+
41
+ ## Pipeline ligero
42
+
43
+ 1. **Rama tipada.** Crea `fix/<slug>` (corrección) o `chore/<slug>` (infra/config/docs/bump).
44
+ `gitflow-guard.sh` ya exige rama tipada y prohíbe commit/push directo a `main`.
45
+ 2. **Aplica el cambio acotado.** Mantente dentro de los límites duros. Si al implementar descubres
46
+ que cruzas uno, **detente y escala** a `building-a-slice`.
47
+ 3. **Test de regresión — solo si cambia comportamiento.** Si el micro-change repara un bug,
48
+ añade/ajusta un test que falle antes y pase después (red→green del fix, delega en
49
+ `superpowers:test-driven-development`). Para cambios **no conductuales** (typo en copy, docs,
50
+ config) **no** se exige test.
51
+ 4. **PR a `main`.** Abre el Pull Request (`gitflow-guard.sh` impide la integración por push directo).
52
+ En la descripción del PR indica que es un micro-change y por qué califica (qué límite NO cruza).
53
+
54
+ ## Qué se mantiene y qué se salta
55
+
56
+ | Se mantiene (gratis, vía hooks deterministas) | Se salta (por diseño) |
57
+ |---|---|
58
+ | `gitflow-guard` (rama tipada + PR) | DoR formal (escenarios G/W/T, INVEST) |
59
+ | `stack-guard` (no dependencia nueva) | OpenSpec change + bloque `## Trazabilidad` |
60
+ | `lint-typecheck` (estilo + typecheck incremental) | `journey_smoke`, `api`, `data`, DoD reducido |
61
+ | | Apertura de `active_slice` / decisión de Release Gate |
62
+
63
+ `scaffold-guard` no aplica: no hay slice activo y el carril exige proyecto en fase `active` (scaffold
64
+ ya confirmado).
65
+
66
+ ## Estado y trazabilidad
67
+
68
+ El micro-change **no escribe** `build-state.json` — es mantenimiento fuera de banda, trazado por el
69
+ historial de git y el PR. No entra a `history[]`, así que `reflect-nudge.sh` **no** sugiere
70
+ reflexionar por él (no hay aprendizaje de épica que capturar en un typo).
71
+
72
+ ## Reglas duras
73
+
74
+ - **El decision gate es obligatorio.** Si dudas si algo es micro-change o épica, **es épica**.
75
+ - **Límites duros = STOP, no excepción.** Cruzar un límite obliga a escalar a `building-a-slice`;
76
+ jamás se "fuerza" un micro-change para evitar el DoR.
77
+ - **Integración solo por PR** a `main` (lo respalda `gitflow-guard.sh`).
78
+ - Si una regla aquí contradice `METODOLOGIA.md`, **gana la metodología**.
@@ -14,6 +14,12 @@ el avance en el estado.
14
14
  > rama = un PR. Las HU de la épica (que siguen viviendo en `docs/04-historias/`) son el **alcance
15
15
  > interno** del change y se listan en `active_slice.hus[]`. Construir por HU suelta es sobre-ingeniería.
16
16
 
17
+ > **¿Mantenimiento, no producto nuevo?** Un typo, un bump de dependencia ya permitida, un ajuste de
18
+ > copy/config/docs o un fix de pocas líneas **sin nueva capacidad** NO abren una épica: usa la skill
19
+ > **`building-a-micro-change`** (carril ligero `fix/*`|`chore/*` → cambio → PR). Si ese micro-change
20
+ > cruza un **límite duro** (dependencia nueva, API/endpoint nuevo, lógica de dominio o datos), escala
21
+ > **aquí** y ábrelo como épica.
22
+
17
23
  ## Principio de operación
18
24
  - **Una sola fuente de verdad**: `.claude/state/build-state.json` (schema + protocolo en
19
25
  `.claude/state/README.md`). Lee antes de actuar; escribe una vez por transición.
@@ -50,6 +56,21 @@ camina* se construye **encima** del scaffold ya existente.
50
56
  3. El gate lo valida también el `dor-dod-gatekeeper` (criterio duro de DoR) y lo respalda el hook
51
57
  determinista `scaffold-guard.sh` (bloquea escribir código de slice sin scaffold confirmado).
52
58
 
59
+ ## Fase 0-bis · Fuente de diseño (seguro para slices con UI)
60
+
61
+ Espejo de la Fase 0, para proyectos **con UI**. Antes de abrir el primer slice con UI:
62
+ 1. Lee `design_source` en `build-state.json`.
63
+ - `applies` indeterminado (ausente) → pregunta *"¿este proyecto tiene UI?"* y fija `applies`.
64
+ - `applies === false` → N/A, salta esta fase.
65
+ - `confirmed === true` → continúa.
66
+ 2. `applies===true && confirmed===false` → **pregunta explícita** (AskUserQuestion): *"¿Existe una
67
+ fuente de diseño declarada (prototipo/export) para la UI de este proyecto?"*
68
+ - **No** → **STOP**. Indica declararla (ruta/URL del prototipo o export). El arnés **NO la genera**.
69
+ No abras el slice con UI.
70
+ - **Sí** → registra `design_source.source`, `confirmed=true`, `confirmed_by`, `confirmed_at`, `notes`.
71
+ 3. Lo respalda el hook determinista `design-source-guard.sh` (bloquea código de slice UI sin fuente
72
+ confirmada) y lo valida el `dor-dod-gatekeeper` (criterio duro de DoR).
73
+
53
74
  ## Pipeline — inner loop (carga la referencia indicada en cada paso)
54
75
 
55
76
  | Fase | Acción | Delega en | Gate | Referencia |
@@ -57,7 +78,7 @@ camina* se construye **encima** del scaffold ya existente.
57
78
  | 1 · dor | Validar Definition of Ready | `dor-dod-gatekeeper` | `dor` | `dor.md` |
58
79
  | 2 · change | `opsx:new` + bloque `## Trazabilidad`; validar enlace (barato) | `opsx:new`, `change-epic-coherence` | `coherence_link` | `link-change-epic.md` |
59
80
  | 3 · tdd | red → green → refactor | `superpowers:test-driven-development` | `tdd` | — |
60
- | 4 · smoke | Recorrer el journey-hasta-aquí end-to-end | skill `verify` / `run` (+ MCP chrome-devtools) | `journey_smoke` | `mcp-map.md` |
81
+ | 4 · smoke | Recorrer el journey-hasta-aquí end-to-end; **slices con UI:** verificar fidelidad a la fuente de diseño | skill `verify` / `run` (+ MCP chrome-devtools), `ux-fidelity-reviewer` | `journey_smoke`,`fidelity` | `mcp-map.md` |
61
82
  | 5 · api/data | contratos + consistencia (si aplican al slice) | `api-contract-tester`, `data-consistency-checker` | `api`,`data` | `newman-tests.md`, `data-consistency.md` |
62
83
  | 6 · dod | Definition of Done (por slice, reducido) | `dor-dod-gatekeeper` | `dod` | `dod.md` |
63
84
  | 7 · pr | Abrir PR + archivar change en el mismo PR | `opsx:archive`, `opsx:sync` | — | `gitflow.md` |
@@ -67,6 +88,10 @@ Los gates `stack`, `security`, `smell`, `ux` y la coherencia triple completa **y
67
88
  aquí**: pertenecen al Release Gate. Las **deps** siguen vigiladas en tiempo real por el hook
68
89
  `stack-guard.sh`; lint/tsc/gitflow por sus hooks.
69
90
 
91
+ El gate `fidelity` (fidelidad a la fuente de diseño) **sí** es de inner loop: es barato (se computa
92
+ en `smoke`, con la app ya levantada) y vivo por-slice; complementa al `ux-krug-reviewer` (usabilidad),
93
+ que sigue en el Release Gate.
94
+
70
95
  MCP/LSP por gate: ver `references/mcp-map.md`. Protocolo de estado: `references/state-protocol.md`.
71
96
 
72
97
  ## Fase 8 · ¿Release Gate ahora? (default computado, humano decide)
@@ -11,6 +11,10 @@ pesadas (seguridad, diseño, UX, coherencia triple, arquitectura, integración)
11
11
  - [ ] **`coherence_link`** — `change-epic-coherence` confirma el enlace change↔épica (bloque `## Trazabilidad`, `openspec validate` ok). Es el chequeo **barato**; la trazabilidad triple completa va al Release Gate.
12
12
  - [ ] **`data`** — `data-consistency-checker` valida invariantes de datos (salida de servicios externos validada contra esquema antes de alimentar la capa de decisión determinista del dominio) (si el slice toca datos).
13
13
  - [ ] **`api`** — `api-contract-tester` (Newman) 100% verde (o `null` si el slice no tiene endpoints).
14
+ - [ ] **`fidelity` (slices con UI)** — `ux-fidelity-reviewer` devuelve **FIEL** (o DESVIACIONES todas
15
+ justificadas/documentadas) → `gates.fidelity: true`; `null` si el slice no tiene UI. INCONCLUSO
16
+ (MCP no disponible) se registra, **no bloquea**. Es gate **vivo** de inner loop (no la revisión Krug,
17
+ que sigue en el Release Gate).
14
18
  - [ ] **OpenSpec**: todas las tasks `[x]`; el archive del change va **en el mismo PR** (no PR aparte).
15
19
  - [ ] **Docs/trazabilidad**: back-ref del change añadida en la épica y en cada HU de `hus[]`.
16
20
  - [ ] **Hooks verdes (automáticos, no son gates de agente)**: `lint-typecheck.sh` (lint + chequeo de tipos del stack declarado), `stack-guard.sh` (deps en allowlist según la sección de requisitos técnicos del PRD del consumidor, ruta declarada en `stack-allowlist.json#source`), `gitflow-guard.sh` (rama `feature/*`, sin commits directos a `main`).
@@ -6,12 +6,15 @@ la épica; lo de abajo aplica a la épica y a **cada HU** que cubre (`hus[]`). L
6
6
  - [ ] **Épica válida**: `EP-XXX` existe en `docs/03-backlog/epicas.md` con trazabilidad a objetivos del PRD.
7
7
  - [ ] **HU enumeradas**: la épica tiene ≥1 HU; todas las que entran se listan en `hus[]`.
8
8
  - [ ] **Frontmatter completo** en cada `docs/04-historias/HU-XXX.md`: `id, titulo, epica, prioridad, complejidad, estado` y `estado: lista`.
9
- - [ ] **AC en Given/When/Then** por HU: 35 escenarios, con **happy + error + edge** (regla dura Trycore).
9
+ - [ ] **AC en Given/When/Then** por HU, **proporcional a `complejidad`** (cubre los modos de fallo que *realmente existen*, no una cuota fija): `trivial`/baja → **12** (happy + el error/edge crítico si existe); `media` → **3** (happy + error + edge); `alta` → **3–5** (cobertura completa). Regla dura Trycore: si existe una rama de error/edge, **debe** tener su escenario (lo que se elimina es fabricar 3–5 para una HU trivial).
10
10
  - [ ] **INVEST** por HU: pasa los 6 criterios (Independent, Negotiable, Valuable, Estimable, Small, Testable). Ante duda, invocar `invest-validator`.
11
11
  - [ ] **Dependencias resueltas**: las épicas/HU de las que depende están archivadas (`history[]`) o explícitamente no bloquean.
12
12
  - [ ] **Cabe en el stack** del PRD §7 (no requiere tecnología fuera de `stack-allowlist.json`).
13
13
  - [ ] **Datos de prueba disponibles** o identificables (p.ej. los datos de ejemplo / fixtures sintéticos del dominio del consumidor).
14
+ - [ ] **Fuente de diseño identificada (slices con UI)**: la fuente visual de verdad del slice
15
+ (el `DESIGN_SOURCE` del dominio) está declarada y confirmada (`design_source.confirmed`), y este
16
+ slice apunta a la(s) pantalla(s) equivalente(s). No se construye UI fuera de la fuente declarada.
14
17
 
15
18
  **Si todo ✓** → `dor-dod-gatekeeper` abre `active_slice` en `build-state.json` con `epica`, `hus[]`,
16
- `phase: dor`, `gates.dor: true` y el resto en `false` (`ux`/`api` en `null` si la épica no toca UI/endpoints).
19
+ `phase: dor`, `gates.dor: true` y el resto en `false` (`fidelity`/`api` en `null` si la épica no toca UI/endpoints).
17
20
  **Si algo ✗** → no se abre el slice; se reporta qué falta y se vuelve a discovery (Trycore).
@@ -16,7 +16,9 @@ gh pr create --base main --head feature/<slug> --fill # integración por PR
16
16
 
17
17
  ## Convenciones
18
18
  - **Rama**: `feature/<slug-kebab>` (nuevo valor), `fix/<slug>` (corrección), `chore/<slug>` (infra/docs).
19
- Una rama por **épica** (= un slice): `feature/ep-003-pricing-engine`.
19
+ Una rama por **épica** (= un slice): `feature/ep-003-pricing-engine`. Las ramas `fix/*` y `chore/*`
20
+ son también el carril de la skill `building-a-micro-change` (mantenimiento que no es producto nuevo:
21
+ va a PR sin abrir épica ni `active_slice`; ver sus límites duros).
20
22
  - **Commits**: Conventional Commits (`feat:`, `fix:`, `test:`, `refactor:`, `chore:`, `docs:`).
21
23
  - **PR**: título claro, descripción enlazando la épica, sus HU (`hus[]`) y el OpenSpec change; checks
22
24
  (lint, types, tests, newman) en verde antes de merge; squash recomendado.
@@ -15,6 +15,7 @@ los expone, el gate se cubre con las alternativas CLI/test indicadas.
15
15
  | Fase / agente | MCP (ejemplo, si habilitado) | Para qué |
16
16
  |---|---|---|
17
17
  | `review` · `ux-krug-reviewer` | **chrome-devtools** | `take_snapshot` (árbol accesible), `lighthouse_audit` (Accessibility/Best-Practices), `take_screenshot`, `list_console_messages` para verificar la UI **corriendo**. |
18
+ | `smoke` · `ux-fidelity-reviewer` | **chrome-devtools** *(ejemplo opt-in)* | `new_page`/`navigate_page`, `take_screenshot`, `take_snapshot` para comparar **composición/paleta/tipografía** del diseño vs la app corriendo. Requiere la app levantada; úsalo en fase `active`. Si no hay MCP, el agente degrada a comparación estática (INCONCLUSO). |
18
19
  | `api` · `api-contract-tester` | — (Newman CLI) | Contratos de endpoints. Newman no es MCP; corre vía Bash. |
19
20
  | `data` · `data-consistency-checker` | **postgresql** *(solo si el slice usa Postgres)* | `read_query`/`describe_table` para validar consistencia en BD. Con un almacén embebido/cliente (según el stack declarado en el PRD del consumidor) se valida por tests, sin MCP. |
20
21
  | perf (opcional, fuera del DoD) | **k6** | `execute_k6_test` para carga/latencia si una HU de la épica lo exige. |
package/state/README.md CHANGED
@@ -51,6 +51,26 @@ Arranca en `confirmed: false` y **solo** pasa a `true` por **confirmación expl
51
51
  restrictiva para abrir cualquier slice: el hook `scaffold-guard.sh` bloquea escribir código de
52
52
  slice (fases `red…data`) mientras `confirmed` no sea `true`. El arnés **no genera** el scaffold.
53
53
 
54
+ ### `design_source` (gate de proyecto, slices con UI)
55
+
56
+ Espejo de `scaffold` para la UI: `applies` (¿el proyecto tiene UI?), `confirmed` (humano confirmó que
57
+ existe una fuente de diseño declarada), `source` (puntero al prototipo/export). El arnés NO genera el
58
+ prototipo. Lo respalda `design-source-guard.sh`.
59
+
60
+ ### gate `fidelity` (por-slice, inner loop)
61
+
62
+ `true` = FIEL (o desviaciones justificadas); `false` = desviaciones sin justificar; `null` = slice sin
63
+ UI. Lo computa `ux-fidelity-reviewer` en la fase `smoke` y lo escribe el `build-orchestrator`.
64
+
65
+ ### Reflexión post-slice (ciclo autocorrectivo)
66
+
67
+ Tras archivar un slice, su entrada en `history[]` puede llevar `reflected` / `reflected_at`. El
68
+ hook `reflect-nudge.sh` (evento `Stop`, **no bloqueante**) sugiere ejecutar `/build:reflect` mientras
69
+ exista al menos una entrada con `reflected != true`. `/build:reflect` lo ejecuta el **modelo**:
70
+ detecta convención nueva o error recurrente, **propone** un parche al bloque `trycore-build-learnings`
71
+ de `CLAUDE.md` (se aplica **solo tras tu aprobación**) y estampa `reflected: true` → el nudge calla.
72
+ El razonamiento vive en el modelo; el hook solo es un recordatorio determinista.
73
+
54
74
  ## Quién escribe qué
55
75
 
56
76
  | Campo / gate | Lo escribe | Cadencia |
@@ -62,4 +82,5 @@ slice (fases `red…data`) mientras `confirmed` no sea `true`. El arnés **no ge
62
82
  | `gates.api` | `api-contract-tester` | slice |
63
83
  | `gates.data` | `data-consistency-checker` | slice |
64
84
  | `releases[]` (`security`, `smell`, `ux`, `coherence`, `stack_arch`, `integration`, `status`) | `releasing-a-version` (delega en `security-reviewer`, `simple-design-reviewer`, `ux-krug-reviewer`, `coherence-three-way`, `stack-guardian`) | release |
85
+ | `history[].reflected` · `history[].reflected_at` | `/build:reflect` | post-slice (tras archivar) |
65
86
  | `harness_phase` | `load-build-state.sh` (SessionStart) | — |
@@ -14,6 +14,7 @@
14
14
  "description": "Señal INFORMATIVA auto-detectada: authoring = aún no hay package.json; active = scaffold de código presente. El gate de avance es `scaffold.confirmed`, NO esta señal."
15
15
  },
16
16
  "scaffold": { "$ref": "#/$defs/scaffold" },
17
+ "design_source": { "$ref": "#/$defs/design_source" },
17
18
  "active_slice": {
18
19
  "description": "El slice (épica) en construcción. null si no hay ninguno activo.",
19
20
  "oneOf": [
@@ -45,6 +46,20 @@
45
46
  "notes": { "type": "string", "description": "Evidencia libre (p.ej. 'build/dev arranca vacío sin error')." }
46
47
  }
47
48
  },
49
+ "design_source": {
50
+ "type": "object",
51
+ "additionalProperties": false,
52
+ "description": "Gate de PROYECTO para slices con UI: existe una fuente de diseño declarada (prototipo/export). Espejo de scaffold: confirmed pasa a true SOLO por confirmación humana, nunca por auto-detección. El arnés NO genera el prototipo. applies=false apaga todo el mecanismo (proyecto sin UI).",
53
+ "required": ["applies", "confirmed"],
54
+ "properties": {
55
+ "applies": { "type": "boolean", "description": "¿el proyecto tiene UI / hay diseño que respetar? false → mecanismo N/A." },
56
+ "confirmed": { "type": "boolean", "description": "true solo tras confirmación humana de que existe una fuente de diseño declarada." },
57
+ "confirmed_by": { "type": ["string", "null"], "description": "Agente/skill que registró la confirmación." },
58
+ "confirmed_at": { "type": ["string", "null"], "format": "date-time" },
59
+ "source": { "type": "string", "description": "Puntero a la fuente: ruta/URL del prototipo o export (el DESIGN_SOURCE del dominio)." },
60
+ "notes": { "type": "string", "description": "Evidencia libre (p.ej. 'prototipo en docs/… revisado y vigente')." }
61
+ }
62
+ },
48
63
  "slice": {
49
64
  "type": "object",
50
65
  "additionalProperties": false,
@@ -75,6 +90,7 @@
75
90
  "journey_smoke": { "type": "boolean", "description": "El backbone-hasta-aquí camina end-to-end (verificado con la skill verify/run)." },
76
91
  "coherence_link": { "type": "boolean", "description": "Enlace change↔épica válido (change-epic-coherence, barato, por slice)." },
77
92
  "data": { "type": "boolean" },
93
+ "fidelity": { "type": ["boolean", "null"], "description": "Gate VIVO de inner loop (slices con UI): fidelidad visual a la fuente de diseño declarada, computado en fase smoke por ux-fidelity-reviewer. true = FIEL (o DESVIACIONES justificadas); false = DESVIACIONES sin justificar; null = N/A (slice sin UI). NO es legado (los legados viven en releases[])." },
78
94
  "api": { "type": ["boolean", "null"], "description": "null = N/A (slice sin endpoints)." },
79
95
  "ux": { "type": ["boolean", "null"], "description": "null = N/A (slice sin UI). Legado: hoy se audita en releases[]." },
80
96
  "stack": { "type": "boolean", "description": "Legado por-slice; deps las cubre el hook stack-guard.sh, la arquitectura se audita en releases[]." },
@@ -86,7 +102,9 @@
86
102
  },
87
103
  "updated_at": { "type": "string", "format": "date-time" },
88
104
  "updated_by": { "type": "string", "description": "Agente o hook que escribió el estado." },
89
- "notes": { "type": "string", "description": "Nota libre opcional (p.ej. changes/branches adicionales de una épica construida en varios pasos)." }
105
+ "notes": { "type": "string", "description": "Nota libre opcional (p.ej. changes/branches adicionales de una épica construida en varios pasos)." },
106
+ "reflected": { "type": "boolean", "description": "True si /build:reflect ya capturó los aprendizajes de este slice archivado (ciclo autocorrectivo). Mientras sea false/ausente, reflect-nudge.sh sugiere reflexionar al cerrar sesión." },
107
+ "reflected_at": { "type": "string", "format": "date-time", "description": "Cuándo se reflexionó (ISO-8601 UTC). Lo escribe /build:reflect." }
90
108
  }
91
109
  },
92
110
  "release": {
@@ -7,6 +7,14 @@
7
7
  "confirmed_at": null,
8
8
  "notes": ""
9
9
  },
10
+ "design_source": {
11
+ "applies": false,
12
+ "confirmed": false,
13
+ "confirmed_by": null,
14
+ "confirmed_at": null,
15
+ "source": "",
16
+ "notes": ""
17
+ },
10
18
  "active_slice": null,
11
19
  "history": [],
12
20
  "releases": []
@@ -35,7 +35,7 @@ Outer loop (por release): Release Gate (seguridad · diseño · UX · cohe
35
35
  ### Bloque de dominio (lo resuelve `/build:onboard`)
36
36
 
37
37
  Estos puntos de extensión los leen los agentes `security-reviewer`, `stack-guardian`,
38
- `data-consistency-checker`, `ux-krug-reviewer` y `simple-design-reviewer`:
38
+ `data-consistency-checker`, `ux-krug-reviewer`, `simple-design-reviewer` y `ux-fidelity-reviewer`:
39
39
 
40
40
  - **PRD técnico (fuente del stack)**: {{PRD_TECH_PATH}}
41
41
  - **Capa de servicios externos / IA (frontera)**: {{EXTERNAL_SERVICE_LAYER}}
@@ -43,6 +43,7 @@ Estos puntos de extensión los leen los agentes `security-reviewer`, `stack-guar
43
43
  - **Categorías de datos sensibles / PII reguladas**: {{SENSITIVE_DATA_CATEGORIES}}
44
44
  - **Secretos server-side**: {{SERVER_SIDE_SECRETS}}
45
45
  - **Decisiones de alto impacto que exigen explicabilidad UX**: {{HIGH_STAKES_DECISIONS}}
46
+ - **Fuente de diseño / referencia visual**: {{DESIGN_SOURCE}}
46
47
 
47
48
  (Si aparecen como `{{...}}`, ejecuta `/build:onboard` para parametrizarlos.)
48
49
 
@@ -54,4 +55,10 @@ Estos puntos de extensión los leen los agentes `security-reviewer`, `stack-guar
54
55
 
55
56
  <!-- END trycore-build-harness -->
56
57
 
58
+ <!-- BEGIN trycore-build-learnings -->
59
+ ## Convenciones aprendidas (mantenido por /build:reflect)
60
+
61
+ <!-- /build:reflect propone aquí viñetas concretas (convención nueva o error recurrente) tras cerrar un slice; se agregan SOLO con tu aprobación. Revísalas en PR como cualquier cambio de equipo. -->
62
+ <!-- END trycore-build-learnings -->
63
+
57
64
  <!-- A partir de aquí, el equipo del proyecto puede agregar instrucciones específicas del cliente. -->
@@ -13,7 +13,7 @@
13
13
  ],
14
14
  "PreToolUse": [
15
15
  { "matcher": "Bash", "hooks": [ { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/gitflow-guard.sh\"" } ] },
16
- { "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/stack-guard.sh\"" }, { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/scaffold-guard.sh\"" } ] }
16
+ { "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/stack-guard.sh\"" }, { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/scaffold-guard.sh\"" }, { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/design-source-guard.sh\"" } ] }
17
17
  ],
18
18
  "PostToolUse": [
19
19
  { "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/lint-typecheck.sh\"" }, { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/coherence-flag.sh\"" } ] }
@@ -1,87 +0,0 @@
1
- # Diseño: Scaffold como Paso 1 fundamental (scaffold gate)
2
-
3
- Fecha: 2026-06-02 · Target: `@trycore/spec-build-harness` v0.2.0 · Estado: aprobado (diseño)
4
-
5
- ## Contexto y problema
6
-
7
- Hoy el arnés es **permisivo** respecto al scaffold del proyecto (el esqueleto runnable: `package.json` + framework que arranca vacío). Lo trata como un evento implícito: `harness_phase` pasa de `authoring` a `active` cuando `load-build-state.sh` detecta `package.json`, y los gates de código "no se cierran" en `authoring`, pero nada **exige ni bloquea** explícitamente. La decisión del usuario:
8
-
9
- > Es requerido que exista un scaffold. **No lo forcemos** (el arnés NO lo genera — sigue agnóstico al stack), **pero nuestro setup debe ser restrictivo para avanzar**. Es el **Paso 1 fundamental**. Y debe **preguntarse explícitamente** (no inferirse en silencio de `package.json`).
10
-
11
- Objetivo: convertir "scaffold presente" en una **precondición explícita y restrictiva** — confirmada por el equipo, registrada en el estado, y respaldada por un bloqueo determinista — sin que el arnés genere el scaffold.
12
-
13
- ## Decisiones tomadas (brainstorming)
14
-
15
- 1. **Condición = confirmación explícita**, no inferencia silenciosa de `package.json`.
16
- 2. **Enforcement = skill/agente (Fase 0 de DoR) + gate en estado + hook determinista de respaldo.**
17
- 3. **Regla del hook = Enfoque A (por estado/fase):** bloquea solo cuando un slice está en fase de código sin el scaffold confirmado; permite crear el scaffold (fases `dor`/`change` o sin slice).
18
- 4. **No se genera el scaffold.** El arnés exige, bloquea e instruye; el equipo lo crea (guiado por `stack-allowlist.json`/PRD).
19
-
20
- ## Diseño
21
-
22
- ### 1. Estado (`state/build-state.json` + `build-state.schema.json`)
23
- Nuevo gate **a nivel proyecto** (no por-slice), explícito, default cerrado:
24
-
25
- ```jsonc
26
- "scaffold": {
27
- "confirmed": false,
28
- "confirmed_by": null, // agente/skill que confirmó
29
- "confirmed_at": null, // ISO 8601 UTC
30
- "notes": "" // ej. "Next.js app arranca vacía; npm run dev ok"
31
- }
32
- ```
33
-
34
- - Top-level, junto a `harness_phase`/`active_slice`/`history`/`releases`.
35
- - `harness_phase` (authoring/active) se mantiene como señal **informativa** auto-detectada; el **gate de avance** es `scaffold.confirmed`.
36
- - Solo pasa a `true` por **confirmación explícita** (nunca auto). Una transición = una escritura, con `confirmed_by`/`confirmed_at` (protocolo de `state/README.md`).
37
- - Schema: `scaffold` se añade a `properties` y a `required` del objeto raíz; `build-state.template.json` lo incluye con `confirmed:false`.
38
-
39
- ### 2. Skill `building-a-slice` — Fase 0 (precondición de DoR)
40
- Antes de abrir cualquier slice:
41
- - Si `scaffold.confirmed` ya es `true` → continúa al DoR normal.
42
- - Si es `false` → **pregunta explícitamente** (AskUserQuestion): *"¿Existe un scaffold runnable del proyecto (arranca vacío: build/dev corre sin error)?"*
43
- - **No** → **STOP**. Instruye crearlo según `stack-allowlist.json#source` (PRD) y el stack permitido; **no lo genera**. No abre el slice.
44
- - **Sí** → registra `scaffold.confirmed=true` (con `confirmed_by`, `confirmed_at`, `notes`) y continúa.
45
- - Documenta la relación con el walking skeleton (ver §5).
46
-
47
- ### 3. Agente `dor-dod-gatekeeper`
48
- Añade **"scaffold confirmado"** como criterio **duro** de DoR (primer ítem). No deja pasar a fases de código sin `scaffold.confirmed=true`. Es el dueño de escribir el gate cuando valida el DoR.
49
-
50
- ### 4. Hook determinista `hooks/build/scaffold-guard.sh` (PreToolUse · Write|Edit) — Enfoque A
51
- Backstop ineludible si el agente se salta la Fase 0:
52
- - Resuelve `ROOT` por `git rev-parse --show-toplevel` (+ fallback `${CLAUDE_PROJECT_DIR}`); lee `$ROOT/.claude/state/build-state.json`.
53
- - Guarda python3 fail-closed dirigida (igual patrón que `stack-guard.sh`).
54
- - **Regla de bloqueo:** si `active_slice` existe y `active_slice.phase ∈ {red, green, refactor, smoke, api, data}` **y** `scaffold.confirmed != true` → **exit 2** con mensaje: *"⛔ scaffold-guard: confirma el scaffold (Paso 1) antes de escribir código de slice. Ver building-a-slice / DoR."* En cualquier otro caso (sin slice, o fase `dor`/`change`) → exit 0 (permite crear el scaffold y planificar).
55
- - Auto-arme: si no existe `build-state.json` → exit 0.
56
-
57
- ### 5. Metodología (`METODOLOGIA.md`) — clarificación walking skeleton
58
- - **Paso 1 — Scaffold (precondición, NO generada por el arnés):** esqueleto runnable mínimo del proyecto (build/dev arranca vacío). El equipo lo crea, guiado por el stack del PRD/allowlist; el arnés lo **exige, lo pregunta explícitamente y lo bloquea** hasta confirmarlo.
59
- - **Primer slice — Walking skeleton:** sobre el scaffold confirmado, construye el journey end-to-end más delgado. El scaffold (shell vacío) precede al walking skeleton (primer journey real delgado).
60
-
61
- ### 6. Wiring de canales y CLI
62
- - `src/lib/settings-merge.ts`: añade `scaffold-guard.sh` al `HOOK_SPECS` (PreToolUse · `Write|Edit|MultiEdit`), misma cadena única.
63
- - `hooks/build-harness.json`: añade la misma entrada (canal plugin).
64
- - `src/commands/doctor.ts` y `status.ts`: reportan `scaffold: ✓ confirmado / ✗ pendiente` leyendo el estado.
65
- - `state/README.md`: documenta el gate `scaffold` y su protocolo de confirmación.
66
-
67
- ### 7. Versión
68
- `0.1.0 → 0.2.0` (feature). Sincronizar `VERSION` / `package.json` / `.claude-plugin/plugin.json`. Incluye el fix pendiente de `state/README.md` ("scaffold Next.js" → "scaffold de código del proyecto"). Entrada en `CHANGELOG.md`. Nota de cadencia/uso en `GOVERNANCE.md` si aplica.
69
-
70
- ## Casos borde
71
- - **Scaffold ya existe al instalar** (proyecto brownfield): la Fase 0 pregunta igual; el usuario confirma `Sí` una vez y queda registrado. No se re-pregunta mientras `scaffold.confirmed=true`.
72
- - **El equipo crea el scaffold dentro de un slice ya abierto**: desaconsejado por diseño (scaffold es Paso 1, antes del primer slice); el hook bloquea fases de código hasta confirmar. La creación del scaffold debe ocurrir con `active_slice=null` o en `dor`/`change`.
73
- - **Regresión de scaffold** (alguien borra package.json): `harness_phase` volvería a `authoring` (informativo); `scaffold.confirmed` sigue `true` salvo que se resetee manualmente. Aceptable para v0.2.0; documentar que el gate es una confirmación, no un chequeo continuo.
74
- - **python3 ausente**: el hook bloquea dirigido (no puede leer el estado de forma fiable) con mensaje claro, consistente con los otros hooks.
75
-
76
- ## Verificación (end-to-end)
77
- 1. `tsc` build limpio; `check-version-sync` (0.2.0 en los 3) / `check-agnostic` / `check-state-clean` en verde.
78
- 2. `build-state.template.json` incluye `scaffold.confirmed=false`; el schema valida.
79
- 3. Instalación en repo temporal: `scaffold-guard.sh` instalado y ejecutable; `settings.json` y `build-harness.json` contienen su entrada con la cadena única (sin doble disparo).
80
- 4. Test del hook por estado: con un `build-state.json` que tenga `active_slice.phase="green"` y `scaffold.confirmed=false`, un `Write` simulado → exit 2; con `scaffold.confirmed=true` → exit 0; con `active_slice=null` → exit 0.
81
- 5. `doctor`/`status` reportan el estado del scaffold.
82
- 6. Lectura de `building-a-slice`/`dor-dod-gatekeeper`: el ask de Fase 0 y el criterio duro están presentes y son agnósticos (pasa `check-agnostic`).
83
-
84
- ## Fuera de alcance
85
- - Generar el scaffold (decisión explícita: no lo forzamos).
86
- - Chequeo continuo de salud del scaffold (es una confirmación puntual, no un monitor).
87
- - Cambiar el modelo `harness_phase` (se mantiene como señal informativa).