@trycore/spec-build-harness 0.12.0 → 0.14.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.
Files changed (37) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/METODOLOGIA.md +6 -1
  3. package/README.md +1 -0
  4. package/VERSION +1 -1
  5. package/agents/build/dor-dod-gatekeeper.md +10 -3
  6. package/commands/build/epic.md +109 -0
  7. package/commands/build/onboard.md +59 -17
  8. package/commands/build/slice.md +4 -2
  9. package/commands/build/work.md +6 -2
  10. package/config/build-config.template.json +2 -1
  11. package/dist/commands/init.js +13 -0
  12. package/dist/commands/status.js +13 -1
  13. package/dist/lib/normalize.js +11 -0
  14. package/dist/lib/paths.js +1 -0
  15. package/dist/lib/runtime-client.js +20 -0
  16. package/dist/lib/state-bundle.js +15 -1
  17. package/docs/commands.md +2 -1
  18. package/docs/hooks.md +11 -1
  19. package/docs/runtime/protocolo-cliente-runtime.md +90 -0
  20. package/hooks/build/design-source-guard.sh +12 -1
  21. package/hooks/build/heartbeat.sh +64 -4
  22. package/hooks/build/lib/agent-context.sh +16 -7
  23. package/hooks/build/lib/config.sh +25 -1
  24. package/hooks/build/lib/runtime-client.sh +540 -9
  25. package/hooks/build/lib/runtime-ops.sh +108 -0
  26. package/hooks/build/scaffold-guard.sh +14 -1
  27. package/hooks/build/slice-ops.sh +498 -16
  28. package/package.json +1 -1
  29. package/scripts/lib/graph-bundle.py +165 -1
  30. package/scripts/tests/test-config.sh +41 -0
  31. package/scripts/tests/test-hooks-runtime.sh +198 -3
  32. package/scripts/tests/test-install.sh +23 -0
  33. package/scripts/tests/test-runtime-client.sh +500 -0
  34. package/scripts/tests/test-skill-ops.sh +574 -0
  35. package/skills/building-a-slice/references/dor.md +21 -9
  36. package/skills/building-a-slice/references/foundation-contract.md +4 -0
  37. package/state/README.md +12 -0
@@ -11,15 +11,27 @@ la épica; lo de abajo aplica a la épica y a **cada HU** que cubre (`hus[]`). L
11
11
  - [ ] **Dependencias resueltas**: las épicas/HU de las que depende están archivadas (`history[]`) o explícitamente no bloquean. **Excepción dura — cimiento:** si la dependencia es **infraestructura fundacional** (autenticación, acceso a datos, arquitectura base, design-system/componentes base), la cláusula "explícitamente no bloquean" **NO aplica**: debe estar **construida y archivada** antes (ver criterio "Cimiento construido").
12
12
  - [ ] **Cimiento construido (épicas de negocio)**: si esta épica es `layer: business`, todo el cimiento que arrastra (auth, acceso a datos, arquitectura base, design-system/componentes base) ya existe como épica(s) `layer: foundational` **archivada(s)** en `history[]`. Si arrastra cimiento no construido → **STOP**: extráelo a una épica fundacional previa y constrúyela primero. Las épicas fundacionales se priorizan **antes** que las de negocio.
13
13
  - [ ] **Caparazón construido (solo greenfield — gate PROACTIVO)**: si `project_kind === "greenfield"`
