cohorte 1.5.0 → 1.6.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/CHANGELOG.md +85 -1
- package/README.md +20 -12
- package/bin/cli.js +8 -0
- package/core/agents/review.md +23 -0
- package/core/commands/audit.md +9 -1
- package/core/commands/brainstorm.md +6 -0
- package/core/commands/build.md +90 -5
- package/core/commands/doctor.md +8 -3
- package/core/commands/{loop.md → drive.md} +25 -6
- package/core/commands/fix.md +5 -0
- package/core/commands/review.md +58 -9
- package/core/commands/spec.md +20 -0
- package/core/commands/update-pipeline.md +6 -1
- package/core/templates/decisions.template.md +42 -0
- package/core/templates/spec.template.md +3 -1
- package/core/templates/steps/init-pipeline/04-write-render.md +2 -2
- package/core/workflows/review.js +44 -2
- package/dashboard/dist/assets/{index-dkO8UUVl.css → index-BZ_LQlEj.css} +1 -1
- package/dashboard/dist/assets/{index-8owBnqyv.js → index-DYyn4p93.js} +11 -11
- package/dashboard/dist/index.html +2 -2
- package/dashboard/server/doctor.js +8 -1
- package/install.ps1 +8 -0
- package/install.sh +7 -0
- package/package.json +1 -1
- package/profile/SCHEMA.md +140 -1
- package/scripts/loop.sh +141 -12
- package/scripts/test-loop.mjs +227 -0
- package/scripts/test-workflows.mjs +28 -0
- package/scripts/validate-core.mjs +16 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,13 +3,97 @@
|
|
|
3
3
|
Entries are shown by `/update-pipeline` ("What's new") after a core refresh. Keep them short,
|
|
4
4
|
user-facing, most recent first. One `## <version> — <YYYY-MM-DD>` section per release.
|
|
5
5
|
|
|
6
|
+
## 1.6.0 — 2026-08-01
|
|
7
|
+
|
|
8
|
+
> **Re-run `npx cohorte@latest update --global` (or `update`)** to pick up the readiness gate, the
|
|
9
|
+
> deferred-findings route, the resumable driver and the decision journal — the update *deletes* the
|
|
10
|
+
> shadowed `/loop` command and the long-dead `/cycle` from your install, it does not just stop
|
|
11
|
+
> shipping them. Existing specs keep working: the new front-matter fields are written on demand, and a
|
|
12
|
+
> spec without them simply isn't resumable yet. **`/loop <id>` is now `/drive <id>`.**
|
|
13
|
+
|
|
14
|
+
- **New — the readiness gate between `/spec` and `/build`.** `/build` §1.6 now scores the frozen spec
|
|
15
|
+
on **implementability** before authoring the contract and before dispatching anything: contract
|
|
16
|
+
shapes complete · every area owned by a surface · named dependencies actually exist · no ambiguity a
|
|
17
|
+
surface would have to guess at · design links present. The verdict goes to
|
|
18
|
+
`specs/reports/<id>.readiness.json` (`READY` · `RESERVATIONS` · `NOT-READY` + `gaps[]`).
|
|
19
|
+
**`NOT-READY` stops the build with zero agents spawned** — a spec that can't be built doesn't get
|
|
20
|
+
cheaper by being built on N surfaces in parallel — and sends you to `/spec`. `RESERVATIONS` never
|
|
21
|
+
blocks: each gap is inlined into the affected surface's dispatch as an assumption the implementer
|
|
22
|
+
applies *and* flags in its handoff. It costs **no extra agent**: the lead already holds the spec,
|
|
23
|
+
the profile and the reconciled surface list.
|
|
24
|
+
- **New — deferred findings: `/review` stops throwing away what isn't blocking.** The review agent
|
|
25
|
+
now returns a separate `## Deferred` section (max 10) for what is real but **out of this feature's
|
|
26
|
+
scope** — pre-existing code the diff never touched, adjacent debt the spec never claims to fix —
|
|
27
|
+
each line carrying its own out-of-scope reason. Deferred items count in no severity row, move no
|
|
28
|
+
verdict, are never cross-checked, and on **every** verdict get routed into
|
|
29
|
+
`specs/refactor-backlog.md` under the owning surface's `## <domain>` heading, tagged
|
|
30
|
+
`deferred:<id>`. So `/review` feeds `/refactor` for free instead of dropping everything
|
|
31
|
+
non-blocking on the floor. Never into `## Remediation`, which is what `/fix` re-dispatches. Not
|
|
32
|
+
deferrable, ever: anything the diff touched, any spec violation, any security issue on a path this
|
|
33
|
+
feature adds or calls. `/audit` now **carries open `deferred:` items over** when it rewrites the
|
|
34
|
+
backlog. The verdict JSON gains `deferred: <n>` (informational, outside `blocking`).
|
|
35
|
+
- **BREAKING — `/loop` is renamed `/drive`, because Claude Code shadowed it.** Claude Code ships its
|
|
36
|
+
own built-in `/loop` (run a prompt on a recurring interval), which won the name: typing
|
|
37
|
+
`/loop <id>` started the *interval runner* with the feature id as its prompt, so cohorte's driver
|
|
38
|
+
never ran — and the session, having never seen `loop.md`, reported a loop that did not exist. Same
|
|
39
|
+
command, same flags, same script (`pipeline/scripts/loop.sh` keeps its name — nothing about your
|
|
40
|
+
install paths changes): type **`/drive <id>`**. The update scrubs the old `commands/loop.md`, so a
|
|
41
|
+
stale shadowed copy can't linger.
|
|
42
|
+
- **`/drive` is resumable — the spec's status is the state machine.** The lifecycle is now
|
|
43
|
+
`draft → frozen → in-progress → in-review → shipped` plus `blocked`. Before every phase the driver
|
|
44
|
+
stamps `status: in-progress` + `loop_pass` + `loop_phase` into the spec's front-matter — plain
|
|
45
|
+
`awk`, a temp file and `mv`, **zero tokens** — and on exit a terminal `in-review` (clean) or
|
|
46
|
+
`blocked`. **`/drive <id> --resume`** then continues at the pass it reached instead of re-paying the
|
|
47
|
+
ones already made, whether the session died, the ceiling hit, or the fix stopped converging.
|
|
48
|
+
`--max` stays a ceiling on the *total* passes. New **exit 4** (`not implementable`) relays the
|
|
49
|
+
readiness gate's `NOT-READY`: the one loop outcome more passes cannot fix. The dashboard's specs
|
|
50
|
+
board gains In-progress and Blocked columns and shows `↻ pass 3 · /review` on the card; `/doctor`
|
|
51
|
+
names any spec left mid-loop.
|
|
52
|
+
- **Fixed — a dead subagent no longer reads as a clean one on the conversational path.** The
|
|
53
|
+
"a dead agent is never a clean result" doctrine existed since 1.3.4 — but only inside the
|
|
54
|
+
**workflows**. `/build`, `/review` and `/fix` had nothing: a subagent that dies (rate limit,
|
|
55
|
+
transport error, exhausted context) returns *nothing*, and nothing was indistinguishable from
|
|
56
|
+
"finished, nothing to report". Concretely, a dead **reviewer** produced zero findings ⇒
|
|
57
|
+
`blocking: 0` ⇒ verdict `SHIP` ⇒ `/drive` exit 0 ⇒ the human sent to `/ship` — a clean bill of
|
|
58
|
+
health on code no agent ever read. Now every fan-out phase does a **roll call** before integrating:
|
|
59
|
+
a silent surface is retried **once** alone (byte-identical prompt, so recovery costs one agent, not
|
|
60
|
+
a rebuild), then `/build` marks it `dead` and verifies the tree with that surface's own quiet
|
|
61
|
+
commands instead of speaking for the agent, `/review` lists it in the verdict's new `unreviewed[]`
|
|
62
|
+
and **refuses to score `SHIP`**, and `/fix` leaves every one of its items `- [ ]` (a dead agent
|
|
63
|
+
never ticks a box). `/build` also writes `specs/reports/<id>.build.json` with `dead[]`, and
|
|
64
|
+
`loop.sh` aborts on either signal with **exit 2** *before* reading `blocking` — because a dead
|
|
65
|
+
reviewer makes `blocking == 0` a statement about unread code. `unreviewed` is deliberately kept
|
|
66
|
+
out of `blocking`: faking a count there would corrupt the one field the driver contract rests on.
|
|
67
|
+
The metrics line is now written even when a surface died (`"<key>":"dead"`) — an incomplete batch
|
|
68
|
+
is exactly the batch worth recording.
|
|
69
|
+
- **Fixed — `/cycle` and its workflow were removed in 1.4.0 but no installer ever scrubbed them.**
|
|
70
|
+
Every install since has kept `commands/cycle.md` + `workflows/cycle.js` on disk, so a dead command
|
|
71
|
+
stayed listed and invokable — dispatching a workflow whose phases 1.5.0 then deleted. All three
|
|
72
|
+
installers now remove them (as they already did for `/smoke`), and CI **plants the orphans before
|
|
73
|
+
re-installing** instead of asserting their absence on a fresh scratch home, which is exactly the
|
|
74
|
+
blind spot that let this survive four releases.
|
|
75
|
+
- **Reconcile now tops up `specs/_template.md`.** It was seeded once at install and never refreshed,
|
|
76
|
+
so every repo kept the front-matter its core shipped with. `/update-pipeline` adds the missing
|
|
77
|
+
front-matter fields (never the body — the section list is yours).
|
|
78
|
+
- **New — `specs/_decisions.md`, the transverse decision journal.** `PIPELINE.md` is a *stack* profile;
|
|
79
|
+
it says nothing about what the project has **decided**, so every `/spec` re-discovered or
|
|
80
|
+
contradicted the same choices. The journal is deliberately tiny: **append-only, one line per
|
|
81
|
+
decision** (`- <date> · <area> · <decision> — because <reason> · <feature_id>`), reversal by a
|
|
82
|
+
superseding line rather than an edit. Written by `/spec` at freeze (typically 0–3 lines; zero is
|
|
83
|
+
normal) and by `/build` when it adds or splits a surface. Read by the **deciding** stages only —
|
|
84
|
+
`/brainstorm`, `/spec`, `/audit`. **Implementers and reviewers never load it:** they have the frozen
|
|
85
|
+
contract, and shipping them the rationale would cost `surfaces × dispatches` tokens per feature for
|
|
86
|
+
a fact they can't act on. That exclusion is what keeps it cheap enough to be worth having. The `_`
|
|
87
|
+
prefix means `/doctor`, the dashboard scanner and the kanban backfill already skip it.
|
|
88
|
+
|
|
6
89
|
## 1.5.0 — 2026-08-01
|
|
7
90
|
|
|
8
91
|
> **Re-run `npx cohorte@latest update --global` (or `update`)** to pick up the collector and the
|
|
9
92
|
> `/smoke` removal — the update *deletes* the command and its agent from your install, it does not
|
|
10
93
|
> just stop shipping them. The new dashboard panel comes with `npx cohorte dashboard`.
|
|
11
94
|
|
|
12
|
-
- **New — `/loop <id>`: the review ⇄ fix cycle, run for you.** `/
|
|
95
|
+
- **New — `/loop <id>`: the review ⇄ fix cycle, run for you.** _(renamed `/drive` in 1.6.0 — see
|
|
96
|
+
there.)_ `/build` → `/review` → `/fix` →
|
|
13
97
|
`/review` … until a review reports **zero blocking findings** (a CRITICAL or a security issue —
|
|
14
98
|
a LOW nit never costs a pass), or the pass ceiling (`--max=N`, default 5), or two consecutive
|
|
15
99
|
reviews returning the *same* blocking findings, which means the fix is treading water and more
|
package/README.md
CHANGED
|
@@ -131,7 +131,8 @@ design system), **interviews** you for the gaps, and **generates**:
|
|
|
131
131
|
symbols instead of grep-and-reading whole files; `graphify` or `none` also available via the
|
|
132
132
|
profile's `retrieval.provider`)
|
|
133
133
|
- `scripts/new-feature.sh` + `remove-feature.sh` — parallel worktree isolation (if you enable it)
|
|
134
|
-
- `specs/_template.md`
|
|
134
|
+
- `specs/_template.md` (and, on first decision, `specs/_decisions.md` — the project's one-line-per-decision
|
|
135
|
+
journal, read by `/brainstorm`, `/spec` and `/audit` so features stop re-litigating settled ground)
|
|
135
136
|
|
|
136
137
|
Sanity-check `PIPELINE.md`, commit it, and run `/brainstorm`.
|
|
137
138
|
|
|
@@ -216,10 +217,10 @@ it in `.claude/pipeline/VERSION` and bundled repos in their committed `pipeline.
|
|
|
216
217
|
| `/init-pipeline` | Detect stack → interview → generate the profile + agents. Run once per project. |
|
|
217
218
|
| `/brainstorm` | Interactive persona panel that pressure-tests a feature idea. |
|
|
218
219
|
| `/spec` | Freeze the feature spec + contract into `specs/<id>.md` (UI features also get a standalone design brief at `specs/design/<id>.md`). Also applies review returns. |
|
|
219
|
-
| `/build <id>` |
|
|
220
|
-
| `/review <id>` | Read-only review agents (one per touched surface, parallel) audit the diff vs the spec. |
|
|
220
|
+
| `/build <id>` | Readiness gate on the frozen spec, then the lead authors the contract and dispatches one implementer per surface in parallel. |
|
|
221
|
+
| `/review <id>` | Read-only review agents (one per touched surface, parallel) audit the diff vs the spec; out-of-scope findings go to the refactor backlog. |
|
|
221
222
|
| `/fix <id>` | Apply a review report: remediation into the spec, re-dispatch only the surfaces with findings. |
|
|
222
|
-
| `/
|
|
223
|
+
| `/drive <id>` | Autonomous `/build → /review → /fix → /review …` until no blocking finding is left (see below). |
|
|
223
224
|
| `/ship <id>` | Release agent commits, pushes, opens the PR; watches CI; proposes worktree teardown. |
|
|
224
225
|
| `/audit [path]` | Prioritized refactor backlog for existing code. |
|
|
225
226
|
| `/refactor <domain>` | Apply the backlog for one surface, TDD-first. |
|
|
@@ -243,19 +244,26 @@ lever: long sessions (>150k) are expensive even when cached. Each command tells
|
|
|
243
244
|
safe to clear. If you'd rather stay in one session, `/compact` mid-task does the lighter version. (Claude
|
|
244
245
|
can't fire `/clear` itself — it's a client-side command; the pipeline just makes it always safe to type.)
|
|
245
246
|
|
|
246
|
-
### Let it run itself — `/
|
|
247
|
+
### Let it run itself — `/drive`
|
|
247
248
|
|
|
248
249
|
```
|
|
249
|
-
/
|
|
250
|
-
/
|
|
251
|
-
/
|
|
250
|
+
/drive feat-x # /build, then /review ⇄ /fix until clean (max 5 passes)
|
|
251
|
+
/drive feat-x --no-build # already built — just re-run the /review ⇄ /fix loop
|
|
252
|
+
/drive feat-x --max=8
|
|
253
|
+
/drive feat-x --resume # continue a run that died / hit the ceiling, at the pass it reached
|
|
252
254
|
```
|
|
253
255
|
|
|
254
256
|
It stops when `/review` reports **zero blocking findings** (a CRITICAL or a security issue — a LOW
|
|
255
|
-
nit never costs a pass), at the pass ceiling,
|
|
256
|
-
blocking findings
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
nit never costs a pass), at the pass ceiling, as soon as two consecutive reviews return the same
|
|
258
|
+
blocking findings (the fix is treading water and more passes won't help), or immediately if `/build`'s
|
|
259
|
+
readiness gate says the frozen spec **cannot be built** — that one needs `/spec`, not passes. **Each
|
|
260
|
+
fix pass is committed** (`loop(<id>): fix pass <i>`) — that's your way back after N autonomous passes —
|
|
261
|
+
and **no fix runs on the last pass**, since fixing without a review behind it leaves unaudited code.
|
|
262
|
+
|
|
263
|
+
**It's resumable.** Before each phase the driver stamps `status: in-progress` + `loop_pass` +
|
|
264
|
+
`loop_phase` into the spec's front-matter (plain `awk`, zero tokens), and a terminal `in-review` or
|
|
265
|
+
`blocked` on exit. So `--resume` continues at pass 3 instead of re-paying passes 1 and 2 — and the spec
|
|
266
|
+
itself tells you, `/doctor` and the dashboard where the loop got to.
|
|
259
267
|
|
|
260
268
|
**The loop does not run in your session.** Each phase is a separate `claude -p` child with its own
|
|
261
269
|
fresh context, driven by `pipeline/scripts/loop.sh`; all of their output goes to
|
package/bin/cli.js
CHANGED
|
@@ -227,6 +227,14 @@ function copyFixedAgents() {
|
|
|
227
227
|
// 1.5.0 removed the /smoke phase; copy-over never deletes, so scrub the orphan agent+command.
|
|
228
228
|
fs.rmSync(path.join(dest, 'agents', 'smoke.md'), { force: true });
|
|
229
229
|
fs.rmSync(path.join(dest, 'commands', 'smoke.md'), { force: true });
|
|
230
|
+
// 1.4.0 removed /cycle and its workflow — and no installer ever scrubbed them, so every
|
|
231
|
+
// install since has kept offering a command that dispatches a workflow whose phases were
|
|
232
|
+
// later deleted. A dead command is worse than a missing one: the model can still fire it.
|
|
233
|
+
fs.rmSync(path.join(dest, 'commands', 'cycle.md'), { force: true });
|
|
234
|
+
fs.rmSync(path.join(dest, 'workflows', 'cycle.js'), { force: true });
|
|
235
|
+
// 1.6.0 renamed /loop → /drive: Claude Code's own built-in /loop shadowed ours, so a leftover
|
|
236
|
+
// commands/loop.md is a command the user can never reach — scrub it rather than leave a decoy.
|
|
237
|
+
fs.rmSync(path.join(dest, 'commands', 'loop.md'), { force: true });
|
|
230
238
|
scrubResearchQuestionnaire();
|
|
231
239
|
}
|
|
232
240
|
|
package/core/agents/review.md
CHANGED
|
@@ -81,6 +81,24 @@ domain** (same finding-line shape) instead of a SHIP/REVISE/BLOCK verdict.
|
|
|
81
81
|
- Any **security vulnerability** ⇒ verdict **BLOCK**.
|
|
82
82
|
- No CRITICAL and no security issue ⇒ verdict **SHIP**.
|
|
83
83
|
|
|
84
|
+
## Deferred — real, but not this feature's problem
|
|
85
|
+
|
|
86
|
+
A finding is **deferred** when it is genuinely true and genuinely **out of this feature's scope**:
|
|
87
|
+
pre-existing code the staged diff did not touch, adjacent debt the spec never claims to fix, a
|
|
88
|
+
convention violation that predates this work. Deferring is not softening — it is naming the right
|
|
89
|
+
owner. The lead routes deferred findings to `specs/refactor-backlog.md` (they feed `/refactor`), so
|
|
90
|
+
they are **never lost and never cost a fix loop**.
|
|
91
|
+
|
|
92
|
+
- **Deferred findings are separate from your findings list** and count in **no** severity row: the
|
|
93
|
+
severity table drives the verdict, and a deferred item must never force one.
|
|
94
|
+
- **Deferrable:** a problem entirely in lines/files the diff did not change, whose fix is not required
|
|
95
|
+
by any acceptance criterion of this spec.
|
|
96
|
+
- **NOT deferrable, ever:** anything the diff touched or introduced; any spec violation; any
|
|
97
|
+
**security** issue on a path this feature adds, calls or modifies (a pre-existing hole this feature
|
|
98
|
+
now exposes to new traffic is this feature's problem). When in doubt, it is a finding, not a deferral.
|
|
99
|
+
- Cap the deferred list at **10 lines**, worst first; each carries its own out-of-scope reason so the
|
|
100
|
+
lead can route it without re-reading anything.
|
|
101
|
+
|
|
84
102
|
## Your return — the REVIEW REPORT, exactly this shape
|
|
85
103
|
|
|
86
104
|
Every finding must be **self-sufficient for a stateless agent**: `file:line` · severity ·
|
|
@@ -110,6 +128,11 @@ Verdict: <SHIP | REVISE | BLOCK>
|
|
|
110
128
|
- **[<SEVERITY>]** `<file>:<line>` · <spec-violation|quality|security> · <problem> → **Fix:** <concrete change>
|
|
111
129
|
(order by severity; "None." if none; max 20 lines, one per finding, no code excerpts)
|
|
112
130
|
|
|
131
|
+
## Deferred
|
|
132
|
+
|
|
133
|
+
- **[<SEVERITY>]** `<file>:<line>` · <quality|security> · <problem> → **Fix:** <concrete change> · out of scope: <why this feature does not own it>
|
|
134
|
+
(real but out of this feature's scope — see §Deferred; worst first; "None." if none; max 10 lines)
|
|
135
|
+
|
|
113
136
|
## Notes
|
|
114
137
|
(ONLY the RBAC / mobile-first assessment when the profile enables them; omit the section otherwise)
|
|
115
138
|
```
|
package/core/commands/audit.md
CHANGED
|
@@ -7,7 +7,9 @@ argument-hint: [path or domain, default = whole repo]
|
|
|
7
7
|
You are the **lead**. Audit **$ARGUMENTS** (default: whole repo) to drive it to a clean base. Read +
|
|
8
8
|
analyze only — no fixes (those go through `/refactor`).
|
|
9
9
|
|
|
10
|
-
> Read `PIPELINE.md` §`commands` (the mechanical gates), `surfaces`, and §Conventions
|
|
10
|
+
> Read `PIPELINE.md` §`commands` (the mechanical gates), `surfaces`, and §Conventions — plus
|
|
11
|
+
> `specs/_decisions.md` §Live if it exists (SCHEMA.md §Decisions): those standing decisions are part
|
|
12
|
+
> of the rulebook you audit against, and code that contradicts one is a finding like any other.
|
|
11
13
|
>
|
|
12
14
|
> **Workflow variant** (opt-in — SCHEMA.md §Workflows): on Claude Code ≥ 2.1.154 with workflows
|
|
13
15
|
> enabled, the human can ask to "run the audit workflow" (`<core>/workflows/audit.js` — one auditor
|
|
@@ -39,5 +41,11 @@ from your instructions), grouped by domain (one group per surface + shared). —
|
|
|
39
41
|
Merge mechanical + convention findings into one prioritized backlog and **write
|
|
40
42
|
`specs/refactor-backlog.md`**, grouped by domain, each item:
|
|
41
43
|
`- [ ] <SEVERITY> · <file:line> · <rule|tdd|lint|format|type|security> · <concrete fix>`
|
|
44
|
+
|
|
45
|
+
**Carry over the deferred items** before overwriting: `grep -n 'deferred:' specs/refactor-backlog.md`
|
|
46
|
+
and re-emit every **open** (`- [ ]`) match verbatim under its domain, tag included. Those lines were
|
|
47
|
+
put there by `/review` §3.5 — a real finding a feature deliberately did not own — and an audit that
|
|
48
|
+
blindly overwrites the file is the one way they silently disappear. Already-ticked (`- [x]`) ones are
|
|
49
|
+
done: drop them.
|
|
42
50
|
Print a short summary (counts per domain + top items). Tell the human: refactor a domain with
|
|
43
51
|
`/refactor <domain>`.
|
|
@@ -11,6 +11,12 @@ at Finish, when a board is configured.
|
|
|
11
11
|
> Read `PIPELINE.md` §Personas (the panel) and §`rbac` first. If `rbac.enabled`, the panel must
|
|
12
12
|
> pressure-test the idea so it serves **every** role, not just admins.
|
|
13
13
|
>
|
|
14
|
+
> Also read `specs/_decisions.md` §Live if it exists (SCHEMA.md §Decisions) — one line per standing
|
|
15
|
+
> decision. The panel argues about the idea, not about settled ground: a persona that proposes
|
|
16
|
+
> something a live line already decided must be told so by another persona, and an idea that genuinely
|
|
17
|
+
> needs to overturn one must say which line, out loud, so the human decides it here rather than
|
|
18
|
+
> discovering the contradiction at `/spec`.
|
|
19
|
+
>
|
|
14
20
|
> Template paths below (`.claude/templates/…`) resolve to `~/.claude/templates/…` when the core is
|
|
15
21
|
> installed globally — read whichever exists.
|
|
16
22
|
>
|
package/core/commands/build.md
CHANGED
|
@@ -16,8 +16,11 @@ You are the **lead**. Build feature **$ARGUMENTS** from its frozen spec.
|
|
|
16
16
|
## 1. Load & check
|
|
17
17
|
|
|
18
18
|
- Check the spec front-matter FIRST — `grep '^status:' specs/$ARGUMENTS.md` (or Read with a ~15-line
|
|
19
|
-
limit) — before any full read.
|
|
20
|
-
|
|
19
|
+
limit) — before any full read. Buildable statuses are `frozen`, `in-review` and `in-progress` (the
|
|
20
|
+
last one means a `/drive` is or was driving this spec — SCHEMA.md §Spec status). `blocked` means a
|
|
21
|
+
loop gave up here: say so, and route by the spec's `## Remediation` — open items ⇒ `/fix`, none ⇒
|
|
22
|
+
continue this build. Anything else (`draft`, missing, `shipped`) ⇒ stop and tell the human to run
|
|
23
|
+
`/spec` first. Only then read the body, selectively: front-matter, §5 contract, the surface
|
|
21
24
|
task sections, and `## Remediation` (fall back to a full read if the spec doesn't follow the
|
|
22
25
|
template's headings).
|
|
23
26
|
- **Route check** — if `## Remediation` has open `- [ ]` items and none requires a contract change,
|
|
@@ -56,6 +59,59 @@ shared-code rule (shared trees get a single-owner surface; cross-slice shapes go
|
|
|
56
59
|
This is the automatic path: you don't send the human back to `/init-pipeline`. If nothing new is needed,
|
|
57
60
|
say so and continue. Dispatch (§3) then covers the reconciled surface list.
|
|
58
61
|
|
|
62
|
+
**Adding or splitting a surface is an architectural decision** — append ONE line for it to
|
|
63
|
+
`specs/_decisions.md` §Live (SCHEMA.md §Decisions; create from `.claude/templates/decisions.template.md`
|
|
64
|
+
if absent), area `surfaces`, e.g.
|
|
65
|
+
`- <date> · surfaces · <key> owns <path>, single owner of <what> — because <the boundary reason> · $ARGUMENTS`.
|
|
66
|
+
One `>>` in the Bash call you're already making. Nothing added ⇒ nothing to append.
|
|
67
|
+
|
|
68
|
+
## 1.6 Readiness verdict — the gate before N dispatches
|
|
69
|
+
|
|
70
|
+
**Zero extra agents: you already hold the spec, the profile and the reconciled surface list.** The
|
|
71
|
+
whole point is that a bancal spec costs one verdict here instead of N implementers discovering it in
|
|
72
|
+
parallel. Judge the frozen contract on **implementability only** — never on whether the feature is a
|
|
73
|
+
good idea (that was `/brainstorm`), never by re-reading files you don't already need:
|
|
74
|
+
|
|
75
|
+
1. **Contract completeness** (§5) — every endpoint/interface has method+path (or signature), auth,
|
|
76
|
+
request fields with types + validation, the success shape, and its error cases. A missing
|
|
77
|
+
**request or success shape** ⇒ `NOT-READY` (an implementer would invent it, and the other surface
|
|
78
|
+
would invent a different one). A missing **error case** ⇒ `RESERVATIONS`.
|
|
79
|
+
2. **Surface coverage** — every §6 task maps to a surface in the reconciled list, and every contract
|
|
80
|
+
entry has an owner **on each side it names** (producer and consumer). A contract entry no surface
|
|
81
|
+
owns ⇒ `NOT-READY`.
|
|
82
|
+
3. **Dependencies exist** — for the modules, packages, tables, env vars and shared helpers the spec
|
|
83
|
+
names as *pre-existing*: verify them in ONE Bash call (`test -f` / `grep -l` / a package-manifest
|
|
84
|
+
grep, output redirected — never a file read per name). Named as pre-existing but absent, and not
|
|
85
|
+
listed as created by this feature ⇒ `NOT-READY`.
|
|
86
|
+
4. **Residual ambiguity** (§10) — an open question a surface would have to *guess* at: blocks a
|
|
87
|
+
contract decision ⇒ `NOT-READY`; merely narrows an implementation choice ⇒ `RESERVATIONS`.
|
|
88
|
+
5. **Design gate** — a `uses_design` surface in scope with `design_files` still empty ⇒ `NOT-READY`
|
|
89
|
+
(this is §1's gate restated as a verdict, so an automated driver sees the same fact).
|
|
90
|
+
|
|
91
|
+
Write the machine-readable verdict to `specs/reports/$ARGUMENTS.readiness.json` (overwrite,
|
|
92
|
+
`mkdir -p specs/reports` first — the same gitignored buffer dir `/review` stages into, which may not
|
|
93
|
+
exist yet on a first build) — on **every** build, including `READY`. It is the only channel between this gate and a driver (`/drive`),
|
|
94
|
+
which parses no prose:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{ "id": "$ARGUMENTS", "phase": "readiness", "ts": "<ISO>", "verdict": "RESERVATIONS",
|
|
98
|
+
"gaps": ["contract|POST /orders|no 409 case for a duplicate id"],
|
|
99
|
+
"surfaces": ["backend", "frontend"] }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- **`gaps`** — one normalized string per gap, `<check>|<where>|<what is missing>`: `<check>` is
|
|
103
|
+
`contract` · `coverage` · `dependency` · `ambiguity` · `design`; `<where>` is the contract entry,
|
|
104
|
+
surface key or dependency name (no `:line` — it shifts on every edit); `<what>` is the gap, not the
|
|
105
|
+
fix. `READY` ⇒ `[]`.
|
|
106
|
+
- **`NOT-READY` ⇒ STOP: author no contract and spawn NO agent.** Print the gaps and send the human to
|
|
107
|
+
`/spec $ARGUMENTS` to patch the contract, then re-run `/build`. This abort is the whole point of the
|
|
108
|
+
step — a spec that cannot be built does not get cheaper by being built N times in parallel.
|
|
109
|
+
- **`RESERVATIONS` ⇒ continue.** It never blocks (a gate that stalls a sound build on a missing error
|
|
110
|
+
case would cost more human round-trips than it saves): inline each gap verbatim into the dispatch of
|
|
111
|
+
the surface it affects, as an explicit assumption the agent must implement *and* flag in its handoff,
|
|
112
|
+
and relay the list to the human in one line each.
|
|
113
|
+
- **`READY` ⇒ continue silently** — one line, no restatement.
|
|
114
|
+
|
|
59
115
|
## 2. Author the contract (lead-only — the single sync channel)
|
|
60
116
|
|
|
61
117
|
_Only if `contract.enabled`._ From §5 of the spec, write/update the feature's contract file at
|
|
@@ -87,19 +143,46 @@ tree. For each surface in `surfaces`:
|
|
|
87
143
|
> via `DesignSync get_file`, build mobile-first · or `none` (non-design surface, or a fix loop whose
|
|
88
144
|
> open items are all non-visual)>. Open Remediation items for YOUR surface (self-contained — fix
|
|
89
145
|
> exactly these, reading only the files they name; `none` ⇒ first build, implement the spec's tasks
|
|
90
|
-
> for your surface): <the surface's open `- [ ]` lines verbatim, or `none`>.
|
|
146
|
+
> for your surface): <the surface's open `- [ ]` lines verbatim, or `none`>. Readiness gaps for YOUR
|
|
147
|
+
> surface (§1.6 `RESERVATIONS` — the spec is silent here: implement the stated assumption and flag what
|
|
148
|
+
> you assumed in your handoff): <that surface's `gaps` entries verbatim, or `none`>."
|
|
149
|
+
|
|
150
|
+
## 3.5 Roll call — account for EVERY dispatch before integrating
|
|
151
|
+
|
|
152
|
+
A subagent can die: a rate limit mid-run, a transport error after retries, its own context exhausted.
|
|
153
|
+
When it does, it returns **nothing** — and nothing is byte-identical to "a clean surface with nothing
|
|
154
|
+
to report". Silence is not a green light; treat it as the failure it is (SCHEMA.md §Dead agents).
|
|
155
|
+
|
|
156
|
+
- **Roll call.** Every surface you dispatched in §3 must come back with a handoff in the format its
|
|
157
|
+
agent instructions define. Missing, empty, or truncated mid-sentence ⇒ that surface is **dead**.
|
|
158
|
+
- **Never infer success from silence,** and never speak for a dead agent — you did not see its work.
|
|
159
|
+
- **Retry that surface ONCE, alone.** Re-dispatch it with the byte-identical §3 prompt. The other
|
|
160
|
+
surfaces' work is already on disk and untouched, so this costs one agent, not a rebuild — and most
|
|
161
|
+
deaths are transient. Never retry a surface that *did* answer.
|
|
162
|
+
- **Died twice ⇒ stop guessing and look.** Run that surface's own quiet commands
|
|
163
|
+
(`<surface>.typecheck_cmd`, `lint_quiet_cmd`, `test_quiet_cmd`) with output redirected to
|
|
164
|
+
`specs/reports/$ARGUMENTS.<key>.deadcheck.txt`, then grep it — never into your context. Report the
|
|
165
|
+
three results plus which of the spec's tasks for that surface actually landed, checked against the
|
|
166
|
+
tree, not against a handoff you never got. Say plainly that the surface is **unverified**.
|
|
91
167
|
|
|
92
168
|
## 4. Integrate
|
|
93
169
|
|
|
94
170
|
When all return, flag any contract mismatch or failing test from the handoffs; otherwise print one
|
|
95
171
|
status line per surface (`<key> · tests pass/fail · <n> TODOs`) — do not restate handoff content.
|
|
172
|
+
A dead surface (§3.5) prints `<key> · DEAD — unverified` and **the batch is never reported as ok**.
|
|
96
173
|
Append **ONE line for the batch** to the **main checkout's** `.claude/pipeline-metrics.jsonl` —
|
|
97
174
|
NOT the worktree's, which dies at teardown while metrics must accumulate across features. Resolve
|
|
98
175
|
it from anywhere: `$(dirname "$(git rev-parse --git-common-dir)")/.claude/pipeline-metrics.jsonl`
|
|
99
176
|
(in the main checkout this resolves to itself). Create it if absent; it must be gitignored.
|
|
100
177
|
Compute the elapsed time in the same Bash call
|
|
101
178
|
(`echo "{...\"seconds\":$(($(date +%s)-<start epoch from §2>)),...}" >> …`):
|
|
102
|
-
`{"ts":"<ISO date>","feature":"$ARGUMENTS","phase":"build","seconds":<wall-clock>,"surfaces":{"<key>":"ok|error",…}}`
|
|
179
|
+
`{"ts":"<ISO date>","feature":"$ARGUMENTS","phase":"build","seconds":<wall-clock>,"surfaces":{"<key>":"ok|error|dead",…}}`
|
|
180
|
+
— **write this line even when a surface died.** An incomplete batch is exactly the batch worth having
|
|
181
|
+
in the record; skipping the append to "wait until it's complete" silently deletes the evidence that
|
|
182
|
+
anything went wrong. In the same call write the machine-readable batch result to
|
|
183
|
+
`specs/reports/$ARGUMENTS.build.json` (overwrite) — the channel an automated driver reads, since it
|
|
184
|
+
never sees your chat:
|
|
185
|
+
`{"id":"$ARGUMENTS","phase":"build","ts":"<ISO>","surfaces":{"<key>":"ok|error|dead",…},"dead":["<key>",…]}`
|
|
103
186
|
— this is the evidence SCHEMA.md §Specialization asks for before splitting a surface. In the same
|
|
104
187
|
Bash call, chain the opt-in usage ping — **the shared form every phase command reuses**:
|
|
105
188
|
`<core>/pipeline/scripts/telemetry-send.sh <phase> "$ARGUMENTS" <seconds> "<results>" || true`
|
|
@@ -108,7 +191,9 @@ Bash call, chain the opt-in usage ping — **the shared form every phase command
|
|
|
108
191
|
never ask about consent here. `/review` and `/fix` chain the same line with their own
|
|
109
192
|
phase + results. The `|| true` swallows a **missing** script too, so a half-copied core goes
|
|
110
193
|
silent rather than loud — `/doctor` check 1 is what catches that.
|
|
111
|
-
Then tell the human: exercise the feature by hand if it's worth it, then run `/review $ARGUMENTS
|
|
194
|
+
Then tell the human: exercise the feature by hand if it's worth it, then run `/review $ARGUMENTS` —
|
|
195
|
+
unless a surface is dead, in which case say so first and let them decide whether to re-run `/build`
|
|
196
|
+
(a dead surface has no findings, so `/fix` has nothing to re-dispatch).
|
|
112
197
|
Do not run the app or migrations yourself here — building is not running.
|
|
113
198
|
**Recommend a `/clear` now** — the spec, contract and diff are all on
|
|
114
199
|
disk, and the lead's history is re-sent at input price on every turn it survives.
|
package/core/commands/doctor.md
CHANGED
|
@@ -84,9 +84,14 @@ fix only with the human's go-ahead (or hand them the command).
|
|
|
84
84
|
End the check with ONE summary line, e.g.
|
|
85
85
|
`workflows: available (opt-in — ask to "run the review workflow")` or
|
|
86
86
|
`workflows: unavailable (<first failing prerequisite>) — conversational commands (the default)`.
|
|
87
|
-
9. **Specs & metrics.** Every `specs/*.md` front-matter `status` is a valid stage —
|
|
88
|
-
`
|
|
89
|
-
|
|
87
|
+
9. **Specs & metrics.** Every `specs/*.md` front-matter `status` is a valid stage — one of
|
|
88
|
+
`draft · frozen · in-progress · in-review · shipped · blocked` (SCHEMA.md §Spec status; the last two
|
|
89
|
+
are written by the `/drive` driver, so flagging them would report the pipeline's own state as a
|
|
90
|
+
defect) — excluding
|
|
91
|
+
`_`-prefixed files (the spec template and `specs/_decisions.md`, the decision journal) and
|
|
92
|
+
`specs/refactor-backlog.md`, which `/audit` writes as a backlog, not a
|
|
93
|
+
spec, and which has no front-matter to check. A spec left `in-progress`/`blocked` with
|
|
94
|
+
`loop_pass` > 0 is a loop that never finished ⇒ say so and name `/drive <id> --resume`. `shipped` specs
|
|
90
95
|
with a live worktree flagged (see 6). `.claude/pipeline-metrics.jsonl` and `specs/reports/` (the
|
|
91
96
|
`/review` report buffer that lets a `/fix` survive a `/clear`) are gitignored. Metrics
|
|
92
97
|
belong to the **main checkout** — a `pipeline-metrics.jsonl` inside a live feature worktree is a
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
model: sonnet
|
|
3
3
|
description: Autonomous /build → /review → /fix → /review loop for one feature, until no blocking finding remains.
|
|
4
|
-
argument-hint: <feature_id> [--max=N] [--no-build] [--rebuild]
|
|
4
|
+
argument-hint: <feature_id> [--max=N] [--no-build] [--rebuild] [--resume]
|
|
5
5
|
allowed-tools: Bash(bash ~/.claude/pipeline/scripts/loop.sh:*), Bash(bash .claude/pipeline/scripts/loop.sh:*), Bash(test:*), Read(specs/reports/**)
|
|
6
6
|
disable-model-invocation: true
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are the **launcher**, not the loop. Run the driver for **$ARGUMENTS** and relay three lines.
|
|
10
10
|
|
|
11
|
+
> **This command was `/drive` until 1.6.0.** Claude Code ships its own built-in `/drive` (run a prompt on
|
|
12
|
+
> a recurring interval), which **shadowed** this one: typing `/drive <id>` started the interval runner
|
|
13
|
+
> with the feature id as its prompt, so the driver below never ran and the session reported a loop that
|
|
14
|
+
> did not exist. The shipped script keeps its `loop.sh` name — nothing about a user's install path
|
|
15
|
+
> changes, only what you type.
|
|
16
|
+
>
|
|
11
17
|
> This command exists because a slash command cannot `/clear` itself. Every phase of the loop runs
|
|
12
18
|
> as a **separate `claude -p` child session** with its own fresh context, driven by a bash script —
|
|
13
19
|
> so the diff, the N review reports and the N contracts never accumulate in YOUR history, which is
|
|
@@ -25,8 +31,15 @@ test -f .claude/pipeline/scripts/loop.sh \
|
|
|
25
31
|
```
|
|
26
32
|
|
|
27
33
|
Pass `$ARGUMENTS` through untouched — the script owns its own flag parsing (`--max=N`,
|
|
28
|
-
`--no-build`, `--rebuild`) and exits 64 on anything it doesn't know. Don't validate flags
|
|
29
|
-
don't rewrite them, don't add any.
|
|
34
|
+
`--no-build`, `--rebuild`, `--resume`) and exits 64 on anything it doesn't know. Don't validate flags
|
|
35
|
+
yourself, don't rewrite them, don't add any.
|
|
36
|
+
|
|
37
|
+
**Resume is the human's call, not yours.** The loop records its position in the spec's front-matter
|
|
38
|
+
(`status: in-progress` · `loop_pass` · `loop_phase` — SCHEMA.md §Spec status), so a run killed by a
|
|
39
|
+
dead session, a ceiling or a `blocked` exit can continue with `--resume` instead of re-paying the
|
|
40
|
+
passes it already made. If the human types `/drive <id>` on a spec whose front-matter says
|
|
41
|
+
`status: in-progress` or `blocked` with `loop_pass` > 1, say so in one line and ask whether to resume
|
|
42
|
+
or restart — never silently add the flag, and never silently restart from pass 1.
|
|
30
43
|
|
|
31
44
|
**Never read `specs/reports/<id>.loop.log`.** It holds the full transcript of every child session —
|
|
32
45
|
the entire diff, every review report, every fix handoff. Pulling it into this session re-imports
|
|
@@ -38,7 +51,9 @@ open it in an editor for free. The same goes for the per-surface `.diff` and `.p
|
|
|
38
51
|
|
|
39
52
|
The script prints one line per phase and one closing line; that is your raw material. For exit
|
|
40
53
|
**1** or **3** only, also Read `specs/reports/<id>.verdict.json` (small, structured, safe) to name
|
|
41
|
-
the remaining findings — never the markdown report, which is the findings body in full.
|
|
54
|
+
the remaining findings — never the markdown report, which is the findings body in full. For exit
|
|
55
|
+
**4**, Read `specs/reports/<id>.readiness.json` instead (also small) and relay its `gaps`. On any
|
|
56
|
+
other exit the closing line already carries the deferred count, so read nothing.
|
|
42
57
|
|
|
43
58
|
| exit | meaning | what to say |
|
|
44
59
|
| ---- | ------- | ----------- |
|
|
@@ -46,14 +61,18 @@ the remaining findings — never the markdown report, which is the findings body
|
|
|
46
61
|
| `1` | ceiling hit | the fix was progressing but ran out of passes ⇒ re-run with a higher `--max` |
|
|
47
62
|
| `2` | no usable verdict | `/review` produced nothing, or aborted on a red preflight — the closing line says which; point at `specs/reports/<id>.preflight.txt` |
|
|
48
63
|
| `3` | non-convergent | the same blocking findings survived a fix pass; a higher `--max` will NOT help — the human needs to look at them (list them from the verdict) |
|
|
64
|
+
| `4` | not implementable | `/build`'s readiness gate returned `NOT-READY` — the frozen spec cannot be built and **no agent ran**; Read `specs/reports/<id>.readiness.json` (small, structured) and relay its `gaps`, then point at `/spec <id>`. More passes cannot fix this |
|
|
49
65
|
| `64` | usage | relay the script's own message verbatim |
|
|
50
66
|
|
|
51
|
-
Then print exactly three lines and nothing else
|
|
67
|
+
Then print exactly three lines and nothing else — plus a fourth **only when the verdict carries
|
|
68
|
+
`deferred` > 0** (findings that were real but out of this feature's scope, parked in the backlog by
|
|
69
|
+
`/review` §3.5; they are not blocking and never cost a pass, but they are not nothing either):
|
|
52
70
|
|
|
53
71
|
```
|
|
54
|
-
outcome: <one clause — clean / ceiling / no verdict / non-convergent / usage>
|
|
72
|
+
outcome: <one clause — clean / ceiling / no verdict / non-convergent / not implementable / usage>
|
|
55
73
|
iterations: <n> review pass(es)<, m fix pass(es) committed>
|
|
56
74
|
remaining: <blocking count + one short phrase per blocking item, or "none">
|
|
75
|
+
deferred: <n> parked in specs/refactor-backlog.md — /refactor <domain> when you want them
|
|
57
76
|
```
|
|
58
77
|
|
|
59
78
|
Add at most one follow-up sentence: the next command to run. Never restate a finding's fix, never
|
package/core/commands/fix.md
CHANGED
|
@@ -50,6 +50,11 @@ that change the *contract*; `/fix` is for everything else.
|
|
|
50
50
|
|
|
51
51
|
When the agents return:
|
|
52
52
|
|
|
53
|
+
- **Roll call first (SCHEMA.md §Dead agents).** A re-dispatched agent that returns nothing has fixed
|
|
54
|
+
nothing you can verify. Retry that surface ONCE with the byte-identical dispatch; still silent ⇒ leave
|
|
55
|
+
**every one of its items `- [ ]`** (a dead agent never ticks a box — that would hide an open finding
|
|
56
|
+
from the next round and from the driver), print `<key> · DEAD — items untouched`, and say the surface
|
|
57
|
+
is unverified.
|
|
53
58
|
- **Tick the resolved items.** Each handoff's `## Remediation addressed` lists what that agent fixed
|
|
54
59
|
(by `file:line`). For every Remediation item an agent reports fixed, flip its `- [ ]` → `- [x]` in
|
|
55
60
|
`specs/<id>.md` and append a terse ` — fixed: <what/where>` note (the convention prior rounds already
|
package/core/commands/review.md
CHANGED
|
@@ -86,9 +86,25 @@ metrics line needs it.
|
|
|
86
86
|
|
|
87
87
|
## 3. Merge & relay the verdict
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
**Roll call FIRST — a dead reviewer is not a clean surface.** Every surface you dispatched in §2 must
|
|
90
|
+
come back with a REVIEW REPORT. A reviewer that died (rate limit, transport error, exhausted context)
|
|
91
|
+
returns **nothing**, and zero findings from a dead reviewer is byte-identical to zero findings from a
|
|
92
|
+
genuinely clean one — which is how "every reviewer crashed" reads as the strongest possible verdict
|
|
93
|
+
from no evidence at all (SCHEMA.md §Dead agents). So:
|
|
94
|
+
|
|
95
|
+
- **Retry a silent surface ONCE**, byte-identical dispatch. Most deaths are transient, and the staged
|
|
96
|
+
diff is already on disk — the retry costs one agent, not a re-review.
|
|
97
|
+
- **Silent twice ⇒ that surface is `unreviewed`.** Name it in the report under
|
|
98
|
+
`## NOT reviewed (no verdict on these)`, list it in the verdict JSON's `unreviewed`, and **refuse to
|
|
99
|
+
score `SHIP`** — the merged verdict is at least `REVISE`. Absence of evidence is not evidence of
|
|
100
|
+
absence, and it must never reach `/ship` or tick a DoD box.
|
|
101
|
+
- **Never re-review the other surfaces** to compensate: their reports are valid and already on disk.
|
|
102
|
+
|
|
103
|
+
Then merge the returned reports into **one** REVIEW REPORT (same template): findings concatenated and
|
|
90
104
|
re-ordered by severity, counts summed, duplicates collapsed, verdict = the worst returned
|
|
91
|
-
(`BLOCK` > `REVISE` > `SHIP`).
|
|
105
|
+
(`BLOCK` > `REVISE` > `SHIP`). The `## Deferred` sections merge the same way (dedupe by
|
|
106
|
+
`file` + problem) and stay **out of the severity table and out of the verdict** — see §3.5, which
|
|
107
|
+
routes them. Append ONE metrics line for the batch to `pipeline-metrics.jsonl`
|
|
92
108
|
(main-checkout path + rules in `/build` §4): `{"ts":"<ISO>","feature":"$ARGUMENTS","phase":"review","seconds":<wall-clock>,"surfaces":{"<key>":"<verdict>:<finding count>",…}}`.
|
|
93
109
|
In the same Bash call, chain the opt-in usage ping (`/build` §4, `phase: "review"`, results = the
|
|
94
110
|
merged verdict + total finding count, e.g. `"REVISE:3"`).
|
|
@@ -97,11 +113,11 @@ merged verdict + total finding count, e.g. `"REVISE:3"`).
|
|
|
97
113
|
non-recursive `specs/*.md` glob, so it's never mistaken for a spec (no phantom card, no bogus stage).
|
|
98
114
|
**Write the machine-readable verdict** to `specs/reports/$ARGUMENTS.verdict.json` (overwrite) — on
|
|
99
115
|
**every** run, including the small-diff fast path of §2 and a `SHIP`. This file is the ONLY contract
|
|
100
|
-
between the pipeline and an automated driver (`/
|
|
116
|
+
between the pipeline and an automated driver (`/drive`), which parses no prose:
|
|
101
117
|
|
|
102
118
|
```json
|
|
103
119
|
{ "id": "$ARGUMENTS", "phase": "review", "ts": "<ISO>", "verdict": "REVISE",
|
|
104
|
-
"findings": 7, "blocking": 2, "security": 1,
|
|
120
|
+
"findings": 7, "blocking": 2, "security": 1, "deferred": 3, "unreviewed": [],
|
|
105
121
|
"severity": {"CRITICAL": 1, "HIGH": 2, "MEDIUM": 3, "LOW": 1},
|
|
106
122
|
"surfaces": {"backend": {"verdict":"BLOCK","findings":4,"blocking":2}},
|
|
107
123
|
"blocking_items": ["backend|apps/api/src/routes/order.ts|missing authz on post"],
|
|
@@ -121,12 +137,42 @@ between the pipeline and an automated driver (`/loop`), which parses no prose:
|
|
|
121
137
|
`printf '%s\n' "<item>" … | LC_ALL=C sort | sha256sum | cut -c1-16` (`shasum -a 256` where there
|
|
122
138
|
is no `sha256sum`). Empty list ⇒ `""`. A driver comparing two consecutive fingerprints detects a
|
|
123
139
|
fix loop that is treading water.
|
|
140
|
+
- **`deferred`** — the count of merged `## Deferred` items §3.5 parked in the backlog. Informational:
|
|
141
|
+
it never enters `blocking`, so it can never cost a driver an iteration.
|
|
142
|
+
- **`unreviewed`** — the surface keys whose reviewer died twice, `[]` on a complete run. It is
|
|
143
|
+
**separate from `blocking` on purpose**: `blocking` counts real findings (CRITICAL + security), and
|
|
144
|
+
faking a number there to force a driver's hand would corrupt the one field the whole contract rests
|
|
145
|
+
on. A non-empty `unreviewed` means "this run does not cover everything" — a driver treats it as no
|
|
146
|
+
usable verdict, never as clean, whatever `blocking` says.
|
|
147
|
+
|
|
148
|
+
## 3.5 Route the deferred findings — the backlog, not the fix loop
|
|
149
|
+
|
|
150
|
+
Do this on **every** run, before the verdict branch below, and whatever the verdict — a deferred
|
|
151
|
+
finding that is only routed on a `SHIP` is a deferred finding lost on every other verdict, which is
|
|
152
|
+
exactly the leak this step closes. Append each merged `## Deferred` item to
|
|
153
|
+
**`specs/refactor-backlog.md`**, under the `## <domain>` heading of the surface that owns its
|
|
154
|
+
`file:line` (create the file and/or heading if absent — same grouping `/audit` writes, so
|
|
155
|
+
`/refactor <domain>` picks them up with no extra plumbing):
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
- [ ] <SEVERITY> · <file:line> · <quality|security|rule> · <concrete fix> · deferred:$ARGUMENTS
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- **Never into the spec's `## Remediation`** — that list is what `/fix` re-dispatches and what `/drive`
|
|
162
|
+
waits on, so a deferred item there would re-trigger the very loop it was deferred out of.
|
|
163
|
+
- **Dedupe before appending:** `grep -F` the backlog for the item's `<file>` + the first words of its
|
|
164
|
+
problem; already there (from a prior round or an `/audit`) ⇒ skip it, don't stack duplicates round
|
|
165
|
+
after round.
|
|
166
|
+
- Append with `>>` in ONE Bash call; never read the whole backlog into context to rewrite it (it grows
|
|
167
|
+
with every audit the repo has ever run).
|
|
168
|
+
- Report it as **one line** in chat: `deferred: <n> parked in specs/refactor-backlog.md (<domains>)`.
|
|
124
169
|
|
|
125
170
|
In chat print ONLY: the verdict, the severity-count table, a one-line digest of each CRITICAL/security
|
|
126
171
|
finding, and `Full report: specs/reports/$ARGUMENTS.md` — never echo the findings body into chat (it
|
|
127
172
|
would sit in this session's history, re-sent every turn). Then:
|
|
128
173
|
|
|
129
|
-
- **SHIP** →
|
|
174
|
+
- **SHIP** → only reachable with `unreviewed` empty (the roll call above forbids it otherwise). A SHIP
|
|
175
|
+
verdict *is* the pipeline's statement that the feature meets its Definition of
|
|
130
176
|
Done, so **tick the DoD**: in `specs/$ARGUMENTS.md` §`Acceptance criteria / DoD`, flip each `- [ ]`
|
|
131
177
|
→ `- [x]` for the criteria the pipeline has actually verified — spec conformance + `ui_language`
|
|
132
178
|
copy (this review), tests · lint · typecheck (a green `/build`), mobile-first as far as the code
|
|
@@ -141,12 +187,15 @@ would sit in this session's history, re-sent every turn). Then:
|
|
|
141
187
|
of exactly the source you just reviewed (specs excluded, so DoD ticks + the ship status flip don't
|
|
142
188
|
trip it). Then tell the human they can `/ship` — **recommend a `/clear` first**, the handoff is
|
|
143
189
|
fully on disk. **SHIP with leftover LOW findings** (or LOW+MEDIUM at the human's call) does NOT
|
|
144
|
-
force a fix cycle for nits: park them
|
|
145
|
-
open `## Remediation` items, which would
|
|
146
|
-
freshness stamp, and let the human ship.
|
|
190
|
+
force a fix cycle for nits: park them through §3.5's exact route (the backlog, under their surface's
|
|
191
|
+
domain heading, tagged `deferred:$ARGUMENTS` — never as open `## Remediation` items, which would
|
|
192
|
+
re-trigger the fix loop), keep the SHIP verdict and the freshness stamp, and let the human ship.
|
|
147
193
|
- **REVISE / BLOCK**, or any CRITICAL/HIGH/security finding → tell the human to run
|
|
148
194
|
**`/fix $ARGUMENTS`** — it appends the report to the spec's `## Remediation` and re-dispatches ONLY
|
|
149
|
-
the surfaces with findings.
|
|
195
|
+
the surfaces with findings. (If they'd rather automate the rounds, the autonomous driver is
|
|
196
|
+
`disable-model-invocation: true` on purpose: **you cannot start it, they must type it**. Name the
|
|
197
|
+
exact line for them to type rather than attempting it — an attempt that silently fails reads as a
|
|
198
|
+
loop that is running when nothing is.) The full path (`/spec` Mode B then `/build`) remains for findings that
|
|
150
199
|
change the contract in ways that ripple into clean surfaces. _The report is staged to
|
|
151
200
|
`specs/reports/$ARGUMENTS.md`, so you can `/clear` before `/fix` — it reads the findings back from
|
|
152
201
|
disk._
|