@ngockhoale/ukit 3.4.66 → 3.4.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/manifests/documentation.yaml +33 -0
  3. package/manifests/instructionRules.yaml +10 -0
  4. package/manifests/platform.full.yaml +67 -0
  5. package/package.json +1 -1
  6. package/src/core/applyPlan.js +111 -2
  7. package/src/core/buildPlan.js +3 -1
  8. package/src/core/diffPlan.js +49 -1
  9. package/src/core/executionContracts.js +51 -10
  10. package/src/core/metadata.js +45 -0
  11. package/src/core/runInstallPipeline.js +30 -2
  12. package/src/core/uninstall.js +106 -2
  13. package/src/manifest/validateManifest.js +25 -1
  14. package/template_project/.claude/agents/code-reviewer.md +22 -9
  15. package/template_project/.claude/agents/handoff-planner.md +97 -8
  16. package/template_project/.claude/commands/ukit/handoff-create.md +114 -19
  17. package/template_project/.claude/commands/ukit/handoff-fullstack.md +247 -79
  18. package/template_project/.claude/commands/ukit/handoff-implement.md +75 -40
  19. package/template_project/.claude/commands/ukit/handoff-review.md +14 -10
  20. package/template_project/.claude/hooks/auto-allow-bash.sh +73 -12
  21. package/template_project/.claude/hooks/auto-prune-bash.sh +10 -0
  22. package/template_project/.claude/hooks/delegation-gate.mjs +21 -0
  23. package/template_project/.claude/hooks/handoff-model-guard.sh +22 -6
  24. package/template_project/.claude/hooks/handoff-resume.sh +141 -1
  25. package/template_project/.claude/hooks/record-execution.mjs +140 -9
  26. package/template_project/.claude/hooks/skill-router.sh +173 -8
  27. package/template_project/.claude/settings.json +2 -2
  28. package/template_project/.claude/skills/advisor-plan/REFERENCE.md +10 -0
  29. package/template_project/.claude/skills/advisor-plan/SKILL.md +2 -2
  30. package/template_project/.claude/ukit/index/allocate-task-worktree.mjs +15 -0
  31. package/template_project/.claude/ukit/index/amend-guard.mjs +116 -0
  32. package/template_project/.claude/ukit/index/cleanup-task-worktree.mjs +1 -1
  33. package/template_project/.claude/ukit/index/land-worktree.mjs +243 -21
  34. package/template_project/.claude/ukit/index/plan-count.mjs +115 -0
  35. package/template_project/.claude/ukit/index/ready-gate.mjs +170 -0
  36. package/template_project/.claude/ukit/index/reset-auto-permissions.mjs +293 -4
  37. package/template_project/.claude/ukit/index/route-resolver.mjs +50 -10
  38. package/template_project/.claude/ukit/index/route-task.mjs +180 -11
  39. package/template_project/.claude/ukit/index/source-snapshot.mjs +172 -0
  40. package/template_project/.claude/ukit/index/task-budget-validator.mjs +109 -3
  41. package/template_project/.claude/ukit/runtime/execution-ledger.mjs +20 -3
  42. package/template_project/.claude/ukit/runtime/handoff-task-scope.mjs +205 -0
  43. package/template_project/.claude/ukit/runtime/loop-state.mjs +3 -1
  44. package/template_project/.claude/ukit/runtime/plan-dispatch.mjs +32 -5
  45. package/template_project/.claude/ukit/runtime/resumable-run.mjs +310 -21
  46. package/template_project/.claude/ukit/runtime/stop-coordinator.mjs +405 -105
  47. package/template_project/.claude/ukit/runtime/task-record-reconciliation.mjs +46 -0
  48. package/template_project/.claude/ukit/runtime/task-watchdog.mjs +28 -2
  49. package/template_project/.claude/ukit/runtime/worktree-allocation.mjs +75 -0
  50. package/template_project/.codex/README.md +25 -0
  51. package/template_project/.omp/RULES.md +22 -22
  52. package/template_project/.omp/agents/code-reviewer.md +22 -9
  53. package/template_project/.omp/agents/handoff-planner.md +102 -12
  54. package/template_project/.omp/hooks/pre/ukit-bridge.js +1 -1
  55. package/template_project/AGENTS.md +5 -1
  56. package/template_project/CLAUDE.md +1 -1
  57. package/template_project/docs/AI_HANDOFF/RULES.md +8 -0
  58. package/template_project/docs/AI_HANDOFF/tasks/_TEMPLATE.md +8 -1
  59. package/template_project/instructions/core.md +5 -1
  60. package/template_project/instructions/layout.yaml +2 -0
  61. package/template_project/instructions/overlays/omp-rules.md +22 -22
  62. package/template_project/ukit/storage/config.json +1 -1
@@ -74,7 +74,12 @@ resumable. If compaction does happen, the run resumes from the cursor automatica
74
74
  ### Run cursor — write after every step
75
75
 
76
76
  Maintain `docs/AI_HANDOFF/RUN.md`. Rewrite it (whole file — the fixed field block below,
77
- exactly as many lines as the fields in play) immediately after every numbered step completes:
77
+ exactly as many lines as the fields in play) immediately after every numbered step completes.
78
+ Before dispatching any mutating worker (including blueprint folding), write and read back the
79
+ P0/P1 cursor with the actual phase, frozen scope, next action and known job references. Do not
80
+ defer cursor creation until P2; omit ExitPredicate until P2 pins it, never invent a satisfied one.
81
+ Reconcile partial writes and existing jobs from that cursor on interruption; never restart the fold blindly.
82
+
78
83
 
79
84
  ```
80
85
  Command: handoff-fullstack
@@ -92,6 +97,8 @@ RetryFingerprint: <stable id of the failing step> # optional; retry-loop ident
92
97
  RetryCount: <n> # optional; consecutive attempts of that fingerprint
93
98
  ScopePlans: <slug[,slug...]> | none # optional; history/archive/Ready-for-AI items the invocation authorized
94
99
  ScopeQueue: <slug[,slug...]> | none # optional; the queued blueprints frozen into this run at P2
100
+ TaskScope: cycle-<NN>/TASK-001 = queue:<slug> # repeat per imported task; cycle-qualified key (TASK ids are reused across cycles); plan:<ScopePlans entry> for an authorized plan
101
+ TaskScope: cycle-<NN>/TASK-001-R1 = repair:TASK-001 # unqualified parent = same cycle; repair:cycle-<NN>/TASK-xxx pins an explicit older-cycle parent
95
102
  Authorization: <one line — who authorized the scope and from which invocation> # optional
96
103
  LateCreate: <slug> — <disposition> # optional; a create that arrived mid-run, never auto-folded
97
104
  ```