14
- y `foundation.required === true` en los hechos de proyecto del runtime (`slice-ops.sh status`; en modo legacy, `build-state.json`), ninguna épica `layer: business` entra a
15
- construcción mientras la épica caparazón (`foundation.epic`) no esté **archivada con su checklist
16
- evidenciada** (`foundation.completed_at` estampado). Las épicas `layer: foundational` (la
17
- caparazón `foundation.epic` u otras fundacionales) pueden abrir. A diferencia de "Cimiento
18
- construido" (reactivo: bloquea si *detecta* arrastre), este criterio bloquea **siempre** en
19
- greenfield hasta que el cimiento exista archivado no depende de detectar nada. Si
20
- `foundation.epic` es `null` (no existe la épica caparazón aún) → **STOP**: se define en
21
- `/build:onboard` Fase 2c o en discovery. Brownfield / `foundation.required: false` → **N/A** (no
22
- bloquea). Contrato: `references/foundation-contract.md`.
14
+ y la caparazón está **requerida**, ninguna épica `layer: business` entra a construcción mientras
15
+ la caparazón no esté **construida y archivada con su checklist evidenciada**. Las épicas
16
+ `layer: foundational` (la caparazón u otras fundacionales) pueden abrir. A diferencia de
17
+ "Cimiento construido" (reactivo: bloquea si *detecta* arrastre), este criterio bloquea
18
+ **siempre** en greenfield hasta que el cimiento exista archivado no depende de detectar nada.
19
+ **Dónde se leen esos hechos depende del modo**, y no son los mismos:
20
+ - **`legacy`/`dual`** — `build-state.json`: `foundation.required`, `foundation.epic` (el
21
+ `EP-XXX` concreto) y `foundation.completed_at`. Si `foundation.epic` es `null` → **STOP**: la
22
+ épica caparazón no existe aún; se define en `/build:onboard` Fase 2c o en discovery.
23
+ - **`runtime`** — la proyección solo trae `foundation_done` (booleano), vía
24
+ `slice-ops.sh status` (línea `hechos:`). **Nadie fija `foundation.epic` en este modo**: la
25
+ Fase 2c propone la épica al hub sin código y la identidad la asigna el hub al aprobar
26
+ (issue #62). Así que aquí **no preguntes por `foundation.epic`** — no existe. Con
27
+ `foundation_done: false`, el estado real de la caparazón lo dice `slice-ops.sh epic-status`
28
+ (o `/build:epic --check`): si hay una propuesta `PROPOSED`, el STOP es **esperar la
29
+ aprobación**, no re-onboardear (repetir la Fase 2c propondría la misma épica dos veces); si
30
+ no hay ninguna propuesta, entonces sí → Fase 2c o discovery.
31
+
32
+ Brownfield o caparazón no requerida (`foundation.required: false` en `legacy`/`dual`;
33
+ `foundation_done: true` en `runtime`) → **N/A** (no bloquea).
34
+ Contrato: `references/foundation-contract.md`.
23
35
  - [ ] **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.
24
36
  - [ ] **Cabe en el stack** del PRD §7 (no requiere tecnología fuera de `stack-allowlist.json`).
25
37
  - [ ] **Cobertura arquitectónica (ADR)** *(opt-in, retrocompatible)*: si el proyecto adoptó la capa de
@@ -40,5 +40,9 @@ N/A y el arnés no pregunta ni exige nada (`foundation.required: false`).
40
40
  - El arnés **propone** el borrador de la épica caparazón; **solo** lo escribe en
41
41
  `docs/03-backlog/epicas.md` con aprobación humana explícita (carve-out acotado, ver
42
42
  METODOLOGIA §9.2). Si el humano rechaza, STOP: la épica se crea en discovery (`/trycore:*`).
43
+ En modo `runtime`, esa aprobación humana en `/build:onboard` **propone al hub**
44
+ (`slice-ops.sh propose-epic`), no escribe: el fichero se escribe después, cuando el hub
45
+ también aprueba y asigna el `EP-XXX`, vía `/build:epic --check` (issue #62). En `legacy`/`dual`
46
+ la aprobación humana escribe directo, como arriba.
43
47
  - La evidencia es de **ejecución**, nunca de inspección.
44
48
  - Si contradice `METODOLOGIA.md`, gana la metodología.
package/state/README.md CHANGED
@@ -141,3 +141,15 @@ El razonamiento vive en el modelo; el hook solo es un recordatorio determinista.
141
141
  | `foundation.checklist[].evidence` | `build-orchestrator` (durante la construcción de la caparazón) | al construir la caparazón |
142
142
  | `foundation.completed_at` | `dor-dod-gatekeeper` (al cerrar el DoD de la épica caparazón) | al archivar la caparazón |
143
143
  | `design_source` (`source`, `confirmed`, `confirmed_by/at`, `notes`) | `building-a-slice` Fase 0-bis · `/build:onboard` Fase 3c · `prototyping-screens` (greenfield, solo tras aprobación humana de ≥1 pantalla; `confirmed` humano siempre) | una vez (proyecto) |
144
+
145
+ ### Ficheros de estado aparte (no viven en `build-state.json`)
146
+
147
+ La tabla de arriba describe **campos** de `build-state.json`. Estos son **ficheros propios** de
148
+ `.claude/state/`: estado derivado del hub que solo existe en modo `runtime`, no forma parte de la
149
+ máquina del pipeline y por eso no entra en el schema del estado. `trycore-build init` los siembra
150
+ en `.gitignore`.
151
+
152
+ | Fichero | Lo escribe | Cadencia |
153
+ |---|---|---|
154
+ | `epic-proposals.json` — ledger de propuestas de épica (`client_event_id`, `proposal_id`, `status`, `epic_code`, `draft`, `written_back_at`) | `slice-ops.sh propose-epic` / `epic-status` / `epic-writeback` | por propuesta de épica |
155
+ | `graph-status.json` — marcador de desfase de grafo (`local`, `server`, `seen_at`): lo deja un `409 stale_graph` del hub y **su existencia es la señal** (el fichero se borra en cuanto la acción vuelve a pasar). Es lo que hace **visible** el desfase en `slice-ops.sh status` y `trycore-build status`; sin él el 409 se resolvería solo y nadie sabría que ocurrió. `local: null` = la petición salió sin versión estampada — nunca `0`, que sería una versión real | `runtime_graph_note_stale` / `runtime_graph_clear_stale` (`hooks/build/lib/runtime-client.sh`), desde `slice-ops.sh claim` y desde el despacho del carril directo | por rechazo `409 stale_graph` |