@trycore/spec-build-harness 0.5.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 +18 -1
- package/INSTALL.md +3 -1
- package/METODOLOGIA.md +68 -12
- package/README.md +8 -14
- package/VERSION +1 -1
- package/agents/build/build-orchestrator.md +38 -9
- package/agents/build/dor-dod-gatekeeper.md +26 -10
- package/agents/build/ux-fidelity-reviewer.md +22 -15
- package/agents/build/wiring-adversarial-verifier.md +59 -0
- package/commands/build/onboard.md +18 -0
- package/docs/agents.md +26 -3
- package/docs/customization/mcp-extensions.md +16 -5
- package/docs/getting-started.md +64 -209
- package/hooks/build/load-build-state.sh +17 -1
- package/package.json +1 -1
- package/skills/building-a-slice/SKILL.md +41 -6
- package/skills/building-a-slice/references/dod.md +13 -3
- package/skills/building-a-slice/references/dor.md +6 -3
- package/skills/building-a-slice/references/integration-check.md +27 -0
- package/skills/building-a-slice/references/mcp-map.md +1 -1
- package/skills/building-a-slice/references/state-protocol.md +21 -4
- package/state/README.md +23 -5
- package/state/build-state.schema.json +51 -4
- package/templates/CLAUDE.md.template +6 -2
- package/templates/integration-check.sh.template +65 -0
|
@@ -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
|
|
@@ -57,10 +59,25 @@ Espejo de `scaffold` para la UI: `applies` (¿el proyecto tiene UI?), `confirmed
|
|
|
57
59
|
existe una fuente de diseño declarada), `source` (puntero al prototipo/export). El arnés NO genera el
|
|
58
60
|
prototipo. Lo respalda `design-source-guard.sh`.
|
|
59
61
|
|
|
60
|
-
### gate `fidelity` (por-slice, inner loop)
|
|
62
|
+
### gate `fidelity` (por-slice, inner loop) — ESTRICTO para UI
|
|
61
63
|
|
|
62
|
-
`true` = FIEL (o desviaciones justificadas
|
|
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.
|
|
64
81
|
|
|
65
82
|
### Reflexión post-slice (ciclo autocorrectivo)
|
|
66
83
|
|
|
@@ -78,9 +95,10 @@ El razonamiento vive en el modelo; el hook solo es un recordatorio determinista.
|
|
|
78
95
|
| `active_slice` (alta) · `gates.dor` · `gates.dod` | `dor-dod-gatekeeper` | slice |
|
|
79
96
|
| `gates.coherence_link` | `change-epic-coherence` | slice |
|
|
80
97
|
| `gates.tdd` | flujo `superpowers:test-driven-development` (vía `build-orchestrator`) | slice |
|
|
81
|
-
| `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 |
|
|
82
99
|
| `gates.api` | `api-contract-tester` | slice |
|
|
83
100
|
| `gates.data` | `data-consistency-checker` | slice |
|
|
101
|
+
| `gates.wiring_verified` | `wiring-adversarial-verifier` (independiente, contexto virgen) | slice (antes de `dod`) |
|
|
84
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 |
|
|
85
103
|
| `history[].reflected` · `history[].reflected_at` | `/build:reflect` | post-slice (tras archivar) |
|
|
86
104
|
| `harness_phase` | `load-build-state.sh` (SessionStart) | — |
|
|
@@ -82,15 +82,16 @@
|
|
|
82
82
|
"gates": {
|
|
83
83
|
"type": "object",
|
|
84
84
|
"additionalProperties": false,
|
|
85
|
-
"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.",
|
|
86
86
|
"required": ["dor", "tdd", "dod"],
|
|
87
87
|
"properties": {
|
|
88
88
|
"dor": { "type": "boolean" },
|
|
89
89
|
"tdd": { "type": "boolean" },
|
|
90
|
-
"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)." },
|
|
91
91
|
"coherence_link": { "type": "boolean", "description": "Enlace change↔épica válido (change-epic-coherence, barato, por slice)." },
|
|
92
92
|
"data": { "type": "boolean" },
|
|
93
|
-
"fidelity": { "type": ["boolean", "null"], "description": "Gate VIVO de inner loop (
|
|
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." },
|
|
94
95
|
"api": { "type": ["boolean", "null"], "description": "null = N/A (slice sin endpoints)." },
|
|
95
96
|
"ux": { "type": ["boolean", "null"], "description": "null = N/A (slice sin UI). Legado: hoy se audita en releases[]." },
|
|
96
97
|
"stack": { "type": "boolean", "description": "Legado por-slice; deps las cubre el hook stack-guard.sh, la arquitectura se audita en releases[]." },
|
|
@@ -104,7 +105,53 @@
|
|
|
104
105
|
"updated_by": { "type": "string", "description": "Agente o hook que escribió el estado." },
|
|
105
106
|
"notes": { "type": "string", "description": "Nota libre opcional (p.ej. changes/branches adicionales de una épica construida en varios pasos)." },
|
|
106
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." },
|
|
107
|
-
"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
|
+
}
|
|
108
155
|
}
|
|
109
156
|
},
|
|
110
157
|
"release": {
|
|
@@ -7,7 +7,7 @@ Este proyecto usa el arnés `@trycore/spec-build-harness` para **construir** sob
|
|
|
7
7
|
(compañero de `@trycore/spec-product-flow`: Discovery → Construcción). Modelo de **dos loops**:
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
Inner loop (por épica EP-XXX): DoR → OpenSpec change → TDD → journey-smoke → api/data → DoD → PR + archive
|
|
10
|
+
Inner loop (por épica EP-XXX): DoR → OpenSpec change → TDD → journey-smoke → api/data → verificación adversarial → DoD → PR + archive
|
|
11
11
|
Outer loop (por release): Release Gate (seguridad · diseño · UX · coherencia triple · arquitectura · integración)
|
|
12
12
|
```
|
|
13
13
|
|
|
@@ -30,7 +30,11 @@ Outer loop (por release): Release Gate (seguridad · diseño · UX · cohe
|
|
|
30
30
|
2. El enlace change↔épica va en el bloque `## Trazabilidad` del `proposal.md`, **nunca** en frontmatter YAML (rompe `openspec validate`).
|
|
31
31
|
3. Las dependencias se vigilan contra `.claude/config/stack-allowlist.json` (hook `stack-guard.sh`), derivado de la sección de requisitos técnicos del PRD.
|
|
32
32
|
4. Las revisiones pesadas (seguridad/diseño/UX/coherencia triple/arquitectura/integración) corren **una vez por release** (outer loop), no por épica.
|
|
33
|
-
5.
|
|
33
|
+
5. **Producto completo, no MVP.** El alcance acordado se construye **entero**. **Recortar o diferir es bloqueante explícito** que requiere acuerdo del equipo — **nunca** una decisión del modelo. No se "deja para después" ni se deriva en lo complejo. La verificación es **ejecutada, no por inspección** (correr la suite, cargar la página, leer la consola).
|
|
34
|
+
6. **Cierre verificado, no declarado.** `dod` exige el gate `wiring_verified`: un subagente **adversarial independiente** (`wiring-adversarial-verifier`, contexto virgen) intenta refutar el slice (stubs, rutas sin cablear, AC sin test) antes de cerrar. El estado del cableado vive en disco (`wiring_checklist[]` + `progress_log[]`) para que una sesión fresca retome sin "creer que ya está".
|
|
35
|
+
7. **Fidelidad por verificación visual real.** Para slices con UI, el gate `fidelity` solo cierra observando la salida real vía MCP de devtools de navegador (screenshot app vs prototipo); sin verificación visual queda `false` (no "INCONCLUSO pasa").
|
|
36
|
+
8. **Cimiento antes que negocio y unidades pequeñas.** Las épicas de cimiento (auth, datos, arquitectura base, design-system) se construyen antes que las de negocio; una épica grande (>3 HU ó ≥3 capas) se descompone en sub-slices construidos de a uno.
|
|
37
|
+
9. Si una regla del arnés contradice la metodología Trycore (`METODOLOGIA.md`), **gana la metodología**.
|
|
34
38
|
|
|
35
39
|
### Bloque de dominio (lo resuelve `/build:onboard`)
|
|
36
40
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# integration-check.sh — runner determinista FUERA DE CHAT para cerrar `journey_smoke` (inner loop).
|
|
3
|
+
#
|
|
4
|
+
# Qué es: un gate determinista que ejecuta build + suite completa + un journey-smoke end-to-end y
|
|
5
|
+
# emite un REPORTE de integración a disco, con salida 0 (verde) / ≠0 (rojo). Está pensado para correr
|
|
6
|
+
# en una **sesión/contexto virgen** distinta de la que escribió el código (el agente que cableó no es
|
|
7
|
+
# juez de su propio cableado), y para el **fix-loop** (lo corres, lees el reporte, arreglas, repites).
|
|
8
|
+
#
|
|
9
|
+
# Por qué un script y no un agente: el cableado end-to-end no se acredita "por inspección" sino
|
|
10
|
+
# EJECUTANDO. Mantenerlo fuera del chat lo hace reproducible y barato en contexto.
|
|
11
|
+
#
|
|
12
|
+
# AGNÓSTICO: este es un TEMPLATE. El arnés no asume tu stack. Ajusta los comandos marcados con
|
|
13
|
+
# «# ADAPTA» a tu proyecto (lenguaje, package manager, comando de e2e). Cópialo a tu repo
|
|
14
|
+
# (p.ej. tools/loop/integration-check.sh) y hazlo ejecutable.
|
|
15
|
+
#
|
|
16
|
+
# NO crea ningún gate nuevo en build-state.json: alimenta el gate EXISTENTE `journey_smoke` del slice.
|
|
17
|
+
# El gate `integration` con dependencias reales sigue siendo del Release Gate (outer loop), no de aquí.
|
|
18
|
+
set -uo pipefail
|
|
19
|
+
|
|
20
|
+
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "${CLAUDE_PROJECT_DIR:-$(pwd)}")"
|
|
21
|
+
REPORT_DIR="$ROOT/.claude/state"
|
|
22
|
+
REPORT="$REPORT_DIR/integration-report.txt"
|
|
23
|
+
mkdir -p "$REPORT_DIR"
|
|
24
|
+
|
|
25
|
+
# Detecta el package manager si hay package.json (Node). ADAPTA para otros stacks.
|
|
26
|
+
PM="npm"
|
|
27
|
+
if [ -f "$ROOT/pnpm-lock.yaml" ]; then PM="pnpm";
|
|
28
|
+
elif [ -f "$ROOT/yarn.lock" ]; then PM="yarn"; fi
|
|
29
|
+
|
|
30
|
+
fail=0
|
|
31
|
+
log() { printf '%s\n' "$*" | tee -a "$REPORT"; }
|
|
32
|
+
|
|
33
|
+
: > "$REPORT"
|
|
34
|
+
log "== integration-check =="
|
|
35
|
+
log "root: $ROOT"
|
|
36
|
+
log "pm: $PM"
|
|
37
|
+
log "ts: (sin timestamp determinista; lo estampa quien invoca)"
|
|
38
|
+
log ""
|
|
39
|
+
|
|
40
|
+
run() { # run <etiqueta> <comando...>
|
|
41
|
+
local label="$1"; shift
|
|
42
|
+
log "▶ $label: $*"
|
|
43
|
+
if "$@" >>"$REPORT" 2>&1; then
|
|
44
|
+
log " ✓ $label OK"
|
|
45
|
+
else
|
|
46
|
+
log " ✗ $label FALLÓ"
|
|
47
|
+
fail=1
|
|
48
|
+
fi
|
|
49
|
+
log ""
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# --- Fases del runner (ADAPTA los comandos a tu stack) ---
|
|
53
|
+
# 1) Build: el proyecto compila/construye sin error.
|
|
54
|
+
run "build" $PM run build # ADAPTA (p.ej. cargo build, ./gradlew build, make)
|
|
55
|
+
# 2) Suite completa: todos los tests, no un subconjunto.
|
|
56
|
+
run "tests" $PM test # ADAPTA (p.ej. pytest, go test ./..., cargo test)
|
|
57
|
+
# 3) Journey-smoke end-to-end: recorre el backbone-hasta-aquí. ADAPTA al e2e de tu proyecto.
|
|
58
|
+
# Si tu e2e necesita la app levantada, levántala aquí (y bájala al salir).
|
|
59
|
+
# run "e2e" $PM run test:e2e # ADAPTA / descomenta
|
|
60
|
+
|
|
61
|
+
log "== resultado: $([ "$fail" -eq 0 ] && echo VERDE || echo ROJO) =="
|
|
62
|
+
log "Reporte: $REPORT"
|
|
63
|
+
|
|
64
|
+
# Salida determinista: 0 verde, 1 rojo. El gate journey_smoke solo se marca true con salida 0.
|
|
65
|
+
exit "$fail"
|