pi-gauntlet 7.20.1 → 7.22.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 +18 -0
- package/README.md +3 -3
- package/agents/code-reviewer.md +0 -2
- package/agents/plan-writer.md +7 -6
- package/extensions/lib/plan-check.test.ts +114 -18
- package/extensions/lib/plan-check.ts +113 -35
- package/extensions/phase-tracker.test.ts +35 -1
- package/package.json +1 -1
- package/skills/brainstorming/SKILL.md +5 -3
- package/skills/brainstorming/gatherer.md +8 -1
- package/skills/brainstorming/reference/amendment-surface.md +1 -1
- package/skills/dispatching-parallel-agents/SKILL.md +8 -2
- package/skills/gauntlet-resume/reference/brief-contract.md +22 -2
- package/skills/requesting-code-review/SKILL.md +5 -6
- package/skills/subagent-driven-development/SKILL.md +49 -51
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +5 -5
- package/skills/subagent-driven-development/implementer-prompt.md +2 -2
- package/skills/subagent-driven-development/stop-note.md +9 -4
- package/skills/verification-before-completion/reference/conformance-check.md +2 -2
- package/skills/writing-plans/SKILL.md +39 -21
- package/skills/writing-plans/reference/plan-contract.md +11 -5
|
@@ -874,6 +874,7 @@ const FIXTURE_PLAN = `# Fixture Plan
|
|
|
874
874
|
|
|
875
875
|
**Tests:**
|
|
876
876
|
- \`node --test lib/task1.test.ts\`
|
|
877
|
+
- baseline: abc1234 skipped - lib/task1.test.ts created by this task
|
|
877
878
|
|
|
878
879
|
This task implements helperFn() for parsing.
|
|
879
880
|
|
|
@@ -889,6 +890,7 @@ This task implements helperFn() for parsing.
|
|
|
889
890
|
|
|
890
891
|
**Tests:**
|
|
891
892
|
- \`node --test lib/task2.test.ts\`
|
|
893
|
+
- baseline: abc1234 skipped - lib/task2.test.ts created by this task
|
|
892
894
|
|
|
893
895
|
This task handles naming details.
|
|
894
896
|
|
|
@@ -968,7 +970,13 @@ test("Guard 2 evaluates the command's target checkout (AC 3)", async () => {
|
|
|
968
970
|
|
|
969
971
|
test("plan_check pass: text, details, and stamp arming when a flow is entered", async () => {
|
|
970
972
|
const dir = gitPrimary().primary;
|
|
971
|
-
const { planPath, specPath, planText, specText } = writePlanFixture(dir
|
|
973
|
+
const { planPath, specPath, planText, specText } = writePlanFixture(dir, {
|
|
974
|
+
mutatePlan: t => t.replace(/- Create: lib\/task[12]\.test\.ts\n/g, "")
|
|
975
|
+
.replace(/skipped - lib\/task[12]\.test\.ts created by this task/g, "pass"),
|
|
976
|
+
});
|
|
977
|
+
mkdirSync(join(dir, "lib"), { recursive: true });
|
|
978
|
+
writeFileSync(join(dir, "lib/task1.test.ts"), "");
|
|
979
|
+
writeFileSync(join(dir, "lib/task2.test.ts"), "");
|
|
972
980
|
const h = harness({ cwd: dir, branch: readyForImplementBranch });
|
|
973
981
|
await h.emit("session_start");
|
|
974
982
|
const tool = h.tools.find((t) => t.name === "plan_check")!;
|
|
@@ -996,6 +1004,32 @@ test("plan_check pass: text, details, and stamp arming when a flow is entered",
|
|
|
996
1004
|
void specText;
|
|
997
1005
|
});
|
|
998
1006
|
|
|
1007
|
+
for (const failure of [false, true]) {
|
|
1008
|
+
test(`plan_check missing baseline${failure ? " with base failure" : ""} prevents implement stamp`, async () => {
|
|
1009
|
+
const dir = gitPrimary().primary;
|
|
1010
|
+
const command = "node --test lib/task1.test.ts";
|
|
1011
|
+
const row = `- Task 1: \`${command}\` fails on abc1234 (exit 2): assertion failed`;
|
|
1012
|
+
const { planPath } = writePlanFixture(dir, {
|
|
1013
|
+
mutatePlan: t => t.replace("- baseline: abc1234 skipped - lib/task1.test.ts created by this task\n", "") + (failure ? "\n## Open Questions\n" + row + "\n" : ""),
|
|
1014
|
+
});
|
|
1015
|
+
const h = harness({ cwd: dir, branch: readyForImplementBranch });
|
|
1016
|
+
await h.emit("session_start");
|
|
1017
|
+
const tool = h.tools.find(t => t.name === "plan_check")!;
|
|
1018
|
+
const result = await tool.execute("baseline", { planPath }, undefined, undefined, h.ctx) as {
|
|
1019
|
+
details: { status: string; findings: { check: string; reason: string }[] };
|
|
1020
|
+
};
|
|
1021
|
+
assert.equal(result.details.status, "fail");
|
|
1022
|
+
assert.ok(result.details.findings.some(f => f.check === "baseline-line" && f.reason.includes("Task 1")));
|
|
1023
|
+
if (failure) assert.ok(result.details.findings.some(f => f.reason === "plan has open questions: " + row));
|
|
1024
|
+
const phase = h.tools.find(t => t.name === "phase_tracker")!;
|
|
1025
|
+
const start = await phase.execute("start", { action: "start", phase: "implement" }, undefined, undefined, h.ctx) as {
|
|
1026
|
+
details: { error?: string; phases: { implement: { status: string } } };
|
|
1027
|
+
};
|
|
1028
|
+
assert.match(start.details.error ?? "", /plan_check/);
|
|
1029
|
+
assert.notEqual(start.details.phases.implement.status, "in_progress");
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
|
|
999
1033
|
test("plan_check pass outside a flow: no stamp, plain-linter text", async () => {
|
|
1000
1034
|
const dir = gitPrimary().primary;
|
|
1001
1035
|
const { planPath } = writePlanFixture(dir);
|
package/package.json
CHANGED
|
@@ -105,9 +105,9 @@ Recommendation: A - the extension already holds the poll loop, so no new entrypo
|
|
|
105
105
|
|
|
106
106
|
Append only citable findings - schemas, hard constraints, contradictions, and scope-changing answers - to `## Appended during questionary` using `edit`.
|
|
107
107
|
|
|
108
|
-
Before approaches, state in chat the supported, disproved, corrected, and unverified premises with sources and attempted lookups, in full sentences - no status-keyword lists, no template; if the design depends on no claims, one sentence says so. An unverified claim is not a stop: put it in Open Questions or a stated assumption. If a load-bearing claim is contradicted, the premise note is your next message - even as question one - and states the corrected fact with its source; the design continues on it and the user overrides in reply. Record the corrected fact, and any override, in the draft for `## Problem` or the relevant design decision.
|
|
108
|
+
Before approaches, state in chat the supported, disproved, corrected, and unverified premises with sources and attempted lookups, in full sentences - no status-keyword lists, no template; if the design depends on no claims, one sentence says so. Treat an implicit dependency found missing as a corrected premise and one not checkable as unverified; state each in the premise note with the lookup the repo or spec names and its result, and carry it into `## Problem`. An unverified claim is not a stop: put it in Open Questions or a stated assumption. If a load-bearing claim is contradicted, the premise note is your next message - even as question one - and states the corrected fact with its source; the design continues on it and the user overrides in reply. Record the corrected fact, and any override, in the draft for `## Problem` or the relevant design decision.
|
|
109
109
|
|
|
110
|
-
Before question one, verify the draft's `Framing:` line against primary code and add your own recon. This check adds to the premise verification above and never replaces it: trace every consumer, caller, and data path the ask's constraints name before writing the holds-statement or the question, and name
|
|
110
|
+
Before question one, verify the draft's `Framing:` line against primary code and add your own recon. This check adds to the premise verification above and never replaces it: trace every consumer, caller, and data path the ask's constraints name, including retained loaders and every repro and verification step's implicit dependencies, before writing the holds-statement or the question; check those dependencies with the lookup the repo or spec names, and name the traces and dependencies in the holds-statement, not only the files read. A framing concern exists when you can state a cited case that the ask is misdiagnosed, wrong-sized, already solved, a band-aid where the root cause is reachable, or cuts across a sound pattern - including a repo convention that is itself the debt - and can name the alternative it implies; an objection without an alternative is a lead to investigate, not a concern. With a concern, question one is the framing question in the questionary format:
|
|
111
111
|
|
|
112
112
|
```text
|
|
113
113
|
A) as framed
|
|
@@ -120,7 +120,7 @@ For a band-aid concern, put the root-cause alternative in B. Without a concern,
|
|
|
120
120
|
|
|
121
121
|
After any premise correction in the same message, ask the framing question or give the holds-statement. Ask the framing question at most once per brainstorm, including after pushback; the user's reply is final, and later doubts on the same point go to Open Questions or a `Pattern:` line. Recommend; never pivot without the reply. A ticket-recorded decision on the exact point follows the ticket rule above; an adopted decision records `Framing: kept (ticket <id>)`. A pivot never rewrites AC rows: rows it no longer satisfies take `deviates:` dispositions, and a pivot that changes the topic re-mints the slug.
|
|
122
122
|
|
|
123
|
-
Record the outcome in the draft under `## Appended during questionary` as `Framing: kept` or `Framing: pivoted to <x> - <why>`; spec-writing carries that line into `## Problem`. On redraw entry (checklist step 4) the count restarts: run this evaluation once against the new draft. On redraw the draft is the approved spec: its `## Problem` `Framing:` line is context, not scout evidence, and the new outcome is recorded directly in `## Problem`. When the scout failed there is no `Framing:` line; the holds-statement or
|
|
123
|
+
Record the outcome in the draft under `## Appended during questionary` as `Framing: kept` or `Framing: pivoted to <x> - <why>`; spec-writing carries that line into `## Problem`. On redraw entry (checklist step 4) the count restarts: run this evaluation once against the new draft. On redraw the draft is the approved spec: its `## Problem` `Framing:` line is context, not scout evidence, and the new outcome is recorded directly in `## Problem`. When the scout failed there is no `Framing:` line; supply the implicit-dependency check and the holds-statement or question from your own recon.
|
|
124
124
|
|
|
125
125
|
Bad: `The ask adds another settings path - should we? Recommendation: no`
|
|
126
126
|
Good:
|
|
@@ -134,6 +134,8 @@ Recommendation: B - the owning schema already exists.
|
|
|
134
134
|
|
|
135
135
|
### 4. Explore approaches
|
|
136
136
|
|
|
137
|
+
In a separate message after the premise note, restate each implicit dependency recorded as missing or not checkable, with its lookup and result, before presenting any approaches.
|
|
138
|
+
|
|
137
139
|
Propose 2-3 genuinely distinct approaches and name what separates them (the axis), comparing them on explicit trade-offs. Consider two candidates in every set: the minimal reuse-only option (no new construct) and an option that drops an assumption the ask makes which the framing reply, if any, did not settle; list each when viable, otherwise state in one sentence with evidence why not (`reuse-only: not viable - the only existing path is the one identified as debt`); a non-viable candidate is not an approach and does not count toward the 2-3. End each approach with `Pattern: <what it follows or cuts across, cited to a repo location>` - judge against sound engineering practice first, then repo rules; when the repo's own convention is the debt, say so, and never recommend an approach that extends it - unless the framing reply or an adopted ticket decision kept the ask as framed: then recommend the best as-framed approach and name the debt in its `Pattern:` line. A `Pattern:` line names things like a band-aid over a shared contract, a second settings path beside the owning one, or a layer bypassed for one caller - the judgment comes from the repo and your own engineering knowledge, not a list. Lead with the recommendation and end with the condition that would flip it. Use conversational prose unless the user asks for a table.
|
|
138
140
|
|
|
139
141
|
### 5. Design for clarity and isolation
|
|
@@ -47,7 +47,14 @@ Scout (always dispatched):
|
|
|
47
47
|
> Recon for an upcoming design discussion. The request: `<initial prompt verbatim>`.
|
|
48
48
|
> Map the territory this change touches: relevant files with line ranges, existing
|
|
49
49
|
> patterns and conventions the change must match, test conventions, integration
|
|
50
|
-
> points, and whether the codebase or ecosystem already solves any of this.
|
|
50
|
+
> points, and whether the codebase or ecosystem already solves any of this. Trace retained
|
|
51
|
+
> loaders and call paths, and every repro and verification step, for dependencies the
|
|
52
|
+
> request relies on without naming: files, binaries, extensions, fixtures, and data
|
|
53
|
+
> subsets. Check each with the lookup the repo or spec names; a named path or
|
|
54
|
+
> capability is a claim to check, not proof it exists. Emit one line per item:
|
|
55
|
+
> `Implicit dependencies: <item> - <how checked> - <found | not found | not checkable: <why>>`
|
|
56
|
+
> or `Implicit dependencies: none found - traced <components, steps>`.
|
|
57
|
+
> Then one required line:
|
|
51
58
|
> `Framing: <the strongest cited case that the request as framed is the wrong change - a path that already covers it, a sound convention it cuts across, an existing convention it would extend that is itself the debt, a band-aid where the root cause is reachable, or a smaller change with the same outcome>`
|
|
52
59
|
> or `Framing: no objection - checked <what was read>`; this line is
|
|
53
60
|
> evidence for the design discussion, not a verdict - the main loop decides. Cite
|
|
@@ -140,7 +140,7 @@ Before the aftermath, `read` this section again; never run it from memory.
|
|
|
140
140
|
|
|
141
141
|
Apply accepted items only: reviewer clears, `accept`, `alt-n`, and state-changing `custom`. Print one line per applied item: `amended the spec: <title> - <what>`.
|
|
142
142
|
|
|
143
|
-
Aftermath, once per batch, only when at least one item applied (nothing applied -> skip to the commit below). No plan yet -> commit the spec; continue. Plan exists ->
|
|
143
|
+
Aftermath, once per batch, only when at least one item applied (nothing applied -> skip to the commit below). No plan yet -> commit the spec; continue. Plan exists -> read `git -C "<abs worktree path>" status --porcelain` (plain jj: `jj -R "<abs worktree path>" diff --summary`); collect the parent's in-flight workflow edits as worktree-relative paths, including the amended spec and staged in-place wave-repair deliverables. Dispatch `plan-writer` per `writing-plans` `## Author the plan` step 3 with an `Amend:` block naming the amended spec sections, an `In-flight:` list of those paths (the parent supplies the set; the child never infers it), and the rule "preserve every task title and wave position the amendment does not touch; edit only affected anchors and tasks", then run that section's steps 5-6 (the parent `plan_check` and its branches), then read the amended plan once (step 7's read, without its phase completion or `plan_tracker` init) - the main loop never edits the plan text; then update the tracker: `plan_tracker` `add` for new tasks; anchor-changed completed tasks are reopened as `in_progress` and re-run the task loop (`update` never sets `pending`). A removed task is deleted from the plan; then re-`init` the tracker with `{ name, status }` elements: preserved tasks keep their order and statuses, reopened tasks are `in_progress` in place, every still-`pending` task (including newly added ones, whatever wave label they carry) trails the non-pending ones, removed tasks are the only deletions (the only permitted `init` after handoff; never `clear`). Commit spec + plan together; continue. A task reopened while `verify` or `ship` is in progress stays in that phase - no `phase_tracker` call. Repair it through the current phase's fix loop and `plan_tracker({ action: "update", index: N, status: "complete" })` it once that repair's review or re-audit accepts; open tasks block `complete verify`, and in `ship` nothing checks them, so close them explicitly.
|
|
144
144
|
|
|
145
145
|
One commit per batch:
|
|
146
146
|
|
|
@@ -13,7 +13,7 @@ When you have multiple **independent tasks** — unrelated test failures, or imp
|
|
|
13
13
|
|
|
14
14
|
**Core principle:** Dispatch one agent per independent problem domain (one bug, one subsystem, or one plan task). Let them work concurrently.
|
|
15
15
|
|
|
16
|
-
This skill is the **mechanic home** for parallel fan-out: fresh-context isolation, `worktree: true` filesystem isolation, and serial patch integration. `subagent-driven-development`'s
|
|
16
|
+
This skill is the **mechanic home** for parallel fan-out: fresh-context isolation, `worktree: true` filesystem isolation, and serial patch integration. `subagent-driven-development`'s wave loop builds its per-wave dispatch on this skill - debugging is the worked example below, but the mechanics are identical for implementation tasks.
|
|
17
17
|
|
|
18
18
|
Gauntlet flow callers dispatch foreground: explicitly set top-level `async: false`, including retries and prose-described dispatches. `forceTopLevelAsync` is incompatible; if an async handle is returned anyway, stop and report rather than polling or relaunching. See [pi-cohort dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md).
|
|
19
19
|
|
|
@@ -113,7 +113,13 @@ Fix rounds in review loops reuse the fan-out mechanics above, keyed off the revi
|
|
|
113
113
|
|
|
114
114
|
Reviewers certify fix concurrency with a `Parallel-safe:` line (see the reviewer's report contract). The fan-out trigger is a `disjoint` group naming **≥ 2 actionable finding IDs**: that group IS the parallel wave — dispatch **one `implementer` per actionable finding ID in the group (the probe's actionable set; the consuming loop places non-actionable findings)** (`context: "fresh"`, `worktree: true`, `cwd` = the current worktree; task = that finding's block **verbatim**, including its `touched-files` line as the ownership boundary). An actionable finding named in any `conflicts` pair runs sequentially after every finding it names has integrated (chained `conflicts` define a partial order; remaining serial findings run in the line's order). Actionable findings outside any ≥ 2-ID `disjoint` group run sequentially. Fan out per review line only — never merge or co-schedule groups from different `Parallel-safe:` lines; run those fan-outs serially.
|
|
115
115
|
|
|
116
|
-
**Precondition:**
|
|
116
|
+
**Precondition:** select the review source below before dispatching fixes.
|
|
117
|
+
|
|
118
|
+
| Review source | Fix dispatch |
|
|
119
|
+
|---|---|
|
|
120
|
+
| Clean committed HEAD containing the code under review (verify-phase whole-diff review or conformance loop) | Fan out from that HEAD when the certificate permits. |
|
|
121
|
+
| Unintegrated patch (per-patch spec review) | Branch each fix task from `WAVE_BASE_SHA` and carry the prior patch verbatim in its task text, per the consuming loop's spec-gap re-dispatch protocol. |
|
|
122
|
+
| Integrated wave before its accepted-wave commit | Fix in place; fan-out is unavailable. Keep the wave commit after its required review accepts, before `plan_tracker` `complete`; never commit early to enable fan-out. |
|
|
117
123
|
|
|
118
124
|
Grammar (identical across producers, modulo id prefix — `F` for code/spec reviewers, `G` for conformance-reviewer):
|
|
119
125
|
|
|
@@ -145,6 +145,26 @@ Zero pairs -> stop; more than one -> human picks.
|
|
|
145
145
|
|
|
146
146
|
Entered from the call table's `implement` row and from `reconstruction.md` "Spec with plan" step 2 when `plan_check` returns FAIL. Inputs: the findings, and the task list with statuses (the brief's, or the confirmed reconstruction snapshot) - read it for evidence, never rewrite it.
|
|
147
147
|
|
|
148
|
+
Before citation-table classification, route `baseline-line` and substantive `open-questions` findings through the continuation below. Keep the brief's or confirmed reconstruction's task snapshot (names, order, statuses) verbatim throughout; never take writing-plans step 7's fresh-plan initialization.
|
|
149
|
+
|
|
150
|
+
### Baseline continuation
|
|
151
|
+
|
|
152
|
+
On `baseline-line` or a substantive baseline-form `open-questions` finding, bring a landed fix named by the brief or human into the worktree through `/skill:using-git-worktrees` "the base branch advances" (rebase, or merge for a shared branch). Without a named fix, proceed directly to the rerun. Dispatch `plan-writer` per `/skill:writing-plans` "Author the plan" step 3: `agent: "plan-writer"`, `context: "fresh"`, `async: false`, `cwd: <absolute worktree>`, `phase: "plan-write"`, `acceptance: { level: "none", reason: "the parent plan_check owns acceptance" }`. Fill its fixed task template with the five absolute paths (worktree, spec, plan, writing-plans SKILL.md, its reference/plan-contract.md), then append `Findings: rerun baseline`. Let the writer run Baseline and regenerate its rows; never synthesize evidence or SHAs. On dispatch error, async handle, or missing/empty plan, stop and report without a parent-authored fallback.
|
|
153
|
+
|
|
154
|
+
Run `plan_check({ planPath })` in the parent after either child reply. Route the result:
|
|
155
|
+
|
|
156
|
+
| Result / substantive row | Continuation |
|
|
157
|
+
|---|---|
|
|
158
|
+
| `PLAN WRITTEN` + `PASS`, section absent or exactly `- none` | Return to the originating restore's remaining steps: call table from `skip plan R` through the appropriate implement/verify continuation (ship restores at verify), or reconstruction step 3. Initialize `plan_tracker` only from the saved task snapshot, never the generated fresh-plan list. |
|
|
159
|
+
| `- Task N: ... fails on <sha>` | Present the task, command, base SHA and exit code, then writing-plans step 6's three options, one per line: **fix-first** - `/skill:shape-ticket` for the base failure (its gate applies), then pause; **narrow** - human supplies filter or path text, re-dispatch with `Findings: Task N Tests: narrow to <text>`; **amend** - brainstorming's `reference/amendment-surface.md` section 5. Print a `Recommendation:` line and wait for selection. |
|
|
160
|
+
| Global or contamination rows (`Baseline: worktree dirty`, `Baseline: in-flight source edits`, `dirtied tracked source`, `moved HEAD`) | Take writing-plans step 6's restore-and-rerun path, not the menu. Name paths and causes; the parent's own in-flight work uses its own commit step (doc-only paths can be listed under `In-flight:`); ask the human to commit, discard, or move other paths and test-produced dirt. Never clean automatically. After restoration re-dispatch with `Findings: rerun baseline`, then parent check. |
|
|
161
|
+
| Other substantive `open-questions` rows (contract questions) | Present the rows, wait for answers, re-dispatch per step 3 with answers in `Findings:`, then parent check and this same return route. |
|
|
162
|
+
| Other checks | Use the citation table and its three-round rollback below. |
|
|
163
|
+
|
|
164
|
+
End a turn awaiting selection, restoration, or answers with phase `plan` retained in_progress and no tracker initialization of any kind. Keep the snapshot for the eventual return. Resolved failure rows disappear only through the writer's Baseline rerun; resume writes no Open Questions rows. Plans without `baseline:` bullets intentionally enter this continuation on their `baseline-line` finding.
|
|
165
|
+
|
|
166
|
+
### Citation repair
|
|
167
|
+
|
|
148
168
|
Record the plan's state before any write: tracked and clean when `git -C <worktree> ls-files --error-unmatch -- <plan path>` exits 0 and `git -C <worktree> status --porcelain -- <plan path>` prints nothing (index and working copy both match HEAD; a staged edit alone makes it dirty); otherwise copy the file to a temp path outside the worktree.
|
|
149
169
|
|
|
150
170
|
Classify every finding against the table by its `check` and `reason`, gathering the row's evidence first. One finding with no row -> stop (below) before any write.
|
|
@@ -158,7 +178,7 @@ Classify every finding against the table by its `check` and `reason`, gathering
|
|
|
158
178
|
| `paths-exist`, `Modify: path "<p>" does not exist` | the owning task is `complete` or `skipped` in the task list, and `git -C <worktree> log --diff-filter=D --format=%h -1 -- <p>` is non-empty | drop that `Modify:` row |
|
|
159
179
|
| `paths-exist` or `tests-block`, a `Test:` path that does not exist or a `Tests:` segment not anchored | `git -C <worktree> log --diff-filter=R --format= --name-status -M -1 -- <old> <new>` shows the rename `<old>` -> `<new>` | substitute `<new>` for `<old>` in the `Test:` line and in the `Tests:` command; nothing else in the command changes |
|
|
160
180
|
|
|
161
|
-
Every other `check` (`input`, `placeholder-scan`, `header-entrypoint`, `header-happy-path`, `waiver-literal`, `wave-file-disjointness`, `
|
|
181
|
+
Every other `check` (`input`, `placeholder-scan`, `header-entrypoint`, `header-happy-path`, `waiver-literal`, `wave-file-disjointness`, `internal`) and every reason not listed (a missing `Files:` block, an invalid or empty glob, a missing or ambiguous heading, a `pending`/`in_progress` owner of a dead `Modify:` row, a command broadening) has no row. Task names, count, order, wave membership, `Solo:` lines, the owner column, and task text beyond an added literal or a substituted path never change.
|
|
162
182
|
|
|
163
183
|
Loop: write every classified edit, re-run `plan_check({ planPath })`, classify any new finding the same way; at most 3 rounds.
|
|
164
184
|
|
|
@@ -175,7 +195,7 @@ Stop (a finding with no row, or a finding surviving the third round): when a rou
|
|
|
175
195
|
- no row: `Repair stopped: <check> - <reason> is outside citation repair; the plan file is unchanged. Edit the plan (task changes allowed), then re-run /skill:gauntlet-resume.`
|
|
176
196
|
- third round: `Repair stopped: <check> - <reason> survived 3 rounds. Edit the plan, then re-run /skill:gauntlet-resume.`
|
|
177
197
|
|
|
178
|
-
Resume never edits the spec
|
|
198
|
+
Resume never edits the spec or writes an Open Question itself; the dispatched plan-writer owns generated baseline rows.
|
|
179
199
|
|
|
180
200
|
"Exact" restoration binds: the active phase identity and substep, and the plan task list
|
|
181
201
|
(names, order, statuses) verbatim. Prior phases show `⊘ (resume: ...)` regardless of the
|
|
@@ -14,7 +14,7 @@ Dispatch a subagent with the code-reviewer prompt template to catch issues befor
|
|
|
14
14
|
## When to Request Review
|
|
15
15
|
|
|
16
16
|
**Mandatory:**
|
|
17
|
-
-
|
|
17
|
+
- Dispatch one initial code review per code-touching wave in subagent-driven development, over the integrated wave diff; doc-only waves are SR-only
|
|
18
18
|
- After completing major feature
|
|
19
19
|
- Before merge to main
|
|
20
20
|
|
|
@@ -25,7 +25,7 @@ Dispatch a subagent with the code-reviewer prompt template to catch issues befor
|
|
|
25
25
|
|
|
26
26
|
## How to Request
|
|
27
27
|
|
|
28
|
-
**1. Select the review source.** For an integrated uncommitted wave, use its recorded base as `BASE_SHA` and the literal `WORKTREE` as `HEAD_SHA`; stage new deliverables before dispatch, per `code-reviewer.md`. For
|
|
28
|
+
**1. Select the review source.** For an integrated uncommitted wave, use its recorded base as `BASE_SHA` and the literal `WORKTREE` as `HEAD_SHA`; stage new deliverables before dispatch, per `code-reviewer.md`. For the whole-diff review only, use the committed range:
|
|
29
29
|
```bash
|
|
30
30
|
BASE_SHA=$(git rev-parse HEAD~1) # or origin/main
|
|
31
31
|
HEAD_SHA=$(git rev-parse HEAD)
|
|
@@ -51,7 +51,7 @@ subagent({ agent: "code-reviewer", async: false, task: "... filled template ..."
|
|
|
51
51
|
- `{DESCRIPTION}` - Brief summary
|
|
52
52
|
- `{SCOPED_TEST_COMMANDS}` - the scoped verification commands the reviewer may run, or `none`
|
|
53
53
|
|
|
54
|
-
**Fix rounds.** A `FIX_FIRST` report triggers a fix round. A `SHIP` report dispatches nothing and ends the loop, whatever Minors it lists. `REJECT` is neither: stop and report (in SDD, per its `stop-note.md`); no fix round. When dispatched from an orchestrating skill, fixes go to `implementer` subagents (per the orchestrator's no-self-coding rule), fanned out per `dispatching-parallel-agents` "Fix fan-out" when the review's `Parallel-safe:` line certifies a `disjoint` group of ≥ 2 Critical/Moderate findings. Before fanning out, validate the review's `Parallel-safe:` line with the structural probe in `dispatching-parallel-agents` § Fix fan-out (exactly-one-line grammar check, one re-ask, then explicit sequential fallback). Sequential round (one task): the task carries the whole report; every Minor rides. Fan-out: the certificate partitions the Critical and Moderate findings; each Minor attaches once to the first task, in `Fn` order, whose ownership boundary - the union of its findings' `touched-files:` - already contains the Minor's `touched-files:`; a Minor no boundary contains is not dispatched this round, and a boundary never grows for a Minor. The implementer fixes its Minors or declines one with a stated reason. After integration and the project's test command, re-dispatch the reviewer once on the integrated delta in the foreground with top-level `async: false`; await its terminal result. A `FIX_FIRST` re-review buys one more fix round and one more foreground re-review; still `FIX_FIRST` -> escalate to the user. A `SHIP` report's Minors are not carried, with one exception: the whole-diff review's Minor finding lines go verbatim into the closure block's `whole-diff minors:` section (`verification-before-completion/reference/conformance-check.md` "Closure / conformance").
|
|
54
|
+
**Fix rounds.** A `FIX_FIRST` report triggers a fix round. A `SHIP` report dispatches nothing and ends the loop, whatever Minors it lists. `REJECT` is neither: stop and report (in SDD, per its `stop-note.md`); no fix round. When dispatched from an orchestrating skill, fixes go to `implementer` subagents (per the orchestrator's no-self-coding rule), fanned out per `dispatching-parallel-agents` "Fix fan-out" when the review's `Parallel-safe:` line certifies a `disjoint` group of ≥ 2 Critical/Moderate findings. Apply `dispatching-parallel-agents` "Fix fan-out" source precondition first: an integrated wave before its accepted-wave commit gets one in-place repair worker, not fan-out; keep the commit after acceptance. Before fanning out, validate the review's `Parallel-safe:` line with the structural probe in `dispatching-parallel-agents` § Fix fan-out (exactly-one-line grammar check, one re-ask, then explicit sequential fallback). Sequential round (one task): the task carries the whole report; every Minor rides. Fan-out: the certificate partitions the Critical and Moderate findings; each Minor attaches once to the first task, in `Fn` order, whose ownership boundary - the union of its findings' `touched-files:` - already contains the Minor's `touched-files:`; a Minor no boundary contains is not dispatched this round, and a boundary never grows for a Minor. The implementer fixes its Minors or declines one with a stated reason. After integration and the project's test command, re-dispatch the reviewer once on the integrated delta in the foreground with top-level `async: false`; await its terminal result. A `FIX_FIRST` re-review buys one more fix round and one more foreground re-review; still `FIX_FIRST` -> escalate to the user. A `SHIP` report's Minors are not carried, with one exception: the whole-diff review's Minor finding lines go verbatim into the closure block's `whole-diff minors:` section (`verification-before-completion/reference/conformance-check.md` "Closure / conformance").
|
|
55
55
|
|
|
56
56
|
Worked example: a `FIX_FIRST` report with 1 Moderate and 3 Minors -> one implementer task holding all four findings (one actionable ID, no fan-out). A `SHIP` report with 4 Minors -> no dispatch; the loop ends.
|
|
57
57
|
|
|
@@ -60,9 +60,8 @@ Take the recipient stance from `receiving-code-review`: verify each finding, ans
|
|
|
60
60
|
## Integration with Workflows
|
|
61
61
|
|
|
62
62
|
**Subagent-Driven Development:**
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
- Fix before moving to next task
|
|
63
|
+
- Dispatch one initial code review per code-touching wave over the integrated wave diff; doc-only waves are SR-only
|
|
64
|
+
- Fix and re-review before the accepted-wave commit and before moving to the next wave
|
|
66
65
|
|
|
67
66
|
**Ad-Hoc Development:**
|
|
68
67
|
- Review before merge
|
|
@@ -43,41 +43,19 @@ Periodic "should I continue?" prompts add latency without adding safety. The pla
|
|
|
43
43
|
- Approved plan or clear task scope
|
|
44
44
|
- `plan_tracker` list initialized at writing-plans handoff with the full wave-ordered task list. Consume and preserve it on continuation; only direct recovery with no tracker initializes the full plan list once, before dispatch, and never over an existing list.
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Extract **`SCOPED_TEST_COMMANDS`** from the task's `**Tests:**` command bullets, backticks stripped, one per line; `- none:` -> `none`; a wave = the union of its tasks' commands. Treat `via:` and `baseline:` bullets and `- Test:` paths as contract, not commands: carry them with the task text, never in `SCOPED_TEST_COMMANDS`.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
**Dependent tasks:** include the previous task's implementation summary and relevant file paths in the next subagent's `task`. Track outputs so you can pass them forward.
|
|
51
|
-
|
|
52
|
-
## The Process
|
|
53
|
-
|
|
54
|
-
Before the first task, enter the implement phase: `phase_tracker({ action: "start", phase: "implement" })` — you hold this phase for the parent session while the per-task work is dispatched to subagents; `plan_tracker` auto-completes it once every task is done.
|
|
55
|
-
|
|
56
|
-
For each task in `plan_tracker`:
|
|
57
|
-
|
|
58
|
-
**`SCOPED_TEST_COMMANDS`** = the task's `**Tests:**` command bullets, backticks stripped, one per line; `- none:` -> `none`; a wave = the union of its tasks' commands. `via:` bullets and `- Test:` paths are contract, not commands: they ride with the task text, never in `SCOPED_TEST_COMMANDS`.
|
|
59
|
-
|
|
60
|
-
1. **Start, then dispatch implementer.** Mark the task's existing `plan_tracker` index `in_progress` before dispatch. Pass the full task text + scene-setting context + its `SCOPED_TEST_COMMANDS` (definition above) and its `**Tests:**` block verbatim. Don't make the subagent re-read the plan.
|
|
61
|
-
2. **Handle implementer status** (see below).
|
|
62
|
-
3. **Dispatch spec reviewer.** Pass the task text, the patch diff, the absolute spec path, and the task's `**Spec:**` anchors, plus the task's `**Tests:**` block and `- Test:` paths as contract (never as commands - SR never executes) — SR reads the anchored ranges from the spec file itself; never inline spec excerpts. The spec wins every dispute; the authority hierarchy and finding labels live in `./spec-reviewer-prompt.md`. Anchor-less tasks (no `**Spec:**` line): task text alone is the contract. Verify the change satisfies the anchored spec — nothing missing, nothing extra.
|
|
63
|
-
4. If spec reviewer finds gaps → re-dispatch implementer to fix → re-review. Loop until ✅, within [Fix-Loop Rounds](#fix-loop-rounds).
|
|
64
|
-
5. **Dispatch code-quality reviewer.** Only after spec is ✅. Skip for doc-only tasks (every file in the task's `Files:` block documentation-only) — SR-only, same exemption as doc-only waves. Pass the task's `SCOPED_TEST_COMMANDS`.
|
|
65
|
-
6. If the quality review is issue-bearing → re-dispatch the implementer per `/skill:requesting-code-review` Fix rounds → re-review. Loop until ✅, within [Fix-Loop Rounds](#fix-loop-rounds).
|
|
66
|
-
7. After its existing reviews accept the work (and its required commit point), mark that same task index `complete` in `plan_tracker`. A subagent exit or green tests alone are not acceptance.
|
|
67
|
-
|
|
68
|
-
The orchestrator is the spec's only writer during execution. Amendment trigger: implementer `BLOCKED` citing a spec defect, or a review finding showing the spec (not the code) is wrong -> pause the fix loop, `read` and execute brainstorming's [amendment path](../brainstorming/SKILL.md#amending-an-approved-spec) in place (it reviews first, stops only on escalation or redraw), resume. Code-vs-spec mismatch stays in the SR loop. An SR unable to read the spec at a cited anchor (missing file, unresolvable heading/range) returns a blocking finding — the contract is spec+task or stop, never a silent fallback to task-only review.
|
|
69
|
-
|
|
70
|
-
After all tasks: proceed to [After All Tasks](#after-all-tasks-complete) - it owns parent full verification, then whole-diff code review, then conformance.
|
|
48
|
+
Keep the orchestrator as the spec's only writer during execution. On implementer `BLOCKED` citing a spec defect, or a review finding showing the spec (not the code) is wrong, pause the fix loop, read and execute brainstorming's [amendment path](../brainstorming/SKILL.md#amending-an-approved-spec) in place (it reviews first, stops only on escalation or redraw), then resume. Keep code-vs-spec mismatch in the SR loop. Require an SR unable to read the spec at a cited anchor (missing file, unresolvable heading/range) to return a blocking finding - the contract is spec+task or stop, never a silent fallback to task-only review.
|
|
71
49
|
|
|
72
50
|
## Fix-Loop Rounds
|
|
73
51
|
|
|
74
|
-
|
|
52
|
+
Apply one rule to both review loops - spec-compliance and code-quality.
|
|
75
53
|
|
|
76
|
-
**Re-review dispatch rule:** every re-review task includes the complete prior review report verbatim under the marker `## Previous review report (re-review trigger)`, plus the trajectory block from the reviewer's prompt template. The marker's presence is what obligates the reviewer to emit the `TRAJECTORY:` line. You never select, summarize, or diff findings yourself - pattern-match the sentinel line only.
|
|
54
|
+
**Re-review dispatch rule:** every re-review task includes the complete prior review report verbatim under the marker `## Previous review report (re-review trigger)`, plus the trajectory block from the reviewer's prompt template. The marker's presence is what obligates the reviewer to emit the `TRAJECTORY:` line. You never select, summarize, or diff findings yourself - pattern-match the sentinel line only. Include the delta defined in [Fix delta](#fix-delta) in every SR/CR re-review.
|
|
77
55
|
|
|
78
|
-
**Fix fan-out.** When a fix round is fanned out per `/skill:requesting-code-review` Fix rounds, dispatch
|
|
56
|
+
**Fix fan-out.** When a fix round is fanned out per `/skill:requesting-code-review` Fix rounds, use the precondition and dispatch shape owned by `/skill:dispatching-parallel-agents` "Fix fan-out"; the fan-out counts as **one** fix against this budget, its scoped test gate is the consuming task/wave's `SCOPED_TEST_COMMANDS`, and one re-review of the integrated delta follows.
|
|
79
57
|
|
|
80
|
-
**Behaviour-change reroute.** When the triggering CR report carries `Behaviour-change: yes`, the fix round's re-review is SR first, then CR.
|
|
58
|
+
**Behaviour-change reroute.** When the triggering CR report carries `Behaviour-change: yes`, the fix round's re-review is SR first, then CR. Include `## Fix delta` on this SR-first behavior-change repair. Dispatch SR against the fix diff and the task's spec anchors as a first review (no `## Previous review report` marker, so no `TRAJECTORY:` line; SR carries no test commands but does carry the task's `**Tests:**` block and `- Test:` paths), but its ordinal continues the task's SR-loop count - a task whose SR loop ended at review 2 gets review 3 here, and an issue-bearing rerouted SR after review 4 escalates. Issues follow the normal sequence: fix, then SR re-review pasting this SR's report. CR round numbering is unchanged. `Behaviour-change: no` re-reviews with CR only. A missing or malformed `Behaviour-change:` line is re-asked once like `Parallel-safe:` (see `dispatching-parallel-agents` "Structural probe"); still missing -> route through SR, never default to `no`. Target the SR re-review at the task(s) whose files the fix touched; after integration, dispatch it against the current implementation worktree, not a pre-integration snapshot.
|
|
81
59
|
|
|
82
60
|
Every fix re-dispatch (implementer) and code-review re-review carries the consuming task/wave's `SCOPED_TEST_COMMANDS`; spec-reviewer re-reviews carry the `**Tests:**` block and `- Test:` paths, no commands - SR never executes.
|
|
83
61
|
|
|
@@ -90,7 +68,7 @@ Every fix re-dispatch (implementer) and code-review re-review carries the consum
|
|
|
90
68
|
|
|
91
69
|
Every dispatched fix is verified by a re-review before escalation or task progression - the loop only ever exits on a clean review or an escalation.
|
|
92
70
|
|
|
93
|
-
**Escalate** = one escalated round; stop only on failure. Call `gauntlet_setting({ key: "escalationLoop" })` (unavailable -> stop and report). `implModel` undefined -> stop note. Otherwise re-dispatch that fix - same payload and isolation knobs (`cwd`, `worktree`, `SCOPED_TEST_COMMANDS`, status protocol, prior patch, spec anchors) plus the prior report verbatim - overriding only `model: <implModel>`, `context: "fresh"`, `async: false`; one implementer, no fan-out. Run the normal fix-round review gate (SR then CR on `Behaviour-change: yes`, else the triggering reviewer with the re-review marker). All clean -> proceed;
|
|
71
|
+
**Escalate** = one escalated round; stop only on failure. Call `gauntlet_setting({ key: "escalationLoop" })` (unavailable -> stop and report). `implModel` undefined -> stop note. Otherwise re-dispatch that fix - same payload and isolation knobs (`cwd`, `worktree`, `SCOPED_TEST_COMMANDS`, status protocol, prior patch, spec anchors) plus the prior report verbatim - overriding only `model: <implModel>`, `context: "fresh"`, `async: false`; one implementer, no fan-out. Run the normal fix-round review gate (SR then CR on `Behaviour-change: yes`, else the triggering reviewer with the re-review marker). All clean -> proceed; the escalated patch supersedes the prior one at integrate. Any review with issues, a non-`DONE` status, or a dispatch error -> stop note per `stop-note.md`; no second dispatch. Once per loop; independent of the convergence exception. No `plan_tracker` write during escalation - the task stays `in_progress` until the human decides.
|
|
94
72
|
|
|
95
73
|
**Worked examples:**
|
|
96
74
|
|
|
@@ -98,16 +76,37 @@ Every dispatched fix is verified by a re-review before escalation or task progre
|
|
|
98
76
|
- Review-3 verdict `TRAJECTORY: CONVERGING (3 -> 1, max severity Moderate)` -> dispatch fix 3; if review 4 still finds issues, escalate.
|
|
99
77
|
- Review-3 verdict `TRAJECTORY: CONVERGING (3 -> 2, max severity Critical)` or `TRAJECTORY: DIVERGING` or no `TRAJECTORY:` line -> escalate.
|
|
100
78
|
|
|
79
|
+
## Fix delta
|
|
80
|
+
|
|
81
|
+
Include a `## Fix delta` block in every SR/CR re-review payload: `git diff --binary <tree-before> <tree-after>` between the tree recorded at the prior review's dispatch and the tree recorded at this re-review's dispatch. Record each tree with the shell block below; keep the printed SHA keyed by task for SR or wave for CR. Run it in the spec-review snapshot for pre-integration reviews, or in the branch checkout for integrated reviews (`FD_ROOT`). Tree objects share the repository's object store; use `git -C "$FD_ROOT" diff --binary <tree-before> <tree-after>` to produce the delta. Worker commits and staging state do not affect it; never substitute a SHA range or working-tree diff.
|
|
82
|
+
|
|
83
|
+
Substitute a shell-quoted checkout path for `{{CHECKOUT}}` and run the entire block. Stop review dispatch on a nonzero exit and report the shell error. The block reads the live index, writes only a scratch index and tree object, and preserves checkout status.
|
|
84
|
+
|
|
85
|
+
<!-- fix-delta-tree-shell -->
|
|
86
|
+
```bash
|
|
87
|
+
FD_ROOT={{CHECKOUT}}
|
|
88
|
+
FD_INDEX=$(mktemp) || exit 1
|
|
89
|
+
cp "$(git -C "$FD_ROOT" rev-parse --path-format=absolute --git-path index)" "$FD_INDEX" || { rm -f "$FD_INDEX"; exit 1; }
|
|
90
|
+
GIT_INDEX_FILE="$FD_INDEX" git -C "$FD_ROOT" add -A && GIT_INDEX_FILE="$FD_INDEX" git -C "$FD_ROOT" write-tree
|
|
91
|
+
FD_STATUS=$?
|
|
92
|
+
rm -f "$FD_INDEX"
|
|
93
|
+
exit "$FD_STATUS"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Omit the delta for whole-diff re-reviews. Otherwise omit it only when the prior tree is genuinely unavailable after a fresh-session resume; the reviewer then treats the task's whole diff as the delta. On an empty delta (including ignored-only repairs), dispatch no re-review: count a failed attempt under [When a Subagent Fails](#when-a-subagent-fails), resend the prior report with "your fix changed no tracked file", and stop after the existing two-attempt limit.
|
|
97
|
+
|
|
101
98
|
## Implementer Status
|
|
102
99
|
|
|
103
100
|
Every implementer dispatch returns one of:
|
|
104
101
|
|
|
105
102
|
| Status | Meaning | Orchestrator action |
|
|
106
103
|
|---|---|---|
|
|
107
|
-
| `DONE` | Implemented + tests pass + self-reviewed
|
|
104
|
+
| `DONE` | Implemented + tests pass + self-reviewed; work present in the worker's tree; the wave commit is step 7 | Proceed to spec review |
|
|
108
105
|
| `DONE_WITH_CONCERNS` | Implemented + tests pass, but flagged a deviation or risk | Read concerns. If acceptable, proceed. If not, dispatch fix subagent. |
|
|
109
|
-
| `NEEDS_CONTEXT` | Implementer needs information you have |
|
|
110
|
-
| `BLOCKED` | Cannot proceed (missing dependency, spec contradicts code, environment broken) |
|
|
106
|
+
| `NEEDS_CONTEXT` | Implementer needs information you have | Resolve fact asks per [lookup handling](./stop-note.md). For decisions, answer and re-dispatch with answers in the task text, or escalate to the user. |
|
|
107
|
+
| `BLOCKED` | Cannot proceed (missing dependency, spec contradicts code, environment broken) | Resolve fact asks per [lookup handling](./stop-note.md). For decisions, stop and diagnose: fix the orchestration-level issue and re-dispatch, or escalate to the user. |
|
|
108
|
+
|
|
109
|
+
Classify each question: artifact location, value, or existence is a fact ask; scope choices, option choices, and another-round approval are decisions.
|
|
111
110
|
|
|
112
111
|
Implementer prompt templates must instruct subagents to return one of these statuses explicitly.
|
|
113
112
|
|
|
@@ -121,11 +120,11 @@ Implementer prompt templates must instruct subagents to return one of these stat
|
|
|
121
120
|
|
|
122
121
|
## Dispatch
|
|
123
122
|
|
|
124
|
-
Pass the implementation worktree as top-level `cwd
|
|
123
|
+
Pass the implementation worktree as top-level `cwd`. For per-patch spec reviews, use [Spec-review snapshots](#spec-review-snapshots) instead.
|
|
125
124
|
|
|
126
125
|
```ts
|
|
127
|
-
//
|
|
128
|
-
subagent({ agent: "implementer", async: false, cwd: "<abs worktree path>", task: "<task text + context + SCOPED_TEST_COMMANDS + status protocol>" })
|
|
126
|
+
// in-place repair worker
|
|
127
|
+
subagent({ agent: "implementer", async: false, cwd: "<abs worktree path>", task: "<task text + context + prior report verbatim + SCOPED_TEST_COMMANDS + status protocol>" })
|
|
129
128
|
|
|
130
129
|
// escalated fix round (Fix-Loop Rounds): same fix payload, model from gauntlet_setting({ key: "escalationLoop" }).implModel
|
|
131
130
|
subagent({ agent: "implementer", model: "<implModel>", context: "fresh", async: false, cwd: "<abs worktree path>", task: "<the just-dispatched fix payload + prior review report verbatim>" })
|
|
@@ -148,30 +147,29 @@ Prompt templates live alongside this SKILL.md:
|
|
|
148
147
|
- `./spec-reviewer-prompt.md`
|
|
149
148
|
- `./code-quality-reviewer-prompt.md`
|
|
150
149
|
|
|
151
|
-
##
|
|
150
|
+
## The Wave Loop
|
|
152
151
|
|
|
153
|
-
|
|
152
|
+
Run every plan task through this loop in a wave of N >= 1 tasks. Run waves in sequence; dispatch file- and runtime-resource-disjoint tasks concurrently in isolated worktrees, then integrate serially behind one test + review gate. For dependent tasks, include the previous task's implementation summary and relevant file paths in the next subagent's `task`; track outputs to pass them forward.
|
|
154
153
|
|
|
155
|
-
**Enter the implement phase first.** Before the first wave, call `phase_tracker({ action: "start", phase: "implement" })
|
|
154
|
+
**Enter the implement phase first.** Before the first wave, call `phase_tracker({ action: "start", phase: "implement" })`; `plan_tracker` auto-completes it once every task across all waves is done.
|
|
156
155
|
|
|
157
156
|
**Progress tracking (`plan_tracker`).** `plan_tracker` is a flat list with no native group concept, so waves are *encoded*, not modeled:
|
|
158
157
|
|
|
159
158
|
- **Consume, preserve, recover only if absent:** consume the wave-ordered list initialized at writing-plans handoff; indices are positional and stable, so never re-init on continuation or mid-run. Only direct recovery with no tracker initializes the full plan list once before dispatch.
|
|
160
|
-
- **Wave fan-out → `in_progress`:** unconditionally mark every task index in the wave `in_progress` before dispatch, in increasing index order (the tracker validates each call against the previous one and rejects a start while an earlier index is still `pending`).
|
|
159
|
+
- **Wave fan-out → `in_progress`:** unconditionally mark every task index in the wave `in_progress` before dispatch, in increasing index order (the tracker validates each call against the previous one and rejects a start while an earlier index is still `pending`). Expect one or more simultaneous entries.
|
|
161
160
|
- **Wave commit → `complete`:** after the wave's gate passes and it commits, unconditionally mark all those same indices `complete`. `complete` = durably committed, so a task in conflict fallback stays `in_progress` until its wave commits.
|
|
162
|
-
- **Lifecycle per task:** `pending → in_progress (wave fan-out) → complete (wave commit)`; `
|
|
163
|
-
- **Widget caveat (known, deliberately unfixed).** The persistent `plan_tracker` widget's icon strip (`○ → ✓`) and `(c/total)` count reflect every task, but its trailing *name* shows only the **first** `in_progress` task.
|
|
164
|
-
- **Sequential mode:** consume the same existing full list, one `in_progress` index at a time; wave prefixes are harmless.
|
|
161
|
+
- **Lifecycle per task:** `pending → in_progress (wave fan-out) → complete (wave commit)`; keep `in_progress` through exhausted integration or repair attempts pending the human's decision (see [When a Subagent Fails](#when-a-subagent-fails)); use `failed` only for a human-decided terminal failure; `skipped` when the plan drops it as not applicable (terminal, counted done). A rejected `update` names the earlier pending tasks and the legal fixes - record those tasks' true state, never `clear` or re-`init` to move on.
|
|
162
|
+
- **Widget caveat (known, deliberately unfixed).** The persistent `plan_tracker` widget's icon strip (`○ → ✓`) and `(c/total)` count reflect every task, but its trailing *name* shows only the **first** `in_progress` task. Use the icon strip and the `status` action for the full in-flight view; a richer multi-task widget is a separate extension change, out of scope (YAGNI).
|
|
165
163
|
|
|
166
164
|
**Per-wave loop:**
|
|
167
165
|
|
|
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;
|
|
166
|
+
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; split it into one-task waves and note it.
|
|
169
167
|
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
168
|
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
|
-
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.
|
|
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.
|
|
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).
|
|
174
|
-
7. **Commit and complete the wave.** After
|
|
169
|
+
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. On an apply failure, drop that task from the wave; finish steps 5-7 for the survivors, then re-dispatch the dropped task as a one-task wave from the new committed HEAD. With zero surviving patches, skip steps 5-7 and retry the failed task from the unchanged clean HEAD under [When a Subagent Fails](#when-a-subagent-fails)'s two-attempt limit; dispatch no empty review or commit. Keep its tracker index `in_progress` until its own wave commits.
|
|
170
|
+
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. On failure, dispatch one plain in-place `implementer` in the branch checkout with the failing output, the owning task's full text, and the wave's `SCOPED_TEST_COMMANDS`, under [When a Subagent Fails](#when-a-subagent-fails), then rerun the scoped gate. After the repaired tree passes, stage repair deliverables with `git -C <worktree> add -A` and dispatch spec review for every affected task against the integrated checkout before the initial CR; prior SR acceptance does not cover the repair. Pass each affected task's full text, absolute spec path, `Spec:` anchors, `Tests:` block, and `- Test:` paths; record its review tree per [Fix delta](#fix-delta). Resolve SR findings through [Fix-Loop Rounds](#fix-loop-rounds), with repairs in place and the scoped gate rerun. Never dispatch a nested wave from this dirty checkout: children cannot see integrated siblings from the old HEAD.
|
|
171
|
+
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). Dispatch repairs as plain in-place workers in the branch checkout, never nested waves from the dirty checkout. Carry the report verbatim and no commit or staging instruction in the repair payload. Before every CR dispatch and every SR/CR re-review, run `git -C <worktree> add -A` so all deliverables appear in the whole diff; record the review tree per [Fix delta](#fix-delta). 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).
|
|
172
|
+
7. **Commit and complete the wave.** After CR accepts (SR alone for doc-only waves), fold worker commits and all remaining changes into one durable wave commit: `git -C <worktree> reset --soft "$WAVE_BASE_SHA" && git -C <worktree> add -A && git -C <worktree> commit -m <message>`. Then mark the wave's existing indices `complete`. Stop on an empty commit instead of completing tasks. Leave a clean tree so the next wave's children see the integrated work.
|
|
175
173
|
|
|
176
174
|
**Two-stage review is preserved:** spec review per task (pre-integration, dispatched `spec-reviewer` — not inline), quality review per wave (post-integration). A wave commit requires one spec-review verdict per accepted task, plus one code-review verdict on the integrated diff for waves that touch code. A doc-only wave (every task's `Files:` block documentation-only, per `writing-plans`' Wave Grouping) is SR-only — the CR gate does not apply.
|
|
177
175
|
|
|
@@ -265,14 +263,14 @@ Route the result already read in step 3; retain all successful sibling patches a
|
|
|
265
263
|
|
|
266
264
|
| Outcome | Recovery |
|
|
267
265
|
|---|---|
|
|
268
|
-
| Exit-0 stop (`## Stop`) with no failed siblings | Siblings finished, statuses remain in `## Outputs`, and no SR step ran. Judge `DONE_WITH_CONCERNS`,
|
|
266
|
+
| Exit-0 stop (`## Stop`) with no failed siblings | Siblings finished, statuses remain in `## Outputs`, and no SR step ran. Judge `DONE_WITH_CONCERNS`, handle `NEEDS_CONTEXT` and `BLOCKED` per the status table, then snapshot accepted patches and use the ordinary SR fan-out below. |
|
|
269
267
|
| 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
268
|
| 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
269
|
| Older-runtime fallback | Parse the plain fan-out statuses, then use the same snapshot-backed SR and fix loop below. |
|
|
272
270
|
|
|
273
271
|
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
272
|
|
|
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.
|
|
273
|
+
**Re-dispatch by cause:** Before fixing a chain-run SR's `NEEDS_REWORK` or `OUT_OF_SCOPE_CHANGES`, reconstruct the original artifact patch's snapshot from `WAVE_BASE_SHA` and record its tree-before per [Fix delta](#fix-delta); the chain's own trees are already removed. Route `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. Materialize the replacement patch in a new detached `WAVE_BASE_SHA` checkout with `git apply --index` per [Spec-review snapshots](#spec-review-snapshots); on setup or tree-capture failure, stop dispatch and retain the failed snapshot directory and shell output for diagnosis. After successful setup, record tree-after in that replacement snapshot before dispatching one plain re-review with `## Previous review report (re-review trigger)`, the trajectory block, and `## Fix delta`. The new patch supersedes the old at step 4. Loop until accepted + spec compliant, within [Fix-Loop Rounds](#fix-loop-rounds). Never dispatch a second chain in the same wave.
|
|
276
274
|
|
|
277
275
|
## Spec-review snapshots
|
|
278
276
|
|
|
@@ -292,7 +290,7 @@ git -C "$SR_TREE" apply --index "$SR_PATCH" || exit 1
|
|
|
292
290
|
printf 'snapshot: %s\n' "$SR_TREE"
|
|
293
291
|
```
|
|
294
292
|
|
|
295
|
-
Use the printed snapshot path as that spec-review task's `cwd` and whole-file read root. Keep the authoritative spec's absolute path in the implementation worktree. Pass the patch diff as before; the snapshot contains this task's changed and added files, with deleted files absent. Read deleted files from `WAVE_BASE_SHA` when the review needs their prior contents. Dispatch read-only, with no `worktree` flag.
|
|
293
|
+
Record its review tree per [Fix delta](#fix-delta) before every parent-dispatched SR, keyed by task. Use the printed snapshot path as that spec-review task's `cwd` and whole-file read root. Keep the authoritative spec's absolute path in the implementation worktree. Pass the patch diff as before; the snapshot contains this task's changed and added files, with deleted files absent. Read deleted files from `WAVE_BASE_SHA` when the review needs their prior contents. Dispatch read-only, with no `worktree` flag. On snapshot setup or tree-capture failure, or a missing snapshot path, stop dispatch and retain the failed snapshot directory and shell output for diagnosis; dispatch no review and perform no snapshot cleanup. Save each snapshot-backed review's terminal report to its `output:` path, read it, then remove that review's snapshot with `git -C <implementation-worktree> worktree remove --force <snapshot-path>`. Keep every snapshot used as a reviewer `cwd` until that terminal report is saved; recording its tree never authorizes early cleanup. Remove a reconstruction used only to record tree-before after capturing its tree, since no reviewer runs there. Recreate from the replacement patch for each pre-integration re-review. Post-integration SR reviews the implementation worktree directly.
|
|
296
294
|
|
|
297
295
|
## When a Subagent Fails
|
|
298
296
|
|
|
@@ -300,7 +298,7 @@ Use the printed snapshot path as that spec-review task's `cwd` and whole-file re
|
|
|
300
298
|
|
|
301
299
|
1. **Attempt 1:** dispatch a NEW fix subagent with the error output, the original task, and specific instructions about what went wrong.
|
|
302
300
|
2. **Attempt 2:** if attempt 1 also fails, dispatch one more with a simplified scope or different approach.
|
|
303
|
-
3. **After 2 failed attempts:** STOP. Report failure to the user.
|
|
301
|
+
3. **After 2 failed attempts:** STOP. Report failure to the user. Keep the task `in_progress`, not `failed` or `complete`, pending the human's decision; completion requires the wave commit.
|
|
304
302
|
|
|
305
303
|
**NEVER:**
|
|
306
304
|
|
|
@@ -10,11 +10,11 @@ Use this template when dispatching a code quality reviewer subagent.
|
|
|
10
10
|
Dispatch a subagent with the code-reviewer template:
|
|
11
11
|
Use the template at ../requesting-code-review/code-reviewer.md
|
|
12
12
|
|
|
13
|
-
DESCRIPTION: [
|
|
14
|
-
PLAN_OR_REQUIREMENTS:
|
|
15
|
-
BASE_SHA: [
|
|
16
|
-
HEAD_SHA: [
|
|
17
|
-
SCOPED_TEST_COMMANDS: [the
|
|
13
|
+
DESCRIPTION: [wave summary, from implementers' reports; whole-diff review: implementation summary]
|
|
14
|
+
PLAN_OR_REQUIREMENTS: [wave tasks from plan-file; whole-diff review: full plan/requirements]
|
|
15
|
+
BASE_SHA: [WAVE_BASE_SHA recorded before worker dispatch; whole-diff review: committed implementation base]
|
|
16
|
+
HEAD_SHA: [the literal WORKTREE for the integrated wave, including re-reviews; whole-diff review: committed HEAD]
|
|
17
|
+
SCOPED_TEST_COMMANDS: [the union of the wave's tasks' Tests: commands; `none` for the whole-diff verify-phase review]
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
**In addition to standard code quality concerns, the reviewer should check:**
|
|
@@ -38,13 +38,13 @@ Dispatch a subagent with this prompt:
|
|
|
38
38
|
|
|
39
39
|
Work from: [directory]
|
|
40
40
|
|
|
41
|
-
SCOPED_TEST_COMMANDS: [the task's Tests: bullets, backticks stripped, verbatim | none]
|
|
41
|
+
SCOPED_TEST_COMMANDS: [only the task's Tests: command bullets, backticks stripped, verbatim; exclude via:, baseline:, and none: metadata | none]
|
|
42
42
|
|
|
43
43
|
Run ONLY these commands for verification. Never run a repo-wide suite,
|
|
44
44
|
linter, or type-checker. If the value is `none`, run nothing and say so
|
|
45
45
|
in your report.
|
|
46
46
|
|
|
47
|
-
TEST_CONTRACT: [the task's **Tests:** block verbatim (commands, via:, none:) and its Files: Create:/Test: paths]
|
|
47
|
+
TEST_CONTRACT: [the task's **Tests:** block verbatim (commands, via:, baseline: bullets verbatim, none:) and its Files: Create:/Test: paths]
|
|
48
48
|
|
|
49
49
|
Tests call the via: seam directly - not a wrapper, not the internals behind it.
|
|
50
50
|
Create every Create: path at exactly that path.
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Stop note (subagent-driven-development companion)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
For a `NEEDS_CONTEXT`/`BLOCKED` fact ask, search the locations documented by the spec, plan, or repo: one bounded lookup per location in documented order, stopping at the first hit. Record each lookup and result, including earlier misses; re-dispatch with the found result in the task text.
|
|
4
|
+
|
|
5
|
+
Emit when no escalation model resolves, the escalated dispatch errors, its one escalated round fails (see `SKILL.md` "Fix-Loop Rounds"), or a `NEEDS_CONTEXT`/`BLOCKED` fact ask exhausts documented locations, needs credentials for a remaining location, or lacks its named lookup tool; an unavailable `gauntlet_setting` tool is a configuration error - stop and report, no stop note. Inline in the reply; the turn ends; phase stays `implement`, the task stays `in_progress`; no further tasks start. Emit one note per stalled task, after the current batch returns.
|
|
4
6
|
|
|
5
7
|
## Template
|
|
6
8
|
|
|
7
9
|
```
|
|
8
10
|
Stopped on task <n> (<title>)[; escalated round on <implModel> did not resolve it].
|
|
9
11
|
|
|
10
|
-
Problem: <one sentence: what is wrong and why
|
|
12
|
+
Problem: <one sentence: what is wrong and why it remains unresolved>
|
|
13
|
+
Searched: <where> - <result> [fact asks only; repeat in lookup order]
|
|
11
14
|
<file:line> - <quoted finding from the final review>
|
|
12
15
|
<failing test/command + 1-3 line output snippet, when present>
|
|
13
16
|
|
|
@@ -22,8 +25,10 @@ Pick one, or give another fix.
|
|
|
22
25
|
## Rules
|
|
23
26
|
|
|
24
27
|
- Bracketed header clause only when an escalated round actually ran; omit it when no model was resolvable or the dispatch errored.
|
|
25
|
-
-
|
|
26
|
-
-
|
|
28
|
+
- For review stalls, quote only residual issues from the final review report; do not summarize history.
|
|
29
|
+
- For fact asks, put one `Searched: <where> - <result>` line per lookup directly under `Problem:`, in lookup order. For an unavailable named tool, write `Searched: <tool> - not available`. Omit `Searched:` for decisions, including extra-round approval.
|
|
30
|
+
- For fact asks, offer supplying the artifact or access, or amending the spec or plan task to drop the requirement. Never ask the human where the artifact is.
|
|
31
|
+
- When no escalated round ran, state the reason in `Problem:`: exhausted or inaccessible fact lookups, "no escalation model resolvable", or the quoted implementer's non-DONE status text / dispatch error; skip the file:line and test lines.
|
|
27
32
|
- Options are actionable edits. Spec/plan amendment is first-class - stalls are usually a slightly contradictory spec, not a capability gap.
|
|
28
33
|
- Never offer "skip the task". If the task is genuinely droppable, say so and name the plan tasks that depend on it.
|
|
29
34
|
- No trajectory verdicts, round history, review counts, or paths to spec/plan/review reports.
|