cohorte 2.1.0 → 2.3.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 +173 -0
- package/README.md +49 -41
- package/bin/cli.js +324 -28
- package/core/adapter/render.js +389 -0
- package/core/agents/implementer.template.md +3 -3
- package/core/agents/release.md +7 -6
- package/core/agents/review.md +17 -2
- package/core/commands/cohorte-audit.md +2 -0
- package/core/commands/cohorte-brainstorm.md +3 -11
- package/core/commands/cohorte-build.md +37 -23
- package/core/commands/cohorte-doctor.md +61 -36
- package/core/commands/cohorte-fix.md +3 -5
- package/core/commands/cohorte-init-pipeline.md +7 -8
- package/core/commands/cohorte-patch.md +113 -0
- package/core/commands/cohorte-refactor.md +5 -2
- package/core/commands/cohorte-review.md +20 -18
- package/core/commands/cohorte-ship.md +13 -14
- package/core/commands/cohorte-spec.md +4 -13
- package/core/commands/cohorte-update-pipeline.md +13 -12
- package/core/hooks/gate.py +203 -16
- package/core/runtimes/claude.json +73 -0
- package/core/runtimes/codex.json +82 -0
- package/core/runtimes/cursor.json +75 -0
- package/core/runtimes/gemini.json +75 -0
- package/core/runtimes/opencode.json +72 -0
- package/core/templates/patch.template.md +86 -0
- package/core/templates/spec.template.md +1 -3
- package/core/templates/steps/init-pipeline/01-detect-stack.md +1 -1
- package/core/templates/steps/init-pipeline/02-interview-gaps.md +1 -11
- package/core/templates/steps/init-pipeline/04-write-render.md +23 -17
- package/core/templates/steps/init-pipeline/05-report.md +1 -1
- package/core/workflows/review.js +1 -3
- package/dashboard/dist/assets/{index-P1I1JGtj.js → index-D1rsbLat.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/server/doctor.js +156 -69
- package/dashboard/server/index.js +12 -2
- package/dashboard/server/metrics.js +13 -6
- package/dashboard/server/runtime.js +115 -0
- package/dashboard/server/versions.js +12 -1
- package/install.ps1 +26 -3
- package/install.sh +28 -6
- package/package.json +6 -2
- package/profile/PIPELINE.template.md +8 -6
- package/profile/SCHEMA.md +70 -108
- package/profile/cohorte.config.template.yaml +0 -16
- package/scripts/kanban-move.sh +11 -1
- package/scripts/metrics/collect.mjs +5 -3
- package/scripts/preflight.sh +27 -8
- package/scripts/test-adapter.mjs +368 -0
- package/scripts/test-dashboard.mjs +70 -0
- package/scripts/test-gate.mjs +62 -0
- package/scripts/validate-core.mjs +26 -24
- package/core/commands/cohorte-loop.md +0 -110
- package/scripts/loop-detach.sh +0 -153
- package/scripts/loop.sh +0 -399
- package/scripts/telemetry-send.sh +0 -77
- package/scripts/test-loop.mjs +0 -330
|
@@ -11,8 +11,7 @@ You are the **lead**. Build feature **$ARGUMENTS** from its frozen spec.
|
|
|
11
11
|
> re-read if it's already in your context this session and unmodified since._
|
|
12
12
|
>
|
|
13
13
|
> **Kanban** (SCHEMA.md §Kanban): once §1 confirms the frozen spec, run
|
|
14
|
-
> `<core>/pipeline/scripts/kanban-move.sh auto $ARGUMENTS building`
|
|
15
|
-
> `~/.claude` global — probe with `test -x`). `auto` resolves the board from the config itself and
|
|
14
|
+
> `<core>/pipeline/scripts/kanban-move.sh auto $ARGUMENTS building`. `auto` resolves the board from the config itself and
|
|
16
15
|
> exits 0 with a `kanban: <reason>` line when there is none — so **never decide "no board is
|
|
17
16
|
> configured" without running it**. That inference, not a missing board, is what used to freeze
|
|
18
17
|
> cards mid-pipeline.
|
|
@@ -20,13 +19,18 @@ You are the **lead**. Build feature **$ARGUMENTS** from its frozen spec.
|
|
|
20
19
|
## 1. Load & check
|
|
21
20
|
|
|
22
21
|
- Check the spec front-matter FIRST — `grep '^status:' specs/$ARGUMENTS.md` (or Read with a ~15-line
|
|
23
|
-
limit) — before any full read. Buildable statuses are `frozen`, `in-review` and `in-progress`
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
limit) — before any full read. Buildable statuses are `frozen`, `in-review` and `in-progress`
|
|
23
|
+
(SCHEMA.md §Spec status). `blocked` means a previous round gave up here: say so, and route by the
|
|
24
|
+
spec's `## Remediation` — open items ⇒ `/cohorte-fix`, none ⇒
|
|
26
25
|
continue this build. Anything else (`draft`, missing, `shipped`) ⇒ stop and tell the human to run
|
|
27
26
|
`/cohorte-spec` first. Only then read the body, selectively: front-matter, §5 contract, the surface
|
|
28
27
|
task sections, and `## Remediation` (fall back to a full read if the spec doesn't follow the
|
|
29
28
|
template's headings).
|
|
29
|
+
- **`kind: patch` in the front-matter ⇒ this is a bug fix** frozen by `/cohorte-patch`, and it is
|
|
30
|
+
built by this command like any other spec, with two differences called out where they apply: §1.6
|
|
31
|
+
judges it against its regression test instead of a contract, and §2 authors no contract unless §5
|
|
32
|
+
carries a delta. Everything else — surface mapping, parallel dispatch, roll call, metrics — is
|
|
33
|
+
identical, and `kind` absent means feature, so nothing changes for existing specs.
|
|
30
34
|
- **Route check** — if `## Remediation` has open `- [ ]` items and none requires a contract change,
|
|
31
35
|
stop and tell the human to run `/cohorte-fix $ARGUMENTS` instead: it re-dispatches only the surfaces with
|
|
32
36
|
findings. A full build with open items is only right when the contract change ripples into clean
|
|
@@ -58,13 +62,13 @@ Map every area the spec touches (§5 contract + each surface's tasks + touched p
|
|
|
58
62
|
For each surface to add: infer its `key`, `path`, `label`, `agent`, `tools`, `model`, `*_cmd`s, and
|
|
59
63
|
`uses_design` (mirror a sibling surface), show the human a one-line proposal, and on go-ahead **render it now** per
|
|
60
64
|
SCHEMA.md §"Rendering / reconciling a surface agent" — write the `surfaces[]` entry + §Conventions/§Testing
|
|
61
|
-
stanza into `PIPELINE.md`, render
|
|
65
|
+
stanza into `PIPELINE.md`, render `<agents>/<agent>.md` from the implementer template, applying the
|
|
62
66
|
shared-code rule (shared trees get a single-owner surface; cross-slice shapes go through the contract).
|
|
63
67
|
This is the automatic path: you don't send the human back to `/cohorte-init-pipeline`. If nothing new is needed,
|
|
64
68
|
say so and continue. Dispatch (§3) then covers the reconciled surface list.
|
|
65
69
|
|
|
66
70
|
**Adding or splitting a surface is an architectural decision** — append ONE line for it to
|
|
67
|
-
`specs/_decisions.md` §Live (SCHEMA.md §Decisions; create from
|
|
71
|
+
`specs/_decisions.md` §Live (SCHEMA.md §Decisions; create from `<core>/templates/decisions.template.md`
|
|
68
72
|
if absent), area `surfaces`, e.g.
|
|
69
73
|
`- <date> · surfaces · <key> owns <path>, single owner of <what> — because <the boundary reason> · $ARGUMENTS`.
|
|
70
74
|
One `>>` in the Bash call you're already making. Nothing added ⇒ nothing to append.
|
|
@@ -80,6 +84,13 @@ good idea (that was `/cohorte-brainstorm`), never by re-reading files you don't
|
|
|
80
84
|
request fields with types + validation, the success shape, and its error cases. A missing
|
|
81
85
|
**request or success shape** ⇒ `NOT-READY` (an implementer would invent it, and the other surface
|
|
82
86
|
would invent a different one). A missing **error case** ⇒ `RESERVATIONS`.
|
|
87
|
+
**On a `kind: patch` spec this check is replaced, not skipped** — a patch has no contract to be
|
|
88
|
+
complete, so judge §1 Symptom & repro + §4 Regression test instead: no stated expected behaviour,
|
|
89
|
+
or a §4 that names no test and no reason the fix would be verifiable ⇒ `NOT-READY` (an implementer
|
|
90
|
+
would fix whatever it guessed the bug was, and nothing would catch a wrong guess). A repro
|
|
91
|
+
explicitly frozen as a hypothesis, or a cause left to the implementer to find, is
|
|
92
|
+
`RESERVATIONS` — normal for a patch, never a blocker. Then judge §5 as above **only** if it
|
|
93
|
+
carries a delta rather than `none`.
|
|
83
94
|
2. **Surface coverage** — every §6 task maps to a surface in the reconciled list, and every contract
|
|
84
95
|
entry has an owner **on each side it names** (producer and consumer). A contract entry no surface
|
|
85
96
|
owns ⇒ `NOT-READY`.
|
|
@@ -94,8 +105,8 @@ good idea (that was `/cohorte-brainstorm`), never by re-reading files you don't
|
|
|
94
105
|
|
|
95
106
|
Write the machine-readable verdict to `specs/reports/$ARGUMENTS.readiness.json` (overwrite,
|
|
96
107
|
`mkdir -p specs/reports` first — the same gitignored buffer dir `/cohorte-review` stages into, which may not
|
|
97
|
-
exist yet on a first build) — on **every** build, including `READY`. It is the only channel between
|
|
98
|
-
which parses no prose:
|
|
108
|
+
exist yet on a first build) — on **every** build, including `READY`. It is the only channel between
|
|
109
|
+
this gate and any automated driver, which parses no prose:
|
|
99
110
|
|
|
100
111
|
```json
|
|
101
112
|
{ "id": "$ARGUMENTS", "phase": "readiness", "ts": "<ISO>", "verdict": "RESERVATIONS",
|
|
@@ -104,7 +115,8 @@ which parses no prose:
|
|
|
104
115
|
```
|
|
105
116
|
|
|
106
117
|
- **`gaps`** — one normalized string per gap, `<check>|<where>|<what is missing>`: `<check>` is
|
|
107
|
-
`contract` · `coverage` · `dependency` · `ambiguity` · `design
|
|
118
|
+
`contract` · `coverage` · `dependency` · `ambiguity` · `design` — plus `repro` on a `kind: patch`
|
|
119
|
+
spec, for a gap check 1 raised against §1/§4; `<where>` is the contract entry,
|
|
108
120
|
surface key or dependency name (no `:line` — it shifts on every edit); `<what>` is the gap, not the
|
|
109
121
|
fix. `READY` ⇒ `[]`.
|
|
110
122
|
- **`NOT-READY` ⇒ STOP: author no contract and spawn NO agent.** Print the gaps and send the human to
|
|
@@ -118,6 +130,15 @@ which parses no prose:
|
|
|
118
130
|
|
|
119
131
|
## 2. Author the contract (lead-only — the single sync channel)
|
|
120
132
|
|
|
133
|
+
_Skipped entirely on a `kind: patch` spec whose §5 Contract delta is `none`_ — which is the usual
|
|
134
|
+
case: a bug fix corrects behaviour behind a shape that already exists, and re-authoring that shape
|
|
135
|
+
would put the contract file in the diff for nothing. Say you skipped it and why, in one line. A patch
|
|
136
|
+
whose §5 **does** carry a delta is authored exactly as below, from the delta, against the existing
|
|
137
|
+
file — never rewritten from scratch. (A patch needing *new* contract surface area never reaches here:
|
|
138
|
+
`/cohorte-patch` §3 routes it to `/cohorte-spec`.) When you skip, still run `date +%s` on its own —
|
|
139
|
+
the skipped postcondition is where §4's wall-clock start comes from, and a build with no start epoch
|
|
140
|
+
writes a metrics line with no duration.
|
|
141
|
+
|
|
121
142
|
_Only if `contract.enabled`._ From §5 of the spec, write/update the feature's contract file at
|
|
122
143
|
`<contract.path>/$ARGUMENTS.<contract.ext>` in the profile's `mechanism` (e.g. Zod v4 schemas + inferred
|
|
123
144
|
types for `shared-types-zod`). Export it from `contract.index` if set. This is the ONLY file the agents
|
|
@@ -129,7 +150,7 @@ wall-clock start — no separate timing call).
|
|
|
129
150
|
|
|
130
151
|
## 3. Dispatch one implementer per surface — IN PARALLEL
|
|
131
152
|
|
|
132
|
-
Spawn every surface's agent in a **single message** (one
|
|
153
|
+
Spawn every surface's agent in a **single message** (one dispatch each) so they run concurrently —
|
|
133
154
|
NEVER serially: build wall-clock must be the slowest surface, not the sum. Use
|
|
134
155
|
the reconciled `surfaces` list from §1.5 (existing + any just-rendered). Give EACH only what a stateless
|
|
135
156
|
agent needs — re-supply everything every time, as **exact file paths** (spec, contract, the surface's
|
|
@@ -153,11 +174,11 @@ tree. For each surface in `surfaces`:
|
|
|
153
174
|
|
|
154
175
|
## 3.5 Roll call — account for EVERY dispatch before integrating
|
|
155
176
|
|
|
156
|
-
A
|
|
177
|
+
A surface's work can die: a rate limit mid-run, a transport error after retries, context exhausted.
|
|
157
178
|
When it does, it returns **nothing** — and nothing is byte-identical to "a clean surface with nothing
|
|
158
179
|
to report". Silence is not a green light; treat it as the failure it is (SCHEMA.md §Dead agents).
|
|
159
180
|
|
|
160
|
-
- **Roll call.** Every surface
|
|
181
|
+
- **Roll call.** Every surface handled in §3 must come back with a handoff in the format its
|
|
161
182
|
agent instructions define. Missing, empty, or truncated mid-sentence ⇒ that surface is **dead**.
|
|
162
183
|
- **Never infer success from silence,** and never speak for a dead agent — you did not see its work.
|
|
163
184
|
- **Retry that surface ONCE, alone.** Re-dispatch it with the byte-identical §3 prompt. The other
|
|
@@ -174,9 +195,9 @@ to report". Silence is not a green light; treat it as the failure it is (SCHEMA.
|
|
|
174
195
|
When all return, flag any contract mismatch or failing test from the handoffs; otherwise print one
|
|
175
196
|
status line per surface (`<key> · tests pass/fail · <n> TODOs`) — do not restate handoff content.
|
|
176
197
|
A dead surface (§3.5) prints `<key> · DEAD — unverified` and **the batch is never reported as ok**.
|
|
177
|
-
Append **ONE line for the batch** to the **main checkout's**
|
|
198
|
+
Append **ONE line for the batch** to the **main checkout's** `<state>/pipeline-metrics.jsonl` —
|
|
178
199
|
NOT the worktree's, which dies at teardown while metrics must accumulate across features. Resolve
|
|
179
|
-
it from anywhere: `$(dirname "$(git rev-parse --git-common-dir)")
|
|
200
|
+
it from anywhere: `$(dirname "$(git rev-parse --git-common-dir)")/<state>/pipeline-metrics.jsonl`
|
|
180
201
|
(in the main checkout this resolves to itself). Create it if absent; it must be gitignored.
|
|
181
202
|
Compute the elapsed time in the same Bash call
|
|
182
203
|
(`echo "{...\"seconds\":$(($(date +%s)-<start epoch from §2>)),...}" >> …`):
|
|
@@ -187,14 +208,7 @@ anything went wrong. In the same call write the machine-readable batch result to
|
|
|
187
208
|
`specs/reports/$ARGUMENTS.build.json` (overwrite) — the channel an automated driver reads, since it
|
|
188
209
|
never sees your chat:
|
|
189
210
|
`{"id":"$ARGUMENTS","phase":"build","ts":"<ISO>","surfaces":{"<key>":"ok|error|dead",…},"dead":["<key>",…]}`
|
|
190
|
-
— this is the evidence SCHEMA.md §Specialization asks for before splitting a surface.
|
|
191
|
-
Bash call, chain the opt-in usage ping — **the shared form every phase command reuses**:
|
|
192
|
-
`<core>/pipeline/scripts/telemetry-send.sh <phase> "$ARGUMENTS" <seconds> "<results>" || true`
|
|
193
|
-
(`<core>` = `~/.claude` global / `.claude` bundled; here `<phase>` = `build`, `<results>` =
|
|
194
|
-
`<ok,ok|error,…>`) — a silent no-op unless the human explicitly consented (SCHEMA.md §Telemetry);
|
|
195
|
-
never ask about consent here. `/cohorte-review` and `/cohorte-fix` chain the same line with their own
|
|
196
|
-
phase + results. The `|| true` swallows a **missing** script too, so a half-copied core goes
|
|
197
|
-
silent rather than loud — `/cohorte-doctor` check 1 is what catches that.
|
|
211
|
+
— this is the evidence SCHEMA.md §Specialization asks for before splitting a surface.
|
|
198
212
|
Then tell the human: exercise the feature by hand if it's worth it, then run `/cohorte-review $ARGUMENTS` —
|
|
199
213
|
unless a surface is dead, in which case say so first and let them decide whether to re-run `/cohorte-build`
|
|
200
214
|
(a dead surface has no findings, so `/cohorte-fix` has nothing to re-dispatch).
|
|
@@ -12,8 +12,17 @@ fix only with the human's go-ahead (or hand them the command).
|
|
|
12
12
|
|
|
13
13
|
## Checks, in order
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
0. **Runtime.** Say which coding agent you are running as and what it can enforce — every check
|
|
16
|
+
below is read through it. **You already know which one**: the Runtime preamble at the top of
|
|
17
|
+
this file names it. Read `<core>/pipeline/runtimes.json` for the details — a map of every
|
|
18
|
+
runtime installed against this core, since they share one core. Report one line:
|
|
19
|
+
`runtime: <label> · scope <global|project> · hooks <yes|no> · workflows <yes|no>`,
|
|
20
|
+
and name the other installed runtimes if there are any (they share `<state>` and `<config>`, so
|
|
21
|
+
a board or a gate config wired from one is seen by all — that is intended, and worth stating).
|
|
22
|
+
File absent ⇒ a core installed before the adapter existed ⇒ ⚠️, fix by re-running the installer.
|
|
23
|
+
A runtime without hooks makes check 3's gate **advisory** — say so there rather than
|
|
24
|
+
reporting a false ✅.
|
|
25
|
+
1. **Core & pointer.** A core exists (`<core>/pipeline/VERSION`); `<state>/pipeline.json` names a mode + `core_version`
|
|
17
26
|
coherent with the VERSION file. A **global**-mode pointer lagging the VERSION file is ⚠️, not ❌:
|
|
18
27
|
nothing bumped that field before 1.2.5, so the core itself is fine and only the pointer is stale
|
|
19
28
|
⇒ fix by running `/cohorte-update-pipeline` (§3 syncs it now), or by editing the one field. Compare
|
|
@@ -21,40 +30,57 @@ fix only with the human's go-ahead (or hand them the command).
|
|
|
21
30
|
commands' step files are present — `templates/steps/init-pipeline/` non-empty (a router whose
|
|
22
31
|
`templates/steps/<cmd>/` dir is missing is a partial/stale install ⇒
|
|
23
32
|
re-run install/update). **Shipped scripts present and executable** in `<core>/pipeline/scripts/`:
|
|
24
|
-
`kanban-move.sh`, `
|
|
33
|
+
`kanban-move.sh`, `preflight.sh`,
|
|
25
34
|
`new-feature.sh.template`, `remove-feature.sh.template` — ❌ any missing one.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"some script is missing". Every caller chains these with `|| true`, so an absent script is a **silent**
|
|
29
|
-
no-op (no kanban card moves, no telemetry ping, no error anywhere) — this check is the only thing
|
|
35
|
+
Every caller chains these with `|| true`, so an absent script is a **silent**
|
|
36
|
+
no-op (no kanban card moves, no error anywhere) — this check is the only thing
|
|
30
37
|
that sees it. Also flag ❌ a `VERSION` **newer than** the other `pipeline/` files (compare mtimes):
|
|
31
38
|
a version bumped without a full re-copy is a half-done update ⇒ re-run install/update.
|
|
32
39
|
2. **Profile.** `PIPELINE.md` exists and its `yaml pipeline-profile` block parses. Every
|
|
33
|
-
`surfaces[].agent` has its
|
|
40
|
+
`surfaces[].agent` has its `<agents>/<agent>.md` and every agent file has its `surfaces[]`
|
|
34
41
|
entry — **no orphans either way** (SCHEMA.md rule). Each rendered agent's frontmatter `tools`
|
|
35
42
|
matches its surface's `tools` (incl. `DesignSync` iff `uses_design`, retrieval MCP tools iff
|
|
36
43
|
`retrieval.provider` ≠ `none`). **Model pins:** each rendered agent's frontmatter `model` matches
|
|
37
44
|
its `surfaces[].model` — ❌ if missing, mismatched, or a literal `<SURFACE_MODEL>` placeholder
|
|
38
45
|
(all three silently fall back to inheriting the lead session's model — often Opus — on every
|
|
39
46
|
dispatch); ⚠️ any `inherit` with the note that it bills at the lead's tier. The generic agents
|
|
40
|
-
(`review.md`, `release.md`, `profile-reader.md`
|
|
41
|
-
each carry their `model:` line too (sonnet/haiku/haiku).
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
(`review.md`, `release.md`, `profile-reader.md` in `<agents>/`) must
|
|
48
|
+
each carry their `model:` line too (sonnet/haiku/haiku).
|
|
49
|
+
<!-- cohorte:if runtime:claude -->
|
|
50
|
+
**Command pins:** every mechanical command file
|
|
51
|
+
(`build`, `review`, `fix`, `ship`, `audit`, `refactor`, `doctor`, `align-ds`,
|
|
52
|
+
`update-pipeline` — in `<commands>/`) carries `model: sonnet` in
|
|
44
53
|
its frontmatter — ⚠️ if missing (the lead's orchestration turn then bills at the session model,
|
|
45
|
-
e.g. Opus/Fable). `brainstorm`, `spec`, and `init-pipeline` are intentionally unpinned
|
|
54
|
+
e.g. Opus/Fable). `brainstorm`, `spec`, `patch`, and `init-pipeline` are intentionally unpinned
|
|
46
55
|
(interactive — they inherit the session model).
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
registered
|
|
56
|
+
<!-- cohorte:endif -->
|
|
57
|
+
|
|
58
|
+
3. **Hooks & gate.** `<state>/gate-config.json` exists and mirrors the profile's `gate` block
|
|
59
|
+
(regenerate if drifted).
|
|
60
|
+
<!-- cohorte:if hooks -->
|
|
61
|
+
The gate hook is registered **once** in the config file the Runtime preamble names — flag a
|
|
62
|
+
double registration, it double-prompts — and its `command` points at a `gate.py` that exists.
|
|
63
|
+
Check the **matcher** actually covers what it must: on Claude Code that means both `Bash` and
|
|
64
|
+
`Task`, since the preflight phase gate keys off `Task` dispatches and a `Bash`-only matcher
|
|
65
|
+
leaves it silently dead (the 1.3.0–1.3.1 regression). Prove the wiring end to end rather than
|
|
66
|
+
trusting the file: `python3 <core>/hooks/gate.py --check "<a pattern from the ask list>"` must
|
|
67
|
+
return a non-`allow` verdict. If the Runtime preamble said this runtime has **no confirmation
|
|
68
|
+
tier**, state it here too: every `ask` pattern behaves as a `deny`, which is safe but stricter
|
|
69
|
+
than the profile reads, and a human who expects a prompt will read the refusal as a bug.
|
|
70
|
+
<!-- cohorte:endif -->
|
|
71
|
+
<!-- cohorte:if !hooks -->
|
|
72
|
+
This runtime has **no blocking hook**, so the gate is **advisory**: it only fires when the agent
|
|
73
|
+
calls it. Say that in one line rather than reporting ✅ — the enforcement property genuinely is
|
|
74
|
+
weaker here, and a human who thinks otherwise will approve less carefully. Verify what CAN be
|
|
75
|
+
verified: `<core>/hooks/gate.py` exists and `python3 <core>/hooks/gate.py --check "git push"`
|
|
76
|
+
returns a verdict line (a non-`allow` on a gated pattern proves config + script are wired). ❌ if
|
|
77
|
+
the script is missing or errors; ℹ️ "advisory (this runtime has no hooks)" otherwise.
|
|
78
|
+
<!-- cohorte:endif -->
|
|
53
79
|
Then the **preflight stamp is local, never versioned**: `git ls-files --error-unmatch
|
|
54
|
-
|
|
80
|
+
<state>/preflight.ok` must miss, and `.gitignore` must cover it. A tracked stamp is a ❌ (not a
|
|
55
81
|
⚠️) — it records the tree it verified, the commit that carries it moves HEAD past that tree, and
|
|
56
82
|
the committed copy lands in every clone and new worktree; the gate then blocks clean trees and
|
|
57
|
-
greens unchecked ones. fix: `git rm --cached
|
|
83
|
+
greens unchecked ones. fix: `git rm --cached <state>/preflight.ok` + add it to `.gitignore`.
|
|
58
84
|
4. **Retrieval** (if `retrieval.provider` ≠ `none`). Run the SCHEMA.md §Code retrieval health
|
|
59
85
|
check: CLI resolvable from PATH, `.mcp.json` entry present in PATH-proof launcher form,
|
|
60
86
|
`.serena/` gitignored, server actually connects.
|
|
@@ -70,13 +96,7 @@ fix only with the human's go-ahead (or hand them the command).
|
|
|
70
96
|
When ≥2 slots are live, print the parallel-feature table (feature · worktree · ports · db ·
|
|
71
97
|
branch behind main by N commits) — a worktree far behind main means its next review will diff
|
|
72
98
|
against stale code ⇒ suggest rebasing it.
|
|
73
|
-
7. **
|
|
74
|
-
status in one line: `disabled` / `enabled since <consent_date> · install_id <id> · endpoint <url>`
|
|
75
|
-
(the install_id is the human's GDPR erasure key — see SCHEMA.md §Telemetry). Flag ❌ any
|
|
76
|
-
incoherent state: `enabled: true` with no `install_id` or no `consent_date` (sending without
|
|
77
|
-
recorded consent — fix: set `enabled: false` until the consent question is re-run), or a
|
|
78
|
-
`telemetry:` block missing entirely on a current core (top up via `/cohorte-update-pipeline`).
|
|
79
|
-
7b. **Kanban** (the board mirror — SCHEMA.md §Kanban). Run
|
|
99
|
+
7. **Kanban** (the board mirror — SCHEMA.md §Kanban). Run
|
|
80
100
|
`<core>/pipeline/scripts/kanban-move.sh --check` and report its one line verbatim: the resolved
|
|
81
101
|
board path, or the exact link that is missing. A board mirror is optional, so "not configured" is
|
|
82
102
|
ℹ️, never ❌ — but it must be **stated**, because the whole class of bug here is a card that
|
|
@@ -85,6 +105,7 @@ fix only with the human's go-ahead (or hand them the command).
|
|
|
85
105
|
other key whose board file exists (a **rename** orphaned the link — re-key it via
|
|
86
106
|
`/cohorte-update-pipeline`), and an entry whose board file no longer exists at
|
|
87
107
|
`vault_path`-relative `board` (moved or renamed in the vault).
|
|
108
|
+
<!-- cohorte:if workflows -->
|
|
88
109
|
8. **Workflows** (the opt-in execution path — SCHEMA.md §Workflows; the conversational commands
|
|
89
110
|
stay the default, so failures here are ⚠️ at most, never ❌). Report which path this machine will
|
|
90
111
|
take and why:
|
|
@@ -92,8 +113,7 @@ fix only with the human's go-ahead (or hand them the command).
|
|
|
92
113
|
on PATH ⇒ conversational only.
|
|
93
114
|
- **Scripts present:** `<core>/workflows/review.js` + `audit.js` + `refactor.js` —
|
|
94
115
|
missing on a current core ⇒ half-done install, re-run install/update.
|
|
95
|
-
- **Phase-0 agent present:** `<agents
|
|
96
|
-
`~/.claude/agents/` global) — the workflows abort without it.
|
|
116
|
+
- **Phase-0 agent present:** `<agents>/profile-reader.md` — the workflows abort without it.
|
|
97
117
|
- **Workflows enabled in this session** — the `Workflow` tool is in your own toolset right now;
|
|
98
118
|
absent ⇒ disabled for this session (a setting or an old client), conversational path.
|
|
99
119
|
- **Preflight wiring** (used by both paths): `pipeline/scripts/preflight.sh` executable and
|
|
@@ -101,15 +121,20 @@ fix only with the human's go-ahead (or hand them the command).
|
|
|
101
121
|
End the check with ONE summary line, e.g.
|
|
102
122
|
`workflows: available (opt-in — ask to "run the review workflow")` or
|
|
103
123
|
`workflows: unavailable (<first failing prerequisite>) — conversational commands (the default)`.
|
|
124
|
+
<!-- cohorte:else -->
|
|
125
|
+
8. **Preflight wiring.** `<core>/pipeline/scripts/preflight.sh` is executable and
|
|
126
|
+
`gate-config.json` carries the `preflight` block — mismatch ⇒ regenerate from the profile.
|
|
127
|
+
(The workflow execution path does not exist on this runtime; the conversational commands are
|
|
128
|
+
the only path, which is also the default everywhere else. Not a defect — state it and move on.)
|
|
129
|
+
<!-- cohorte:endif -->
|
|
104
130
|
9. **Specs & metrics.** Every `specs/*.md` front-matter `status` is a valid stage — one of
|
|
105
|
-
`draft · frozen · in-progress · in-review · shipped · blocked` (SCHEMA.md §Spec status
|
|
106
|
-
are written by the `/cohorte-loop` driver, so flagging them would report the pipeline's own state as a
|
|
107
|
-
defect) — excluding
|
|
131
|
+
`draft · frozen · in-progress · in-review · shipped · blocked` (SCHEMA.md §Spec status) — excluding
|
|
108
132
|
`_`-prefixed files (the spec template and `specs/_decisions.md`, the decision journal) and
|
|
109
133
|
`specs/refactor-backlog.md`, which `/cohorte-audit` writes as a backlog, not a
|
|
110
|
-
spec, and which has no front-matter to check. A spec left `in-progress
|
|
111
|
-
|
|
112
|
-
|
|
134
|
+
spec, and which has no front-matter to check. A spec left `in-progress` or `blocked` is a round
|
|
135
|
+
that never finished ⇒ say so and route it: open `## Remediation` items ⇒ `/cohorte-fix`, none ⇒
|
|
136
|
+
`/cohorte-build`. `shipped` specs
|
|
137
|
+
with a live worktree flagged (see 6). `<state>/pipeline-metrics.jsonl` and `specs/reports/` (the
|
|
113
138
|
`/cohorte-review` report buffer that lets a `/cohorte-fix` survive a `/clear`) are gitignored. Metrics
|
|
114
139
|
belong to the **main checkout** — a `pipeline-metrics.jsonl` inside a live feature worktree is a
|
|
115
140
|
stale-core sign (its lines die at teardown) ⇒ suggest appending its lines to the main checkout's
|
|
@@ -12,8 +12,7 @@ that change the *contract*; `/cohorte-fix` is for everything else.
|
|
|
12
12
|
> _Skip the re-read if it's already in your context this session and unmodified since._
|
|
13
13
|
>
|
|
14
14
|
> **Kanban** (SCHEMA.md §Kanban): on ingest, run
|
|
15
|
-
> `<core>/pipeline/scripts/kanban-move.sh auto $ARGUMENTS fix
|
|
16
|
-
> `~/.claude` global — probe with `test -x`); the card returns to **Review** when `/cohorte-review`
|
|
15
|
+
> `<core>/pipeline/scripts/kanban-move.sh auto $ARGUMENTS fix`; the card returns to **Review** when `/cohorte-review`
|
|
17
16
|
> re-runs. `auto` resolves the board from the config itself and exits 0 with a `kanban: <reason>`
|
|
18
17
|
> line when there is none — so **never decide "no board is configured" without running it**.
|
|
19
18
|
|
|
@@ -71,10 +70,9 @@ When the agents return:
|
|
|
71
70
|
needs those checkboxes).
|
|
72
71
|
- Print one status line per surface (`<key> · items fixed <n>/<m> · tests pass/fail`) — do not restate
|
|
73
72
|
handoff content — and append ONE metrics line for the batch to the **main checkout's**
|
|
74
|
-
`$(dirname "$(git rev-parse --git-common-dir)")
|
|
73
|
+
`$(dirname "$(git rev-parse --git-common-dir)")/<state>/pipeline-metrics.jsonl` (never a bare
|
|
75
74
|
relative path: from a feature worktree that writes a stray sink whose lines die at teardown)
|
|
76
|
-
(rules in `/cohorte-build` §4, `phase: "fix"`)
|
|
77
|
-
(results = items fixed over items found across surfaces, e.g. `"5/6"`).
|
|
75
|
+
(rules in `/cohorte-build` §4, `phase: "fix"`).
|
|
78
76
|
- Tell the human: re-test by hand if the failures were runtime ones, and `/cohorte-review $ARGUMENTS` for the
|
|
79
77
|
re-verdict — the re-review is what *verifies* the ticked items actually hold (a regression simply
|
|
80
78
|
reappears as a new finding in the next round). **Recommend a `/clear`** — all state (spec,
|
|
@@ -9,13 +9,12 @@ agents. Interactive — confirm inferences with the human.
|
|
|
9
9
|
|
|
10
10
|
> **Bootstrap (applies to every step):**
|
|
11
11
|
>
|
|
12
|
-
> **Where the core lives (bundled vs global).**
|
|
13
|
-
>
|
|
14
|
-
> (
|
|
15
|
-
>
|
|
16
|
-
>
|
|
17
|
-
>
|
|
18
|
-
> root, agents/config under this repo's `.claude/`), never into `~/.claude/`.
|
|
12
|
+
> **Where the core lives (bundled vs global).** `<core>` above already names it — the adapter
|
|
13
|
+
> resolved the scope at install time, so nothing here probes. Read it once to learn WHICH mode you
|
|
14
|
+
> are in (`<core>` inside this repo ⇒ `bundled`; `<core>` under your home ⇒ `global`) and remember
|
|
15
|
+
> it — Phase 4 branches on it. **Everything you GENERATE is always written into THIS repo**
|
|
16
|
+
> (`PIPELINE.md` at the root, agents under `<agents>/`, config under `<state>/`), never into the
|
|
17
|
+
> global core.
|
|
19
18
|
>
|
|
20
19
|
> Work in phases. Do not write any file until Phase 4.
|
|
21
20
|
|
|
@@ -29,4 +28,4 @@ agents. Interactive — confirm inferences with the human.
|
|
|
29
28
|
| 04 | `04-write-render` | Write files & render surface agents | after go-ahead |
|
|
30
29
|
| 05 | `05-report` | Print install mode, files, mapping | always |
|
|
31
30
|
|
|
32
|
-
**Before running a step, read its file** in
|
|
31
|
+
**Before running a step, read its file** in `<core>/templates/steps/init-pipeline/`. This table is a map, not the instructions.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Triage a bug and freeze a minimal patch spec — the cheap entry into the pipeline for a fix, no brainstorm, no contract.
|
|
3
|
+
argument-hint: [bug description / stack trace / issue text — or empty to pick from the kanban]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You run the **patch triage** in the main thread — interactive, with the human. This is the bug-fix
|
|
7
|
+
entry point: it produces `specs/patch-<slug>.md` and stops. Everything after it is the normal
|
|
8
|
+
pipeline (`/cohorte-build` → `/cohorte-review` → `/cohorte-fix`* → `/cohorte-ship`), unchanged — the
|
|
9
|
+
patch spec is a spec, so those commands consume it as-is. Splitting it this way is the point: each
|
|
10
|
+
phase is a fresh session with the artifact on disk, instead of one long thread paying for the whole
|
|
11
|
+
cycle at input price on every turn.
|
|
12
|
+
|
|
13
|
+
Bug (may be empty): **$ARGUMENTS**
|
|
14
|
+
|
|
15
|
+
> Read `PIPELINE.md` §`pipeline-profile` first: `surfaces` (paths — this is what you map the bug onto)
|
|
16
|
+
> and `vcs`. _Skip the re-read if it's already in your context this session and unmodified since._
|
|
17
|
+
> Do NOT read `specs/_decisions.md`: a bug fix decides nothing transverse, and the journal is for
|
|
18
|
+
> decisions that outlive a feature.
|
|
19
|
+
>
|
|
20
|
+
> **Kanban** (SCHEMA.md §Kanban): two moves, and their **order is load-bearing** — §1 settles the
|
|
21
|
+
> slug and moves the card to `spec`, §4 moves it to `ready` at freeze. Both are one call to
|
|
22
|
+
> `<core>/pipeline/scripts/kanban-move.sh auto patch-<slug> <stage> [--title "[patch] <human title>"]`.
|
|
23
|
+
> The slug is settled first precisely because the move needs it: a card cannot be joined on an id
|
|
24
|
+
> that doesn't exist yet. `auto` resolves the board from the config itself and exits 0
|
|
25
|
+
> with a `kanban: <reason>` line when there is none — so **never decide "no board is configured"
|
|
26
|
+
> without running it**. Reading the Ideas column at §1 still needs the board path: get it from a
|
|
27
|
+
> `kanban-move.sh` run, or grep the config for `boards[<PIPELINE name>]`.
|
|
28
|
+
|
|
29
|
+
## 1. Get the bug
|
|
30
|
+
|
|
31
|
+
If `$ARGUMENTS` is non-empty, restate it in one line and confirm you've got it.
|
|
32
|
+
|
|
33
|
+
If it is empty: when a board is configured and its **Ideas** column has cards, list them (with any
|
|
34
|
+
sub-bullet notes as context) — **cards titled `[patch]` first**, since those are the ones a human
|
|
35
|
+
filed as bugs — and let the human pick one. Otherwise ask **"What's broken?"**. Either way, wait.
|
|
36
|
+
|
|
37
|
+
Then **settle the id, before anything moves.** Derive `<slug>` (kebab-case, from the symptom —
|
|
38
|
+
`500-on-empty-cart`, not `bug-42`) and confirm it. The `feature_id` is **`patch-<slug>`**, prefix
|
|
39
|
+
included: it is the join key for the kanban card, the spec filename, the branch and every later
|
|
40
|
+
command, so the prefix is part of the id itself, not decoration on the card.
|
|
41
|
+
|
|
42
|
+
**Kanban, in this order:**
|
|
43
|
+
|
|
44
|
+
1. **If the human picked an Ideas card, tag it FIRST.** Ideas cards are free text with no
|
|
45
|
+
`#<feature_id>`, and the move script joins on that tag: move before tagging and it finds nothing,
|
|
46
|
+
creates a second card, and strands the untagged original in Ideas forever. One targeted Edit
|
|
47
|
+
appending ` #patch-<slug>` to that line, located by `grep -n` — never a full board read.
|
|
48
|
+
2. `<core>/pipeline/scripts/kanban-move.sh auto patch-<slug> spec --title "[patch] <human title>"` —
|
|
49
|
+
which moves the (now tagged) card, or creates one under `--title` if the human typed a fresh bug.
|
|
50
|
+
Report what it printed — `moved #…` or `kanban: <reason>` — never a guess about which happened.
|
|
51
|
+
|
|
52
|
+
## 2. Triage — three questions, not an interview
|
|
53
|
+
|
|
54
|
+
`/cohorte-spec` walks a template section by section because a feature has to be *designed*. A bug is
|
|
55
|
+
already specified by reality; your job is to pin it down, not to explore it. Ask only what you
|
|
56
|
+
genuinely cannot infer from the input, batched into ONE message:
|
|
57
|
+
|
|
58
|
+
1. **Repro** — the shortest deterministic path to the symptom. No repro ⇒ ask whether they want you
|
|
59
|
+
to go find one first (a diagnosis session, no spec) or to freeze it as a hypothesis and let the
|
|
60
|
+
implementer confirm. Never invent a repro to fill the section.
|
|
61
|
+
2. **Expected behaviour** — often the whole spec. "It should 404, not 500" is a complete contract.
|
|
62
|
+
3. **Blast radius** — what must NOT change. This becomes §7 Out of scope, and it is what stops a fix
|
|
63
|
+
from becoming a refactor.
|
|
64
|
+
|
|
65
|
+
Then locate it yourself — do not make the human do it. Use the retrieval provider if one is wired,
|
|
66
|
+
else grep for the symptom's strings/identifiers. Read only the files the trail actually names.
|
|
67
|
+
Report the suspected `file:line` in one line and let them confirm or correct it.
|
|
68
|
+
|
|
69
|
+
## 3. Map it onto surfaces — as many as it takes
|
|
70
|
+
|
|
71
|
+
Match the suspected cause and the fix's blast radius against `surfaces[].path`. **A patch is not
|
|
72
|
+
capped at one surface**: a bug that spans an API validator and the form feeding it is one bug with
|
|
73
|
+
one repro, and splitting it into two specs would give each half a contract it doesn't have. List the
|
|
74
|
+
surfaces you're claiming, one line each, with why.
|
|
75
|
+
|
|
76
|
+
**The one escalation that is not a judgment call:** if the fix needs **new** contract surface area —
|
|
77
|
+
a new endpoint, a new shared type, a new field crossing surfaces — stop. That is a feature wearing a
|
|
78
|
+
bug's clothes, and §5 is the only channel that keeps two surfaces in agreement about a shape that
|
|
79
|
+
doesn't exist yet. Say so plainly and send the human to `/cohorte-spec`. Changing an **existing**
|
|
80
|
+
contract entry is fine: describe the delta in §5 and continue.
|
|
81
|
+
|
|
82
|
+
## 4. Freeze the patch spec
|
|
83
|
+
|
|
84
|
+
Write `specs/patch-<slug>.md` from `<core>/templates/patch.template.md` with `status: frozen`, filled
|
|
85
|
+
from §§1–3. **Create the file — do not ask the human to.** Budget: **~60 lines**. A patch spec that
|
|
86
|
+
wants 200 is a feature or a refactor — say which and route it (`/cohorte-spec`, or an item on
|
|
87
|
+
`specs/refactor-backlog.md`).
|
|
88
|
+
|
|
89
|
+
Two sections carry the weight, and both are cheap to get wrong:
|
|
90
|
+
|
|
91
|
+
- **§4 Regression test** — name the test file and what it asserts. It replaces §5 as the thing the
|
|
92
|
+
reviewer checks the diff against, so "add a test" is not enough: say what fails today and why. A
|
|
93
|
+
patch whose test can only be written after the cause is found says exactly that.
|
|
94
|
+
- **§5/§9 keep the feature spec's numbers** (contract delta, acceptance). `review.md` and
|
|
95
|
+
`implementer.template.md` name "contract §5, acceptance §9" verbatim — renumbering them here would
|
|
96
|
+
silently point both agents at the wrong section. The template already does this; don't "fix" it.
|
|
97
|
+
|
|
98
|
+
**Postcondition:** `grep -q '^status: frozen' specs/patch-<slug>.md` — if it fails the freeze didn't
|
|
99
|
+
land; fix it before pointing the human at `/cohorte-build`. Chain the second kanban move onto that
|
|
100
|
+
same Bash call — `kanban-move.sh auto patch-<slug> ready` (the card is already tagged and on the
|
|
101
|
+
board from §1, so this one needs no `--title`) — and report what it printed: `moved #…` or
|
|
102
|
+
`kanban: <reason>`, never a guess.
|
|
103
|
+
|
|
104
|
+
## 5. Hand off
|
|
105
|
+
|
|
106
|
+
Print the spec path, the surfaces, and the branch to cut: `<prefix>patch-<slug>`, where `<prefix>` is
|
|
107
|
+
`vcs.patch_branch_prefix` — falling back to `fix/` on a profile that predates the key. If `isolation.enabled`
|
|
108
|
+
and the fix is big enough to want its own worktree, mention `scripts/new-feature.sh patch-<slug>`;
|
|
109
|
+
most patches don't need it.
|
|
110
|
+
|
|
111
|
+
Then: `/cohorte-build patch-<slug>` — and **recommend a `/clear` first**. The spec is on disk; the
|
|
112
|
+
lead's triage history is re-sent at input price on every turn it survives, and `/cohorte-build`
|
|
113
|
+
re-reads everything it needs.
|
|
@@ -8,10 +8,12 @@ You are the **lead**. Refactor domain **$ARGUMENTS** to match `PIPELINE.md`, usi
|
|
|
8
8
|
|
|
9
9
|
> Read `PIPELINE.md` §`surfaces` (map the domain → a surface + its agent + commands) and §`contract`.
|
|
10
10
|
>
|
|
11
|
+
<!-- cohorte:if workflows -->
|
|
11
12
|
> **Workflow variant** (opt-in — SCHEMA.md §Workflows): for BIG domains (many open backlog items
|
|
12
13
|
> across several surfaces), on Claude Code ≥ 2.1.154 with workflows enabled, the human can ask to
|
|
13
14
|
> "run the refactor workflow" (`<core>/workflows/refactor.js`). For a handful of items this
|
|
14
15
|
> conversational path is cheaper — and it stays the default and the fallback.
|
|
16
|
+
<!-- cohorte:endif -->
|
|
15
17
|
|
|
16
18
|
## 1. Gather
|
|
17
19
|
|
|
@@ -22,11 +24,12 @@ You are the **lead**. Refactor domain **$ARGUMENTS** to match `PIPELINE.md`, usi
|
|
|
22
24
|
|
|
23
25
|
## 2. Dispatch the surface's implementer agent — TDD-first, stateless
|
|
24
26
|
|
|
25
|
-
Spawn the matching `<surface.agent>` with the template below
|
|
27
|
+
Spawn the matching `<surface.agent>` with the template below (as `subagent_type: <surface.agent>`).
|
|
28
|
+
Keep it **byte-identical across loop
|
|
26
29
|
rounds** (only the final items slot varies — it sits at the end so repeats hit the prompt cache), and
|
|
27
30
|
never paste a diff — the agent computes its own, scoped to its tree:
|
|
28
31
|
|
|
29
|
-
>
|
|
32
|
+
> "Refactor pass on your surface (no feature spec). Read
|
|
30
33
|
> `PIPELINE.md` first. **Add the missing tests FIRST** (pin current behavior / cover the entry
|
|
31
34
|
> points), watch them pass, **then** refactor to clear each item. Preserve current public behavior
|
|
32
35
|
> unless an item marks it a bug. Migrations stay additive. Need the current state of your tree?
|
|
@@ -10,20 +10,21 @@ You are the **lead**. Dispatch the review for feature **$ARGUMENTS**.
|
|
|
10
10
|
> _Skip the re-read if it's already in your context this session and unmodified since._
|
|
11
11
|
>
|
|
12
12
|
> **Kanban** (SCHEMA.md §Kanban): run
|
|
13
|
-
> `<core>/pipeline/scripts/kanban-move.sh auto $ARGUMENTS review`
|
|
14
|
-
> `~/.claude` global — probe with `test -x`). `auto` resolves the board from the config itself and
|
|
13
|
+
> `<core>/pipeline/scripts/kanban-move.sh auto $ARGUMENTS review`. `auto` resolves the board from the config itself and
|
|
15
14
|
> exits 0 with a `kanban: <reason>` line when there is none — so **never decide "no board is
|
|
16
15
|
> configured" without running it**.
|
|
17
16
|
>
|
|
17
|
+
<!-- cohorte:if workflows -->
|
|
18
18
|
> **Workflow variant** (opt-in — SCHEMA.md §Workflows): on Claude Code ≥ 2.1.154 with workflows
|
|
19
19
|
> enabled, the human can ask to "run the review workflow" (`<core>/workflows/review.js`) instead.
|
|
20
20
|
> This conversational path stays the default and the fallback; `/cohorte-doctor` shows which is available.
|
|
21
|
+
<!-- cohorte:endif -->
|
|
21
22
|
|
|
22
23
|
## 0. Deterministic pre-flight — no agents while red
|
|
23
24
|
|
|
24
25
|
Run the profile's mechanical gates in ONE Bash call via the shipped script
|
|
25
|
-
(`<core>/pipeline/scripts/preflight.sh
|
|
26
|
-
|
|
26
|
+
(`<core>/pipeline/scripts/preflight.sh`); note the epoch (`date +%s`) in the same call — §3's
|
|
27
|
+
metrics line needs it:
|
|
27
28
|
|
|
28
29
|
```
|
|
29
30
|
<core>/pipeline/scripts/preflight.sh specs/reports/$ARGUMENTS.preflight.txt \
|
|
@@ -37,8 +38,14 @@ with `test -x`); note the epoch (`date +%s`) in the same call — §3's metrics
|
|
|
37
38
|
rather than silence:
|
|
38
39
|
`{"id":"$ARGUMENTS","phase":"review","ts":"<ISO>","aborted":"preflight","verdict":"BLOCK","blocking":null}`
|
|
39
40
|
→ `specs/reports/$ARGUMENTS.verdict.json`. One `printf`, in the same Bash call.
|
|
40
|
-
|
|
41
|
+
<!-- cohorte:if hooks -->
|
|
42
|
+
- **Zero exit** ⇒ it stamped `<state>/preflight.ok`, which the gate hook checks before letting
|
|
41
43
|
`review` dispatches through (SCHEMA.md §Preflight). Continue.
|
|
44
|
+
<!-- cohorte:else -->
|
|
45
|
+
- **Zero exit** ⇒ it stamped `<state>/preflight.ok`. Nothing enforces that stamp on this runtime, so
|
|
46
|
+
§2 does not start until you have seen this line: a review of red code is the one failure mode this
|
|
47
|
+
step exists to prevent, and here only you can prevent it (SCHEMA.md §Preflight). Continue.
|
|
48
|
+
<!-- cohorte:endif -->
|
|
42
49
|
- Script absent (older core) ⇒ run the three commands yourself, each redirected into
|
|
43
50
|
`specs/reports/$ARGUMENTS.preflight.txt`, aborting on the first failure the same way.
|
|
44
51
|
|
|
@@ -61,7 +68,7 @@ with `test -x`); note the epoch (`date +%s`) in the same call — §3's metrics
|
|
|
61
68
|
|
|
62
69
|
## 2. Dispatch review agents — one per touched surface, IN PARALLEL
|
|
63
70
|
|
|
64
|
-
Spawn ONE `review` agent per surface that has changed files, in a **single message** (one
|
|
71
|
+
Spawn ONE `review` agent per surface that has changed files, in a **single message** (one dispatch
|
|
65
72
|
each, like `/cohorte-build`) so they run concurrently — NEVER serially: review wall-clock must be the
|
|
66
73
|
slowest surface, not the sum. A diff touching a single surface ⇒ a single reviewer.
|
|
67
74
|
|
|
@@ -70,12 +77,12 @@ changed lines), touches no contract file, and every open finding it addresses is
|
|
|
70
77
|
LOW/MEDIUM, skip the dispatch: verify the hunks yourself against the open Remediation items (did the
|
|
71
78
|
prescribed fixes land? — NOT a de-novo audit) and write the same REVIEW REPORT into the §3 flow.
|
|
72
79
|
First-round reviews, contract changes, and security findings always get a full reviewer. For each
|
|
73
|
-
|
|
80
|
+
reviewed surface:
|
|
74
81
|
|
|
75
82
|
Keep the dispatch prompt **byte-identical across features and rounds** except the variable block,
|
|
76
83
|
which sits at the END so every repeat hits the prompt-cache prefix:
|
|
77
84
|
|
|
78
|
-
> `subagent_type: review` — "Review one feature surface against its frozen spec. Read `PIPELINE.md`
|
|
85
|
+
> `subagent_type: review` (or this runtime's equivalent) — "Review one feature surface against its frozen spec. Read `PIPELINE.md`
|
|
79
86
|
> first (flags + the §Conventions/§Testing slice for your scope). Check spec conformance first, then
|
|
80
87
|
> correctness, security, conventions, RBAC/mobile-first _if the profile enables them_, and TDD
|
|
81
88
|
> coverage. Your dispatch names a staged diff file — read it FIRST; open a full source file only when
|
|
@@ -109,16 +116,14 @@ re-ordered by severity, counts summed, duplicates collapsed, verdict = the worst
|
|
|
109
116
|
(`BLOCK` > `REVISE` > `SHIP`). The `## Deferred` sections merge the same way (dedupe by
|
|
110
117
|
`file` + problem) and stay **out of the severity table and out of the verdict** — see §3.5, which
|
|
111
118
|
routes them. Append ONE metrics line for the batch to the **main checkout's**
|
|
112
|
-
`$(dirname "$(git rev-parse --git-common-dir)")
|
|
119
|
+
`$(dirname "$(git rev-parse --git-common-dir)")/<state>/pipeline-metrics.jsonl` (rules in
|
|
113
120
|
`/cohorte-build` §4; never a bare relative path — from a worktree that strands the lines): `{"ts":"<ISO>","feature":"$ARGUMENTS","phase":"review","seconds":<wall-clock>,"surfaces":{"<key>":"<verdict>:<finding count>",…}}`.
|
|
114
|
-
In the same Bash call, chain the opt-in usage ping (`/cohorte-build` §4, `phase: "review"`, results = the
|
|
115
|
-
merged verdict + total finding count, e.g. `"REVISE:3"`).
|
|
116
121
|
**Stage the full report to `specs/reports/$ARGUMENTS.md`** (overwrite) — a gitignored buffer so a
|
|
117
122
|
`/cohorte-fix` after a `/clear` can still read the findings; the `specs/reports/` subfolder is skipped by the
|
|
118
123
|
non-recursive `specs/*.md` glob, so it's never mistaken for a spec (no phantom card, no bogus stage).
|
|
119
124
|
**Write the machine-readable verdict** to `specs/reports/$ARGUMENTS.verdict.json` (overwrite) — on
|
|
120
125
|
**every** run, including the small-diff fast path of §2 and a `SHIP`. This file is the ONLY contract
|
|
121
|
-
between the pipeline and
|
|
126
|
+
between the pipeline and any automated driver, which parses no prose:
|
|
122
127
|
|
|
123
128
|
```json
|
|
124
129
|
{ "id": "$ARGUMENTS", "phase": "review", "ts": "<ISO>", "verdict": "REVISE",
|
|
@@ -163,8 +168,8 @@ exactly the leak this step closes. Append each merged `## Deferred` item to
|
|
|
163
168
|
- [ ] <SEVERITY> · <file:line> · <quality|security|rule> · <concrete fix> · deferred:$ARGUMENTS
|
|
164
169
|
```
|
|
165
170
|
|
|
166
|
-
- **Never into the spec's `## Remediation`** — that list is what `/cohorte-fix` re-dispatches
|
|
167
|
-
|
|
171
|
+
- **Never into the spec's `## Remediation`** — that list is what `/cohorte-fix` re-dispatches, so a
|
|
172
|
+
deferred item there would re-trigger the very fix round it was deferred out of.
|
|
168
173
|
- **Dedupe before appending:** `grep -F` the backlog for the item's `<file>` + the first words of its
|
|
169
174
|
problem; already there (from a prior round or an `/cohorte-audit`) ⇒ skip it, don't stack duplicates round
|
|
170
175
|
after round.
|
|
@@ -197,10 +202,7 @@ would sit in this session's history, re-sent every turn). Then:
|
|
|
197
202
|
re-trigger the fix loop), keep the SHIP verdict and the freshness stamp, and let the human ship.
|
|
198
203
|
- **REVISE / BLOCK**, or any CRITICAL/HIGH/security finding → tell the human to run
|
|
199
204
|
**`/cohorte-fix $ARGUMENTS`** — it appends the report to the spec's `## Remediation` and re-dispatches ONLY
|
|
200
|
-
the surfaces with findings. (
|
|
201
|
-
`disable-model-invocation: true` on purpose: **you cannot start it, they must type it**. Name the
|
|
202
|
-
exact line for them to type rather than attempting it — an attempt that silently fails reads as a
|
|
203
|
-
loop that is running when nothing is.) The full path (`/cohorte-spec` Mode B then `/cohorte-build`) remains for findings that
|
|
205
|
+
the surfaces with findings. The full path (`/cohorte-spec` Mode B then `/cohorte-build`) remains for findings that
|
|
204
206
|
change the contract in ways that ripple into clean surfaces. _The report is staged to
|
|
205
207
|
`specs/reports/$ARGUMENTS.md`, so you can `/clear` before `/cohorte-fix` — it reads the findings back from
|
|
206
208
|
disk._
|