shapeup-sdlc 3.0.2 → 3.1.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/AGENTS.md +1 -0
- package/README.md +2 -2
- package/commands/hill.md +10 -0
- package/kernel/reduce/hill.mjs +19 -21
- package/package.json +1 -1
- package/skills/hill-chart/SKILL.md +151 -0
- package/skills/hill-chart/assets/dashboard.template.html +1432 -0
- package/skills/tech-lead/references/protocol.md +17 -0
- package/skills/tech-lead/workflows/shapeup-run.js +45 -11
|
@@ -422,6 +422,23 @@ Why it aborts rather than pauses: nothing persists an answer between launches, s
|
|
|
422
422
|
in front of a human once instead of looping silently.
|
|
423
423
|
```
|
|
424
424
|
|
|
425
|
+
## 3b.1 The other reason `--require`/`--set-status` fail: the check never ran
|
|
426
|
+
```
|
|
427
|
+
The abort message names an exit code. `probe resume --require` documents exit 0 (satisfied) or
|
|
428
|
+
6 (artifact genuinely absent) as its only two real answers — anything else means the
|
|
429
|
+
mechanical courier's Bash call was denied before the kernel script ever ran, most often
|
|
430
|
+
an untrusted workspace or Claude Code's own auto-mode classifier flagging the courier's
|
|
431
|
+
--require/--set-status pattern as gate-manipulation. Neither layer is this plugin's own
|
|
432
|
+
hook, so neither leaves a row in .shapeup/<slug>/decisions.jsonl.
|
|
433
|
+
What you see: the same-shaped abort as 3b, but the artifact IS actually on disk — the abort
|
|
434
|
+
message now says so (exit_code shown, courier's own detail quoted) instead of asserting
|
|
435
|
+
"the worker most likely escalated".
|
|
436
|
+
Do: verify the phase's artifact by hand before trusting either diagnosis. If it exists, the
|
|
437
|
+
phase is done; either relaunch (the classifier's denial is not guaranteed to repeat) or
|
|
438
|
+
drive the remaining phase's kernel commands directly rather than through the Workflow —
|
|
439
|
+
this is what routes around a blocked relaunch without waiting on the classifier.
|
|
440
|
+
```
|
|
441
|
+
|
|
425
442
|
## 3c. T0 verify → `harness verify t0` (skill-local; scope contracts present, every attempt)
|
|
426
443
|
```
|
|
427
444
|
Invoke via Bash directly — NOT an Agent, this is deterministic tooling, not a worker:
|
|
@@ -609,7 +609,12 @@ async function cmd(verbs, phaseName, label) {
|
|
|
609
609
|
`Report its exit code as exit_code, ok=true if and only if exit_code is 0, and one line of ` +
|
|
610
610
|
`detail. If the command printed JSON carrying a top-level "decision" key, copy that value into ` +
|
|
611
611
|
`decision EXACTLY as it appears — one bare token, no sentence, no quotes, no rephrasing. ` +
|
|
612
|
-
`Otherwise omit decision. Do not interpret, summarise or act on the command's output beyond that
|
|
612
|
+
`Otherwise omit decision. Do not interpret, summarise or act on the command's output beyond that.\n\n` +
|
|
613
|
+
`If the tool call itself is refused or blocked before the command ever runs — a permission or ` +
|
|
614
|
+
`policy denial, not the command's own exit — that is NOT an exit code, and you must never invent ` +
|
|
615
|
+
`one to fill the field: report exit_code as -1 and put the denial's own wording verbatim in ` +
|
|
616
|
+
`detail. -1 is not a real process exit and this file treats it as "the check could not run", never ` +
|
|
617
|
+
`as evidence about what the command would have said.`,
|
|
613
618
|
{ model: "sonnet", effort: "low", phase: phaseName, label, schema: CMD },
|
|
614
619
|
);
|
|
615
620
|
return (r && typeof r === "object") ? r : { exit_code: -1, ok: false, detail: `${label}: no result` };
|
|
@@ -813,12 +818,29 @@ const attest = (phaseKey, phaseName, label) =>
|
|
|
813
818
|
async function requirePhase(gate, phaseKey, phaseName) {
|
|
814
819
|
const r = await attest(phaseKey, phaseName, `require:${phaseKey}`);
|
|
815
820
|
if (r.exit_code === 0) return null;
|
|
821
|
+
// Exit 6 is `probe resume --require`'s OWN documented code for "the artifact really is not on
|
|
822
|
+
// disk" (kernel/probe/resume.mjs banner). Any other value — including -1, the courier's sentinel
|
|
823
|
+
// for a tool call that never ran — is not that predicate answering "no"; it is the predicate never
|
|
824
|
+
// being asked. Collapsing both into one message manufactured a false "worker escalated" diagnosis
|
|
825
|
+
// the one time this was measured live: the artifacts existed, and the check itself had been denied
|
|
826
|
+
// by a layer above this plugin (workspace trust, or Claude Code's own auto-mode classifier —
|
|
827
|
+
// neither leaves a row in decisions.jsonl, because neither is this plugin's hook).
|
|
828
|
+
if (r.exit_code === 6) {
|
|
829
|
+
return aborted(gate,
|
|
830
|
+
`${gate} produced no artifact: the ${phaseKey} artifact is not on disk after the phase ran and its ` +
|
|
831
|
+
`result was ingested. The phase did not complete — its worker most likely escalated (a WorkResult ` +
|
|
832
|
+
`may report "escalated" with an empty artifacts list) — and because completion is derived from the ` +
|
|
833
|
+
`artifact, every relaunch would re-dispatch this phase and escalate again. Read the phase's result ` +
|
|
834
|
+
`to see what it could not complete, resolve it, then relaunch.`);
|
|
835
|
+
}
|
|
816
836
|
return aborted(gate,
|
|
817
|
-
`${gate}
|
|
818
|
-
`
|
|
819
|
-
`
|
|
820
|
-
`
|
|
821
|
-
`
|
|
837
|
+
`${gate}'s completion check for "${phaseKey}" did not run to a verdict — exit_code ${r.exit_code}, ` +
|
|
838
|
+
`not the 0 (satisfied) or 6 (artifact absent) \`probe resume --require\` documents.` +
|
|
839
|
+
`${r.detail ? ` Courier reported: ${r.detail}.` : ""} This is NOT evidence the phase failed — it means ` +
|
|
840
|
+
`the check itself could not run, most often a Bash call denied above this plugin's own hooks and ` +
|
|
841
|
+
`permission grant (an untrusted workspace, or Claude Code's auto-mode classifier). Verify the ` +
|
|
842
|
+
`${phaseKey} artifact by hand before assuming it is missing, then either relaunch or drive the ` +
|
|
843
|
+
`remaining phase's kernel commands directly.`);
|
|
822
844
|
}
|
|
823
845
|
|
|
824
846
|
/**
|
|
@@ -851,12 +873,24 @@ async function fastForward(gate, phaseKey, phaseName, what) {
|
|
|
851
873
|
log(`${gate} — ${what}, fast-forwarding past it`);
|
|
852
874
|
const r = await attest(phaseKey, phaseName, `ff:${phaseKey}`);
|
|
853
875
|
if (r.exit_code === 0) return null;
|
|
876
|
+
// Same distinction as requirePhase: only exit 6 is the predicate genuinely answering "not there".
|
|
877
|
+
// Anything else means this re-attestation call itself never executed, most likely denied above
|
|
878
|
+
// this plugin's hooks and permission grant — not a real disagreement between the two probes.
|
|
879
|
+
if (r.exit_code === 6) {
|
|
880
|
+
return aborted(gate,
|
|
881
|
+
`${gate} was fast-forwarded on a state probe that reported its artifact present, and re-asking ` +
|
|
882
|
+
`\`probe resume --require ${phaseKey}\` at the phase itself says it is not on disk. Two readings ` +
|
|
883
|
+
`of "is this done" disagree, and the one taken AT the phase is the later of the two — so the run ` +
|
|
884
|
+
`stops here rather than building on a phase nothing can attest. Check whether the ${phaseKey} ` +
|
|
885
|
+
`artifact was moved or removed since this run last touched it, then relaunch.`);
|
|
886
|
+
}
|
|
854
887
|
return aborted(gate,
|
|
855
|
-
`${gate}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
`
|
|
859
|
-
`
|
|
888
|
+
`${gate}'s re-attestation of "${phaseKey}" did not run to a verdict — exit_code ${r.exit_code}, not ` +
|
|
889
|
+
`the 0 (satisfied) or 6 (artifact absent) \`probe resume --require\` documents.` +
|
|
890
|
+
`${r.detail ? ` Courier reported: ${r.detail}.` : ""} The two probes are not actually in disagreement — ` +
|
|
891
|
+
`this one never executed, most often a Bash call denied above this plugin's own hooks and ` +
|
|
892
|
+
`permission grant (an untrusted workspace, or Claude Code's auto-mode classifier). Verify the ` +
|
|
893
|
+
`${phaseKey} artifact by hand before assuming it regressed, then relaunch.`);
|
|
860
894
|
}
|
|
861
895
|
|
|
862
896
|
// The ledger's `status` field is bookkeeping, not this file's resume oracle — the fast-forward reads
|