@@ -104,7 +111,29 @@ session boundaries; they never replace INDEX.md or RUN.md authority.
104
111
 
105
112
  **Late creates do not expand scope.** A blueprint or Ready-for-AI item that appears mid-run and is
106
113
  not in `ScopeQueue`/`ScopePlans` is recorded as `LateCreate:` with disposition `Backlog`. A late create does not expand scope and is never silently folded in. Repairs of work already assigned to this run
107
- still continue.
114
+ still continue. When folding a blueprint or authorized plan into INDEX, stamp a repeated
115
+ `TaskScope:` line for every assigned task in RUN.md. A repair/replan stamps `repair:<original task>`
116
+ (unqualified parent resolves in the same cycle) or `repair:cycle-<NN>/<original task>` (explicit
117
+ older-cycle parent) and inherits that task's scope, including across repair chains — never
118
+ unrelated late scope.
119
+
120
+ **Task ids are reused across cycles — qualify scope keys.** Stamp every new `TaskScope:` mapping
121
+ cycle-qualified (`cycle-<NN>/TASK-001`, same spelling the run's `Cycle:` field and claim cycles
122
+ normalize to). A task id reused in a later cycle never overwrites or inherits an earlier cycle's
123
+ scope or repair chain: the current cycle's mapping governs the live INDEX evaluation and each
124
+ archive cycle's mapping governs its ARCHIVE snapshot. Preserve ALL mapping lines on disk across
125
+ compaction, resume and cycle transition — retain the original mapping even after its task closes;
126
+ never rewrite or drop an older cycle's lines when opening the next cycle. Legacy unqualified
127
+ mappings stay honored only while no other cycle qualified the same id; an unqualified mapping that
128
+ collides with a cycle-qualified one is ambiguous and keeps the run in reconciliation instead of
129
+ guessing the old cycle. Completion, blocked and archive predicates use the same membership
130
+ selector: exclude only a task mapped to a different cycle/queue than the one being evaluated, and
131
+ refuse completion while any in-scope mapping is unresolved — unknown, conflicting, malformed,
132
+ cyclic or ambiguous mappings remain included and require reconciliation against the source before
133
+ declaring completion; never guess away unmapped obligations. The resume hook prints a bounded
134
+ slice of the frozen map (the current cycle plus the CurrentTask repair chain, hard-capped); the
135
+ full map is never truncated on disk — read `docs/AI_HANDOFF/RUN.md` for the remainder. Legacy runs
136
+ without frozen scope retain all INDEX rows. The eight-column INDEX format is unchanged.
108
137
 
109
138
  **Compact-carry fields.** `Acceptance`, `CurrentTask`, `RetryFingerprint` and `RetryCount`
110
139
  are what a compacted session carries forward — these four lines plus `Goal`/`Next:`, never
@@ -175,11 +204,13 @@ skipped silently.
175
204
 
176
205
  `Phase: blocked` is terminal for the run — the machinery (Stop gate, hooks, stop-coordinator)
177
206
  all treats it as closed. It is *paused*, not abandoned: an explicit `/ukit:handoff-fullstack`
178
- re-invocation resumes it as a continuation; `ukit handoff-clear` abandons it. Only when
207
+ re-invocation resumes it as a continuation; `ukit handoff-clear` pauses it (`Paused: yes`, backlog and scope kept, no completion minted). Only when
179
208
  `RUN.md` is absent or `Phase: done` does a new request start a fresh cycle.
180
209
 
181
210
  ### Explicit invocation reacquires ownership
182
211
 
212
+ An explicit `/ukit:handoff-fullstack` also lifts a liveness pause: the resume hook rewrites `Paused: yes` to `Paused: no` in `RUN.md`, reads it back, and keeps `Phase:`, scope, and the queue untouched. Ordinary prompts, startup, and clear never lift it.
213
+
183
214
  `/ukit:handoff-create` is planning-only and makes a session's handoff intent *planning* — so
184
215
  while the human is planning, neither the Stop gate nor the SessionStart compact/resume hook
185
216
  forces a paused run back into implementation. This command is the explicit counter-action:
@@ -226,6 +257,57 @@ Never stop at `recap: ... Next: ...` while unfinished work remains — the Stop
226
257
  bounces that stop straight back into the pipeline, so stopping is not even restful; it
227
258
  just costs a round-trip.
228
259
 
260
+ ### Pre-stop reconciliation — decide the stop, never rely on the bounce
261
+
262
+ The Stop gate is the **backstop, never the plan**. Before ANY turn ends — mid-wave or at
263
+ the end of the pipeline — reconcile the run once, explicitly, against this checklist and
264
+ then choose the ending yourself:
265
+
266
+ 1. **Tasks** — every in-scope task is `done`/`cancelled_superseded`, or its real phase and
267
+ next step are in the cursor. Nothing is left "almost done" without a record.
268
+ 2. **Acceptance** — every done task's acceptance criteria carry verification evidence on
269
+ disk (command + output). Never waived, never assumed.
270
+ 3. **Findings** — every review/plan finding is dispositioned: fixed, or recorded as
271
+ `changes_requested`/`needs_breakdown` with its open signature. Nothing silently open.
272
+ 4. **Jobs** — every spawned agent/background job is awaited through the host's own
273
+ mechanics (agent task result, background-shell output) and its report is consumed into
274
+ run state before the next step. NEVER spawn a second job for work a live job is
275
+ already doing — await the live one and consume its result.
276
+ 5. **Independent work** — a blocked or waiting branch never strands independent tasks:
277
+ they ran first (Autonomy Contract).
278
+ 6. **Integration** — landed work is committed (scoped `--only` commits); worktrees and
279
+ branches are cleaned, or every survivor is named in the retained-reason report.
280
+ 7. **Release** — the run's single push (R5) happened, or the reason it did not is named.
281
+ 8. **Consumer** — when a task or the goal names consumer/release evidence, it is recorded;
282
+ a missing consumer gate is work remaining, not a stop.
283
+ 9. **Pause** — a pause (`Paused: yes`, set via `ukit handoff-clear` or an explicit user
284
+ instruction) releases the session: the backlog is retained, completion is never
285
+ minted, and nothing resumes until an explicit instruction lifts the pause.
286
+ 10. **Blocker** — `HANDOFF FULLSTACK BLOCKED` only when every remaining task shares one
287
+ valid external blocker, evidence and attempted fixes are recorded, and no safe local
288
+ work exists.
289
+
290
+ **Turn wait ≠ run done.** If reconciliation leaves a live job running, a host async
291
+ result pending, or any checklist item open, the correct outcome is a **turn wait**: bound
292
+ the wait with the host's own mechanics, write the CHECKPOINT block above (cursor updated:
293
+ YES), and keep the run alive. A turn wait is never `Phase: done` and never claims
294
+ completion. If the wait ends in a compaction, the cursor plus the SessionStart resume
295
+ hook continue the run — never a manual `/compact` instruction loop. If Ready independent
296
+ work exists, select and run it first; a turn wait is only for an actual pending host event
297
+ with no runnable independent scope. **Pause** (`Paused: yes`) and **cancel** are releases,
298
+ not completion: they emit no terminal line and mint nothing. **Blocked** is a terminal
299
+ release, not done: `HANDOFF FULLSTACK BLOCKED` is emitted only when no safe local work
300
+ remains. **Run done** is only §0's `HANDOFF FULLSTACK COMPLETE` after F4, with the checklist
301
+ green item by item. The Final Report states scope-complete and correct termination as two
302
+ separate facts.
303
+
304
+ **Completed runs are not restarted by their own echo.** If this session is re-invoked (a
305
+ stale watchdog job, a repeated prompt, a queued wakeup) and `RUN.md` still reads
306
+ `Phase: done` with its ExitPredicate satisfied, the invocation is a **no-op**: re-verify
307
+ the predicate cheaply, re-emit the completion report if one is due, disarm the stale
308
+ watchdog job, and stop. A new cycle starts ONLY from a new explicit user request — never
309
+ from the run's own completion echo.
310
+
229
311
  ---
