@trycore/spec-build-harness 0.8.4 → 0.10.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 +43 -5
- package/INSTALL.md +28 -6
- package/METODOLOGIA.md +65 -10
- package/README.md +41 -7
- package/VERSION +1 -1
- package/agents/build/build-orchestrator.md +33 -7
- package/agents/build/dor-dod-gatekeeper.md +17 -6
- package/agents/build/ux-fidelity-reviewer.md +4 -1
- package/agents/build/wiring-adversarial-verifier.md +52 -5
- package/commands/build/architect.md +1 -1
- package/commands/build/claim.md +46 -0
- package/commands/build/escalate.md +36 -0
- package/commands/build/front.md +9 -3
- package/commands/build/onboard.md +63 -14
- package/commands/build/prototype.md +23 -0
- package/commands/build/reflect.md +60 -40
- package/commands/build/release.md +10 -7
- package/commands/build/resume.md +33 -13
- package/commands/build/slice.md +32 -27
- package/commands/build/status.md +35 -0
- package/commands/build/work.md +11 -8
- package/config/build-config.template.json +4 -0
- package/dist/cli.js +22 -0
- package/dist/commands/doctor.js +42 -0
- package/dist/commands/init.js +84 -1
- package/dist/commands/migrate.js +48 -0
- package/dist/commands/status.js +34 -0
- package/dist/lib/normalize.js +276 -0
- package/dist/lib/paths.js +6 -0
- package/dist/lib/runtime-client.js +196 -0
- package/dist/lib/settings-merge.js +3 -3
- package/dist/lib/state-bundle.js +46 -0
- package/docs/commands.md +32 -9
- package/docs/getting-started.md +2 -1
- package/docs/hooks.md +114 -27
- package/docs/runtime/guia-modo-dual-y-migracion.md +136 -0
- package/docs/runtime/plan-migracion-harness-v0.9.md +11 -0
- package/docs/runtime/protocolo-cliente-runtime.md +109 -34
- package/hooks/build/build-gate-check.sh +21 -0
- package/hooks/build/context-monitor.sh +82 -15
- package/hooks/build/context-sync.sh +192 -0
- package/hooks/build/design-source-guard.sh +31 -3
- package/hooks/build/dual-compare.sh +92 -0
- package/hooks/build/event-emitter.sh +75 -0
- package/hooks/build/gitflow-guard.sh +164 -14
- package/hooks/build/heartbeat.sh +259 -0
- package/hooks/build/lib/agent-context.sh +139 -0
- package/hooks/build/lib/config.sh +27 -0
- package/hooks/build/lib/projection.sh +71 -0
- package/hooks/build/lib/runtime-client.sh +465 -0
- package/hooks/build/lib/runtime-ops.sh +221 -0
- package/hooks/build/lib/state-io.sh +5 -18
- package/hooks/build/load-build-state.sh +64 -2
- package/hooks/build/reflect-nudge.sh +15 -0
- package/hooks/build/release-gate-nudge.sh +15 -0
- package/hooks/build/release-ops.sh +164 -0
- package/hooks/build/scaffold-guard.sh +29 -2
- package/hooks/build/session-start.sh +103 -0
- package/hooks/build/session-stop.sh +22 -0
- package/hooks/build/slice-ops.sh +877 -0
- package/hooks/build/stack-guard.sh +8 -0
- package/hooks/build/statusline-bridge.sh +24 -3
- package/hooks/build-harness.json +16 -0
- package/package.json +3 -3
- package/scripts/check-agnostic.sh +3 -1
- package/scripts/check-pack-clean.sh +31 -0
- package/scripts/check-runtime-purity.sh +43 -0
- package/scripts/lib/front-plan.py +4 -0
- package/scripts/lib/graph-bundle.py +133 -0
- package/scripts/runtime-purity-allow.txt +5 -0
- package/scripts/smoke-test.sh +1 -1
- package/scripts/tests/lib/http-stub.py +46 -0
- package/scripts/tests/test-baseline-verdict.sh +92 -0
- package/scripts/tests/test-config.sh +25 -0
- package/scripts/tests/test-hooks-runtime.sh +853 -0
- package/scripts/tests/test-install.sh +57 -0
- package/scripts/tests/test-runtime-client.sh +298 -0
- package/scripts/tests/test-schema.sh +29 -1
- package/scripts/tests/test-skill-ops.sh +847 -0
- package/skills/building-a-micro-change/SKILL.md +22 -4
- package/skills/building-a-slice/SKILL.md +58 -23
- package/skills/building-a-slice/assets/baseline-verdict.sh +172 -0
- package/skills/building-a-slice/references/dod.md +12 -3
- package/skills/building-a-slice/references/dor.md +7 -3
- package/skills/building-a-slice/references/evidence-budget.md +51 -0
- package/skills/building-a-slice/references/exploration-fanout.md +1 -1
- package/skills/building-a-slice/references/gitflow.md +1 -1
- package/skills/building-a-slice/references/regression-baseline.md +67 -0
- package/skills/building-a-slice/references/runtime-protocol.md +75 -0
- package/skills/building-a-slice/references/state-protocol.md +12 -1
- package/skills/building-a-slice/workflows/README.md +7 -3
- package/skills/building-a-slice/workflows/explore-fanout.workflow.js +3 -3
- package/skills/building-a-slice/workflows/wiring-verify.workflow.js +26 -4
- package/skills/managing-parallel-front/SKILL.md +32 -16
- package/skills/openspec-archive-change/SKILL.md +15 -0
- package/skills/prototyping-screens/SKILL.md +104 -0
- package/skills/prototyping-screens/assets/DESIGN.md.template +55 -0
- package/skills/prototyping-screens/assets/manifest.schema.json +70 -0
- package/skills/prototyping-screens/assets/screen.template.html +34 -0
- package/skills/prototyping-screens/references/aesthetic-directions.md +42 -0
- package/skills/prototyping-screens/references/extraction.md +57 -0
- package/skills/prototyping-screens/references/self-check.md +40 -0
- package/skills/releasing-a-version/SKILL.md +25 -16
- package/skills/releasing-a-version/references/release-dod.md +7 -5
- package/skills/releasing-a-version/workflows/README.md +2 -1
- package/skills/releasing-a-version/workflows/release-gate.workflow.js +6 -5
- package/skills/setup-architecture/SKILL.md +4 -2
- package/state/README.md +20 -3
- package/state/build-state.schema.json +3 -2
- package/templates/CLAUDE.md.template +17 -1
- package/templates/settings-hooks.template.json +8 -4
- package/internal/skills/auditar-arnes/SKILL.md +0 -29
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "BUILD: Claim"
|
|
3
|
+
description: Reclama trabajo al Agent Orchestrator Runtime (POST /tasks/next) sincronizando el contexto antes, reportando los hashes locales de los archivos gobernados y continuando desde el checkpoint si lo hay. Adaptador delgado sobre slice-ops.sh claim; en modo legacy o dual el slice lo decide el fichero local.
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [build-harness, runtime, claim, trycore]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /build:claim — Pedir la siguiente tarea al runtime
|
|
9
|
+
|
|
10
|
+
**Entrada (opcional):** `EP-XXX` para pedir una épica concreta. Sin argumento, el runtime elige.
|
|
11
|
+
|
|
12
|
+
## 1. Reclamar
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
bash .claude/hooks/build/slice-ops.sh claim ${1:+--epic "$1"}
|
|
16
|
+
echo "rc=$?"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
El comando ya hace, por ti y en este orden: sincroniza el contexto (no se abre trabajo con
|
|
20
|
+
contexto viejo), reporta los `sha256` locales efectivos de los archivos gobernados (el servidor
|
|
21
|
+
detecta drift), reclama por **POST**, refresca la caché de proyección y rinde el slice.
|
|
22
|
+
|
|
23
|
+
## 2. Ramificar por el código de salida
|
|
24
|
+
|
|
25
|
+
| rc | Qué significa | Qué haces |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| 0 | slice reclamado | si la salida trae **CHECKPOINT**, haz checkout de esa rama y **continúa desde ahí, jamás reinicies**; luego `/build:slice` |
|
|
28
|
+
| 3 | modo `legacy`, o `dual` (el fichero decide) | abre/retoma el slice con el protocolo del fichero (`/build:slice`) |
|
|
29
|
+
| 5 | runtime inalcanzable | **sigue trabajando** con lo local; reintenta al reconectar |
|
|
30
|
+
| 6 | rechazo del servidor (409/401/422) | muestra su razón tal cual; **no reintentes** — token, contexto o proyecto a resolver con el ADMIN |
|
|
31
|
+
| 7 | sin trabajo disponible, o carrera perdida | dilo y termina limpio; ofrece `/build:status` |
|
|
32
|
+
|
|
33
|
+
## 3. Seguir
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bash .claude/hooks/build/slice-ops.sh next-step
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Ejecuta esa acción, o entra al pipeline con `/build:slice`.
|
|
40
|
+
|
|
41
|
+
## Guardrails
|
|
42
|
+
|
|
43
|
+
- **No** armes peticiones al runtime a mano: todo pasa por `slice-ops.sh`.
|
|
44
|
+
- **Un solo slice activo**: reclamar con lease vigente devuelve el mismo slice (idempotente).
|
|
45
|
+
- **Nunca reinicies** un slice que trae checkpoint: es trabajo de otro agente que cayó.
|
|
46
|
+
- Si algo contradice `METODOLOGIA.md`, **gana la metodología**.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "BUILD: Escalate"
|
|
3
|
+
description: Registra un bloqueo del slice en el runtime (evento escalation_raised) y devuelve la decisión al humano — recortar, diferir o desbloquear nunca lo decide el modelo. Adaptador delgado sobre slice-ops.sh escalate.
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [build-harness, runtime, escalada, gobierno, trycore]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /build:escalate — Bloqueo que decide una persona
|
|
9
|
+
|
|
10
|
+
**Entrada:** la razón del bloqueo (una frase concreta y verificable). Opcional: el gate afectado.
|
|
11
|
+
|
|
12
|
+
## 1. Registrar
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
bash .claude/hooks/build/slice-ops.sh escalate "<razón>" --gate <gate opcional>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Deja el rastro tipado en el runtime (ámbito slice si hay slice reclamado; de proyecto si no).
|
|
19
|
+
Para razones largas, escríbelas en un fichero y usa `--file`.
|
|
20
|
+
|
|
21
|
+
## 2. Devolver la decisión al humano
|
|
22
|
+
|
|
23
|
+
Presenta al usuario, en tres líneas: **qué está bloqueado**, **qué evidencia lo demuestra** y
|
|
24
|
+
**las opciones reales** (con su coste). No elijas por él.
|
|
25
|
+
|
|
26
|
+
> **Regla dura del arnés:** *Producto completo, no MVP.* Recortar o diferir alcance es un
|
|
27
|
+
> **bloqueante explícito** que requiere acuerdo del equipo — jamás una decisión del modelo. Escalar
|
|
28
|
+
> no es rendirse: es negarse a degradar el alcance en silencio.
|
|
29
|
+
|
|
30
|
+
## Guardrails
|
|
31
|
+
|
|
32
|
+
- **No** cierres gates «para avanzar» mientras el bloqueo esté vivo.
|
|
33
|
+
- **No** inventes alternativas fuera del alcance acordado.
|
|
34
|
+
- Si el bloqueo es de contexto gobernado (allowlist, política, reglas), la salida es una
|
|
35
|
+
**propuesta** en el hub que publica un ADMIN, no una edición local del fichero sincronizado.
|
|
36
|
+
- Si algo contradice `METODOLOGIA.md`, **gana la metodología**.
|
package/commands/build/front.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "BUILD: Front"
|
|
3
|
-
description:
|
|
3
|
+
description: Prepara y coordina un front paralelo de épicas NO fundacionales y disjuntas en archivos, cada una en su worktree/rama/PR con su propio agente registrado. Delega en la skill managing-parallel-front (selección disjunta local vía scripts/lib/front-plan.py, worktrees, merge en orden con re-smoke reportado por cada worktree). Planificar, abrir, drenar y cerrar el front son actos humanos en la consola.
|
|
4
4
|
category: Workflow
|
|
5
5
|
tags: [build-harness, outer-loop, front-paralelo, trycore]
|
|
6
6
|
---
|
|
@@ -8,8 +8,14 @@ tags: [build-harness, outer-loop, front-paralelo, trycore]
|
|
|
8
8
|
# /build:front — Front paralelo inter-épica
|
|
9
9
|
|
|
10
10
|
Delega en la skill **managing-parallel-front**. Resumen:
|
|
11
|
-
1. Verifica precondiciones (scaffold confirmado; sin épica foundational abierta)
|
|
11
|
+
1. Verifica precondiciones (scaffold confirmado; sin épica foundational abierta) con
|
|
12
|
+
`bash .claude/hooks/build/slice-ops.sh status`.
|
|
12
13
|
2. Reúne candidatas no fundacionales listas (DoR pasado) con `layer` y `files_scope`.
|
|
13
|
-
3.
|
|
14
|
+
3. Propón el conjunto disjunto y el `merge_order` (`scripts/lib/front-plan.py`, local) y
|
|
15
|
+
**preséntaselo a una persona**: abrir el front es acto de gobierno, en la consola del hub.
|
|
16
|
+
4. Un worktree por épica aprobada, cada uno registrado como **agente propio**
|
|
17
|
+
(`trycore-build init` con el mismo token de proyecto); construye con `/build:slice`.
|
|
18
|
+
5. Tras cada merge, re-smoke y reporte desde el worktree:
|
|
19
|
+
`bash .claude/hooks/build/release-ops.sh front-integration <front_id> --merge-status … --resmoke …`.
|
|
14
20
|
|
|
15
21
|
Úsalo solo cuando haya ≥2 épicas no fundacionales disjuntas listas. Para una sola épica, usa `/build:slice`.
|
|
@@ -66,20 +66,23 @@ Voy a leer tu PRD/openspec para proponer valores y confirmar contigo:
|
|
|
66
66
|
- **Decisiones de alto impacto** (`HIGH_STAKES_DECISIONS`): decisiones que exigen explicabilidad/justificación en la UI.
|
|
67
67
|
- **Fuente de diseño** (`DESIGN_SOURCE`): ¿el producto tiene UI? Si sí, ruta/URL de la fuente
|
|
68
68
|
visual de verdad (prototipo, export de diseño o mockups) y cómo localizar cada pantalla; si no,
|
|
69
|
-
"N/A".
|
|
69
|
+
"N/A". Si hay UI pero **no existe** fuente aún, indica que `/build:prototype` puede generarla
|
|
70
|
+
tras el onboarding (prototipo HTML de referencia en `docs/05-prototipo/`; la confirmación
|
|
71
|
+
sigue siendo humana). (El reporte del hecho `design_source` se hace en la Fase 3c.)
|
|
70
72
|
3. Si un punto no aplica al proyecto, registra explícitamente "no aplica" (no lo dejes como `{{...}}`).
|
|
71
73
|
|
|
72
74
|
---
|
|
73
75
|
|
|
74
76
|
## Fase 2b: Clasificar la capa de las épicas (cimiento vs negocio)
|
|
75
77
|
|
|
76
|
-
**Primero, resuelve `project_kind`** (
|
|
78
|
+
**Primero, resuelve `project_kind`** (léelo de `bash .claude/hooks/build/slice-ops.sh status`):
|
|
77
79
|
- `"brownfield"` → el mecanismo del caparazón es **N/A**: no preguntes ni exijas nada de la
|
|
78
80
|
Fase 2c; clasifica capas como siempre y sigue.
|
|
79
81
|
- `null` / ausente (detección ambigua del CLI) → pregunta **una sola vez** vía AskUserQuestion:
|
|
80
82
|
*"¿Este proyecto es una app nueva (greenfield: el caparazón — menús, layout, homepage, login,
|
|
81
|
-
redirecciones — aún no existe) o ya construida (brownfield)?"*.
|
|
82
|
-
`
|
|
83
|
+
redirecciones — aún no existe) o ya construida (brownfield)?"*. Repórtalo:
|
|
84
|
+
`bash .claude/hooks/build/slice-ops.sh fact project-kind <greenfield|brownfield> --source human`
|
|
85
|
+
(rc 3 = modo legacy: escríbelo en el fichero con su protocolo).
|
|
83
86
|
- `"greenfield"` → tras clasificar capas (abajo), continúa a la **Fase 2c**.
|
|
84
87
|
|
|
85
88
|
El factor que más reduce el consumo de contexto por slice es que el **cimiento** ya esté construido y
|
|
@@ -121,11 +124,16 @@ Si `project_kind !== "greenfield"`, salta esta fase (N/A total).
|
|
|
121
124
|
- **Rechaza** → **STOP** de la fase: deja `foundation.epic: null`, instruye crearla en
|
|
122
125
|
discovery (`/trycore:*`) con la checklist como alcance. El gate del DoR bloqueará las
|
|
123
126
|
épicas de negocio igual hasta que exista y se archive.
|
|
124
|
-
3. **
|
|
125
|
-
(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
3. **Reportar el hecho**: escribe la checklist podada en un fichero temporal
|
|
128
|
+
(`[{"id","applies","evidence":""}, …]`) y repórtala en una sola transición:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
bash .claude/hooks/build/slice-ops.sh fact foundation \
|
|
132
|
+
--required true --epic EP-XXX --checklist-file /tmp/foundation-checklist.json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`--required false` cuando el humano podó todos los ítems (no hay caparazón exigible).
|
|
136
|
+
En modo legacy (rc 3) se escribe en el fichero con su protocolo.
|
|
129
137
|
|
|
130
138
|
---
|
|
131
139
|
|
|
@@ -164,15 +172,22 @@ Si el usuario lo desea y existe `package.json` en el proyecto:
|
|
|
164
172
|
|
|
165
173
|
## Fase 3c: (Si hay UI) Confirmar la fuente de diseño en el estado
|
|
166
174
|
|
|
167
|
-
Espejo de la confirmación de scaffold, para
|
|
175
|
+
Espejo de la confirmación de scaffold, para el hecho `design_source`:
|
|
168
176
|
- Si el producto **tiene UI**: setea `design_source.applies=true`, `source` (el puntero confirmado) y
|
|
169
177
|
`confirmed=true` **solo si** el usuario confirma que la fuente de diseño existe (con `confirmed_by`,
|
|
170
|
-
`confirmed_at`). El
|
|
178
|
+
`confirmed_at`). El prototipo puede generarse con `/build:prototype` (skill `prototyping-screens`);
|
|
179
|
+
`confirmed` sigue siendo exclusivamente humano.
|
|
171
180
|
- Si **no hay UI**: setea `design_source.applies=false` (el mecanismo de fidelidad queda N/A).
|
|
172
181
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
Repórtalo en una sola transición:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
bash .claude/hooks/build/slice-ops.sh fact design-source \
|
|
186
|
+
--applies true --source "<ruta/URL confirmada>" --confirmed true --by "<quién confirmó>"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Sin UI: `--applies false` (el mecanismo de fidelidad queda N/A). Guardarraíl: **una transición =
|
|
190
|
+
una llamada**; `--confirmed true` exige `--by`: confirmar es acto humano.
|
|
176
191
|
|
|
177
192
|
---
|
|
178
193
|
|
|
@@ -221,6 +236,40 @@ CLAUDE.md actualizado. Auto-memory escrita. Los agentes de calidad ya leen tu do
|
|
|
221
236
|
|
|
222
237
|
---
|
|
223
238
|
|
|
239
|
+
## Fase 5: (Con runtime) Preparar el bundle de grafo para el ADMIN
|
|
240
|
+
|
|
241
|
+
El grafo del backlog (épicas, capas, `files_scope`, dependencias, historias, líneas de release) vive
|
|
242
|
+
en el runtime. **Importarlo es un acto de gobierno**: la superficie exige sesión de ADMIN y rechaza
|
|
243
|
+
el token de agente. El arnés **prepara y valida**; una persona sube.
|
|
244
|
+
|
|
245
|
+
1. Extrae el grafo de los artefactos de discovery ya leídos (`docs/03-backlog/epicas.md`,
|
|
246
|
+
`docs/02-user-story-map/`, `docs/04-historias/`) a un JSON:
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
{"project_ref": "<nombre del proyecto>",
|
|
250
|
+
"epics": [{"code": "EP-001", "title": "…", "layer": "foundational",
|
|
251
|
+
"files_scope": ["src/core/**"], "depends_on": [],
|
|
252
|
+
"stories": [{"id": "HU-001", "title": "…"}]}],
|
|
253
|
+
"release_lines": [{"id": "R1-mvp", "epics": ["EP-001"]}]}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
2. Normalízalo y valídalo (determinista, nunca sube nada):
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
python3 .claude/scripts/lib/graph-bundle.py < /tmp/epics.json > /tmp/graph-bundle.json
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
3. **Lee los avisos** (`warnings` del bundle y stderr): capa ausente, dependencia inexistente,
|
|
263
|
+
ciclo, línea de release que referencia una épica desconocida. Corrígelos en discovery — el arnés
|
|
264
|
+
**no inventa** el grafo ni edita `epicas.md` (salvo el carve-out de la épica caparazón, Fase 2c).
|
|
265
|
+
|
|
266
|
+
4. **Entrega el fichero a un ADMIN** con esta instrucción literal: *«súbelo en la consola del hub,
|
|
267
|
+
pantalla de import del proyecto»*. El import es idempotente y **reanuda** si falló a medias.
|
|
268
|
+
|
|
269
|
+
5. Modo `legacy` o sin credenciales: salta esta fase; el grafo sigue viviendo en los documentos.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
224
273
|
## Guardrails
|
|
225
274
|
|
|
226
275
|
- No avances sin confirmar los 7 puntos. Si el usuario omite alguno, repregunta o marca "no aplica".
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "BUILD: Prototype"
|
|
3
|
+
description: Genera o amplía el prototipo HTML de referencia (la fuente de diseño / DESIGN_SOURCE) en docs/05-prototipo/. Dos modos — greenfield (prototipo inicial desde los docs de discovery + dirección estética elegida por el humano) y feature (pantallas de una épica nueva extraídas en vivo del UI ya implementado). Delega en la skill prototyping-screens. La confirmación de design_source sigue siendo humana.
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [build-harness, outer-loop, prototipo, design-source, trycore]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /build:prototype — Prototipo HTML de referencia
|
|
9
|
+
|
|
10
|
+
Delega en la skill **prototyping-screens**. Uso:
|
|
11
|
+
|
|
12
|
+
- `/build:prototype` — modo **greenfield** (o detección automática): prototipo inicial completo.
|
|
13
|
+
Inventario de pantallas desde PRD/mapa/historias → confirmación humana → dirección estética
|
|
14
|
+
(manual de marca o 2-3 variantes a elección humana) → generación por lotes con auto-verificación.
|
|
15
|
+
- `/build:prototype <épica>` — modo **feature**: pantallas nuevas de esa épica, coherentes con el
|
|
16
|
+
UX/UI ya implementado. **Precondición dura**: app corriendo + MCP de inspección de UI (p.ej.
|
|
17
|
+
chrome-devtools); sin ellos hace STOP (la extracción viva de CSS computado no se degrada).
|
|
18
|
+
|
|
19
|
+
Es **outer-loop**: córrelo antes de abrir slices (como `/build:architect`). Produce
|
|
20
|
+
`docs/05-prototipo/` (DESIGN.md, tokens.css, manifest.json, pantallas/) y, en greenfield con
|
|
21
|
+
aprobación humana, reporta el hecho `design_source` al runtime
|
|
22
|
+
(`slice-ops.sh fact design-source …`). **La skill genera; el humano aprueba**: la confirmación de la
|
|
23
|
+
fuente de diseño y el `estado: "aprobada"` del manifest nunca se auto-marcan.
|
|
@@ -33,12 +33,41 @@ Stop aquí si no está instalado o si falta `python3`.
|
|
|
33
33
|
|
|
34
34
|
## Fase 1: Identificar slices sin reflexionar
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
El origen del dato depende del **modo** (igual que consume `reflect-nudge.sh`): en `runtime` puro el
|
|
37
|
+
fichero local NO se lee — puede faltar o quedar fósil (`runtime-protocol.md`) — y el cómputo lo hace el
|
|
38
|
+
servidor sobre **todo el proyecto**; en `legacy`/`dual` el fichero sigue siendo primario.
|
|
37
39
|
|
|
38
40
|
```bash
|
|
39
|
-
|
|
41
|
+
MODE="$(bash .claude/hooks/build/slice-ops.sh mode)"
|
|
42
|
+
if [ "$MODE" = "runtime" ]; then
|
|
43
|
+
# runtime: NO se lee el fichero legacy (fósil/ausente). El servidor ya agregó el nudge
|
|
44
|
+
# "reflect" sobre todo el proyecto; lo leemos de la línea `nudges:` de `status`, el mismo
|
|
45
|
+
# dato que consume reflect-nudge.sh.
|
|
46
|
+
bash .claude/hooks/build/slice-ops.sh status | python3 - <<'PY'
|
|
47
|
+
import json, sys
|
|
48
|
+
nudges = []
|
|
49
|
+
for line in sys.stdin:
|
|
50
|
+
if line.startswith("nudges:"):
|
|
51
|
+
try:
|
|
52
|
+
nudges = json.loads(line.split(":", 1)[1].strip())
|
|
53
|
+
except Exception:
|
|
54
|
+
nudges = []
|
|
55
|
+
break
|
|
56
|
+
pend = [n.get("message") for n in nudges
|
|
57
|
+
if isinstance(n, dict) and n.get("kind") == "reflect" and n.get("message")]
|
|
58
|
+
if pend:
|
|
59
|
+
for m in pend:
|
|
60
|
+
print(m)
|
|
61
|
+
print("TOTAL_RUNTIME", len(pend))
|
|
62
|
+
else:
|
|
63
|
+
print("TOTAL 0")
|
|
64
|
+
PY
|
|
65
|
+
else
|
|
66
|
+
# legacy o dual: el fichero es primario en ambos modos (en dual, reconcile-build-state.py
|
|
67
|
+
# lo mantiene sincronizado — runtime-protocol.md); filtra `history[]` con `reflected != true`.
|
|
68
|
+
python3 - <<'PY'
|
|
40
69
|
import json, os, sys
|
|
41
|
-
p = ".claude/state/build-state.json"
|
|
70
|
+
p = ".claude/state/build-state.json" # legacy: ruta local, no runtime
|
|
42
71
|
if not os.path.exists(p):
|
|
43
72
|
print("NO_STATE"); sys.exit(0) # estado ausente → nada que reflexionar, salir
|
|
44
73
|
try:
|
|
@@ -50,13 +79,21 @@ for h in pend:
|
|
|
50
79
|
print(h.get("epica"), "·", h.get("openspec_change"), "·", h.get("branch"), "·", ",".join(h.get("hus") or []))
|
|
51
80
|
print("TOTAL", len(pend))
|
|
52
81
|
PY
|
|
82
|
+
fi
|
|
53
83
|
```
|
|
54
84
|
|
|
55
|
-
**Si `NO_STATE
|
|
56
|
-
corrupto → repórtalo y **detente sin escribir** (no estampes ni
|
|
57
|
-
slices pendientes de reflexión ✅" y termina. No inventes
|
|
85
|
+
**Si `NO_STATE`** (solo aplica en `legacy`/`dual`): no hay estado → nada que reflexionar; termina.
|
|
86
|
+
**Si `CORRUPT_STATE`:** el estado está corrupto → repórtalo y **detente sin escribir** (no estampes ni
|
|
87
|
+
edites). **Si `TOTAL 0`:** informa "No hay slices pendientes de reflexión ✅" y termina. No inventes
|
|
88
|
+
trabajo.
|
|
89
|
+
|
|
90
|
+
**En `runtime`** el servidor solo entrega el **conteo agregado** (`TOTAL_RUNTIME`), sin `epica`/
|
|
91
|
+
`openspec_change`/`branch` por slice (el cliente no puede enumerarlos hoy). Si `TOTAL_RUNTIME > 0`,
|
|
92
|
+
dile al humano cuántos hay pendientes según el runtime y **pregúntale con AskUserQuestion** qué slice
|
|
93
|
+
(`EP-XXX` + `openspec_change`) reflexionar primero; no adivines ni asumas "el más reciente" sin ese dato.
|
|
58
94
|
|
|
59
|
-
Si hay varios, procésalos **de uno en uno** (el más
|
|
95
|
+
Si tienes el detalle por slice (`legacy`/`dual`) y hay varios, procésalos **de uno en uno** (el más
|
|
96
|
+
reciente primero), o pregunta al usuario cuál.
|
|
60
97
|
|
|
61
98
|
---
|
|
62
99
|
|
|
@@ -119,42 +156,25 @@ Para las viñetas aprobadas, **inserta** (no reemplaces) dentro del bloque marca
|
|
|
119
156
|
|
|
120
157
|
## Fase 5: Estampar el slice como reflexionado
|
|
121
158
|
|
|
122
|
-
|
|
159
|
+
El estampado es una transición de dominio más: la hace el ejecutable, no un `json.dump` a mano.
|
|
123
160
|
|
|
124
161
|
```bash
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
h["reflected"] = True
|
|
137
|
-
h["reflected_at"] = now
|
|
138
|
-
# Validación contra el schema ANTES de persistir (si jsonschema está disponible); aborta si no valida.
|
|
139
|
-
try:
|
|
140
|
-
import jsonschema
|
|
141
|
-
schema = json.load(open(".claude/state/build-state.schema.json"))
|
|
142
|
-
jsonschema.Draft202012Validator(schema).validate(d)
|
|
143
|
-
except ImportError:
|
|
144
|
-
pass # sin jsonschema: se omite la validación profunda (no se relaja la escritura atómica)
|
|
145
|
-
except Exception as e:
|
|
146
|
-
print("ABORT: el estado modificado NO valida contra el schema, no escribo:", e); sys.exit(1)
|
|
147
|
-
# Escritura ATÓMICA (una transición = una escritura): tmp + os.replace.
|
|
148
|
-
fd, tmp = tempfile.mkstemp(dir=os.path.dirname(p) or ".", prefix=".build-state.", suffix=".tmp")
|
|
149
|
-
with os.fdopen(fd, "w") as out:
|
|
150
|
-
json.dump(d, out, indent=2, ensure_ascii=False)
|
|
151
|
-
os.replace(tmp, p)
|
|
152
|
-
print("estampado:", change)
|
|
153
|
-
PY
|
|
162
|
+
MODE="$(bash .claude/hooks/build/slice-ops.sh mode)"
|
|
163
|
+
if [ "$MODE" = "legacy" ]; then
|
|
164
|
+
# Modo legacy (v0.8.5): se estampa `reflected`/`reflected_at` en la entrada de history[]
|
|
165
|
+
# del fichero, con escritura atómica y validación contra el schema local. Protocolo en
|
|
166
|
+
# skills/building-a-slice/references/state-protocol.md.
|
|
167
|
+
echo "legacy: estampa reflected=true en la entrada de history[] del fichero"
|
|
168
|
+
else
|
|
169
|
+
bash .claude/hooks/build/slice-ops.sh progress \
|
|
170
|
+
"reflexión completada de <EP-XXX> (<openspec_change>): <N> aprendizajes aplicados"
|
|
171
|
+
bash .claude/hooks/build/slice-ops.sh fact harness-phase building >/dev/null 2>&1 || true
|
|
172
|
+
fi
|
|
154
173
|
```
|
|
155
174
|
|
|
156
|
-
|
|
157
|
-
|
|
175
|
+
En `dual`/`runtime` el hecho «este slice ya se reflexionó» vive en el event stream del runtime:
|
|
176
|
+
el nudge de `reflect-nudge.sh` lo computa el servidor sobre **todo** el proyecto, no sobre este
|
|
177
|
+
clon (por eso el nudge dejó de mentir con 31/33 slices sin estampar).
|
|
158
178
|
|
|
159
179
|
---
|
|
160
180
|
|
|
@@ -165,7 +185,7 @@ ciclo). Repite por cada slice procesado.
|
|
|
165
185
|
|
|
166
186
|
Slice: <EP-XXX> (<openspec_change>)
|
|
167
187
|
Aprendizajes: <N agregados a CLAUDE.md> · <M a auto-memory> · <0 si solo se estampó>
|
|
168
|
-
Estampado: reflected=true
|
|
188
|
+
Estampado: reportado al runtime (o reflected=true en modo legacy)
|
|
169
189
|
|
|
170
190
|
Pendientes de reflexión restantes: <K>
|
|
171
191
|
```
|
|
@@ -27,9 +27,9 @@ Stop si no está instalado o falta `python3`.
|
|
|
27
27
|
|
|
28
28
|
## 2. Identificar la release y sus épicas
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
Consulta el estado con `bash .claude/hooks/build/slice-ops.sh status` y cruza con
|
|
31
|
+
`docs/02-user-story-map/` para resolver qué épicas componen la release. No hay entrada que crear: los
|
|
32
|
+
veredictos que reporte `releasing-a-version` pueblan la línea de release en el runtime.
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
@@ -67,10 +67,12 @@ reviewer. Es el gate **no negociable**: sin él, no hay release.
|
|
|
67
67
|
|
|
68
68
|
## 6. Síntesis y escritura
|
|
69
69
|
|
|
70
|
-
-
|
|
71
|
-
`
|
|
72
|
-
|
|
73
|
-
-
|
|
70
|
+
- Reporta **cada** gate medido con
|
|
71
|
+
`bash .claude/hooks/build/release-ops.sh verdict <line> <gate> <pass|fail|na> --evidence-file f`
|
|
72
|
+
(`na` cuando no aplica). El **agregado** lo hace el runtime: **parciales no promueven a `passed`**.
|
|
73
|
+
- Con los seis reportados y en verde, recuérdale al humano que **el cierre es suyo**
|
|
74
|
+
(`release-ops.sh close-hint <line>`): el agente no cierra releases.
|
|
75
|
+
- Algo ✗ → los hallazgos bloqueantes se corrigen **como un slice normal**
|
|
74
76
|
(`/build:slice` / `building-a-slice`) y se **re-corre** el Release Gate.
|
|
75
77
|
|
|
76
78
|
---
|
|
@@ -81,4 +83,5 @@ reviewer. Es el gate **no negociable**: sin él, no hay release.
|
|
|
81
83
|
vez por release (`O(releases)`).
|
|
82
84
|
- **No dupliques el inner loop**: no se hace TDD ni se cierran gates por slice.
|
|
83
85
|
- **`integration` con deps reales es obligatorio**; no se acepta con todo stubbeado.
|
|
86
|
+
- **El agente reporta, el humano cierra** (spec §2): ninguna llamada de cierre con token de agente.
|
|
84
87
|
- Delega en `releasing-a-version`; **no** la reimplementa. Si algo contradice `METODOLOGIA.md`, gana la metodología.
|
package/commands/build/resume.md
CHANGED
|
@@ -1,29 +1,49 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "BUILD: Resume"
|
|
3
|
-
description: Rehidrata el slice activo
|
|
3
|
+
description: Rehidrata el slice activo tras un reinicio de contexto — refresca la proyección desde el runtime (o reconcilia el fichero en modo legacy), muestra la continuidad y la siguiente acción determinista.
|
|
4
4
|
category: Workflow
|
|
5
5
|
tags: [build-harness, resume, rehydrate, trycore]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# /build:resume — Retomar sin pérdida
|
|
9
9
|
|
|
10
|
-
Objetivo: reconstruir el contexto de construcción **desde
|
|
10
|
+
Objetivo: reconstruir el contexto de construcción **desde fuera de la conversación** — del
|
|
11
|
+
runtime en `dual`/`runtime`, del disco en `legacy`.
|
|
11
12
|
|
|
12
13
|
## Pasos
|
|
13
14
|
|
|
14
|
-
1. **
|
|
15
|
-
(degrada wiring sin evidencia; anota branch drift; fail-open).
|
|
15
|
+
1. **Averigua el modo y refresca**:
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
```bash
|
|
18
|
+
MODE="$(bash .claude/hooks/build/slice-ops.sh mode)"
|
|
19
|
+
bash .claude/hooks/build/slice-ops.sh status
|
|
20
|
+
```
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
- `legacy` → reconcilia el fichero como en v0.8.5: `python3 .claude/hooks/build/reconcile-build-state.py .claude/state/build-state.json`
|
|
23
|
+
(degrada wiring sin evidencia; anota branch drift; fail-open) y sigue
|
|
24
|
+
`building-a-slice/references/state-protocol.md`.
|
|
25
|
+
- `dual|runtime` → `status` ya trae slice, fase, gates, wiring `failing`, contexto, lease y
|
|
26
|
+
cola pendiente.
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
2. **Determina la siguiente acción**:
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
```bash
|
|
31
|
+
bash .claude/hooks/build/slice-ops.sh next-step
|
|
32
|
+
```
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
La prioridad es determinista y la calcula el cliente: `resume_hint` → items de wiring en
|
|
35
|
+
`failing` → sub-slice pendiente → primer gate abierto por fase. **Ejecútala.**
|
|
36
|
+
|
|
37
|
+
3. **Si el `status` muestra `⚠ lease` (lease perdido)**: haz `slice-ops.sh checkpoint --note …`,
|
|
38
|
+
**detén** el trabajo y vuelve a reclamar (`slice-ops.sh claim`) antes de cerrar nada más.
|
|
39
|
+
|
|
40
|
+
4. **Si el `status` muestra la proyección `⚠ stale`** (sin refrescar) y el runtime no responde:
|
|
41
|
+
sigue trabajando con lo que hay — offline nunca bloquea — y no cierres gates a ciegas.
|
|
42
|
+
|
|
43
|
+
5. **Front paralelo**: si este worktree pertenece a un front, delega en la skill
|
|
44
|
+
`managing-parallel-front`.
|
|
45
|
+
|
|
46
|
+
6. Deja el hito: `bash .claude/hooks/build/slice-ops.sh progress "retomado por /build:resume: <qué sigue>"`.
|
|
47
|
+
|
|
48
|
+
**Regla dura:** mientras quede un item `failing`, el slice NO está terminado. Nunca marques
|
|
49
|
+
`passing` sin evidencia de ejecución real (`--evidence-file`).
|
package/commands/build/slice.md
CHANGED
|
@@ -29,25 +29,20 @@ Stop si no está instalado o falta `python3`.
|
|
|
29
29
|
## 2. Leer el estado y decidir punto de entrada
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
p = ".claude/state/build-state.json"
|
|
35
|
-
if not os.path.exists(p): print("NO_STATE"); sys.exit(0)
|
|
36
|
-
try: d = json.load(open(p))
|
|
37
|
-
except Exception as e: print("CORRUPT_STATE", e); sys.exit(0)
|
|
38
|
-
s = d.get("active_slice")
|
|
39
|
-
if not s:
|
|
40
|
-
print("START dor")
|
|
41
|
-
else:
|
|
42
|
-
g = s.get("gates", {})
|
|
43
|
-
abierto = next((k for k, v in g.items() if v is False), None)
|
|
44
|
-
print(f"RESUME {s.get('epica')} fase={s.get('phase')} primer_gate_abierto={abierto}")
|
|
45
|
-
PY
|
|
32
|
+
MODE="$(bash .claude/hooks/build/slice-ops.sh mode)"
|
|
33
|
+
bash .claude/hooks/build/slice-ops.sh status
|
|
46
34
|
```
|
|
47
35
|
|
|
48
|
-
- `
|
|
49
|
-
|
|
50
|
-
- `
|
|
36
|
+
- `MODE=legacy` → el fichero es primario: sigue `building-a-slice/references/state-protocol.md`
|
|
37
|
+
(comportamiento v0.8.5 exacto, sin red).
|
|
38
|
+
- `MODE=dual|runtime` → el estado vive en el runtime
|
|
39
|
+
(`building-a-slice/references/runtime-protocol.md`).
|
|
40
|
+
- **Sin slice activo** (`slice: ninguno reclamado`): en `runtime`, reclámalo con
|
|
41
|
+
`bash .claude/hooks/build/slice-ops.sh claim --epic EP-XXX` — `rc 7` = sin trabajo disponible,
|
|
42
|
+
`rc 6` = rechazo del servidor (muestra su razón, no reintentes). En `legacy|dual` (rc 3) abre el
|
|
43
|
+
slice por **dor** con el protocolo del fichero.
|
|
44
|
+
- **Con slice activo** → **reanuda donde toca**:
|
|
45
|
+
`bash .claude/hooks/build/slice-ops.sh next-step` (no abras otro: el modelo es
|
|
51
46
|
secuencial, un solo slice activo).
|
|
52
47
|
|
|
53
48
|
---
|
|
@@ -56,14 +51,19 @@ PY
|
|
|
56
51
|
|
|
57
52
|
Antes de escribir código de slice, verifica los gates de proyecto:
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
Los tres hechos salen de la línea `hechos:` que imprime `slice-ops.sh status` (`scaffold_confirmed`,
|
|
55
|
+
`design_source_confirmed`, `project_kind`, `foundation_done` — del runtime en `dual`/`runtime`; del
|
|
56
|
+
fichero en `legacy`):
|
|
57
|
+
|
|
58
|
+
- **scaffold** confirmado (`scaffold_confirmed`). Si no → **STOP**: delega en la **Fase 0** de
|
|
59
|
+
`building-a-slice` (pregunta explícita; el arnés **no genera** el scaffold). No abras el slice.
|
|
60
|
+
- Si el proyecto tiene UI, **fuente de diseño** confirmada (`design_source_confirmed`, Fase 0-bis). Si
|
|
61
|
+
no → **STOP** igual.
|
|
62
|
+
- **Caparazón (solo greenfield)**: si `project_kind` es `greenfield` y `foundation_done` es `false`, y
|
|
63
|
+
la épica objetivo es `layer: business` → **STOP**: solo la épica caparazón u otra fundacional puede
|
|
64
|
+
abrir. `status` no identifica **cuál** es la épica caparazón (eso vive hoy en el fichero legacy,
|
|
65
|
+
leído directo por `dor-dod-gatekeeper`); pregunta o consúltalo ahí. Lo valida en detalle el
|
|
66
|
+
`dor-dod-gatekeeper` (criterio 7-bis). Brownfield → N/A, no preguntes.
|
|
67
67
|
|
|
68
68
|
El hook `scaffold-guard.sh` respalda esto en tiempo real.
|
|
69
69
|
|
|
@@ -91,8 +91,13 @@ archivada, recuerda el default del Release Gate (ver `/build:release`).
|
|
|
91
91
|
|
|
92
92
|
## Guardrails
|
|
93
93
|
|
|
94
|
-
- **Un solo slice activo** (secuencial). No abras un segundo mientras haya
|
|
95
|
-
|
|
94
|
+
- **Un solo slice activo** (secuencial). No abras un segundo mientras haya uno reclamado; en
|
|
95
|
+
`runtime` el propio claim es idempotente y devuelve el mismo slice con el lease vigente.
|
|
96
|
+
- **Todo acto de dominio pasa por `slice-ops.sh`**; en modo `runtime` no se escribe el fichero local.
|
|
97
|
+
- **Orden estricto de gates**; un gate no se salta. `dod` exige `wiring_verified: true`. El bucle
|
|
98
|
+
adversarial tiene condición de parada: **máximo 2 pasadas completas por slice** (pasadas 2+
|
|
99
|
+
incrementales por `verified_at_sha`; lo diferido se declara en el PR y lo custodia el Release
|
|
100
|
+
Gate — ver METODOLOGIA §1-bis).
|
|
96
101
|
- **Sin scaffold confirmado, no hay slice** (el arnés lo exige pero no lo genera).
|
|
97
102
|
- **Agnóstico**: este comando no asume dominio; lo específico entra por `/build:onboard` y `stack-allowlist.json`.
|
|
98
103
|
- Si algo contradice `METODOLOGIA.md`, **gana la metodología**.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "BUILD: Status"
|
|
3
|
+
description: Informe del agente y su trabajo — modo, proyecto, slice activo, gates, wiring failing, versión de contexto, lease y cola de eventos pendientes. Solo lectura, nunca bloquea. Adaptador delgado sobre slice-ops.sh status.
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [build-harness, runtime, status, trycore]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /build:status — ¿Dónde estamos?
|
|
9
|
+
|
|
10
|
+
## 1. Informe
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
bash .claude/hooks/build/slice-ops.sh status
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Refresca la proyección desde `/agent/context` y muestra: **modo**, proyecto y agente, slice activo
|
|
17
|
+
con fase/gates/wiring, rama y change, versión de contexto (`✓ vN` o `⚠ stale`), lease y número de
|
|
18
|
+
eventos pendientes en la cola. En modo `legacy` dice que la fuente de verdad es el fichero local y
|
|
19
|
+
no consulta nada.
|
|
20
|
+
|
|
21
|
+
Con `--no-refresh` no toca la red (útil sin conexión).
|
|
22
|
+
|
|
23
|
+
## 2. Leer las señales
|
|
24
|
+
|
|
25
|
+
- `⚠ stale` → la proyección no se pudo refrescar: los guards siguen operando con lo último
|
|
26
|
+
sincronizado. **No cierres gates a ciegas**; reintenta cuando vuelva el runtime.
|
|
27
|
+
- `⚠ lease perdido` → haz `slice-ops.sh checkpoint --note …`, detén el trabajo y vuelve a reclamar.
|
|
28
|
+
- `cola: N evento(s)` con N creciendo y sin bajar → el daemon no está despachando; revisa
|
|
29
|
+
`.claude/state/heartbeat-status.json` (y, en el sub-slice D, `trycore-build doctor`).
|
|
30
|
+
|
|
31
|
+
## Guardrails
|
|
32
|
+
|
|
33
|
+
- **Solo lectura**: este comando no transiciona nada.
|
|
34
|
+
- El estado de **la flota** (otros agentes, otros slices, releases y fronts del proyecto) vive en la
|
|
35
|
+
consola del hub: es superficie humana, no de agente.
|