@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.
@@ -18,7 +18,7 @@ issue label lifecycle, and runs closeout. The entry-protocol summary lives in
18
18
 
19
19
  ## Companion files (lazy — read on trigger only)
20
20
 
21
- Three procedures live in sibling files, kept out of boot context by design (a fourth
21
+ Four procedures live in sibling files, kept out of boot context by design (a fifth
22
22
  sibling, `.claude/agents/fit-assessment.md`, is a reference doc for the task-fit
23
23
  dial — not a procedure; consult it on a borderline classification). Read the
24
24
  file **when its trigger fires**, then run it as if it were a section here:
@@ -32,6 +32,11 @@ file **when its trigger fires**, then run it as if it were a section here:
32
32
  - **`.claude/agents/spinoff.md`** — mid-task capture (the `/spinoff` offer). Trigger:
33
33
  the human mentions what may be an independent, non-blocking defect, or a sub-agent
34
34
  summary carries a `## Side-findings` block.
35
+ - **`.claude/agents/partition.md`** — partitioning an oversized feature into
36
+ independently mergeable parts (several issues/branches instead of one). Trigger: the
37
+ grill closes a PRD that looks like it bundles separable wants (the define's closing
38
+ question, L1 step 1), RESUME or ORIENT lands on an issue carrying
39
+ `harness:partition-plan`, or a sub-agent raises an oversize discovery.
35
40
 
36
41
  ## Dispatch
37
42
 
@@ -50,9 +55,13 @@ Parse the first prompt's intent (or honor a slash command):
50
55
  nothing to check out: its task PR already merged and its state is archived under
51
56
  `_archive/<id>/`. Its issue is **closed** (the task PR's `Closes #<id>` fired), so it
52
57
  surfaces in the queue only when you list closed issues too (`--state all`) — an
53
- open-only listing misses it. It resumes at closeout **finalize** — confirm the open
54
- `harness/closeout-<id>` record PR merged, then finish the `task-closeout` skill
55
- (see §Closeout). A **`harness:status:pending`** stub (captured by `/spinoff`, so it
58
+ open-only listing misses it. It resumes at closeout **finalize** — if the open
59
+ `harness/closeout-<id>` record PR is **still unmerged, re-run the self-merge
60
+ executor on it first** (the skill's step-5 line verbatim, flags included:
61
+ `.claude/hooks/lib/merge-pr.sh harness/closeout-<id> --squash --delete-branch` —
62
+ a park on pending/red
63
+ checks is transient, and checks may be green by now; a repeat not-green re-parks),
64
+ then, once it reports merged, finish the `task-closeout` skill (see §Closeout). A **`harness:status:pending`** stub (captured by `/spinoff`, so it
56
65
  has **no branch and no task state yet**) is the exception: there is nothing to check
57
66
  out. Read the captured context — the **issue title is the always-present symptom**; the
58
67
  body adds a location/pointer and the `Discovered during #<parent>` ref when they exist
@@ -74,7 +83,11 @@ Parse the first prompt's intent (or honor a slash command):
74
83
  the Implementer; closeout's `update-architecture` then re-runs over that diff as a no-op,
75
84
  and there is no spec to archive. **Fallback:** if the project no longer keeps an
76
85
  `architecture.md` (the skill is uninstalled), treat it as a normal `pending` stub —
77
- run the task-fit assessment as usual, never break on the absent routing target.
86
+ run the task-fit assessment as usual, never break on the absent routing target. An
87
+ issue carrying **`harness:partition-plan`** is a **partition parent**, not a task —
88
+ nothing to check out and no fit assessment: read `.claude/agents/partition.md` and
89
+ start the **next part** per its `## Status` checklist (re-validating the cut first);
90
+ its in-flight children resume as today, by their own id.
78
91
  - **DEFINE** — "define / new task / I have an idea" → the **L1 full-SDD round-trip**
79
92
  below.
80
93
  - **TRIAGE** — "bug / error in / broken / fails when" → the **L2 lightweight
@@ -87,8 +100,8 @@ Parse the first prompt's intent (or honor a slash command):
87
100
  exact same listing `/resume` does with no args. `/resume` (authority: its command
88
101
  file) **owns** the precise `gh` queries; ORIENT does not re-specify them, so it
89
102
  cannot drift. That queue covers the spec-ready and in-progress tasks, the **`/spinoff`
90
- pending stubs** (what a human who never types `/resume` would otherwise forget), and
91
- the parked closeouts; then (2) the **start options** — `/define` (new feature, L1) and
103
+ pending stubs** (what a human who never types `/resume` would otherwise forget), the
104
+ parked closeouts, and the partition parents; then (2) the **start options** — `/define` (new feature, L1) and
92
105
  `/triage` (a bug, L2) — and ask which to do. The **start options are unconditional**:
93
106
  when the queue is **empty** (nothing parked), still render the menu with just the
94
107
  start options — that is the "nothing to resume, start something?" case, **not** a
@@ -121,14 +134,25 @@ discardable question; never block on it.
121
134
 
122
135
  This paragraph is the canonical criterion — act on it directly. The fuller L1/L2/L3
123
136
  model, the spec-or-no-spec call between L1 and L2, and worked examples live in the
124
- sibling `fit-assessment.md`; consult it for a borderline classification.
137
+ sibling `fit-assessment.md`; consult it for a borderline classification. The dial's
138
+ **ceiling** — a feature too big for one merge unit — is the partition question at the
139
+ define's close (`.claude/agents/partition.md`); a parent issue carrying
140
+ `harness:partition-plan` is never assessed: it is not a task.
125
141
 
126
142
  ## L1 full-SDD round-trip (DEFINE)
127
143
 
128
144
  1. **Grill the idea into a PRD** — run the `grill-with-docs` skill. One question at a
129
145
  time, never auto-decide. Output: a PRD at `docs/prds/<topic>-<date>.md`. The PRD is
130
146
  yours (creator/maintainer); its `Status:` flips to `completed` when the grill
131
- closes.
147
+ closes. **Then, before step 2, the partition question — when it applies.** If the
148
+ closed PRD looks like it bundles **separable, independently mergeable** wants (soft
149
+ cues, no threshold: capabilities a user could get one without the other, a natural
150
+ grouping beyond ~4–5 groups, closed decisions that don't touch each other), read
151
+ `.claude/agents/partition.md` and ask its closing question — the cut, its dependency
152
+ shape, and what each cut buys, approved by the human. No cue → continue silently. An
153
+ approved partition opens a **parent partition-plan issue** (`harness:partition-plan`,
154
+ never a task) and then **Part 1** in step 2 as a normal task plus the trace lines the
155
+ companion specifies; later parts open at their turn.
132
156
  2. **Open the task** — before dispatching anyone, create the tracked task so every
133
157
  sub-agent has an issue to label and a branch to work on:
134
158
  - `gh issue create` with a skeleton body
@@ -137,7 +161,9 @@ sibling `fit-assessment.md`; consult it for a borderline classification.
137
161
  id the task store assigns — the **GitHub issue number** while
138
162
  `task_storage.type: github` — as the task `<id>`.
139
163
  - Create the task branch `harness/<id>-<slug>` off the default branch
140
- (`git fetch && git checkout -b harness/<id>-<slug> origin/<default>`). All task
164
+ (`git fetch && git checkout -b harness/<id>-<slug> origin/<default>`; a **stacked**
165
+ partition child branches from its predecessor's head instead —
166
+ `.claude/agents/partition.md`). All task
141
167
  work — spec **and** code — lives on this branch; nothing touches the default
142
168
  branch until the human merge gate.
143
169
  3. **Design the UI (if it touches UI)** — before any spec work, evaluate the
@@ -151,7 +177,8 @@ sibling `fit-assessment.md`; consult it for a borderline classification.
151
177
  4. **Dispatch the Spec Author** — invoke the **Spec Author** sub-agent (fresh context,
152
178
  spawn by reference — §Sub-agent invocation) with
153
179
  the PRD path (and the `ui-handoff.md` if one was authored), the issue `<id>`, and the
154
- branch. It runs `prd-to-spec` (→ `requirements.md` EARS + `design.md` + `tasks.md` under
180
+ branch for a partition part, also the parent issue, its `## Plan` row and the
181
+ effective base (`.claude/agents/partition.md`). It runs `prd-to-spec` (→ `requirements.md` EARS + `design.md` + `tasks.md` under
155
182
  `tasks/<id>/spec/` — no draft holder, the id is real from the start) then `spec-to-issue`
156
183
  (fills the issue **body** from the spec; it creates nothing and moves no labels). It
157
184
  returns a summary.
@@ -176,18 +203,31 @@ sibling `fit-assessment.md`; consult it for a borderline classification.
176
203
  `harness:status:in-progress` and proceed **per the mode chosen at the gate**
177
204
  (§Implementation mode): **all-at-once** invokes the **Implementer** sub-agent (fresh
178
205
  context) once with the `tdd` skill and the branch — it keeps `progress.md` live and
179
- signals done; **step-by-step** runs the per-group loop in §Step-by-step
180
- implementation instead, and rejoins this flow at step 8 after the last group.
206
+ signals done; **step-by-step** runs the per-group loop (§Step-by-step
207
+ implementation) instead, and rejoins this flow at step 8 after the last group. With
208
+ **pre-commit review ON** (the gate's second knob), either mode runs the zero-commit
209
+ protocol — no commit touches the branch before a checkpoint OK (§Pre-commit review
210
+ ON); in all-at-once its single gate runs when the Implementer signals done,
211
+ **before** step 8 — the PR never opens on uncommitted work.
181
212
  8. **Review** — flip to `harness:status:in-review` and **open the PR**
182
213
  (`gh pr create`, `harness/<id>-<slug> → <default>`, with `Closes #<id>` in the PR
183
- body so the provider auto-links and closes the issue on merge). Invoke
214
+ body so the provider auto-links and closes the issue on merge; while its predecessor
215
+ is unmerged, a **stacked** partition child targets that branch as base instead, and
216
+ the Reviewer is handed that base for its stale-approve record —
217
+ `.claude/agents/partition.md`). Invoke
184
218
  the **Reviewer** sub-agent (fresh context) with the `senior-review` skill to review
185
219
  that PR. Fresh context is what prevents the Implementer's confirmation bias. **If the
186
220
  task touched UI** — the durable signal is that `tasks/<id>/spec/ui-handoff.md`
187
221
  exists — also invoke the **UI Designer** as a distinct design + a11y lens
188
222
  (REVIEW in `.claude/agents/ui-design.md`). Either lens rejecting routes back to the
189
223
  Implementer (rejection is transient — no dedicated
190
- label); on approval (both lenses), go to the merge gate.
224
+ label); on approval (both lenses), **validate the Reviewer's ledger** —
225
+ `lemony review-ledger validate --task-id=<id> --anchor=<merge-base> --full-pass`,
226
+ where `<merge-base>` is the merge-base of the freshly fetched base branch and the
227
+ PR head (`git fetch -q origin <base>` then `git merge-base FETCH_HEAD HEAD` — the
228
+ same OID the stale-approve Diff-fingerprint digests from), routed as every full-pass
229
+ APPROVE is (§Step-by-step implementation, after the last group: one fresh Reviewer
230
+ retry, then the human; never relayed on a red) — then go to the merge gate.
191
231
  9. **Merge gate** — see below. Human-explicit, never auto-merged.
192
232
  10. **Closeout** — see below.
193
233
 
@@ -203,7 +243,27 @@ its branch, read the spec cold, and run this gate before writing any code.
203
243
  1. Present the spec to the human: a short summary plus links to
204
244
  `tasks/<id>/spec/{requirements,design,tasks}.md` and the issue. `tasks.md`
205
245
  carries the **step grouping** the step-by-step loop would follow (risk-sized
206
- headers, one-line rationale each) approving the spec approves the grouping.
246
+ headers, one-line rationale each, and a `[risk: <class>]` tag on the groups whose
247
+ damage the vocabulary names) — approving the spec approves the grouping **and those
248
+ tags**. Surface them when you present it — **including when there are none**, which is
249
+ the case an under-declared spec hides in: say which groups carry which classes, or
250
+ that no group carries one, and let the human judge that against what the spec does.
251
+ The vocabulary is the table in the `prd-to-spec` skill; read it if you need to check a
252
+ tag. You are the last reader before implementation starts.
253
+
254
+ **Declared review gates ride the same presentation.** If `harness.config.yml` has no
255
+ `gates` key, propose one in this interaction: read the project's manifest
256
+ (`package.json` scripts) and CI workflow, list every mechanical gate they enforce —
257
+ drift checks included, exactly the gates a name-guessing heuristic misses — and offer
258
+ it as the flat `gates` list. On the human's confirmation, add the key by hand: you
259
+ are editing their config under contract (no tool writes it for you; the schema
260
+ validates it loudly on the next read, and the template's commented block shows the
261
+ shape). A "no" stands — a project that wants no script gates records `gates: []`,
262
+ which also ends the offer. **Never propose or write the key mid-review**: an
263
+ undeclared project reviews against the real-run floor only (the ledger reports
264
+ `basis: 'undeclared'`), an acceptable state — the offer exists so that state is
265
+ chosen, never defaulted into.
266
+
207
267
  2. Wait for an explicit decision:
208
268
  - **Approve** → ask the **implementation mode** in the same interaction
209
269
  (§Implementation mode — the human just read `tasks.md` cold, the best moment to
@@ -259,6 +319,29 @@ applies. The mode is switchable **downward only** (step-by-step → all-at-once,
259
319
  at every checkpoint); there is no upgrade path — all-at-once has no stop where the
260
320
  switch could be offered.
261
321
 
322
+ **The second knob, same interaction — pre-commit review.** Alongside the mode, settle
323
+ whether the human reviews the work **uncommitted**, before anything lands on the
324
+ branch. Read `implementation.pre_commit_review` from `harness.config.yml` first (an
325
+ absent key means `human`): `on` / `off` **pin the answer — record it without asking**;
326
+ `human` (the default) asks here, in the same interaction, suggesting OFF:
327
+
328
+ > **Pre-commit review OFF** (default) — the Implementer commits and best-effort
329
+ > pushes as it works, exactly as today; checkpoints present committed work per
330
+ > the checkpoint contract.
331
+ >
332
+ > **Pre-commit review ON** — the Implementer makes **zero commits**: the work
333
+ > accumulates in the worktree under a staging protocol, you review it
334
+ > **uncommitted** (the Source Control panel shows it natively, and you can edit
335
+ > it in place), and the branch receives its first commit only on your OK.
336
+
337
+ Record it next to the mode line (`Pre-commit review: off` / `on`) — execution state,
338
+ like the mode. The knob is **L1-only** (it rides this question; L2 always runs today's
339
+ flow) and orthogonal to the mode: it moves **when the branch first receives commits**,
340
+ never whether review happens. In step-by-step the uncommitted gate runs per group; in
341
+ all-at-once it is **one gate over the entire implementation** (its single "group" is
342
+ the whole `tasks.md`). ON's mechanics — staging save-points, full deferral,
343
+ watch-fors — live in §Pre-commit review ON.
344
+
262
345
  ## Step-by-step implementation (the per-group loop)
263
346
 
264
347
  One step = one `tasks.md` **group**, 1:1 with the grouping the human approved at the
@@ -267,27 +350,103 @@ the human checkpoint run, never how the Implementer works. A `tasks.md` without
267
350
  headers (a legacy or hand-written spec) runs **one task per group** — the pre-grouping
268
351
  cadence. Tasks added mid-implementation (a resolved discovery) default to **their own
269
352
  group**, appended at the end of the loop — M grows, and already-resolved step numbers
270
- never shift. For each group, in order:
271
-
272
- 1. **Implement the group** invoke the **Implementer** sub-agent (fresh context, as
273
- always) scoped to **this one group**: give it the branch, the task-state paths, and
274
- the group's id + header line in `tasks.md` by reference (§Sub-agent invocation),
275
- it reads the group's tasks from the file itself (`tdd` skill checkbox by checkbox
276
- with small commits, as always). It commits to the branch, logs to
277
- `progress.md`, and signals done. **No PR yet** — the PR opens after the last group,
353
+ never shift; a narrowing (a resolved partition discovery) trims or removes groups from
354
+ the current one onward and trims a resolved group in place — M may shrink, resolved step
355
+ numbers still never shift. For each group, in order:
356
+
357
+ 1. **Implement the group** first **record the group's anchor**: the branch head OID
358
+ at this moment (= the end of the previous approved group; the head at
359
+ implementation start for group 1) goes on the group's step-log line — the
360
+ checkpoint contract diffs against it. Then invoke the **Implementer** sub-agent
361
+ (fresh context, as always) scoped to **this one group**: give it the branch, the
362
+ task-state paths, and the group's id + header line in `tasks.md` — by reference
363
+ (§Sub-agent invocation), it reads the group's tasks from the file itself (`tdd`
364
+ skill — checkbox by checkbox with small commits, as always). It commits to the
365
+ branch (pre-commit review ON: it **stages** instead of committing — point the
366
+ invocation at the staging protocol in `implementer.md`), logs to `progress.md`,
367
+ and signals done. **No PR yet** — the PR opens after the last group,
278
368
  as in all-at-once; the human inspects and runs the **local checkout** (a checkpoint
279
369
  never needs GitHub; the branch is pushed best-effort at each checkpoint — step 3).
280
370
  2. **Per-step review** — invoke the **Reviewer** sub-agent (fresh context) **by
281
371
  reference** (§Sub-agent invocation): the group id + its header line — it reads the
282
372
  group's tasks and requirements itself — scoped to the **group's diff against its
283
- slice of the spec**. The verdict is **local**
373
+ slice of the spec**. **Hand the group's anchor OID (step 1's step-log line) in the
374
+ spawn prompt in both knob states** — the Reviewer self-validates its ledger
375
+ against it (`--anchor`); pre-commit review ON additionally hands the ON flag —
376
+ the diff is then the group's **uncommitted work against the anchor**,
377
+ `git diff <anchor> -- ':(exclude).claude/state'`; worktree == index
378
+ within that scope at review time. The
379
+ verdict is **local**
284
380
  (`progress.md` + session narration) — no issue comment; only the final full-pass
285
381
  posts one. **On a UI-touching step**, also run the deterministic design gates here —
286
382
  `lemony design-tokens validate` + `lemony design-tokens contrast`, agent-free and cheap — and let the
287
383
  project's a11y lint ride the step's lint; a failure is an early-catch REJECT so a bad
288
384
  token pair or hardcoded value can't propagate to a later step. The **judgment** design
289
385
  lenses (`design-critique` / `a11y-audit`) do **not** run per-step — they are full-pass
290
- only (REVIEW in `.claude/agents/ui-design.md`). On REJECT, re-invoke the Implementer (fresh) with the
386
+ only (REVIEW in `.claude/agents/ui-design.md`).
387
+
388
+ **On an APPROVE, validate the evidence ledger before relaying it** — agent-free and
389
+ cheap, like the design gates, and for the same reason: a check an agent performs is a
390
+ check an agent can rationalize away. The Reviewer wrote
391
+ `.claude/state/tasks/<id>/review-ledger/step-<N>.json` (its `## Evidence ledger`
392
+ contract) and self-validated it; you run the same verb:
393
+
394
+ ```bash
395
+ lemony review-ledger validate --task-id=<id> --anchor=<oid> --step=<N>
396
+ ```
397
+
398
+ `<oid>` is the anchor **you** recorded when the group started (step 1's step-log
399
+ line) — never one the Reviewer reports. Trust is by double execution, the
400
+ Diff-fingerprint's own pattern: the Reviewer self-validated with the anchor its
401
+ invocation handed it, and your authoritative run catches a green built on the
402
+ wrong anchor — that red routes like any sidecar-side red below.
403
+
404
+ **In pre-commit review OFF, run the verb on a clean tree.** The floor's owed set
405
+ reads the diff against the anchor _including uncommitted work_ — correct in ON,
406
+ where the group's work is uncommitted by design, but in OFF an uncommitted tracked
407
+ edit outside `.claude/state` at validation time is a **human delta the Reviewer
408
+ never saw**, and it would red the floor as `unaccounted-file` on a ledger that is
409
+ not wrong. Check `git status --porcelain -- . ':(exclude).claude/state'` first; a
410
+ hit routes through the checkpoint contract's human-delta check **before** you
411
+ validate — never burn the Reviewer retry on unreviewed human content.
412
+
413
+ Green → the APPROVE stands; carry its counts — both halves, `criteria n/m (basis: …)`
414
+ and `gates n/m (basis: …)` — onto the step-log line: the gates basis is the one
415
+ place a green run shows the human whether the project reviews against declared
416
+ gates or the bare real-run floor (`undeclared`).
417
+ Red → **an APPROVE with a red ledger is never relayed**, and a red ledger is not a
418
+ REJECT of the code: the Implementer is not at fault and is **never** re-invoked for
419
+ it. Route on the `[kind]` lines the verb prints — it closes with
420
+ `N spec-side problem(s) … do not retry the Reviewer while any of these stands.`
421
+ whenever any problem lives outside the sidecar:
422
+
423
+ - **any spec-side problem** — the verb counts them out loud (`unknown-risk-class`, a
424
+ tag or ref list that did not parse, a duplicated group number, an orphan task, an
425
+ empty group, a dangling requirement ref, a step with no group) → no retry. They
426
+ live in `tasks.md` / `requirements.md`, which the Reviewer cannot fix: stop and
427
+ bring them to the human as an **anticipated checkpoint** (below) with the verb's
428
+ lines as the content — the spec needs a decision, and the fix routes as a discovery
429
+ (§Discovery mediation). Once the resolution lands in the spec, re-run the verb on
430
+ the sidecar on disk: green → the checkpoint; a sidecar-side red then follows the
431
+ one-retry rule below. The human's `ok` on an anticipated checkpoint is their call,
432
+ as at every gate — what never happens is you relaying a red as an APPROVE.
433
+ - **anything else** (a problem in the sidecar itself) → re-invoke the **Reviewer**
434
+ (fresh, as always) **once**, with the
435
+ verb's `[kind] message` lines **verbatim** in the spawn prompt — the delta is the
436
+ payload (§Sub-agent invocation). This is its own cap of **one retry**, separate from
437
+ the REJECT cap below: a Reviewer that cannot hit the format must not burn the
438
+ Implementer's budget. Set the open step's transient line to
439
+ `awaiting ledger retry (step N/M, retry 1/1)` (step 5) **before** re-invoking — the
440
+ retry is spent the moment it is issued, so a session that dies mid-retry resumes
441
+ knowing it is gone. Validate the second APPROVE the same way; a **second red** →
442
+ anticipated checkpoint with the verb's lines as the content. A `/resume` that lands
443
+ on the `awaiting ledger retry` line re-runs the verb on the sidecar on disk: green →
444
+ step 3's checkpoint; red → the anticipated checkpoint, the retry being spent.
445
+
446
+ A REJECT owes no ledger — do not run the verb on one. A red ledger emits no telemetry
447
+ of its own in this version; the step-log line is its record.
448
+
449
+ On REJECT, re-invoke the Implementer (fresh) with the
291
450
  feedback and re-review — the fix-loop runs until clean, **capped at 3 REJECTs on the
292
451
  same step**:
293
452
  at the cap, stop the loop and bring the disagreement to the human as an
@@ -297,7 +456,15 @@ never shift. For each group, in order:
297
456
  `awaiting human checkpoint (step N/M)` line in `progress.md` — except you present
298
457
  the unresolved disagreement (both positions, the spec slice) instead of a clean
299
458
  step.
300
- 3. **Human checkpoint** — first set the open step's `progress.md` line to
459
+
460
+ In pre-commit review ON, `OK` is also the moment the group's single code commit
461
+ lands, and `changes` sends the fresh Implementer to iterate **over the worktree**
462
+ — both per §Pre-commit review ON.
463
+
464
+ 3. **Human checkpoint** — first run §Checkpoint contract's **spec check** (item
465
+ 4): the state commit below sweeps `spec/`, so an unconfirmed human spec edit
466
+ must route as a discovery **before** anything commits it. Then set the open
467
+ step's `progress.md` line to
301
468
  `awaiting human checkpoint (step N/M)` (step 5), then commit the task state and
