pi-gauntlet 7.19.0 → 7.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v7.20.1 - 2026-10-19
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Require pi-cohort >= 7.4.1 and document its file-only failure pointers instead of the obsolete inline-failure exception; save-error summaries still take the degrade path.
|
|
8
|
+
|
|
9
|
+
## v7.20.0 - 2026-10-19
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **A parallel wave's implementers and first spec reviews are one chain call.** On pi-cohort 7.4.0 or newer, `subagent-driven-development` dispatches each wave as one `chain:` call: implementers fan out with `worktree: true` and stop the chain on `BLOCKED`, `NEEDS_CONTEXT`, or `DONE_WITH_CONCERNS`; spec reviewers then read each implementer's base-plus-patch tree through `{outputs.<as>.treePath}` with no `outputSchema` and acceptance off, their verdict read from the report's `Verdict:` line. A clean wave costs one parent turn fewer. A chain stop, chain error, spec `FAIL`, re-review, and sequential mode keep the parent-built snapshot path; an older pi-cohort is detected by a `pi list` preflight and uses the two fan-outs. Peer floor `pi-cohort >=7.4.0`. (#70)
|
|
14
|
+
|
|
3
15
|
## v7.19.0 - 2026-10-19
|
|
4
16
|
|
|
5
17
|
### Changed
|
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ Run by a human against pi-cohort >= 7.1.0, before a pi-gauntlet release claims t
|
|
|
122
122
|
## Requirements
|
|
123
123
|
|
|
124
124
|
- [pi-coding-agent](https://github.com/earendil-works/pi) ≥ 0.85.1 - tested minimum for sequential `phase_tracker` tool execution, which persists a tracker update before a later tool call in the same model message.
|
|
125
|
-
- [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.
|
|
125
|
+
- [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.4.1 - required peer package, including binary-safe worktree patches. Skills that dispatch agents (`requesting-code-review`, `subagent-driven-development`, `dispatching-parallel-agents`, `writing-plans`, `forge-skill`, `shape-ticket`, `roasting-the-spec`) call `subagent({})`, which pi-cohort provides. pi-gauntlet does not vendor the dispatch tool; without pi-cohort those skills have nothing to call. Gauntlet execution dispatches explicitly use `async: false`; do not enable pi-cohort's incompatible `forceTopLevelAsync` setting. See pi-cohort's [dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md) for that setting's owner and semantics. In Parallel-Wave Mode a wave's implementers and first spec reviews are one chain call.
|
|
126
126
|
|
|
127
127
|
Both packages must be listed in your `.pi/settings.json#packages` array (pi adds them automatically when you `pi install`). pi-gauntlet and pi-cohort are versioned independently but release together whenever dispatch semantics change - pin compatible versions of both.
|
|
128
128
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-gauntlet",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.20.1",
|
|
4
4
|
"description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
|
|
5
5
|
"author": "Jacek Juraszek",
|
|
6
6
|
"type": "module",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"test": "node scripts/ci.mjs"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"pi-cohort": ">=7.
|
|
65
|
+
"pi-cohort": ">=7.4.1"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"yaml": "^2.9.0"
|
|
@@ -102,7 +102,7 @@ If the council path ran, the body is its audit (`Coverage:` when present, then `
|
|
|
102
102
|
|
|
103
103
|
Evaluate the summary in two stages (the **Degrade path** referenced in each is defined just below):
|
|
104
104
|
|
|
105
|
-
1. **From the dispatch tool result, before the `Read`.** If the result is **not** an `"Output saved to: <path> (<N> KB, <M> lines)"` reference (
|
|
105
|
+
1. **From the dispatch tool result, before the `Read`.** If the result is **not** an `"Output saved to: <path> (<N> KB, <M> lines)"` reference (an exit-0 save error returns the save error plus a `Full reply preserved at` / `not preserved` pointer, no inline output), or the reference reports under ~500 bytes, or over ~45 KB (the `Read` truncates at 50KB / 2000 lines, so a larger file cannot render whole) - skip the `Read` and take the degrade path. Use the reference's reported figures; do not re-derive them.
|
|
106
106
|
2. **The `Read` itself, as the last content-producing tool call before composing the gate.** `Read` `$SUMMARY_PATH` and paste its contents verbatim at the top of the gate. If the `Read` fails, returns 0 bytes, or reports truncation - take the degrade path. The `Read` must be last: pi-condense does not protect a `/tmp` read, so any turn boundary between the `Read` and the render lets the read result be pruned, reproducing the bug.
|
|
107
107
|
|
|
108
108
|
**Degrade path** - reach the gate with a one-line "summary generation failed" note; never paraphrase from the file-only reference, never render a stub as the canonical summary.
|
|
@@ -86,7 +86,7 @@ The `Human input (verbatim; off-limits for over-spec)` block is supplied by the
|
|
|
86
86
|
|
|
87
87
|
**Targeted retry.** Members whose file is missing or not usable are re-dispatched **once**, together, in a second foreground parallel call carrying `async: false` and the same `control` block. Reuse the complete initial task verbatim, including per-task `outputMode: "file-only"`. Use fresh output paths that preserve the `member-<i>-<slug>` basename under a `retry/` subdir of the same temp dir (the chair recovers `raised-by` attribution from that filename pattern). Await its terminal result. Members with usable files are never re-run.
|
|
88
88
|
|
|
89
|
-
Override the harness's "Read this file if needed" invitation: run only the structural probe; never ingest member findings or the chair report.
|
|
89
|
+
Override the harness's "Read this file if needed" invitation: run only the structural probe; never ingest member findings or the chair report.
|
|
90
90
|
|
|
91
91
|
**Quorum.** At least one usable file after retry -> dispatch the chair over the usable files only (next section). Zero usable files -> abort the council, say so, and return to the user gate.
|
|
92
92
|
|
|
@@ -166,8 +166,8 @@ Auto-selected at handoff by `writing-plans` (any wave with ≥2 tasks) when the
|
|
|
166
166
|
**Per-wave loop:**
|
|
167
167
|
|
|
168
168
|
1. **Independence check.** Parse the wave's tasks' `Files:` blocks; assert pairwise-disjoint (mechanical, mirroring `wave-file-disjointness`: `Test`/`Test` on one path is not overlap, `Test` vs another task's `Create`/`Modify` is, `Modify`/`Modify` is). Runtime-resource disjointness (DB/schema, port, fixture, external service, shared temp path) is not machine-checkable here — trust the plan's wave grouping, which `writing-plans`' D5 contract guarantees. Either kind of overlap → the wave is mis-grouped; run those tasks as sequential single-task waves and note it.
|
|
169
|
-
2. **Start, then
|
|
170
|
-
3. **
|
|
169
|
+
2. **Start, then dispatch.** Record `WAVE_BASE_SHA` with `git -C <worktree> rev-parse HEAD` before dispatch; keep it fixed through the wave's commit. Mark every wave index `in_progress` in increasing index order. Use the once-per-phase preflight below to choose exactly one initial chain (including one-task waves), or the fallback implementer fan-out.
|
|
170
|
+
3. **Read the result once.** Read statuses, verdicts, patches, and reports as specified below. All implementers `DONE` and all verdicts `COMPLIANT` -> step 4. Any other outcome -> [Chain stopped or failed](#chain-stopped-or-failed). The ticket's `FAIL` means a spec gap (`NEEDS_REWORK`), not a structured verdict or an SR `stopOn` condition.
|
|
171
171
|
4. **Integrate.** Run `git -C <worktree> apply --index <patch-path>` for each accepted task's patch sequentially. This stages additions as well as tracked changes for review. Apply fails = textual conflict → drop that task, finish the rest, re-run the dropped task sequentially on the updated HEAD.
|
|
172
172
|
5. **Test gate.** Run the wave's `SCOPED_TEST_COMMANDS` (union of its tasks' `Tests:` commands) on the integrated tree as `(cd "<worktree>" && <command>)` for each command — the full verification set is the verify phase's job, run once. Failure = semantic conflict or bug → re-run the offending task sequentially, else fix per [When a Subagent Fails](#when-a-subagent-fails).
|
|
173
173
|
6. **Quality review.** CR binds to the wave: exactly one **initial** code-review dispatch per code-touching wave, over the integrated wave diff - never per task within a wave, never batched across waves. Subsequent dispatches within the wave are re-reviews triggered only by findings, per Fix-Loop Rounds. Pass the wave's `SCOPED_TEST_COMMANDS`, `BASE_SHA: <WAVE_BASE_SHA>`, and `HEAD_SHA: WORKTREE` per `code-quality-reviewer-prompt.md`; the review reads the staged and unstaged integrated diff, not a commit range. On findings, fix and re-review per `/skill:requesting-code-review` and [Fix-Loop Rounds](#fix-loop-rounds). For in-place repairs, stage the reviewed deliverables before dispatch and override the implementer commit step: leave the fix uncommitted and unstaged. After it returns, run `git -C <worktree> add -N -- <new-fix-paths>` for new deliverables, capture `git -C <worktree> diff --binary` as `## Fix delta`, then stage the fix's deliverable paths before SR/CR re-review. Preserve `WAVE_BASE_SHA` and `HEAD_SHA: WORKTREE` through every re-review and escalated in-place repair. Skip CR for doc-only waves (SR-only per the commit precondition below).
|
|
@@ -179,12 +179,69 @@ Auto-selected at handoff by `writing-plans` (any wave with ≥2 tasks) when the
|
|
|
179
179
|
|
|
180
180
|
**Caveat:** each task must be independently runnable and verifiable in a fresh worktree — no reliance on uncommitted local state. `pi-cohort` symlinks `node_modules`; repos needing other per-worktree setup must account for it.
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
Requires pi-cohort >= 7.4.0 for `treePath` (`stopOn` is 7.3.0); below it, the preflight turns the chain off and the wave runs as today's two fan-outs.
|
|
183
|
+
|
|
184
|
+
Before the first wave, run this lookup once per implement phase, observing both commands' failures (use shell pipeline failure detection):
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
set -o pipefail
|
|
188
|
+
COHORT_DIR=$(pi list | grep -A1 'pi-cohort$' | tail -1 | tr -d ' ')
|
|
189
|
+
COHORT_VERSION=$(node -p "require('$COHORT_DIR/package.json').version")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Compare the three semver components numerically against 7.4.0, not lexicographically. On a lower or unparseable version, or either command's failure, use the two fan-outs for every wave in this run. Note `pi-cohort <version>: chain disabled` once with the observed version; display `unknown` and the lookup failure when discovery failed. A 7.3.x runtime must never receive the chain: it passes the literal tree reference to SR. The package peer floor is declarative; pi-managed packages do not auto-install peers.
|
|
193
|
+
|
|
194
|
+
Pass the implementation worktree's absolute path as top-level `cwd`. Per-task `cwd` outranks step and run `cwd`; only the SR tasks override it. Rule and rationale for editing dispatches: `dispatching-parallel-agents` "pi-cohort Integration".
|
|
183
195
|
|
|
184
196
|
```bash
|
|
185
197
|
REPORT_DIR=$(mktemp -d)
|
|
186
198
|
```
|
|
187
199
|
|
|
200
|
+
```ts
|
|
201
|
+
IMPLEMENTER_STATUS_SCHEMA = { type: "object", required: ["status"], additionalProperties: true,
|
|
202
|
+
properties: { status: { type: "string", enum: ["DONE", "DONE_WITH_CONCERNS", "NEEDS_CONTEXT", "BLOCKED"] } } }
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
subagent({
|
|
207
|
+
async: false,
|
|
208
|
+
context: "fresh",
|
|
209
|
+
cwd: "<abs worktree path>",
|
|
210
|
+
chain: [
|
|
211
|
+
{
|
|
212
|
+
parallel: [
|
|
213
|
+
{ agent: "implementer", as: "impl_1", outputSchema: IMPLEMENTER_STATUS_SCHEMA,
|
|
214
|
+
output: "<REPORT_DIR>/wave<w>-task1.md",
|
|
215
|
+
task: "<full task text + owned files + SCOPED_TEST_COMMANDS + Tests: block + status protocol> pi-cohort saves your final report to the output path; do not write that file yourself, and it is not a concern about owned files." },
|
|
216
|
+
// one entry per wave task, as: "impl_<n>" in plan index order
|
|
217
|
+
],
|
|
218
|
+
worktree: true,
|
|
219
|
+
concurrency: 4,
|
|
220
|
+
stopOn: { path: "/status", in: ["BLOCKED", "NEEDS_CONTEXT", "DONE_WITH_CONCERNS"] },
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
parallel: [
|
|
224
|
+
{ agent: "spec-reviewer", as: "sr_1",
|
|
225
|
+
cwd: "{outputs.impl_1.treePath}",
|
|
226
|
+
output: "<REPORT_DIR>/wave<w>-sr1.md",
|
|
227
|
+
acceptance: { level: "none", reason: "the parent reads each SR Verdict: line; review trees are staged by design" },
|
|
228
|
+
task: "<full task text + absolute spec path (in the implementation worktree) + Spec: anchors + Tests: block + Test: paths> The patch under review is the file at {outputs.impl_1.patchPath}; the working tree you run in already has it applied. The implementer's report is at <REPORT_DIR>/wave<w>-task1.md; read it for the 'What Implementer Claims They Built' section." },
|
|
229
|
+
// one entry per wave task, paired by index
|
|
230
|
+
],
|
|
231
|
+
concurrency: 4,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Count the clean code-wave path as one chain plus one separate CR `subagent()` call; integration and tests remain parent actions between them. Use positional 1-based `impl_<n>` and `sr_<n>` names; map results to plan indices by wave position. Keep `context`, `async`, and top-level `cwd` invocation-level; `worktree`, `concurrency`, and `stopOn` step-level; `as`, `outputSchema`, `cwd`, `output`, `acceptance`, and `task` per-task. Give the SR step neither `worktree` nor `stopOn`, and its tasks no `outputSchema`.
|
|
238
|
+
|
|
239
|
+
Tell SR to start from diff hunks carrying `file:line`, read every touched file in full from its materialized tree, read deleted files from `WAVE_BASE_SHA`, and never run tests. Pass the authoritative spec's absolute implementation-worktree path; SR reads the anchored ranges itself (never inline excerpts; authority hierarchy in `./spec-reviewer-prompt.md`; anchor-less tasks are task-text-only). Output references resolve only in `task` strings and `cwd` (`treePath` only), never `reads:`; paste no diff into the chain payload. Rely on pi-cohort's `structured_output` injection only for implementers carrying `outputSchema`; 7.4.0 orders an enabled acceptance report before that call. Keep SR schema-free because no `stopOn` reads its verdict. Disable acceptance on each initial chained SR task with `none` and a nonempty reason because the parent reads each `Verdict:` line and review trees are staged by design: risky-word inference precedes read-only inference, non-none explicit levels only raise the inferred level, and `checked` or higher requires no staged files; snapshot-backed spec reviews and code review carry no `acceptance` field. Keep prompts and persona vocabularies unchanged.
|
|
240
|
+
|
|
241
|
+
Read the tool-result text, not `details`: read implementer statuses from fenced JSON in `## Outputs` and the `## Stop` line; read SR verdicts from the `Verdict:` line of each SR `output:` report, one of `COMPLIANT`, `NEEDS_REWORK`, or `OUT_OF_SCOPE_CHANGES`. Read patch locations from `Artifacts:`: `<Artifacts dir>/worktree-diffs/step-0/task-<i>-implementer.patch`, with 0-based wave position `<i>`. Use these artifact patches for integration and later repairs. Exit-0 reports are the known `output:` files. A nonzero task has no `output:` file and no bound output. Recover its prose from its session `subagent-artifacts` output file (`<runId>_implementer_<index>_output.md`, defined by pi-cohort `src/shared/artifacts.ts`), matching the run/task identity in the result or session transcript. Use the same source-defined per-agent naming for a failed reviewer. Do not use the chain's empty `parallel-0/` directories for failed prose. If artifacts are disabled, missing, or cannot be unambiguously matched, enter [When a Subagent Fails](#when-a-subagent-fails) with the visible diagnostic; never invent a status. Keep SR's large-wave `outputMode: "file-only"` hint; read the report itself, not its `Output saved to:` pointer. Carry its full contents verbatim under `## Previous review report (re-review trigger)` on re-review.
|
|
242
|
+
|
|
243
|
+
**Older-runtime fallback only:** use this plain implementer fan-out, then the snapshot-backed SR fan-out below. Keep the same report-path wave/task mapping.
|
|
244
|
+
|
|
188
245
|
```ts
|
|
189
246
|
subagent({
|
|
190
247
|
context: "fresh",
|
|
@@ -202,9 +259,24 @@ subagent({
|
|
|
202
259
|
|
|
203
260
|
For the fan-out + worktree + patch-integration + conflict mechanics, see `dispatching-parallel-agents`.
|
|
204
261
|
|
|
262
|
+
### Chain stopped or failed
|
|
263
|
+
|
|
264
|
+
Route the result already read in step 3; retain all successful sibling patches and verdicts. Inspect failed tasks regardless of whether `## Stop` is also present: pi-cohort evaluates the stop condition before checking sibling failures, so both can coexist. Read exit-0 statuses from `## Outputs` when present or their `output:` reports; recover failed-task prose using the session-artifact rule above, including its unavailable-artifact fallback. Treat `## Stop` as a matched exit-0 status, not proof that every sibling succeeded. For `DONE_WITH_CONCERNS` alongside a nonzero `BLOCKED`, judge the concerns, diagnose the failed task, and retain accepted siblings:
|
|
265
|
+
|
|
266
|
+
| Outcome | Recovery |
|
|
267
|
+
|---|---|
|
|
268
|
+
| Exit-0 stop (`## Stop`) with no failed siblings | Siblings finished, statuses remain in `## Outputs`, and no SR step ran. Judge `DONE_WITH_CONCERNS`, answer `NEEDS_CONTEXT`, diagnose `BLOCKED`, then snapshot accepted patches and use the ordinary SR fan-out below. |
|
|
269
|
+
| Chain error, with or without `## Stop` | Identify and diagnose every failed task from the result, including prose `**Status:**` / `Verdict:` recovered through the session-artifact rule above. Completion-guard failure with no edits, rejected/missing `structured_output`, failed `treePath`, and sibling process failure all take this route. Handle a recoverable `BLOCKED` or `NEEDS_CONTEXT` through its status matrix even when that unaccepted task has no patch. Route a task with no recoverable status, or an accepted task with a missing/empty patch, to [When a Subagent Fails](#when-a-subagent-fails) with the visible diagnostic; never invent a status or review an unchanged tree. Retain exit-0 SR verdicts obtained in a materialized tree; dispatch only accepted patches without a verdict. Successful siblings are never re-run. |
|
|
270
|
+
| Completed chain with `NEEDS_REWORK` or `OUT_OF_SCOPE_CHANGES` | Repair only those tasks using the spec-gap loop below. Preserve passing sibling patches/verdicts. |
|
|
271
|
+
| Older-runtime fallback | Parse the plain fan-out statuses, then use the same snapshot-backed SR and fix loop below. |
|
|
272
|
+
|
|
273
|
+
Parse each `DONE`/`BLOCKED`/etc. (see [Implementer Status](#implementer-status)) **first**. Then **dispatch a `spec-reviewer` per accepted patch** (`DONE`, or a `DONE_WITH_CONCERNS` you proceeded with) still missing a verdict in one parallel fan-out - `context: "fresh"`, each task's `cwd` = its [Spec-review snapshot](#spec-review-snapshots), **no `worktree` flag** (read-only) - each passed its full task text, the returned **patch diff**, the absolute spec path, and the task's `**Spec:**` anchors, plus its `**Tests:**` block and `- Test:` paths as contract. SR reads the anchored ranges itself (never inline excerpts; authority hierarchy in `./spec-reviewer-prompt.md`; anchor-less tasks are task-text-only). Review starts from the diff (its hunks carry `file:line`) and reads each touched file in full; test execution is never the reviewer's job (step 5 runs the wave's `SCOPED_TEST_COMMANDS`). Inline verdicts are fine at normal wave sizes; large waves use `output:` + `outputMode: "file-only"`; read the full report file itself.
|
|
274
|
+
|
|
275
|
+
**Re-dispatch by cause:** `BLOCKED`/`NEEDS_CONTEXT` per the [Implementer Status](#implementer-status) matrix; a **spec gap** re-dispatches only that implementer using a one-entry `tasks` array with invocation-level `worktree: true`, `context: "fresh"`, and implementation `cwd`, carrying the artifacts patch + full SR report verbatim. Snapshot the replacement patch with [Spec-review snapshots](#spec-review-snapshots) (a setup failure stops dispatch and keeps the failed snapshot) and dispatch one plain re-review with `## Previous review report (re-review trigger)` and the trajectory block. The new patch supersedes the old at step 4. Loop until accepted + spec compliant, within [Fix-Loop Rounds](#fix-loop-rounds), same as sequential. Never dispatch a second chain in the same wave.
|
|
276
|
+
|
|
205
277
|
## Spec-review snapshots
|
|
206
278
|
|
|
207
|
-
Materialize each accepted patch
|
|
279
|
+
Materialize each accepted patch for every pre-integration review not run by the chain: accepted siblings after errors/stops, replacement patches on re-review, and older-runtime fallback. Keep the implementation worktree unchanged; pi-cohort removes its worker checkouts before returning patches.
|
|
208
280
|
|
|
209
281
|
Substitute shell-quoted literals for the implementation worktree, the recorded `WAVE_BASE_SHA`, and the absolute patch path. Run this block once per patch:
|
|
210
282
|
|
|
@@ -318,6 +390,7 @@ Use the printed snapshot path as that spec-review task's `cwd` and whole-file re
|
|
|
318
390
|
- Making a subagent read the plan, inlining spec excerpts to the spec reviewer, or dispatching with a `SCOPED_TEST_COMMANDS` value missing or not copied from the plan's `Tests:` bullets.
|
|
319
391
|
- Dispatching `code-reviewer` before every in-scope spec-review verdict is ✅, or per task inside a wave.
|
|
320
392
|
- Moving to the next task with either review still showing issues, or skipping the `Implementer Status` parse.
|
|
393
|
+
- Second chain call in the same wave after a stop or a chain error - the retained results are the fan-out result; continue on the snapshot path.
|
|
321
394
|
- Dispatching fix 3 without a reviewer-emitted `CONVERGING` verdict, or continuing past `STAGNANT` instead of escalating.
|
|
322
395
|
- Running the full verification entrypoint, or any test command outside `SCOPED_TEST_COMMANDS`, during the implement phase.
|
|
323
396
|
- Dispatching a repair before reopening the plan-task indices that own its files, whole-diff CR before parent verification passes, or conformance before the CR result is accepted.
|