@trycore/spec-build-harness 0.8.0 → 0.8.1
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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "trycore-spec-build-harness",
|
|
4
4
|
"displayName": "Trycore — Spec & Build Harness",
|
|
5
|
-
"version": "0.8.
|
|
5
|
+
"version": "0.8.1",
|
|
6
6
|
"description": "Arnés de construcción de dos loops (slice por épica + release gate) para Claude Code, con gates de calidad, estado compartido y OpenSpec. Compañero de @trycore/spec-product-flow. Agnóstico al proyecto.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Trycore",
|
package/README.md
CHANGED
|
@@ -180,7 +180,8 @@ El core no menciona ningún dominio de cliente. Toda parametrización entra por
|
|
|
180
180
|
- ✅ **v0.5.0** — seguro de fuente de diseño (`design_source` + `design-source-guard.sh`) + agente `ux-fidelity-reviewer` (gate `fidelity`, inner loop). Total: **11 agentes**, **9 hooks**.
|
|
181
181
|
- ✅ **v0.6.0** — **calidad de cierre contra horizonte largo** (feedback exodocs): handoff fino en disco (`wiring_checklist[]` + `progress_log[]` + `sub_slices[]`), gate `wiring_verified` por nuevo agente **`wiring-adversarial-verifier`** (verificación adversarial independiente, contexto virgen), cimiento pre-construido + tag `layer` y gate de tamaño en el DoR, runner fuera-de-chat `integration-check`, y **fidelidad estricta por verificación visual real** (MCP requerido para UI). Convenciones anti-deriva (producto completo, no MVP) upstreadas al bloque del arnés. Total: **12 agentes**, **9 hooks**.
|
|
182
182
|
- ✅ **v0.7.0** — **orquestación con workflows dinámicos + hardening** (de una evaluación adversarial del propio arnés): **3 plantillas `*.workflow.js`** opt-in y read-only (`explore-fanout`, `wiring-verify`, `release-gate`) que entran **solo donde aportan valor** y nunca en el camino caliente del inner loop; **3 comandos nuevos** `/build:slice` (entrada del inner loop), `/build:release` (outer loop) y `/build:work` (router *classify-and-act*); hook **`release-gate-nudge.sh`** (Stop, determinista: solo sugiere el Release Gate). Rename de los gates de los 5 reviewers pesados → `releases[].gates.{security,smell,ux,coherence,stack_arch}` (`stack`→`stack_arch`; separación `coherence` (release) / `coherence_link` (inner)). Hardening: degradación segura en 8 agentes, escritura atómica del estado, cierre del bypass de specs no-semver, `wiring` exige evidencia ejecutada y `check-agnostic` barre `*.js`. Total: **12 agentes**, **10 hooks**, **5 comandos `/build:*`**.
|
|
183
|
-
- ✅ **v0.8.0
|
|
183
|
+
- ✅ **v0.8.0** — **motor de contexto + estado anclado a disco + front paralelo inter-épica**: hooks **`statusline-bridge.sh`** (canal CLI) + **`context-monitor.sh`** (umbrales `context.warning_pct`/`context.critical_pct` configurables, 35%/25% por defecto) con **auto-handoff** a `session_continuity` en critical/`PreCompact` y comando **`/build:resume`** para rehidratar desde disco; config **`context.auto_checkpoint`** (opt-in). Reconciliador **`reconcile-build-state.py`** (`SessionStart`): deriva de git + evidencia de tests, degrada `wiring_checklist` sin evidencia, anota *branch drift*, ratchet de gates, fail-open. **Front paralelo** (`parallel_front` en el estado): comando **`/build:front`** + skill **`managing-parallel-front`** + `scripts/lib/front-plan.py` (disjunción por `files_scope`, foundational-first). Schema nuevo: `slice.layer`, `slice.files_scope`, `slice.branch_drift`, `slice.session_continuity`. **Caveat:** `statusLine` es solo canal CLI; en plugin-only el motor de contexto degrada fail-open. Total: **12 agentes**, **13 hooks**, **7 comandos `/build:*`**, **14 skills**.
|
|
184
|
+
- ✅ **v0.8.1 (actual)** — **hotfix del motor de contexto**: `context-monitor.sh` re-inyectaba `additionalContext` en cada evento `Stop`, lo que re-lanzaba el turno en bucle hasta el tope `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` (9→override). Ahora en `Stop` re-lanza como mucho una vez por sesión (solo la transición a crítico que graba el handoff) y `warning` nunca inyecta en `Stop`. Cubierto por `test-context-monitor.sh`.
|
|
184
185
|
|
|
185
186
|
## Licencia
|
|
186
187
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.8.
|
|
1
|
+
0.8.1
|
|
@@ -70,5 +70,11 @@ else:
|
|
|
70
70
|
" Avisa al usuario para reiniciar en un punto natural.")
|
|
71
71
|
msg=(f"🛑 Contexto CRÍTICO al {rem}% restante.{tail} El estado ya vive en build-state.json;"
|
|
72
72
|
f" no reescribas handoff manual.{cont}")
|
|
73
|
+
# En 'Stop', inyectar additionalContext RE-LANZA el turno (re-prompt): repetirlo en cada
|
|
74
|
+
# intento de cierre entra en bucle hasta el tope CLAUDE_CODE_STOP_HOOK_BLOCK_CAP (=9→override).
|
|
75
|
+
# Por eso en 'Stop' re-lanzamos como MUCHO una vez por sesión y solo en la TRANSICIÓN a crítico
|
|
76
|
+
# (recorded=True, el instante en que se graba el handoff). 'warning' nunca inyecta en 'Stop'
|
|
77
|
+
# (el nudge solo sirve mientras se trabaja). Fuera de 'Stop' se inyecta con normalidad.
|
|
78
|
+
if evt=="Stop" and not (sev=="critical" and recorded): sys.exit(0)
|
|
73
79
|
print(json.dumps({"hookSpecificOutput":{"hookEventName":evt,"additionalContext":msg}}))
|
|
74
80
|
PY
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trycore/spec-build-harness",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
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": {
|
|
@@ -31,6 +31,42 @@ echo "$out" | grep -q 'additionalContext' && echo "OK monitor inyecta aviso" ||
|
|
|
31
31
|
sc="$(python3 -c "import json;print(json.load(open('$TMP/proj/.claude/state/build-state.json'))['active_slice'].get('session_continuity',{}).get('critical_recorded'))" 2>/dev/null)"
|
|
32
32
|
[ "$sc" = True ] && echo "OK monitor handoff" || { echo "FAIL monitor handoff ($sc)"; fail=1; }
|
|
33
33
|
|
|
34
|
+
# ── Stop: no debe re-lanzar el turno en bucle (regresión CLAUDE_CODE_STOP_HOOK_BLOCK_CAP) ──
|
|
35
|
+
# En 'Stop' inyectar additionalContext = re-prompt (bloquea el cierre). El warning es solo un
|
|
36
|
+
# nudge mientras se trabaja → en 'Stop' NO debe inyectar (si no, bucle hasta el tope de 9).
|
|
37
|
+
sidW="sessW"; echo "{\"remaining_pct\":30,\"used_pct\":70,\"ts\":$(date +%s)}" > "$TMP/claude-ctx-$sidW.json"
|
|
38
|
+
PW="$TMP/proj-warn-stop"; mkdir -p "$PW/.claude/state" "$PW/.claude/config"
|
|
39
|
+
cp "$TMP/proj/.claude/state/build-state.json" "$PW/.claude/state/build-state.json"
|
|
40
|
+
echo '{"context":{"critical_pct":25,"warning_pct":35,"auto_checkpoint":false}}' > "$PW/.claude/config/build-config.json"
|
|
41
|
+
outW="$(echo "{\"session_id\":\"$sidW\",\"hook_event_name\":\"Stop\"}" \
|
|
42
|
+
| CLAUDE_PROJECT_DIR="$PW" bash "$ROOT/hooks/build/context-monitor.sh")"
|
|
43
|
+
echo "$outW" | grep -q 'additionalContext' \
|
|
44
|
+
&& { echo "FAIL warning+Stop inyecta (re-prompt → bucle)"; fail=1; } \
|
|
45
|
+
|| echo "OK warning+Stop no inyecta"
|
|
46
|
+
# warning en PostToolUse (trabajando) SÍ debe seguir avisando (regresión: no romper el nudge útil).
|
|
47
|
+
outWP="$(echo "{\"session_id\":\"$sidW\",\"hook_event_name\":\"PostToolUse\"}" \
|
|
48
|
+
| CLAUDE_PROJECT_DIR="$PW" bash "$ROOT/hooks/build/context-monitor.sh")"
|
|
49
|
+
echo "$outWP" | grep -q 'additionalContext' \
|
|
50
|
+
&& echo "OK warning+PostToolUse sigue avisando" \
|
|
51
|
+
|| { echo "FAIL warning+PostToolUse dejó de avisar"; fail=1; }
|
|
52
|
+
|
|
53
|
+
# critical en 'Stop': inyecta como MUCHO una vez (la transición que graba el handoff), luego calla.
|
|
54
|
+
sidC="sessC"; echo "{\"remaining_pct\":20,\"used_pct\":80,\"ts\":$(date +%s)}" > "$TMP/claude-ctx-$sidC.json"
|
|
55
|
+
PC="$TMP/proj-crit-stop"; mkdir -p "$PC/.claude/state" "$PC/.claude/config"
|
|
56
|
+
cp "$TMP/proj/.claude/state/build-state.json" "$PC/.claude/state/build-state.json"
|
|
57
|
+
python3 -c "import json;p='$PC/.claude/state/build-state.json';d=json.load(open(p));d['active_slice'].pop('session_continuity',None);json.dump(d,open(p,'w'))"
|
|
58
|
+
echo '{"context":{"critical_pct":25,"warning_pct":35,"auto_checkpoint":false}}' > "$PC/.claude/config/build-config.json"
|
|
59
|
+
outC1="$(echo "{\"session_id\":\"$sidC\",\"hook_event_name\":\"Stop\"}" \
|
|
60
|
+
| CLAUDE_PROJECT_DIR="$PC" bash "$ROOT/hooks/build/context-monitor.sh")"
|
|
61
|
+
echo "$outC1" | grep -q 'additionalContext' \
|
|
62
|
+
&& echo "OK critical+Stop inyecta la transición (1ª vez)" \
|
|
63
|
+
|| { echo "FAIL critical+Stop no inyecta la transición"; fail=1; }
|
|
64
|
+
outC2="$(echo "{\"session_id\":\"$sidC\",\"hook_event_name\":\"Stop\"}" \
|
|
65
|
+
| CLAUDE_PROJECT_DIR="$PC" bash "$ROOT/hooks/build/context-monitor.sh")"
|
|
66
|
+
echo "$outC2" | grep -q 'additionalContext' \
|
|
67
|
+
&& { echo "FAIL critical+Stop re-inyecta (bucle)"; fail=1; } \
|
|
68
|
+
|| echo "OK critical+Stop NO re-inyecta (bucle roto)"
|
|
69
|
+
|
|
34
70
|
# load-build-state (SessionStart): reset once-per-SESSION del guard critical_recorded.
|
|
35
71
|
# Sesión NUEVA (last_session distinto del session_id del payload) -> reabre el guard y
|
|
36
72
|
# persiste el session_id actual.
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Cómo trabaja el arnés — flujo funcional
|
|
2
|
-
|
|
3
|
-
Vista única y sencilla del flujo de trabajo, para explicar a los devs **qué pasa con cada cambio**.
|
|
4
|
-
(Versión detallada/técnica en [flujo-harness.md](./flujo-harness.md).)
|
|
5
|
-
|
|
6
|
-
```mermaid
|
|
7
|
-
flowchart TD
|
|
8
|
-
A([Llega un trabajo]) --> B{"¿Qué tipo de cambio es?"}
|
|
9
|
-
|
|
10
|
-
B -->|"Arreglo pequeño<br/>(typo, copy, config)"| C["Carril rápido:<br/>rama → cambio → PR"]
|
|
11
|
-
C --> Z([PR listo para mergear])
|
|
12
|
-
|
|
13
|
-
B -->|"Funcionalidad nueva<br/>(una épica)"| D{"¿Está lista para construir?<br/>historias claras, criterios definidos,<br/>base ya construida"}
|
|
14
|
-
D -->|"No"| E["Vuelve a discovery<br/>a completar la historia"]
|
|
15
|
-
D -->|"Sí"| F["Construir con pruebas<br/>(escribo el test, luego el código)"]
|
|
16
|
-
|
|
17
|
-
F --> G{"¿La app funciona<br/>de punta a punta?"}
|
|
18
|
-
G -->|"No"| F
|
|
19
|
-
G -->|"Sí"| H["Revisión final del cambio<br/>+ pantallas iguales al diseño (si hay UI)"]
|
|
20
|
-
|
|
21
|
-
H --> I["Abrir PR y dejar todo enlazado<br/>(historia ↔ cambio ↔ código)"]
|
|
22
|
-
I --> J{"¿Esta épica cierra<br/>una entrega/release?"}
|
|
23
|
-
|
|
24
|
-
J -->|"No, sigue otra épica"| A
|
|
25
|
-
J -->|"Sí"| K["Revisión profunda de la entrega:<br/>seguridad · calidad · UX ·<br/>coherencia · arquitectura"]
|
|
26
|
-
|
|
27
|
-
K --> L{"¿Todo el journey completo<br/>funciona con dependencias reales?"}
|
|
28
|
-
L -->|"No, hay hallazgos"| M["Corregir como un cambio normal"]
|
|
29
|
-
M --> K
|
|
30
|
-
L -->|"Sí"| N([Release lista ✅])
|
|
31
|
-
|
|
32
|
-
classDef q fill:#fff3cd,stroke:#d39e00,color:#000;
|
|
33
|
-
classDef ok fill:#d4edda,stroke:#155724,color:#000;
|
|
34
|
-
class B,D,G,J,L q;
|
|
35
|
-
class N,Z ok;
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## La idea en una frase
|
|
39
|
-
|
|
40
|
-
- **Cambios chicos** van por un carril rápido.
|
|
41
|
-
- **Cada funcionalidad nueva** se construye completa, con pruebas, verificando que la app **funcione de punta a punta** antes de cerrarla.
|
|
42
|
-
- **De vez en cuando** (al cerrar una entrega) se hace una **revisión profunda** de todo lo acumulado antes de liberar.
|
package/docs/flujo-harness.md
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
# Flujo del arnés de construcción — `@trycore/spec-build-harness`
|
|
2
|
-
|
|
3
|
-
Diagrama de flujo end-to-end del harness, modelado al estilo BPMN:
|
|
4
|
-
|
|
5
|
-
- **◆ XOR** (rombo) = compuerta **exclusiva** (un solo camino).
|
|
6
|
-
- **⬡ AND** (hexágono) = compuerta **paralela** (fork: todos los caminos; join: convergencia/barrera).
|
|
7
|
-
- **▭ Tarea** con su **gate** entre `[ ]`.
|
|
8
|
-
- Aristas punteadas `-.->` = retroceso (gate monótono que vuelve a `false`).
|
|
9
|
-
|
|
10
|
-
Fuente de verdad: [METODOLOGIA.md](../METODOLOGIA.md). Si algo contradice ese documento, gana la metodología.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## 1. Vista global (router → inner loop → outer loop)
|
|
15
|
-
|
|
16
|
-
```mermaid
|
|
17
|
-
flowchart TD
|
|
18
|
-
START([Trabajo entrante]) --> PRE{{"⬡ Preflight<br/>¿instalado?"}}
|
|
19
|
-
PRE -->|NOT_INSTALLED| INIT[trycore-build init] --> ROUTER
|
|
20
|
-
PRE -->|ok| ROUTER
|
|
21
|
-
|
|
22
|
-
ROUTER[/"/build:work — Router (classify-and-act)<br/>solo ruteo: no toca estado ni ramas"/]
|
|
23
|
-
ROUTER --> GW1{"◆ XOR — Decision gate<br/>¿qué carril?"}
|
|
24
|
-
|
|
25
|
-
%% --- Rama 1: micro-change ---
|
|
26
|
-
GW1 -->|"mantenimiento<br/>sin capacidad nueva"| HARD{"◆ XOR — ¿cruza límite duro?<br/>dep nueva / API nueva / dominio·datos"}
|
|
27
|
-
HARD -->|"sí → escala"| INNER
|
|
28
|
-
HARD -->|no| MICRO["building-a-micro-change<br/>fix/* | chore/* → cambio → PR<br/>(sin abrir active_slice)"]
|
|
29
|
-
MICRO --> ENDM([PR mergeado])
|
|
30
|
-
|
|
31
|
-
%% --- Rama 2: épica / producto nuevo ---
|
|
32
|
-
GW1 -->|"capacidad nueva<br/>o límite duro"| INNER[["INNER LOOP<br/>building-a-slice<br/>(ver §2)"]]
|
|
33
|
-
|
|
34
|
-
%% --- Rama 3: release gate ---
|
|
35
|
-
GW1 -->|"cierra línea de release<br/>o ≥2 épicas archivadas"| OUTER[["OUTER LOOP<br/>releasing-a-version<br/>(ver §3)"]]
|
|
36
|
-
|
|
37
|
-
INNER --> DEC{"◆ XOR — fase 8<br/>¿correr Release Gate ahora?<br/>(default computado, decide humano)"}
|
|
38
|
-
DEC -->|"sí (cierra release<br/>o nudge ≥2)"| OUTER
|
|
39
|
-
DEC -->|no| NEXT([Siguiente épica]) -.-> INNER
|
|
40
|
-
|
|
41
|
-
OUTER --> OUTGW{"◆ XOR — ¿todos los gates ✓?"}
|
|
42
|
-
OUTGW -->|"passed"| REL([Release lista])
|
|
43
|
-
OUTGW -->|"failed (hallazgos)"| FIX["Fix como slice normal<br/>(building-a-slice)"] -.->|re-corre| OUTER
|
|
44
|
-
|
|
45
|
-
classDef xor fill:#fff3cd,stroke:#d39e00,color:#000;
|
|
46
|
-
classDef andg fill:#d1ecf1,stroke:#0c5460,color:#000;
|
|
47
|
-
classDef loop fill:#e2e3f3,stroke:#383d6b,color:#000;
|
|
48
|
-
class GW1,HARD,DEC,OUTGW xor;
|
|
49
|
-
class PRE andg;
|
|
50
|
-
class INNER,OUTER loop;
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## 2. Inner loop — `building-a-slice` (pipeline secuencial por épica)
|
|
56
|
-
|
|
57
|
-
Precondición dura: **scaffold confirmado** (`scaffold.confirmed`) antes de abrir cualquier slice.
|
|
58
|
-
Secuencial (un `active_slice` a la vez), divulgación progresiva, ningún gate se salta.
|
|
59
|
-
|
|
60
|
-
```mermaid
|
|
61
|
-
flowchart TD
|
|
62
|
-
S0([Épica EP-XXX entrante]) --> SCAF{"◆ XOR — gate proyecto<br/>scaffold.confirmed?"}
|
|
63
|
-
SCAF -->|"false"| STOPS["STOP — exige scaffold runnable<br/>(scaffold-guard.sh)"]
|
|
64
|
-
SCAF -->|"true"| F1
|
|
65
|
-
|
|
66
|
-
%% Fase 1: DoR
|
|
67
|
-
F1["F1 · dor — Definition of Ready<br/>delega: dor-dod-gatekeeper"]
|
|
68
|
-
F1 --> DORGW{"◆ XOR — ¿DoR ✓?<br/>épica+HU, AC G/W/T, INVEST,<br/>cimiento, tamaño, stack, fixtures"}
|
|
69
|
-
DORGW -->|"✗"| BACKDISC["Vuelve a discovery<br/>(/trycore:*) — no se abre slice"]
|
|
70
|
-
DORGW -->|"✓ [gate: dor]"| SIZE{"◆ XOR — gate tamaño<br/>>3 HU ó ≥3 capas?"}
|
|
71
|
-
|
|
72
|
-
SIZE -->|"sí"| SUB["Descompone en sub_slices[]<br/>se construyen de a uno<br/>(journey_smoke verde entre cada uno)"]
|
|
73
|
-
SIZE -->|"no (atómica)"| F2
|
|
74
|
-
SUB --> F2
|
|
75
|
-
|
|
76
|
-
%% Fase 2: change
|
|
77
|
-
F2["F2 · change — opsx:new + ## Trazabilidad<br/>delega: change-epic-coherence"]
|
|
78
|
-
F2 --> F2GW{"◆ XOR — ¿enlace change↔épica ✓?"}
|
|
79
|
-
F2GW -->|"✓ [gate: coherence_link]"| F3
|
|
80
|
-
F2GW -.->|"✗ retroceso"| F2
|
|
81
|
-
|
|
82
|
-
%% Fase 3: TDD
|
|
83
|
-
F3["F3 · red→green→refactor<br/>TDD por cada escenario AC de cada HU<br/>delega: superpowers:test-driven-development"]
|
|
84
|
-
F3 --> F3GW{"◆ XOR — ¿suite verde?"}
|
|
85
|
-
F3GW -.->|"✗ retroceso"| F3
|
|
86
|
-
F3GW -->|"✓ [gate: tdd]"| F4
|
|
87
|
-
|
|
88
|
-
%% Fase 4: smoke + fidelity (UI)
|
|
89
|
-
F4["F4 · smoke — journey-hasta-aquí end-to-end<br/>runner determinista fuera-de-chat (sesión virgen)"]
|
|
90
|
-
F4 --> UIGW{"◆ XOR — ¿la épica toca UI?"}
|
|
91
|
-
UIGW -->|"no"| F4OUT["fidelity = null"]
|
|
92
|
-
UIGW -->|"sí"| FID["Verificación visual real (MCP chrome-devtools)<br/>screenshot app vs prototipo<br/>delega: ux-fidelity-reviewer"]
|
|
93
|
-
FID --> FIDGW{"◆ XOR — ¿fidelidad ESTRICTA ✓?<br/>INCONCLUSO = false"}
|
|
94
|
-
FIDGW -.->|"✗ → false"| FID
|
|
95
|
-
FIDGW -->|"✓ [gate: fidelity]"| F4OUT
|
|
96
|
-
F4OUT -->|"[gate: journey_smoke]"| F5FORK
|
|
97
|
-
|
|
98
|
-
%% Fase 5: api / data en paralelo (condicional/null)
|
|
99
|
-
F5FORK{{"⬡ AND — fork (fase api/data)"}}
|
|
100
|
-
F5FORK --> APIB["api — contratos endpoints<br/>Newman 100% (delega: api-contract-tester)<br/>null si no hay endpoints"]
|
|
101
|
-
F5FORK --> DATAB["data — invariantes de datos<br/>(delega: data-consistency-checker)<br/>N/A si no toca datos"]
|
|
102
|
-
APIB --> F5JOIN
|
|
103
|
-
DATAB --> F5JOIN
|
|
104
|
-
F5JOIN{{"⬡ AND — join (convergencia)<br/>[gates: api, data]"}}
|
|
105
|
-
|
|
106
|
-
%% Fase 6: dod — adversarial THEN dod
|
|
107
|
-
F5JOIN --> WIRE["F6a · Verificación ADVERSARIAL independiente<br/>(subagente contexto virgen)<br/>asume slice incompleto e intenta refutarlo<br/>delega: wiring-adversarial-verifier"]
|
|
108
|
-
WIRE --> WIREGW{"◆ XOR — ¿wiring_checklist[] sin items failing?"}
|
|
109
|
-
WIREGW -.->|"✗ huecos (stub/ruta/AC sin test)"| F3
|
|
110
|
-
WIREGW -->|"✓ [gate: wiring_verified]"| DOD["F6b · DoD reducido<br/>delega: dor-dod-gatekeeper<br/>(piso declarativo, no el arreglo)"]
|
|
111
|
-
DOD --> DODGW{"◆ XOR — ¿DoD ✓?<br/>tdd·journey_smoke·coherence_link·<br/>data·api·fidelity·wiring_verified·hooks"}
|
|
112
|
-
DODGW -.->|"✗ retroceso"| F3
|
|
113
|
-
DODGW -->|"✓ [gate: dod]"| F7
|
|
114
|
-
|
|
115
|
-
%% Fase 7: PR + archive
|
|
116
|
-
F7["F7 · pr — abrir PR + archivar change EN EL MISMO PR<br/>opsx:archive + opsx:sync<br/>back-reference en épica y HU"]
|
|
117
|
-
F7 --> ARCH["active_slice → history[] (phase: archived)<br/>active_slice = null"]
|
|
118
|
-
ARCH --> F8([F8 · decisión Release Gate → §1])
|
|
119
|
-
|
|
120
|
-
classDef xor fill:#fff3cd,stroke:#d39e00,color:#000;
|
|
121
|
-
classDef andg fill:#d1ecf1,stroke:#0c5460,color:#000;
|
|
122
|
-
classDef stop fill:#f8d7da,stroke:#842029,color:#000;
|
|
123
|
-
class SCAF,DORGW,SIZE,F2GW,F3GW,UIGW,FIDGW,WIREGW,DODGW xor;
|
|
124
|
-
class F5FORK,F5JOIN andg;
|
|
125
|
-
class STOPS,BACKDISC stop;
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
> **Disciplina de horizonte largo:** cada iteración nace headless / contexto virgen y reconstruye estado
|
|
129
|
-
> desde disco (`build-state.json` + git + logs). `wiring_checklist[]` (1 item por escenario AC y por punto
|
|
130
|
-
> de integración entre capas) nace `failing` y solo pasa a `passing` **tras prueba real ejecutada**.
|
|
131
|
-
> Mientras quede un item `failing`, el cableado NO está hecho.
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## 3. Outer loop — `releasing-a-version` (Release Gate)
|
|
136
|
-
|
|
137
|
-
Alcance = **diff acumulado** de todas las épicas de la release (merge anterior → `main`).
|
|
138
|
-
Los reviewers se disparan **en paralelo** y devuelven síntesis (protegen el contexto).
|
|
139
|
-
|
|
140
|
-
```mermaid
|
|
141
|
-
flowchart TD
|
|
142
|
-
R0([Línea de release identificada]) --> R1["Crear/actualizar releases[] (status: pending)<br/>cruzar con docs/02-user-story-map/"]
|
|
143
|
-
R1 --> FORK{{"⬡ AND — fork (reviewers en paralelo<br/>sobre el diff acumulado)"}}
|
|
144
|
-
|
|
145
|
-
FORK --> SEC["security — sin CRÍTICO/ALTO;<br/>claves server-side; PII no cruda;<br/>salida IA = input no confiable<br/>(security-reviewer)"]
|
|
146
|
-
FORK --> SME["smell — 4 reglas de Beck<br/>+ code smells sin bloqueantes<br/>(simple-design-reviewer)"]
|
|
147
|
-
FORK --> UX["ux — Krug + Lighthouse<br/>(null si sin UI)<br/>(ux-krug-reviewer)"]
|
|
148
|
-
FORK --> COH["coherence — trazabilidad triple<br/>AC↔change↔código, sin huérfanos<br/>(coherence-three-way · opus)"]
|
|
149
|
-
FORK --> ARCH["stack_arch — arquitectura PRD:<br/>capa IA en frontera server-side;<br/>decisión determinista sin IA<br/>(stack-guardian)"]
|
|
150
|
-
|
|
151
|
-
SEC --> JOIN
|
|
152
|
-
SME --> JOIN
|
|
153
|
-
UX --> JOIN
|
|
154
|
-
COH --> JOIN
|
|
155
|
-
ARCH --> JOIN
|
|
156
|
-
|
|
157
|
-
JOIN{{"⬡ AND — join (convergencia de reviewers)"}}
|
|
158
|
-
JOIN --> INTEG["integration — journey COMPLETO end-to-end<br/>con DEPENDENCIAS REALES (no stubs)<br/>skill verify/run + MCP chrome-devtools"]
|
|
159
|
-
|
|
160
|
-
INTEG --> RGW{"◆ XOR — ¿todos los gates ✓ (o null N/A)?"}
|
|
161
|
-
RGW -->|"✓"| PASS["status: passed<br/>escribir gates + updated_by: releasing-a-version"]
|
|
162
|
-
RGW -->|"✗ hallazgos bloqueantes"| FAIL["status: failed"]
|
|
163
|
-
PASS --> RELOK([Release ✅])
|
|
164
|
-
FAIL --> FIXLOOP["Humano corrige como slice normal<br/>(building-a-slice)"]
|
|
165
|
-
FIXLOOP -.->|"re-corre Release Gate"| R1
|
|
166
|
-
|
|
167
|
-
classDef xor fill:#fff3cd,stroke:#d39e00,color:#000;
|
|
168
|
-
classDef andg fill:#d1ecf1,stroke:#0c5460,color:#000;
|
|
169
|
-
classDef gate fill:#d4edda,stroke:#155724,color:#000;
|
|
170
|
-
class RGW xor;
|
|
171
|
-
class FORK,JOIN andg;
|
|
172
|
-
class INTEG gate;
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
> **`integration` es el gate no negociable.** Sin journey completo con dependencias reales **no hay release**.
|
|
176
|
-
> No se acepta con todo stubbeado.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## 4. Leyenda de loops y gates
|
|
181
|
-
|
|
182
|
-
| | Inner loop | Outer loop |
|
|
183
|
-
|---|---|---|
|
|
184
|
-
| Skill | `building-a-slice` | `releasing-a-version` |
|
|
185
|
-
| Unidad | una épica `EP-XXX` | una línea de release |
|
|
186
|
-
| Cadencia | muchas (1 por épica) | pocas (1 por release) |
|
|
187
|
-
| Costo | barato (≤ ~20 min/épica) | pesado (subagentes profundos) |
|
|
188
|
-
| Gates | dor · coherence_link · tdd · journey_smoke · fidelity · api · data · wiring_verified · dod | security · smell · ux · coherence · stack_arch · integration |
|
|
189
|
-
| Estado | `active_slice` + `history[]` | `releases[]` |
|
|
190
|
-
|
|
191
|
-
**Regla de no duplicación:** cada gate vive en exactamente un loop. El outer no hace TDD ni gates por slice;
|
|
192
|
-
el inner no dispara reviewers pesados.
|