302
469
  **push the branch, best-effort**, as **one composite invocation** (§Turn economy).
303
470
  This commit and step 4's OK-side twin are **yours, anchored to your checkpoint
@@ -307,15 +474,25 @@ never shift. For each group, in order:
307
474
 
308
475
  ```bash
309
476
  git add .claude/state/tasks/<id>/ && \
310
- git commit -m "step(<id>): step <N> awaiting checkpoint"; \
477
+ git commit -m "step(<id>): step <N> awaiting checkpoint" \
478
+ -- .claude/state/tasks/<id>/; \
311
479
  git push # best-effort — a failure warns, never blocks
312
480
  ```
313
481
 
482
+ The commit's pathspec keeps it honest: anything else already staged (e.g. a
483
+ human edit staged ahead of the checkpoint) stays staged instead of riding
484
+ mislabeled into the state commit.
485
+
314
486
  A failed push — offline, auth — warns and never blocks; the next push carries
315
487
  it. This long wait is where a session likeliest dies — the push is what lets
316
488
  another machine's `/resume` see the pending checkpoint.
317
- Then present the step: what was built, where to look, how to run it. Three
318
- answers:
489
+ **Pre-commit review ON skips this state commit and push entirely** until the
490
+ OK the branch receives _nothing_, state included (§Pre-commit review ON): update
491
+ the `progress.md` line on disk only, accepting the documented price that the
492
+ pending checkpoint is invisible to a cold `/resume` from another machine.
493
+ Then present the step **per §Checkpoint contract**: what was built and how to
494
+ run it, the group's commits and touched files, the anchored group diff, the
495
+ richer-view offer, and the human-delta check. Three answers:
319
496
  - **OK** → emit `step_completed` (below), next group.
