@trycore/spec-build-harness 0.8.3 → 0.8.5

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 (37) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/GOVERNANCE.md +17 -2
  3. package/INSTALL.md +2 -2
  4. package/METODOLOGIA.md +35 -5
  5. package/README.md +5 -3
  6. package/VERSION +1 -1
  7. package/agents/build/dor-dod-gatekeeper.md +22 -1
  8. package/agents/build/ux-fidelity-reviewer.md +4 -1
  9. package/commands/build/onboard.md +49 -2
  10. package/commands/build/prototype.md +22 -0
  11. package/commands/build/slice.md +5 -0
  12. package/commands/build/work.md +9 -0
  13. package/dist/commands/doctor.js +8 -0
  14. package/dist/commands/init.js +3 -1
  15. package/dist/commands/status.js +19 -0
  16. package/dist/lib/state-seed.js +95 -1
  17. package/docs/commands.md +9 -3
  18. package/docs/getting-started.md +1 -1
  19. package/docs/hooks.md +1 -1
  20. package/hooks/build/design-source-guard.sh +1 -1
  21. package/package.json +1 -1
  22. package/scripts/tests/test-install.sh +88 -0
  23. package/scripts/tests/test-schema.sh +21 -0
  24. package/skills/building-a-slice/SKILL.md +3 -2
  25. package/skills/building-a-slice/references/dor.md +14 -1
  26. package/skills/building-a-slice/references/foundation-contract.md +44 -0
  27. package/skills/prototyping-screens/SKILL.md +100 -0
  28. package/skills/prototyping-screens/assets/DESIGN.md.template +55 -0
  29. package/skills/prototyping-screens/assets/manifest.schema.json +70 -0
  30. package/skills/prototyping-screens/assets/screen.template.html +34 -0
  31. package/skills/prototyping-screens/references/aesthetic-directions.md +42 -0
  32. package/skills/prototyping-screens/references/extraction.md +57 -0
  33. package/skills/prototyping-screens/references/self-check.md +40 -0
  34. package/state/README.md +26 -2
  35. package/state/build-state.schema.json +41 -2
  36. package/state/build-state.template.json +8 -0
  37. package/templates/CLAUDE.md.template +2 -2
package/docs/hooks.md CHANGED
@@ -93,7 +93,7 @@ Cierra el **ciclo autocorrectivo**. Al terminar el turno, si en `history[]` hay
93
93
 
94
94
  ### 9. `design-source-guard.sh` — `PreToolUse` · Write/Edit/MultiEdit · **bloqueante** (desde v0.5.0)
95
95
 
96
- Refuerza el **seguro de fuente de diseño** (espejo de `scaffold-guard`, para slices con UI). Bloquea con `exit 2` la escritura de **código de un slice con UI** —cuando `active_slice.phase` ∈ `red`/`green`/`refactor`/`smoke`/`api`/`data` **y** `active_slice.gates.fidelity === false` (marcado UI-pendiente por la DoR)— mientras el proyecto tenga UI (`design_source.applies === true`) y `design_source.confirmed` no sea `true`. **Permite** todo lo demás: slices sin UI (`gates.fidelity === null` o ausente), proyectos sin UI (`applies !== true`), fases de planificación (`dor`/`change`), o fuente ya confirmada. El arnés **exige** la fuente de diseño pero **no genera** el prototipo; la confirmación es **explícita** (vía `building-a-slice` Fase 0-bis / `dor-dod-gatekeeper`), nunca auto-detectada. Guarda `python3` fail-closed dirigido. En la práctica, como `design_source` es gate de proyecto, solo muerde la **primera** construcción de UI sin fuente declarada.
96
+ Refuerza el **seguro de fuente de diseño** (espejo de `scaffold-guard`, para slices con UI). Bloquea con `exit 2` la escritura de **código de un slice con UI** —cuando `active_slice.phase` ∈ `red`/`green`/`refactor`/`smoke`/`api`/`data` **y** `active_slice.gates.fidelity === false` (marcado UI-pendiente por la DoR)— mientras el proyecto tenga UI (`design_source.applies === true`) y `design_source.confirmed` no sea `true`. **Permite** todo lo demás: slices sin UI (`gates.fidelity === null` o ausente), proyectos sin UI (`applies !== true`), fases de planificación (`dor`/`change`), o fuente ya confirmada. El arnés **exige** la fuente de diseño y puede **generarla** vía `/build:prototype` (skill `prototyping-screens`; el mensaje de bloqueo lo sugiere); la confirmación sigue siendo **explícita y humana** (vía `building-a-slice` Fase 0-bis / `dor-dod-gatekeeper`), nunca auto-detectada. Guarda `python3` fail-closed dirigido. En la práctica, como `design_source` es gate de proyecto, solo muerde la **primera** construcción de UI sin fuente declarada.
97
97
 
98
98
  ### 10. `release-gate-nudge.sh` — `Stop` · no bloqueante (desde v0.7.0)
99
99
 
@@ -46,7 +46,7 @@ PY
46
46
  if [ "$VERDICT" = "BLOCK" ]; then
47
47
  echo "⛔ design-source-guard: el slice con UI está en fase de código pero la fuente de diseño NO está confirmada." >&2
48
48
  echo " Declara y confirma primero el DESIGN_SOURCE del proyecto (ver building-a-slice Fase 0-bis / DoR)." >&2