230
312
 
231
313
  ## Phase 0 — Sweep & Inventory (before planning)
@@ -256,7 +338,15 @@ work, not only the current plan:
256
338
  so it is folded in here like any legacy blueprint and is never silently excluded.
257
339
  Backlog items do not count toward `index:all-done` / `ExitPredicate`, so they never block completion. Only
258
340
  an explicit slug in the invocation drains one (one blueprint per invocation). The
259
- create phase of this command applies the same advisor intake as `/ukit:handoff-create`.
341
+ create phase of this command applies the same advisor intake as `/ukit:handoff-create`
342
+ — including the SOURCE snapshot (`node .claude/ukit/index/source-snapshot.mjs
343
+ <original-path> docs/AI_HANDOFF/SOURCE.md`, or `source snapshot MISSING` stated in
344
+ PLAN/LEDGER when it cannot run) and the plan-count rule: an owner-stated plan count is
345
+ delivered as that many real plans (the first under the planning root, each further one
346
+ its own `docs/AI_HANDOFF/queued/<slug>/` blueprint with its own SPEC.md/PLAN.md/tasks/;
347
+ labels inside one PLAN never satisfy a stated count; verify mechanically with
348
+ `node .claude/ukit/index/plan-count.mjs docs/AI_HANDOFF <N>` → `PLAN_COUNT: ok (<found>/<N>)`;
349
+ if impossible, record an explicit owner-decision item).
260
350
  6. `git status` / `git diff` — uncommitted work-in-progress that must be finished or
261
351
  checkpointed, never silently dropped.
262
352
 
@@ -264,10 +354,19 @@ The inventory feeds P2: the planner either schedules every discovered item or re
264
354
  it is out of scope (§1/§2 of PLAN.md). Silent omission is a plan defect — a queued
265
355
  blueprint dropped without either scheduling or a recorded reason is exactly that defect.
266
356
 
267
- > **Never overwrite a live run to consume a queued blueprint.** A blueprint is folded in
268
- > only through P2's normal plan-write path, and only when no run is mid-flight; on a
269
- > Resume (RUN.md `Phase:` not `done`/`blocked`) the run continues from its own cursor and
270
- > leaves the queued blueprint untouched for the next cycle.
357
+ **Resume gates before planning.** If INDEX.md has `needs_breakdown` rows and PLAN.md has no
358
+ `PLAN_REVIEW: Approved`, a previous planning run died before both gates completed: do NOT
359
+ re-intake the request, do NOT re-run the advisor chain, do NOT rewrite SPEC/PLAN/tasks, and
360
+ never overwrite the existing plan on this path. Run only the missing gates on the existing
361
+ plan — the per-task validator (`--record`, P2 step 5) for tasks lacking a recorded
362
+ `Validator:` line, and the P2.5 independent review — then flip per the ready gate and
363
+ continue from P3. If a gate cannot run, leave the statuses as they are and name the missing
364
+ gate in INDEX.md and ACTIVE.md.
365
+
366
+ > **Never overwrite a live run to consume a queued blueprint.** Fold only through P2's
367
+ > normal plan-write path. On Resume, continue an already-authorized fold recorded in the
368
+ > cursor's frozen scope and `Next:`; reconcile partial writes and existing jobs first.
369
+ > Do not admit unrelated queued blueprints: leave those untouched for the next cycle.
271
370
 
272
371
  **Recovery rule — stuck task records.** For every `pending`, stale `in_progress`, or