320
497
  - **Changes** (with feedback) → fresh Implementer with the feedback → per-step
321
498
  review again (step 2; the review-iteration count resets) → checkpoint again.
@@ -331,7 +508,8 @@ never shift. For each group, in order:
331
508
  (`Mode: step-by-step (downgraded to all-at-once at step N)` — the gate choice
332
509
  stays first; the downgrade is a suffix, because `task_done.mode` records the gate
333
510
  choice), and run the **remaining** tasks as a single Implementer invocation
334
- (today's mode). Checkpoint OKs already given stand.
511
+ (all-at-once; the pre-commit review knob keeps its recorded setting).
512
+ Checkpoint OKs already given stand.
335
513
 
336
514
  Aborting needs no protocol: the human interrupts the session; `/resume` picks the
337
515
  step sub-state back up from `progress.md`.
@@ -339,9 +517,16 @@ never shift. For each group, in order:
339
517
  4. **Telemetry** — every **resolved checkpoint** emits one event (so a step the human
340
518
  sent back emits more than once, same `--step`); the emit, the step's resolved
341
519
  `progress.md` line (step 5) and the resolution state commit (on OK, plain or
342
- downgrade: `step(<id>): step <N> checkpoint OK`) + best-effort push ride as
520
+ downgrade: `step(<id>): step <N> checkpoint OK`, carrying the same
521
+ `-- .claude/state/tasks/<id>/` pathspec as step 3's twin so other staged
522
+ content never rides mislabeled) + best-effort push ride as
343
523
  **one composite turn** (§Turn economy) — without that commit a cold `/resume`