49
- echo " El arnés NO genera el prototipo: declara la fuente (prototipo/export) y confírmala." >&2
49
+ echo " Genera el prototipo con /build:prototype o declara una fuente existente (prototipo/export), y confírmala." >&2
50
50
  exit 2
51
51
  fi
52
52
  exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trycore/spec-build-harness",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
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": {
@@ -86,4 +86,92 @@ check "hooks/build/reconcile-build-state.py"
86
86
  check "hooks/build/lib/state-io.sh"
87
87
  check "scripts/lib/front-plan.py"
88
88
 
89
+ # project_kind: el TMP de init es un directorio vacío → greenfield detectado (auto)
90
+ if python3 -c "
91
+ import json,sys
92
+ d=json.load(open('$TMP/.claude/state/build-state.json'))
93
+ assert d.get('project_kind')=='greenfield', d.get('project_kind')
94
+ assert d.get('project_kind_source')=='auto', d.get('project_kind_source')
95
+ " 2>/dev/null; then
96
+ echo "OK install: project_kind=greenfield detectado (auto)"
97
+ else
98
+ echo "FAIL install: project_kind no detectado como greenfield/auto"
99
+ fail=1
100
+ fi
101
+
102
+ # 5) Brownfield seguro: manifiesto + código + historial git que toca código.
103
+ TMP_BF="$(mktemp -d)"
104
+ echo '{}' > "$TMP_BF/package.json"
105
+ mkdir -p "$TMP_BF/src"
106
+ echo 'export const x = 1;' > "$TMP_BF/src/index.ts"
107
+ (
108
+ cd "$TMP_BF" &&
109
+ git init -q &&
110
+ git add -A &&
111
+ git -c user.email=t@t -c user.name=t commit -qm x
112
+ ) >/dev/null 2>&1
113
+
114
+ node "$ROOT/dist/cli.js" init "$TMP_BF" \
115
+ --copy \
116
+ --skip-doctor \
117
+ --yes \
118
+ --stack "" \
119
+ --pkg-manager npm \
120
+ --runtime ">=18.18" \
121
+ --prd-path "docs/01-prd/x.md#req" \
122
+ >"$TMP_BF/.init.log" 2>&1
123
+ rc=$?
124
+ if [ $rc -ne 0 ]; then
125
+ echo "FAIL install: \`trycore-build init\` (brownfield) salió con código $rc"
126
+ cat "$TMP_BF/.init.log"
127
+ fail=1
128
+ fi
129
+
130
+ if python3 -c "
131
+ import json,sys
132
+ d=json.load(open('$TMP_BF/.claude/state/build-state.json'))
133
+ assert d.get('project_kind')=='brownfield', d.get('project_kind')
134
+ assert d.get('project_kind_source')=='auto', d.get('project_kind_source')
135
+ " 2>/dev/null; then
136
+ echo "OK install: project_kind=brownfield con historial git"
137
+ else
138
+ echo "FAIL install: project_kind no detectado como brownfield con historial git"
139
+ fail=1
140
+ fi
141
+ rm -rf "$TMP_BF"
142
+
143
+ # 6) Ambiguo: manifiesto + código pero SIN repo git (sin historial) → project_kind null.
144
+ TMP_AMB="$(mktemp -d)"
145
+ echo '{}' > "$TMP_AMB/package.json"
146
+ mkdir -p "$TMP_AMB/src"
147
+ echo 'export const x = 1;' > "$TMP_AMB/src/index.ts"
148
+
149
+ node "$ROOT/dist/cli.js" init "$TMP_AMB" \
150
+ --copy \
151
+ --skip-doctor \
152
+ --yes \
153
+ --stack "" \
154
+ --pkg-manager npm \
155
+ --runtime ">=18.18" \
156
+ --prd-path "docs/01-prd/x.md#req" \
157
+ >"$TMP_AMB/.init.log" 2>&1
158
+ rc=$?
159
+ if [ $rc -ne 0 ]; then
160
+ echo "FAIL install: \`trycore-build init\` (ambiguo) salió con código $rc"
161
+ cat "$TMP_AMB/.init.log"
162
+ fail=1
163
+ fi
164
+
165
+ if python3 -c "
166
+ import json,sys
167
+ d=json.load(open('$TMP_AMB/.claude/state/build-state.json'))
168
+ assert d.get('project_kind') is None, d.get('project_kind')
169
+ " 2>/dev/null; then
170
+ echo "OK install: project_kind=null (ambiguo sin historial git)"
171
+ else
172
+ echo "FAIL install: project_kind no quedó null en caso ambiguo"
173
+ fail=1
174
+ fi
175
+ rm -rf "$TMP_AMB"
176
+
89
177
  exit $fail
@@ -43,8 +43,29 @@ cat > "$TMP/bad-layer.json" <<'JSON'
43
43
  "layer":"WRONG","gates":{"dor":true,"tdd":false,"dod":false},"updated_at":"2026-07-03T00:00:00Z","updated_by":"t"},
44
44
  "history":[],"releases":[]}
45
45
  JSON