273
372
  `blocked` task whose record cannot be cleanly resumed (invalid state, orphaned worktree
@@ -294,10 +393,12 @@ The run must keep itself alive without the human watching.
294
393
  (`handoff.fullstack.stopGateMaxStalledBlocks`, default 12) releases the session if the
295
394
  cursor has genuinely stopped advancing — the escape hatch, not the norm — and its
296
395
  release advisory reports the predicate state, so a plateau is visible, not silent.
297
- - **Scheduled wakeup (when the harness offers one):** arm it at run start — Claude Code:
298
- `CronCreate` a ~`handoff.fullstack.idleWatchdogMin`-minute (default 5) session job with
299
- prompt `Resume HANDOFF FULLSTACK from docs/AI_HANDOFF/RUN.md — continue the Next: step`;
300
- `/loop`-style tools: the equivalent interval. Cancel/let it expire once `Phase: done`.
396
+ - **Scheduled wakeup (when the harness offers one):** use the supported host event wait, not
397
+ a polling job. Do not create a duplicate job: arm at most one resume wakeup while a real
398
+ host event is pending, and cancel it on pause, cancel, blocker, or completion
399
+ (`Phase: done` / `blocked` / `Paused: yes`). Claude Code's supported mechanics are the
400
+ Stop gate and SessionStart resume hook; `CronCreate` is used only when the harness offers no
401
+ event wait.
301
402
  - **Harnesses with neither:** treat EVERY activation as a watchdog recovery turn — read
302
403
  RUN.md first, rescan the inventory, continue `Next:`.
303
404
 
@@ -335,14 +436,20 @@ Return a compact summary. Do NOT write any files yet.
335
436
  The planner agent does the following (use P1 summary — do NOT re-read files):
336
437
 
337
438
  1. **Guard — check INDEX statuses:**
338
- - All tasks are `ready` (planning only) → **only an explicit amendment may overwrite**: when the human explicitly names this plan to amend, first copy every prior file (PLAN.md, SPEC.md, LEDGER.md, NOTES.md, SOURCE.md, tasks/TASK-*.md, when present) to the next unused `amendments/rev-<NN>/` (scan existing rev dirs, take max+1, never reuse one). Then compose the revised PLAN.md in full: carry the existing `## Amendment History` forward and append this amendment's entry (prior review rounds and verdicts; prior requirement, decision and task versions with what changed and why; each change's `invalidated` evidence: tasks, executor reports, verdicts that no longer hold). Write the revised PLAN.md only after that entry is in the composed text, so the overwrite can never drop the history. An **independent new request** is NOT an amendment: write its plan under `docs/AI_HANDOFF/queued/<slug>/` (the queued lane, see Phase 0) and never overwrite the existing canonical plan.
439
+ - **Resume gates — `needs_breakdown` rows and PLAN.md without `PLAN_REVIEW: Approved`:**
440
+ a previous planning run died before both gates. Never re-intake and never rewrite
441
+ SPEC/PLAN/tasks, never overwrite the existing plan. Run only the missing gates on the
442
+ existing plan — the per-task validator (`--record`, step 5 below) for tasks lacking a
443
+ recorded `Validator:` line and the P2.5 independent review — flip per the ready gate,
444
+ and report; the orchestrator continues from P3.
445
+ - All tasks are `ready` (planning only) → **only an explicit amendment may overwrite**: when the human explicitly names this plan to amend, first copy every prior file (PLAN.md, SPEC.md, LEDGER.md, NOTES.md, SOURCE.md, tasks/TASK-*.md, when present) to the next unused `amendments/rev-<NN>/` (scan existing rev dirs, take max+1, never reuse one). Then run the mechanical guard ONCE — `node .claude/ukit/index/amend-guard.mjs docs/AI_HANDOFF PLAN.md SPEC.md`, naming every file about to be rewritten — and proceed only on `AMEND_GUARD: ok` (the checker is mechanical; its invocation is prose). Then compose the revised PLAN.md in full: carry the existing `## Amendment History` forward and append this amendment's entry (prior review rounds and verdicts; prior requirement, decision and task versions with what changed and why; each change's `invalidated` evidence: tasks, executor reports, verdicts that no longer hold). Write the revised PLAN.md only after that entry is in the composed text, so the overwrite can never drop the history. An **independent new request** is NOT an amendment: write its plan under `docs/AI_HANDOFF/queued/<slug>/` (the queued lane, see Phase 0) and never overwrite the existing canonical plan.
339
446
  - Any task has status `pending_review`, `changes_requested`, `merge_conflict`, or `blocked` → **do not overwrite, and do not stop either.** Mid-flight work exists. Skip the rest of P2 entirely, write the run cursor with `Phase: I1`, and hand control back to the orchestrator to resume from Phase 3 with the surviving tasks (see Resume in the Autonomy Contract). Overwriting is what is unsafe here — stopping is not required.
340
447
  - No tasks → fresh cycle, proceed.
341
448
 
342
- 2. **Resolve base branch:**
343
- ```bash
344
- BASE=$(git symbolic-ref --short HEAD)
345
- ```
449
+ 2. **Resolve base branch:** run ONE simple command — `git symbolic-ref --short HEAD` — and
450
+ use the printed branch name as a literal (`<base-branch>`) in ACTIVE.md's `Base:` line
451
+ and in every later command (worktree creation, final push). No assignment, no command
452
+ substitution, no compound.
346
453
 
347
454
  3. **Write `docs/AI_HANDOFF/SPEC.md`** — the detailed implementation spec, from
348
455
  `template_project/docs/AI_HANDOFF/SPEC.md`'s section list (or RULES.md §Spec). It must be
@@ -370,16 +477,36 @@ The planner agent does the following (use P1 summary — do NOT re-read files):
370
477
  Every task MUST have:
371
478
  - Spec references (SPEC.md section IDs this task implements)
372
479
  - Target Files (exact paths — no two tasks in same wave share a file)
373
- - Dependencies (`TASK-xxx` or `none` — wave structure inferred from this)
374
- - Test Cases (Type | Name | Expected — ≥1 happy + ≥2 edge cases of different kinds)
480
+ - Dependencies (`TASK-xxx` or `none` — wave structure inferred from this; a source delivery-order qualifier like "after import works" IS a dependency, name its source line)
481
+ - Test Cases (Type | Name | Expected — ≥1 happy + ≥2 edge cases of different kinds; every Expected is ONE deterministic outcome, never "X or nothing")
375
482
  - Test Files (exact paths)
376
- - Verification Commands (runnable shell commands)
483
+ - Verification Commands (runnable shell commands that run the tests — grepping a doc for a literal line such as `Coverage: N/N` is not evidence)
377
484
  - Acceptance Criteria (verifiable checklist)
378
485
  Missing any field → status `needs_breakdown`, never `ready`.
