pi-gauntlet 7.43.1 → 8.0.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +2 -2
  3. package/agents/plan-writer.md +3 -3
  4. package/agents/wave-reviewer.md +111 -0
  5. package/extensions/lib/phase-tracker-helpers.test.ts +7 -8
  6. package/extensions/lib/phase-tracker-helpers.ts +2 -5
  7. package/extensions/lib/plan-check.test.ts +45 -0
  8. package/extensions/lib/plan-check.ts +19 -7
  9. package/extensions/lib/telemetry-collect.test.ts +21 -1
  10. package/extensions/lib/telemetry-collect.ts +23 -1
  11. package/extensions/phase-tracker.test.ts +80 -73
  12. package/extensions/phase-tracker.ts +10 -13
  13. package/extensions/telemetry.test.ts +11 -5
  14. package/extensions/telemetry.ts +2 -2
  15. package/package.json +1 -1
  16. package/skills/brainstorming/reference/amendment-surface.md +9 -1
  17. package/skills/chase-bug/hotfix.md +1 -1
  18. package/skills/dispatching-parallel-agents/SKILL.md +2 -2
  19. package/skills/finishing-a-development-branch/reference/disposition-protocol.md +1 -1
  20. package/skills/gatekeep-pr/SKILL.md +1 -1
  21. package/skills/gatekeep-pr/reference/assessment.md +1 -1
  22. package/skills/gatekeep-pr/reference/sync.md +1 -1
  23. package/skills/loop-implementation/SKILL.md +8 -87
  24. package/skills/loop-implementation/reference/coordinated-legs.md +104 -0
  25. package/skills/requesting-code-review/SKILL.md +9 -9
  26. package/skills/requesting-code-review/{code-reviewer.md → wave-reviewer.md} +2 -2
  27. package/skills/subagent-driven-development/SKILL.md +124 -121
  28. package/skills/subagent-driven-development/reference/dispatch-contract.md +10 -9
  29. package/skills/subagent-driven-development/reference/implement-amendments.md +3 -1
  30. package/skills/subagent-driven-development/stop-note.md +4 -4
  31. package/skills/subagent-driven-development/wave-reviewer-prompt.md +55 -0
  32. package/skills/verification-before-completion/reference/conformance-check.md +2 -2
  33. package/skills/writing-plans/SKILL.md +7 -1
  34. package/skills/writing-plans/reference/plan-contract.md +6 -0
  35. package/agents/code-reviewer.md +0 -115
  36. package/agents/spec-reviewer.md +0 -121
  37. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +0 -67
  38. package/skills/subagent-driven-development/reference/fix-loop.md +0 -45
  39. package/skills/subagent-driven-development/spec-reviewer-prompt.md +0 -125
@@ -39,7 +39,7 @@ Mint and initialize the continuation record before progress initialization (`ref
39
39
 
40
40
  ## Harness notes
41
41
 
42
- Every helper is a fresh context with `cwd` the PR worktree; its task names its output path and ends with the output contract. Every dispatch on either harness gets its own output path from `mktemp "${TMPDIR:-/tmp}/gatekeep-<role>.XXXXXX"` outside the worktree. On pi: `subagent({ agent: <persona>, context: "fresh", async: false, cwd: <worktree> })` with `worker` for Verify, `code-reviewer` for Review and the pre-push review, `implementer` for payloads; `gauntlet_setting({ key: "closureReview" })` supplies the fix-round cap. On Claude Code: the harness's subagent dispatch tool with the duty text as the prompt - Verify: `verification-brief.md` Section B; Review, pre-push review, and comment-delta review: Section C plus `review-baseline.md` (the pre-push review adds the closure-line contract); implementer: the payload task of `reference/fix-wave.md` `## Wave`; sync conflict stop: the task `reference/sync.md` `## Conflict stop` builds; sync review: Section C plus `review-baseline.md` with the `## Review before push` subject, no closure lines; the no-tool accounting fallback is `2 x 5`. A Claude Code helper inherits the session's directory, so its prompt opens with the absolute worktree path and the rule that every command runs as `git -C <worktree> ...` or `(cd <worktree> && ...)`, checks that `git -C <worktree> rev-parse HEAD` equals the head its task names (the assessed head for Verify, Review, and the comment-delta reviewer; the current wave HEAD for wave helpers) before working, and names the output path; the orchestrator awaits the tool result before reading the file. For description recheck on pi, use the fresh worker duty in Section B with mode `description recheck`; on Claude Code, use Section B's separate recheck duty as the native helper prompt. Both tasks supply actual body/head, affected claim IDs, existing evidence, and the affected-only disposition/closure contract, never the CI-emitting claim-only contract. A harness with neither facility is unsupported: stop at step 3 and say so - at step 2b, before any sync write, when `--rebase` was passed (`reference/sync.md`).
42
+ Every helper is a fresh context with `cwd` the PR worktree; its task names its output path and ends with the output contract. Every dispatch on either harness gets its own output path from `mktemp "${TMPDIR:-/tmp}/gatekeep-<role>.XXXXXX"` outside the worktree. On pi: `subagent({ agent: <persona>, context: "fresh", async: false, cwd: <worktree> })` with `worker` for Verify, `wave-reviewer` for Review and the pre-push review, `implementer` for payloads; `gauntlet_setting({ key: "closureReview" })` supplies the fix-round cap. On Claude Code: the harness's subagent dispatch tool with the duty text as the prompt - Verify: `verification-brief.md` Section B; Review, pre-push review, and comment-delta review: Section C plus `review-baseline.md` (the pre-push review adds the closure-line contract); implementer: the payload task of `reference/fix-wave.md` `## Wave`; sync conflict stop: the task `reference/sync.md` `## Conflict stop` builds; sync review: Section C plus `review-baseline.md` with the `## Review before push` subject, no closure lines; the no-tool accounting fallback is `2 x 5`. A Claude Code helper inherits the session's directory, so its prompt opens with the absolute worktree path and the rule that every command runs as `git -C <worktree> ...` or `(cd <worktree> && ...)`, checks that `git -C <worktree> rev-parse HEAD` equals the head its task names (the assessed head for Verify, Review, and the comment-delta reviewer; the current wave HEAD for wave helpers) before working, and names the output path; the orchestrator awaits the tool result before reading the file. For description recheck on pi, use the fresh worker duty in Section B with mode `description recheck`; on Claude Code, use Section B's separate recheck duty as the native helper prompt. Both tasks supply actual body/head, affected claim IDs, existing evidence, and the affected-only disposition/closure contract, never the CI-emitting claim-only contract. A harness with neither facility is unsupported: stop at step 3 and say so - at step 2b, before any sync write, when `--rebase` was passed (`reference/sync.md`).
43
43
 
44
44
  ## Wording rules
45
45
 
@@ -85,6 +85,6 @@ Before step 3, mint the two output paths outside the worktree - `mktemp "${TMPDI
85
85
  | Step | Helper | Detail |
86
86
  |---|---|---|
87
87
  | 3 Verify | the `worker` persona, or `../verification-brief.md` Section B as the prompt (`../SKILL.md` `## Harness notes`) | task prefixed "report only - do not edit, fix, or commit anything"; writes the Verifier output schema to its output path; the orchestrator reads `source`, `head_sha`, `worktree_root`, each `run_cwd`, each check's `name`, `url`, `status`, and `conclusion`, each run's `command`, `result`, `exit_code`, and `log_path`, and the claim dispositions - never a log's contents |
88
- | 4 Review | the `code-reviewer` persona, or Section C plus `../review-baseline.md` as the prompt | emits its native report to its output path; the one call-time addition is the closure-line contract of `fix-wave.md` `## Review before push`, used only in the wave |
88
+ | 4 Review | the `wave-reviewer` persona, or Section C plus `../review-baseline.md` as the prompt | emits its native report to its output path; the one call-time addition is the closure-line contract of `fix-wave.md` `## Review before push`, used only in the wave |
89
89
 
90
90
  Verify and Review share the provisioned worktree via `cwd`, dispatched sequentially - never `worktree: true`, which provisions a separate tree and breaks the shared-tree contract. A helper that leaves its output file empty or not in its section's output contract (the Verifier output schema for Verify, the reviewer's native report for Review), returns a non-zero result, or returns an async handle stops the step: quote the failure and offer `stop`.