46
+ cat > "$TMP/valid-foundation.json" <<'JSON'
47
+ {"version":"1.0","harness_phase":"authoring","scaffold":{"confirmed":false},
48
+ "project_kind":"greenfield","project_kind_source":"auto",
49
+ "foundation":{"required":true,"epic":"EP-001","completed_at":null,
50
+ "checklist":[{"item":"navegacion-menus","applies":true,"evidence":""},
51
+ {"item":"login-authn","applies":true,"evidence":"smoke login OK"}]},
52
+ "active_slice":null,"history":[],"releases":[]}
53
+ JSON
54
+ cat > "$TMP/bad-project-kind.json" <<'JSON'
55
+ {"version":"1.0","harness_phase":"authoring","scaffold":{"confirmed":false},
56
+ "project_kind":"unknown","active_slice":null,"history":[],"releases":[]}
57
+ JSON
58
+ cat > "$TMP/bad-foundation-item.json" <<'JSON'
59
+ {"version":"1.0","harness_phase":"authoring","scaffold":{"confirmed":false},
60
+ "foundation":{"required":true,"epic":null,"completed_at":null,
61
+ "checklist":[{"applies":true}]},
62
+ "active_slice":null,"history":[],"releases":[]}
63
+ JSON
46
64
  check "estado válido con campos nuevos" pass "$TMP/valid.json"
47
65
  check "layer inválido rechazado" fail "$TMP/bad-layer.json"
66
+ check "foundation + project_kind válidos" pass "$TMP/valid-foundation.json"
67
+ check "project_kind inválido rechazado" fail "$TMP/bad-project-kind.json"
68
+ check "checklist item sin 'item' rechazado" fail "$TMP/bad-foundation-item.json"
48
69
 
49
70
  CFG="$ROOT/config/build-config.template.json"
50
71
  if [ -f "$CFG" ] && python3 -c "import json,sys; d=json.load(open('$CFG'))['context']; assert d['warning_pct']==35 and d['critical_pct']==25 and d['auto_checkpoint'] is False" 2>/dev/null; then
@@ -105,8 +105,9 @@ Espejo de la Fase 0, para proyectos **con UI**. Antes de abrir el primer slice c
105
105
  - `confirmed === true` → continúa.
106
106
  2. `applies===true && confirmed===false` → **pregunta explícita** (AskUserQuestion): *"¿Existe una
107
107
  fuente de diseño declarada (prototipo/export) para la UI de este proyecto?"*
108
- - **No** → **STOP**. Indica declararla (ruta/URL del prototipo o export). El arnés **NO la genera**.
109
- No abras el slice con UI.
108
+ - **No** → **STOP**. Ofrece dos salidas: **generarla con `/build:prototype`** (skill
109
+ `prototyping-screens`; la confirmación sigue siendo humana) o declarar una fuente externa
110
+ (ruta/URL del prototipo o export). No abras el slice con UI sin fuente confirmada.
110
111
  - **Sí** → registra `design_source.source`, `confirmed=true`, `confirmed_by`, `confirmed_at`, `notes`.
111
112
  3. Lo respalda el hook determinista `design-source-guard.sh` (bloquea código de slice UI sin fuente
112
113
  confirmada) y lo valida el `dor-dod-gatekeeper` (criterio duro de DoR).
@@ -10,6 +10,16 @@ la épica; lo de abajo aplica a la épica y a **cada HU** que cubre (`hus[]`). L
10
10
  - [ ] **INVEST** por HU: pasa los 6 criterios (Independent, Negotiable, Valuable, Estimable, Small, Testable).
11
11
  - [ ] **Dependencias resueltas**: las épicas/HU de las que depende están archivadas (`history[]`) o explícitamente no bloquean. **Excepción dura — cimiento:** si la dependencia es **infraestructura fundacional** (autenticación, acceso a datos, arquitectura base, design-system/componentes base), la cláusula "explícitamente no bloquean" **NO aplica**: debe estar **construida y archivada** antes (ver criterio "Cimiento construido").
12
12
  - [ ] **Cimiento construido (épicas de negocio)**: si esta épica es `layer: business`, todo el cimiento que arrastra (auth, acceso a datos, arquitectura base, design-system/componentes base) ya existe como épica(s) `layer: foundational` **archivada(s)** en `history[]`. Si arrastra cimiento no construido → **STOP**: extráelo a una épica fundacional previa y constrúyela primero. Las épicas fundacionales se priorizan **antes** que las de negocio.
13
+ - [ ] **Caparazón construido (solo greenfield — gate PROACTIVO)**: si `project_kind === "greenfield"`
14
+ y `foundation.required === true` en `build-state.json`, ninguna épica `layer: business` entra a
15
+ construcción mientras la épica caparazón (`foundation.epic`) no esté **archivada con su checklist
16
+ evidenciada** (`foundation.completed_at` estampado). Las épicas `layer: foundational` (la
17
+ caparazón `foundation.epic` u otras fundacionales) sí pueden abrir. A diferencia de "Cimiento
18
+ construido" (reactivo: bloquea si *detecta* arrastre), este criterio bloquea **siempre** en
19
+ greenfield hasta que el cimiento exista archivado — no depende de detectar nada. Si
20
+ `foundation.epic` es `null` (no existe la épica caparazón aún) → **STOP**: se define en
21
+ `/build:onboard` Fase 2c o en discovery. Brownfield / `foundation.required: false` → **N/A** (no
22
+ bloquea). Contrato: `references/foundation-contract.md`.
13
23
  - [ ] **Tamaño acotado (gate de descomposición)**: si la épica supera el umbral —heurística por defecto **> 3 HU** ó **≥ 3 capas tocadas** (configurable por proyecto)— **no entra como slice único**: se descompone en `sub_slices[]` verificables construidos de a uno, con `journey_smoke` verde entre cada uno. El umbral es proporcional (no cuota rígida): una épica de 1 capa y pocas HU entra directa.