344
- still reads `awaiting` after the last group. `<review-iterations>` is the number
524
+ still reads `awaiting` after the last group. Pre-commit review ON: on OK the
525
+ same composite additionally carries the group's **code commit** — the deferral
526
+ ends here, so code commit + state commit + push + emit land together (exact
527
+ commands, the pathspec split of the mixed index, and the all-at-once no-emit
528
+ rule in §Pre-commit review ON); on
529
+ `changes` nothing is committed and the deferral continues. `<review-iterations>` is the number
345
530
  of Reviewer invocations that preceded this checkpoint (≥ 1; resets after a
346
531
  "changes"):
347
532
 
@@ -358,7 +543,8 @@ never shift. For each group, in order:
358
543
  **Attribution — name the component the checkpoint friction is about, or
359
544
  omit.** The two `--attributed-*` flags are **optional**; they're meaningful when
360
545
  the checkpoint surfaced friction (`changes`, or repeated `review-iterations`) and
361
- you can name what produced it — usually the Implementer. **Omit both on a clean
546
+ you can name what produced it — usually the Implementer; a ledger retry is the
547
+ Reviewer's own. **Omit both on a clean
362
548
  `ok` checkpoint or when you can't confidently attribute** (a wrong guess pollutes
363
549
  the signal). Use the **exact** name from this roster so the data aggregates:
364
550
 
@@ -370,28 +556,35 @@ never shift. For each group, in order:
370
556
  `cli-e2e`, `bash-hooks`)
371
557
 
372
558
  Per-step Reviewer REJECTs also emit `review_rejected` as usual, with the extra
373
- `--step=<N>` flag (the `iteration` count stays task-global, as today).
559
+ `--step=<N>` flag (the `iteration` count stays task-global, as today; an
560
+ all-at-once single-group pass — pre-commit review ON's pre-gate review —
561
+ omits `--step`, per the events schema).
374
562
 
375
563
  5. **`progress.md` step log** — keep the sub-state explicit so `/resume` can re-enter
376
564
  mid-loop. Under a `## Step log` heading, one line per resolved step; the **open**
377
565
  step's line is transient — update it in place as the loop progresses
378
566
  (`fix-loop iteration K — in progress` while implementing/reviewing,
379
- `awaiting human checkpoint (step N/M)` while waiting on the human), then replace it
380
- with the resolved outcome:
567
+ `awaiting ledger retry (step N/M, retry 1/1)` while the fresh Reviewer redoes a red
568
+ ledger, `awaiting human checkpoint (step N/M)` while waiting on the human), then
569
+ replace it with the resolved outcome:
381
570
 
382
571
  ```markdown
383
572
  Mode: step-by-step
384
573
 
385
574
  ## Step log
386
575
 
387
- - step 1/6 — review ×1 → checkpoint: OK
388
- - step 2/6 — review ×3 (2 rejects: missing error path; flaky spec) → checkpoint: changes → review ×1 → checkpoint: OK
389
- - step 3/6 — awaiting human checkpoint (step 3/6)
576
+ - step 1/6 (anchor a1b2c3d) — review ×1 → checkpoint: OK
577
+ - step 2/6 (anchor e4f5a6b) — review ×3 (2 rejects: missing error path; flaky spec) → checkpoint: changes → review ×1 → checkpoint: OK
578
+ - step 3/6 (anchor c7d8e9f) review ×2 (ledger retry ×1) — ledger: criteria 3/3 (basis: requirements), gates 2/2 (basis: config) → checkpoint: OK
579
+ - step 4/6 (anchor f1a2b3c) — awaiting human checkpoint (step 4/6)
390
580
  ```
391
581
 
392
- Those two transient sub-state strings are exactly what a later `/resume` re-enters
582
+ Those transient sub-state strings are exactly what a later `/resume` re-enters
393
583
  on: the awaiting line re-presents the pending checkpoint, the fix-loop line
394
- re-enters the implement→review loop at that iteration.
584
+ re-enters the implement→review loop at that iteration, and the ledger-retry line
585
+ says the single retry is already spent. The `(anchor <oid>)`
586
+ field is the OID step 1 recorded — the checkpoint contract and the per-step
587
+ Reviewer diff against it.
395
588
 
396
589
  After the **last group**, rejoin the normal flow unchanged (L1 step 8): flip to
397
590
  `in-review`, open the PR, and run the **full-pass Reviewer** over everything against
@@ -399,6 +592,190 @@ the spec. The full-pass may reject anything, **including human-OK'd steps** —
399
592
  checkpoint OK means "right direction and it runs", not a review waiver; the full-pass
400
593
  wins, and the human still holds the merge gate to disagree.
401
594
 