@@ -53,7 +53,7 @@ Continue by running `GIT_EDITOR=true git rebase --continue` spelled exactly so,
53
53
 
54
54
  ## Review before push
55
55
 
56
- Runs on every rewritten head, with or without a stop; only a `no-op` skips it. One fresh `code-reviewer`, `cwd` the PR worktree, read-only, dispatched per SKILL.md `## Harness notes` (Claude Code: the sync review duty), over `git range-diff origin/<base> <pre_head> HEAD` and, when stops were resolved, `git diff <pre_head> HEAD -- <resolved files>`; the task asks for the reviewer's native findings report with "rebase replay and conflict resolutions" as the review subject and no closure lines. Write out the dispatch as the harness call with `context: "fresh"`, `async: false`, and the worktree `cwd` (pi: `subagent({ agent: "code-reviewer", context: "fresh", async: false, cwd: <worktree> })`). A Critical or Moderate finding takes `## Failure path`; no second helper.
56
+ Runs on every rewritten head, with or without a stop; only a `no-op` skips it. One fresh `wave-reviewer`, `cwd` the PR worktree, read-only, dispatched per SKILL.md `## Harness notes` (Claude Code: the sync review duty), over `git range-diff origin/<base> <pre_head> HEAD` and, when stops were resolved, `git diff <pre_head> HEAD -- <resolved files>`; the task asks for the reviewer's native findings report with "rebase replay and conflict resolutions" as the review subject and no closure lines. Write out the dispatch as the harness call with `context: "fresh"`, `async: false`, and the worktree `cwd` (pi: `subagent({ agent: "wave-reviewer", context: "fresh", async: false, cwd: <worktree> })`). A Critical or Moderate finding takes `## Failure path`; no second helper.
57
57
 
58
58
  ## Push
59
59
 
@@ -18,7 +18,7 @@ Run this driver in the main session. Carry the absolute implementation worktree
18
18
  | Otherwise overrides has `## verification-before-completion` | Use its exactly one backticked command; zero or several is a configuration error. |
19
19
  | Neither section supplies a command | Discover the project's test entrypoint from its actual manifest/build instructions; print discovery as source. Stop on an unresolved or ambiguous entrypoint. |
20
20
 
21
- For more than one `### Leg:` block, apply coordinated Entry below instead of the home-only skeleton and cap calculation. Keep legacy and single-member ledger bytes unchanged, with no coordinated metadata.
21
+ On fresh entry and on every ledger restore, for a spec whose `## Legs` section has more than one `### Leg:` block, read `reference/coordinated-legs.md` IN FULL now with read; stop on an unreadable reference naming its path, never reconstruct it. On fresh entry apply its `## Entry` section instead of the home-only skeleton and cap calculation below. On a restore apply its `## Resume` section before the dirty-tree stop and before any pending recovery. Keep legacy and single-member ledger bytes unchanged, with no coordinated metadata.
22
22
 
23
23
  3. Call `phase_tracker({ action: "skip", phase: "plan", reason: "loop engine" })`.
24
24
  4. Require a clean named-branch implementation worktree. Write `<resolved plan dir>/<spec stem>-ledger.md`. Use this grammar with literal values, not placeholders:
@@ -43,20 +43,10 @@ Use the actual repo-relative spec path alone in the Spec header. Read base with
43
43
 
44
44
  For resume, use the admitted ledger, its base and verification command, and durable iterations and cap instead of overwriting it. Skip Entry step 1 for an admitted ledger; settings apply only to fresh seeding. Render rows, cap and decision history; stop on a dirty tree before dispatch.
45
45
 