14
24
  - [ ] **Cabe en el stack** del PRD §7 (no requiere tecnología fuera de `stack-allowlist.json`).
15
25
  - [ ] **Cobertura arquitectónica (ADR)** *(opt-in, retrocompatible)*: si el proyecto adoptó la capa de
@@ -23,7 +33,10 @@ la épica; lo de abajo aplica a la épica y a **cada HU** que cubre (`hus[]`). L
23
33
  - [ ] **Datos de prueba disponibles** o identificables (p.ej. los datos de ejemplo / fixtures sintéticos del dominio del consumidor).
24
34
  - [ ] **Fuente de diseño identificada (slices con UI)**: la fuente visual de verdad del slice
25
35
  (el `DESIGN_SOURCE` del dominio) está declarada y confirmada (`design_source.confirmed`), y este
26
- slice apunta a la(s) pantalla(s) equivalente(s). No se construye UI fuera de la fuente declarada.
36
+ slice apunta a la(s) pantalla(s) equivalente(s). Si la fuente es un prototipo generado
37
+ (`docs/05-prototipo/`), esas pantallas existen en `manifest.json` con `estado: "aprobada"`
38
+ (un `borrador` no satisface el criterio; genera/aprueba primero con `/build:prototype`).
39
+ No se construye UI fuera de la fuente declarada.
27
40
  - [ ] **Clasificación `layer`**: `foundational` (auth/datos/design-system/arquitectura base) | `business`. Se escribe en `active_slice.layer`. Gatea el front paralelo (foundational nunca en paralelo).
28
41
  - [ ] **`files_scope`**: globs de los archivos que la épica tocará (p.ej. `src/reports/**`). Fuente de la disjunción inter-épica. Se escribe en `active_slice.files_scope`.
29
42
 
