@trycore/spec-build-harness 0.7.1 → 0.8.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 +3 -3
- package/METODOLOGIA.md +44 -0
- package/README.md +59 -5
- package/VERSION +1 -1
- package/agents/build/build-orchestrator.md +6 -0
- package/commands/build/front.md +15 -0
- package/commands/build/resume.md +29 -0
- package/config/build-config.template.json +8 -0
- package/dist/commands/init.js +15 -5
- package/dist/commands/status.js +1 -0
- package/dist/commands/uninstall.js +2 -1
- package/dist/lib/paths.js +7 -0
- package/dist/lib/settings-merge.js +29 -2
- package/dist/lib/state-seed.js +14 -0
- package/docs/commands.md +15 -3
- package/docs/decisiones/2026-07-03-gsd-vs-openspec-fork-vs-rama.md +157 -0
- package/docs/flujo-harness-funcional.md +42 -0
- package/docs/flujo-harness.md +192 -0
- package/docs/hooks.md +22 -5
- package/hooks/build/build-gate-check.sh +1 -1
- package/hooks/build/context-monitor.sh +74 -0
- package/hooks/build/design-source-guard.sh +1 -1
- package/hooks/build/lib/state-io.sh +55 -0
- package/hooks/build/lint-typecheck.sh +1 -1
- package/hooks/build/load-build-state.sh +46 -2
- package/hooks/build/reconcile-build-state.py +70 -0
- package/hooks/build/reflect-nudge.sh +1 -1
- package/hooks/build/release-gate-nudge.sh +1 -1
- package/hooks/build/scaffold-guard.sh +1 -1
- package/hooks/build/stack-guard.sh +1 -1
- package/hooks/build/statusline-bridge.sh +32 -0
- package/hooks/build-harness.json +24 -0
- package/package.json +1 -1
- package/scripts/lib/front-plan.py +47 -0
- package/scripts/smoke-test.sh +12 -0
- package/scripts/tests/test-context-monitor.sh +70 -0
- package/scripts/tests/test-front-plan.sh +38 -0
- package/scripts/tests/test-install.sh +89 -0
- package/scripts/tests/test-reconciler.sh +54 -0
- package/scripts/tests/test-schema.sh +58 -0
- package/skills/building-a-slice/references/dor.md +2 -0
- package/skills/managing-parallel-front/SKILL.md +36 -0
- package/state/build-state.schema.json +50 -0
|
@@ -16,6 +16,8 @@ la épica; lo de abajo aplica a la épica y a **cada HU** que cubre (`hus[]`). L
|
|
|
16
16
|
- [ ] **Fuente de diseño identificada (slices con UI)**: la fuente visual de verdad del slice
|
|
17
17
|
(el `DESIGN_SOURCE` del dominio) está declarada y confirmada (`design_source.confirmed`), y este
|
|
18
18
|
slice apunta a la(s) pantalla(s) equivalente(s). No se construye UI fuera de la fuente declarada.
|
|
19
|
+
- [ ] **Clasificación `layer`**: `foundational` (auth/datos/design-system/arquitectura base) | `business`. Se escribe en `active_slice.layer`. Gatea el front paralelo (foundational nunca en paralelo).
|
|
20
|
+
- [ ] **`files_scope`**: globs de los archivos que la épica tocará (p.ej. `src/reports/**`). Fuente de la disjunción inter-épica. Se escribe en `active_slice.files_scope`.
|
|
19
21
|
|
|
20
22
|
**Si todo ✓** → `dor-dod-gatekeeper` abre `active_slice` en `build-state.json` con `epica`, `hus[]`,
|
|
21
23
|
`phase: dor`, `gates.dor: true` y el resto en `false` —incluido **`wiring_verified: false`**—
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: managing-parallel-front
|
|
3
|
+
description: Use when building multiple NON-foundational, file-disjoint epics in parallel via git worktrees. Coordinates the parallel_front in build-state.json (selection, worktrees, deterministic merge order with re-smoke). Never parallelizes foundational epics or overlapping file scopes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gestionar el front paralelo inter-épica (outer-loop)
|
|
7
|
+
|
|
8
|
+
**Invariante:** el paralelismo es outer-loop. Cada worktree es un checkout aislado con su
|
|
9
|
+
**propio** `build-state.json` y su `active_slice` singular (el inner loop no cambia).
|
|
10
|
+
|
|
11
|
+
## Precondiciones (compuertas)
|
|
12
|
+
- `scaffold.confirmed == true`.
|
|
13
|
+
- **G1 Fundacionales primero:** ninguna épica `layer=foundational` abierta. Si aparece una,
|
|
14
|
+
poner `parallel_front.status="draining"` (terminar en curso, no admitir nuevas) antes de abrirla.
|
|
15
|
+
|
|
16
|
+
## Procedimiento
|
|
17
|
+
1. **Reunir candidatas** no fundacionales listas (DoR pasado), cada una con `layer` y `files_scope`.
|
|
18
|
+
2. **Seleccionar el conjunto disjunto** (G2):
|
|
19
|
+
`echo "$CANDS" | python3 .claude/scripts/lib/front-plan.py`
|
|
20
|
+
→ `selected` van al front; `serialized` esperan (construir secuencial después);
|
|
21
|
+
`excluded_foundational` nunca en paralelo.
|
|
22
|
+
3. **Abrir un worktree por épica seleccionada:**
|
|
23
|
+
`git worktree add ".wt/<epica>" -b feature/<slug>` (rama por `1 épica = 1 rama = 1 PR`).
|
|
24
|
+
Registrar el miembro en `parallel_front.members[]` (`merge_status:"pending"`).
|
|
25
|
+
4. **Construir cada worktree** con la skill `building-a-slice` (inner loop normal, en su cwd).
|
|
26
|
+
Cada uno mantiene su `journey_smoke` verde localmente.
|
|
27
|
+
5. **Coordinar merge (G3)** en `merge_order` (determinista: por orden de épica):
|
|
28
|
+
- Merge del PR; tras cada merge, **re-smoke del journey completo** en el árbol principal.
|
|
29
|
+
- Conflicto → `merge_status:"conflict"`, serializar la perdedora (rebase + re-correr sus gates).
|
|
30
|
+
- Éxito → `merge_status:"merged"`; `git worktree remove`.
|
|
31
|
+
6. **Cerrar el front** cuando todos `merged`: `parallel_front=null`.
|
|
32
|
+
|
|
33
|
+
## Reglas duras
|
|
34
|
+
- Nunca escritores paralelos sobre el mismo árbol (por eso worktrees).
|
|
35
|
+
- Nunca paralelizar dentro de una épica (preserva la "regla del esqueleto que camina").
|
|
36
|
+
- Un solape de `files_scope` no detectado que cause conflicto de merge → el re-smoke (G3) lo caza.
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
"type": "array",
|
|
32
32
|
"description": "Release Gates (outer loop). Una entrada por línea de release del Story Map auditada en bloque.",
|
|
33
33
|
"items": { "$ref": "#/$defs/release" }
|
|
34
|
+
},
|
|
35
|
+
"parallel_front": {
|
|
36
|
+
"description": "Coordinación outer-loop de worktrees inter-épica (C). null = modo secuencial normal.",
|
|
37
|
+
"oneOf": [ { "type": "null" }, { "$ref": "#/$defs/parallel_front" } ]
|
|
34
38
|
}
|
|
35
39
|
},
|
|
36
40
|
"$defs": {
|
|
@@ -75,6 +79,7 @@
|
|
|
75
79
|
},
|
|
76
80
|
"openspec_change": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" },
|
|
77
81
|
"branch": { "type": "string", "pattern": "^(feature|fix|chore)/[a-z0-9._-]+$" },
|
|
82
|
+
"branch_drift": { "type": "string", "description": "Rama git real cuando difiere de branch (lo escribe el reconciliador)." },
|
|
78
83
|
"phase": {
|
|
79
84
|
"type": "string",
|
|
80
85
|
"enum": ["dor", "change", "red", "green", "refactor", "smoke", "api", "data", "dod", "pr", "archived"]
|
|
@@ -151,6 +156,19 @@
|
|
|
151
156
|
"journey_smoke": { "type": "boolean", "description": "El backbone-hasta-este-sub-slice camina end-to-end." }
|
|
152
157
|
}
|
|
153
158
|
}
|
|
159
|
+
},
|
|
160
|
+
"layer": { "type": "string", "enum": ["foundational", "business"], "default": "business", "description": "Clasificación (taxonomía existente del arnés): foundational (auth/datos/design-system/arquitectura base) nunca va en paralelo; business = épica de negocio (paralelizable si es disjunta). Gatea el front paralelo (C)." },
|
|
161
|
+
"files_scope": { "type": "array", "items": { "type": "string" }, "description": "Globs de archivos que la épica toca. Fuente de la disjunción inter-épica (G2)." },
|
|
162
|
+
"session_continuity": {
|
|
163
|
+
"type": "object", "additionalProperties": false,
|
|
164
|
+
"description": "Handoff de sesión (A): permite resume sin pérdida tras presión de contexto.",
|
|
165
|
+
"properties": {
|
|
166
|
+
"last_session": { "type": ["string", "null"] },
|
|
167
|
+
"stopped_at": { "type": ["string", "null"], "description": "p.ej. 'context exhaustion at 24% (ISO)'." },
|
|
168
|
+
"resume_hint": { "type": ["string", "null"], "description": "Siguiente acción concisa." },
|
|
169
|
+
"critical_recorded": { "type": "boolean", "description": "Guard once-per-session del auto-handoff." },
|
|
170
|
+
"auto_continue": { "type": "boolean", "description": "true cuando context.auto_checkpoint disparó continuación automática (§4.4)." }
|
|
171
|
+
}
|
|
154
172
|
}
|
|
155
173
|
}
|
|
156
174
|
},
|
|
@@ -184,6 +202,38 @@
|
|
|
184
202
|
"created_at": { "type": "string", "format": "date-time" },
|
|
185
203
|
"updated_by": { "type": "string" }
|
|
186
204
|
}
|
|
205
|
+
},
|
|
206
|
+
"parallel_front": {
|
|
207
|
+
"type": "object", "additionalProperties": false,
|
|
208
|
+
"required": ["status", "opened_at", "updated_by", "members", "merge_order"],
|
|
209
|
+
"properties": {
|
|
210
|
+
"status": { "type": "string", "enum": ["active", "draining"] },
|
|
211
|
+
"opened_at": { "type": "string", "format": "date-time" },
|
|
212
|
+
"updated_by": { "type": "string" },
|
|
213
|
+
"members": {
|
|
214
|
+
"type": "array",
|
|
215
|
+
"items": {
|
|
216
|
+
"type": "object", "additionalProperties": false,
|
|
217
|
+
"required": ["epica", "worktree", "files_scope", "merge_status"],
|
|
218
|
+
"properties": {
|
|
219
|
+
"epica": { "type": "string", "pattern": "^EP-[0-9]{3}$" },
|
|
220
|
+
"worktree": {
|
|
221
|
+
"type": "object", "additionalProperties": false,
|
|
222
|
+
"required": ["path", "branch", "created_at"],
|
|
223
|
+
"properties": {
|
|
224
|
+
"path": { "type": "string" },
|
|
225
|
+
"branch": { "type": "string", "pattern": "^(feature|fix|chore)/[a-z0-9._-]+$" },
|
|
226
|
+
"created_at": { "type": "string", "format": "date-time" }
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"files_scope": { "type": "array", "items": { "type": "string" } },
|
|
230
|
+
"journey_smoke": { "type": "boolean" },
|
|
231
|
+
"merge_status": { "type": "string", "enum": ["pending", "merged", "conflict"] }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"merge_order": { "type": "array", "items": { "type": "string", "pattern": "^EP-[0-9]{3}$" } }
|
|
236
|
+
}
|
|
187
237
|
}
|
|
188
238
|
}
|
|
189
239
|
}
|