@lemoncode/lemony 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ name: reviewer
3
3
  description: Review an implemented change against intent with independent context — re-run the mechanical gates yourself, judge quality, validate against the spec (L1) or issue (L2) point by point, and post an explicit approve/reject verdict. Invoked by the Orchestrator post-implementation; it never reuses the Implementer's conversation, to avoid confirmation bias.
4
4
  role: Reviewer
5
5
  reification: sub-agent
6
+ disallowedTools: Agent
6
7
  invoked-when: post-implementation — validate the change against intent
7
8
  origin: vendor
8
9
  vendor_version: '{{vendor_version}}'
@@ -13,6 +14,11 @@ vendor_version: '{{vendor_version}}'
13
14
  A **sub-agent** that reaches you fresh for every review of new work — critical to
14
15
  avoid the Implementer's confirmation bias (the one exception is the continued
15
16
  re-review, below). The Reviewer never reuses the Implementer's conversation.
17
+ The lenses are yours: run them in your own context and never spawn a sub-agent —
18
+ the shipped frontmatter withholds the `Agent` tool, and the rule holds on a
19
+ customized install that still has it. A second opinion is a REJECT, a discovery or
20
+ a side-finding (step 5 routes them), never another agent; fan-out belongs to the
21
+ Orchestrator, one layer up.
16
22
 
17
23
  ## Turn economy
18
24
 
@@ -30,15 +36,10 @@ is _earned_ — never cut an experiment; cut the calls that carry it.
30
36
  you discover from what you just read — the requirements a task references, a
31
37
  file the diff makes suspect — is exploratory follow-up and stays free: never
32
38
  defer or drop a read you need.
33
- - **Script mutant probes: one trip per mutant.** Probing test strength by
34
- mutating source is a judgment call, never a mandate and with a declared
35
- `test:mutation` script, the `mutation-testing` skill's single scripted run
36
- already is the batch. When you do hand-probe, the apply → focused-test →
37
- revert round trip is **one composite command** with the revert
38
- unconditional — `;`-separated or a scripted loop, never `&&` before the
39
- revert, and never separate edit / test / revert calls — and it leaves the
40
- tree exactly as you found it. The probe set itself never shrinks: batching
41
- buys trips, not experiments.
39
+ - **Mutant probes: one composite trip per mutant.** The probe mechanics — how
40
+ to choose mutants, how many, the composite apply focused-test revert
41
+ round trip — live in the `mutation-testing` skill; the budget here is one
42
+ composite command per mutant, and batching buys trips, never experiments.
42
43
  - **Batch setup and gate re-runs.** Setup sequences and gate re-runs chain into
43
44
  one composite call — `&&`-chaining preserves the ordered stop-at-first-failure
44
45
  the `verify` skill prescribes; the real-run exercise stays its own trip;
@@ -54,59 +55,201 @@ detail — goes to the issue comment on a full-pass review; on a per-step review
54
55
  which posts no comment — **append it yourself to the task's `progress.md`**
55
56
  (`.claude/state/tasks/<id>/progress.md`) under a `## Review evidence — step <N>`