379
-
380
- 6. **Update `docs/AI_HANDOFF/INDEX.md`** — one row per task, `status=ready`. Every
486
+ Write every task file `Status: needs_breakdown` — `ready` is a verdict, not a default —
487
+ and run the task-budget validator on each file as ONE simple command per task, from the
488
+ project root, literal path, no `cd`, no loop, no shell variables, no pipes, no compound:
489
+ ```
490
+ node .claude/ukit/index/task-budget-validator.mjs docs/AI_HANDOFF/tasks/TASK-001.md
491
+ ```
492
+ Repeat the command per task file (eight tasks = eight separate calls). `VERDICT:
493
+ needs_breakdown` → split further, or record a one-line dismissal in the task's
494
+ `## Discussion`. Nothing is `ready` until P2.5 returns `Approved`.
495
+ Right after each `VERDICT: ok`, record it from the tool itself with ONE simple command
496
+ per task — `node .claude/ukit/index/task-budget-validator.mjs --record docs/AI_HANDOFF/tasks/TASK-001.md` — which re-validates and appends
497
+ `Validator: ok <YYYY-MM-DD> <tool-version>` to that task's `## Discussion` thread
498
+ (atomic temp-file + rename, existing BOM and line endings preserved, idempotent — a
499
+ second run never duplicates the line — and it refuses a non-ok verdict, so a
500
+ `needs_breakdown` file is never recorded). A dismissal stays a hand-written one-liner:
501
+ `Validator: dismissed <YYYY-MM-DD> — <reason>`. Verdicts live on disk, not in session
502
+ memory: compaction must not erase a gate.
503
+
504
+ 6. **Update `docs/AI_HANDOFF/INDEX.md`** — one row per task, starting
505
+ `status=needs_breakdown`; P2.5's `Approved` verdict is what sets `ready` (every
381
506
  unfinished item from the Phase 0 sweep is either a row here or superseded by a
382
- `-R<n>` recovery row.
507
+ `-R<n>` recovery row). If the run ends before both gates completed (budget exhausted,
508
+ command denied, interruption), the rows stay `needs_breakdown`, and INDEX.md and
509
+ ACTIVE.md must say which gate is missing.
383
510
  Then **verify the write** (read back the new rows).
384
511
 
385
512
  7. **Update `docs/AI_HANDOFF/ACTIVE.md`:**
@@ -390,6 +517,10 @@ The planner agent does the following (use P1 summary — do NOT re-read files):
390
517
  Tasks: <N> total
391
518
  Status: planning_done — ready for executor
392
519
  ```
520
+ When the gates have not all passed, write the honest state instead:
521
+ `Status: planning_incomplete — tasks not ready: <validator | plan review>` (a
522
+ human-readable ACTIVE.md marker only — machine readers parse INDEX.md rows and
523
+ task-file `- Status:` lines, never write `planning_incomplete` into those).
393
524
  Then **verify the write** (read back the `Status:` line).
394
525
 
395
526
  8. **Write `ExitPredicate:` into `docs/AI_HANDOFF/RUN.md`** — the mechanical definition of
@@ -419,9 +550,9 @@ The gate still does its job: two independent opus passes plus one escalation pas
419
550
 
420
551
  **Claude Code — MANDATORY, do this before anything else in P2.5:** call the Agent tool with `subagent_type: "code-reviewer"` (omp: the `task` tool with `agent: "code-reviewer"`), passing `REVIEW_TARGET_TYPE=plan` and the paths to `docs/AI_HANDOFF/PLAN.md` AND `docs/AI_HANDOFF/SPEC.md`. This MUST be a separate agent invocation from P2's `handoff-planner` call (fresh context) — same-session self-review defeats the purpose of an independent gate.
421
552
 
422
- 1. Reviewer reads `SPEC.md` + `PLAN.md` plus the plan's sources, starting from the original: `SOURCE.md` (the verbatim original bytes; verify the recorded sha256 against them; for chat input, the durable verbatim message origin stands in for the file), then `LEDGER.md` (classification of every requirement), `NOTES.md` (optional source-only notes, when present; a missing note is caught because the chain starts at SOURCE, not at NOTES), the `tasks/TASK-*.md` files of the plan, and the current source the plan's Target Files touch (no diff, no executor report). It compares the chain SOURCE → classification (LEDGER) → tasks (acceptance and verification), and NOTES are checked against the same chain. Each `feasible`/`adapted` row maps to a task with acceptance and a verification command; it checks that every `feasible`/`adapted` row and every requirement not explicitly deferred, blocked, or classified as rejected/proposal/example is covered by a task with acceptance and verification, and checks Completeness / Consistency / Clarity / Scope / YAGNI plus the spec quality gate — every requirement testable, every fullstack layer covered, dependencies explicit, legacy sweep included, no vague instruction left ("improve UI" without defined behavior fails) — see `.claude/agents/code-reviewer.md` → Spec/Plan Review — and appends its verdict to PLAN.md's `## Plan Review Log` (new round entry, prior rounds kept).
553
+ 1. Reviewer reads `SPEC.md` + `PLAN.md` plus the plan's sources, starting from the original: `SOURCE.md` (the verbatim original bytes; verify the recorded sha256 against them; for chat input, the durable verbatim message origin stands in for the file), then `LEDGER.md` (classification of every requirement), `NOTES.md` (optional source-only notes, when present; a missing note is caught because the chain starts at SOURCE, not at NOTES), the `tasks/TASK-*.md` files of the plan, and the current source the plan's Target Files touch (no diff, no executor report). It compares the chain SOURCE → classification (LEDGER) → tasks (acceptance and verification), and NOTES are checked against the same chain. Each `feasible`/`adapted` row maps to a task with acceptance and a verification command; it checks that every `feasible`/`adapted` row and every requirement not explicitly deferred, blocked, or classified as rejected/proposal/example is covered by a task with acceptance and verification, and checks Completeness / Consistency / Clarity / Scope / YAGNI plus the spec quality gate — every requirement testable, every fullstack layer covered, dependencies explicit, legacy sweep included, no vague instruction left ("improve UI" without defined behavior fails) — see `.claude/agents/code-reviewer.md` → Spec/Plan Review — and returns its verdict block; the planner appends it with `Edit` to PLAN.md's `## Plan Review Log` (new round entry, prior rounds kept).
423
554
  2. `Issues Found` → route back to P2: `handoff-planner` revises `PLAN.md` and the affected `TASK-xxx.md` files to address every finding, then re-submit for one more P2.5 review round — subject to the loop cap above.
424
- 3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer, then proceed to P3.
555
+ 3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer. Before any flip, run the mechanical ready gate ONCE — `node .claude/ukit/index/ready-gate.mjs docs/AI_HANDOFF` — and require `READY_GATE: ok`; any `tasks not ready: …` / `index/task mismatch …` line names the exact gap to fix and re-run, and no task flips while it fails. That verdict is the second readiness gate: flip ONLY the tasks whose task file's `## Discussion` records `Validator: ok <date>` (or `Validator: dismissed <date> — <reason>`) to `Status: ready` in that task file and in `INDEX.md` — re-read each task file from disk to decide, never from session memory; a task without the recorded `Validator:` line stays `needs_breakdown` (a verdict held only in the session does not count) — and set ACTIVE.md to `Status: planning_done — ready for executor` — P3 and the I-phase only ever collect `ready` tasks, so a skipped flip stalls the whole run. Then proceed to P3.
425
556
 