46
- ## Coordinated Entry and resume
47
-
48
- Read `## Legs` with [the scope grammar](../brainstorming/reference/legs.md#scope-grammar-and-validation) before skeleton commit or dispatch. Require exactly one `scope:` per block: `scope: AC 1, AC 3` or `scope: none`. Reject missing/duplicate scope lines, duplicate indices within a list, malformed tokens and out-of-range original indices through the amendment stop. Include cut original AC indices; never infer ownership from a `design:` mention or path. Default only indices absent from every valid list to home; repeat shared indices in every owner's list.
49
-
50
- Retain the home skeleton's `**Spec:**`, `verification:`, `iterations:`, `cap:` and `## Decisions` fields and its `plan_check`/commit admission. Read each member's verification from the home spec's `## Legs` `contract:` `- verification:` line before dispatch; keep the existing home verification header.
51
-
52
- Assign numeric entries in original AC order, then membership order for shared ACs, independent of scope-list order. Leave spec rows untouched and copy each cut disposition to every expanded entry. Keep the four-column table and add `## Leg mapping` with `row | ac | leg`, one mapping per entry exactly once. Reject duplicate/missing mappings. Keep `base:` as home base; record one actual `base repo-a: <sha>` / `seeded repo-a: no` pair per member, including home. Resolve bases with each member's `git -C`, not home HEAD.
53
-
54
- Compute initial cap as non-cut entry count times `maxIterationsPerRow` plus one seed dispatch per leg with non-cut entries. One shared home/companion AC and one home-only AC produce three entries, two seeds and cap 14 at default 4; a wholly cut third leg adds no seed. All-cut cap stays 1 and exits without seed. Preserve cap after cuts, reopens, amendments, funding and recovery; only an explicit cap grant raises it.
55
-
56
- Recover pending companion work before generic dirty checks and before any new dispatch. Read the durable home ledger's `pending:` tuple and consumed iteration, selected companion HEAD and saved pre-dispatch state. Reconstruct the pre-dispatch ledger from home `HEAD:<ledger path>` on resume and admit only the expected on-disk iterations bump and tuple against it. Admit only the known iterations bump and exact pending tuple as pre-dispatch dirt; stop on other dirt. Reapply companion return validation below only when exactly one new commit after the recorded HEAD matches attribution and result. Apply the home-ledger commit without another attempt or iteration bump, clear pending and retain prior decisions. Stop preserving state on zero commits, unrelated movement, multiple commits or attribution/result mismatch. Never rerun that row or seed. After a successful parent commit no pending tuple remains, so a subsequent resume cannot duplicate the update.
57
-
58
46
  ## Before each dispatch
59
47
 
48
+ For a spec whose `## Legs` section has more than one `### Leg:` block, read `reference/coordinated-legs.md` IN FULL now with read; stop on an unreadable reference naming its path, never reconstruct it. Apply its `## Resume`, `## Targeting and dispatch`, `## Companion return validation`, `### Companion commit admission`, `## Exit verification` and `## Amendments` sections together with this driver; never apply `## Entry` here.
49
+
60
50
  Read the ledger and require its `cap:` header before the ordered table, including before rule 1. On a missing header stop with `ledger has no cap: line - seeded under the old loopEngine contract`, even for a completed ledger; use the legacy grant below, never derive cap from settings. Count empty child commits and validation misses only after the latest `loop: retry row <n>` commit. Funding alone resets neither window. Preserve every row's attempts and the total iteration cap. Apply this ordered table, starting here after each return or human decision:
61
51
 
62
52
  | Order | Observed state | Action |
@@ -77,12 +67,8 @@ For attempts 5 with fund 2, append `row 2 escalated | implModel round | allowed
77
67
 
78
68
  Select `seed` until a validated `loop: seed evidence` commit with its `row 0 done` decision and evidence on every non-cut row survives on the branch, independently of `iterations`; otherwise select the still-unresolved human retry target, then the still-failed row named by the previous decision, then first failed row, then first open row. Use the latest operational `row <n> ...` decision for targeting and the child's `previous decision:` input, skipping cap grant history while retaining the entire Decisions section. Durable status beats a decision's suggestion. Keep the retry hint only for its target.
79
69
 
80
- For coordinated targeting, select the next unseeded leg with non-cut entries in membership order before ordinary targeting. Use the existing retry/failed/open priority only after those seeds validate. Skip wholly cut legs; never mark foreign legs seeded. Map each numeric target to its original AC and leg via `## Leg mapping`.
81
-
82
70
  ## Dispatch
83
71
 
84
- For coordinated dispatch, capture home and selected leg heads and save a pre-dispatch ledger snapshot for the expected-dirt comparison. Select the leg worktree as `cwd` and git root, its own base, mapped original AC, `Leg:` and combined spec/task `Rules:` as additive task inputs. Read spec and ledger by absolute home paths. Bump iterations exactly once. Before every companion dispatch, including seed, persist the exact tuple such as `pending: 2 | repo-b | abc1234` (or `pending: seed | repo-b | abc1234`) with actual target, repo and pre-dispatch HEAD in the home ledger. Keep that expected bump/tuple durable on disk before generic dirty checks; admit no other dirt. After persisting the bump and pending tuple, bind `SAVED_LEDGER` to the durable home ledger for companion admission, not the pre-dispatch snapshot. Pass consumed `iteration:` and the exact `pending:` as attribution. Leave home iterations on the existing single child commit path, validating only home entries and home seeded state.
85
-
86
72
  For home-only dispatch, record `HEAD_BEFORE`, copy the ledger text, and take i from the current iterations count. Increment `iterations:` before dispatch in the working tree so the child's commit persists it. Create a unique absolute output path with `mktemp` outside the repository. Dispatch exactly one foreground child in the main implementation worktree, not a nested worktree:
87
73
 
88
74
  ```text
@@ -99,11 +85,7 @@ Omit the model override except on an escalated round (`model: <implModel>`); let
99
85
 
100
86
  ## Validate the return
101
87
 
102
- For a companion, validate from its commit, not the reply. Require a clean companion and exactly one commit after pending HEAD; require unchanged home HEAD and no home edits except the expected persisted bump/tuple. Match subject `loop: row <n> <status>` or `loop: seed evidence`, exact pending tuple and consumed `iteration:` in the body. Parse only the resulting four-column target row (all and only that leg's non-cut rows for seed), followed by one bounded decision. Apply the evidence and decision bounds below. Reject a wrong target, foreign entry, header changes, fabricated counts, malformed evidence or extra results. Validate seed counts against actual rows and baseline closures; preserve attempts and set only this leg's seeded value to `yes` after every non-cut entry validates. Keep seed misses a human stop. Apply ordinary repair only to the target, retaining consumed iterations and saved cap.
103
-
104
- After validation update only that leg's target or seed entries, append the validated decision, record companion SHA in evidence, and remove `pending:` in one home-ledger commit. Preserve every other row, header and prior decision. That home-ledger commit (`loop: record <repo> row <n>`) is a parent commit, not a child `loop: row ...` commit: it never counts toward child-only empty-commit stagnation, and a rejected companion return records the rejection in the same parent commit while preserving the pending tuple and every row. Recover interrupted returns by this same validation, never trusted reply text.
105
-
106
- For home-only returns, apply the following boundary and table. For coordinated home returns apply it only to home entries/seeded state, preserving foreign entries, mappings and bases.
88
+ For home-only returns, apply the following boundary and table.
107
89
 
108
90
  1. Require empty `git -C "<worktree>" status --porcelain` and exactly 1 from `git -C "<worktree>" rev-list HEAD_BEFORE..HEAD --count`. On dirty/zero/multiple commits stop, preserving changes and commits. Use `Stopped: iteration <i> left the tree dirty` or `Stopped: iteration <i> added <k> commits`. Read the ledger from HEAD only after this boundary passes.
109
91
  2. Validate by dispatched `target`, not iteration number, against the saved copy using this table. Preserve headers including cap and the bumped iterations, row identifiers and prior decisions.
@@ -117,72 +99,13 @@ Require ordinary decision grammar `^row <target> (done|failed) \| .{1,200} \| .{
117
99
 
118
100
  On an ordinary miss restore every non-target row, headers (including the saved cap) and prior decisions from the saved copy, retaining the incremented iterations. Set the target `failed`, attempts = saved attempts +1, evidence = `iteration <i>: <concrete miss>`. Remove malformed appended decisions and commit `loop: repair row <n>`. Set previous decision to `none`; otherwise use the new conforming line. Two consecutive validation misses stop because the child is not following the contract. A conforming return resets the consecutive-miss count; parent repair commits do not count toward child-only empty stagnation.
119
101
 
120
- ### Companion commit admission
121
-
122
- Require the unchanged home HEAD and expected-only home dirt boundary above, then run this read-only admission recipe on both immediate returns and pending recovery. Set `CHECKOUT` to the companion root, `PENDING` to the exact persisted tuple including `pending:`, `ITERATION` to the consumed count and `SAVED_LEDGER` to the durable home ledger after the iterations bump and pending write, including on recovery. Use the pre-dispatch snapshot only for the expected-dirt comparison. On failure preserve pending and stop. On success use the emitted object for the single parent ledger commit described above; never treat it as permission for another dispatch.
123
-
124
- <!-- companion-return-shell -->
125
- ```bash
126
- node - "$CHECKOUT" "$PENDING" "$ITERATION" "$SAVED_LEDGER" <<'NODE'
127
- const fs = require('node:fs');
128
- const { execFileSync } = require('node:child_process');
129
- const [root, pending, iteration, savedPath] = process.argv.slice(2);
130
- const requireThat = (ok, why) => { if (!ok) throw new Error(why); };
131
- const git = (...args) => execFileSync('git', ['-C', root, ...args], { encoding: 'utf8' }).trim();
132
- const tuple = /^pending: (seed|\d+) \| (\S+) \| ([a-f0-9]{7,40})$/.exec(pending);
133
- requireThat(tuple, 'invalid pending');
134
- const saved = fs.readFileSync(savedPath, 'utf8');
135
- requireThat(saved.split('\n').filter(line => line.startsWith('pending:')).length === 1 && saved.split('\n').includes(pending) && saved.split('\n').includes(`iterations: ${iteration}`), 'pending already applied or iteration mismatch');
136
- const [, target, leg, before] = tuple;
137
- requireThat(git('status', '--porcelain') === '', 'dirty companion');
138
- requireThat(git('merge-base', '--is-ancestor', before, 'HEAD') === '', 'unrelated HEAD');
139
- requireThat(git('rev-list', '--count', `${before}..HEAD`) === '1', 'expected one companion commit');
140
- const commit = git('rev-parse', 'HEAD');
141
- const message = git('show', '-s', '--format=%B', 'HEAD').split('\n');
142
- const subject = message.shift();
143
- requireThat(message.shift() === '', 'missing body separator');
144
- requireThat(message.shift() === pending, 'pending mismatch');
145
- requireThat(message.shift() === `iteration: ${iteration}`, 'iteration mismatch');
146
- const resultLines = message.filter(line => line.trim() !== '');
147
- const cells = line => line.split(/(?<!\\)\|/).slice(1, -1).map(s => s.trim());
148
- const table = text => text.split('\n').filter(line => /^\|\s*\d+\s*\|/.test(line)).map(cells);
149
- const [ledger, mapping] = saved.split('## Leg mapping\n');
150
- requireThat(mapping, 'missing mapping');
151
- const map = table(mapping.split('## Decisions')[0]);
152
- const oldRows = table(ledger);
153
- requireThat(new Set(map.map(r => r[0])).size === map.length && map.length === oldRows.length && oldRows.every(r => map.some(m => m[0] === r[0])), 'invalid mapping');
154
- const expected = oldRows.filter(r => map.some(m => m[0] === r[0] && m[2] === leg) && (target === 'seed' ? r[1] !== 'cut' : r[0] === target));
155
- requireThat(expected.length && expected.every(r => r[1] !== 'cut'), 'foreign or cut target');
156
- const decision = resultLines.pop();
157
- const rows = resultLines.map(cells);
158
- requireThat(rows.length === expected.length && resultLines.every(l => l.startsWith('|') && l.endsWith('|')), 'extra result');
159
- for (const [i, row] of rows.entries()) {
160
- const old = expected[i];
161
- requireThat(row.length === 4 && row[0] === old[0], 'foreign row');
162
- requireThat((target === 'seed' ? /^(open|done)$/ : /^(done|failed)$/).test(row[1]), 'invalid status');
163
- requireThat(/^\d+$/.test(row[2]) && Number(row[2]) === Number(old[2]) + (target === 'seed' ? 0 : 1), 'attempt mismatch');
164
- requireThat(row[3].length > 0 && row[3].split(';').length <= 4 && !/[<>]/.test(row[3]), 'unbounded evidence');
165
- requireThat(target !== 'seed' || old[1] !== 'done' || row[1] === 'done', 'lost baseline closure');
166
- }
167
- if (target === 'seed') {
168
- requireThat(subject === 'loop: seed evidence', 'seed subject mismatch');
169
- const d = /^row 0 done \| seeded (\d+) rows, closed (\d+) on baseline \| .{1,200}$/.exec(decision);
170
- requireThat(d && Number(d[1]) === expected.length && Number(d[2]) === rows.filter(r => r[1] === 'done').length, 'seed counts mismatch');
171
- } else {
172
- requireThat(subject === `loop: row ${target} ${rows[0][1]}`, 'row subject mismatch');
173
- requireThat(new RegExp(`^row ${target} ${rows[0][1]} \\| .{1,200} \\| .{1,200}$`).test(decision), 'invalid decision');
174
- }
175
- console.log(JSON.stringify({ sha: commit, rows: resultLines, decision }));
176
- NODE
177
- ```
178
-
179
102
  ## Exit verification
180
103
 
181
- For coordinated exit, read each leg's verification from the home spec's `## Legs` `contract:` `- verification:` line and run it once foreground in its owning checkout. Require every leg to pass before completing implement. For legacy/single-member exit, run the ledger's `verification:` command once foreground in the worktree. Failure uses `Stopped: verification failed with every row closed`, Problem quoting failing output.
104
+ For legacy/single-member exit, run the ledger's `verification:` command once foreground in the worktree. Failure uses `Stopped: verification failed with every row closed`, Problem quoting failing output.
182
105
 
183
- Apply hard boundaries first; at cap use the cap stop without repair. With amend permission, `iterations < cap`, resolved `escalationLoop.implModel` and no spent `loop: repair verification` identity, bump home iterations once and record `HEAD_BEFORE` in the failing leg. Dispatch exactly one `implementer` with `model: <implModel>`, `context: "fresh"`, `async: false`, that leg's cwd/Rules, failing output, absolute home spec path and exact leg verification command. Require a clean tree and exactly one commit after HEAD_BEFORE; dirty/zero/multiple commits use existing boundary stops preserving count and state. Require all ledger rows unchanged, preserving mapping, cap and prior decisions. The home child's sole commit includes the already-bumped home ledger; after validation parent commits `loop: repair verification`, using an empty parent marker when no dirt remains. A companion child commits its leg only; parent commits the bumped home ledger as `loop: repair verification`, preserving rows and mapping. This marker is once per flow, not per failing leg.
106
+ Apply hard boundaries first; at cap use the cap stop without repair. With amend permission, `iterations < cap`, resolved `escalationLoop.implModel` and no spent `loop: repair verification` identity, bump iterations once and record `HEAD_BEFORE`. Dispatch exactly one `implementer` with `model: <implModel>`, `context: "fresh"`, `async: false`, the implementation worktree as cwd and its Rules, failing output, absolute spec path and the exact verification command. Require a clean tree and exactly one commit after HEAD_BEFORE; dirty/zero/multiple commits use existing boundary stops preserving count and state. Require all ledger rows unchanged, preserving cap and prior decisions. The child's sole commit includes the already-bumped ledger; after validation parent commits `loop: repair verification`, using an empty parent marker when no dirt remains. This marker is once per flow.
184
107
 
185
- Rerun that command once in the failing leg only. Never spend another leg's verification or verify-phase credits. A second failure retains the original header plus `escalated round spent`, then goes through Human stop. Dispatch error or non-DONE consumes the round before a decision; preserve the consumed count and stop. Recover spent identity from the parent commit on resume; interrupted or unrecoverable identity is spent, never add a carrier or fabricate success. With no permission or spent identity: no reopening and no automatic rerun. Missing settings/model stops with the capability in Problem. Success only after every leg passes: record verified HEAD and clean status; call `phase_tracker({ action: "complete", phase: "implement" })`, then continue immediately below.
108
+ Rerun that command once. Never spend verify-phase credits. A second failure retains the original header plus `escalated round spent`, then goes through Human stop. Dispatch error or non-DONE consumes the round before a decision; preserve the consumed count and stop. Recover spent identity from the parent commit on resume; interrupted or unrecoverable identity is spent, never add a carrier or fabricate success. With no permission or spent identity: no reopening and no automatic rerun. Missing settings/model stops with the capability in Problem. On success record verified HEAD and clean status; call `phase_tracker({ action: "complete", phase: "implement" })`, then continue immediately below.
186
109
 
187
110
  ## Human stop
188
111
 
@@ -203,8 +126,6 @@ Serialize the bare decision as `cap +50 |` with an empty words cell. A cap grant
203
126
 
204
127
  For dirty/commit-boundary retry, ask the human to authorize discarding uncommitted changes/resetting to last valid commit. Preserve consumed dispatch count: set iterations to restored HEAD's value +1 before the next normal bump. An interrupted dispatch consumes the same count; recover it from disk/branch rather than silently repeating iteration 0.
205
128
 
206
- For coordinated amendments, reconcile by original AC/leg mapping without resetting attempts, iterations or cap. Re-read explicit scope lists after approved ownership amendments and reconcile expanded entries; a disposition-only cut changes neither original indices nor ownership. Preserve unchanged mapped entries and their histories.
207
-
208
129
  For ledger amendments use its line-1 discriminant: no plan writer, plan_check or task-tracker lifecycle. Approved deviates/deferred/elsewhere becomes `cut` with disposition evidence; requirement-preserving amendments leave rows unchanged; a re-bounded done row becomes `open` with `reopened by amendment`. Preserve attempts, iterations and cap. Commit spec + ledger as `loop: cut row <n>` or `loop: amend`. Option 4 stops for amendments, option 5 auto-applies amends, redraw always stops and deletes the ledger with the plan. Cut only through the amendment surface, including its standing-grant section 5.
209
130
 
210
131
  End every stop with `Recommendation: <option> - <why>` or `Recommendation: none - <why>`. An unnamed repair is none. Under amend permission take only a named authorized amend: print `took recommendation: amend for row <n>`, apply amendment-surface section 5 (including its audit), commit `loop: amend` / `loop: cut row <n>`, then return to the ordered table. Whitespace-normalize the row evidence cell and compare with evidence already auto-resolved on that row; repetition renders `Recommendation: none - evidence repeats row <n>`. Recover this evidence from amendment/ledger history; missing history never authorizes a repeated action. A cut leaves the stop; an unresolved row at allowance stops again, not a free retry. Retry, more attempts, cap +N and redraw wait for the human. Fix-first enters `/skill:shape-ticket`'s own gate, never an automatic separate repair. Hard boundaries never auto-take recommendations.
@@ -217,7 +138,7 @@ For coordinated runs, route each verification and review below to every leg with
217
138
 
218
139
  0. Call `phase_tracker({ action: "start", phase: "verify" })`.
219
140
  1. Parent full verification uses the ledger command. Reuse the passing exit run only when HEAD and clean/no-change worktree still match. Commit verification-produced tracked changes. Any repair invalidates that run: rerun the full command successfully before the next gate. No task reopen/update is awaited.
220
- 2. Dispatch foreground whole-diff `code-reviewer` per `/skill:requesting-code-review`, from ledger base through committed HEAD, with `SCOPED_TEST_COMMANDS: none`. Apply its fix rounds. Rerun full verification after every repair before re-review/next gate. Carry final SHIP Minor lines verbatim as `whole-diff minors:`, or `whole-diff minors: none`.
141
+ 2. Dispatch foreground whole-diff `wave-reviewer` per `/skill:requesting-code-review`, from ledger base through committed HEAD, with `SCOPED_TEST_COMMANDS: none`. Apply its fix rounds. Rerun full verification after every repair before re-review/next gate. Carry final SHIP Minor lines verbatim as `whole-diff minors:`, or `whole-diff minors: none`.
221
142
  3. Run happy path per the fully read reference when overrides has `## Happy path` or the diff selects a row; use the diff-derived row, not a plan header. Pass summary and outcome to the separate fresh `conformance-reviewer`, along with spec path, verbatim original prompt and full diff. Use spec AC rows against the ledger as the checklist. Follow the reference's partition, concern decomposition, fix rounds and Convergence with the ledger command replacing plan Verification. Keep durable Gn identities in reports, without plan_tracker initialization or lifecycle updates. Rerun full verification after repairs. Resolve closureReview settings and reviewer dispatch per the reference. Reviews happen only after complete implement; none inside the iteration loop.
222
143
  4. Complete verify only on current CONFORMS or valid carried-open deferred inventory per the reference. A started positive-cap fix loop blocking/failing/exhausting with an open fix gap stops, never completes verify. Summarize rows closed, iterations consumed, files changed, test counts and review verdict. Emit exact `## Closure / conformance` schema from the reference: `status: CONFORMS (0 open)` or `status: GAPS (N open)`, then `audited-base: <full HEAD SHA>`, happy-path exactly when run, Deferred/deviates per spec exactly when applicable, all gap/concern fields unchanged, auto-applied fix commits index and whole-diff minors. Read its whole-diff-minors companion when directed. Never rename fields.
223
144
  5. Immediately invoke `/skill:finishing-a-development-branch <abs worktree path>`. Its menu is the human gate; do not add a ready-to-finish prompt.
@@ -0,0 +1,104 @@
1
+ Read this reference with the loop driver for a spec whose `## Legs` section has more than one `### Leg:` block.
2
+
3
+ ## Entry
4
+
5
+ Read `## Legs` with [the scope grammar](../../brainstorming/reference/legs.md#scope-grammar-and-validation) before skeleton commit or dispatch. Require exactly one `scope:` per block: `scope: AC 1, AC 3` or `scope: none`. Reject missing/duplicate scope lines, duplicate indices within a list, malformed tokens and out-of-range original indices through the amendment stop. Include cut original AC indices; never infer ownership from a `design:` mention or path. Default only indices absent from every valid list to home; repeat shared indices in every owner's list.
6
+
7
+ Retain the home skeleton's `**Spec:**`, `verification:`, `iterations:`, `cap:` and `## Decisions` fields and its `plan_check`/commit admission. Read each member's verification from the home spec's `## Legs` `contract:` `- verification:` line before dispatch; keep the existing home verification header.
8
+
9
+ Assign numeric entries in original AC order, then membership order for shared ACs, independent of scope-list order. Leave spec rows untouched and copy each cut disposition to every expanded entry. Keep the four-column table and add `## Leg mapping` with `row | ac | leg`, one mapping per entry exactly once. Reject duplicate/missing mappings. Keep `base:` as home base; record one actual `base repo-a: <sha>` / `seeded repo-a: no` pair per member, including home. Resolve bases with each member's `git -C`, not home HEAD.
10
+
11
+ Compute initial cap as non-cut entry count times `maxIterationsPerRow` plus one seed dispatch per leg with non-cut entries. One shared home/companion AC and one home-only AC produce three entries, two seeds and cap 14 at default 4; a wholly cut third leg adds no seed. All-cut cap stays 1 and exits without seed. Preserve cap after cuts, reopens, amendments, funding and recovery; only an explicit cap grant raises it.
12
+
13
+ ## Resume
14
+
15
+ Recover pending companion work before generic dirty checks and before any new dispatch. Read the durable home ledger's `pending:` tuple and consumed iteration, selected companion HEAD and saved pre-dispatch state. Reconstruct the pre-dispatch ledger from home `HEAD:<ledger path>` on resume and admit only the expected on-disk iterations bump and tuple against it. Admit only the known iterations bump and exact pending tuple as pre-dispatch dirt; stop on other dirt. Reapply companion return validation below only when exactly one new commit after the recorded HEAD matches attribution and result. Apply the home-ledger commit without another attempt or iteration bump, clear pending and retain prior decisions. Stop preserving state on zero commits, unrelated movement, multiple commits or attribution/result mismatch. Never rerun that row or seed. After a successful parent commit no pending tuple remains, so a subsequent resume cannot duplicate the update.
16
+
17
+ ## Targeting and dispatch
18
+
19
+ For coordinated targeting, select the next unseeded leg with non-cut entries in membership order before ordinary targeting. Use the existing retry/failed/open priority only after those seeds validate. Skip wholly cut legs; never mark foreign legs seeded. Map each numeric target to its original AC and leg via `## Leg mapping`.
20
+
21
+ For coordinated dispatch, capture home and selected leg heads and save a pre-dispatch ledger snapshot for the expected-dirt comparison. Select the leg worktree as `cwd` and git root, its own base, mapped original AC, `Leg:` and combined spec/task `Rules:` as additive task inputs. Read spec and ledger by absolute home paths. Bump iterations exactly once. Before every companion dispatch, including seed, persist the exact tuple such as `pending: 2 | repo-b | abc1234` (or `pending: seed | repo-b | abc1234`) with actual target, repo and pre-dispatch HEAD in the home ledger. Keep that expected bump/tuple durable on disk before generic dirty checks; admit no other dirt. After persisting the bump and pending tuple, bind `SAVED_LEDGER` to the durable home ledger for companion admission, not the pre-dispatch snapshot. Pass consumed `iteration:` and the exact `pending:` as attribution. Leave home iterations on the existing single child commit path, validating only home entries and home seeded state.
22
+
23
+ ## Companion return validation
24
+
25
+ For a companion, validate from its commit, not the reply. Require a clean companion and exactly one commit after pending HEAD; require unchanged home HEAD and no home edits except the expected persisted bump/tuple. Match subject `loop: row <n> <status>` or `loop: seed evidence`, exact pending tuple and consumed `iteration:` in the body. Parse only the resulting four-column target row (all and only that leg's non-cut rows for seed), followed by one bounded decision. Apply the evidence and decision bounds in the driver's `## Validate the return` table. Reject a wrong target, foreign entry, header changes, fabricated counts, malformed evidence or extra results. Validate seed counts against actual rows and baseline closures; preserve attempts and set only this leg's seeded value to `yes` after every non-cut entry validates. Keep seed misses a human stop. Apply ordinary repair only to the target, retaining consumed iterations and saved cap.
26
+
27
+ After validation update only that leg's target or seed entries, append the validated decision, record companion SHA in evidence, and remove `pending:` in one home-ledger commit. Preserve every other row, header and prior decision. That home-ledger commit (`loop: record <repo> row <n>`) is a parent commit, not a child `loop: row ...` commit: it never counts toward child-only empty-commit stagnation, and a rejected companion return records the rejection in the same parent commit while preserving the pending tuple and every row. Recover interrupted returns by this same validation, never trusted reply text.
28
+
29
+ For coordinated home returns apply it only to home entries/seeded state, preserving foreign entries, mappings and bases.
30
+
31
+ ### Companion commit admission
32
+
33
+ Require the unchanged home HEAD and expected-only home dirt boundary above, then run this read-only admission recipe on both immediate returns and pending recovery. Set `CHECKOUT` to the companion root, `PENDING` to the exact persisted tuple including `pending:`, `ITERATION` to the consumed count and `SAVED_LEDGER` to the durable home ledger after the iterations bump and pending write, including on recovery. Use the pre-dispatch snapshot only for the expected-dirt comparison. On failure preserve pending and stop. On success use the emitted object for the single parent ledger commit described above; never treat it as permission for another dispatch.
34
+
35
+ <!-- companion-return-shell -->
36
+ ```bash
37
+ node - "$CHECKOUT" "$PENDING" "$ITERATION" "$SAVED_LEDGER" <<'NODE'
38
+ const fs = require('node:fs');
39
+ const { execFileSync } = require('node:child_process');
40
+ const [root, pending, iteration, savedPath] = process.argv.slice(2);
41
+ const requireThat = (ok, why) => { if (!ok) throw new Error(why); };
42
+ const git = (...args) => execFileSync('git', ['-C', root, ...args], { encoding: 'utf8' }).trim();
43
+ const tuple = /^pending: (seed|\d+) \| (\S+) \| ([a-f0-9]{7,40})$/.exec(pending);
44
+ requireThat(tuple, 'invalid pending');
45
+ const saved = fs.readFileSync(savedPath, 'utf8');
46
+ requireThat(saved.split('\n').filter(line => line.startsWith('pending:')).length === 1 && saved.split('\n').includes(pending) && saved.split('\n').includes(`iterations: ${iteration}`), 'pending already applied or iteration mismatch');
47
+ const [, target, leg, before] = tuple;
48
+ requireThat(git('status', '--porcelain') === '', 'dirty companion');
49
+ requireThat(git('merge-base', '--is-ancestor', before, 'HEAD') === '', 'unrelated HEAD');
50
+ requireThat(git('rev-list', '--count', `${before}..HEAD`) === '1', 'expected one companion commit');
51
+ const commit = git('rev-parse', 'HEAD');
52
+ const message = git('show', '-s', '--format=%B', 'HEAD').split('\n');
53
+ const subject = message.shift();
54
+ requireThat(message.shift() === '', 'missing body separator');
55
+ requireThat(message.shift() === pending, 'pending mismatch');
56
+ requireThat(message.shift() === `iteration: ${iteration}`, 'iteration mismatch');
57
+ const resultLines = message.filter(line => line.trim() !== '');
58
+ const cells = line => line.split(/(?<!\\)\|/).slice(1, -1).map(s => s.trim());
59
+ const table = text => text.split('\n').filter(line => /^\|\s*\d+\s*\|/.test(line)).map(cells);
60
+ const [ledger, mapping] = saved.split('## Leg mapping\n');
61
+ requireThat(mapping, 'missing mapping');
62
+ const map = table(mapping.split('## Decisions')[0]);
63
+ const oldRows = table(ledger);
64
+ requireThat(new Set(map.map(r => r[0])).size === map.length && map.length === oldRows.length && oldRows.every(r => map.some(m => m[0] === r[0])), 'invalid mapping');
65
+ const expected = oldRows.filter(r => map.some(m => m[0] === r[0] && m[2] === leg) && (target === 'seed' ? r[1] !== 'cut' : r[0] === target));
66
+ requireThat(expected.length && expected.every(r => r[1] !== 'cut'), 'foreign or cut target');
67
+ const decision = resultLines.pop();
68
+ const rows = resultLines.map(cells);
69
+ requireThat(rows.length === expected.length && resultLines.every(l => l.startsWith('|') && l.endsWith('|')), 'extra result');
70
+ for (const [i, row] of rows.entries()) {
71
+ const old = expected[i];
72
+ requireThat(row.length === 4 && row[0] === old[0], 'foreign row');
73
+ requireThat((target === 'seed' ? /^(open|done)$/ : /^(done|failed)$/).test(row[1]), 'invalid status');
74
+ requireThat(/^\d+$/.test(row[2]) && Number(row[2]) === Number(old[2]) + (target === 'seed' ? 0 : 1), 'attempt mismatch');
75
+ requireThat(row[3].length > 0 && row[3].split(';').length <= 4 && !/[<>]/.test(row[3]), 'unbounded evidence');
76
+ requireThat(target !== 'seed' || old[1] !== 'done' || row[1] === 'done', 'lost baseline closure');
77
+ }
78
+ if (target === 'seed') {
79
+ requireThat(subject === 'loop: seed evidence', 'seed subject mismatch');
80
+ const d = /^row 0 done \| seeded (\d+) rows, closed (\d+) on baseline \| .{1,200}$/.exec(decision);
81
+ requireThat(d && Number(d[1]) === expected.length && Number(d[2]) === rows.filter(r => r[1] === 'done').length, 'seed counts mismatch');
82
+ } else {
83
+ requireThat(subject === `loop: row ${target} ${rows[0][1]}`, 'row subject mismatch');
84
+ requireThat(new RegExp(`^row ${target} ${rows[0][1]} \\| .{1,200} \\| .{1,200}$`).test(decision), 'invalid decision');
85
+ }
86
+ console.log(JSON.stringify({ sha: commit, rows: resultLines, decision }));
87
+ NODE
88
+ ```
89
+
90
+ ## Exit verification
91
+
92
+ For coordinated exit, read each leg's verification from the home spec's `## Legs` `contract:` `- verification:` line and run it once foreground in its owning checkout. Require every leg to pass before completing implement.
93
+
94
+ With amend permission, `iterations < cap`, resolved `escalationLoop.implModel` and no spent `loop: repair verification` identity, bump home iterations once and record `HEAD_BEFORE` in the failing leg. Dispatch exactly one `implementer` with `model: <implModel>`, `context: "fresh"`, `async: false`, that leg's cwd/Rules, failing output, absolute home spec path and exact leg verification command.
95
+
96
+ Require all ledger rows unchanged, preserving mapping, cap and prior decisions. The home child's sole commit includes the already-bumped home ledger; after validation parent commits `loop: repair verification`, using an empty parent marker when no dirt remains. A companion child commits its leg only; parent commits the bumped home ledger as `loop: repair verification`, preserving rows and mapping. This marker is once per flow, not per failing leg.
97
+
98
+ Rerun that command once in the failing leg only. Never spend another leg's verification or verify-phase credits.
99
+
100
+ Success only after every leg passes: record verified HEAD and clean status.
101
+
102
+ ## Amendments
103
+
104
+ For coordinated amendments, reconcile by original AC/leg mapping without resetting attempts, iterations or cap. Re-read explicit scope lists after approved ownership amendments and reconcile expanded entries; a disposition-only cut changes neither original indices nor ownership. Preserve unchanged mapped entries and their histories.
@@ -7,14 +7,14 @@ description: Use when completing tasks, implementing major features, or before m
7
7
 
8
8
  # Requesting Code Review
9
9
 
10
- Dispatch a subagent with the code-reviewer prompt template to catch issues before they cascade.
10
+ Dispatch a subagent with the wave-reviewer prompt template to catch issues before they cascade.
11
11
 
12
12
  **Core principle:** Review early, review often.
13
13
 
14
14
  ## When to Request Review
15
15
 
16
16
  **Mandatory:**
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
17
+ - Dispatch one integrated wave review per green wave in subagent-driven development, including doc-only waves, over the integrated wave diff
18
18
  - After completing major feature
19
19
  - Before merge to main
20
20
 
@@ -25,22 +25,22 @@ 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 the whole-diff review only, use the committed range:
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 `wave-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)
32
32
  ```
33
33
 
34
- **2. Dispatch code-reviewer subagent:**
34
+ **2. Dispatch wave-reviewer subagent:**
35
35
 
36
- Fill the template at `code-reviewer.md` in this skill directory, then dispatch a subagent with it.
36
+ Fill the template at `wave-reviewer.md` in this skill directory, then dispatch a subagent with it.
37
37
 
38
38
  **How to dispatch:**
39
39
 
40
- Use the `subagent` tool with the code-reviewer template filled in. This foreground dispatch must return a terminal result before acting on review feedback:
40
+ Use the `subagent` tool with the wave-reviewer template filled in. This foreground dispatch must return a terminal result before acting on review feedback:
41
41
 
42
42
  ```ts
43
- subagent({ agent: "code-reviewer", async: false, task: "... filled template ..." })
43
+ subagent({ agent: "wave-reviewer", async: false, task: "... filled template ..." })
44
44
  ```
45
45
 
46
46
  **Placeholders:**
@@ -60,7 +60,7 @@ 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
- - Dispatch one initial code review per code-touching wave over the integrated wave diff; doc-only waves are SR-only
63
+ - Dispatch one integrated wave review per green wave over the integrated wave diff, including doc-only waves
64
64
  - Fix and re-review before the accepted-wave commit and before moving to the next wave
65
65
 
66
66
  **Ad-Hoc Development:**
@@ -75,7 +75,7 @@ Take the recipient stance from `receiving-code-review`: verify each finding, ans
75
75
  - Proceed with unfixed Moderate issues
76
76
  - Argue with valid technical feedback
77
77
 
78
- See template at: `code-reviewer.md` in this skill directory
78
+ See template at: `wave-reviewer.md` in this skill directory
79
79
 
80
80
  ## Project overrides
81
81
 
@@ -1,4 +1,4 @@
1
- # Code Review Agent
1
+ # Wave Review Agent
2
2
 
3
3
  You are reviewing code changes for production readiness.
4
4
 
@@ -84,4 +84,4 @@ fi
84
84
  - Documentation complete?
85
85
  - No obvious bugs?
86
86
 
87
- Report in the output format `agents/code-reviewer.md` defines in your system prompt.
87
+ Report in the output format `agents/wave-reviewer.md` defines in your system prompt.