@trycore/spec-build-harness 0.4.0 → 0.6.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.
- package/.claude-plugin/plugin.json +1 -1
- package/GOVERNANCE.md +27 -2
- package/INSTALL.md +6 -4
- package/METODOLOGIA.md +68 -12
- package/README.md +11 -15
- package/VERSION +1 -1
- package/agents/build/build-orchestrator.md +39 -5
- package/agents/build/dor-dod-gatekeeper.md +28 -7
- package/agents/build/ux-fidelity-reviewer.md +68 -0
- package/agents/build/wiring-adversarial-verifier.md +59 -0
- package/commands/build/onboard.md +38 -4
- package/dist/lib/settings-merge.js +1 -1
- package/dist/lib/state-seed.js +1 -0
- package/docs/agents.md +26 -2
- package/docs/customization/mcp-extensions.md +16 -5
- package/docs/getting-started.md +64 -209
- package/docs/hooks.md +12 -6
- package/hooks/build/design-source-guard.sh +52 -0
- package/hooks/build/load-build-state.sh +17 -1
- package/hooks/build-harness.json +4 -0
- package/package.json +1 -1
- package/skills/building-a-slice/SKILL.md +57 -3
- package/skills/building-a-slice/references/dod.md +14 -0
- package/skills/building-a-slice/references/dor.md +9 -3
- package/skills/building-a-slice/references/integration-check.md +27 -0
- package/skills/building-a-slice/references/mcp-map.md +1 -0
- package/skills/building-a-slice/references/state-protocol.md +21 -4
- package/state/README.md +31 -2
- package/state/build-state.schema.json +66 -3
- package/state/build-state.template.json +8 -0
- package/templates/CLAUDE.md.template +8 -3
- package/templates/integration-check.sh.template +65 -0
- package/templates/settings-hooks.template.json +1 -1
package/docs/hooks.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Hooks del arnés de construcción
|
|
2
2
|
|
|
3
|
-
Este documento describe los **
|
|
3
|
+
Este documento describe los **9 hooks** que `@trycore/spec-build-harness` instala en el proyecto del consumidor. Todos viven en `hooks/build/` (un script bash por hook) y se cablean a los eventos de Claude Code mediante una **cadena de comando única**, idéntica en ambos canales de instalación.
|
|
4
4
|
|
|
5
|
-
Los hooks son el sistema nervioso del arnés: vigilan GitFlow, el stack declarado
|
|
5
|
+
Los hooks son el sistema nervioso del arnés: vigilan GitFlow, el stack declarado, el scaffold y la fuente de diseño (bloqueantes), inyectan el estado del build al iniciar la sesión, delegan estilo/typecheck a herramientas, y recuerdan validar trazabilidad, gates abiertos y reflexionar al cerrar un slice. No reemplazan a los agentes ni a las skills; los **complementan** liberando capacidad de razonamiento del modelo y poniendo barandillas mecánicas donde un olvido cuesta caro.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## Resumen de los
|
|
9
|
+
## Resumen de los 9 hooks
|
|
10
10
|
|
|
11
11
|
| Hook | Evento | Matcher | Qué hace | ¿Bloqueante? |
|
|
12
12
|
|---|---|---|---|---|
|
|
@@ -14,12 +14,13 @@ Los hooks son el sistema nervioso del arnés: vigilan GitFlow, el stack declarad
|
|
|
14
14
|
| `gitflow-guard.sh` | `PreToolUse` | `Bash` | Enforce GitHub Flow estricto sobre `git commit` / `git push`. | **Sí (exit 2)** |
|
|
15
15
|
| `stack-guard.sh` | `PreToolUse` | `Write\|Edit\|MultiEdit` | Bloquea dependencias en `package.json` fuera de la allowlist del stack del PRD. | **Sí (exit 2)** |
|
|
16
16
|
| `scaffold-guard.sh` | `PreToolUse` | `Write\|Edit\|MultiEdit` | Bloquea escribir código de slice (fases `red…data`) si el scaffold no está confirmado (`scaffold.confirmed`). | **Sí (exit 2)** |
|
|
17
|
+
| `design-source-guard.sh` | `PreToolUse` | `Write\|Edit\|MultiEdit` | Bloquea escribir código de un slice **con UI** (`gates.fidelity===false`, fases `red…data`) si la fuente de diseño del proyecto no está confirmada (`design_source.confirmed`). | **Sí (exit 2)** |
|
|
17
18
|
| `lint-typecheck.sh` | `PostToolUse` | `Write\|Edit\|MultiEdit` | Corre prettier/eslint/tsc sobre el archivo `.ts`/`.tsx` editado. | No |
|
|
18
19
|
| `coherence-flag.sh` | `PostToolUse` | `Write\|Edit\|MultiEdit` | Recuerda validar la trazabilidad de un `proposal.md` de OpenSpec recién tocado. | No |
|
|
19
20
|
| `build-gate-check.sh` | `Stop` | `.*` | Al cerrar el turno, avisa si el slice activo tiene gates abiertos. | No |
|
|
20
21
|
| `reflect-nudge.sh` | `Stop` | `.*` | Al cerrar el turno, sugiere `/build:reflect` si hay slice(s) archivado(s) sin reflexionar (`reflected != true`). | No |
|
|
21
22
|
|
|
22
|
-
>
|
|
23
|
+
> Cuatro bloqueantes (`gitflow-guard`, `stack-guard`, `scaffold-guard`, `design-source-guard`) y cinco informativos. Los bloqueantes usan `exit 2`: Claude Code devuelve el `stderr` al modelo y aborta la herramienta; el resto siempre sale `0`.
|
|
23
24
|
|
|
24
25
|
---
|
|
25
26
|
|
|
@@ -84,6 +85,10 @@ Refuerza el **scaffold como "Paso 1 fundamental"**. Bloquea con `exit 2` la escr
|
|
|
84
85
|
|
|
85
86
|
Cierra el **ciclo autocorrectivo**. Al terminar el turno, si en `history[]` hay slice(s) archivado(s) con `reflected != true`, imprime un *nudge* sugiriendo ejecutar `/build:reflect` para capturar las convenciones aprendidas (y errores recurrentes) en el bloque `trycore-build-learnings` de `CLAUDE.md`. **Nunca bloquea** el cierre de sesión: si falta `python3` o el estado, sale `0` en silencio (**fail-open**). El razonamiento —qué se aprendió— vive en el comando `/build:reflect`, no en el hook; este solo recuerda. Tras reflexionar y estampar `reflected: true`, el nudge calla.
|
|
86
87
|
|
|
88
|
+
### 9. `design-source-guard.sh` — `PreToolUse` · Write/Edit/MultiEdit · **bloqueante** (desde v0.5.0)
|
|
89
|
+
|
|
90
|
+
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.
|
|
91
|
+
|
|
87
92
|
---
|
|
88
93
|
|
|
89
94
|
## La cadena de comando única (sin doble disparo entre canales)
|
|
@@ -107,7 +112,7 @@ Como la cadena es **carácter por carácter idéntica** en ambos canales, si el
|
|
|
107
112
|
|
|
108
113
|
Los hooks parsean el JSON del evento con `python3`. Qué pasa si **falta** `python3` depende de si el hook es bloqueante:
|
|
109
114
|
|
|
110
|
-
- **Bloqueantes** (`gitflow-guard`, `stack-guard`, `scaffold-guard`) → **fail-closed dirigido**: si no pueden analizar el comando/edición, solo bloquean (`exit 2`) cuando la entrada *cruda* parece relevante (un `git commit`/`push`, una edición que menciona `package.json`, o código de slice sin scaffold
|
|
115
|
+
- **Bloqueantes** (`gitflow-guard`, `stack-guard`, `scaffold-guard`, `design-source-guard`) → **fail-closed dirigido**: si no pueden analizar el comando/edición, solo bloquean (`exit 2`) cuando la entrada *cruda* parece relevante (un `git commit`/`push`, una edición que menciona `package.json`, o código de slice sin scaffold/fuente de diseño confirmados); en cualquier otro caso salen `0`. Esto evita falsos negativos peligrosos sin frenar el trabajo no relacionado. El mensaje pide instalar `python3` (verificable con `trycore-build doctor`).
|
|
111
116
|
- **No bloqueantes** (`load-build-state`, `lint-typecheck`, `coherence-flag`, `build-gate-check`, `reflect-nudge`) → si falta `python3`, simplemente **omiten** su trabajo y salen `0` (fail-open).
|
|
112
117
|
|
|
113
118
|
> `python3` es un **requisito duro**: `trycore-build init` y `trycore-build doctor` **fallan** si no está presente, justo porque toda la cadena de hooks depende de él para leer el JSON del evento.
|
|
@@ -126,6 +131,7 @@ Los hooks que tocan el código construido se **auto-arman**: permanecen **inerte
|
|
|
126
131
|
| `lint-typecheck.sh` | Inerte (sale `0` de inmediato). |
|
|
127
132
|
| `coherence-flag.sh` | Funciona siempre (depende de OpenSpec, no del código). |
|
|
128
133
|
| `scaffold-guard.sh` | Permite (sin slice en fases de código no hay nada que bloquear; también permite crear el scaffold). |
|
|
134
|
+
| `design-source-guard.sh` | Permite (sin slice UI en fases de código, o sin `design_source.applies=true`, no hay nada que bloquear). |
|
|
129
135
|
| `build-gate-check.sh` | Inerte (sale `0` de inmediato). |
|
|
130
136
|
| `reflect-nudge.sh` | Silencioso (en `authoring` no hay slices archivados que reflexionar). |
|
|
131
137
|
|
|
@@ -141,7 +147,7 @@ Una sola definición de hooks, expresada en dos archivos espejo según el canal:
|
|
|
141
147
|
|
|
142
148
|
`trycore-build init` hace un **merge idempotente y aditivo** en el `settings.json` del consumidor (lógica en `src/lib/settings-merge.ts`; espejo documental en `templates/settings-hooks.template.json`):
|
|
143
149
|
|
|
144
|
-
- Agrega las 5 agrupaciones de hooks (las
|
|
150
|
+
- Agrega las 5 agrupaciones de hooks (las 9 invocaciones: `PreToolUse·Write` agrupa `stack-guard` + `scaffold-guard` + `design-source-guard`; `PostToolUse·Write` agrupa `lint-typecheck` + `coherence-flag`; `Stop` agrupa `build-gate-check` + `reflect-nudge`) sin pisar lo que ya exista.
|
|
145
151
|
- Agrega **permisos mínimos y enumerados** (sin `mcp__*` ni rutas absolutas):
|
|
146
152
|
|
|
147
153
|
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# design-source-guard.sh — PreToolUse · Write/Edit/MultiEdit
|
|
3
|
+
# Backstop determinista del "seguro de fuente de diseño": no se escribe código de un slice
|
|
4
|
+
# CON UI sin que la fuente de diseño del proyecto esté confirmada. Espejo de scaffold-guard.sh.
|
|
5
|
+
# Bloquea (exit 2) SOLO si: hay active_slice en fase de código (red/green/refactor/smoke/api/data),
|
|
6
|
+
# el proyecto tiene UI (design_source.applies===true), el slice está marcado UI-pendiente
|
|
7
|
+
# (gates.fidelity===false) y design_source.confirmed!==true.
|
|
8
|
+
# AUTO-ARME: si no existe build-state.json, exit 0.
|
|
9
|
+
set -uo pipefail
|
|
10
|
+
|
|
11
|
+
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "${CLAUDE_PROJECT_DIR:-$(pwd)}")"
|
|
12
|
+
STATE="$ROOT/.claude/state/build-state.json"
|
|
13
|
+
[ -f "$STATE" ] || exit 0
|
|
14
|
+
|
|
15
|
+
INPUT="$(cat)" # consumir stdin (protocolo de hook); la decisión es por estado.
|
|
16
|
+
|
|
17
|
+
# Guarda python3 [H4]: si falta, no podemos leer el estado de forma fiable. Fail-closed.
|
|
18
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
19
|
+
echo "⛔ design-source-guard: python3 no disponible; no puedo verificar el gate de fuente de diseño. Instala python3 (trycore-build doctor)." >&2
|
|
20
|
+
exit 2
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
VERDICT="$(STATE="$STATE" python3 <<'PY' 2>/dev/null
|
|
24
|
+
import os, sys, json
|
|
25
|
+
try:
|
|
26
|
+
d = json.load(open(os.environ["STATE"]))
|
|
27
|
+
except Exception:
|
|
28
|
+
sys.exit(0) # estado ilegible -> no bloquear (auto-arme)
|
|
29
|
+
slice_ = d.get("active_slice")
|
|
30
|
+
if not slice_:
|
|
31
|
+
sys.exit(0) # sin slice: permitir declarar / planificar
|
|
32
|
+
code_phases = {"red", "green", "refactor", "smoke", "api", "data"}
|
|
33
|
+
if slice_.get("phase") not in code_phases:
|
|
34
|
+
sys.exit(0) # fases dor/change/pr/archived: permitido
|
|
35
|
+
ds = d.get("design_source") or {}
|
|
36
|
+
if ds.get("applies") is not True:
|
|
37
|
+
sys.exit(0) # proyecto sin UI (o indeterminado): mecanismo apagado
|
|
38
|
+
if (slice_.get("gates") or {}).get("fidelity") is not False:
|
|
39
|
+
sys.exit(0) # solo UI-pendiente (false) cuenta; null/ausente -> no bloquear
|
|
40
|
+
if ds.get("confirmed") is True:
|
|
41
|
+
sys.exit(0) # fuente de diseño confirmada: permitido
|
|
42
|
+
print("BLOCK")
|
|
43
|
+
PY
|
|
44
|
+
)"
|
|
45
|
+
|
|
46
|
+
if [ "$VERDICT" = "BLOCK" ]; then
|
|
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
|
+
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
|
|
50
|
+
exit 2
|
|
51
|
+
fi
|
|
52
|
+
exit 0
|
|
@@ -39,8 +39,24 @@ if not s:
|
|
|
39
39
|
else:
|
|
40
40
|
g=s.get("gates",{})
|
|
41
41
|
abiertos=[k for k,v in g.items() if v is False]
|
|
42
|
-
|
|
42
|
+
hus=", ".join(s.get("hus") or []) or "—"
|
|
43
|
+
print(f" Slice activo: {s.get('epica')} [{hus}] · change={s.get('openspec_change')} · fase={s.get('phase')}")
|
|
43
44
|
print(f" Gates pendientes: {', '.join(abiertos) if abiertos else 'ninguno ✅'}")
|
|
45
|
+
# Handoff fino en disco (A1): items de cableado aún FAILING + última bitácora.
|
|
46
|
+
# Una sesión fresca arranca de aquí; mientras queden failing, el cableado NO está hecho.
|
|
47
|
+
failing=[w for w in (s.get("wiring_checklist") or []) if w.get("status")=="failing"]
|
|
48
|
+
if failing:
|
|
49
|
+
muestra="; ".join(f"{w.get('id')}({w.get('kind')})" for w in failing[:8])
|
|
50
|
+
extra=f" (+{len(failing)-8} más)" if len(failing)>8 else ""
|
|
51
|
+
print(f" ⚠️ Cableado pendiente ({len(failing)} item/s failing): {muestra}{extra}")
|
|
52
|
+
print(" NO declares el slice terminado mientras queden items failing (verifica con prueba real).")
|
|
53
|
+
pend=[ss for ss in (s.get("sub_slices") or []) if ss.get("status")!="done"]
|
|
54
|
+
if pend:
|
|
55
|
+
print(f" ⚠️ Sub-slices pendientes: {', '.join(ss.get('id') for ss in pend)}")
|
|
56
|
+
log=s.get("progress_log") or []
|
|
57
|
+
if log:
|
|
58
|
+
last=log[-1]
|
|
59
|
+
print(f" Última bitácora: [{last.get('by')}] {last.get('note')}")
|
|
44
60
|
PY
|
|
45
61
|
fi
|
|
46
62
|
exit 0
|
package/hooks/build-harness.json
CHANGED
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
{
|
|
32
32
|
"type": "command",
|
|
33
33
|
"command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/scaffold-guard.sh\""
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "command",
|
|
37
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/design-source-guard.sh\""
|
|
34
38
|
}
|
|
35
39
|
]
|
|
36
40
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trycore/spec-build-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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": {
|
|
@@ -25,7 +25,14 @@ el avance en el estado.
|
|
|
25
25
|
`.claude/state/README.md`). Lee antes de actuar; escribe una vez por transición.
|
|
26
26
|
- **Secuencial**: un slice activo a la vez. Un gate no se salta.
|
|
27
27
|
- **Divulgación progresiva**: carga el `references/<tema>.md` solo cuando la fase lo necesita.
|
|
28
|
-
- **Delega en subagentes** para revisión pesada (devuelven síntesis,
|
|
28
|
+
- **Delega en subagentes** para revisión pesada y para **explorar** (devuelven síntesis condensada,
|
|
29
|
+
protegen el presupuesto de atención de la sesión principal para **cablear**, no para descubrir).
|
|
30
|
+
- **Refresh de contexto = estado por defecto**: cada iteración nace **headless / contexto virgen** y
|
|
31
|
+
reconstruye el estado **desde disco** (git + `build-state.json` + logs), no desde la conversación
|
|
32
|
+
viva. Mantén el **`wiring_checklist[]`** (un item por escenario AC y por punto de integración entre
|
|
33
|
+
capas): nace `failing`, pasa a `passing` **solo tras prueba real ejecutada**. Deja una nota en
|
|
34
|
+
`progress_log[]` por hito. **Mientras quede un item `failing`, el slice NO está terminado.** Ver
|
|
35
|
+
`references/state-protocol.md`.
|
|
29
36
|
|
|
30
37
|
## Dos loops
|
|
31
38
|
|
|
@@ -39,6 +46,21 @@ inner loop: **≤ ~20 min por épica** y producto que **camina end-to-end en tod
|
|
|
39
46
|
> cada paso sea un stub. Cada épica posterior **engorda** un paso de ese esqueleto y mantiene el
|
|
40
47
|
> `journey_smoke` verde. Nunca se construyen capas horizontales aisladas que "se juntan al final".
|
|
41
48
|
|
|
49
|
+
> **Cimiento antes que negocio (épicas fundacionales).** Las épicas marcadas `layer: foundational`
|
|
50
|
+
> (autenticación, acceso a datos, arquitectura base, design-system/componentes base) se construyen
|
|
51
|
+
> **antes** que las `layer: business`. El DoR **rechaza** abrir una épica de negocio que arrastra
|
|
52
|
+
> cimiento no construido y lo extrae a una épica fundacional previa (ver `dor.md`). Así cada slice de
|
|
53
|
+
> negocio **solo toca lógica aplicable** y no quema contexto creando infra.
|
|
54
|
+
|
|
55
|
+
> **Descomposición por tamaño (no one-shot).** Una épica que supera el **gate de tamaño**
|
|
56
|
+
> (heurística por defecto: **> 3 HU** ó **≥ 3 capas tocadas**; configurable por proyecto) es
|
|
57
|
+
> demasiado grande para una pasada: el DoR obliga a trocearla en **sub-slices verificables**
|
|
58
|
+
> (`sub_slices[]`) construidos **de a uno**, con `journey_smoke` verde entre cada uno antes de pasar
|
|
59
|
+
> al siguiente. El orquestador trabaja por **fases encadenadas** (mapear → generar → revisar →
|
|
60
|
+
> fix-loop → optimizar) y reparte la exploración **"ancho antes que profundo"** con subagentes
|
|
61
|
+
> **solo-lectura por área** (frontend/backend/datos); el **cableado** lo hace la sesión, no
|
|
62
|
+
> subagentes que escriben en paralelo. Trocear acota además el tamaño del `wiring_checklist[]`.
|
|
63
|
+
|
|
42
64
|
## Fase 0 · Scaffold (Paso 1 fundamental — precondición restrictiva)
|
|
43
65
|
|
|
44
66
|
Antes de abrir **cualquier** slice, el scaffold runnable del proyecto debe **existir y estar
|
|
@@ -56,6 +78,21 @@ camina* se construye **encima** del scaffold ya existente.
|
|
|
56
78
|
3. El gate lo valida también el `dor-dod-gatekeeper` (criterio duro de DoR) y lo respalda el hook
|
|
57
79
|
determinista `scaffold-guard.sh` (bloquea escribir código de slice sin scaffold confirmado).
|
|
58
80
|
|
|
81
|
+
## Fase 0-bis · Fuente de diseño (seguro para slices con UI)
|
|
82
|
+
|
|
83
|
+
Espejo de la Fase 0, para proyectos **con UI**. Antes de abrir el primer slice con UI:
|
|
84
|
+
1. Lee `design_source` en `build-state.json`.
|
|
85
|
+
- `applies` indeterminado (ausente) → pregunta *"¿este proyecto tiene UI?"* y fija `applies`.
|
|
86
|
+
- `applies === false` → N/A, salta esta fase.
|
|
87
|
+
- `confirmed === true` → continúa.
|
|
88
|
+
2. `applies===true && confirmed===false` → **pregunta explícita** (AskUserQuestion): *"¿Existe una
|
|
89
|
+
fuente de diseño declarada (prototipo/export) para la UI de este proyecto?"*
|
|
90
|
+
- **No** → **STOP**. Indica declararla (ruta/URL del prototipo o export). El arnés **NO la genera**.
|
|
91
|
+
No abras el slice con UI.
|
|
92
|
+
- **Sí** → registra `design_source.source`, `confirmed=true`, `confirmed_by`, `confirmed_at`, `notes`.
|
|
93
|
+
3. Lo respalda el hook determinista `design-source-guard.sh` (bloquea código de slice UI sin fuente
|
|
94
|
+
confirmada) y lo valida el `dor-dod-gatekeeper` (criterio duro de DoR).
|
|
95
|
+
|
|
59
96
|
## Pipeline — inner loop (carga la referencia indicada en cada paso)
|
|
60
97
|
|
|
61
98
|
| Fase | Acción | Delega en | Gate | Referencia |
|
|
@@ -63,9 +100,9 @@ camina* se construye **encima** del scaffold ya existente.
|
|
|
63
100
|
| 1 · dor | Validar Definition of Ready | `dor-dod-gatekeeper` | `dor` | `dor.md` |
|
|
64
101
|
| 2 · change | `opsx:new` + bloque `## Trazabilidad`; validar enlace (barato) | `opsx:new`, `change-epic-coherence` | `coherence_link` | `link-change-epic.md` |
|
|
65
102
|
| 3 · tdd | red → green → refactor | `superpowers:test-driven-development` | `tdd` | — |
|
|
66
|
-
| 4 · smoke | Recorrer el journey-hasta-aquí end-to-end
|
|
103
|
+
| 4 · smoke | Recorrer el journey-hasta-aquí end-to-end con el **runner determinista fuera-de-chat** (`integration-check`: suite+build+reporte) en **sesión/contexto virgen**; **slices con UI:** fidelidad por **verificación visual REAL** (MCP chrome-devtools, screenshot app vs prototipo) | runner `integration-check`, skill `verify`/`run` + MCP chrome-devtools, `ux-fidelity-reviewer` | `journey_smoke`,`fidelity` | `integration-check.md`, `mcp-map.md` |
|
|
67
104
|
| 5 · api/data | contratos + consistencia (si aplican al slice) | `api-contract-tester`, `data-consistency-checker` | `api`,`data` | `newman-tests.md`, `data-consistency.md` |
|
|
68
|
-
| 6 · dod |
|
|
105
|
+
| 6 · dod | **Primero** verificación adversarial INDEPENDIENTE del cableado (contexto virgen: refuta stubs/rutas sin cablear/AC sin test/items `failing`) → `wiring_verified`; **solo entonces** Definition of Done | `wiring-adversarial-verifier`, `dor-dod-gatekeeper` | `wiring_verified`,`dod` | `dod.md`, `integration-check.md` |
|
|
69
106
|
| 7 · pr | Abrir PR + archivar change en el mismo PR | `opsx:archive`, `opsx:sync` | — | `gitflow.md` |
|
|
70
107
|
| 8 · release? | Preguntar si correr el Release Gate ahora | usuario (default computado) | — | abajo |
|
|
71
108
|
|
|
@@ -73,6 +110,16 @@ Los gates `stack`, `security`, `smell`, `ux` y la coherencia triple completa **y
|
|
|
73
110
|
aquí**: pertenecen al Release Gate. Las **deps** siguen vigiladas en tiempo real por el hook
|
|
74
111
|
`stack-guard.sh`; lint/tsc/gitflow por sus hooks.
|
|
75
112
|
|
|
113
|
+
El gate `fidelity` (fidelidad a la fuente de diseño) **sí** es de inner loop: se computa en `smoke`,
|
|
114
|
+
con la app ya levantada, y es vivo por-slice; complementa al `ux-krug-reviewer` (usabilidad), que
|
|
115
|
+
sigue en el Release Gate. **Estricto para UI:** una UI no mejora su fidelidad por el prompt sino
|
|
116
|
+
porque el agente **carga la página, observa la salida real y lee la consola**. Para slices con UI
|
|
117
|
+
(`design_source.applies===true`), `fidelity` **solo cierra con verificación visual real vía MCP
|
|
118
|
+
chrome-devtools** (screenshot app vs prototipo). Sin MCP, `fidelity` queda `false` (INCONCLUSO ya
|
|
119
|
+
**no** pasa) → el `dod` no cierra: corre el slice donde haya MCP. Mantén **cobertura** (ninguna
|
|
120
|
+
pantalla del prototipo en alcance sin construir; ninguna pantalla de la app sin HU/EP) y el
|
|
121
|
+
**journey-smoke de clic real como tenant no-admin**.
|
|
122
|
+
|
|
76
123
|
MCP/LSP por gate: ver `references/mcp-map.md`. Protocolo de estado: `references/state-protocol.md`.
|
|
77
124
|
|
|
78
125
|
## Fase 8 · ¿Release Gate ahora? (default computado, humano decide)
|
|
@@ -107,4 +154,11 @@ El usuario siempre puede sobreescribir el default. Si acepta, invoca la skill
|
|
|
107
154
|
- El enlace change↔épica va en `## Trazabilidad` del `proposal.md`, **nunca** en frontmatter YAML
|
|
108
155
|
(rompe `openspec validate`). Ver `link-change-epic.md`.
|
|
109
156
|
- Integración solo por **PR** a `main` (el hook `gitflow-guard.sh` bloquea commits/push directos).
|
|
157
|
+
- **`dod` exige `wiring_verified: true`** (verificación adversarial independiente, contexto virgen).
|
|
158
|
+
El DoD declarativo del gatekeeper es un **piso, no el arreglo**: reusar el mismo agente como
|
|
159
|
+
generador y verificador produce auto-confirmación. La generación y la verificación van separadas.
|
|
160
|
+
- **Producto completo, no MVP.** El alcance acordado se construye entero. **Recortar o diferir es
|
|
161
|
+
bloqueante explícito** que requiere acuerdo del equipo — nunca una decisión del modelo. No derives
|
|
162
|
+
en lo complejo. La verificación es **ejecutada, no por inspección** (ver `METODOLOGIA.md` y el
|
|
163
|
+
bloque del arnés en `CLAUDE.md`).
|
|
110
164
|
- Si una regla aquí contradice la metodología Trycore (`METODOLOGIA.md`), **gana la metodología**.
|
|
@@ -11,6 +11,20 @@ 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. **ESTRICTO para
|
|
16
|
+
UI** (`design_source.applies===true`): solo `true` con **verificación visual real** vía MCP
|
|
17
|
+
chrome-devtools (screenshot app vs prototipo). **INCONCLUSO ya NO pasa**: sin MCP queda `false` y el
|
|
18
|
+
`dod` no cierra (corre el slice donde haya MCP). Mantén **cobertura** (ninguna pantalla del prototipo
|
|
19
|
+
en alcance sin construir; ninguna pantalla de la app sin HU/EP). Es gate **vivo** de inner loop (no la
|
|
20
|
+
revisión Krug, que sigue en el Release Gate).
|
|
21
|
+
- [ ] **Sub-slices completos** — si la épica se descompuso (`sub_slices[]` no vacío), **todos** en
|
|
22
|
+
`status: done` con su `journey_smoke` verde. No se cierra `dod` con sub-slices pendientes.
|
|
23
|
+
- [ ] **`wiring_verified`** — el `wiring-adversarial-verifier` (subagente **independiente**, contexto
|
|
24
|
+
virgen) intentó **refutar** el slice (stubs, rutas sin cablear, AC sin test, items de
|
|
25
|
+
`wiring_checklist[]` aún `failing`) y no halló huecos → `gates.wiring_verified: true`. **Prerequisito
|
|
26
|
+
duro de `dod`**: el DoD declarativo de este checklist es un **piso, no el arreglo** (la auto-confirmación
|
|
27
|
+
surge de reusar el mismo agente como generador y verificador).
|
|
14
28
|
- [ ] **OpenSpec**: todas las tasks `[x]`; el archive del change va **en el mismo PR** (no PR aparte).
|
|
15
29
|
- [ ] **Docs/trazabilidad**: back-ref del change añadida en la épica y en cada HU de `hus[]`.
|
|
16
30
|
- [ ] **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`).
|
|
@@ -7,11 +7,17 @@ la épica; lo de abajo aplica a la épica y a **cada HU** que cubre (`hus[]`). L
|
|
|
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
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 → **1–2** (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
|
-
- [ ] **INVEST** por HU: pasa los 6 criterios (Independent, Negotiable, Valuable, Estimable, Small, Testable).
|
|
11
|
-
- [ ] **Dependencias resueltas**: las épicas/HU de las que depende están archivadas (`history[]`) o explícitamente no bloquean.
|
|
10
|
+
- [ ] **INVEST** por HU: pasa los 6 criterios (Independent, Negotiable, Valuable, Estimable, Small, Testable).
|
|
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
|
+
- [ ] **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
|
+
- [ ] **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.
|
|
12
14
|
- [ ] **Cabe en el stack** del PRD §7 (no requiere tecnología fuera de `stack-allowlist.json`).
|
|
13
15
|
- [ ] **Datos de prueba disponibles** o identificables (p.ej. los datos de ejemplo / fixtures sintéticos del dominio del consumidor).
|
|
16
|
+
- [ ] **Fuente de diseño identificada (slices con UI)**: la fuente visual de verdad del slice
|
|
17
|
+
(el `DESIGN_SOURCE` del dominio) está declarada y confirmada (`design_source.confirmed`), y este
|
|
18
|
+
slice apunta a la(s) pantalla(s) equivalente(s). No se construye UI fuera de la fuente declarada.
|
|
14
19
|
|
|
15
20
|
**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`
|
|
21
|
+
`phase: dor`, `gates.dor: true` y el resto en `false` —incluido **`wiring_verified: false`**—
|
|
22
|
+
(`fidelity`/`api` en `null` si la épica no toca UI/endpoints; `fidelity` arranca en `false` si toca UI).
|
|
17
23
|
**Si algo ✗** → no se abre el slice; se reporta qué falta y se vuelve a discovery (Trycore).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Runner de integración fuera-de-chat (`integration-check`)
|
|
2
|
+
|
|
3
|
+
Gate determinista que cierra `journey_smoke` **ejecutando**, no por inspección. Lleva el patrón del
|
|
4
|
+
gate fuera-de-chat (como `tools/loop/gateway-check.sh` de un consumidor) al **inner-loop manual**, no
|
|
5
|
+
solo al autónomo. **No crea ningún gate nuevo**: alimenta el `journey_smoke` existente del slice. El
|
|
6
|
+
gate `integration` con dependencias reales sigue siendo del **Release Gate** (outer loop).
|
|
7
|
+
|
|
8
|
+
## Por qué fuera de chat y en contexto virgen
|
|
9
|
+
- El cableado end-to-end **se ejecuta** (build + suite + journey), no se "razona". Un script lo hace
|
|
10
|
+
reproducible y barato en contexto.
|
|
11
|
+
- Quien escribió el código **no es buen juez** de su propio cableado: corre el runner en una
|
|
12
|
+
**sesión/contexto virgen** (o como paso de CI) y entra al **fix-loop** (corre → lee el reporte →
|
|
13
|
+
arregla → repite) hasta verde.
|
|
14
|
+
|
|
15
|
+
## Cómo adoptarlo
|
|
16
|
+
1. Copia `templates/integration-check.sh.template` a tu repo (p.ej. `tools/loop/integration-check.sh`)
|
|
17
|
+
y hazlo ejecutable (`chmod +x`).
|
|
18
|
+
2. **Adapta** los comandos marcados `# ADAPTA` a tu stack (build, suite, e2e). El arnés es agnóstico:
|
|
19
|
+
el template trae defaults de Node como punto de partida.
|
|
20
|
+
3. Córrelo en la fase `smoke`. Salida **0 = verde** (puedes marcar `journey_smoke: true`), **≠0 = rojo**.
|
|
21
|
+
El reporte queda en `.claude/state/integration-report.txt`.
|
|
22
|
+
4. Mientras la suite no esté verde y el journey no camine end-to-end, `journey_smoke` queda `false`.
|
|
23
|
+
|
|
24
|
+
## Relación con el cableado fino
|
|
25
|
+
Cada paso verde del runner es la **evidence** que permite pasar items de `wiring_checklist[]` de
|
|
26
|
+
`failing` a `passing` (ver `state-protocol.md`). El `wiring-adversarial-verifier` (fase `dod`) revisará
|
|
27
|
+
después que esa evidencia sea real.
|
|
@@ -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** *(REQUERIDO para slices con UI)* | `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`. **Excepción a la regla opt-in**: para UI la verificación visual real es obligatoria; sin MCP, `fidelity` queda `false` (INCONCLUSO bloquea) y el `dod` no cierra. Cualquier MCP de devtools de navegador sirve (chrome-devtools es el ejemplo). |
|
|
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. |
|
|
@@ -11,6 +11,19 @@ python3 -c 'import json;print(json.dumps(json.load(open(".claude/state/build-sta
|
|
|
11
11
|
- `active_slice == null` → no hay slice; solo `dor` puede abrir uno.
|
|
12
12
|
- Si no es null → identifica el **primer gate en `false`**: ahí se reanuda.
|
|
13
13
|
|
|
14
|
+
## Refresh de contexto = estado por defecto (handoff en disco)
|
|
15
|
+
Cada iteración nace **headless / contexto virgen** y reconstruye el estado **desde disco** (git history +
|
|
16
|
+
este `build-state.json` + logs de build), **no** desde la conversación viva: alargar una sesión degrada
|
|
17
|
+
el razonamiento (ruido acumulado → deriva). Para retomar sin "creer que ya está":
|
|
18
|
+
- **`wiring_checklist[]`** — un item por escenario AC de cada HU y por **punto de integración entre capas**.
|
|
19
|
+
Nace `failing`; pasa a `passing` **SOLO tras prueba real ejecutada** (con `evidence`), nunca por inspección.
|
|
20
|
+
**Mientras quede un item `failing`, el slice NO está cableado** — no cierres `wiring_verified` ni `dod`.
|
|
21
|
+
- **`progress_log[]`** — bitácora append-only (`{at, by, note}`) de qué se hizo / qué falta. Deja una nota
|
|
22
|
+
por hito para que la siguiente sesión retome el cableado.
|
|
23
|
+
- **`sub_slices[]`** — si la épica superó el gate de tamaño (>3 HU ó ≥3 capas), se trocea aquí; cada
|
|
24
|
+
sub-slice se construye de a uno con su `journey_smoke` verde antes de pasar al siguiente.
|
|
25
|
+
`load-build-state.sh` inyecta al arrancar los items `failing` y la última bitácora (JIT, solo lo pendiente).
|
|
26
|
+
|
|
14
27
|
## Escritura (una transición = una escritura)
|
|
15
28
|
Patrón seguro (lee-modifica-escribe) con timestamp UTC:
|
|
16
29
|
```bash
|
|
@@ -27,16 +40,20 @@ PY
|
|
|
27
40
|
```
|
|
28
41
|
|
|
29
42
|
## Inner loop vs releases[]
|
|
30
|
-
- **Inner loop (por slice)**: gates `dor`, `tdd`, `journey_smoke`, `coherence_link`, `data`, `
|
|
31
|
-
`dod` en `active_slice.gates`. Los escribe el flujo de `building-a-slice` /
|
|
43
|
+
- **Inner loop (por slice)**: gates `dor`, `tdd`, `journey_smoke`, `coherence_link`, `data`, `fidelity`,
|
|
44
|
+
`api`, `wiring_verified`, `dod` en `active_slice.gates`. Los escribe el flujo de `building-a-slice` /
|
|
45
|
+
`build-orchestrator`. **`wiring_verified` es prerequisito de `dod`** (lo cierra el verificador
|
|
46
|
+
adversarial independiente, no el mismo agente que construyó).
|
|
32
47
|
- **Outer loop (por release)**: los gates pesados (`security`, `smell`, `ux`, `coherence`,
|
|
33
48
|
`stack_arch`, `integration`) **no** viven en el slice — viven en una entrada de `releases[]` que
|
|
34
49
|
escribe la skill `releasing-a-version`. Una release = una línea de release del Story Map.
|
|
35
50
|
|
|
36
51
|
## Reglas
|
|
37
|
-
1. **No saltes gates**: no cierres `dod` con gates abiertos
|
|
52
|
+
1. **No saltes gates**: no cierres `dod` con gates abiertos; en particular `dod` exige `wiring_verified: true`.
|
|
38
53
|
2. **Retroceso permitido**: si una revisión posterior falla, pon su gate en `false` y retrocede `phase`.
|
|
39
|
-
3. **`
|
|
54
|
+
3. **`fidelity`/`api` = `null`** cuando no aplican (no cuentan como abiertos para DoD). `fidelity` NO puede
|
|
55
|
+
quedar `null` si el slice toca UI (`design_source.applies===true`): ahí debe llegar a `true` por
|
|
56
|
+
verificación visual real (MCP). `wiring_verified` aplica siempre (no admite `null`).
|
|
40
57
|
4. **Archivar**: mueve `active_slice` a `history[]` con `phase:"archived"`, deja `active_slice:null`.
|
|
41
58
|
5. **Valida tras escribir**:
|
|
42
59
|
```bash
|
package/state/README.md
CHANGED
|
@@ -24,7 +24,9 @@ Cada gate del pipeline transiciona el estado; el siguiente agente lo lee antes d
|
|
|
24
24
|
correspondiente, `updated_at` (ISO 8601 UTC) y `updated_by` (su nombre). No tocar otros campos.
|
|
25
25
|
3. **Gates monótonos hacia adelante.** Un gate solo pasa de `false`→`true` cuando su agente lo
|
|
26
26
|
aprueba. Si una revisión posterior falla, se vuelve a `false` y `phase` retrocede.
|
|
27
|
-
4. **`
|
|
27
|
+
4. **`fidelity`/`api` admiten `null`** cuando el slice no tiene UI o endpoints (N/A, no bloquea DoD).
|
|
28
|
+
`fidelity` **no** puede quedar `null` si el slice toca UI. `wiring_verified` aplica siempre (sin `null`)
|
|
29
|
+
y es **prerequisito de `dod`**.
|
|
28
30
|
5. **Archivar**: al completar `opsx:archive`, mover el `active_slice` a `history[]` con
|
|
29
31
|
`phase: "archived"` y dejar `active_slice: null`.
|
|
30
32
|
6. **Dos loops**: el slice (inner loop) cierra gates baratos por épica; los gates pesados viven en
|
|
@@ -51,6 +53,32 @@ Arranca en `confirmed: false` y **solo** pasa a `true` por **confirmación expl
|
|
|
51
53
|
restrictiva para abrir cualquier slice: el hook `scaffold-guard.sh` bloquea escribir código de
|
|
52
54
|
slice (fases `red…data`) mientras `confirmed` no sea `true`. El arnés **no genera** el scaffold.
|
|
53
55
|
|
|
56
|
+
### `design_source` (gate de proyecto, slices con UI)
|
|
57
|
+
|
|
58
|
+
Espejo de `scaffold` para la UI: `applies` (¿el proyecto tiene UI?), `confirmed` (humano confirmó que
|
|
59
|
+
existe una fuente de diseño declarada), `source` (puntero al prototipo/export). El arnés NO genera el
|
|
60
|
+
prototipo. Lo respalda `design-source-guard.sh`.
|
|
61
|
+
|
|
62
|
+
### gate `fidelity` (por-slice, inner loop) — ESTRICTO para UI
|
|
63
|
+
|
|
64
|
+
`true` = FIEL (o desviaciones justificadas, **vía verificación visual real**); `false` = desviaciones
|
|
65
|
+
sin justificar **o** verificación visual no realizada; `null` = slice sin UI. Lo computa
|
|
66
|
+
`ux-fidelity-reviewer` en la fase `smoke` y lo escribe el `build-orchestrator`. Para slices con UI
|
|
67
|
+
(`design_source.applies===true`) solo cierra con **MCP chrome-devtools** (screenshot app vs prototipo):
|
|
68
|
+
INCONCLUSO ya **no** pasa (queda `false` → el `dod` no cierra hasta correrlo donde haya MCP).
|
|
69
|
+
|
|
70
|
+
### Handoff fino del cableado (`wiring_checklist[]`, `progress_log[]`, `sub_slices[]`) + gate `wiring_verified`
|
|
71
|
+
|
|
72
|
+
Campos por-slice que hacen el **refresh de contexto el estado por defecto** (una sesión fresca retoma
|
|
73
|
+
desde disco, no desde la conversación):
|
|
74
|
+
- **`wiring_checklist[]`** — un item por escenario AC y por punto de integración entre capas; nace
|
|
75
|
+
`failing`, pasa a `passing` **solo tras prueba real ejecutada** (con `evidence`).
|
|
76
|
+
- **`progress_log[]`** — bitácora append-only (`{at, by, note}`) que sobrevive al reset.
|
|
77
|
+
- **`sub_slices[]`** — descomposición de una épica que superó el gate de tamaño (>3 HU ó ≥3 capas).
|
|
78
|
+
- **gate `wiring_verified`** — lo cierra el `wiring-adversarial-verifier` (subagente **independiente**,
|
|
79
|
+
contexto virgen, que intenta **refutar** el slice). `dod` no puede ser `true` sin él. Lo inicializa
|
|
80
|
+
el `dor-dod-gatekeeper` en `false` durante el DoR.
|
|
81
|
+
|
|
54
82
|
### Reflexión post-slice (ciclo autocorrectivo)
|
|
55
83
|
|
|
56
84
|
Tras archivar un slice, su entrada en `history[]` puede llevar `reflected` / `reflected_at`. El
|
|
@@ -67,9 +95,10 @@ El razonamiento vive en el modelo; el hook solo es un recordatorio determinista.
|
|
|
67
95
|
| `active_slice` (alta) · `gates.dor` · `gates.dod` | `dor-dod-gatekeeper` | slice |
|
|
68
96
|
| `gates.coherence_link` | `change-epic-coherence` | slice |
|
|
69
97
|
| `gates.tdd` | flujo `superpowers:test-driven-development` (vía `build-orchestrator`) | slice |
|
|
70
|
-
| `gates.journey_smoke` · `phase` (transiciones) · `history[]` (archivado) | `build-orchestrator` | slice |
|
|
98
|
+
| `gates.journey_smoke` · `gates.fidelity` · `phase` (transiciones) · `history[]` (archivado) · `wiring_checklist[]` · `progress_log[]` · `sub_slices[]` | `build-orchestrator` (fidelity desde `ux-fidelity-reviewer`) | slice |
|
|
71
99
|
| `gates.api` | `api-contract-tester` | slice |
|
|
72
100
|
| `gates.data` | `data-consistency-checker` | slice |
|
|
101
|
+
| `gates.wiring_verified` | `wiring-adversarial-verifier` (independiente, contexto virgen) | slice (antes de `dod`) |
|
|
73
102
|
| `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 |
|
|
74
103
|
| `history[].reflected` · `history[].reflected_at` | `/build:reflect` | post-slice (tras archivar) |
|
|
75
104
|
| `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,
|
|
@@ -67,14 +82,16 @@
|
|
|
67
82
|
"gates": {
|
|
68
83
|
"type": "object",
|
|
69
84
|
"additionalProperties": false,
|
|
70
|
-
"description": "Inner loop (por slice): dor, tdd, journey_smoke, data, api(null),
|
|
85
|
+
"description": "Inner loop (por slice): dor, tdd, journey_smoke, coherence_link, data, fidelity, api(null), wiring_verified, dod. Los gates pesados (stack, security, smell, ux, coherence) se cerraron por slice en la era anterior y hoy viven en releases[]; se mantienen como propiedades opcionales para validar historial.",
|
|
71
86
|
"required": ["dor", "tdd", "dod"],
|
|
72
87
|
"properties": {
|
|
73
88
|
"dor": { "type": "boolean" },
|
|
74
89
|
"tdd": { "type": "boolean" },
|
|
75
|
-
"journey_smoke": { "type": "boolean", "description": "El backbone-hasta-aquí camina end-to-end (verificado con la skill verify/run)." },
|
|
90
|
+
"journey_smoke": { "type": "boolean", "description": "El backbone-hasta-aquí camina end-to-end (verificado con la skill verify/run + runner fuera-de-chat integration-check)." },
|
|
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, computado en fase smoke por ux-fidelity-reviewer. Aplica cuando el slice toca UI (en un proyecto con design_source.applies===true); si el slice NO toca UI, es null aunque el proyecto tenga UI. ESTRICTO para UI: solo cierra con VERIFICACIÓN VISUAL REAL vía MCP de devtools de navegador (screenshot app vs prototipo). true = FIEL (o DESVIACIONES justificadas, vía MCP); false = DESVIACIONES sin justificar O verificación visual no realizada (INCONCLUSO ya NO pasa para UI); null = N/A (slice sin UI). NO es legado (los legados viven en releases[])." },
|
|
94
|
+
"wiring_verified": { "type": "boolean", "description": "Gate de cierre del inner loop (A4): un subagente adversarial INDEPENDIENTE de contexto virgen (wiring-adversarial-verifier) intentó refutar el slice (stubs, rutas sin cablear, AC sin test, items de wiring_checklist[] aún failing) y NO encontró huecos. dod NO puede ser true hasta que wiring_verified sea true. Lo inicializa el gatekeeper en false en el DoR." },
|
|
78
95
|
"api": { "type": ["boolean", "null"], "description": "null = N/A (slice sin endpoints)." },
|
|
79
96
|
"ux": { "type": ["boolean", "null"], "description": "null = N/A (slice sin UI). Legado: hoy se audita en releases[]." },
|
|
80
97
|
"stack": { "type": "boolean", "description": "Legado por-slice; deps las cubre el hook stack-guard.sh, la arquitectura se audita en releases[]." },
|
|
@@ -88,7 +105,53 @@
|
|
|
88
105
|
"updated_by": { "type": "string", "description": "Agente o hook que escribió el estado." },
|
|
89
106
|
"notes": { "type": "string", "description": "Nota libre opcional (p.ej. changes/branches adicionales de una épica construida en varios pasos)." },
|
|
90
107
|
"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." },
|
|
91
|
-
"reflected_at": { "type": "string", "format": "date-time", "description": "Cuándo se reflexionó (ISO-8601 UTC). Lo escribe /build:reflect." }
|
|
108
|
+
"reflected_at": { "type": "string", "format": "date-time", "description": "Cuándo se reflexionó (ISO-8601 UTC). Lo escribe /build:reflect." },
|
|
109
|
+
"wiring_checklist": {
|
|
110
|
+
"type": "array",
|
|
111
|
+
"description": "Handoff FINO del cableado (A1): un item por escenario AC de cada HU y por punto de integración entre capas (SPA↔gateway↔core↔worker↔persistencia). Nace failing; pasa a passing SOLO tras prueba real ejecutada (con evidence), nunca por inspección. Sobrevive al reset de contexto: una sesión fresca lee los failing de disco y NO declara 'hecho' si quedan. El wiring-adversarial-verifier audita estos items antes de cerrar wiring_verified. Ausente/vacío en slices triviales.",
|
|
112
|
+
"items": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"additionalProperties": false,
|
|
115
|
+
"required": ["id", "kind", "ref", "status"],
|
|
116
|
+
"properties": {
|
|
117
|
+
"id": { "type": "string", "description": "Identificador estable del item (p.ej. HU-003-AC2 o INT-spa-gateway)." },
|
|
118
|
+
"kind": { "type": "string", "enum": ["hu_ac", "integration_point"], "description": "hu_ac = escenario Given/When/Then de una HU; integration_point = cableado entre dos capas." },
|
|
119
|
+
"ref": { "type": "string", "description": "A qué apunta: el AC (HU-XXX#escenario) o el par de capas (capaA→capaB)." },
|
|
120
|
+
"status": { "type": "string", "enum": ["failing", "passing"], "description": "failing al nacer; passing SOLO tras prueba real ejecutada." },
|
|
121
|
+
"evidence": { "type": "string", "description": "Evidencia de ejecución que justificó passing (test, comando, salida). Vacío mientras failing." }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"progress_log": {
|
|
126
|
+
"type": "array",
|
|
127
|
+
"description": "Bitácora de progreso que sobrevive al reset de contexto (A1): permite a una sesión fresca/headless retomar el cableado sin 'creer que ya está'. Append-only; complementa a git history y los logs de build.",
|
|
128
|
+
"items": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"additionalProperties": false,
|
|
131
|
+
"required": ["at", "by", "note"],
|
|
132
|
+
"properties": {
|
|
133
|
+
"at": { "type": "string", "format": "date-time" },
|
|
134
|
+
"by": { "type": "string", "description": "Agente/sesión que dejó la nota." },
|
|
135
|
+
"note": { "type": "string", "description": "Qué se hizo / qué falta (hito conciso)." }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"sub_slices": {
|
|
140
|
+
"type": "array",
|
|
141
|
+
"description": "Descomposición de una épica grande (A3): si supera el umbral del gate de tamaño (>3 HU ó ≥3 capas tocadas), se trocea en sub-slices verificables construidos DE A UNO, con journey_smoke verde entre cada uno. Ausente/vacío = épica atómica (no superó el umbral). Acota además el tamaño de wiring_checklist[] por paso.",
|
|
142
|
+
"items": {
|
|
143
|
+
"type": "object",
|
|
144
|
+
"additionalProperties": false,
|
|
145
|
+
"required": ["id", "title", "status"],
|
|
146
|
+
"properties": {
|
|
147
|
+
"id": { "type": "string", "description": "Identificador del sub-slice (p.ej. EP-003-a)." },
|
|
148
|
+
"title": { "type": "string" },
|
|
149
|
+
"hus": { "type": "array", "items": { "type": "string", "pattern": "^HU-[0-9]{3}$" }, "description": "Subconjunto de hus[] cubierto por este sub-slice." },
|
|
150
|
+
"status": { "type": "string", "enum": ["pending", "done"], "description": "done SOLO con su journey_smoke verde." },
|
|
151
|
+
"journey_smoke": { "type": "boolean", "description": "El backbone-hasta-este-sub-slice camina end-to-end." }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
92
155
|
}
|
|
93
156
|
},
|
|
94
157
|
"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": []
|