426
557
  > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model in a **separate** chat/session from P2, paste PLAN.md, review using the Spec/Plan Review checklist in `.claude/agents/code-reviewer.md`.
427
558
 
@@ -515,11 +646,20 @@ leaves worktrees behind. Batching only ever narrows a wave, never reorders acros
515
646
 
516
647
  For each wave:
517
648
 
518
- **3a — Create worktrees** (one per task, from `$BASE`):
649
+ **3a — Create worktrees** (one per task, from the `<base-branch>` literal recorded at P2 — ACTIVE.md `Base:`):
650
+ Under `Worktree-Policy: existing-only`, raw worktree mutation and Agent isolation remain forbidden.
651
+ Only an explicit owner-authorized RUN.md entry such as
652
+ `Worktree-Allow: TASK-003 handoff/task-003 .worktrees/task-003 owner-20261025`
653
+ permits that frozen task through `node .claude/ukit/index/allocate-task-worktree.mjs <absolute-project-root> TASK-003`.
654
+ The helper exclusively records task/branch/path/claim/base before allocation under the claims lock;
655
+ an existing intent refuses reallocation even after failure. Resume only that task's verified retained
656
+ worktree; never repurpose/delete a tree, allocate reviewer/investigator trees, or infer cleanup permission.
657
+ Without this restricted policy, use the normal command:
519
658
  ```bash
520
- git worktree add -b handoff/task-xxx .worktrees/task-xxx $BASE
521
- # (omit -b if branch already exists)
659
+ git worktree add -b handoff/task-xxx .worktrees/task-xxx <base-branch>
522
660
  ```
661
+ (Omit `-b` when the branch already exists. One simple command per worktree — no variable,
662
+ no compound.)
523
663
 
524
664
  **3b — Run the batch in parallel** — one code-model agent per task in the batch (at most `handoff.maxParallelAgents`), each in its own worktree. Each agent:
525
665
  ```
@@ -527,12 +667,12 @@ Read docs/AI_HANDOFF/tasks/TASK-xxx.md
527
667
 
528
668
  TDD — mandatory:
529
669
  1. Write tests from §Test Cases
530
- cd .worktrees/task-xxx && <test command>
670
+ run <test command> from the worktree root (your cwd IS .worktrees/task-xxx — no cd)
531
671
  Confirm RED — paste the actual failing output, don't just assert it happened
532
672
  (immediately GREEN → test is wrong — flag this)
533
673
  2. Implement → run → confirm GREEN
534
674
  3. Run §Verification Commands inside the worktree:
535
- cd .worktrees/task-xxx && <each verification command>
675
+ run <each verification command> from the worktree root — no cd, no compound
536
676
  Paste full output.
537
677
 
538
678
  Milestone commits INSIDE your own worktree (e.g. `handoff/task-xxx`) are REQUIRED by the
@@ -570,45 +710,67 @@ run mid-pipeline.
570
710
 
571
711
  Landing is **task-scoped, base-relative and receipt-backed** — never an ad-hoc cp loop.
572
712
  `land-worktree.mjs` snapshots the source worktree's FINAL content against the immutable
573
- `$BASE` (committed milestone + staged + unstaged + nonignored untracked), so committed and
713
+ `<base-branch>` head (committed milestone + staged + unstaged + nonignored untracked), so committed and
574
714
  staged work is never dropped, deletions and rename origins are applied, and binary /
575
715
  executable / symlink semantics and unusual filenames (space / newline / literal backslash)
576
716
  survive. The helper refuses on any destination conflict, scope drift or identity drift
577
717
  **before mutating anything** and writes no receipt on refusal.
578
718
 
579
719
  For **PASS + EXECUTOR_MODEL present:**
580
- ```bash
581
- TASK="TASK-xxx"
582
- WORKTREE=".worktrees/task-xxx"
583
-
584
- # Scope = the exact task-approved target paths (both rename endpoints).
585
- # Written outside the source worktree AND outside the target set.
586
- cat > ".worktrees/$TASK-scope.json" <<JSON
587
- {
588
- "schemaVersion": 1,
589
- "taskId": "$TASK",
590
- "baseCommit": "$(git rev-parse $BASE)",
591
- "sourceRoot": "$(git -C "$WORKTREE" rev-parse --show-toplevel)",
592
- "destinationRoot": "$(git rev-parse --show-toplevel)",
593
- "sourceHead": "$(git -C "$WORKTREE" rev-parse HEAD)",
594
- "destinationHead": "$(git rev-parse HEAD)",
595
- "targetPaths": ["<each approved path>"]
596
- }
597
- JSON
598
-
599
- node .claude/ukit/index/land-worktree.mjs \
600
- --scope ".worktrees/$TASK-scope.json" \
601
- --receipt "docs/AI_HANDOFF/benchmark/$TASK-landing.json"
602
- # exit 0 → landed (receipt written); exit 2 → refused, both repos untouched;
603
- # exit 1 → apply/receipt failure, source retained, never a success claim.
604
- # After each exit-0 landing, checkpoint-commit the landed paths (receipt stays outside the target set)
605
- # BEFORE landing the next task: the helper refuses a destination with tracked modifications
606
- # (destination-dirty), so uncommitted landed work would block every later task in the wave.
607
- git add -- <landed paths>
608
- git commit --only -m "checkpoint: $TASK landed" -- <landed paths>
609
-
610
- # update INDEX.md: status → pending_review
611
- ```
720
+
721
+ 1. Write the scope file with the **Write tool** (never a shell heredoc, no variable) to
722
+ `docs/AI_HANDOFF/benchmark/TASK-xxx-scope.json` — every field a literal. Get each value with ONE simple
723
+ command and paste the printed output: `git rev-parse <base-branch>` (baseCommit),
724
+ `git -C .worktrees/task-xxx rev-parse --show-toplevel` (sourceRoot),
725
+ `git rev-parse --show-toplevel` (destinationRoot),
726
+ `git -C .worktrees/task-xxx rev-parse HEAD` (sourceHead), `git rev-parse HEAD`
727
+ (destinationHead).
728
+ ```json
729
+ {
730
+ "schemaVersion": 1,
731
+ "taskId": "TASK-xxx",
732
+ "baseCommit": "<base-branch head sha>",
733
+ "sourceRoot": "<absolute worktree root>",
734
+ "destinationRoot": "<absolute project root>",
735
+ "sourceHead": "<worktree HEAD sha>",
736
+ "destinationHead": "<project HEAD sha>",
737
+ "targetPaths": ["<each approved path>"]
738
+ }
739
+ ```
740
+ Scope = the exact task-approved target paths (both rename endpoints); the file is
741
+ written outside the source worktree AND outside the target set. This is coordinator metadata,
742
+ not task implementation: keep it in the docs benchmark directory so the main-session
743
+ ownership guard remains intact.
744
+ 2. Land with ONE simple command, literal paths:
745
+ `node .claude/ukit/index/land-worktree.mjs --scope docs/AI_HANDOFF/benchmark/TASK-xxx-scope.json --receipt docs/AI_HANDOFF/benchmark/TASK-xxx-landing.json`
746
+ — exit 0 → landed (receipt written); exit 2 → refused, both repos untouched; exit 1 →
747
+ apply/receipt failure, source retained, never a success claim. Landing is self-fencing: it reads the destination claims store under the claims lock held through apply+receipt, and exits 2 `worker-not-terminated` while any delegated worker claim for the task remains (handback must release it; lease expiry does not), or `claims-unreadable`/`claims-busy` (fail closed). Never fabricate a claim or receipt to pass.
748
+ 3. After each exit-0 landing, checkpoint-commit the landed paths (receipt stays outside
749
+ the target set) BEFORE landing the next task: the helper refuses a destination with
750
+ tracked modifications (destination-dirty), so uncommitted landed work would block every
751
+ later task in the wave.
752
+ ```bash
753
+ git add -- <landed paths>
754
+ git commit --only -m "checkpoint: TASK-xxx landed" -- <landed paths>
755
+ ```
756
+ 4. Update INDEX.md: status → pending_review (the orchestrator writes it; agents never do).
757
+
758
+ **Already-applied / divergent-history recovery:** normal landing steps above do not turn
759
+ all exit-0 helper results into landed status. `--adopt-applied` requires complete source
760
+ snapshot blob+mode equality. Where preserved task-record history differs, do not repeat a
761
+ known-failing adoption, copy metadata, omit scope, or fabricate a landed receipt. Explicit
762
+ owner-authorized recovery uses `--reconcile-metadata <proof-json> --preflight --scope
763
+ <scope-json> --receipt <new-json>` for ALL affected full scopes first, then the same command
764
+ without `--preflight`. File evidence is hash-pinned and colocated with the proof in its audit
765
+ directory; independently audit semantic provenance, which hashes alone cannot establish.
766
+ Consume `receiptKind: metadata-reconciliation`, `status: reconciled` only with
767
+ `completion:false`, `cleanupEligible:false` and matching current HEAD/snapshot/scope.
768
+ It resolves specifically verified integration-history debt, NOT task completion or normal
769
+ landing. Retain blocked status until independent current-source review and missing gates
770
+ justify progression; continue those gates on destination source without another equality
771
+ adoption attempt. No automatic pending_review/done, cleanup, archive or completion authority
772
+ comes from reconciliation. Preserve both histories and source worktrees; separate acceptance,
773
+ archive and cleanup gates and owner prohibitions remain binding.
612
774
 
613
775
  For **FAIL:**
614
776
  ```bash
