@trycore/spec-build-harness 0.11.0 → 0.11.1
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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "trycore-spec-build-harness",
|
|
4
4
|
"displayName": "Trycore — Spec & Build Harness",
|
|
5
|
-
"version": "0.11.
|
|
5
|
+
"version": "0.11.1",
|
|
6
6
|
"description": "Arnés de construcción de dos loops (slice por épica + release gate) para Claude Code, con gates de calidad, estado compartido y OpenSpec. Compañero de @trycore/spec-product-flow. Agnóstico al proyecto.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Trycore",
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.11.
|
|
1
|
+
0.11.1
|
|
@@ -70,8 +70,9 @@ reviewer. Es el gate **no negociable**: sin él, no hay release.
|
|
|
70
70
|
- Reporta **cada** gate medido con
|
|
71
71
|
`bash .claude/hooks/build/release-ops.sh verdict <line> <gate> <pass|fail|na> --evidence-file f`
|
|
72
72
|
(`na` cuando no aplica). El **agregado** lo hace el runtime: **parciales no promueven a `passed`**.
|
|
73
|
-
- Con los seis reportados
|
|
74
|
-
|
|
73
|
+
- Con los seis reportados **en verde, el hub auto-cierra** (`closed_by: AUTO_6_OF_6_PASS`; lo
|
|
74
|
+
anuncia la respuesta del último `verdict`). Si la release queda degradada, el cierre es
|
|
75
|
+
decisión humana en la consola (`release-ops.sh close-hint <line>` imprime la política).
|
|
75
76
|
- Algo ✗ → los hallazgos bloqueantes se corrigen **como un slice normal**
|
|
76
77
|
(`/build:slice` / `building-a-slice`) y se **re-corre** el Release Gate.
|
|
77
78
|
|
|
@@ -83,5 +84,5 @@ reviewer. Es el gate **no negociable**: sin él, no hay release.
|
|
|
83
84
|
vez por release (`O(releases)`).
|
|
84
85
|
- **No dupliques el inner loop**: no se hace TDD ni se cierran gates por slice.
|
|
85
86
|
- **`integration` con deps reales es obligatorio**; no se acepta con todo stubbeado.
|
|
86
|
-
- **El agente reporta
|
|
87
|
+
- **El agente reporta; el verde se auto-cierra; el degradado lo decide un humano** (política A-con-B): ninguna llamada de cierre con token de agente — el auto-cierre lo ejecuta el runtime al agregar, no el cliente.
|
|
87
88
|
- Delega en `releasing-a-version`; **no** la reimplementa. Si algo contradice `METODOLOGIA.md`, gana la metodología.
|
|
@@ -35,7 +35,7 @@ _rel_evidence_json() {
|
|
|
35
35
|
|
|
36
36
|
# ── verdict ──────────────────────────────────────────────────────────────────────────
|
|
37
37
|
cmd_verdict() {
|
|
38
|
-
local line="${1:-}" gate="${2:-}" estado="${3:-}" ev="" evfile="" mode payload resp status pfile
|
|
38
|
+
local line="${1:-}" gate="${2:-}" estado="${3:-}" ev="" evfile="" mode payload resp status pfile rel_status closed_by
|
|
39
39
|
if [ -z "$line" ] || [ -z "$gate" ] || [ -z "$estado" ]; then usage; return $OPS_RC_USAGE; fi
|
|
40
40
|
shift 3
|
|
41
41
|
while [ $# -gt 0 ]; do
|
|
@@ -57,7 +57,7 @@ cmd_verdict() {
|
|
|
57
57
|
esac
|
|
58
58
|
mode="$(ops_mode)"
|
|
59
59
|
[ "$mode" = "legacy" ] && { echo "LEGACY: escribe el gate en releases[] del fichero"; return $OPS_RC_LEGACY; }
|
|
60
|
-
payload="{\"release_line\":$(ops_json_str "$line"),\"gate\":$(ops_json_str "$gate"),\"status\":$(ops_json_str "$estado"),\"evidence\":$(_rel_evidence_json "$ev" "$evfile")}"
|
|
60
|
+
payload="{\"release_line\":$(ops_json_str "$line"),\"gate\":$(ops_json_str "$gate"),\"status\":$(ops_json_str "$estado"),\"verdict\":$(ops_json_str "$(printf %s "$estado" | tr a-z A-Z)"),\"evidence\":$(_rel_evidence_json "$ev" "$evfile")}"
|
|
61
61
|
if [ "$mode" = "dual" ]; then
|
|
62
62
|
pfile="$(ops_tmpjson "$payload")" || return $OPS_RC_OFFLINE
|
|
63
63
|
ops_mirror release_verdict_reported "$pfile" || echo "⚠ veredicto de release no espejado; el comparador dual lo marcará" >&2
|
|
@@ -69,7 +69,30 @@ cmd_verdict() {
|
|
|
69
69
|
case "$status" in
|
|
70
70
|
200|201|202)
|
|
71
71
|
echo "veredicto de release registrado: $gate=$estado en $line"
|
|
72
|
-
|
|
72
|
+
# [A-con-B] El hub auto-cierra la release cuando el ÚLTIMO veredicto de cada uno
|
|
73
|
+
# de los 6 gates canónicos es PASS (closed_by=AUTO_6_OF_6_PASS, queda en el audit
|
|
74
|
+
# trail). Con algún fail/partial el cierre sigue siendo decisión HUMANA en la
|
|
75
|
+
# consola. Fail-open: un hub previo sin release_status cae al recordatorio.
|
|
76
|
+
rel_status="$(printf '%s' "$resp" | python3 -c 'import json,sys
|
|
77
|
+
try:
|
|
78
|
+
print(json.load(sys.stdin).get("release_status") or "")
|
|
79
|
+
except Exception:
|
|
80
|
+
print("")' 2>/dev/null)"
|
|
81
|
+
closed_by="$(printf '%s' "$resp" | python3 -c 'import json,sys
|
|
82
|
+
try:
|
|
83
|
+
print(json.load(sys.stdin).get("closed_by") or "")
|
|
84
|
+
except Exception:
|
|
85
|
+
print("")' 2>/dev/null)"
|
|
86
|
+
case "$rel_status" in
|
|
87
|
+
PASSED)
|
|
88
|
+
echo "✅ release «${line}» CERRADA por el hub: 6/6 gates PASS (closed_by: ${closed_by:-AUTO_6_OF_6_PASS})." ;;
|
|
89
|
+
FAILED)
|
|
90
|
+
echo "⛔ release «${line}» en FAILED en el hub; los hallazgos bloqueantes se corrigen como slice y se re-mide." ;;
|
|
91
|
+
IN_PROGRESS)
|
|
92
|
+
echo "release aún IN_PROGRESS: el hub auto-cierra al llegar el 6/6 PASS; con algún fail/partial el cierre es decisión humana en la consola (spec §2)." ;;
|
|
93
|
+
*)
|
|
94
|
+
echo "El hub auto-cierra con 6/6 PASS; si algún gate queda en fail, el cierre/decisión es humano en la consola (spec §2)." ;;
|
|
95
|
+
esac
|
|
73
96
|
return $OPS_RC_OK ;;
|
|
74
97
|
422)
|
|
75
98
|
echo "⛔ 422 el servidor rechazó el veredicto: $resp — no reintentes; corrige y vuelve a medir." >&2
|
|
@@ -96,11 +119,13 @@ cmd_close_hint() {
|
|
|
96
119
|
local line="${1:-}"
|
|
97
120
|
[ -n "$line" ] || { usage; return $OPS_RC_USAGE; }
|
|
98
121
|
cat <<HINT
|
|
99
|
-
|
|
122
|
+
Política de cierre de la release «${line}» (A-con-B):
|
|
100
123
|
1. El agente reporta los 6 veredictos con \`release-ops.sh verdict $line <gate> <estado>\`.
|
|
101
|
-
2. El runtime agrega:
|
|
102
|
-
|
|
103
|
-
|
|
124
|
+
2. El runtime agrega y AUTO-CIERRA en verde: con el último veredicto de los 6 gates
|
|
125
|
+
canónicos en PASS la release pasa a PASSED (closed_by=AUTO_6_OF_6_PASS, audit trail).
|
|
126
|
+
3. Los casos DEGRADADOS (algún fail/partial, deudas por decidir) siguen siendo gobierno
|
|
127
|
+
humano: una persona con permiso decide y cierra en la consola del hub (PDP).
|
|
128
|
+
Parciales no promueven; el gobierno humano vive donde hay decisión real, no en el clic.
|
|
104
129
|
HINT
|
|
105
130
|
return $OPS_RC_OK
|
|
106
131
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trycore/spec-build-harness",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Arnés agéntico de construcción de Trycore para Claude Code: pipeline de dos loops (slice por épica + release gate) con gates de calidad, estado compartido y OpenSpec. Compañero de @trycore/spec-product-flow. Agnóstico al proyecto.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,9 +24,12 @@ de épicas de la release son las que vas a auditar en bloque.
|
|
|
24
24
|
`dual`/`runtime` la release vive en el runtime y cada gate se reporta con
|
|
25
25
|
`bash .claude/hooks/build/release-ops.sh verdict <line> <gate> <pass|fail|na>`; en `legacy`, en el
|
|
26
26
|
array `releases[]` del fichero local (protocolo en `building-a-slice/references/state-protocol.md`).
|
|
27
|
-
- **Reportar es de agentes;
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
- **Reportar es de agentes; el cierre en verde es del runtime; el degradado es humano** (política
|
|
28
|
+
A-con-B). El agente mide y reporta los seis veredictos; con el último veredicto de los 6 gates
|
|
29
|
+
canónicos en PASS **el hub auto-cierra** la release (`closed_by: AUTO_6_OF_6_PASS`, audit trail).
|
|
30
|
+
Si algún gate queda `fail`/`partial` o hay deudas por decidir, **el cierre es decisión humana en
|
|
31
|
+
la consola** — el gobierno humano vive donde hay decisión real, no en el clic de un resultado
|
|
32
|
+
derivable. `release-ops.sh close-hint <line>` imprime la política.
|
|
30
33
|
- **Sobre el diff acumulado**: el alcance es el rango de commits de todas las épicas de la release
|
|
31
34
|
(desde el merge anterior a la primera épica de la release hasta `main`).
|
|
32
35
|
- **Delega en subagentes** (devuelven síntesis, protegen el contexto).
|
|
@@ -69,8 +72,8 @@ Checklist de cierre: `references/release-dod.md`.
|
|
|
69
72
|
no aplique — p. ej. `ux` en una release sin UI). Un `rc 6` es el servidor rechazando: muestra su
|
|
70
73
|
razón, no reintentes. Sin red, el veredicto **no** tiene camino por la cola offline (`rc 5`,
|
|
71
74
|
issue #44): reintenta el mismo comando cuando vuelva la red, antes de pedir el cierre.
|
|
72
|
-
6.
|
|
73
|
-
|
|
75
|
+
6. Con los seis reportados **en verde, el hub cierra solo** (la respuesta del último `verdict`
|
|
76
|
+
anuncia `release CERRADA … closed_by: AUTO_6_OF_6_PASS`) — no hay paso manual. Si algún gate quedó `fail`,
|
|
74
77
|
lista los hallazgos bloqueantes; el usuario los corrige como un slice normal (fix en
|
|
75
78
|
`building-a-slice`) y se re-corre el Release Gate.
|
|
76
79
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
//
|
|
10
10
|
// READ-ONLY sobre el estado: esta plantilla devuelve un diagnóstico; la skill
|
|
11
11
|
// releasing-a-version es la ÚNICA que reporta los veredictos (release-ops.sh verdict por gate;
|
|
12
|
-
// en modo legacy, una entrada en releases[] del fichero). El agregado y el cierre son del
|
|
12
|
+
// en modo legacy, una entrada en releases[] del fichero). El agregado y el auto-cierre en verde son del
|
|
13
13
|
// runtime/humano. Parciales NO promueven a passed. Si METODOLOGIA.md (§5) contradice algo aquí,
|
|
14
14
|
// gana la metodología.
|
|
15
15
|
//
|
|
@@ -150,11 +150,11 @@ const reviewersGreen = reviews.filter(Boolean).every((r) => r.na || r.value ===
|
|
|
150
150
|
const status = (reviewersGreen && gates.integration === true) ? 'passed' : 'failed'
|
|
151
151
|
|
|
152
152
|
return {
|
|
153
|
-
status, // reportado por releasing-a-version vía release-ops.sh verdict (agregado y cierre son del runtime
|
|
153
|
+
status, // reportado por releasing-a-version vía release-ops.sh verdict (agregado y auto-cierre en verde son del runtime; el degradado lo decide un humano).
|
|
154
154
|
gates, // {security, smell, ux, coherence, stack_arch, integration}
|
|
155
155
|
blocking: [
|
|
156
156
|
...reviews.filter((r) => r && r.value === false).map((r) => ({ gate: r.gate, error: r.error || null, findings: r.findings || [] })),
|
|
157
157
|
...(gates.integration === true ? [] : [{ gate: 'integration', findings: (integration && integration.findings) || [] }]),
|
|
158
158
|
],
|
|
159
|
-
note: 'Read-only. releasing-a-version reporta un veredicto por gate (release-ops.sh verdict). El runtime agrega y
|
|
159
|
+
note: 'Read-only. releasing-a-version reporta un veredicto por gate (release-ops.sh verdict). El runtime agrega y AUTO-CIERRA con 6/6 PASS (closed_by: AUTO_6_OF_6_PASS); el caso degradado lo decide un humano en la consola. Parciales NO promueven a passed.',
|
|
160
160
|
}
|