@ngockhoale/ukit 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,58 @@
2
2
 
3
3
  All notable changes to UKit are documented here.
4
4
 
5
+ ## 2.6.0 - 2026-09-18
6
+
7
+ handoff-fullstack v2 — autonomous create→implement→review loop that runs to 100%
8
+ completion of all unfinished work, with a mandatory detailed SPEC gate.
9
+
10
+ - **Never-stall Stop gate**: `stop-coordinator.mjs` gained a `handoff-cursor` lane that
11
+ reads `docs/AI_HANDOFF/RUN.md` and blocks stop while `Phase:` is not `done`/`blocked`,
12
+ carrying the cursor's `Next:` step. Liveness breaker releases after
13
+ `handoff.fullstack.stopGateMaxStalledBlocks` (default 12) un-advancing blocks; the lane
14
+ is advisory-on-failure and `stopGateEnabled` disables it. This fixes the observed
15
+ stall where runs went idle after a recap.
16
+ - **Mandatory SPEC.md**: `handoff-create` now writes `docs/AI_HANDOFF/SPEC.md` — a
17
+ 15-section template (FRs with Given/When/Then, fullstack scope, data model, API
18
+ contract, test matrix, acceptance criteria, migration, chosen defaults) — before task
19
+ files. Tasks carry `Spec references`; `handoff-model-guard.sh` hard-blocks fresh task
20
+ creation without a filled SPEC (`handoff.fullstack.specRequired=false` bypasses).
21
+ - **Autonomous loop contract**: only `HANDOFF FULLSTACK COMPLETE` / `HANDOFF FULLSTACK
22
+ BLOCKED` may end a run; `CHECKPOINT — WORK CONTINUING` replaces bare recaps. Phase 0
23
+ sweeps INDEX, task files, HISTORY/archive, `docs/TASKS.md` Ready-for-AI, and
24
+ uncommitted WIP. Stuck tasks recover via `cancelled_superseded` + `TASK-xxx-R<n>`
25
+ replacement tasks. `idleWatchdogMin` (default 5) scheduled wakeups keep the loop
26
+ alive off-Claude-Code; `quietScansRequired` (default 2) guards completion; Phase F
27
+ runs docs sync → `archive/cycle-NN/` → `Phase: done` → marker report.
28
+ - **Agent + command wiring**: `handoff-planner` gained legacy-sweep and SPEC-authoring
29
+ phases; `code-reviewer` reviews SPEC+PLAN against a 7-point spec quality gate;
30
+ `feature-implementer` treats `Spec references` as outranking task-file wording;
31
+ `handoff-implement`/`handoff-review` codify spec-is-the-contract and `-R<n>`
32
+ recovery. `handoff-clear` archives SPEC and must close RUN.md; `handoff-status`
33
+ reports run phase + spec presence.
34
+ - **Config**: `handoff.fullstack.*` keys (`stopGateEnabled`, `stopGateMaxStalledBlocks`,
35
+ `quietScansRequired`, `idleWatchdogMin`, `autoArchive`, `specRequired`) with `_help`
36
+ notes, in both config trees.
37
+
38
+ ## 2.5.1 - 2026-09-18
39
+
40
+ Post-release fixes from C20 reviewer advisories.
41
+
42
+ - **`projectImportant` symlink fallback**: the odd-open-error fallback imported
43
+ `stat` as `lstat`, which follows symlinks — a broken symlink degraded to `missing`
44
+ and a symlink-to-file to `unreadable` instead of the correct `unsafe-type`
45
+ (spec §6.1). Now uses real `lstat`; fixed in `src/core/projectImportant.js` and both
46
+ installed-runtime mirrors (parity-locked).
47
+ - **`inspectProjectImportant` guard**: a non-string `projectRoot` threw `TypeError`
48
+ before the try block instead of degrading to `unreadable`, violating the
49
+ "no documented entry point throws" contract. Guard added (src + mirrors).
50
+ - **Uninstall backup exhaustion surfaced**: when all 101 backup-name candidates are
51
+ occupied, `PROJECT_IMPORTANT.md` was silently preserved without a backup. Now emits
52
+ a `backupWarnings` line telling the user to free a slot and rerun.
53
+ - **Test tightening**: the packed-install smoke now asserts `project-important.sh`
54
+ occupies SessionStart index 0 (spec: must run first); corrected a stale "~5%
55
+ headroom" comment on the unpacked-size ceiling.
56
+
5
57
  ## 2.5.0 - 2026-09-18
6
58
 
7
59
  C20 feature release (14 handoff tasks + 3-lane review): project-owner instructions via a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngockhoale/ukit",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "Install/update an index-first AI workspace for Claude Code, OpenAI Codex, OpenCode, and omp (Oh My Pi).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -17,7 +17,7 @@
17
17
  */
18
18
 
19
19
  import fs from 'node:fs';
20
- import { open, stat as lstat, readFile } from 'node:fs/promises';
20
+ import { open, lstat, readFile } from 'node:fs/promises';
21
21
  import path from 'node:path';
22
22
 