@@ -701,10 +863,9 @@ git status # should show modified/new files, no handoff branches/worktrees
701
863
  git diff --stat # summary of all changes
702
864
  ```
703
865
 
704
- Because 3d commits each wave, the changes under review are in **commits since the plan commit**, not only in the working tree. Resolve the review range once and use it everywhere below:
866
+ Because 3d commits each wave, the changes under review are in **commits since the plan commit**, not only in the working tree. Resolve the review range once: run ONE simple command — `git log --format=%H --grep='^handoff: plan' -n 1` — and use the printed hash as a literal (`<plan-commit>`) everywhere below:
705
867
  ```bash
706
- PLAN_COMMIT=$(git log --format=%H --grep='^handoff: plan' -n 1)
707
- git diff $PLAN_COMMIT # all handoff changes: committed waves + anything uncommitted
868
+ git diff <plan-commit> # all handoff changes: committed waves + anything uncommitted
708
869
  ```
709
870
 
710
871
  Classify the review by what the diff can show — an empty diff is NOT automatically "implement incomplete":
@@ -720,7 +881,7 @@ Never make fake edits or fake tests to satisfy an empty diff, and never lower ac
720
881
 
721
882
  **Batch the review set — mandatory.** Read `handoff.maxParallelAgents` from `.ukit/storage/config.json`. If more `pending_review` tasks exist than that, split into consecutive batches of at most that many; finish one batch's verdicts (R2–R4, appended to each task file) before starting the next. The cap counts child workers of ONE batch/review set, summed across roles (implementers and reviewers together); the main session is outside it, and it is not a session-wide limit. It is prompt-level guidance: no hook counts children, and the host's own concurrency limit is separate.
722
883
 
723
- **Claude Code — MANDATORY, do this before anything else in R2–R4:** for each batch, call the Agent tool once per `pending_review` task **in parallel** (at most `handoff.maxParallelAgents`), each with `subagent_type: "code-reviewer"` (omp: the `task` tool with `agent: "code-reviewer"`, likewise invoked once per task in the batch, not once per wave). Reviewer agents only read the diff and append a verdict to their own task file — no worktree, no shared write target — so running them in parallel carries none of Phase 3's file-conflict risk. Do NOT review the diff yourself in the current session — this step is contracted to the strong tier (opus/unic-smart) and MUST differ from the executor's model, which only the spawned agent's frontmatter model guarantees.
884
+ **Claude Code — MANDATORY, do this before anything else in R2–R4:** for each batch, call the Agent tool once per `pending_review` task **in parallel** (at most `handoff.maxParallelAgents`), each with `subagent_type: "code-reviewer"` (omp: the `task` tool with `agent: "code-reviewer"`, likewise invoked once per task in the batch, not once per wave). Reviewers return the complete verdict block (≤30 lines), without shell writes; the orchestrator appends it with `Edit` to the task file, preserving prior rounds, before aggregation or status updates. No reviewer writes INDEX or task files; serial persistence avoids shared-write races. Do NOT review the diff yourself in the current session — this step is contracted to the strong tier (opus/unic-smart) and MUST differ from the executor's model, which only the spawned agent's frontmatter model guarantees.
724
885
 
725
886
  The spawned reviewer agent reads `EXECUTOR_MODEL` from each task file `## Executor Report`:
726
887
 
@@ -742,7 +903,7 @@ If any command fails → `VERDICT: CRITICAL` (`NEXT_STATUS_FOR_INDEX: critical_b
742
903
  ### R4 — Review unified diff + append verdict (strong model)
743
904
 
744
905
  ```bash
745
- git diff $PLAN_COMMIT # every handoff change: committed waves + working tree
906
+ git diff <plan-commit> # every handoff change: committed waves + working tree
746
907
  git status # overview of modified/new/deleted files
747
908
  ```
748
909
 
@@ -750,7 +911,7 @@ Review as one unified diff — correctness, regression risk, security, edge case
750
911
 
751
912
  Stage gate (unic-decision): reviewers still generate findings; when `decisionPlane.families.review.stage` is not `off`, the emitted verdict goes through `node .claude/ukit/index/review-verdict.mjs` (`review.verdict.v1`; `--panel` for `review.panel-verdict.v1`/`review.finding-bucket.v1`) — the deterministic severity aggregate stays authoritative at `off` or on adapter failure.
752
913
 
753
- Append verdict to each task file:
914
+ Return the verdict for orchestrator persistence to each task file:
754
915
  ```
755
916
  ## Reviewer Verdict
756
917
  VERDICT: APPROVED | APPROVED-WITH-MINOR | CHANGES-REQUESTED | CRITICAL
@@ -758,6 +919,10 @@ REVIEWER_MODEL: <your exact model ID>
758
919
  EXECUTOR_MODEL: <from Executor Report>
759
920
  REVIEW_KIND: product | integration-evidence | status-only
760
921
  VERIFICATION_RERUN: PASS | FAIL | NOT_RUN | N/A
922
+ command: <exact command, or ->
923
+ result: <actual pass/fail counts or NOT_RUN/N/A with reason>
924
+ TEST_PLAN_COVERAGE: all-followed | partial — <gaps> | missing — <gaps>
925
+ NOTES: <acceptance limitations, or none>
761
926
  FINDINGS:
762
927
  critical: <file:line — what fails> | none
763
928
  important: <file:line — risk> | none
@@ -767,7 +932,7 @@ NEXT_STATUS_FOR_INDEX: approved | approved_minor | changes_requested | critical_
767
932
 
768
933
  `VERDICT:` uses the aggregator's canonical hyphen vocabulary — underscore spellings (`changes_requested`, `critical_block`, `approved_with_minor`) parse to the same verdicts, so a blocking reviewer is never dropped as unparsed. `NOT_RUN` = the required re-run never executed in your session; `FAIL` = it executed and failed; either blocks approval. `N/A` is legitimate only when this review has no executable required checks (`command: -` or none) — an `N/A` beside a declared executable `command:` counts as `NOT_RUN`. `REVIEW_KIND` comes from the R1 classification; it scopes only the implementation-TDD evidence (new tests + RED_OUTPUT) — required executable checks and the task's original acceptance criteria are never waived, and approving an evidence review never marks product acceptance met.
769
934
 
770
- Then return to the orchestrator **at most 6 lines** — the full verdict is already on disk:
935
+ Return this routing header followed by the complete verdict block above; the orchestrator persists the block with `Edit` before reading it back and advancing R4.5:
771
936
  ```
772
937
  TASK: TASK-xxx
773
938
  VERDICT: approved | approved_minor | changes_requested | critical_block
@@ -776,7 +941,7 @@ VERIFICATION_RERUN: PASS | FAIL | NOT_RUN | N/A (+ one-line reason)
776
941
  BLOCKING: <one line per critical/important finding, or "none">
777
942
  ```
778
943
  The return `VERDICT:` carries the NEXT_STATUS_FOR_INDEX vocabulary; the on-disk block's `VERDICT:` field uses the canonical hyphen vocabulary above.
779
- Do not paste the diff, the findings prose, or verification logs back into the orchestrator.
944
+ Return actionable findings inside the bounded block, not the diff or raw verification logs.
780
945
 
781
946
  ### R4.5 — Auto-fix loop (max 2 rounds)
782
947
 
@@ -824,12 +989,14 @@ once — this is the run's only push:
824
989
  ```bash
825
990
  git add -- <run-owned paths>
826
991
  git commit --only -m "handoff: implement <goal>" -- <run-owned paths> # skip if nothing left to commit
827
- git push origin $BASE
992
+ git push origin <base-branch>
828
993
  ```
829
994
 
830
- Replace `<goal>` with the one-sentence goal from ACTIVE.md. Push without asking — `git push`
831
- is in the settings `allow` list precisely so a one-shot run never stalls at the last step.
832
- Force-push stays denied, so this can only ever fast-forward.
995
+ Replace `<goal>` with the one-sentence goal from ACTIVE.md. Push only when the user's explicit
996
+ delivery scope authorizes it, and only within the host's permissions. A settings `allow` entry
997
+ is host configuration, not user authorization to publish, so it never licenses a push by itself.
998
+ Without explicit delivery scope the run commits locally and records "not pushed" in the Final
999
+ Report. Force-push stays denied, so any push can only fast-forward.
833
1000
 
834
1001
  **If some tasks are `blocked`:** still push. The approved work is reviewed, tested, and
835
1002
  committed; withholding it helps no one, and the per-wave commits make any subset revertible.
@@ -977,10 +1144,11 @@ fixes, local work completed, and the recovery instructions for the next session.
977
1144
 
978
1145
  Then, as the last line of the run:
979
1146
 
980
- > Cycle finished. Run `/compact` before starting the next cycle — this session is carrying
981
- > the whole pipeline's history and the next cycle deserves a clean window.
1147
+ > Cycle finished. State is in git, `INDEX.md` and `RUN.md`; the next cycle continues from
1148
+ > the cursor (a `/compact` is optional and never required, and never asked while assigned
1149
+ > queue work remains).
982
1150
 
983
- This is the **only** place in the pipeline that may ask for a compaction. Asking at a cycle
984
- boundary costs nothing: all state is in git, `INDEX.md` and `RUN.md`, so a compacted or
1151
+ Do not make a manual `/compact` mandatory at the cycle boundary; compaction is a host choice.
1152
+ Asking at a cycle boundary costs nothing: all state is in git, `INDEX.md` and `RUN.md`, so a compacted or
985
1153
  brand-new session picks the next cycle up with no loss. Asking mid-cycle is forbidden — see
986
1154
  the Autonomy Contract.