595
+ **Every full-pass APPROVE is ledger-validated too** — the step-8 review in either mode,
596
+ pre-commit review ON's single-group pre-gate pass, and a re-APPROVE after the merge gate
597
+ or PR comments sent the PR back to review. The Reviewer writes `full-pass.json` (no step
598
+ number → the union of every group); you run
599
+ `lemony review-ledger validate --task-id=<id> --anchor=<merge-base> --full-pass` —
600
+ the merge-base of the freshly fetched base and the PR head, the Diff-fingerprint's
601
+ own OID (L1 step 8; pre-commit review ON's pre-gate pass instead anchors at the OID
602
+ you recorded when its single group started) — and route a red exactly as
603
+ in step 2 above: one fresh Reviewer retry with the lines verbatim, a second red or any
604
+ spec-side problem to the human, and never an APPROVE relayed on a red ledger. Outside
605
+ the step loop the transient line is `awaiting ledger retry (full pass, retry 1/1)` in
606
+ `progress.md` (no step counter), and "the human" is the gate the pass feeds: the
607
+ pre-commit-ON checkpoint when there is one, otherwise the merge-gate presentation,
608
+ with the verb's lines as the content.
609
+
610
+ ## Checkpoint contract (how a human gate presents work)
611
+
612
+ Every human checkpoint — per-group in step-by-step, and the single all-at-once gate
613
+ when pre-commit review is ON — presents the same way. "Present the step" is a
614
+ contract, not a vibe:
615
+
616
+ 1. **Anchored scope.** The group's **anchor** — the branch head OID recorded when
617
+ the group started (= the end of the previous approved group; the head at
618
+ implementation start when no group has yet been approved — group 1, or an
619
+ all-at-once run; an all-at-once run that began as a mid-task downgrade anchors
620
+ at the head after the last OK'd group) — bounds exactly what is
621
+ under review. Present the commit list + touched-files table, then the **exact
622
+ group diff**, always excluding task state:
623
+ - OFF: `git log --oneline <anchor>..HEAD` +
624
+ `git diff --stat <anchor>..HEAD -- ':(exclude).claude/state'`,
625
+ then `git diff <anchor>..HEAD -- ':(exclude).claude/state'`;
626
+ - ON (nothing committed):
627
+ `git diff --stat <anchor> -- ':(exclude).claude/state'`, then
628
+ `git diff <anchor> -- ':(exclude).claude/state'` — staged new files are in
629
+ the index, so they appear.
630
+ 2. **The inline rendered diff is the universal floor.** Probe the environment: when
631
+ a difftool is configured (or an extension like GitLens is present), **offer**
632
+ the richer side-by-side view — an ephemeral config works without touching the
633
+ repo's (`git -c diff.tool=<tool> difftool <range>`). Never assume an extension
634
+ exists. In ON the Source Control panel already shows the work natively — it IS
635
+ uncommitted.
636
+ 3. **What was built and how to run it** — from the Implementer's verification line,
637
+ as today. Checkpoint narration is the product, never overhead (§Turn economy).
638
+ 4. **The human delta — always detected, always revalidated.** Whatever the answer
639
+ (`ok` or `changes: …`), first detect the human's own edits — in ON, **two
640
+ checks with distinct routes** (every agent save-point is staged at
641
+ presentation time, so the staged/unstaged seam is the auto-detect):
642
+ - **Work delta**: the unstaged section outside task state —
643
+ `git diff -- ':(exclude).claude/state'` **plus untracked files outside
644
+ `.claude/state`** (from `git status --porcelain`; `git diff` never shows a
645
+ file the human created). Your own disk-only `progress.md` edits sit
646
+ unstaged under `.claude/state` by design — agent noise, never a human
647
+ delta.
648
+ - **Spec check**: unstaged edits **or untracked files** under the spec —
649
+ `git diff -- .claude/state/tasks/<id>/spec/` plus the untracked (`??`)
650
+ porcelain entries
651
+ under that path (a human-created spec file is untracked and invisible to
652
+ the diff). A hit is **not** a work
653
+ delta: it changes the approved spec, so route it as a **discovery**
654
+ (§Discovery mediation) before the checkpoint resolves. The Spec Author —
655
+ the spec's owner — applies the resolution to the file (restoring it if the
656
+ human's interpretation is rejected), then **re-present this checkpoint**;
657
+ only after that may any commit run, so `git add -A` lands the resolved
658
+ spec, never an unconfirmed unstaged edit. **Mediated changes are staged on
659
+ arrival and never re-raise**: whenever a discovery resolution is applied
660
+ mid-task — the Spec Author's spec update, an Architect artifact — stage it
661
+ immediately (`git add` the touched paths). Resolved artifacts join the
662
+ agent-staged floor, so this check fires only on **unmediated** edits and
663
+ the re-presented checkpoint is clean; an unstaged edit that matches the
664
+ recorded `**Resolution**` in `discoveries.md` is confirmed content — stage
665
+ it, don't re-raise.
666
+
667
+ The **spec check runs in both knob states** — in OFF, run it **before** step
668
+ 3's `awaiting` state commit, which would otherwise silently commit a
669
+ pre-existing spec edit before detection. OFF's work-delta detection is
670
+ simply any uncommitted working-tree change.
671
+ The **work delta** then runs the pipeline: present it, confirm it is
672
+ intended, and **re-run the suite with the delta applied** — the delta never
673
+ inherits the group's green. **A red revalidation blocks the OK**: never run
674
+ the commit composite on a red suite — re-present the failure and route it as
675
+ `changes` (the human decides: fix it themselves, drop the delta, or hand it
676
+ to the Implementer). On a green revalidation the delta rides with the group:
677
+ on OK it lands with
678
+ the group's work (ON: staged into the group's commit; OFF: committed as its
679
+ own commit — `step(<id>): step <N> human delta` — before the next group); on
680
+ `changes` it stays in the worktree for
681
+ the fresh Implementer (ON: staged first as the safe starting point —
682
+ §Pre-commit review ON).
683
+
684
+ ## Pre-commit review ON (zero commits + staging save-points)
685
+
686
+ The knob's ON state (chosen at the approval gate — §Implementation mode) moves
687
+ **when the branch first receives commits**; review, fix-loop routing, and the merge
688
+ gate are unchanged. v1 is deliberately an experiment — the watch-fors below are its
689
+ pre-registered exit signals.
690
+
691
+ - **Zero commits; staging save-points.** The Implementer never commits: it stages
692
+ after every green task (`git add -A`) and **never stages mid-experiment** — the
693
+ staging protocol in `implementer.md`, which the spawn prompt must point at
694
+ explicitly (it inverts the tdd add-early reflex, and a fresh Implementer only
695
+ knows what the contract and the branch tell it). A failed experiment rolls back
696
+ with `git restore . && git clean -fd`: the worktree returns to the last green
697
+ save-point; staged content survives verbatim, including new files.
698
+ - **Everything is deferred** until the human OK: no code commits and **no state
699
+ commits** either — the checkpoint's `awaiting` state commit + push do not run;
700
+ `progress.md` updates on disk only. The documented price, accepted at the
701
+ grill: **no multi-machine durability** during implementation and during the
702
+ checkpoint wait (the flow's longest, where a session likeliest dies) — a cold
703
+ `/resume` from another machine sees nothing pending. (One exception: a
704
+ discovery pause **is** visible cross-machine — its labels and issue comment
705
+ surface — but the full `discoveries.md` entry stays machine-local until an OK
706
+ lands it.) Same-machine resume reads the worktree as usual.
707
+ - **The gate** runs at end of group (step-by-step) or end of everything
708
+ (all-at-once — after the Implementer signals done and **before** the
709
+ `in-review` flip: the PR never opens on uncommitted work). In all-at-once the
710
+ whole implementation is the **single group** and the per-group machinery
711
+ applies to it: the mid-implementation Reviewer runs over the anchored diff
712
+ **before** the gate — nothing reaches the human unreviewed, in either mode —
713
+ and the `changes` fix-loop carries the same 3-reject cap into an anticipated
714
+ checkpoint (whose `step_completed` clause and `step N/M` strings apply only
715
+ in step-by-step — in all-at-once the no-emit rule below wins and the awaiting
716
+ line drops the step counter). Its APPROVE is ledger-validated with `--full-pass`
717
+ and `--anchor=<oid>` — the anchor you recorded when its single group started
718
+ (§Step-by-step implementation, after the last group), never relayed on a red.
719
+ Hand that pre-gate Reviewer the anchor, the ON
720
+ flag, and "the whole `tasks.md` as the single group" in place of a group id.
721
+ All agent work is
722
+ staged at presentation time; present per §Checkpoint contract. The human
723
+ inspects the work natively in the Source Control panel and edits/discards
724
+ directly in the worktree; answers are `ok` / `changes: …` (step-by-step keeps
725
+ its third answer, OK-and-downgrade).
726
+ - **OK ⇒ commit + push, after revalidating.** Re-run the suite over the final
727
+ worktree (human delta staged in) — the gate's green is fresh, never inherited.
728
+ Then the deferral ends as **one composite turn**, splitting the mixed index by
729
+ pathspec (`git add -A` staged code and task state together; a bare
730
+ `git commit` would swallow both into one commit):
731
+
732
+ ```bash
733
+ git add -A && \
734
+ { git diff --cached --quiet -- . ':(exclude).claude/state' || \
735
+ git commit -m "<code-msg>" -- . ':(exclude).claude/state'; } && \
736
+ { git diff --cached --quiet -- .claude/state || \
737
+ git commit -m "<state-msg>" -- .claude/state; }; \
738
+ git push # best-effort — a failure warns, never blocks
739
+ ```
740
+
741
+ Each commit is **guarded on its half of the index holding changes**, so a
742
+ degenerate group no-ops that half instead of short-circuiting the other: a
743
+ state-only OK (an audit group whose artifact is progress notes, or a human who
744
+ discarded the work in the worktree and answered `ok`) still lands its state
745
+ commit — an unguarded `&&` chain would silently drop it while the push still
746
+ ran, leaving the resolution nowhere on the branch.
747
+
748
+ Step-by-step: `<code-msg>` = `step(<id>): step <N>`, `<state-msg>` =
749
+ `step(<id>): step <N> checkpoint OK`, and the `step_completed` emit rides the
750
+ same turn (step 4). All-at-once (a downgraded remainder resolves as
751
+ all-at-once here too): `<code-msg>` = `task(<id>): implementation`,
752
+ `<state-msg>` = `task(<id>): pre-commit gate OK`, and **nothing is emitted** —
753
+ `step_completed` is step-by-step-only (its `--step` has no meaning here, and
754
+ closeout's mode recovery reads any `step_completed` as proof of step-by-step);
755
+ the gate resolution reaches telemetry through `task_done` as usual. One commit
756
+ per group in v1; all-at-once commits the whole implementation as its single
757
+ group.
758
+
759
+ - **Changes ⇒ the Implementer iterates over the worktree.** Same routing as any
760
+ rejection (fresh context, ≤3 rejects per step): it first **stages the
761
+ revalidated human delta** (its suite result rides in the feedback) as its
762
+ safe starting point, then continues
763
+ under the staging protocol. Nothing is committed; the deferral continues.
764
+ - **Watch-fors — pre-registered failure signatures.** v1 tests in real use whether
765
+ the three roles of tdd commits (fresh-Implementer memory via the branch,
766
+ granular save-points, 1:1 per-task history) are missed. If one fires, don't
767
+ improvise: **surface it at the checkpoint and record it in `progress.md`** so
768
+ the human can decide the swap to the pre-designed fallback — _deferred push_
769
+ (local tdd commits exactly as today but unpublished; the OK becomes the push:
770
+ commit = internal memory, push = publication). The signatures:
771
+ 1. **Fix-loop memory** — iteration 2 redoes or overwrites iteration 1's work.
772
+ 2. **Save-point residual** — a mid-experiment `git add` silently destroyed the
773
+ save-point (`git status` looks identical; recovery yields nameless blobs),
774
+ or single-level undo proves insufficient (e.g. selectively reverting task
775
+ N−2).
776
+ 3. **PR narrative** — one commit per group cannot reconstruct the per-task
777
+ `step(<id>): step <N>` story.
778
+
402
779
  ## Discovery mediation
403
780
 
404
781
  Any sub-agent (Spec Author, Implementer, Reviewer, Architect) may stop mid-task and
@@ -417,7 +794,11 @@ paused sub-agent with the decision. A discovery can also be raised by **you** (e
417
794
  checkpoint "changes" request that contradicts the spec): the same skill runs, with
418
795
  nothing to re-invoke — the resolution re-enters the loop where it paused. You are the
419
796
  only one who talks to the human and
420
- moves labels — never let a sub-agent self-resolve.
797
+ moves labels — never let a sub-agent self-resolve. An **oversize** discovery — the Spec
798
+ Author or the Implementer finds the scope hides ≥2 independently mergeable units the PRD
799
+ didn't reveal — is a T2 raised and mediated exactly like this; when the human answers
800
+ "partition", read `.claude/agents/partition.md` for the parent/part mechanics (the
801
+ current task keeps the first unit).
421
802
 
422
803
  ## Architect (on-demand)
423
804
 
@@ -466,16 +847,78 @@ action that touches the default branch, so it stays a human decision. Surface it
466
847
  wait:
467
848
 
468
849
  > Reviewed and approved — PR #<pr> is here: <url>.
469
- > (1) merge it yourself, (2) I'll merge it (`gh pr merge`), or
850
+ > (1) merge it yourself, (2) I'll merge it once checks are green (`gh pr merge`), or
470
851
  > (3) run `/review-pr` first for a curated inline pass.
471
852
 
472
- The task stays at `harness:status:in-review` while it waits there is no
473
- "approved-awaiting-merge" rung between review and merge (the `closeout-pending` status is
853
+ A **stacked partition child** reaches this gate only once its PR base is the default
854
+ branch check `baseRefName` first and retarget/merge-in per `.claude/agents/partition.md`;
855
+ never merge a part into a sibling's branch. The task stays at `harness:status:in-review`
856
+ while it waits — there is no "approved-awaiting-merge" rung between review and merge (the `closeout-pending` status is
474
857
  **post**-merge, for a parked closeout record PR — not this gate). When the
475
858
  human merges (in the GitHub UI, by CLI, or by authorizing you to run `gh pr merge`),
476
859
  proceed to closeout. **GitHub is the source of truth for the merge, not this
477
860
  conversation** — closeout confirms it via `gh pr view`.
478
861
 
862
+ ### Executing an authorized merge — the checks precondition
863
+
864
+ "Merge it" is a **conditional authorization**: the agent merges _when it is safe to do
865
+ so_, not an order to execute immediately. The human's yes carries the implicit
866
+ assumption that CI is fine; this contract makes that assumption an explicit
867
+ precondition. Not green ⇒ you never merge on your own — you re-present this gate with
868
+ the real state. (The failure pattern this kills: nobody _decided_ to merge on red — an
869
+ authorization whose background assumption was false got executed without looking.)
870
+
871
+ So never run a bare `gh pr merge`. Execute the merge through the shared executor, which
872
+ verifies the check status the platform reports for the PR and waits — bounded — for
873
+ pending checks (`merge.checks_timeout_secs` in `harness.config.yml`, default ~10 min).
874
+ For a task PR, always pass `--approve-issue` with the task's issue number — that arms
875
+ the **stale-approve guard**: the executor reads the Reviewer's APPROVE record
876
+ (`Reviewed-tree` / `Diff-fingerprint`) from that issue and refuses to merge content
877
+ that no longer matches what the APPROVE reviewed (a clean update-branch stays valid;
878
+ any content change does not):
879
+
880
+ ```bash
881
+ .claude/hooks/lib/merge-pr.sh <pr> --approve-issue <issue> --squash # merge-strategy flags pass through to `gh pr merge`
882
+ ```
883
+
884
+ Act on its exit code:
885
+
886
+ - **0 — merged.** Proceed to closeout.
887
+ - **10 — checks red.** Never merge on red by omission. Re-present the gate with the
888
+ failure: "checks red: <check> fails — merge anyway / wait / want to look at it?".
889
+ Merging on red stays possible, but only as the human's informed decision — on that
890
+ explicit yes, re-run with `--force`.
891
+ - **30 — still pending after the bound.** The authorization never expires silently; it
892
+ expires by asking: "checks still running after <N> min — keep waiting, or leave it
893
+ and I'll tell you when they settle?". "Keep waiting" = re-run the executor (a fresh
894
+ bound, or a longer one via `--timeout-secs <secs>`).
895
+ - **40 — stale approve: the PR content changed after the review.** A push landed in
896
+ the merge-gate window (another dev, a re-invoked implementer) and the diff no longer
897
+ matches what the APPROVE reviewed. Never merge it on the old verdict: route the PR
898
+ back to the Reviewer — the same back-to-review route as the comments path below; a
899
+ fresh APPROVE re-records the hashes — then re-surface this gate. Merging anyway
900
+ stays possible, but only as the human's informed decision — on that explicit yes,
901
+ re-run with `--force` (which skips the checks precondition too: make sure the
902
+ informed yes covers both).
903
+ - **20 — no checks reported (after the grace window).** Never merge alone, whatever the
904
+ cause — repo with no CI, CI outage, path filters: don't try to auto-classify. Ask:
905
+ "I saw no checks available on this PR — merge?". If the human's answer is standing
906
+ ("this repo has no CI — merge without checks"), record it **now** as
907
+ `merge.allow_no_checks: true` in `harness.config.yml` (the executor reads the working
908
+ tree, so no later merge — including this task's closeout — re-asks); the line lands
909
+ on the base with the closeout record PR's commit, never a direct push. For the merge
910
+ at hand, re-run with `--force`.
911
+ - **1 (or any other non-zero)** — not merged, and **not a verdict**: either the check
912
+ status could not be read (`gh`/auth/network failure — the precondition is
913
+ unverifiable, which is _not_ the same as "checks failed") or the merge attempt itself
914
+ was rejected (branch protection wants approval, a conflict, a bad ref). The
915
+ executor's stderr says which — surface that, verbatim, at the gate.
916
+
917
+ The precondition is platform-neutral by design — "the merge executor verifies the check
918
+ status the platform reports for the PR"; `gh` is the GitHub rendering of it. Branch
919
+ protection is the user's belt: the harness executes merges and cannot assume it is
920
+ configured, so the executor carries its own precondition either way.
921
+
479
922
  ### When the human leaves review comments instead of merging
480
923
 
481
924
  The human may respond at this gate not by merging but by **leaving comments on the PR**.
@@ -490,7 +933,14 @@ of an `in-review` task surfaces the open PR's comments and routes here — see
490
933
  route as a Reviewer rejection: re-invoke the Implementer sub-agent (fresh context)
491
934
  with the feedback (transient, no dedicated label). Skip pure acknowledgements or
492
935
  questions that need no code.
493
- 3. **After the fix commit, draft do not auto-post the replies.** Compose a short
936
+ 3. **Route the fixed PR to re-review.** The fix commits are new, unreviewed content
937
+ the Reviewer's standing APPROVE no longer covers them (and the executor's
938
+ stale-approve guard would refuse the merge with exit 40 anyway). Invoke the
939
+ Reviewer on the updated PR (continued re-review of its own findings when the
940
+ comments echo them; fresh otherwise); an approving verdict posts a fresh APPROVE
941
+ with fresh hashes. A reject routes back to step 2 — never draft "done" replies on
942
+ work that hasn't re-passed review.
943
+ 4. **After the re-APPROVE, draft — do not auto-post — the replies.** Compose a short
494
944
  "done ✅" reply threading each addressed comment, then **offer to post them with one
495
945
  confirmation**. Posting a reply inside someone's review thread is outward-facing and
496
946
  notifies the reviewer, so it is a **HITL gate, never automatic**. On approval, post
@@ -499,7 +949,7 @@ of an `in-review` task surfaces the open PR's comments and routes here — see
499
949
  identity it uses for issues, PRs, and merges; there is no separate bot identity). The
500
950
  fix commit is visible on the PR regardless, so declining only skips the
501
951
  acknowledgement, not the fix.
502
- 4. **Re-surface the merge gate** above.
952
+ 5. **Re-surface the merge gate** above.
503
953
 
504
954
  ## Closeout
505
955
 
@@ -508,17 +958,26 @@ GitHub — `gh pr view <pr> --json state,mergedAt` reports `MERGED`, regardless
508
958
  was merged). Closeout **archives, it does not delete, and it records via a dedicated PR**:
509
959
  it raises durable decisions to ADRs, `git mv`s the spec + `discoveries.md`
510
960
  into `.claude/state/tasks/_archive/<id>/`, drops only `progress.md`, and lands the
511
- `history.md` append + the archival on a `harness/closeout-<id>` PR merged with
512
- `gh pr merge` `--auto`. Nothing is pushed direct to the base the closeout record obeys
513
- the same branch isolation as every other change. The skill owns the full mechanics.
514
-
515
- **Closeout splits into two phases** because `--auto` defers to branch protection. If the
516
- closeout PR self-merges (protection is PR + checks only), closeout finalizes in one go. If
517
- protection requires human approval **or auto-merge is disabled repo-wide, which makes
518
- `--auto` error rather than queue** the PR waits: flip the issue to
519
- `harness:status:closeout-pending`, tell the human the record PR is open, and stop. A later
520
- `/resume` of a `closeout-pending` task finalizes once that PR is merged (see Dispatch
521
- RESUME).
961
+ `history.md` append + the archival on a `harness/closeout-<id>` PR self-merged through
962
+ the same checks-precondition executor as the merge gate (`.claude/hooks/lib/merge-pr.sh`
963
+ — **the executor never self-merges on anything but green**; no standing human
964
+ authorization exists on this path, so every not-green outcome takes one of the skill's
965
+ exits self-fix, park, or a human's informed decision never an autonomous merge).
966
+ Nothing is pushed direct to the base the
967
+ closeout record obeys the same branch isolation as every other change. The skill owns
968
+ the full mechanics, including what to do on red, absent, or still-pending checks. A
969
+ task that is a **part of a partition** (its body carries `Part <k> of #<parent>`) also,
970
+ at finalize, ticks its row in the parent's checklist and on the last part — closes the
971
+ parent with a summary comment; the skill's finalize step owns it (mechanics in
972
+ `.claude/agents/partition.md`).
973
+
974
+ **Closeout splits into two phases** because the self-merge only happens on green. If the
975
+ closeout PR's checks pass within the bound (and branch protection asks nothing more),
976
+ closeout finalizes in one go. Otherwise — checks red (and not self-fixable), no checks
977
+ and no standing answer, timeout, or protection requiring human approval — the PR waits:
978
+ flip the issue to `harness:status:closeout-pending`, tell the human the record PR is
979
+ open and why it didn't merge, and stop. A later `/resume` of a `closeout-pending` task
980
+ finalizes once that PR is merged (see Dispatch → RESUME).
522
981
 
523
982
  **Closeout is the Architect's reliable activation point**: before
524
983
  archiving, the skill drives three durable-capture activations, **asymmetric by design** —
@@ -528,7 +987,7 @@ path (the Architect reads the merged diff itself) — no pre-offer, the map
528
987
  tracks reality and the edit is reviewed in the closeout PR), and `playbook-iterate` (HITL
529
988
  offer once per task, for a reusable pattern no `T6` conflict already routed). Closeout
530
989
  never drafts the artifact itself — it lights up the Architect, who owns the criteria
531
- (§Architect on-demand). Each activation no-ops when its skill isn't installed.
990
+ (§Architect). Each activation no-ops when its skill isn't installed.
532
991
 
533
992
  Before any of this, enforce the discovery invariant: **no `discoveries.md` entry may lack
534
993
  a resolved `**Resolution**`block, and no`harness:discovery:\*` label may remain.** An