23
23
  import {
@@ -112,6 +112,9 @@ function invalidResult(state) {
112
112
  */
113
113
  export async function inspectProjectImportant(options = {}) {
114
114
  const { projectRoot, config } = options;
115
+ if (typeof projectRoot !== 'string' || projectRoot.length === 0) {
116
+ return invalidResult('unreadable');
117
+ }
115
118
  const target = path.join(projectRoot, PROJECT_IMPORTANT_FILENAME);
116
119
 
117
120
  let handle;
@@ -89,6 +89,10 @@ async function planImportantBackup(projectRoot) {
89
89
  }
90
90
 
91
91
  plan.exhausted = true;
92
+ plan.backupWarnings.push(
93
+ `[UKit] Backup name space exhausted (${IMPORTANT_BACKUP_COLLISION_LIMIT + 1} candidates in use); `
94
+ + `${PROJECT_IMPORTANT_FILENAME} preserved in place without a backup. Free a backup slot and rerun \`ukit uninstall\`.`,
95
+ );
92
96
  return plan;
93
97
  }
94
98
 
@@ -127,17 +127,28 @@ Same model is the most common silent failure. Do not skip this check.
127
127
  ### Inputs you expect
128
128
 
129
129
  - Path to the spec/plan document (e.g. `docs/plans/*.md`). No diff, no task file, no executor report — review the document itself.
130
+ - When invoked from the handoff pipeline you get BOTH `docs/AI_HANDOFF/SPEC.md` and `docs/AI_HANDOFF/PLAN.md`. Review them as one unit: the spec is the contract, the plan is the decomposition. Verdicts still append to PLAN.md's `## Plan Review Log`.
130
131
 
131
132
  ### Review order
132
133
 
133
134
  | Category | What to look for |
134
135
  |---|---|
135
136
  | Completeness | TODO/TBD/placeholders, incomplete sections |
136
- | Consistency | internal contradictions, conflicting requirements |
137
+ | Consistency | internal contradictions, conflicting requirements; SPEC and PLAN contradicting each other |
137
138
  | Clarity | requirements ambiguous enough to cause a wrong build |
138
139
  | Scope | focused enough for one plan, not silently covering multiple subsystems |
139
140
  | YAGNI | unrequested features, over-engineering |
140
141
 
142
+ **Handoff spec quality gate** (only when reviewing `docs/AI_HANDOFF/SPEC.md`):
143
+
144
+ 1. Every functional requirement is testable — Given/When/Then or a command, never "should work".
145
+ 2. Every applicable fullstack layer is covered or explicitly `N/A` with a reason.
146
+ 3. Every FR traces forward to plan scope; nothing in the plan is unbacked by the spec.
147
+ 4. Dependencies between parts are explicit.
148
+ 5. Legacy/unfinished work discovered by the Phase 0 sweep is either planned or recorded out-of-scope.
149
+ 6. Rollback/migration impact is addressed when data or schema changes.
150
+ 7. No vague instruction survives — "improve UI", "faster", "better UX" without defined behavior fails Clarity.
151
+
141
152
  Only flag issues that would cause real problems during implementation planning. Approve unless there are serious gaps that would lead to a flawed plan.
142
153
 
143
154
  ### Output
@@ -19,8 +19,10 @@ reasoning to the parent agent so it can decide whether to re-route.
19
19
  **In Handoff mode you are running unattended — ask nothing.** You were spawned by an
20
20
  orchestrator driving a pipeline; there is no human in your conversation to answer, and a
21
21
  question there is silently dropped while the run stalls. Resolve ambiguity in this order:
22
- the task file → `PLAN.md` → the surrounding code's existing patterns → the choice you would
23
- recommend. Record what you chose and why in the task's `## Discussion` thread. Only a blocker
22
+ the task file → the `Spec references` sections of `SPEC.md` → `PLAN.md` → the surrounding
23
+ code's existing patterns → the choice you would recommend. The spec is the contract; if the
24
+ task file and spec disagree, implement the spec and note it in the task's `## Discussion`
25
+ thread. Record what you chose and why in that thread. Only a blocker
24
26
  outside the repo (missing credential, unreachable service) justifies reporting `FAIL` early —
25
27
  and even then, report it, don't ask about it.
26
28
 
@@ -55,6 +55,35 @@ Before writing any path or command into `PLAN.md` or a task file, verify it:
55
55
  If something cannot be verified, say so in the task's `## Discussion` rather than guessing.
56
56
  A stated unknown costs the executor one read; a wrong path costs it a round.
57
57
 
58
+ ## Phase 0 — Legacy sweep (before writing anything)
59
+
60
+ The plan owns ALL unfinished work, not only the new request. Scan and fold in:
61
+
62
+ - `INDEX.md` rows that are not `done`/`cancelled_superseded`.
63
+ - Task files in stale `in_progress` / `blocked` / `changes_requested` /
64
+ `needs_executor_report` / `needs_breakdown` from dead sessions.
65
+ - `docs/AI_HANDOFF/HISTORY.md` + `archive/` — cycles closed with leftovers.
66
+ - `docs/TASKS.md` — `Ready for AI` items are newly-assigned work.
67
+ - `git status` — uncommitted work-in-progress (finish or checkpoint, never drop silently).
68
+
69
+ Every discovered item becomes either a task row in the new plan or an explicitly recorded
70
+ out-of-scope line in PLAN.md §2. Silent omission is a plan defect.
71
+
72
+ **Recovery:** a stuck task record that cannot be cleanly resumed (orphaned worktree,
73
+ contradicting reports, invalid state) is marked `cancelled_superseded` and replaced by
74
+ `TASK-xxx-R1` (`-R2`, …) carrying the same spec references, acceptance criteria and
75
+ verification — link both files' `## Discussion` threads.
76
+
77
+ ## Phase 0.5 — Write SPEC.md
78
+
79
+ Write `docs/AI_HANDOFF/SPEC.md` from the template at `templates/docs/AI_HANDOFF/SPEC.md`
80
+ (15 sections). The spec is the contract executors implement against — concrete enough that
81
+ nothing is guessed: exact paths, module and API names, schemas, validation rules,
82
+ permissions, empty/error states, migration behavior, test expectations. Every section is
83
+ filled or marked `N/A — <reason>`; every open question is resolved to a chosen default
84
+ recorded in §14. A vague line ("improve UI", "make it faster" with no number) is a spec
85
+ defect — fix it before writing tasks.
86
+
58
87
  ## Phase 1 — Write PLAN.md
59
88
 
60
89
  Write all 7 sections to `docs/AI_HANDOFF/PLAN.md`:
@@ -101,6 +130,7 @@ Use `_TEMPLATE.md` structure (from pre-read context or file).
101
130
 
102
131
  | Field | Rule |
103
132
  |-------|------|
133
+ | Spec references | SPEC.md section/FR IDs this task implements — every task traces to the spec |
104
134
  | Target Files | Exact paths — no two tasks in same wave share a file |
105
135
  | Dependencies | `TASK-xxx` or `none` — wave order is inferred from this |
106
136
  | Test Cases | Type \| Test Name \| Expected — ≥1 happy + ≥2 edge cases of different kinds |
@@ -160,6 +190,7 @@ most chains are ordering preferences that a wide wave 1 would satisfy just as we
160
190
  ```
161
191
  Cycle: <ID> Date: <YYYY-MM-DD> Base: <current HEAD branch>
162
192
  Goal: <1 sentence>
193
+ Spec: docs/AI_HANDOFF/SPEC.md
163
194
  Tasks: <N> total
164
195
  Status: planning_done — ready for executor
165
196
  ```
@@ -179,6 +210,8 @@ catches it:
179
210
  2. Does every task trace back to something in §1/§6? A task nothing asks for is scope creep — cut it.
180
211
  3. Do the tasks together actually deliver §1's success definition, or only the easy part of it? State the gap if there is one.
181
212
  4. Is the *unhappy* path planned — errors, empty input, permissions, migration of existing data — or only the feature?
213
+ 4b. Does every task carry `Spec references` into SPEC.md, and does every SPEC.md FR trace to at least one task? A spec section no task implements is a silent hole.
214
+ 4c. Did the Phase 0 sweep leave anything unplanned — stale tasks, legacy leftovers, Ready-for-AI items, uncommitted WIP — without a §2 out-of-scope line?
182
215
 
183
216
  **Correctness — is anything wrong?**
184
217
  5. Every `Target Files` path verified per Grounding? Any `(new)` file marked as such?
@@ -195,7 +228,7 @@ catches it:
195
228
  Append the result to `PLAN.md`:
196
229
  ```
197
230
  ## Planner Self-Audit
198
- Checklist: 12/12 pass
231
+ Checklist: 14/14 pass
199
232
  Fixed during audit: <what you changed, or "nothing">
200
233
  Known gaps: <what you deliberately left out and why, or "none">
201
234
  ```
@@ -209,6 +242,8 @@ Keep the returned message under 25 lines — the caller may be an orchestrator w
209
242
  budget is the constraint on the whole run. Detail belongs in `PLAN.md`, not in the reply.
210
243
 
211
244
  - Task count + IDs
245
+ - Spec path + one-line coverage statement (`SPEC.md §5 FR-001→TASK-003`, …)
246
+ - Recovery/superseded pairs (`TASK-007 → TASK-007-R1`) | none
212
247
  - Dependency graph (text form: TASK-001 → TASK-003, TASK-002 independent)
213
248
  - Wave plan: `wave 1: N tasks | wave 2: M tasks` — flag it if the graph is mostly a chain
214
249
  - Self-audit result + any `Known gaps`
@@ -37,6 +37,7 @@ Write `docs/AI_HANDOFF/archive/cycle-NNN.md` (if there is anything worth archivi
37
37
  ```
38
38
  # Cycle NNN — <YYYY-MM-DD> — ABORTED
39
39
  ## Summary: cycle was cleared before completion
40
+ ## Spec: <copy SPEC.md — or note its path if archived separately>
40
41
  ## Tasks: <copy INDEX.md table as-is>
41
42
  ```
42
43
  If `archive/` has > 3 files → delete oldest, append 1-line summary to `HISTORY.md`.
@@ -45,8 +46,11 @@ If `archive/` has > 3 files → delete oldest, append 1-line summary to `HISTORY
45
46
 
46
47
  ```
47
48
  PLAN.md → "# PLAN\n_(empty)_"
49
+ SPEC.md → restore the untouched template (keep section headings, clear content)
48
50
  INDEX.md → empty table header only
49
51
  ACTIVE.md → "# ACTIVE\n_(no active cycle)_"
52
+ RUN.md → set `Phase: done` (or delete) — a live non-done cursor makes the Stop gate
53
+ refuse the next session's stops; clearing a cycle MUST close the cursor.
50
54
  tasks/TASK-*.md → delete all (keep _TEMPLATE.md)
51
55
  ```
52
56
 
@@ -69,7 +69,21 @@ The planner agent does the following (use Step 1 summary — do NOT re-read file
69
69
  BASE=$(git symbolic-ref --short HEAD)
70
70
  ```
71
71
 
72
- 3. Write `docs/AI_HANDOFF/PLAN.md` — all 6 sections mandatory:
72
+ 3. Write `docs/AI_HANDOFF/SPEC.md` — the detailed implementation spec (BẮT BUỘC before tasks).
73
+ Follow `docs/AI_HANDOFF/SPEC.md`'s template sections (or `templates/docs/AI_HANDOFF/SPEC.md`
74
+ on a fresh tree): problem/context, goals, non-goals, user journeys, functional requirements
75
+ with Given/When/Then + error cases, fullstack scope (backend, schema/migrations, API
76
+ contract, UI+state, integration, security, performance, observability, deploy/rollback),
77
+ data model, edge cases, test matrix, acceptance criteria, migration steps, open questions
78
+ with chosen defaults, review checklist.
79
+
80
+ The spec must be concrete enough that an executor implements it WITHOUT guessing: exact
81
+ file paths, module names, API methods, statuses, schemas, validation rules, permissions,
82
+ empty/error states, migration behavior, and test expectations. Open questions are
83
+ resolved to a chosen default recorded inline — the plan phase is the only question
84
+ window, so anything left "TBD" becomes a guess downstream.
85
+
86
+ 4. Write `docs/AI_HANDOFF/PLAN.md` — all 6 sections mandatory:
73
87
  - §1 Intent — problem + success definition
74
88
  - §2 Scope — in / out of scope. **Add a constraint**: same-wave tasks must not modify the same file (prevents merge conflicts). If two tasks need the same file, make one depend on the other.
75
89
  - §3 Approach — solution, trade-offs, alternatives rejected
@@ -83,8 +97,9 @@ The planner agent does the following (use Step 1 summary — do NOT re-read file
83
97
  PLANNER_MODEL: <your exact model ID>
84
98
  ```
85
99
 
86
- 4. Create `docs/AI_HANDOFF/tasks/TASK-001.md`, `TASK-002.md`... from `_TEMPLATE.md`
100
+ 5. Create `docs/AI_HANDOFF/tasks/TASK-001.md`, `TASK-002.md`... from `_TEMPLATE.md`
87
101
  Every task MUST have:
102
+ - Spec references (SPEC.md section IDs this task implements)
88
103
  - Target Files (exact paths — no two tasks in same wave share a file)
89
104
  - Dependencies (`TASK-xxx` or `none` — wave structure inferred from this, not stored separately)
90
105
  - Test Cases (Type | Name | Expected — ≥1 happy + ≥2 edge cases of different kinds)
@@ -93,18 +108,19 @@ The planner agent does the following (use Step 1 summary — do NOT re-read file
93
108
  - Acceptance Criteria (verifiable checklist)
94
109
  Missing any field → status: `needs_breakdown`, never `ready`
95
110
 
96
- 5. Update `INDEX.md` — one row per task, `status=ready`
111
+ 6. Update `INDEX.md` — one row per task, `status=ready`
97
112
 
98
- 6. Update `ACTIVE.md`:
113
+ 7. Update `ACTIVE.md`:
99
114
  ```
100
115
  Cycle: <ID> Date: <YYYY-MM-DD> Base: <BASE>
101
116
  Goal: <1 sentence>
117
+ Spec: docs/AI_HANDOFF/SPEC.md
102
118
  Tasks: <N> total
103
119
  Status: planning_done — ready for executor
104
120
  ```
105
121
  Note: wave structure is inferred from task Dependencies fields — not stored here.
106
122
 
107
- 7. Report: task IDs, dependency graph, any `needs_breakdown` + reason
123
+ 8. Report: task IDs, dependency graph, any `needs_breakdown` + reason
108
124
 
109
125
  > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the strong model, execute steps 1–7 above yourself.
110
126
 
@@ -121,9 +137,9 @@ The planner agent does the following (use Step 1 summary — do NOT re-read file
121
137
  Two independent strong-model passes shape the plan before any code is written — that gate is
122
138
  intact. What it no longer does is hand a stalled plan back and wait.
123
139
 
124
- **Claude Code — MANDATORY, do this before anything else:** call the Agent tool with `subagent_type: "code-reviewer"` (omp: the `task` tool with `agent: "code-reviewer"`), passing `REVIEW_TARGET_TYPE=plan` and the path to `docs/AI_HANDOFF/PLAN.md`. This MUST be a separate agent invocation from Step 2's `handoff-planner` call (fresh context) — same-session self-review defeats the purpose of an independent gate.
140
+ **Claude Code — MANDATORY, do this before anything else:** 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 Step 2's `handoff-planner` call (fresh context) — same-session self-review defeats the purpose of an independent gate.
125
141
 
126
- 1. Reviewer reads `PLAN.md` only (no diff, no task files, no executor report), checks Completeness / Consistency / Clarity / Scope / YAGNI — 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).
142
+ 1. Reviewer reads `SPEC.md` + `PLAN.md` (no diff, no task files, no executor report), checks Completeness / Consistency / Clarity / Scope / YAGNI plus the spec quality gate — every requirement testable, every fullstack layer covered, dependencies explicit, no vague instruction left — 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).
127
143
  2. `Issues Found` → route back to Step 2: planner revises `PLAN.md` and the affected `TASK-xxx.md` files to address every finding, then re-submit for another Step 2.5 review (this becomes the next round). Do NOT commit or hand off to executor on `Issues Found`.
128
144
  3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer, then proceed.
129
145
 
@@ -66,9 +66,10 @@ numbered step completes:
66
66
  Command: handoff-fullstack
67
67
  Goal: <one sentence from the **Problem / feature** section above>
68
68
  Base: <BASE branch>
69
- Phase: <P1|P2|P2.5|P3|I1|I2|I3|I4|R1|R2|R3|R4|R5|done>
69
+ Phase: <P0|P1|P2|P2.5|P3|I1|I2|I3|I4|R1|R2|R3|R4|R4.5|R5|F|done|blocked>
70
70
  Cursor: wave <N> batch <M> — <what just finished>
71
71
  Next: <the exact next step to run>
72
+ QuietScans: <n>/<required> # only while sweeping for stragglers near the end
72
73
  ```
73
74
 
74
75
  This file is the resume contract. It costs one small write per step and is what turns an
@@ -86,6 +87,89 @@ Only when `RUN.md` is absent or `Phase: done` does a new request start a fresh c
86
87
 
87
88
  ---
88
89
 
90
+ ## §0 — Completion contract (terminal outputs)
91
+
92
+ This run has exactly **two** legal ways to end:
93
+
94
+ - `HANDOFF FULLSTACK COMPLETE` — the completion gate in Phase F passed. First line of the
95
+ final report, verbatim.
96
+ - `HANDOFF FULLSTACK BLOCKED` — every remaining task depends on the same external blocker
97
+ (missing credential, dead service, permission wall) AND no safe local work exists. Write
98
+ `Phase: blocked` to RUN.md before emitting it so the Stop gate releases the session.
99
+
100
+ Nothing else ends the run. A recap is a progress notification, not a stopping point. If you
101
+ emit a checkpoint it MUST use this shape and be followed by immediate work:
102
+
103
+ ```
104
+ CHECKPOINT — WORK CONTINUING
105
+ Cycle:
106
+ Completed since last checkpoint:
107
+ Currently executing:
108
+ Exact next action:
109
+ Verification status:
110
+ Run cursor updated: YES
111
+ ```
112
+
113
+ Never stop at `recap: ... Next: ...` while unfinished work remains — the Stop gate now
114
+ bounces that stop straight back into the pipeline, so stopping is not even restful; it
115
+ just costs a round-trip.
116
+
117
+ ---
118
+
119
+ ## Phase 0 — Sweep & Inventory (before planning)
120
+
121
+ Before Phase 1, build the authoritative task inventory — the run owns **all** unfinished
122
+ work, not only the current plan:
123
+
124
+ 1. `docs/AI_HANDOFF/INDEX.md` — every task not `done`/`cancelled_superseded`.
125
+ 2. `docs/AI_HANDOFF/tasks/TASK-*.md` — stale `in_progress` from a dead session, `blocked`,
126
+ `changes_requested`, `needs_executor_report`, `needs_breakdown`.
127
+ 3. Previous cycles — `docs/AI_HANDOFF/HISTORY.md` and `archive/` for cycles closed with
128
+ unfinished tasks; their leftovers join THIS cycle.
129
+ 4. `docs/TASKS.md` — `Ready for AI` items are newly-assigned work; fold them into the plan.
130
+ 5. `git status` / `git diff` — uncommitted work-in-progress that must be finished or
131
+ checkpointed, never silently dropped.
132
+
133
+ The inventory feeds P2: the planner either schedules every discovered item or records why
134
+ it is out of scope (§1/§2 of PLAN.md). Silent omission is a plan defect.
135
+
136
+ **Recovery rule — stuck task records.** For every `pending`, stale `in_progress`, or
137
+ `blocked` task whose record cannot be cleanly resumed (invalid state, orphaned worktree
138
+ gone, contradicting reports):
139
+
140
+ 1. Inspect code/tests/git to see what is actually missing.
141
+ 2. Recoverable → finish the original task in place.
142
+ 3. Not recoverable → mark the old row `cancelled_superseded`, create `TASK-xxx-R1`
143
+ (`-R2`, …) with the same spec references, acceptance criteria and verification, link
144
+ both files' `## Discussion` threads, and execute the replacement in this cycle.
145
+ 4. Never leave stranded work merely because a task record was pending.
146
+
147
+ ---
148
+
149
+ ## Watchdog — surviving idle and new assignments
150
+
151
+ The run must keep itself alive without the human watching.
152
+
153
+ - **Stop gate (Claude Code, automatic):** while `RUN.md` `Phase:` is not `done`/`blocked`,
154
+ `completion-gate.sh` refuses the stop with the cursor's `Next:` step. Recaps and
155
+ premature stops cannot park the run. A stalled-cursor breaker
156
+ (`handoff.fullstack.stopGateMaxStalledBlocks`, default 12) releases the session if the
157
+ cursor has genuinely stopped advancing — the escape hatch, not the norm.
158
+ - **Scheduled wakeup (when the harness offers one):** arm it at run start — Claude Code:
159
+ `CronCreate` a ~`handoff.fullstack.idleWatchdogMin`-minute (default 5) session job with
160
+ prompt `Resume HANDOFF FULLSTACK from docs/AI_HANDOFF/RUN.md — continue the Next: step`;
161
+ `/loop`-style tools: the equivalent interval. Cancel/let it expire once `Phase: done`.
162
+ - **Harnesses with neither:** treat EVERY activation as a watchdog recovery turn — read
163
+ RUN.md first, rescan the inventory, continue `Next:`.
164
+
165
+ **Quiet-period rule.** The run may finish only after the backlog is empty AND
166
+ `handoff.fullstack.quietScansRequired` (default 2) consecutive watchdog scans find no new
167
+ assignment, no recoverable task, and no uncommitted intended change. Record each quiet
168
+ scan in RUN.md as `QuietScans: <n>/<required>`. A scan that finds anything resets the
169
+ counter and starts a new cycle automatically.
170
+
171
+ ---
172
+
89
173
  ## Phase 1+2 — Plan (strong model)
90
174
 
91
175
  ### P1 — Read context (lite model)
@@ -117,7 +201,15 @@ The planner agent does the following (use P1 summary — do NOT re-read files):
117
201
  BASE=$(git symbolic-ref --short HEAD)
118
202
  ```
119
203
 
120
- 3. **Write `docs/AI_HANDOFF/PLAN.md`** — all 6 sections mandatory:
204
+ 3. **Write `docs/AI_HANDOFF/SPEC.md`** — the detailed implementation spec, from
205
+ `templates/docs/AI_HANDOFF/SPEC.md`'s section list (or RULES.md §Spec). It must be
206
+ concrete enough that an executor implements without guessing: exact paths, module and
207
+ API names, schemas, validation rules, permissions, empty/error states, migration
208
+ behavior, and test expectations — every applicable section filled, open questions
209
+ resolved to chosen defaults recorded inline. Implementation begins from SPEC+PLAN,
210
+ never from the raw request.
211
+
212
+ 4. **Write `docs/AI_HANDOFF/PLAN.md`** — all 6 sections mandatory:
121
213
  - §1 Intent — problem + success definition
122
214
  - §2 Scope — in / out of scope; same-wave tasks must not modify the same file (prevents merge conflicts)
123
215
  - §3 Approach — solution, trade-offs, alternatives rejected
@@ -131,8 +223,9 @@ The planner agent does the following (use P1 summary — do NOT re-read files):
131
223
  PLANNER_MODEL: <your exact model ID>
132
224
  ```
133
225
 
134
- 4. **Create `docs/AI_HANDOFF/tasks/TASK-001.md`, `TASK-002.md`...** from `_TEMPLATE.md`.
226
+ 5. **Create `docs/AI_HANDOFF/tasks/TASK-001.md`, `TASK-002.md`...** from `_TEMPLATE.md`.
135
227
  Every task MUST have:
228
+ - Spec references (SPEC.md section IDs this task implements)
136
229
  - Target Files (exact paths — no two tasks in same wave share a file)
137
230
  - Dependencies (`TASK-xxx` or `none` — wave structure inferred from this)
138
231
  - Test Cases (Type | Name | Expected — ≥1 happy + ≥2 edge cases of different kinds)
@@ -141,17 +234,21 @@ The planner agent does the following (use P1 summary — do NOT re-read files):
141
234
  - Acceptance Criteria (verifiable checklist)
142
235
  Missing any field → status `needs_breakdown`, never `ready`.
143
236
 
144
- 5. **Update `docs/AI_HANDOFF/INDEX.md`** — one row per task, `status=ready`.
237
+ 6. **Update `docs/AI_HANDOFF/INDEX.md`** — one row per task, `status=ready`. Every
238
+ unfinished item from the Phase 0 sweep is either a row here or superseded by a
239
+ `-R<n>` recovery row.
145
240
 
146
- 6. **Update `docs/AI_HANDOFF/ACTIVE.md`:**
241
+ 7. **Update `docs/AI_HANDOFF/ACTIVE.md`:**
147
242
  ```
148
243
  Cycle: <ID> Date: <YYYY-MM-DD> Base: <BASE>
149
244
  Goal: <1 sentence>
245
+ Spec: docs/AI_HANDOFF/SPEC.md
150
246
  Tasks: <N> total
151
247
  Status: planning_done — ready for executor
152
248
  ```
153
249
 
154
- 7. **Report:** task IDs, dependency graph, any `needs_breakdown` tasks + reason.
250
+ 8. **Report:** task IDs, dependency graph, recovery/superseded tasks, any
251
+ `needs_breakdown` tasks + reason.
155
252
 
156
253
  ### P2.5 — Independent plan review (strong model, separate agent)
157
254
 
@@ -164,9 +261,9 @@ The planner agent does the following (use P1 summary — do NOT re-read files):
164
261
  The gate still does its job — two independent opus passes shape the plan before a line of code
165
262
  is written. What it no longer does is hand a stalled plan back to a human who isn't there.
166
263
 
167
- **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 path to `docs/AI_HANDOFF/PLAN.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.
264
+ **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.
168
265
 
169
- 1. Reviewer reads `PLAN.md` only (no diff, no task files, no executor report), checks Completeness / Consistency / Clarity / Scope / YAGNI — 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).
266
+ 1. Reviewer reads `SPEC.md` + `PLAN.md` only (no diff, no task files, no executor report), 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).
170
267
  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.
171
268
  3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer, then proceed to P3.
172
269
 
@@ -510,9 +607,50 @@ Force-push stays denied, so this can only ever fast-forward.
510
607
 
511
608
  **If some tasks are `blocked`:** still push. The approved work is reviewed, tested, and
512
609
  committed; withholding it helps no one, and the per-wave commits make any subset revertible.
513
- Name the blocked tasks in the Final Report.
610
+ Name the blocked tasks in the Final Report. Tasks that stayed `blocked` only because their
611
+ record was unrecoverable get the Phase 0 recovery treatment — `cancelled_superseded` plus a
612
+ `-R<n>` replacement — before the run may close.
613
+
614
+ Do NOT set `Phase: done` yet — Phase F still has to close the books.
615
+
616
+ ---
617
+
618
+ ## Phase F — Finalize: quiet period, docs, archive
619
+
620
+ ### F1 — Quiet-period scan
621
+
622
+ Run the sweep from Phase 0 again (INDEX, task files, `docs/TASKS.md`, git status).
623
+ `handoff.fullstack.quietScansRequired` (default 2) consecutive scans must each find:
624
+ no unfinished task, no new assignment, no uncommitted intended change. Record each scan
625
+ in RUN.md (`QuietScans: <n>/<required>`). Anything found resets the counter — fold it in
626
+ through the normal pipeline and keep going.
627
+
628
+ ### F2 — Docs sync
629
+
630
+ Update only the docs the change actually touched: `docs/WORKLOG.md` (always — one entry
631
+ for the cycle), plus `docs/PROJECT.md` / `docs/CODE_MAP.md` / `docs/CHANGELOG.md` when the
632
+ cycle changed architecture, surface area, or shipped behavior. Record: behavior
633
+ implemented, API/schema/UI changes, migration steps, config changes, verification
634
+ evidence, rollback notes.
635
+
636
+ ### F3 — Archive the cycle
514
637
 
515
- Finally set `Phase: done` in `docs/AI_HANDOFF/RUN.md`.
638
+ When `handoff.fullstack.autoArchive` is true (default), archive per `handoff-clear`
639
+ conventions so a future session needs no transcript to understand the cycle:
640
+
641
+ 1. Move the completed cycle's records (PLAN.md, SPEC.md, task files, ACTIVE.md snapshot)
642
+ into `docs/AI_HANDOFF/archive/cycle-<NN>/`.
643
+ 2. If `archive/` holds more than 3 cycle folders → fold the oldest into a one-line
644
+ summary in `HISTORY.md` and remove it.
645
+ 3. Reset `ACTIVE.md` to its empty template; clear `INDEX.md` rows to a fresh header;
646
+ remove `tasks/TASK-*.md`; clear `PLAN.md`/`SPEC.md` (templates stay).
647
+ 4. Commit the docs + archive changes:
648
+ `git add -A && git commit -m "handoff: finalize + archive cycle <ID>"`
649
+
650
+ ### F4 — Close the run
651
+
652
+ Set `Phase: done` in `docs/AI_HANDOFF/RUN.md`, disarm any watchdog job armed at the
653
+ start, and emit the Final Report below.
516
654
 
517
655
  ---
518
656
 
@@ -539,17 +677,40 @@ Re-run assertions after removal to confirm clean state.
539
677
 
540
678
  ## Final Report
541
679
 
680
+ The ONLY legal first lines are:
681
+
682
+ ```
683
+ HANDOFF FULLSTACK COMPLETE
684
+ ```
685
+ or, when every remaining task shares one external blocker and no safe local work exists
686
+ (RUN.md set to `Phase: blocked` first):
687
+ ```
688
+ HANDOFF FULLSTACK BLOCKED
689
+ ```
690
+
691
+ Then the body:
692
+
542
693
  ```
543
- handoff-fullstack complete:
544
694
  Cycle: <ID>
695
+ Spec: docs/AI_HANDOFF/SPEC.md
545
696
  Tasks: <N> approved, <M> blocked
697
+ Recovery/superseded: <TASK-xxx→TASK-xxx-R1, …> | none
698
+ Newly assigned processed: <n> | none
699
+ Quiet scans: <n>/<required>
546
700
  Fix rounds used: <0|1|2>
701
+ Verification: <commands + results>
547
702
  Git: <K> wave commits + pushed to <branch>
703
+ Docs updated: <files>
704
+ Archive: docs/AI_HANDOFF/archive/cycle-<NN>/
548
705
  Worktrees: all cleaned
549
706
  Branches: all cleaned
707
+ Remaining tasks: NONE | <list>
550
708
  Blocked (needs you): <TASK-xxx — one-line reason> | none
551
709
  ```
552
710
 
711
+ A blocked report additionally lists: blocked tasks, exact blocker + evidence, attempted
712
+ fixes, local work completed, and the recovery instructions for the next session.
713
+
553
714
  Then, as the last line of the run:
554
715
 
555
716
  > Cycle finished. Run `/compact` before starting the next cycle — this session is carrying
@@ -59,8 +59,12 @@ If this file already exists with `Phase:` not `done` when the command starts, th
59
59
 
60
60
  Read `docs/AI_HANDOFF/ACTIVE.md` → get `Base: <BASE>`.
61
61
  Read `docs/AI_HANDOFF/INDEX.md` → collect `ready` tasks (or the specific task named in the request above).
62
- If there are no `ready` tasks, check for `changes_requested`/`blocked` ones and run those
63
- instead. Only if nothing is actionable → report and stop.
62
+ If there are no `ready` tasks, check for `changes_requested`/`blocked`/stale `in_progress`
63
+ ones and run those instead. A stuck record that cannot resume (orphaned worktree,
64
+ contradicting reports) gets the recovery treatment: mark it `cancelled_superseded`, create
65
+ `TASK-xxx-R1` with the same spec references/acceptance/verification, and run the
66
+ replacement — never leave stranded work just because a record was pending.
67
+ Only if nothing is actionable → report and stop.
64
68
 
65
69
  Verify working tree state:
66
70
  ```bash
@@ -125,6 +129,9 @@ Each spawned agent works independently in its own worktree — **NO git commit,
125
129
 
126
130
  ```
127
131
  Read docs/AI_HANDOFF/tasks/TASK-xxx.md
132
+ Read the SPEC.md sections named in the task's `Spec references` — the spec is the contract;
133
+ the task file is the slice. If they disagree, implement the spec and note it in the task's
134
+ ## Discussion.
128
135
 
129
136
  TDD — mandatory:
130
137
  1. Write tests from §Test Cases
@@ -86,7 +86,10 @@ git status # overview of modified/new/deleted files
86
86
  ```
87
87
 
88
88
  Review as one unified diff — correctness, regression risk, security, edge cases, maintainability.
89
- Cross-reference with each task's intent in `docs/AI_HANDOFF/tasks/TASK-xxx.md`.
89
+ Cross-reference each task's intent in `docs/AI_HANDOFF/tasks/TASK-xxx.md` AND the
90
+ `Spec references` sections it names in `docs/AI_HANDOFF/SPEC.md` — spec compliance is the
91
+ primary correctness bar; a diff that drifts from the spec's contract fails even when it
92
+ matches the task file's wording.
90
93
 
91
94
  ### 2d — Append verdict to each task file
92
95
 
@@ -12,8 +12,10 @@ Read and display current handoff state. Do NOT modify any files.
12
12
 
13
13
  1. `docs/AI_HANDOFF/ACTIVE.md` → cycle ID, goal, base branch
14
14
  2. `docs/AI_HANDOFF/INDEX.md` → all tasks + statuses
15
- 3. `git worktree list` → open worktrees
16
- 4. `git branch | grep handoff/` → open handoff branches
15
+ 3. `docs/AI_HANDOFF/RUN.md` → fullstack run cursor: `Phase:` ≠ `done`/`blocked` means a run is live and the Stop gate is holding the session to it
16
+ 4. `docs/AI_HANDOFF/SPEC.md` → spec exists/fresh (one line)
17
+ 5. `git worktree list` → open worktrees
18
+ 6. `git branch | grep handoff/` → open handoff branches
17
19
 
18
20
  ## Report
19
21
 
@@ -21,6 +23,8 @@ Read and display current handoff state. Do NOT modify any files.
21
23
  ━━━ Handoff Status ━━━━━━━━━━━━━━━━━━━━━━━━
22
24
  Cycle: <ID> Base: <branch> Date: <date>
23
25
  Goal: <goal>
26
+ Run: <Phase — or "no live cursor">
27
+ Spec: <present | missing>
24
28
 
25
29
  Tasks:
26
30
  ✅ done TASK-001 <name>