@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,75 @@
|
|
|
1
|
+
# Protocolo de estado sobre el runtime (modos `dual` y `runtime`)
|
|
2
|
+
|
|
3
|
+
El estado del pipeline vive en el **Agent Orchestrator Runtime**: fases, gates, wiring,
|
|
4
|
+
checkpoints, releases y hechos de proyecto son suyos. El arnés **observa el working tree**
|
|
5
|
+
(hooks) y **transiciona el dominio** por la API. Ningún agente arma peticiones a mano: todo
|
|
6
|
+
acto pasa por `slice-ops.sh` (inner loop) y `release-ops.sh` (outer loop), instalados en
|
|
7
|
+
`.claude/hooks/build/`.
|
|
8
|
+
|
|
9
|
+
> **Antes de nada, pregunta el modo:**
|
|
10
|
+
> ```bash
|
|
11
|
+
> bash .claude/hooks/build/slice-ops.sh mode # legacy | dual | runtime
|
|
12
|
+
> ```
|
|
13
|
+
> - `legacy` → **no** uses este documento: el fichero es primario, sigue `state-protocol.md`.
|
|
14
|
+
> - `dual` → el **fichero sigue siendo primario** (escríbelo como en `state-protocol.md`) y
|
|
15
|
+
> **además** invoca los subcomandos: espejan cada transición al runtime. El claim NO
|
|
16
|
+
> aplica en `dual` (devuelve rc 3): el slice lo decide el fichero.
|
|
17
|
+
> - `runtime` → el fichero es fósil: **no lo leas ni lo escribas**. Todo pasa por los
|
|
18
|
+
> subcomandos, y el estado se consulta con `slice-ops.sh status`.
|
|
19
|
+
|
|
20
|
+
## Códigos de salida (ramifica sobre ellos, no sobre el texto)
|
|
21
|
+
|
|
22
|
+
| rc | Significado | Qué hace la skill |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| 0 | aceptado | continúa |
|
|
25
|
+
| 2 | uso incorrecto | corrige la invocación (bug de la skill, no del runtime) |
|
|
26
|
+
| 3 | modo `legacy` (o claim en `dual`) | sigue el protocolo del fichero |
|
|
27
|
+
| 4 | sin slice activo | reclama primero (`claim`) o abre el slice por DoR |
|
|
28
|
+
| 5 | offline: encolado | **sigue trabajando**; el daemon entrega al reconectar |
|
|
29
|
+
| 6 | rechazado por el servidor | **NO reintentes**: muestra la razón y corrige la causa |
|
|
30
|
+
| 7 | sin trabajo (204) o carrera perdida | comunica y termina limpio |
|
|
31
|
+
|
|
32
|
+
## El ciclo del slice
|
|
33
|
+
|
|
34
|
+
| Acto | Comando | Notas |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| Reclamar | `slice-ops.sh claim [--epic EP-XXX]` | Sincroniza el contexto **antes** (regla: no se abre trabajo con contexto viejo) y reporta los sha256 locales de los archivos gobernados. Si la respuesta trae `checkpoint`, **continúa desde él; jamás reinicies**. |
|
|
37
|
+
| Saber el paso | `slice-ops.sh next-step` | Lo deriva el **cliente** desde la proyección: `resume_hint` → wiring `failing` → sub-slice pendiente → primer gate abierto. |
|
|
38
|
+
| Sembrar el cableado | `slice-ops.sh wiring seed --file items.json` | Un item por escenario AC y por punto de integración entre capas. Nacen `failing`. |
|
|
39
|
+
| Cablear un item | `slice-ops.sh wiring update <item_id> passing --kind K --ref HU-XXX --evidence-file f` | `passing` **solo tras prueba real ejecutada**. Sin evidencia el comando avisa: no lo ignores. |
|
|
40
|
+
| Cerrar un gate | `slice-ops.sh gate <nombre> <pass\|fail\|na> --evidence-file f` | Gates canónicos: `dor coherence_link tdd journey_smoke fidelity api data wiring_verified dod`. Un `na` es legítimo cuando el gate no aplica. |
|
|
41
|
+
| Dejar bitácora | `slice-ops.sh progress «hito»` | Sustituye a `progress_log[]`: el event stream **es** la bitácora. |
|
|
42
|
+
| Guardar continuidad | `slice-ops.sh checkpoint --note «dónde me quedé»` | Rama + commit reales. Es lo que permite que otro agente continúe tras una caída. |
|
|
43
|
+
| Entregar | `slice-ops.sh submit --pr-url U --openspec-change C` | Tras abrir el PR. |
|
|
44
|
+
| Archivar | `slice-ops.sh archive --epic EP-XXX --openspec-change C --pr-url U` | Lo dispara `opsx:archive` en el mismo PR. Va por cola (idempotente, protegido de la cota). |
|
|
45
|
+
| Hechos de proyecto | `slice-ops.sh fact scaffold-confirmed --by «persona»` · `fact design-source …` · `fact project-kind …` · `fact foundation …` | **Reportan lo que un humano confirmó**; el agente nunca confirma por su cuenta. |
|
|
46
|
+
| Bloqueo | `slice-ops.sh escalate «razón» --gate G` | Deja el rastro; la decisión (recortar/diferir/desbloquear) es del equipo. |
|
|
47
|
+
| Ver el estado | `slice-ops.sh status` | Modo, slice, gates, wiring, contexto, lease y cola pendiente. |
|
|
48
|
+
|
|
49
|
+
## Reglas duras
|
|
50
|
+
|
|
51
|
+
1. **Un gate no se salta y `dod` exige `wiring_verified`.** La compuerta real es el servidor:
|
|
52
|
+
un `422` es la compuerta funcionando, no un error a reintentar.
|
|
53
|
+
2. **Nunca marques `passing`/`pass` por inspección.** La evidencia es de ejecución real.
|
|
54
|
+
3. **Contexto antes que trabajo.** Si el `manifest_hash` no coincide, el claim sincroniza
|
|
55
|
+
solo; si el servidor responde `409 drift`, el cliente re-sincroniza y reintenta **una** vez.
|
|
56
|
+
4. **Un solo slice activo.** Reclamar con lease vigente devuelve el mismo slice (idempotente).
|
|
57
|
+
5. **Lease perdido** (`⚠ lease` en la statusline, `heartbeat-status.json`): haz `checkpoint`,
|
|
58
|
+
detén el trabajo y vuelve a reclamar. No sigas cerrando gates con el lease caído.
|
|
59
|
+
6. **Offline no bloquea.** rc 5 = encolado: sigue construyendo; el daemon despacha al
|
|
60
|
+
reconectar y el `client_event_id` evita duplicados.
|
|
61
|
+
7. **El agente no gobierna.** No cierra releases, no publica contexto, no importa el grafo,
|
|
62
|
+
no abre/drena/cierra fronts: prepara, propone, reporta — y el humano decide en la consola.
|
|
63
|
+
|
|
64
|
+
## Qué queda del fichero (legado)
|
|
65
|
+
|
|
66
|
+
En `runtime` el fichero `.claude/state/build-state.json` **no se lee ni se escribe** (queda fósil hasta que el sub-slice E lo retire); solo en modo `legacy` sigue siendo el protocolo primario — ver `state-protocol.md`. Lo que antes se leía de él ahora:
|
|
67
|
+
|
|
68
|
+
| Antes (fichero) | Ahora |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `active_slice.gates` | `slice-ops.sh status` / caché de proyección |
|
|
71
|
+
| `active_slice.wiring_checklist[]` | eventos `wiring_*` + `wiring_failing` de la proyección |
|
|
72
|
+
| `active_slice.progress_log[]` | eventos `progress_note_recorded` (event stream) |
|
|
73
|
+
| `session_continuity.resume_hint` | `resume_hint` de `/agent/context` (lo rinde `next-step`) |
|
|
74
|
+
| `scaffold`, `design_source`, `project_kind`, `foundation` | hechos de proyecto (`fact …`) |
|
|
75
|
+
| `history[]`, `releases[]`, `parallel_front` | proyecciones del runtime (consola del hub) |
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
# Protocolo del archivo de estado (`build-state.json`)
|
|
1
|
+
# Protocolo del archivo de estado (`build-state.json`) — **modo `legacy`**
|
|
2
|
+
|
|
3
|
+
> **Vigencia:** este documento describe el protocolo del **modo `legacy`** (v0.8.5 exacto),
|
|
4
|
+
> donde el fichero es la fuente de verdad. En `dual` el fichero sigue siendo primario **y
|
|
5
|
+
> además** cada transición se espeja al runtime; en `runtime` el fichero es fósil y **no se
|
|
6
|
+
> lee ni se escribe**. Para esos dos modos, el protocolo es
|
|
7
|
+
> [`runtime-protocol.md`](runtime-protocol.md). Comprueba el modo con
|
|
8
|
+
> `bash .claude/hooks/build/slice-ops.sh mode`.
|
|
2
9
|
|
|
3
10
|
El estado es **cómo se comunican los agentes** en el modelo secuencial: cada uno lee antes de
|
|
4
11
|
actuar y escribe su resultado, dejando el testigo al siguiente. Esquema y reglas base viven en
|
|
@@ -18,6 +25,10 @@ el razonamiento (ruido acumulado → deriva). Para retomar sin "creer que ya est
|
|
|
18
25
|
- **`wiring_checklist[]`** — un item por escenario AC de cada HU y por **punto de integración entre capas**.
|
|
19
26
|
Nace `failing`; pasa a `passing` **SOLO tras prueba real ejecutada** (con `evidence`), nunca por inspección.
|
|
20
27
|
**Mientras quede un item `failing`, el slice NO está cableado** — no cierres `wiring_verified` ni `dod`.
|
|
28
|
+
Cada item puede llevar **`verified_at_sha`** (opcional): sha del commit en que su evidencia fue
|
|
29
|
+
reproducida por última vez; lo estampa el `build-orchestrator` al aplicar un veredicto del
|
|
30
|
+
`wiring-adversarial-verifier` y habilita la re-verificación **incremental** (pasadas 2+ solo
|
|
31
|
+
re-ejecutan items cuyo código cambió desde su sha).
|
|
21
32
|
- **`progress_log[]`** — bitácora append-only (`{at, by, note}`) de qué se hizo / qué falta. Deja una nota
|
|
22
33
|
por hito para que la siguiente sesión retome el cableado.
|
|
23
34
|
- **`sub_slices[]`** — si la épica superó el gate de tamaño (>3 HU ó ≥3 capas), se trocea aquí; cada
|
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
atómica: inflaría el inner loop barato. *Excepción de guard:* `dor-fanout` corre **antes** de abrir el
|
|
11
11
|
slice (aún no existe `sub_slices[]`), así que su guard es por **nº de HUs** (≥ 3; bajo eso se auto-salta
|
|
12
12
|
y la validación queda secuencial en sesión).
|
|
13
|
-
2. **Read-only sobre el estado.** Ninguna plantilla
|
|
13
|
+
2. **Read-only sobre el estado.** Ninguna plantilla transiciona el estado (ni por `slice-ops.sh` ni,
|
|
14
|
+
en modo legacy, escribiendo el fichero). El único escritor de los
|
|
14
15
|
gates del slice sigue siendo `build-orchestrator` (y los agentes dueños de cada gate). Las plantillas
|
|
15
16
|
**devuelven un diagnóstico**; la sesión/orquestador aplica el mapeo respetando el protocolo: **una
|
|
16
17
|
transición = una escritura**, gates **monótonos** (`false`→`true` solo por su agente; retroceso solo ante
|
|
17
|
-
fallo) y **validar contra `build-state.schema.json` tras escribir**.
|
|
18
|
+
fallo) y en modo legacy **validar contra `build-state.schema.json` tras escribir**.
|
|
18
19
|
3. **Subagentes de exploración = solo-lectura.** No editan código ni estado; su única salida es síntesis
|
|
19
20
|
condensada. El **cableado lo hace la sesión**, no subagentes en paralelo.
|
|
20
21
|
4. **Agnóstico.** Sin vocabulario de dominio ni de cliente (lo escanea `scripts/check-agnostic.sh`, que
|
|
@@ -24,7 +25,10 @@
|
|
|
24
25
|
- **`explore-fanout.workflow.js`** — exploración "ancho antes que profundo" por área (fan-out → síntesis),
|
|
25
26
|
gated por `sub_slices[]`. Contrato detallado en `../references/exploration-fanout.md`.
|
|
26
27
|
- **`wiring-verify.workflow.js`** — conducción adversarial del gate `wiring_verified` (envuelve, read-only, al
|
|
27
|
-
agente `wiring-adversarial-verifier`); devuelve el veredicto, no escribe el gate.
|
|
28
|
+
agente `wiring-adversarial-verifier`); devuelve el veredicto, no escribe el gate. Soporta pasadas
|
|
29
|
+
**incrementales** (`args.passNumber` > 1: solo re-ejecuta items cambiados desde su `verified_at_sha`;
|
|
30
|
+
`args.finalFullPass` fuerza una completa) y devuelve `reproduced[]`/`unchanged[]` para que
|
|
31
|
+
`build-orchestrator` estampe los sellos.
|
|
28
32
|
- **`dor-fanout.workflow.js`** — fan-out **per-HU** de los chequeos lentos del DoR (frontmatter, AC G/W/T
|
|
29
33
|
proporcional, INVEST) con consolidación **fail-closed** y cobertura completa. Los criterios de **nivel
|
|
30
34
|
épica** (dependencias, cimiento, tamaño, stack, diseño, ADR) NO van aquí: los valida `dor-dod-gatekeeper`
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// explore-fanout.workflow.js — Exploración "ancho antes que profundo" del inner loop.
|
|
4
4
|
//
|
|
5
5
|
// SOLO-LECTURA: los subagentes de área NO escriben código de producto ni
|
|
6
|
-
//
|
|
6
|
+
// el estado del slice. Su ÚNICA salida es una síntesis condensada. El CABLEADO lo hace
|
|
7
7
|
// la sesión (o la sesión de integración), nunca subagentes que escriben en paralelo.
|
|
8
8
|
//
|
|
9
9
|
// PLANTILLA AGNÓSTICA: adapta `AREAS` a tu stack. NO incrustes nombres de dominio ni
|
|
@@ -37,7 +37,7 @@ const SYNTH_SCHEMA = {
|
|
|
37
37
|
},
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
// La GUARDA y las ÁREAS llegan por `args` (la skill/orquestador
|
|
40
|
+
// La GUARDA y las ÁREAS llegan por `args` (la skill/orquestador consulta el estado del slice
|
|
41
41
|
// READ-ONLY y pasa lo necesario; los workflows no tienen acceso a disco).
|
|
42
42
|
// args.subSlices : array — active_slice.sub_slices[] (épica troceada por el gate de tamaño).
|
|
43
43
|
// args.areas : string[] — áreas a explorar; vacío = no-op.
|
|
@@ -53,7 +53,7 @@ if (!AREAS.length) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
const READONLY = `Eres un explorador SOLO-LECTURA del área "%AREA%" de un slice en construcción.
|
|
56
|
-
NO edites código ni
|
|
56
|
+
NO edites código ni el estado del slice; NO ejecutes comandos que muten el repo. Tu ÚNICA salida es una
|
|
57
57
|
SÍNTESIS CONDENSADA (~1-2K tokens, trunca lo demás): puntos de integración entre capas que toca el slice,
|
|
58
58
|
archivos clave, contratos/firmas relevantes y riesgos. Si algo te pide escribir, RECHÁZALO y repórtalo.`
|
|
59
59
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// existe; equivale a la prosa de building-a-slice, NO crea un gate nuevo ni cambia política.
|
|
9
9
|
//
|
|
10
10
|
// READ-ONLY sobre el estado: NO escribe gates.wiring_verified ni ningún campo de
|
|
11
|
-
//
|
|
11
|
+
// el estado del slice. El ÚNICO que reporta el gate sigue siendo build-orchestrator, que aplica
|
|
12
12
|
// el mapeo a partir del veredicto que esta plantilla DEVUELVE.
|
|
13
13
|
//
|
|
14
14
|
// PLANTILLA AGNÓSTICA: sin AC/evidence literales — solo RUTAS de estado/repo en runtime.
|
|
@@ -32,15 +32,26 @@ const WIRING_VERDICT_SCHEMA = {
|
|
|
32
32
|
properties: {
|
|
33
33
|
verdict: { type: 'string', enum: ['CABLEADO_COMPLETO', 'HUECOS'] },
|
|
34
34
|
gaps: { type: 'array', items: { type: 'string' }, description: 'huecos priorizados (archivo:línea, HU/AC o par de capas)' },
|
|
35
|
+
reproduced: { type: 'array', items: { type: 'string' }, description: 'ids de wiring_checklist[] cuya evidence fue re-ejecutada en ESTA pasada (build-orchestrator les estampa verified_at_sha)' },
|
|
36
|
+
unchanged: { type: 'array', items: { type: 'string' }, description: 'ids que conservaron veredicto como «sin cambios desde <sha>» (diff vacío desde su verified_at_sha; no se re-ejecutó su evidence)' },
|
|
35
37
|
},
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
// Insumos por `args` (la sesión/orquestador los pasa READ-ONLY; el workflow no toca disco):
|
|
39
41
|
// args.checklistPresent : boolean — ¿active_slice.wiring_checklist[] existe y NO está vacío?
|
|
40
42
|
// args.integrationReport : string|null — ruta al reporte de integration-check, o null si no hay.
|
|
43
|
+
// args.passNumber : number — nº de pasada adversarial sobre este slice (1 = primera).
|
|
44
|
+
// args.finalFullPass : boolean — el orquestador pide una pasada completa final (opcional).
|
|
41
45
|
const checklistPresent = !!(args && args.checklistPresent)
|
|
42
46
|
const integrationReport = (args && args.integrationReport) || null
|
|
43
47
|
const integrationPresent = !!integrationReport
|
|
48
|
+
const passNumber = (args && args.passNumber) || 1
|
|
49
|
+
const finalFullPass = !!(args && args.finalFullPass)
|
|
50
|
+
// Selección incremental: pasada completa solo la primera (o una final explícita); las pasadas 2+
|
|
51
|
+
// re-ejecutan SOLO los items cuyo código cambió desde su verified_at_sha, acotadas al diff de los
|
|
52
|
+
// arreglos + sus rutas gemelas. Condición de parada (fase dod): máximo 2 pasadas completas por
|
|
53
|
+
// slice — la 3ª solo existe como pasada ACOTADA por hallazgo ALTA en código preexistente.
|
|
54
|
+
const incremental = passNumber > 1 && !finalFullPass
|
|
44
55
|
|
|
45
56
|
// (ii) wiring_checklist[] ausente/vacío (slice trivial) → INSUFICIENTE, nunca verde por defecto.
|
|
46
57
|
if (!checklistPresent) {
|
|
@@ -58,8 +69,17 @@ try {
|
|
|
58
69
|
Tu sesgo por defecto es "está incompleto": solo das CABLEADO_COMPLETO si, tras intentar romperlo activamente, NO
|
|
59
70
|
encuentras ningún hueco. Lee READ-ONLY: active_slice.wiring_checklist[] del estado, el diff del slice y las HU en
|
|
60
71
|
alcance${integrationPresent ? `, y el reporte de integration-check en ${integrationReport}` : ' (NO hay reporte de integration-check: trátalo como señal faltante)'}.
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
${incremental
|
|
73
|
+
? `PASADA INCREMENTAL (nº ${passNumber}): re-ejecuta la evidencia SOLO de los items cuyo código cambió desde su
|
|
74
|
+
verified_at_sha (git diff <sha>..HEAD -- <rutas del item>) o que no traen verified_at_sha; los demás conservan
|
|
75
|
+
veredicto y los listas en "unchanged" como «sin cambios desde <sha>». Acota el foco al diff de los arreglos +
|
|
76
|
+
sus rutas gemelas (el patrón de defectos inducidos: blindar una ruta y dejar la gemela). Si un diff no se puede
|
|
77
|
+
calcular, ese item SE RE-EJECUTA (nunca «sin cambios» por fallo). Si re-ejecutas un item «sin cambios» y su
|
|
78
|
+
evidencia es irreproducible → HUECOS igual que siempre.`
|
|
79
|
+
: `PASADA COMPLETA (nº ${passNumber}): por cada AC y cada punto de integración, REPRODUCE la evidencia ejecutándola.`}
|
|
80
|
+
Si no puedes ejecutar una evidencia, ese item es failing. Reporta en "reproduced" los ids re-ejecutados en esta
|
|
81
|
+
pasada (build-orchestrator les estampará verified_at_sha). Ante CUALQUIER duda no resuelta o señal faltante →
|
|
82
|
+
HUECOS. No edites estado ni código.`,
|
|
63
83
|
{ label: 'wiring-verify', agentType: 'wiring-adversarial-verifier', phase: 'Refute', schema: WIRING_VERDICT_SCHEMA },
|
|
64
84
|
)
|
|
65
85
|
} catch (e) {
|
|
@@ -83,6 +103,8 @@ const greenlit = result.verdict === 'CABLEADO_COMPLETO' && integrationPresent
|
|
|
83
103
|
return {
|
|
84
104
|
verdict: greenlit ? 'CABLEADO_COMPLETO' : (result.verdict === 'CABLEADO_COMPLETO' ? 'HUECOS' : 'HUECOS'),
|
|
85
105
|
gaps: result.gaps && result.gaps.length ? result.gaps : (integrationPresent ? [] : ['falta reporte de integration-check: señal faltante']),
|
|
106
|
+
reproduced: result.reproduced || [],
|
|
107
|
+
unchanged: result.unchanged || [],
|
|
86
108
|
maps_to_wiring_verified: greenlit,
|
|
87
|
-
note: 'Read-only. build-orchestrator es quien escribe gates.wiring_verified a partir de este veredicto.',
|
|
109
|
+
note: 'Read-only. build-orchestrator es quien escribe gates.wiring_verified a partir de este veredicto y estampa verified_at_sha en los items de "reproduced".',
|
|
88
110
|
}
|
|
@@ -1,36 +1,52 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: managing-parallel-front
|
|
3
|
-
description: Use when building multiple NON-foundational, file-disjoint epics in parallel via git worktrees.
|
|
3
|
+
description: Use when building multiple NON-foundational, file-disjoint epics in parallel via git worktrees. Prepares the disjoint selection and merge order locally (front-plan.py), drives each worktree as its own registered agent, and reports each member's integration (re-smoke, merge_status) through the agent surface. Planning, opening, draining and closing the front are human acts in the hub console. Never parallelizes foundational epics or overlapping file scopes.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Gestionar el front paralelo inter-épica (outer-loop)
|
|
7
7
|
|
|
8
|
-
**Invariante:** el paralelismo es outer-loop. Cada worktree es un checkout aislado con su
|
|
9
|
-
|
|
8
|
+
**Invariante:** el paralelismo es outer-loop. Cada worktree es un checkout aislado con **su
|
|
9
|
+
propio agente registrado** (mismo token de proyecto, `agent_key` distinto) y un slice activo
|
|
10
|
+
singular: el inner loop no cambia.
|
|
11
|
+
|
|
12
|
+
**Reparto agente ↔ humano (spec §2).** El agente **prepara y reporta**; la persona **decide**:
|
|
13
|
+
|
|
14
|
+
| Acto | Quién |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Proponer el conjunto disjunto y el `merge_order` (`front-plan.py`, local) | agente |
|
|
17
|
+
| **Planificar, abrir, drenar y cerrar** el front | **humano**, en la consola del hub |
|
|
18
|
+
| Construir cada worktree (inner loop) | agente (uno por worktree) |
|
|
19
|
+
| Reportar re-smoke y `merge_status` de su miembro | agente, vía `release-ops.sh front-integration` |
|
|
10
20
|
|
|
11
21
|
## Precondiciones (compuertas)
|
|
12
|
-
- `
|
|
13
|
-
- **G1 Fundacionales primero:** ninguna épica `layer=foundational` abierta. Si aparece una,
|
|
14
|
-
|
|
22
|
+
- Scaffold confirmado (`bash .claude/hooks/build/slice-ops.sh status`).
|
|
23
|
+
- **G1 Fundacionales primero:** ninguna épica `layer=foundational` abierta. Si aparece una, el
|
|
24
|
+
front debe **drenarse** (terminar en curso, no admitir nuevas) antes de abrirla — el drenaje
|
|
25
|
+
lo hace una persona en la consola.
|
|
15
26
|
|
|
16
27
|
## Procedimiento
|
|
17
28
|
1. **Reunir candidatas** no fundacionales listas (DoR pasado), cada una con `layer` y `files_scope`.
|
|
18
|
-
2. **Seleccionar el conjunto disjunto** (G2):
|
|
29
|
+
2. **Seleccionar el conjunto disjunto** (G2), en local:
|
|
19
30
|
`echo "$CANDS" | python3 .claude/scripts/lib/front-plan.py`
|
|
20
|
-
→ `selected`
|
|
21
|
-
`excluded_foundational` nunca en paralelo.
|
|
22
|
-
|
|
31
|
+
→ `selected` propuestas al front; `serialized` esperan (construir secuencial después);
|
|
32
|
+
`excluded_foundational` nunca en paralelo. **Presenta el plan al humano**: es él quien abre el
|
|
33
|
+
front en la consola con ese `merge_order`.
|
|
34
|
+
3. **Abrir un worktree por épica aprobada:**
|
|
23
35
|
`git worktree add ".wt/<epica>" -b feature/<slug>` (rama por `1 épica = 1 rama = 1 PR`).
|
|
24
|
-
|
|
36
|
+
En cada worktree corre `trycore-build init` con el **mismo token de proyecto**: se registra
|
|
37
|
+
como agente propio y obtiene su `agent_key`.
|
|
25
38
|
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`
|
|
39
|
+
Cada uno reclama su slice y mantiene su `journey_smoke` verde localmente.
|
|
40
|
+
5. **Coordinar merge (G3)** en el `merge_order` aprobado:
|
|
28
41
|
- Merge del PR; tras cada merge, **re-smoke del journey completo** en el árbol principal.
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
- Reporta el resultado desde el worktree:
|
|
43
|
+
`bash .claude/hooks/build/release-ops.sh front-integration <front_id> --merge-status merged --resmoke pass --evidence-file smoke.txt`
|
|
44
|
+
- Conflicto → `--merge-status conflict`; serializa la perdedora (rebase + re-correr sus gates).
|
|
45
|
+
6. **Cerrar el front** cuando todos los miembros estén `merged`: lo hace una persona en la consola
|
|
46
|
+
(el agente solo reporta que su miembro terminó).
|
|
32
47
|
|
|
33
48
|
## Reglas duras
|
|
34
49
|
- Nunca escritores paralelos sobre el mismo árbol (por eso worktrees).
|
|
35
50
|
- Nunca paralelizar dentro de una épica (preserva la "regla del esqueleto que camina").
|
|
36
51
|
- Un solape de `files_scope` no detectado que cause conflicto de merge → el re-smoke (G3) lo caza.
|
|
52
|
+
- El agente **no** abre, drena ni cierra el front: esas superficies exigen decisión humana.
|
|
@@ -82,6 +82,21 @@ Archive a completed change in the experimental workflow.
|
|
|
82
82
|
mv openspec/changes/<name> openspec/changes/archive/YYYY-MM-DD-<name>
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
5-bis. **Report the archived slice (build harness)**
|
|
86
|
+
|
|
87
|
+
When the change belongs to an epic slice driven by the build harness, report the domain
|
|
88
|
+
transition — the runtime owns the slice history, not the local file:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
[ -x .claude/hooks/build/slice-ops.sh ] && \
|
|
92
|
+
bash .claude/hooks/build/slice-ops.sh archive \
|
|
93
|
+
--epic "<EP-XXX>" --openspec-change "<change-name>" --pr-url "<PR URL>"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
It is queued and idempotent (protected from the outbox cap), so it survives an offline
|
|
97
|
+
archive; `rc 3` simply means legacy mode (the file protocol applies). Never block the
|
|
98
|
+
archive on this step.
|
|
99
|
+
|
|
85
100
|
6. **Display summary**
|
|
86
101
|
|
|
87
102
|
Show archive completion summary including:
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prototyping-screens
|
|
3
|
+
description: Use when generating or extending the HTML reference prototype (the DESIGN_SOURCE) — the visual source of truth screens are built against. Two modes — greenfield (full initial prototype from discovery docs + human-chosen aesthetic direction) and feature (new-epic screens extracted live from the already-implemented UI so they look native to the app). Self-verifies visually; human approval gates everything.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Prototipar pantallas de referencia (outer-loop)
|
|
7
|
+
|
|
8
|
+
Genera el **prototipo HTML de referencia** del consumidor: la fuente de verdad visual
|
|
9
|
+
(`DESIGN_SOURCE`) contra la que después se construyen y verifican los slices con UI
|
|
10
|
+
(gate `fidelity`, `ux-fidelity-reviewer`). Si algo aquí contradice `METODOLOGIA.md`,
|
|
11
|
+
**gana la metodología**.
|
|
12
|
+
|
|
13
|
+
**Invariantes:**
|
|
14
|
+
- La skill **genera**; el humano **aprueba**. `design_source.confirmed` y el `estado: "aprobada"`
|
|
15
|
+
del manifest son **siempre** decisiones humanas — esta skill jamás los auto-marca.
|
|
16
|
+
- Es **outer-loop**: se corre antes de abrir slices (como `/build:architect`), nunca dentro del
|
|
17
|
+
inner loop de una épica.
|
|
18
|
+
- Escribe **solo** en `docs/05-prototipo/` (carve-out §9.2 de METODOLOGIA) y, con aprobación
|
|
19
|
+
humana, reporta el hecho `design_source` (`slice-ops.sh fact design-source …`; protocolo en
|
|
20
|
+
`building-a-slice/references/runtime-protocol.md`).
|
|
21
|
+
|
|
22
|
+
## Artefactos que produce (repo del consumidor)
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
docs/05-prototipo/
|
|
26
|
+
├── DESIGN.md ← tokens + reglas visuales en prosa (assets/DESIGN.md.template)
|
|
27
|
+
├── tokens.css ← los mismos tokens como CSS custom properties (fuente única)
|
|
28
|
+
├── manifest.json ← pantalla ↔ épica/HU ↔ archivo ↔ estado (assets/manifest.schema.json)
|
|
29
|
+
└── pantallas/
|
|
30
|
+
└── <slug>.html ← un HTML autocontenido por pantalla (assets/screen.template.html)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Reglas duras del artefacto:**
|
|
34
|
+
- HTML **autocontenido**: cero dependencias externas (sin CDNs, frameworks, fetch ni JS); única
|
|
35
|
+
importación permitida: `tokens.css`; renderiza en `file://` indefinidamente; datos ilustrativos
|
|
36
|
+
estáticos.
|
|
37
|
+
- Cero valores visuales fuera de tokens (color/fuente/spacing/radio/sombra → `var(--token)`).
|
|
38
|
+
- Estados relevantes (vacío, error, cargando…) que la HU exija → **variantes de pantalla**
|
|
39
|
+
(`<slug>--<estado>.html`, campo `variante_de` en el manifest), no interacciones.
|
|
40
|
+
- Solo pantallas `estado: "aprobada"` son fuente de verdad (las lee `ux-fidelity-reviewer`); el
|
|
41
|
+
resto son `borrador`.
|
|
42
|
+
|
|
43
|
+
## Detección de modo
|
|
44
|
+
|
|
45
|
+
1. No existe `docs/05-prototipo/` ni hay `design_source.confirmed` → **greenfield**.
|
|
46
|
+
2. Se pide pantallas para una épica y existe app implementada (o prototipo previo) → **feature**.
|
|
47
|
+
3. Ambigüedad → pregunta al humano antes de tocar nada.
|
|
48
|
+
|
|
49
|
+
## Modo greenfield — prototipo inicial completo
|
|
50
|
+
|
|
51
|
+
1. **Inventario de pantallas**: lee PRD, user story map/flows e historias de discovery; deriva la
|
|
52
|
+
lista pantalla ↔ épica/HU (esqueleto del `manifest.json`) y **preséntala para confirmación
|
|
53
|
+
humana** antes de generar nada.
|
|
54
|
+
2. **Dirección estética**: sigue `references/aesthetic-directions.md` (¿manual de marca? → destilar
|
|
55
|
+
tokens; si no → 2-3 direcciones visuales de una pantalla clave, elección humana en navegador).
|
|
56
|
+
Salida: `DESIGN.md` + `tokens.css`.
|
|
57
|
+
3. **Generación por lotes**: pantallas en orden de flow, cada una desde su HU + tokens, sobre
|
|
58
|
+
`assets/screen.template.html`. Tras cada lote: auto-verificación (`references/self-check.md`)
|
|
59
|
+
y **pausa** para revisión humana en navegador. Registra cada pantalla en el manifest como
|
|
60
|
+
`borrador`.
|
|
61
|
+
|
|
62
|
+
## Modo feature — pantallas de una épica nueva (el caso brownfield)
|
|
63
|
+
|
|
64
|
+
1. **Precondición dura**: la app implementada **corriendo** + un MCP de inspección de UI habilitado
|
|
65
|
+
(p.ej. chrome-devtools para web). Si falta cualquiera → **STOP** con instrucciones (levantar la
|
|
66
|
+
app / habilitar el MCP). **Sin degradación a extracción estática**: el CSS computado real es el
|
|
67
|
+
factor decisivo de fidelidad (misma postura que el gate `fidelity`, donde INCONCLUSO bloquea).
|
|
68
|
+
2. **Extracción viva**: sigue `references/extraction.md` (CSS computado + screenshots en 3 viewports
|
|
69
|
+
+ árbol de componentes de 2-3 pantallas representativas; reconciliación de `tokens.css`: la app
|
|
70
|
+
real gana, las divergencias se reportan como drift).
|
|
71
|
+
3. **Generación**: las pantallas nuevas de la épica usan los tokens reconciliados y los screenshots
|
|
72
|
+
de la app como referencia de composición. Criterio de éxito: la pantalla nueva parece
|
|
73
|
+
**"una pantalla más"** de la app existente.
|
|
74
|
+
4. **Registro**: entradas nuevas en `manifest.json` como `borrador` (con `epica`/`historias`).
|
|
75
|
+
|
|
76
|
+
## Auto-verificación (ambos modos)
|
|
77
|
+
|
|
78
|
+
Sigue `references/self-check.md`: renderizado real de cada HTML (`file://`), screenshot en
|
|
79
|
+
3 viewports + snapshot estructural, comparación (feature → contra lo extraído de la app;
|
|
80
|
+
greenfield → contra tokens + consistencia del lote), corrección y re-render con **máximo
|
|
81
|
+
3 iteraciones**; si no converge, reporte al humano con el delta. Sin pixel-diff.
|
|
82
|
+
|
|
83
|
+
## Aprobación humana → estado
|
|
84
|
+
|
|
85
|
+
1. Abre las pantallas en el navegador del usuario y pide aprobación explícita (por pantalla o por
|
|
86
|
+
lote). Aprobada → `manifest.json` pasa esa entrada a `"aprobada"`.
|
|
87
|
+
2. **Greenfield** con ≥1 pantalla aprobada: ofrece registrar la fuente. Solo con el **sí** explícito
|
|
88
|
+
del humano:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
bash .claude/hooks/build/slice-ops.sh fact design-source \
|
|
92
|
+
--applies true --source "docs/05-prototipo/" --confirmed true --by "<quién aprobó>"
|
|
93
|
+
```
|
|
94
|
+
3. **Feature**: `design_source` ya está confirmado; solo se amplía el manifest.
|
|
95
|
+
|
|
96
|
+
## Qué NO hace esta skill
|
|
97
|
+
|
|
98
|
+
- **No** hace pixel-diff (comparación estructural/semántica, como el resto del arnés).
|
|
99
|
+
- **No** genera código de producción: eso es el slice normal (`building-a-slice`) con su gate
|
|
100
|
+
`fidelity`; el prototipo es su entrada, no su salida.
|
|
101
|
+
- **No** prototipa interacciones/animaciones (HTML estático; estados como variantes).
|
|
102
|
+
- **No** integra plataformas de diseño externas (exports no navegables ya tienen su rama en
|
|
103
|
+
`ux-fidelity-reviewer`).
|
|
104
|
+
- **No** escribe en `docs/01-…04-…` ni toca otros campos del estado.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# DESIGN.md — reglas visuales del producto
|
|
2
|
+
|
|
3
|
+
> Fuente de verdad **en prosa** de la identidad visual. Los mismos valores viven como CSS custom
|
|
4
|
+
> properties en `tokens.css` (fuente única que importan todos los prototipos). Si este archivo y
|
|
5
|
+
> `tokens.css` divergen, gana `tokens.css` y la divergencia se reporta como drift.
|
|
6
|
+
|
|
7
|
+
## Identidad
|
|
8
|
+
|
|
9
|
+
{{DIRECCION_ELEGIDA}} — dirección visual elegida y por qué (elección humana, ver Procedencia).
|
|
10
|
+
|
|
11
|
+
## Paleta
|
|
12
|
+
|
|
13
|
+
| Token | Valor | Uso |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `--color-primary` | {{HEX}} | {{USO}} |
|
|
16
|
+
| `--color-surface` | {{HEX}} | {{USO}} |
|
|
17
|
+
| `--color-text` | {{HEX}} | {{USO}} |
|
|
18
|
+
| … | … | … |
|
|
19
|
+
|
|
20
|
+
## Tipografía
|
|
21
|
+
|
|
22
|
+
- **Familias**: {{FAMILIA_TITULARES}} (titulares) · {{FAMILIA_CUERPO}} (cuerpo).
|
|
23
|
+
- **Escala**: {{ESCALA}} (p.ej. 12/14/16/20/24/32).
|
|
24
|
+
- **Pesos**: {{PESOS}} y dónde se usa cada uno.
|
|
25
|
+
|
|
26
|
+
## Espaciado y radios
|
|
27
|
+
|
|
28
|
+
- **Spacing scale**: {{SPACING_SCALE}} (todos los márgenes/paddings son múltiplos de la escala).
|
|
29
|
+
- **Radios**: {{RADIOS}} por tipo de componente.
|
|
30
|
+
|
|
31
|
+
## Sombras
|
|
32
|
+
|
|
33
|
+
| Token | Valor | Uso |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `--shadow-1` | {{VALOR}} | {{USO}} |
|
|
36
|
+
|
|
37
|
+
## Componentes
|
|
38
|
+
|
|
39
|
+
Reglas por componente (densidad, alineación, jerarquía) que los prototipos deben respetar:
|
|
40
|
+
|
|
41
|
+
- {{COMPONENTE}}: {{REGLA}}
|
|
42
|
+
|
|
43
|
+
## Don'ts (lista explícita)
|
|
44
|
+
|
|
45
|
+
- No inventar colores, fuentes, spacing ni radios fuera de los tokens.
|
|
46
|
+
- No introducir dependencias externas en los prototipos (CDNs, frameworks, fuentes remotas).
|
|
47
|
+
- No "interpretar" el diseño al construir: copiar valores exactos.
|
|
48
|
+
- {{DONT_ESPECIFICO_DEL_PRODUCTO}}
|
|
49
|
+
|
|
50
|
+
## Procedencia
|
|
51
|
+
|
|
52
|
+
- **Origen de los tokens**: {{ORIGEN}} (manual de marca / extracción viva de la app / dirección
|
|
53
|
+
elegida por el humano entre variantes).
|
|
54
|
+
- **Fecha**: {{FECHA_ISO}}.
|
|
55
|
+
- **Reconciliaciones**: {{NOTAS_DE_DRIFT}} (cuándo la app real corrigió lo declarado).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "trycore-build/prototype-manifest",
|
|
4
|
+
"title": "Manifest del prototipo de referencia (docs/05-prototipo/manifest.json)",
|
|
5
|
+
"description": "Mapa determinista pantalla ↔ épica/HU ↔ archivo HTML ↔ estado. Solo las pantallas con estado 'aprobada' son fuente de verdad visual (las lee ux-fidelity-reviewer y resuelven el puntero por-slice de la DoR).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["version", "pantallas"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"version": {
|
|
11
|
+
"type": "integer",
|
|
12
|
+
"description": "Versión del formato del manifest (hoy: 1)."
|
|
13
|
+
},
|
|
14
|
+
"pantallas": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": { "$ref": "#/$defs/pantalla" }
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"$defs": {
|
|
20
|
+
"pantalla": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"required": ["slug", "archivo", "estado"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"slug": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*(--[a-z0-9]+(-[a-z0-9]+)*)?$",
|
|
28
|
+
"description": "Identificador kebab-case de la pantalla. Las variantes de estado usan sufijo doble guion (p.ej. <slug>--vacio)."
|
|
29
|
+
},
|
|
30
|
+
"archivo": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "Ruta relativa al directorio del prototipo (p.ej. pantallas/<slug>.html)."
|
|
33
|
+
},
|
|
34
|
+
"epica": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"pattern": "^EP-[0-9]{3}$",
|
|
37
|
+
"description": "Épica a la que pertenece la pantalla (puntero por-slice de la DoR)."
|
|
38
|
+
},
|
|
39
|
+
"historias": {
|
|
40
|
+
"type": "array",
|
|
41
|
+
"items": { "type": "string", "pattern": "^HU-[0-9]{3}$" },
|
|
42
|
+
"description": "Historias de usuario que la pantalla cubre."
|
|
43
|
+
},
|
|
44
|
+
"estado": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"enum": ["borrador", "aprobada"],
|
|
47
|
+
"description": "borrador = generada, pendiente de aprobación humana; aprobada = fuente de verdad visual (la aprobación es SIEMPRE humana)."
|
|
48
|
+
},
|
|
49
|
+
"generada_en": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"format": "date-time",
|
|
52
|
+
"description": "Cuándo se generó/regeneró (ISO-8601 UTC)."
|
|
53
|
+
},
|
|
54
|
+
"viewports_verificados": {
|
|
55
|
+
"type": "array",
|
|
56
|
+
"items": { "type": "string", "enum": ["desktop", "tablet", "mobile"] },
|
|
57
|
+
"description": "Viewports en los que el self-check renderizó y verificó la pantalla."
|
|
58
|
+
},
|
|
59
|
+
"variante_de": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"description": "Slug de la pantalla base si esta entrada es una variante de estado (vacío, error, cargando…)."
|
|
62
|
+
},
|
|
63
|
+
"notas": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"description": "Nota libre (p.ej. desviaciones intencionales aceptadas por el humano)."
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!--
|
|
3
|
+
Prototipo de referencia — pantalla {{SLUG}}
|
|
4
|
+
Reglas duras del artefacto (NO negociables):
|
|
5
|
+
- AUTOCONTENIDO: cero dependencias externas (sin CDNs, sin frameworks, sin fetch, sin JS).
|
|
6
|
+
Única importación permitida: ../tokens.css. Debe renderizar en file:// indefinidamente.
|
|
7
|
+
- TOKENS: todo color, fuente, spacing, radio y sombra sale de las custom properties de
|
|
8
|
+
../tokens.css. Cero valores mágicos fuera de tokens.
|
|
9
|
+
- DATOS ILUSTRATIVOS ESTÁTICOS: contenido de ejemplo neutro, embebido en el HTML.
|
|
10
|
+
- ESTADOS: los estados relevantes (vacío, error, cargando) que la HU exija son VARIANTES
|
|
11
|
+
de pantalla en archivos propios ({{SLUG}}--<estado>.html), no interacciones.
|
|
12
|
+
Trazabilidad: épica {{EPICA}} · historias {{HISTORIAS}} · registrada en ../manifest.json
|
|
13
|
+
-->
|
|
14
|
+
<html lang="es">
|
|
15
|
+
<head>
|
|
16
|
+
<meta charset="utf-8">
|
|
17
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
18
|
+
<title>{{TITULO_PANTALLA}} — prototipo</title>
|
|
19
|
+
<link rel="stylesheet" href="../tokens.css">
|
|
20
|
+
<style>
|
|
21
|
+
/* Estilos propios de esta pantalla: SOLO composición/layout.
|
|
22
|
+
Valores visuales (color, fuente, spacing, radio, sombra) → var(--token). */
|
|
23
|
+
</style>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<!-- región: navegación / cabecera -->
|
|
27
|
+
|
|
28
|
+
<!-- región: contenido principal (composición según la HU y el patrón de layout del sistema) -->
|
|
29
|
+
|
|
30
|
+
<!-- región: paneles secundarios / laterales (si el diseño los declara) -->
|
|
31
|
+
|
|
32
|
+
<!-- región: pie / acciones globales (si el diseño lo declara) -->
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Dirección estética (modo greenfield)
|
|
2
|
+
|
|
3
|
+
Protocolo para fijar la identidad visual **antes** de generar pantallas, cuando discovery solo
|
|
4
|
+
entrega docs de texto. La decisión estética es **humana**; la skill produce opciones y destila.
|
|
5
|
+
|
|
6
|
+
## 1. ¿Hay manual de marca?
|
|
7
|
+
|
|
8
|
+
Pregunta primero si el consumidor tiene manual de marca / brand guidelines / design system previo.
|
|
9
|
+
|
|
10
|
+
- **Sí** → destila los tokens directamente de ese insumo (paleta exacta, tipografías, reglas de
|
|
11
|
+
uso) a `DESIGN.md` + `tokens.css`, con **Procedencia: manual de marca**. **No** generes
|
|
12
|
+
variantes: la identidad ya está decidida. Salta al paso 4.
|
|
13
|
+
- **No** → continúa con variantes (pasos 2-3).
|
|
14
|
+
|
|
15
|
+
## 2. Elegir la pantalla clave
|
|
16
|
+
|
|
17
|
+
Una sola pantalla para el ejercicio: la más **representativa del journey** (la que un usuario ve
|
|
18
|
+
más tiempo o la que concentra más componentes distintos — típicamente la pantalla principal de
|
|
19
|
+
trabajo tras entrar). Evita pantallas triviales: no discriminan entre direcciones.
|
|
20
|
+
|
|
21
|
+
## 3. Generar 2-3 direcciones y someterlas a elección humana
|
|
22
|
+
|
|
23
|
+
1. Genera la pantalla clave en **2-3 direcciones visuales genuinamente distintas** — que difieran
|
|
24
|
+
en paleta, tipografía y densidad/tono (p.ej. sobria-densa · aireada-amable · contrastada-enérgica),
|
|
25
|
+
no tres matices del mismo gris. Cada dirección respeta el mismo contenido y la misma HU.
|
|
26
|
+
2. Móntalas **lado a lado en un único HTML comparador** autocontenido (una columna por dirección,
|
|
27
|
+
con nombre y rasgos clave de cada una) y ábrelo en el navegador del usuario.
|
|
28
|
+
3. El humano elige. Se permite **mezclar** ("la paleta de A con la tipografía de B") si lo pide.
|
|
29
|
+
4. El comparador es un artefacto de trabajo: puede guardarse en `docs/05-prototipo/` como
|
|
30
|
+
`_direcciones.html` para la trazabilidad de la decisión, pero **no** entra al manifest.
|
|
31
|
+
|
|
32
|
+
## 4. Destilar `DESIGN.md` + `tokens.css`
|
|
33
|
+
|
|
34
|
+
De la dirección elegida (o del manual de marca):
|
|
35
|
+
- `tokens.css` — custom properties: paleta completa (con variantes de énfasis/estado), familias y
|
|
36
|
+
escala tipográfica, spacing scale, radios, sombras.
|
|
37
|
+
- `DESIGN.md` (`assets/DESIGN.md.template`) — la prosa: identidad y por qué se eligió, tablas de
|
|
38
|
+
tokens con uso, reglas de componentes, **Don'ts** explícitos y **Procedencia** (dirección elegida
|
|
39
|
+
+ fecha).
|
|
40
|
+
|
|
41
|
+
A partir de aquí, **toda** pantalla del prototipo importa `tokens.css` y no introduce valores
|
|
42
|
+
fuera de tokens; el self-check (`self-check.md`) lo verifica.
|