@@ -0,0 +1,44 @@
1
+ # Contrato del caparazón (épica fundacional de app shell) — solo greenfield
2
+
3
+ El **caparazón** es el shell con contenido donde aterrizan las features: navegación, layout,
4
+ homepage, login y redirecciones. No es el *scaffold* (shell vacío que arranca — gate
5
+ `scaffold.confirmed`) ni el *walking skeleton* (primer journey de negocio más delgado): es la
6
+ infraestructura de UI/entrada fundacional que, si no existe primero, cada épica de negocio
7
+ improvisa a pedazos y acumula deuda estructural.
8
+
9
+ **Aplica si y solo si `project_kind === "greenfield"`.** En brownfield el mecanismo entero es
10
+ N/A y el arnés no pregunta ni exige nada (`foundation.required: false`).
11
+
12
+ ## Checklist base (ids canónicos)
13
+
14
+ | id | Qué cubre | Poda típica |
15
+ |---|---|---|
16
+ | `navegacion-menus` | Menús / estructura de navegación principal | API sin UI |
17
+ | `layout-panel-central` | Layout base + panel/área central de contenido | API sin UI |
18
+ | `homepage` | Página de inicio real (no placeholder del scaffold) | API sin UI |
19
+ | `login-authn` | Login + autenticación cableada end-to-end | app pública sin cuentas |
20
+ | `redirecciones-guards` | Redirecciones y guards de ruta (authed/anon, 404, deep-links) | API sin UI |
21
+
22
+ - La **poda** se decide una vez, en `/build:onboard` Fase 2c, con el humano (ítem podado =
23
+ `applies: false`; queda en la checklist como decisión trazable, no se borra).
24
+ - El proyecto puede **añadir** ítems propios (id kebab-case) si su caparazón exige más.
25
+
26
+ ## Ciclo de vida
27
+
28
+ 1. **Onboard (Fase 2c)** — se poda la checklist, se persiste en `foundation.checklist[]` y se
29
+ identifica (o redacta en borrador híbrido) la épica caparazón → `foundation.epic`.
30
+ 2. **DoR (gate proactivo)** — mientras la épica caparazón no esté **archivada**, ninguna épica
31
+ `layer: business` abre slice (solo fundacionales). Ver `dor.md`.
32
+ 3. **DoD de la épica caparazón** — cada ítem `applies: true` exige `evidence` de ejecución real
33
+ (test, comando, screenshot MCP), patrón `wiring_checklist`. Sin evidencia completa no se
34
+ archiva.
35
+ 4. **Cierre** — al archivar con la checklist evidenciada se estampa `foundation.completed_at` y
36
+ las épicas de negocio quedan desbloqueadas.
37
+
38
+ ## Reglas duras
39
+
40
+ - El arnés **propone** el borrador de la épica caparazón; **solo** lo escribe en
41
+ `docs/03-backlog/epicas.md` con aprobación humana explícita (carve-out acotado, ver
42
+ METODOLOGIA §9.2). Si el humano rechaza, STOP: la épica se crea en discovery (`/trycore:*`).
43
+ - La evidencia es de **ejecución**, nunca de inspección.
44
+ - Si contradice `METODOLOGIA.md`, gana la metodología.
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: prototyping-screens
3
+ description: Use when generating or extending the HTML reference prototype (the DESIGN_SOURCE) — the visual source of truth screens are built against. Two modes — greenfield (full initial prototype from discovery docs + human-chosen aesthetic direction) and feature (new-epic screens extracted live from the already-implemented UI so they look native to the app). Self-verifies visually; human approval gates everything.
4
+ ---
5
+
6
+ # Prototipar pantallas de referencia (outer-loop)
7
+
8
+ Genera el **prototipo HTML de referencia** del consumidor: la fuente de verdad visual
9
+ (`DESIGN_SOURCE`) contra la que después se construyen y verifican los slices con UI
10
+ (gate `fidelity`, `ux-fidelity-reviewer`). Si algo aquí contradice `METODOLOGIA.md`,
11
+ **gana la metodología**.
12
+
13
+ **Invariantes:**
14
+ - La skill **genera**; el humano **aprueba**. `design_source.confirmed` y el `estado: "aprobada"`
15
+ del manifest son **siempre** decisiones humanas — esta skill jamás los auto-marca.
16
+ - Es **outer-loop**: se corre antes de abrir slices (como `/build:architect`), nunca dentro del
17
+ inner loop de una épica.
18
+ - Escribe **solo** en `docs/05-prototipo/` (carve-out §9.2 de METODOLOGIA) y, con aprobación
19
+ humana, en `design_source` de `build-state.json` (protocolo de `state/README.md`).
20
+
21
+ ## Artefactos que produce (repo del consumidor)
22
+
23
+ ```
24
+ docs/05-prototipo/
25
+ ├── DESIGN.md ← tokens + reglas visuales en prosa (assets/DESIGN.md.template)
26
+ ├── tokens.css ← los mismos tokens como CSS custom properties (fuente única)
27
+ ├── manifest.json ← pantalla ↔ épica/HU ↔ archivo ↔ estado (assets/manifest.schema.json)
28
+ └── pantallas/
29
+ └── <slug>.html ← un HTML autocontenido por pantalla (assets/screen.template.html)
30
+ ```
31
+
32
+ **Reglas duras del artefacto:**
33
+ - HTML **autocontenido**: cero dependencias externas (sin CDNs, frameworks, fetch ni JS); única
34
+ importación permitida: `tokens.css`; renderiza en `file://` indefinidamente; datos ilustrativos
35
+ estáticos.
36
+ - Cero valores visuales fuera de tokens (color/fuente/spacing/radio/sombra → `var(--token)`).
37
+ - Estados relevantes (vacío, error, cargando…) que la HU exija → **variantes de pantalla**
38
+ (`<slug>--<estado>.html`, campo `variante_de` en el manifest), no interacciones.
39
+ - Solo pantallas `estado: "aprobada"` son fuente de verdad (las lee `ux-fidelity-reviewer`); el
40
+ resto son `borrador`.
41
+
42
+ ## Detección de modo
43
+
44
+ 1. No existe `docs/05-prototipo/` ni hay `design_source.confirmed` → **greenfield**.
45
+ 2. Se pide pantallas para una épica y existe app implementada (o prototipo previo) → **feature**.
46
+ 3. Ambigüedad → pregunta al humano antes de tocar nada.
47
+
48
+ ## Modo greenfield — prototipo inicial completo
49
+
50
+ 1. **Inventario de pantallas**: lee PRD, user story map/flows e historias de discovery; deriva la
51
+ lista pantalla ↔ épica/HU (esqueleto del `manifest.json`) y **preséntala para confirmación
52
+ humana** antes de generar nada.
53
+ 2. **Dirección estética**: sigue `references/aesthetic-directions.md` (¿manual de marca? → destilar
54
+ tokens; si no → 2-3 direcciones visuales de una pantalla clave, elección humana en navegador).
55
+ Salida: `DESIGN.md` + `tokens.css`.
56
+ 3. **Generación por lotes**: pantallas en orden de flow, cada una desde su HU + tokens, sobre
57
+ `assets/screen.template.html`. Tras cada lote: auto-verificación (`references/self-check.md`)
58
+ y **pausa** para revisión humana en navegador. Registra cada pantalla en el manifest como
59
+ `borrador`.
60
+
61
+ ## Modo feature — pantallas de una épica nueva (el caso brownfield)
62
+
63
+ 1. **Precondición dura**: la app implementada **corriendo** + un MCP de inspección de UI habilitado
64
+ (p.ej. chrome-devtools para web). Si falta cualquiera → **STOP** con instrucciones (levantar la
65
+ app / habilitar el MCP). **Sin degradación a extracción estática**: el CSS computado real es el
66
+ factor decisivo de fidelidad (misma postura que el gate `fidelity`, donde INCONCLUSO bloquea).
67
+ 2. **Extracción viva**: sigue `references/extraction.md` (CSS computado + screenshots en 3 viewports
68
+ + árbol de componentes de 2-3 pantallas representativas; reconciliación de `tokens.css`: la app
69
+ real gana, las divergencias se reportan como drift).
70
+ 3. **Generación**: las pantallas nuevas de la épica usan los tokens reconciliados y los screenshots
71
+ de la app como referencia de composición. Criterio de éxito: la pantalla nueva parece
72
+ **"una pantalla más"** de la app existente.
73
+ 4. **Registro**: entradas nuevas en `manifest.json` como `borrador` (con `epica`/`historias`).
74
+
75
+ ## Auto-verificación (ambos modos)
76
+
77
+ Sigue `references/self-check.md`: renderizado real de cada HTML (`file://`), screenshot en
78
+ 3 viewports + snapshot estructural, comparación (feature → contra lo extraído de la app;
79
+ greenfield → contra tokens + consistencia del lote), corrección y re-render con **máximo
80
+ 3 iteraciones**; si no converge, reporte al humano con el delta. Sin pixel-diff.
81
+
82
+ ## Aprobación humana → estado
83
+
84
+ 1. Abre las pantallas en el navegador del usuario y pide aprobación explícita (por pantalla o por
85
+ lote). Aprobada → `manifest.json` pasa esa entrada a `"aprobada"`.
86
+ 2. **Greenfield** con ≥1 pantalla aprobada: ofrece registrar la fuente en `build-state.json` —
87
+ `design_source.source: "docs/05-prototipo/"`, `confirmed: true`, `confirmed_by`, `confirmed_at`,
88
+ `notes` — siguiendo el protocolo de escritura de `state/README.md`. Solo con el **sí** explícito
89
+ del humano.
90
+ 3. **Feature**: `design_source` ya está confirmado; solo se amplía el manifest.
91
+
92
+ ## Qué NO hace esta skill
93
+
94
+ - **No** hace pixel-diff (comparación estructural/semántica, como el resto del arnés).
95
+ - **No** genera código de producción: eso es el slice normal (`building-a-slice`) con su gate
96
+ `fidelity`; el prototipo es su entrada, no su salida.
97
+ - **No** prototipa interacciones/animaciones (HTML estático; estados como variantes).
98
+ - **No** integra plataformas de diseño externas (exports no navegables ya tienen su rama en
99
+ `ux-fidelity-reviewer`).
100
+ - **No** escribe en `docs/01-…04-…` ni toca otros campos del estado.
@@ -0,0 +1,55 @@
1
+ # DESIGN.md — reglas visuales del producto
2
+
3
+ > Fuente de verdad **en prosa** de la identidad visual. Los mismos valores viven como CSS custom
4
+ > properties en `tokens.css` (fuente única que importan todos los prototipos). Si este archivo y
5
+ > `tokens.css` divergen, gana `tokens.css` y la divergencia se reporta como drift.
6
+
7
+ ## Identidad
8
+
9
+ {{DIRECCION_ELEGIDA}} — dirección visual elegida y por qué (elección humana, ver Procedencia).
10
+
11
+ ## Paleta
12
+
13
+ | Token | Valor | Uso |
14
+ |---|---|---|
15
+ | `--color-primary` | {{HEX}} | {{USO}} |
16
+ | `--color-surface` | {{HEX}} | {{USO}} |
17
+ | `--color-text` | {{HEX}} | {{USO}} |
18
+ | … | … | … |
19
+
20
+ ## Tipografía
21
+
22
+ - **Familias**: {{FAMILIA_TITULARES}} (titulares) · {{FAMILIA_CUERPO}} (cuerpo).
23
+ - **Escala**: {{ESCALA}} (p.ej. 12/14/16/20/24/32).
24
+ - **Pesos**: {{PESOS}} y dónde se usa cada uno.
25
+
26
+ ## Espaciado y radios
27
+
28
+ - **Spacing scale**: {{SPACING_SCALE}} (todos los márgenes/paddings son múltiplos de la escala).
29
+ - **Radios**: {{RADIOS}} por tipo de componente.
30
+
31
+ ## Sombras
32
+
33
+ | Token | Valor | Uso |
34
+ |---|---|---|
35
+ | `--shadow-1` | {{VALOR}} | {{USO}} |
36
+
37
+ ## Componentes
38
+
39
+ Reglas por componente (densidad, alineación, jerarquía) que los prototipos deben respetar:
40
+
41
+ - {{COMPONENTE}}: {{REGLA}}
42
+
43
+ ## Don'ts (lista explícita)
44
+
45
+ - No inventar colores, fuentes, spacing ni radios fuera de los tokens.
46
+ - No introducir dependencias externas en los prototipos (CDNs, frameworks, fuentes remotas).
47
+ - No "interpretar" el diseño al construir: copiar valores exactos.
48
+ - {{DONT_ESPECIFICO_DEL_PRODUCTO}}
49
+
50
+ ## Procedencia
51
+
52
+ - **Origen de los tokens**: {{ORIGEN}} (manual de marca / extracción viva de la app / dirección
53
+ elegida por el humano entre variantes).
54
+ - **Fecha**: {{FECHA_ISO}}.
55
+ - **Reconciliaciones**: {{NOTAS_DE_DRIFT}} (cuándo la app real corrigió lo declarado).
@@ -0,0 +1,70 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "trycore-build/prototype-manifest",
4
+ "title": "Manifest del prototipo de referencia (docs/05-prototipo/manifest.json)",
5
+ "description": "Mapa determinista pantalla ↔ épica/HU ↔ archivo HTML ↔ estado. Solo las pantallas con estado 'aprobada' son fuente de verdad visual (las lee ux-fidelity-reviewer y resuelven el puntero por-slice de la DoR).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["version", "pantallas"],
9
+ "properties": {
10
+ "version": {
11
+ "type": "integer",
12
+ "description": "Versión del formato del manifest (hoy: 1)."
13
+ },
14
+ "pantallas": {
15
+ "type": "array",
16
+ "items": { "$ref": "#/$defs/pantalla" }
17
+ }
18
+ },
19
+ "$defs": {
20
+ "pantalla": {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "required": ["slug", "archivo", "estado"],
24
+ "properties": {
25
+ "slug": {
26
+ "type": "string",
27
+ "pattern": "^[a-z0-9]+(-[a-z0-9]+)*(--[a-z0-9]+(-[a-z0-9]+)*)?$",
28
+ "description": "Identificador kebab-case de la pantalla. Las variantes de estado usan sufijo doble guion (p.ej. <slug>--vacio)."
29
+ },
30
+ "archivo": {
31
+ "type": "string",
32
+ "description": "Ruta relativa al directorio del prototipo (p.ej. pantallas/<slug>.html)."
33
+ },
34
+ "epica": {
35
+ "type": "string",
36
+ "pattern": "^EP-[0-9]{3}$",
37
+ "description": "Épica a la que pertenece la pantalla (puntero por-slice de la DoR)."
38
+ },
39
+ "historias": {
40
+ "type": "array",
41
+ "items": { "type": "string", "pattern": "^HU-[0-9]{3}$" },
42
+ "description": "Historias de usuario que la pantalla cubre."
43
+ },
44
+ "estado": {
45
+ "type": "string",
46
+ "enum": ["borrador", "aprobada"],
47
+ "description": "borrador = generada, pendiente de aprobación humana; aprobada = fuente de verdad visual (la aprobación es SIEMPRE humana)."
48
+ },
49
+ "generada_en": {
50
+ "type": "string",
51
+ "format": "date-time",
52
+ "description": "Cuándo se generó/regeneró (ISO-8601 UTC)."
53
+ },
54
+ "viewports_verificados": {
55
+ "type": "array",
56
+ "items": { "type": "string", "enum": ["desktop", "tablet", "mobile"] },
57
+ "description": "Viewports en los que el self-check renderizó y verificó la pantalla."
58
+ },
59
+ "variante_de": {
60
+ "type": "string",
61
+ "description": "Slug de la pantalla base si esta entrada es una variante de estado (vacío, error, cargando…)."
62
+ },
63
+ "notas": {
64
+ "type": "string",
65
+ "description": "Nota libre (p.ej. desviaciones intencionales aceptadas por el humano)."
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,34 @@
1
+ <!doctype html>
2
+ <!--
3
+ Prototipo de referencia — pantalla {{SLUG}}
4
+ Reglas duras del artefacto (NO negociables):
5
+ - AUTOCONTENIDO: cero dependencias externas (sin CDNs, sin frameworks, sin fetch, sin JS).
6
+ Única importación permitida: ../tokens.css. Debe renderizar en file:// indefinidamente.
7
+ - TOKENS: todo color, fuente, spacing, radio y sombra sale de las custom properties de
8
+ ../tokens.css. Cero valores mágicos fuera de tokens.
9
+ - DATOS ILUSTRATIVOS ESTÁTICOS: contenido de ejemplo neutro, embebido en el HTML.
10
+ - ESTADOS: los estados relevantes (vacío, error, cargando) que la HU exija son VARIANTES
11
+ de pantalla en archivos propios ({{SLUG}}--<estado>.html), no interacciones.
12
+ Trazabilidad: épica {{EPICA}} · historias {{HISTORIAS}} · registrada en ../manifest.json
13
+ -->
14
+ <html lang="es">
15
+ <head>
16
+ <meta charset="utf-8">
17
+ <meta name="viewport" content="width=device-width, initial-scale=1">
18
+ <title>{{TITULO_PANTALLA}} — prototipo</title>
19
+ <link rel="stylesheet" href="../tokens.css">
20
+ <style>
21
+ /* Estilos propios de esta pantalla: SOLO composición/layout.
22
+ Valores visuales (color, fuente, spacing, radio, sombra) → var(--token). */
23
+ </style>
24
+ </head>
25
+ <body>
26
+ <!-- región: navegación / cabecera -->
27
+
28
+ <!-- región: contenido principal (composición según la HU y el patrón de layout del sistema) -->
29
+
30
+ <!-- región: paneles secundarios / laterales (si el diseño los declara) -->
31
+
32
+ <!-- región: pie / acciones globales (si el diseño lo declara) -->
33
+ </body>
34
+ </html>
@@ -0,0 +1,42 @@
1
+ # Dirección estética (modo greenfield)
2
+
3
+ Protocolo para fijar la identidad visual **antes** de generar pantallas, cuando discovery solo
4
+ entrega docs de texto. La decisión estética es **humana**; la skill produce opciones y destila.
5
+
6
+ ## 1. ¿Hay manual de marca?
7
+
8
+ Pregunta primero si el consumidor tiene manual de marca / brand guidelines / design system previo.
9
+
10
+ - **Sí** → destila los tokens directamente de ese insumo (paleta exacta, tipografías, reglas de
11
+ uso) a `DESIGN.md` + `tokens.css`, con **Procedencia: manual de marca**. **No** generes
12
+ variantes: la identidad ya está decidida. Salta al paso 4.
13
+ - **No** → continúa con variantes (pasos 2-3).
14
+
15
+ ## 2. Elegir la pantalla clave
16
+
17
+ Una sola pantalla para el ejercicio: la más **representativa del journey** (la que un usuario ve
18
+ más tiempo o la que concentra más componentes distintos — típicamente la pantalla principal de
19
+ trabajo tras entrar). Evita pantallas triviales: no discriminan entre direcciones.
20
+
21
+ ## 3. Generar 2-3 direcciones y someterlas a elección humana
22
+
23
+ 1. Genera la pantalla clave en **2-3 direcciones visuales genuinamente distintas** — que difieran
24
+ en paleta, tipografía y densidad/tono (p.ej. sobria-densa · aireada-amable · contrastada-enérgica),
25
+ no tres matices del mismo gris. Cada dirección respeta el mismo contenido y la misma HU.
26
+ 2. Móntalas **lado a lado en un único HTML comparador** autocontenido (una columna por dirección,
27
+ con nombre y rasgos clave de cada una) y ábrelo en el navegador del usuario.
28
+ 3. El humano elige. Se permite **mezclar** ("la paleta de A con la tipografía de B") si lo pide.
29
+ 4. El comparador es un artefacto de trabajo: puede guardarse en `docs/05-prototipo/` como
30
+ `_direcciones.html` para la trazabilidad de la decisión, pero **no** entra al manifest.
31
+
32
+ ## 4. Destilar `DESIGN.md` + `tokens.css`
33
+
34
+ De la dirección elegida (o del manual de marca):
35
+ - `tokens.css` — custom properties: paleta completa (con variantes de énfasis/estado), familias y
36
+ escala tipográfica, spacing scale, radios, sombras.
37
+ - `DESIGN.md` (`assets/DESIGN.md.template`) — la prosa: identidad y por qué se eligió, tablas de
38
+ tokens con uso, reglas de componentes, **Don'ts** explícitos y **Procedencia** (dirección elegida
39
+ + fecha).
40
+
41
+ A partir de aquí, **toda** pantalla del prototipo importa `tokens.css` y no introduce valores
42
+ fuera de tokens; el self-check (`self-check.md`) lo verifica.
@@ -0,0 +1,57 @@
1
+ # Extracción viva del UX/UI implementado (modo feature)
2
+
3
+ Protocolo para capturar el **contexto rico real** de la app implementada antes de generar
4
+ pantallas nuevas. La lección de fondo: la fidelidad no sale de "mirar un screenshot", sale de
5
+ **CSS computado real + capturas multi-viewport + estructura**. Todo esto exige la app corriendo
6
+ y un MCP de inspección de UI habilitado (p.ej. chrome-devtools para web); sin ellos, la skill
7
+ ya hizo STOP antes de llegar aquí.
8
+
9
+ ## 1. Elegir pantallas representativas (2-3)
10
+
11
+ Criterio: cubrir los patrones que la pantalla nueva va a necesitar —
12
+ - la pantalla de **navegación/layout principal** (caparazón: menús, cabecera, panel central);
13
+ - una pantalla del **mismo tipo** que la que se va a generar (listado si va a haber listado,
14
+ formulario si va a haber formulario, detalle si detalle);
15
+ - si existe, una pantalla ya validada como fiel (`gates.fidelity: true` en `history[]`).
16
+
17
+ ## 2. Capturar por cada pantalla
18
+
19
+ 1. **Screenshots en 3 viewports** — desktop, tablet y mobile (redimensionar la página antes de
20
+ cada captura). Guardan la referencia de composición y densidad.
21
+ 2. **CSS computado de elementos clave** — vía el MCP (evaluar `getComputedStyle` sobre):
22
+ - tipografía real: `font-family`, `font-size`, `font-weight`, `line-height` de titular
23
+ principal, titular secundario, cuerpo y etiquetas;
24
+ - color real: `color`, `background-color`, `border-color` de superficie, texto, acción
25
+ primaria, acción secundaria y estados de énfasis;
26
+ - espaciado real: `padding`/`margin`/`gap` de los contenedores estructurales y de los
27
+ componentes repetidos (tarjetas, filas, campos);
28
+ - `border-radius` y `box-shadow` de los componentes elevados.
29
+ 3. **Árbol estructural** — snapshot del árbol accesible/DOM de la pantalla: número y disposición
30
+ de paneles, orden de secciones, jerarquía. Es la referencia de **composición** (estructura >
31
+ píxeles).
32
+
33
+ ## 3. Destilar y reconciliar tokens
34
+
35
+ 1. Consolida lo capturado en un conjunto de tokens (paleta, tipografía, spacing scale, radios,
36
+ sombras). Los valores repetidos entre pantallas son los tokens; los valores únicos son ruido.
37
+ 2. **Si `docs/05-prototipo/tokens.css` ya existe → reconciliar**:
38
+ - **La app real gana** sobre lo declarado: si el token declarado dice un valor y el CSS
39
+ computado dice otro de forma consistente, actualiza el token al valor real.
40
+ - Cada divergencia se **reporta al humano como drift** (tabla token → declarado → real →
41
+ pantallas donde se observó). El drift es señal de que prototipo viejo y app se separaron:
42
+ el humano decide si además hay que corregir la app (fuera del alcance de esta skill).
43
+ 3. Si no existe `tokens.css`, créalo desde lo extraído y genera/actualiza `DESIGN.md`
44
+ (`assets/DESIGN.md.template`) con **Procedencia: extracción viva** y la fecha.
45
+
46
+ ## 4. Empaquetar el contexto para la generación
47
+
48
+ Antes de generar, deja explícito el paquete de referencia que usará la pantalla nueva:
49
+ - `tokens.css` reconciliado;
50
+ - screenshots de referencia (composición/densidad) de las pantallas capturadas;
51
+ - el árbol estructural del layout principal (dónde vive el contenido en el caparazón);
52
+ - las reglas de componentes observadas (densidad de tablas, anatomía de formularios, etc.),
53
+ anotadas en `DESIGN.md` si no estaban.
54
+
55
+ La generación no "interpreta" este paquete: **copia valores exactos**. Toda desviación deliberada
56
+ se anota como desviación intencional en `notas` del manifest para que `ux-fidelity-reviewer` no
57
+ la penalice después.