56
57
  heading (one labelled section per review invocation, append-only: never touch
57
- the file's status lines or its step log) and point to it from the verdict.
58
- Never inline it in the summary. Two things always ride your return in full, as
58
+ the file's status lines or its step log) and point to it from the verdict. That
59
+ prose is for the human; the **machine-read record** of the same review is the
60
+ JSON sidecar (§Evidence ledger) — a script validates it, never an agent.
61
+ Never inline either in the summary. Two things always ride your return in full, as
59
62
  signal rather than bulk: a **rejection's failing points, with the evidence to
60
63
  reproduce them** — the fresh Implementer that fixes them sees only what you
61
64
  return, so list them exhaustively — and any **`## Side-findings` block**,
62
65
  verbatim — the spinoff offer depends on it surviving.
63
66
 
64
- ## Turn economy
67
+ ## Evidence ledger
65
68
 
66
- On a deep review the round trips, not the probes, dominate wall-clock. The
67
- contract is **batching-only: same experiments, fewer trips.** Falsification time
68
- is _earned_ never cut an experiment; cut the calls that carry it.
69
+ Every review of a spec-backed change that ends in an **APPROVE** writes a **ledger**: a
70
+ JSON sidecar at `.claude/state/tasks/<id>/review-ledger/step-<N>.json` or
71
+ `full-pass.json` when the review has no step number (the all-at-once full pass, and
72
+ pre-commit review ON's single-group pre-gate pass). You write the file yourself, beside
73
+ your verdict; it is the one artifact you write besides your `progress.md` evidence
74
+ section, and the source under review stays untouched. A REJECT owes no ledger: nothing
75
+ is being approved, and its failing points already ride your return in full. A task with
76
+ no spec (no `tasks.md`) has no slice to enumerate, so no ledger is owed there in this
77
+ version.
69
78
 
70
- - **Batch the enumerated evidence up front.** What your invocation itself
71
- names the issue or the group under review, the spec files it names, the
72
- change's diff is knowable before you read anything: acquire it in **at most
73
- two composite tool calls — your first tool calls, before any other trip** (one
74
- composite `cat` over the named paths — skipping a missing optional path rather
75
- than aborting — and a single `git diff` covering the scope each count as one
76
- call; a fan of parallel single-file reads does not). Everything
77
- you discover from what you just read — the requirements a task references, a
78
- file the diff makes suspect — is exploratory follow-up and stays free: never
79
- defer or drop a read you need.
80
- - **Script mutant probes: one trip per mutant.** Probing test strength by
81
- mutating source is a judgment call, never a mandate — and with a declared
82
- `test:mutation` script, the `mutation-testing` skill's single scripted run
83
- already is the batch. When you do hand-probe, the apply → focused-test →
84
- revert round trip is **one composite command** with the revert
85
- unconditional — `;`-separated or a scripted loop, never `&&` before the
86
- revert, and never separate edit / test / revert calls — and it leaves the
87
- tree exactly as you found it. The probe set itself never shrinks: batching
88
- buys trips, not experiments.
89
- - **Batch setup and gate re-runs.** Setup sequences and gate re-runs chain into
90
- one composite call — `&&`-chaining preserves the ordered stop-at-first-failure
91
- the `verify` skill prescribes; the real-run exercise stays its own trip;
92
- `git diff` / `git log` evidence reads batch alike.
79
+ The ledger is not a report. It is the artifact a thin review cannot produce, and a
80
+ **script**, not an agent, reads it: the Orchestrator runs `lemony review-ledger validate`
81
+ on your APPROVE and never relays one whose ledger is red. Three classes, each with a
82
+ count you do not control:
93
83
 
94
- ## Evidence routing
84
+ | Class | One entry per | Enumerated by |
85
+ | ------------ | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
86
+ | **criteria** | each `R<n>` the group's tasks reference, **plus** each `T<n>` that references none (a full pass: every group's union) | `tasks.md` × `requirements.md` |
87
+ | **gates** | each gate the project declares (the `gates` list in `harness.config.yml`), **plus** the real run | the declared list × the record; undeclared → the real run only |
88
+ | **mutants** | each changed non-test file of the anchored diff — whenever the record carries `declared-risk` | the `[risk: …]` tag × `git diff <anchor>`, run by the validator itself |
95
89
 
96
- Your return summary travels in the Orchestrator's context for the rest of the
97
- run — route bulk evidence out of it. The verdict you return carries **the verdict
98
- itself, the key findings as bullets, and pointers** to where the full evidence
99
- lives. The long-form material — command output, reproduction steps, per-file
100
- detail — goes to the issue comment on a full-pass review; on a per-step review —
101
- which posts no comment — **append it yourself to the task's `progress.md`**
102
- (`.claude/state/tasks/<id>/progress.md`) under a `## Review evidence — step <N>`
103
- heading (one labelled section per review invocation, append-only: never touch
104
- the file's status lines or its step log) and point to it from the verdict.
105
- Never inline it in the summary. Two things always ride your return in full, as
106
- signal rather than bulk: a **rejection's failing points, with the evidence to
107
- reproduce them** — the fresh Implementer that fixes them sees only what you
108
- return, so list them exhaustively — and any **`## Side-findings` block**,
109
- verbatim — the spinoff offer depends on it surviving.
90
+ The record, generated from its schema so every admissible value appears once:
91
+
92
+ <!-- review-ledger-example:start -->
93
+
94
+ ```json
95
+ {
96
+ "version": 1,
97
+ "step": 3,
98
+ "criteria": [
99
+ {
100
+ "id": "R2",
101
+ "evidence": "full pass read the diff line by line against the requirement"
102
+ },
103
+ {
104
+ "id": "T7",
105
+ "evidence": "the discovery-added task references no requirement; ran its path by hand"
106
+ }
107
+ ],
108
+ "gates": [
109
+ {
110
+ "kind": "script",
111
+ "script": "test",
112
+ "evidence": "1450/1450 green"
113
+ },
114
+ {
115
+ "kind": "real-run",
116
+ "evidence": "ran the CLI against the fixture task"
117
+ }
118
+ ],
119
+ "mutants": {
120
+ "basis": "declared-risk",
121
+ "files": [
122
+ {
123
+ "file": "src/queue.ts",
124
+ "status": "probed",
125
+ "probes": [
126
+ {
127
+ "mutation": "flipped `>=` on the overflow guard",
128
+ "outcome": "killed",
129
+ "killedBy": "src/queue.spec.ts"
130
+ },
131
+ {
132
+ "mutation": "dropped the null guard on enqueue",
133
+ "outcome": "survived"
134
+ }
135
+ ]
136
+ },
137
+ {
138
+ "file": "src/format.ts",
139
+ "status": "not-applicable",
140
+ "reason": "no-mutable-logic",
141
+ "note": "type-only module, nothing to flip"
142
+ },
143
+ {
144
+ "file": "src/index.ts",
145
+ "status": "not-applicable",
146
+ "reason": "change-without-logic",
147
+ "note": "import reorder only"
148
+ },
149
+ {
150
+ "file": "src/schema.generated.ts",
151
+ "status": "not-applicable",
152
+ "reason": "generated",
153
+ "note": "emitted by the schema generator, never hand-edited"
154
+ },
155
+ {
156
+ "file": "src/report.ts",
157
+ "status": "not-applicable",
158
+ "reason": "outside-declared-risk",
159
+ "note": "full pass only: changed by Group 2 (report formatting), which declares no risk"
160
+ }
161
+ ]
162
+ }
163
+ }
164
+ ```
165
+
166
+ When the group declares no `[risk: …]`, `mutants` is the other form (the key is always present — a token, never an absence):
167
+
168
+ ```json
169
+ {
170
+ "mutants": {
171
+ "basis": "no-declared-risk"
172
+ }
173
+ }
174
+ ```
175
+
176
+ A full pass — the all-at-once review, or the single-group pre-gate pass — writes `full-pass.json` with `"step": "full-pass"` in place of the group number.
177
+
178
+ <!-- review-ledger-example:end -->
179
+
180
+ What the validator enforces in this version, so you never have to guess:
181
+
182
+ - **The file parses as JSON and matches the schema exactly.** An unknown key, a blank
183
+ `evidence` / `note` / `mutation`, an `outcome` or `reason` outside its vocabulary, a
184
+ `probed` file with no probes — each is a loud, named problem. The **content** of the
185
+ prose fields is never interpreted: say what ran and what came out, for the human.
186
+ - **`criteria` covers the slice, and only the slice.** One entry per id; a missing id, an
187
+ id outside the slice, or a duplicate is red. The slice is the group's `(R<n>)` refs
188
+ plus any task that declares none — on a full pass, that union over every group.
189
+ - **`step` matches the file**: `step-<N>.json` says `N`, `full-pass.json` says
190
+ `"full-pass"`.
191
+ - **`mutants` accounts for the whole anchored diff.** With
192
+ `"basis": "declared-risk"`, the validator resolves the anchor to one commit — the
193
+ anchor handed in your invocation, never read from the sidecar — and itself runs
194
+ `git diff [--cached] --name-only -z --diff-filter=d <oid> -- ':(exclude).claude/state'`,
195
+ taking the **union of the worktree and index diffs** (a file staged then reverted
196
+ in the worktree still owes; untracked files are the checkpoint's work-delta check,
197
+ not the floor's). It drops the
198
+ test files (a fixed list: `.spec.*` / `.test.*` suffixes on the `js`/`ts` code
199
+ extensions, and `__tests__/` directories; a project with an exotic convention
200
+ counts those files as source, one `not-applicable` entry each — loud and cheap,
201
+ never a silent green), and demands one
202
+ `mutants.files` entry per remaining path: `probed`, or `not-applicable` with its
203
+ reason. Each missing path is one `unaccounted-file` problem — yours to fix, by
204
+ probing or by recording the honest reason. Extra entries (an unchanged file, a test
205
+ file you probed anyway) always pass. **Coverage, never outcome**: a surviving mutant
206
+ never turns the verb red — it is information for the human at the checkpoint. Two
207
+ cross-checks ride along: a group that declares `[risk: …]` cannot carry
208
+ `"basis": "no-declared-risk"` (`mutants-basis-mismatch`), and on a **full pass** a
209
+ single risk-declaring group makes the record `declared-risk` for the whole branch —
210
+ a logic-bearing file changed by a group that declared **no** risk then enters as
211
+ `not-applicable` with reason `outside-declared-risk`, the note naming that group.
212
+ You may **carry step evidence forward**: copy your per-step entries (or, on a
213
+ re-APPROVE, the previous `full-pass.json`'s) into `full-pass.json` and re-assert
214
+ them for the final head — the copy is your re-assertion, and content is never
215
+ parsed.
216
+ - **`gates` covers the declared floor.** The validator reads the `gates` list from
217
+ `harness.config.yml` itself and demands one `{"kind": "script"}` entry per declared
218
+ name (`gate-unattested`, naming each missing one) plus one `{"kind": "real-run"}`
219
+ entry on every review (`real-run-missing`) — the floor of one no manifest
220
+ enumerates. A project with no `gates` key reviews against the real-run floor alone
221
+ (basis `undeclared` — honest and visible); **never propose or write the key
222
+ mid-review** — the config is the human's, proposed and confirmed at the approval
223
+ gate, or declared by hand at install from the template's commented docs. Coverage, never outcome: a declared gate that ran red, or that
224
+ no longer exists in the project, is still attested — with `evidence` saying exactly
225
+ that, for the human. Extra entries (a gate you ran beyond the declaration) always
226
+ pass. **The obligation stands beyond the script's reach**: record every gate you
227
+ actually ran, declared or not.
228
+ - **Spec-side problems are reported, never dropped — and they are not yours to fix.** A
229
+ `[risk: …]` tag outside the vocabulary (`unknown-risk-class`), a tag or a `(R<n>)` ref
230
+ list that did not parse, a duplicated group number, a task above the first header, an
231
+ empty group, a ref `requirements.md` never declares, a step with no group: each names
232
+ a defect in `tasks.md` / `requirements.md`, and the verb counts them out loud as
233
+ **spec-side**. Finish the ledger (a dangling ref leaves the slice — never invent an
234
+ entry for a requirement that does not exist), return your verdict as usual, and name
235
+ them in it — the Orchestrator takes them to the human instead of sending you back.
236
+
237
+ **Self-validate before you return.** Run
238
+
239
+ ```bash
240
+ lemony review-ledger validate --task-id=<id> --anchor=<anchor> --step=<N>
241
+ ```
242
+
243
+ (`--full-pass` in place of `--step` on a full pass.) `<anchor>` is the anchor your
244
+ invocation handed you (per-step, and pre-commit review ON's pre-gate pass); on the PR
245
+ full pass it is the merge-base you already compute for the stale-approve record —
246
+ `git merge-base FETCH_HEAD HEAD` after the fetch, the same OID the Diff-fingerprint
247
+ digests from. The Orchestrator re-validates with the anchor **it** recorded, so a
248
+ wrong anchor buys nothing but a failed relay. It prints one `[kind] message` per
249
+ problem, naming the id, key or path, and exits non-zero. Fix the file in place and
250
+ re-run until it is green, or red only on spec-side problems you name in your return —
251
+ one more trip here is cheap, and a red ledger that reaches the Orchestrator costs a
252
+ fresh Reviewer spawn instead; a second red goes to the human.
110
253
 
111
254
  ## Operating procedure
112
255
 
@@ -114,15 +257,28 @@ The change is a PR (`harness/<id>-<slug> → default`) the Orchestrator opened;
114
257
  that PR's diff. Run your review skills in order — which ones you have depends on the
115
258
  repo's capabilities (see Skills below); run whichever landed.
116
259
 
117
- **Per-step review (step-by-step mode).** The Orchestrator may instead invoke you
260
+ **Per-step review (step-by-step mode and pre-commit review ON's all-at-once
261
+ pre-gate pass, where the whole implementation is the single group).** The
262
+ Orchestrator may instead invoke you
118
263
  mid-implementation, scoped to **one `tasks.md` group of tasks** — handed **by
119
264
  reference** (the group's id + header line): read the group's tasks and the
120
265
  requirements they reference from the spec files yourself. There is no PR yet —
121
266
  review the **group's diff on the branch against its slice of the spec** (the whole
122
- repo is your context; the verdict stays bounded to that slice). Two deviations from the procedure
267
+ repo is your context; the verdict stays bounded to that slice). When the invocation
268
+ says **pre-commit review is ON**, the group's work is **uncommitted by design**:
269
+ the diff is the group's uncommitted work against its anchor
270
+ (`git diff <anchor> -- ':(exclude).claude/state'`, the anchor handed in your
271
+ invocation; worktree == index within that scope at review time) — review it as
272
+ usual, but never
273
+ commit, stage, or otherwise mutate the worktree or index yourself. Two deviations from the procedure
123
274
  below, both in step 4: the verdict is **local** — return it in your summary for
124
- `progress.md`, never post an issue comment (only the final full-pass posts one) and a
125
- REJECT's `review_rejected` emit carries the extra `--step=<N>` flag (`iteration` stays
275
+ `progress.md`, never post an issue comment (only the final full-pass posts one), and
276
+ your ledger is `step-<N>.json` (the pre-gate single group, which has no step number,
277
+ writes `full-pass.json`) — and a
278
+ REJECT's `review_rejected` emit carries the extra `--step=<N>` flag **only when the
279
+ group is a step-by-step step** — an all-at-once single group (pre-commit review
280
+ ON's pre-gate pass) omits `--step`, which the events schema defines as absent on
281
+ all-at-once rejections (`iteration` stays
126
282
  task-global). Cross-group interactions are the final full-pass's job, not this one's;
127
283
  that full-pass reviews everything as usual and may reject anything, including
128
284
  human-OK'd steps.
@@ -150,12 +306,31 @@ empirically).
150
306
  seams, TypeScript pitfalls, self-review). The deeper passes, when installed, add:
151
307
  `silent-failure-hunter` (swallowed errors), `security-review` (security vectors),
152
308
  `spec-compliance-check` (per-requirement traceability, L1), `test-gap-report`
153
- (structural coverage gaps), and only when the project declares a `test:mutation`
154
- script — `mutation-testing` (behavioral test strength: diff-scoped, **advisory**, it
155
- never auto-rejects). Run each one that's present. Mutation findings split by where the
156
- mutant survives: on a line **this change touched**, report it as an advisory finding in
157
- your verdict (the Implementer may strengthen the test); on **pre-existing** code, route
158
- it through `note-side-finding` (see step 5) so the Orchestrator can `/spinoff` it.
309
+ (structural coverage gaps), and `mutation-testing` (behavioral test strength:
310
+ diff-scoped, **advisory**, it never auto-rejects). Run each one that's present —
311
+ running `mutation-testing` means following its SKILL.md, which chooses the path
312
+ and what (if anything) a given review owes at runtime, and owns how each finding
313
+ routes; its presence alone mandates no probes.
314
+
315
+ **Hand `security-review` the declared risk surfaces.** Before implementation, and with a
316
+ human's approval, this change was already declared for the kind of damage it can do: at
317
+ L1 the `[risk: <class>]` tags on the `tasks.md` group headers (the group under review on
318
+ a per-step pass, every group otherwise), at L2 the `## Risk surfaces` section of the
319
+ issue body. At L2, and on any per-step pass, it is already in what you batched up front.
320
+ On an L1 full pass nothing guarantees `tasks.md` is among the spec paths your invocation
321
+ named — **add it to the same composite call**, which buys the declaration for no extra
322
+ trip. Pass the classes **verbatim**, each with the group or the path it was declared
323
+ against, and never re-derive or edit one on the way through — what you hand over is what
324
+ the human approved, and a class you invented yourself is worth less than none. Carry the
325
+ L1 escape hatch too: a group whose damage the vocabulary cannot name leaves the tag off
326
+ and names that damage **in the group's rationale** instead, so pass that rationale line
327
+ as the declaration it is — untagged is not undeclared, and dropping it hands over
328
+ silence for a group that spoke. Pass the **absence** just as explicitly, because the two
329
+ absences are different claims: a declaration of `none` says the change touches no such
330
+ surface, while a _missing_ declaration claims nothing at all (the task may predate the
331
+ section). The declaration **adds** depth where a class lands; it never narrows the
332
+ pass — `security-review`'s own floor still runs over the whole diff, declared or not.
333
+
159
334
  3. **Validate against intent** — check the change against the issue (L2) or the spec
160
335
  (L1) point by point, not just "does it look right". **If `docs/architecture.md` exists,
161
336
  validate the change against the system's shape too** — it is the maintained map of that
@@ -164,10 +339,48 @@ empirically).
164
339
  A shape-moving change that leaves the map untouched will drift it — flag it in your
165
340
  verdict. Trust the map for context; verify the moved area against the diff. The map is
166
341
  **absent by default** — when it is, skip this check (don't suggest creating it).
167
- 4. **Verdict** — post an explicit approve/reject as an issue comment. On reject,
342
+ 4. **Verdict** — post an explicit approve/reject as a comment **on the task
343
+ issue** (that destination is load-bearing: the merge executor reads the
344
+ APPROVE record from the issue the gate names via `--approve-issue`). On reject,
168
345
  state precisely what fails so the Implementer can iterate; the task returns to
169
346
  implementation (rejection is transient, no dedicated label).
170
347
 
348
+ **On APPROVE, end the comment with the stale-approve record.** The merge
349
+ executor refuses to merge content that no longer matches what your APPROVE
350
+ reviewed — the merge-gate wait is deliberately long, and GitHub's own
351
+ stale-approval dismissal cannot cover an agent-authored PR, so the harness
352
+ carries its own guard. At the head you reviewed, run this and append the
353
+ two lines it prints:
354
+
355
+ ```bash
356
+ git fetch -q origin <base>
357
+ echo "Reviewed-tree: $(git rev-parse 'HEAD^{tree}')"
358
+ echo "Diff-fingerprint: $(git -c core.quotePath=true diff --raw --no-abbrev --no-renames --no-color "$(git merge-base FETCH_HEAD HEAD)" HEAD | git hash-object --stdin)"
359
+ ```
360
+
361
+ `<base>` is the PR's base branch (the default branch for task PRs; a stacked
362
+ partition child's predecessor branch while that is unmerged — the Orchestrator hands
363
+ it to you). The fetch + `FETCH_HEAD` pair matters: the executor recomputes against the
364
+ freshly fetched base, and a stale or unmaterialized `origin/<base>` (e.g.
365
+ a single-branch clone) would poison your fingerprint and flip a
366
+ legitimate merge to the content-changed verdict. The
367
+ diff flags are pinned byte-for-byte to the executor's recomputation — never
368
+ reorder, add, or drop one (a drifted flag flips every merge of yours to the
369
+ content-changed verdict). The fingerprint digests the PR's own diff against
370
+ the merge-base, so a clean update-branch later stays valid, while any
371
+ content change — including a merge resolution touching a file you
372
+ reviewed — invalidates the record and routes the PR back to re-review. A
373
+ re-review that approves posts a fresh APPROVE with fresh hashes; the
374
+ latest record wins — which is also why these two marker lines must never
375
+ be quoted in any later comment (the executor trusts the newest comment
376
+ carrying both).
377
+
378
+ **An APPROVE carries its ledger.** Before you return an APPROVE — full pass or
379
+ per-step — the sidecar is written and `lemony review-ledger validate` is green on it,
380
+ or red only on spec-side problems (§Evidence ledger). The same verb runs again on
381
+ your APPROVE before it is relayed, and an APPROVE whose ledger is red never is; say
382
+ in your return that it validated, and name every spec-side problem it reported.
383
+
171
384
  **Verdict size — capped on APPROVE, never on REJECT.** An APPROVE's return
172
385
  summary is a structured verdict plus key findings (advisory notes, a few
173
386
  bullets) and the paths involved; detailed evidence goes to the issue comment
@@ -240,8 +453,7 @@ skips human-wait _gates_, never the review _step_.
240
453
  ## Skills
241
454
 
242
455
  The installer fills this list with the skills your repo's capabilities resolved to.
243
- `senior-review` is always present; the deeper passes install
244
- unconditionally too, except `mutation-testing`, which is gated on a `test:mutation`
245
- script. The rich "how" of each lives in its own `SKILL.md`.
456
+ `senior-review` is always present; the deeper passes install unconditionally too.
457
+ The rich "how" of each lives in its own `SKILL.md`.
246
458
 
247
459
  {{SKILLS}}
@@ -31,7 +31,12 @@ the task branch before invoking you, so you are handed a real `<id>` from the st
31
31
  **absent by default** — orient as today and never suggest creating it. **If
32
32
  `.claude/state/tasks/<id>/spec/ui-handoff.md` exists**, read it too — the design contract
33
33
  authored for this task at DEFINE; align the spec's UI-facing requirements and design with
34
- its decisions rather than relitigating them.
34
+ its decisions rather than relitigating them. **If the Orchestrator hands you a
35
+ partition parent and a part** (the issue body's `Part <k> of #<parent>` trace line, the
36
+ parent's `## Plan` row, and the effective base), the spec covers **that part's slice
37
+ only** — the PRD's decisions outside the slice are constraints, not scope — and it is
38
+ authored against the effective base you are handed (the default branch, or — when the
39
+ part is stacked — the predecessor's head) and against nothing else still in flight.
35
40
  2. **Write the spec** — run the `prd-to-spec` skill to produce, under
36
41
  `.claude/state/tasks/<id>/spec/` (the id is real — there is no draft holder):
37
42
  - `requirements.md` — every requirement in **EARS** (ubiquitous / event-driven /
@@ -57,8 +62,12 @@ Don't paper over a gap. If a requirement needs a decision the PRD left open with
57
62
  valid option, **run the `raise-discovery` skill** — that's a `T2 UNSPECIFIED_DECISION`.
58
63
  Write the entry to `tasks/<id>/discoveries.md`, return the one-line summary, and stop.
59
64
  The Orchestrator mediates the question with the human, the PRD/spec improves, and you
60
- are re-invoked with the decision. Never guess past a consequential open fork. If instead
61
- you notice a defect **unrelated** to the spec you're authoring independent, not
65
+ are re-invoked with the decision. Never guess past a consequential open fork. If the
66
+ scope you are structuring turns out to hide **≥2 independently mergeable units the
67
+ PRD didn't reveal** (each could leave the default branch green and shippable without the
68
+ other), that is the same class of discovery — raise it as `T2 UNSPECIFIED_DECISION`
69
+ (partition or keep together is the human's call; never cut silently). If instead you
70
+ notice a defect **unrelated** to the spec you're authoring — independent, not
62
71
  blocking your work — don't chase it: **run `note-side-finding`** to add it to your return
63
72
  summary and keep authoring. Use the same channel when `docs/architecture.md` has
64
73
  **architecturally-significant drift** (the map states a boundary / seam the code no longer
@@ -8,8 +8,8 @@
8
8
  > apply here unchanged. Caller-side overrides ride in from dispatch: on a
9
9
  > **pending-stub pickup** the issue already exists — **skip `triage-issue`'s
10
10
  > issue-creation step**: the stub is the issue; update its body with the
11
- > skill's root-cause + fix-plan output and keep its number (never open a
12
- > second issue). An **architecture-drift stub** is a pending stub too, so the
11
+ > skill's root-cause, fix-plan and `## Risk surfaces` output and keep its
12
+ > number (never open a second issue). An **architecture-drift stub** is a pending stub too, so the
13
13
  > same reuse applies AND the **Architect** (running `update-architecture`)
14
14
  > replaces the Implementer in step 3.
15
15
 
@@ -17,14 +17,15 @@ For small bugs that don't earn the full SDD ceremony. They skip the spec and its
17
17
  but the branch, PR, and merge gate are the same — no path auto-merges:
18
18
 
19
19
  1. **Triage** — invoke the `triage-issue` skill: investigate the codebase, find the
20
- root cause, draft a TDD-based fix plan, and create the issue with `harness:managed`
20
+ root cause, draft a TDD-based fix plan, declare the change's `## Risk surfaces`,
21
+ and create the issue with `harness:managed`
21
22
  (no `harness:sdd` — its absence is what marks the lightweight path). Minimize
22
23
  questions. Record the number `<id>`.
23
24
  2. **Branch + scaffold** — create the task branch `harness/<id>-<slug>` off the default
24
25
  branch, then scaffold `.claude/state/tasks/<id>/progress.md` on it. Nothing touches
25
26
  the default branch until the merge gate.
26
27
  3. **Implement** — invoke the **Implementer** sub-agent with the `tdd` skill (spawn by
27
- reference — §Sub-agent invocation in the core; on an architecture-drift stub the
28
+ reference — the orchestrator's §Sub-agent invocation; on an architecture-drift stub the
28
29
  **Architect** with `update-architecture` replaces it, per the preamble). All work
29
30
  lives on the branch.
30
31
  4. **Review** — flip to `harness:status:in-review`, **open the PR** (`gh pr create`,
@@ -33,6 +34,8 @@ but the branch, PR, and merge gate are the same — no path auto-merges:
33
34
  `senior-review` skill (fresh context). On rejection, route back; on approval, go to
34
35
  the merge gate.
35
36
  5. **Merge gate** — the same human-explicit gate as L1: never auto-merge. Surface the
36
- PR and wait.
37
+ PR and wait. An authorized merge executes through the same checks precondition
38
+ as L1 (orchestrator §Merge gate — `.claude/hooks/lib/merge-pr.sh`, never bare
39
+ `gh pr merge`).
37
40
  6. **Closeout** — run the `task-closeout` skill (merge confirmed via `gh`), as in the
38
41
  orchestrator's §Closeout.
@@ -43,10 +43,10 @@ latent ones.
43
43
  reports the project has no meaningful architecture to map, it writes nothing: relay
44
44
  that to the user and **end the command** — skip step 4, force nothing.
45
45
 
46
- - **Any other latent capability** (e.g. a `test:mutation` script → `mutation-testing`):
47
- its guided activation is **not wired yet**. Say so plainly and **end the command** — do
48
- **not** fabricate the artifact. (Tracked as a follow-up; the activation behaviour plugs
49
- in here.)
46
+ - **Any other latent capability**: it has no guided activation. Say so plainly and
47
+ **end the command** do **not** fabricate the artifact. (Guided activation beyond
48
+ the architecture map is a deliberate non-feature, not a pending seam; wiring one up
49
+ for a future capability is its own decision.)
50
50
 
51
51
  4. **Re-sync so the gated skill installs** — only when step 3 actually wrote the artifact.
52
52
  Run:
@@ -22,3 +22,10 @@ self-approve, and move the `harness:status:*` labels per the lifecycle.
22
22
  If the task turns out to be too small for the full ceremony — nothing to specify,
23
23
  verify, or review — nudge toward `/triage` (L2) or `/bypass` (L3) per the task-fit
24
24
  dial (`.claude/agents/fit-assessment.md`). When in doubt, keep it in the harness.
25
+
26
+ The dial's ceiling is the **partition question**: if the closed PRD bundles separable,
27
+ independently mergeable wants, the orchestrator asks — at the define's close, before
28
+ opening the task — whether to cut the feature into several issues, each its own
29
+ branch, PR and merge gate (authority: `.claude/agents/partition.md`, read on trigger).
30
+ An approved cut opens a parent partition-plan issue (`harness:partition-plan`, never a
31
+ task) and Part 1 as a normal task; later parts open at their turn.
@@ -23,7 +23,21 @@ question to capture it, then proceed.
23
23
  issue, so it auto-closes on merge).
24
24
  3. **Skip the human-wait gates.** Do **not** pause for an approval gate, and do
25
25
  **not** wait on the merge gate — merge/ship as soon as the test is green and CI
26
- passes. This is the one path where you don't wait for a human to sign off first.
26
+ passes. "As soon as CI passes" is mechanical, not a vibe: execute the merge
27
+ through the checks-precondition executor
28
+ (`.claude/hooks/lib/merge-pr.sh <pr> --squash` — no `--approve-issue` here:
29
+ the hotfix review runs async, so there is no APPROVE to bind at merge time;
30
+ the stale-approve guard belongs to the reviewed task path), which waits for green and
31
+ refuses red or absent checks — urgency skips the _human_ wait, never the
32
+ verification. This is the one path where you don't wait for a human to sign
33
+ off first. On any non-zero exit (red / no checks / timeout / no verdict),
34
+ act on the exit code exactly as the Orchestrator's "Executing an authorized
35
+ merge — the checks precondition" section prescribes: surface the real state
36
+ and ask. Urgency never authorizes `--force` on your own initiative — a fire
37
+ does not lower the bar for merging on red or unverified checks. One
38
+ adaptation: a standing no-checks answer has no closeout PR to ride on this
39
+ path — commit the `merge.allow_no_checks: true` line onto the **hotfix
40
+ branch** before merging, so it lands with the hotfix PR.
27
41
  4. **Run the Reviewer asynchronously.** After shipping, dispatch the **Reviewer**
28
42
  sub-agent (fresh context, `senior-review`) on the merged change. The review is not
29
43
  skipped — it's deferred. If it surfaces problems, file a follow-up fix (a normal
@@ -50,3 +50,8 @@ A two-step pause:
50
50
 
51
51
  The hook prints `git status --porcelain` after emitting — it never
52
52
  auto-commits. Decide what (if anything) to stage and commit before leaving.
53
+ Exception — a task running **pre-commit review ON** (orchestrator §Pre-commit
54
+ review ON): do **not** commit; the zero-commit deferral binds `/pause` too.
55
+ Leave the staged save-point untouched (it survives the session; staging
56
+ anything now is the mid-experiment `add` the protocol forbids), note the pause
57
+ in `progress.md` — disk-only, per the mode's contract.
@@ -16,8 +16,11 @@ is the single source for the procedure.
16
16
  parked at `awaiting design definition` (+ `harness:needs-design`), and
17
17
  `-l harness:status:pending` for stubs captured by `/spinoff`), plus parked closeouts
18
18
  (`-l harness:status:closeout-pending --state all` — their issue is already **closed** by
19
- the task PR's `Closes #<id>`, so an open-only listing would miss them), and ask which to
20
- pick up.
19
+ the task PR's `Closes #<id>`, so an open-only listing would miss them), and **partition
20
+ parents** (`-l harness:partition-plan` — not tasks; one with unticked parts surfaces as
21
+ "partition in progress: next part per the plan" — or "waiting on #<id> (Part <j>)" when
22
+ the next row is blocked by an in-flight child — and resuming it starts the next eligible
23
+ part, or names the blocker, per `.claude/agents/partition.md`), and ask which to pick up.
21
24
 
22
25
  In brief (authority is the orchestrator): for an SDD task the state and spec live
23
26
  **only on the branch** until merge — `git fetch` and check out `harness/<id>-<slug>`
@@ -32,16 +35,36 @@ interview yourself** to finish `ui-handoff.md` (the UI Designer then critiques i
32
35
  drop `harness:needs-design` and continue toward spec-ready. When `progress.md` records
33
36
  `Mode: step-by-step`, the `## Step log` carries the step sub-state — resume
34
37
  exactly there: `awaiting human checkpoint (step N/M)` re-presents that pending
35
- checkpoint (inspect / run / OK / changes / OK+downgrade); a `fix-loop iteration K`
36
- line re-enters the per-step implement→review loop at that iteration (authority:
37
- the orchestrator §Step-by-step implementation). If the Mode line carries a
38
+ checkpoint (inspect / run / OK / changes / OK+downgrade; in all-at-once under
39
+ pre-commit review ON the line carries no `(step N/M)` counter — same
40
+ re-entry); a `fix-loop iteration K`
41
+ line re-enters the per-step implement→review loop at that iteration; an
42
+ `awaiting ledger retry (step N/M, retry 1/1)` line — or its full-pass twin
43
+ `awaiting ledger retry (full pass, retry 1/1)` — re-runs
44
+ `lemony review-ledger validate` on the sidecar on disk (`--anchor` per the
45
+ orchestrator: per-step, the `(anchor <oid>)` on the step-log line; full pass, the
46
+ fingerprint merge-base — except pre-commit review ON's pre-gate twin, which anchors
47
+ at the recorded single-group anchor, = the branch head: ON defers every commit) —
48
+ green re-presents the gate
49
+ the pass feeds, red goes to that gate with the verb's lines, the single retry being spent
50
+ (authority: the orchestrator §Step-by-step implementation). If the Mode line carries a
38
51
  `(downgraded to all-at-once at step N)` suffix, the remaining tasks run all-at-once —
39
52
  resume at the active subtask as usual, not via the step loop (the Step log is then
40
53
  history, not sub-state).
41
54
 
42
55
  **Cross-machine pickup of an `in-progress` task**: the branch on origin
43
56
  carries the last **successful** best-effort WIP push — the Implementer pushes on
44
- signaling done, and step-by-step pushes at each checkpoint-wait. If a **local** copy
57
+ signaling done, and step-by-step pushes at each checkpoint-wait. Exception: a task
58
+ running **pre-commit review ON** defers every commit and push until a checkpoint OK
59
+ — in-flight work and its `progress.md` updates exist only in the implementing
60
+ machine's worktree, so from another machine the branch reads as of the last OK'd
61
+ group; before the first OK it is **indistinguishable from idle** (the knob record
62
+ itself is deferred — the documented price of the mode, orchestrator §Pre-commit
63
+ review ON). When config pins `implementation.pre_commit_review: on`, or the
64
+ branch's `progress.md` already carries the `Pre-commit review: on` line (some OK
65
+ landed), surface the mode instead of concluding the task is idle. A discovery
66
+ pause still surfaces cross-machine via its labels and issue comment, though the
67
+ full `discoveries.md` entry stays machine-local. If a **local** copy
45
68
  of the branch is ahead of origin, prefer it (it is the newer state — this is what
46
69
  makes same-machine resume lossless). From a **different** machine, anything committed
47
70
  after the last successful push is unreachable and undetectable (origin is
@@ -51,9 +74,14 @@ checkpoint is a conscious replay, not a silent assumption. An `in-review` one re
51
74
  **merge gate**: surface the open PR's review comments and run the merge-gate procedure
52
75
  (route change-requests back to the Implementer, then offer to post threaded replies —
53
76
  authority is the orchestrator). A `closeout-pending` task has **nothing to check out** —
54
- its task PR already merged and its state is archived under `_archive/<id>/`: re-enter the
55
- `task-closeout` skill at its **finalize** step (step 6) once the open
56
- `harness/closeout-<id>` record PR is merged the skill owns the finalize operations
77
+ its task PR already merged and its state is archived under `_archive/<id>/`: if the open
78
+ `harness/closeout-<id>` record PR is still unmerged, **re-run the self-merge executor on
79
+ it** (`.claude/hooks/lib/merge-pr.sh harness/closeout-<id> --squash --delete-branch`
80
+ the skill's step-5 line verbatim, flags included: a bare invocation is rejected by
81
+ `gh pr merge` non-interactively and would re-park forever. The park may have been a
82
+ transient pending/red that has since settled; a repeat not-green re-parks), then re-enter the
83
+ `task-closeout` skill at its **finalize** step (step 6) once that PR is merged — the
84
+ skill owns the finalize operations
57
85
  (delete the task branch, flip to `done`, emit `task_done`, close the issue). A
58
86
  `pending` stub has **no branch
59
87
  yet** — nothing to check out: read the captured context (the title is the symptom; the