@aperant/framework 0.7.0 → 0.7.4

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 (151) hide show
  1. package/CHANGELOG.md +205 -0
  2. package/agents/apt-planner.md +12 -0
  3. package/agents/apt-pr-review-fixer.md +13 -9
  4. package/bin/apt-tools.mjs +7 -0
  5. package/dist/cli/ci-watch/stop-matrix.d.mts.map +1 -1
  6. package/dist/cli/ci-watch/stop-matrix.mjs +16 -0
  7. package/dist/cli/ci-watch/stop-matrix.mjs.map +1 -1
  8. package/dist/cli/commands/ci-watch.d.mts +11 -0
  9. package/dist/cli/commands/ci-watch.d.mts.map +1 -1
  10. package/dist/cli/commands/ci-watch.mjs +108 -2
  11. package/dist/cli/commands/ci-watch.mjs.map +1 -1
  12. package/dist/cli/commands/features-audit.d.mts +24 -0
  13. package/dist/cli/commands/features-audit.d.mts.map +1 -1
  14. package/dist/cli/commands/features-audit.mjs +159 -5
  15. package/dist/cli/commands/features-audit.mjs.map +1 -1
  16. package/dist/cli/commands/health-check.d.mts +16 -0
  17. package/dist/cli/commands/health-check.d.mts.map +1 -1
  18. package/dist/cli/commands/health-check.mjs +118 -2
  19. package/dist/cli/commands/health-check.mjs.map +1 -1
  20. package/dist/cli/commands/init.d.mts +9 -0
  21. package/dist/cli/commands/init.d.mts.map +1 -1
  22. package/dist/cli/commands/init.mjs +49 -4
  23. package/dist/cli/commands/init.mjs.map +1 -1
  24. package/dist/cli/commands/modes.d.mts.map +1 -1
  25. package/dist/cli/commands/modes.mjs +11 -0
  26. package/dist/cli/commands/modes.mjs.map +1 -1
  27. package/dist/cli/commands/pr-review-audit-fixer.d.mts +13 -0
  28. package/dist/cli/commands/pr-review-audit-fixer.d.mts.map +1 -1
  29. package/dist/cli/commands/pr-review-audit-fixer.mjs +18 -5
  30. package/dist/cli/commands/pr-review-audit-fixer.mjs.map +1 -1
  31. package/dist/cli/commands/task.d.mts.map +1 -1
  32. package/dist/cli/commands/task.mjs +84 -5
  33. package/dist/cli/commands/task.mjs.map +1 -1
  34. package/dist/cli/commands/validate-evidence.d.mts +24 -2
  35. package/dist/cli/commands/validate-evidence.d.mts.map +1 -1
  36. package/dist/cli/commands/validate-evidence.mjs +154 -17
  37. package/dist/cli/commands/validate-evidence.mjs.map +1 -1
  38. package/dist/cli/commands/vitest-doctor.d.mts +2 -0
  39. package/dist/cli/commands/vitest-doctor.d.mts.map +1 -0
  40. package/dist/cli/commands/vitest-doctor.mjs +168 -0
  41. package/dist/cli/commands/vitest-doctor.mjs.map +1 -0
  42. package/dist/cli/config/gitignore-drift.d.mts +23 -1
  43. package/dist/cli/config/gitignore-drift.d.mts.map +1 -1
  44. package/dist/cli/config/gitignore-drift.mjs +81 -3
  45. package/dist/cli/config/gitignore-drift.mjs.map +1 -1
  46. package/dist/cli/config/load.d.mts +56 -2
  47. package/dist/cli/config/load.d.mts.map +1 -1
  48. package/dist/cli/config/load.mjs +192 -2
  49. package/dist/cli/config/load.mjs.map +1 -1
  50. package/dist/cli/consistency/parse-review.mjs +7 -0
  51. package/dist/cli/consistency/parse-review.mjs.map +1 -1
  52. package/dist/cli/dispatch.d.mts.map +1 -1
  53. package/dist/cli/dispatch.mjs +24 -2
  54. package/dist/cli/dispatch.mjs.map +1 -1
  55. package/dist/cli/gate/gates/gitignore-in-sync.d.mts +1 -1
  56. package/dist/cli/gate/gates/gitignore-in-sync.d.mts.map +1 -1
  57. package/dist/cli/gate/gates/gitignore-in-sync.mjs +5 -2
  58. package/dist/cli/gate/gates/gitignore-in-sync.mjs.map +1 -1
  59. package/dist/cli/gate/gates/review-clean.d.mts +5 -1
  60. package/dist/cli/gate/gates/review-clean.d.mts.map +1 -1
  61. package/dist/cli/gate/gates/review-clean.mjs +23 -18
  62. package/dist/cli/gate/gates/review-clean.mjs.map +1 -1
  63. package/dist/cli/gate/gates/verify-approved.d.mts +49 -1
  64. package/dist/cli/gate/gates/verify-approved.d.mts.map +1 -1
  65. package/dist/cli/gate/gates/verify-approved.mjs +93 -14
  66. package/dist/cli/gate/gates/verify-approved.mjs.map +1 -1
  67. package/dist/cli/help.d.mts.map +1 -1
  68. package/dist/cli/help.mjs +7 -2
  69. package/dist/cli/help.mjs.map +1 -1
  70. package/dist/cli/install/runtime-detect.d.mts +13 -0
  71. package/dist/cli/install/runtime-detect.d.mts.map +1 -1
  72. package/dist/cli/install/runtime-detect.mjs +9 -0
  73. package/dist/cli/install/runtime-detect.mjs.map +1 -1
  74. package/dist/cli/task/index-md.d.mts.map +1 -1
  75. package/dist/cli/task/index-md.mjs +14 -2
  76. package/dist/cli/task/index-md.mjs.map +1 -1
  77. package/dist/plugin/.claude-plugin/plugin.json +11 -2
  78. package/dist/plugin/agents/apt-improver.md +99 -0
  79. package/dist/plugin/agents/apt-planner.md +127 -10
  80. package/dist/plugin/agents/apt-pr-review-fixer.md +13 -9
  81. package/dist/plugin/skills/apt/SKILL.md +1 -0
  82. package/dist/plugin/skills/apt-close-task/SKILL.md +63 -1
  83. package/dist/plugin/skills/apt-debug/SKILL.md +39 -6
  84. package/dist/plugin/skills/apt-debug/appendices/diagnose-discipline.md +119 -0
  85. package/dist/plugin/skills/apt-diagram/SKILL.md +378 -0
  86. package/dist/plugin/skills/apt-diagram/appendices/design-discipline.md +97 -0
  87. package/dist/plugin/skills/apt-discuss/SKILL.md +72 -5
  88. package/dist/plugin/skills/apt-discuss/appendices/grill-discipline.md +104 -0
  89. package/dist/plugin/skills/apt-discuss/appendices/zoom-out-helper.md +79 -0
  90. package/dist/plugin/skills/apt-execute/SKILL.md +57 -5
  91. package/dist/plugin/skills/apt-execute/appendices/tdd-mode.md +107 -0
  92. package/dist/plugin/skills/apt-improve/DEEPENING.md +84 -0
  93. package/dist/plugin/skills/apt-improve/INTERFACE-DESIGN.md +97 -0
  94. package/dist/plugin/skills/apt-improve/LANGUAGE.md +104 -0
  95. package/dist/plugin/skills/apt-improve/SKILL.md +141 -0
  96. package/dist/plugin/skills/apt-plan/SKILL.md +171 -4
  97. package/dist/plugin/skills/apt-plan/adapters/conductor.md +98 -0
  98. package/dist/plugin/skills/apt-pr-review/SKILL.md +57 -18
  99. package/dist/plugin/skills/apt-prototype/LOGIC.md +109 -0
  100. package/dist/plugin/skills/apt-prototype/SKILL.md +143 -0
  101. package/dist/plugin/skills/apt-prototype/UI.md +90 -0
  102. package/dist/plugin/skills/apt-quick/SKILL.md +49 -8
  103. package/dist/plugin/skills/apt-release-notes/SKILL.md +193 -0
  104. package/dist/plugin/skills/apt-release-notes/appendices/persona-voice.md +59 -0
  105. package/dist/plugin/skills/apt-review/SKILL.md +2 -0
  106. package/dist/plugin/skills/apt-run/SKILL.md +32 -4
  107. package/dist/plugin/skills/apt-setup/SKILL.md +308 -6
  108. package/dist/plugin/skills/apt-ship/SKILL.md +122 -1
  109. package/dist/plugin/skills/apt-spar/SKILL.md +315 -0
  110. package/dist/plugin/skills/apt-triage/AGENT-BRIEF.md +84 -0
  111. package/dist/plugin/skills/apt-triage/OUT-OF-SCOPE.md +75 -0
  112. package/dist/plugin/skills/apt-triage/SKILL.md +169 -0
  113. package/dist/plugin/skills/apt-update/SKILL.md +77 -10
  114. package/dist/plugin/skills/apt-verify/SKILL.md +3 -0
  115. package/dist/plugin/skills/apt-verify-proof/SKILL.md +10 -5
  116. package/dist/plugin/skills/apt-watch-ci/SKILL.md +166 -0
  117. package/dist/plugin/skills/apt-zoom-out/SKILL.md +130 -0
  118. package/package.json +1 -1
  119. package/prompts/conductor-framework-context.md +63 -0
  120. package/prompts/conductor-system.md +11 -0
  121. package/skills/apt-close-task/SKILL.md +1 -0
  122. package/skills/apt-discuss/SKILL.md +47 -5
  123. package/skills/apt-execute/SKILL.md +9 -0
  124. package/skills/apt-plan/SKILL.md +12 -0
  125. package/skills/apt-pr-review/SKILL.md +19 -3
  126. package/skills/apt-quick/SKILL.md +19 -8
  127. package/skills/apt-researcher.md +1 -0
  128. package/skills/apt-setup/SKILL.md +33 -2
  129. package/skills/apt-verify-proof/SKILL.md +7 -5
  130. package/src/cli/ci-watch/stop-matrix.mjs +17 -0
  131. package/src/cli/commands/ci-watch.mjs +113 -2
  132. package/src/cli/commands/features-audit.mjs +164 -5
  133. package/src/cli/commands/health-check.mjs +115 -2
  134. package/src/cli/commands/init.mjs +52 -4
  135. package/src/cli/commands/modes.mjs +11 -0
  136. package/src/cli/commands/pr-review-audit-fixer.mjs +18 -5
  137. package/src/cli/commands/task.mjs +83 -5
  138. package/src/cli/commands/validate-evidence.mjs +158 -17
  139. package/src/cli/commands/vitest-doctor.mjs +173 -0
  140. package/src/cli/config/gitignore-drift.mjs +74 -3
  141. package/src/cli/config/load.mjs +188 -2
  142. package/src/cli/consistency/parse-review.mjs +6 -0
  143. package/src/cli/dispatch.mjs +23 -2
  144. package/src/cli/gate/gates/gitignore-in-sync.mjs +5 -2
  145. package/src/cli/gate/gates/review-clean.mjs +24 -19
  146. package/src/cli/gate/gates/verify-approved.mjs +97 -14
  147. package/src/cli/help.mjs +7 -2
  148. package/src/cli/install/runtime-detect.mjs +9 -0
  149. package/src/cli/task/index-md.mjs +15 -2
  150. package/templates/config.json +2 -7
  151. package/workflows/verify-proof.md +8 -3
@@ -59,6 +59,18 @@ For STANDARD and COMPLEX tasks:
59
59
  3. Read key files to understand current architecture
60
60
  4. Identify: files to modify, interfaces to respect, tests to update, config to change
61
61
 
62
+ ### 3.35. React state guidance — sync-store vs render-committed ref (BUG-025-planner)
63
+
64
+ When a planned event handler fires a flush/persist immediately after mutating a Zustand/Jotai/refs-stored store, the spec MUST recommend reading from `store.getState()` (or the equivalent direct-read primitive) on the synchronous path, NOT from a `useRef`-populated-by-`useEffect`.
65
+
66
+ Why: refs populated via `useEffect` lag the store by one render cycle. A handler that mutates the store and immediately reads the ref sees the pre-mutation value, silently corrupting persists and order-of-operations contracts. Reference pattern: `apps/desktop/src/renderer/src/App.tsx::runUpsertForIds` (post-fix commit `4c263856`).
67
+
68
+ Checklist when the task touches a Zustand/Jotai store or any handler doing flush-after-mutate:
69
+
70
+ - Grep for `useRef(` references that cache store state (e.g. `const fooRef = useRef(foo); useEffect(() => { fooRef.current = foo }, [foo])`).
71
+ - If the spec or planned subtasks read from such a ref on a synchronous path that ALSO mutates the store, recommend `store.getState()` as the read primitive.
72
+ - Note the caveat explicitly in the spec's Implementation Decisions section so the executor doesn't silently revert it.
73
+
62
74
  ### 3.4. Consume design.md (C24)
63
75
 
64
76
  If `{task_dir}/design.md` exists (emitted by a prior `/apt:design` run), load it before decomposing subtasks:
@@ -199,7 +211,13 @@ If unable to enumerate (network unavailable, action docs unclear), flag it expli
199
211
 
200
212
  ## 4. Write Specification
201
213
 
202
- Create `{task_dir}/spec.md`:
214
+ The spec.md content format **branches on track** (Pocock adoption ID-05,
215
+ Fast Path Guarantee). QUICK-routed tasks keep the existing 4-section
216
+ shape; STANDARD/DEEP/COMPLEX tasks get a PRD-shaped artifact that
217
+ survives the task as a second-consumer document.
218
+
219
+ ### 4.A. QUICK track / SIMPLE complexity — legacy 4-section spec
220
+
203
221
  ```markdown
204
222
  # Task: {task description}
205
223
 
@@ -219,6 +237,57 @@ Create `{task_dir}/spec.md`:
219
237
  {What this task explicitly does NOT cover}
220
238
  ```
221
239
 
240
+ ### 4.B. STANDARD / DEEP / COMPLEX — PRD-shaped spec.md
241
+
242
+ ```markdown
243
+ # Spec: {task title}
244
+
245
+ **Task ID:** {task-id}
246
+ **Track:** {STANDARD | DEEP}
247
+ **Scope:** {framework | desktop | web | core | ui | backend | docs}
248
+
249
+ ## Problem Statement
250
+ {What pain are we solving? Cite empirical evidence where possible.}
251
+
252
+ ## Solution
253
+ {Chosen approach + bulleted net delta of files / flags / config / skills.}
254
+
255
+ ## User Stories
256
+ {One **US-NN (persona).** story per user-value slice. Stories map 1:1
257
+ onto subtasks in implementation_plan.json.}
258
+
259
+ ## Implementation Decisions
260
+ {Load-bearing principles carried into every subtask. Format:
261
+ "### ID-NN: {title}" + rationale + practical consequence.}
262
+
263
+ ## Testing Decisions
264
+ {One block per test family: "### TD-NN: {family}" + what's covered +
265
+ which subtask owns the test file. Fast Path regression tests MUST be
266
+ enumerated here.}
267
+
268
+ ## Out of Scope
269
+ {Non-goals. Each bullet names what is deferred + where it belongs.}
270
+
271
+ ## Further Notes
272
+ {Sequencing rationale, risk surface, dependencies, files-affected
273
+ preview, and any other executor-load-bearing context.}
274
+
275
+ ### Acceptance Criteria
276
+ {Cross-cutting **AC1..ACN** list — each AC gets a stable ID. Subtasks
277
+ reference these IDs via the per-subtask `acceptance_criteria` field.}
278
+ ```
279
+
280
+ **PRD section ordering is load-bearing.** `apt-tools coverage-check
281
+ validate` greps `## Acceptance Criteria`; `apt-tools consistency check`
282
+ greps `## Solution` and `## User Stories`. Renaming or reordering these
283
+ sections breaks downstream tooling and the C15 consistency rules.
284
+
285
+ **Do NOT interview the user.** The PRD is synthesized from the task
286
+ description + codebase investigation + AGENTS.md, not from a clarifying
287
+ back-and-forth. If a section truly cannot be filled, write
288
+ `{TBD — needs user input}`; do NOT pause for clarification (that is
289
+ `apt:discuss`'s surface, not the planner's).
290
+
222
291
  ### 4.05. Design Reference section (C24 — when design.md exists)
223
292
 
224
293
  When `{task_dir}/design.md` exists, `spec.md` MUST include a `## Design Reference` section directly below `## Requirements`. Shape:
@@ -275,12 +344,41 @@ fix it now, not later.
275
344
 
276
345
  ## 5. Create Implementation Plan
277
346
 
278
- Create `{task_dir}/implementation_plan.json`:
347
+ Subtask schema branches on track (Pocock adoption ID-05 — Fast Path Guarantee).
348
+
349
+ ### 5.A. QUICK track / SIMPLE complexity — legacy flat subtask schema
350
+
279
351
  ```json
280
352
  {
281
353
  "task": "{task description}",
282
- "complexity": "simple|standard|complex",
354
+ "complexity": "simple",
283
355
  "spec": "spec.md",
356
+ "subtasks": [
357
+ {
358
+ "id": "1",
359
+ "title": "{subtask title}",
360
+ "description": "{what to do — concrete, not vague}",
361
+ "files": ["path/to/file1.ts", "path/to/file2.ts"],
362
+ "dependencies": [],
363
+ "status": "pending",
364
+ "verification": "{command or check to verify completion}"
365
+ }
366
+ ]
367
+ }
368
+ ```
369
+
370
+ QUICK subtasks omit `hitl`, `afk`, `acceptance_criteria`, and `user_value`
371
+ fields. The one-shot path doesn't need user-value framing or per-subtask
372
+ HITL gates.
373
+
374
+ ### 5.B. STANDARD / DEEP / COMPLEX — vertical-slice subtask schema
375
+
376
+ ```json
377
+ {
378
+ "task": "{task description}",
379
+ "complexity": "standard|complex",
380
+ "spec": "spec.md",
381
+ "vertical_slice_schema_version": "1",
284
382
  "declared_persona_tier": "primary",
285
383
  "declared_personas": ["mobile-dev"],
286
384
  "tier_confidence": "high",
@@ -308,29 +406,48 @@ Create `{task_dir}/implementation_plan.json`:
308
406
  "subtasks": [
309
407
  {
310
408
  "id": "1",
311
- "title": "{subtask title}",
409
+ "title": "{subtask title — user-value framing, not 'add UI'}",
312
410
  "description": "{what to do — concrete, not vague}",
313
411
  "files": ["path/to/file1.ts", "path/to/file2.ts"],
314
412
  "acceptance_criteria": ["AC1", "AC3"],
315
413
  "dependencies": [],
316
414
  "status": "pending",
415
+ "hitl": "required | review | none",
416
+ "afk": "safe | unsafe",
417
+ "user_value": "{one-line user-value framing — who benefits, how}",
317
418
  "verification": "{command or check to verify completion}"
318
419
  }
319
420
  ]
320
421
  }
321
422
  ```
322
423
 
424
+ Mandatory STANDARD/DEEP fields per subtask:
425
+
426
+ - `hitl` — `"required" | "review" | "none"`. `required` blocks the
427
+ executor pending human approval (autonomy 1 always pauses; autonomy 2
428
+ batches; autonomy 3 escalates only on conflict). `review` means the
429
+ human reviews the diff post-hoc, not blocking. `none` is agent-only.
430
+ - `afk` — `"safe" | "unsafe"`. `safe` means proceed unattended. `unsafe`
431
+ means pause at the start of this subtask if no human is present
432
+ (autonomy < 3).
433
+ - `acceptance_criteria` — `string[]` of id-refs (`"AC1"`, …) into spec.md's
434
+ `## Acceptance Criteria` section.
435
+ - `user_value` — one-line framing of WHO benefits and HOW. Prevents
436
+ horizontal slicing — every subtask is a vertical user-shippable slice.
437
+
438
+ Plan-level: `vertical_slice_schema_version: "1"` declares the schema
439
+ version so future migrations can detect this plan as v1.
440
+
323
441
  Rules:
324
442
  - Each subtask completable in one focused session
325
443
  - Dependencies form a DAG (no circular deps)
326
444
  - Verification must be automated (test command, grep check, type check)
327
445
  - Files list must be exhaustive — every file the subtask touches
328
- - `acceptance_criteria` is mandatory: list the canonical AC id-refs
329
- (`"AC1"`, `"AC3"`, ...) from the `## Acceptance Criteria` section of
330
- spec.md that this subtask satisfies. Verbatim AC text is accepted but
331
- discouraged — the id-ref form is stable across spec edits. Every AC in
332
- spec.md must be referenced by at least one subtask; gate G8
333
- (`consistency-check`) enforces this on ship.
446
+ - `acceptance_criteria` is mandatory on STANDARD/DEEP: every AC in spec.md
447
+ must be referenced by at least one subtask; gate G8
448
+ (`consistency-check`) enforces this on ship. Verbatim AC text is
449
+ accepted but discouraged — id-refs are stable across spec edits.
450
+ - Subtask title MUST frame user value, not file scope.
334
451
 
335
452
  ### 5.1 Framework-scope doc-sync rule
336
453
 
@@ -64,7 +64,7 @@ The only valid reasons to skip a finding:
64
64
  ```
65
65
  [TOOLCHAIN_COMMANDS]
66
66
  ```
67
- 6. **If verification passes**: Stage with `git add [specific files]`
67
+ 6. **If verification passes**: Stage AND commit atomically per finding with `git add [specific files] && git commit -m "<finding-id>: <one-line>"` (BUG-016 — the audit gate only observes COMMITTED edits in the iteration window; stage-only leaves the index dirty and trips a false-positive hallucination verdict).
68
68
  7. **If verification fails**: Revert with `git checkout -- [file]`, mark as "manual fix required" in your report
69
69
 
70
70
  ---
@@ -89,7 +89,7 @@ Findings with severity `critical`:
89
89
 
90
90
  ## Report Format
91
91
 
92
- Write to `[REVIEW_DIR]/iterations/[N]/fixes-applied.md`:
92
+ Write to `[REVIEW_DIR]/iterations/[N]/fixes-applied-[FIXER_NAME].md` (BUG-030 canonical naming — the audit gate resolves `fixes-applied-${FIXER_NAME}.md` ahead of the legacy `fixes-applied.md`, so parallel fixers no longer collide on a shared report path):
93
93
 
94
94
  ```markdown
95
95
  # Fix Report — Iteration [N]
@@ -142,11 +142,13 @@ Write to `[REVIEW_DIR]/iterations/[N]/fixes-applied.md`:
142
142
 
143
143
  ## Pre-Return Self-Audit (mandatory)
144
144
 
145
- Before emitting `VERIFICATION: PASS` or any `FIXED: N > 0` status, run BOTH of these inside the worktree:
145
+ Before emitting `VERIFICATION: PASS` or any `FIXED: N > 0` status, run BOTH of these inside the worktree.
146
+
147
+ The orchestrator passes you `[ITERATION_START_SHA]` — the SHA captured BEFORE fixers were spawned. The audit gate uses the same SHA as its `--since-sha` window, so your self-audit must mirror it (BUG-016):
146
148
 
147
149
  ```bash
150
+ cd [WORKTREE_PATH] && git log [ITERATION_START_SHA]..HEAD --oneline
148
151
  cd [WORKTREE_PATH] && git diff --cached --name-only
149
- cd [WORKTREE_PATH] && git diff --name-only
150
152
  ```
151
153
 
152
154
  Paste the **literal command output** into your report under a new section:
@@ -154,11 +156,13 @@ Paste the **literal command output** into your report under a new section:
154
156
  ```markdown
155
157
  ## Pre-Return Self-Audit
156
158
 
157
- git diff --cached --name-only:
158
- <paste literal output, or empty if nothing staged>
159
+ git log [ITERATION_START_SHA]..HEAD --oneline:
160
+ <paste literal output MUST list 1 commit per claimed fix>
159
161
 
160
- git diff --name-only:
161
- <paste literal output, or empty if nothing unstaged>
162
+ git diff --cached --name-only:
163
+ <paste literal output MUST be empty (index clean after every commit)>
162
164
  ```
163
165
 
164
- **Rule:** if BOTH outputs are empty AND you claimed to have fixed ≥ 1 finding, your status line MUST be `FIXED: 0 | FAILED: N | SKIPPED: 0 | VERIFICATION: FAIL` and every claimed fix MUST be marked FAILED in the report with `- **Verification**: FAILno diff produced`. Do not emit `VERIFICATION: PASS` with an empty diff — the orchestrator runs an **independent** deterministic audit (see `/apt:pr-review` SKILL.md Phase 6 Step 4b, `apt-tools pr-review audit-fixer`) that cross-checks your status line against the worktree git state. Emitting `PASS` when the diff is empty will be caught deterministically and counted as a hallucination; your findings will be treated as unresolved and you may be re-spawned with an explicit hallucination callout.
166
+ **Pass condition (BUG-016 commit discipline):** the `git log` output MUST contain ≥ 1 commit attributable to this fixer (one commit per fixed finding, message prefixed with the finding id) AND `git diff --cached --name-only` MUST be empty. The previous "I see staged files" rule is OBSOLETE staging without committing leaves the index dirty and the audit gate's `--since-sha` window (which scopes to committed diff for the current iteration) sees zero matching paths, false-positiving `hallucinated`.
167
+
168
+ **Fail condition:** if `git log [ITERATION_START_SHA]..HEAD --oneline` is EMPTY AND you claimed to have fixed ≥ 1 finding, your status line MUST be `FIXED: 0 | FAILED: N | SKIPPED: 0 | VERIFICATION: FAIL` and every claimed fix MUST be marked FAILED in the report with `- **Verification**: FAIL — no commit produced`. Likewise if `git diff --cached --name-only` is NON-EMPTY (you forgot to commit some staged edits), status MUST be `VERIFICATION: FAIL` until the index is clean. Do not emit `VERIFICATION: PASS` with an empty commit log or dirty index — the orchestrator runs an **independent** deterministic audit (see `/apt:pr-review` SKILL.md Phase 6 Step 4b, `apt-tools pr-review audit-fixer`) that cross-checks your status line against the worktree git state. Emitting `PASS` when no commits exist will be caught deterministically and counted as a hallucination; your findings will be treated as unresolved and you may be re-spawned with an explicit hallucination callout.
@@ -130,6 +130,7 @@ Show available commands table:
130
130
  | `apt:resume` | Restore context after session break |
131
131
  | `apt:pause` | Human-initiated handoff — save state when YOU need to stop |
132
132
  | `apt:ship` | Create PR with traceability |
133
+ | `apt:close-task` | Post-merge closer — confirm PR merged, flip phase, drain narration ledger |
133
134
  | `apt:setup` | Change framework preferences |
134
135
 
135
136
  Show current state summary and autonomy flags (`--supervised`, `--guided`, `--autonomous`, `--yolo`).
@@ -15,7 +15,7 @@ execution_modes:
15
15
  - auto
16
16
  - step
17
17
  allowed-tools: "Bash, Read, Grep, Glob, Write"
18
- argument-hint: "apt:close-task [--all | --task <id>]"
18
+ argument-hint: "apt:close-task [--all | --task <id>] [--narrate-only]"
19
19
  gates: []
20
20
  ---
21
21
  <objective>
@@ -40,6 +40,7 @@ Confirm a shipped PR has merged on GitHub, then run the closer side of the task
40
40
  - `.aperant/events/{today}.jsonl` — emits `task.closed.merged`.
41
41
  - `.aperant/config.json` — strips `authorship_overrides['pr-{N}']` entries for merged PRs.
42
42
  - `.aperant/roadmap/{scope}/**` — linked-phase flip (when `task_isolation.auto_close_phase: true`).
43
+ - `.aperant/ci-watches/{pr}.json` — removed for each merged PR (BUG-027 (b) side-effect: prevents watcher state files leaking past PR-terminal-state). Idempotent — already-removed state is a no-op. For retroactive cleanup of orphan state files left behind by pre-fix runs, use `apt-tools ci-watch sweep . --orphaned`.
43
44
  </state_files>
44
45
 
45
46
  <process>
@@ -70,6 +71,7 @@ Internally, close-merged does:
70
71
  a. `apt-tools task close . --id {task-id} --verdict approved` (respects `task_isolation.auto_close_phase`).
71
72
  b. Strips `config.pr_review.authorship_overrides['pr-{N}']` if present.
72
73
  c. Emits `task.closed.merged` event.
74
+ d. Appends a `pending_narration[]` ledger row to `.aperant/state.json` so `--narrate-only` (see §4) can pick it up. Additive only; never blocks the close.
73
75
  3. When `state !== 'MERGED'`, the task stays in `shipped-pending-merge` with a skip reason the user can inspect.
74
76
 
75
77
  ## 2.5 Narrate completed phases (moved from /apt:ship in C56 B5)
@@ -85,6 +87,33 @@ For each entry in the close-merged envelope's `closed[]` whose record has a non-
85
87
 
86
88
  Do NOT wait on the narrator. Its status lands in `.aperant/digests/.last-run.json`. Skip narrator spawn entirely when `closed[]` is empty or no closed item has a phase_id.
87
89
 
90
+ After step 2.5 spawns narrators for the just-closed candidates, the skill ALSO drains `state.pending_narration[]` (entries the passive sweep parked there) — see §4.
91
+
92
+ ## 2.6 Drop user-facing release-note fragment (persona-aware release-notes opt-in)
93
+
94
+ This step is additive bookkeeping — it must NEVER block the close path or surface a destructive failure. Runs ONLY when `.aperant/config.json` has `changelog.release_notes.enabled === true`. When the toggle is `false` (the default for projects that don't publish user-facing notes), skip the section entirely.
95
+
96
+ For each entry in the close-merged envelope's `closed[]`:
97
+
98
+ 1. Read the merged PR body via `gh pr view <pr_number> --json body`. Look for a single `Release note:` line (case-insensitive). The line is what `/apt:ship` Section 2.6 auto-drafted (or a manual edit by the author).
99
+ 2. Look for a persona tag in the PR body or in commits. Reasonable sources: the `Release note:` line itself if the author included one (e.g. `Release note: [Maya] …`), a `release-note-persona:` trailer in the most recent commit, or the persona name embedded in the auto-drafted line by §2.6.2 of /apt:ship.
100
+ 3. Invoke the deterministic drafter:
101
+
102
+ ```bash
103
+ node packages/framework/bin/apt-tools.mjs release-notes draft . \
104
+ --pr <pr_number> \
105
+ --note "<release-note-line-text>" \
106
+ [--persona <persona-name>]
107
+ ```
108
+
109
+ This call is synchronous, sub-100ms, and idempotent per subtask 2 — re-running close-task does not duplicate the fragment.
110
+
111
+ 4. On non-zero exit from `release-notes draft`, append a `pending_release_note[]` row to `.aperant/state.json` so a manual re-run can recover. Do NOT block close-merged on this — it is additive bookkeeping, not core lifecycle. Use `apt-tools state-update . --append-pending-release-note '{"task_id": "<id>", "pr_number": <n>, "reason": "<error>"}'` if such a helper exists, otherwise call `apt-tools state-artifacts . --note '<msg>'` or write a one-line warning to stderr.
112
+
113
+ Skip the section quietly when:
114
+ - The PR body has no `Release note:` line AND no auto-draft signal (intentional infra-only PR, or the `no-notes` label was applied at ship time).
115
+ - The CLI returns `{status: 'ok', written: false, reason: 'no-change'}` — already idempotent-handled by subtask 2's contract; treat as success.
116
+
88
117
  ## 3. Summary
89
118
 
90
119
  close-merged emits an envelope with:
@@ -95,6 +124,39 @@ close-merged emits an envelope with:
95
124
 
96
125
  Report the summary verbatim. If anything landed in `skipped[]` with a recoverable reason (`offline`, `rate_limited`), suggest the user re-run once the network clears.
97
126
 
127
+ **Local cleanup recap (best-effort).** On confirmed merge, `task close-merged` runs `computeWorktreeCleanup` against the primary repo (`packages/framework/src/cli/task/worktree-cleanup.mjs:140-230`): `git fetch origin <base>` (failure → recorded as `fetch_failed` warning, cleanup proceeds), `git checkout <base>` (failure → returns `action: 'checkout_failed'` and preserves BOTH the worktree and the task branch — nothing is removed), `git merge --ff-only origin/<base>` (failure → `ff_only_failed` warning, GC still runs), `git worktree remove <wtPath>`, and `git branch -d <taskBranch>` (failure on squash/rebase merges → `branch_delete_failed` warning, `branch_deleted: false` in the envelope; user can `git branch -D` manually). This is why `/apt:watch-ci` auto-merge MUST NOT pass `gh pr merge --delete-branch` — that flag would try to do the same work from inside the worktree where `git switch <base>` cannot succeed (see FRAMEWORK-BUG-019).
128
+
129
+ ## 4. Narrate-only mode
130
+
131
+ When invoked with `--narrate-only`, skip §1 (no `gh pr view` polling) and §2 (no destructive close path). The deterministic close already ran via the passive post-merge sweep — your job is to drain the `state.pending_narration[]` ledger the sweep parked.
132
+
133
+ Flags:
134
+ - `--narrate-only --all` (default when `--narrate-only` is bare) — drain every ledger entry.
135
+ - `--narrate-only --task <id>` — drain only the entry for `<id>`.
136
+
137
+ Per ledger entry `{ task_id, scope, phase_id, closed_at, pr_number }`:
138
+
139
+ 0. **Enumerate the ledger first.** Run `apt-tools task close-merged . --narrate-only [--task <id>]`. The envelope's `closed[]` is the read-only list of pending narration rows (each carries `narration_pending: true`); state.json is not mutated. When `closed[]` is empty, exit early with `{status: 'ok', narrated: [], skipped: [], remaining: 0}` — there is nothing to drain.
140
+ 1. Run `apt-tools features-audit . --apply-stubs --task <task_id>` so the feature registry catches whatever the closed task introduced. If the subprocess exits non-zero, skip the entry with `reason: 'features-audit-failed'` — never block narration on registry update.
141
+ 2. When `phase_id` is non-null, spawn `apt-team-docs-narrator` (background, fire-and-forget) using the same shape as §2.5: `subagent_type: apt-team-docs-narrator`, `run_in_background: true`, `description: Narrate shipped phase {phase_id}`, `prompt: Run in phase-ship mode with --phase {phase_id} --scope {scope}.`. When `phase_id` is null, skip the spawn with `reason: 'no-phase-id'` (quick tasks have no phase to narrate).
142
+ 3. On successful spawn (or successful no-phase skip), drain the row via `apt-tools task narration-drain . --task <task_id>` which acquires `withFileLock(state.json)` and removes the matching `pending_narration[]` entry. On spawn failure, leave the row in place with `reason: 'narrator-spawn-failed'` so the user can re-invoke.
143
+
144
+ **At-least-once retry semantics (FRAMEWORK-BUG-020).** Step 0 is read-only — it does NOT remove rows. Steps 1–3 are the existing per-row drain contract: a row stays in `pending_narration[]` until step 3 calls `narration-drain` successfully. If the orchestrator crashes between step 2 (narrator spawn) and step 3 (drain), the row remains parked and a retry will spawn narration again. Re-spawning is safe because the narrator is **anchor-replace idempotent** by design (see `agents/apt-team-docs-narrator.md` §6 / §2 and the "Idempotent operations only" rule in §notes) — it uses HTML-comment anchors to bound the replaced region in ROADMAP.md, so a second run replaces the same span rather than appending.
145
+
146
+ Emit a summary envelope:
147
+
148
+ ```json
149
+ {
150
+ "status": "ok",
151
+ "command": "close-task-narrate-only",
152
+ "narrated": [{ "task_id": "<id>", "phase_id": "<p|null>", "scope": "<s>" }],
153
+ "skipped": [{ "task_id": "<id>", "reason": "no-phase-id|features-audit-failed|narrator-spawn-failed" }],
154
+ "remaining": <ledger.length>
155
+ }
156
+ ```
157
+
158
+ The regular `apt:close-task` flow ALSO falls through to this drain step at the tail of §2.5 — so users who run the skill manually after the sweep get narration without remembering the flag. The `--narrate-only` flag exists for the explicit "drain only, don't poll gh" case.
159
+
98
160
  </process>
99
161
 
100
162
  <notes>
@@ -21,6 +21,19 @@ gates: []
21
21
  ---
22
22
  <objective>
23
23
  Debug an issue using the scientific method: observe symptoms, form hypotheses, test them systematically, and reach a conclusion. State persists across context resets via `.aperant/debug/{session-id}/DEBUG.md`.
24
+
25
+ **Diagnose-discipline posture loader (Pocock adoption AC10).** You MUST
26
+ load `appendices/diagnose-discipline.md` into reasoning context at
27
+ session start. It carries the 6-phase loop (Reproduce → Minimise →
28
+ Hypothesise → Instrument → Fix → Regression-test) and the **Phase-1
29
+ prerequisite** constraint: do NOT advance from Observe (Section 2) to
30
+ Hypothesize (Section 3) until DEBUG.md records `repro_loop_verified:
31
+ true`. The appendix carries the rationale, the anti-pattern list
32
+ (sprint-to-hypothesis, stack-trace cargo cult, test-the-fix-not-the-bug,
33
+ logging-without-minimising), and the distinction between Phase 1
34
+ "reproduce" and Phase 2 "minimise". Open question #1 was verified —
35
+ apt:debug's existing Section 2 conflates symptom-gathering with
36
+ reproduction, so loading this appendix is non-trivial.
24
37
  </objective>
25
38
 
26
39
  <your_environment>
@@ -59,18 +72,38 @@ mkdir -p .aperant/debug/{session-id}
59
72
  mkdir -p .aperant/debug/{session-id}/checkpoints
60
73
  ```
61
74
 
62
- ## 2. Observe — Gather Symptoms
75
+ ## 2. Observe — Gather Symptoms + Phase 1 (Reproduce — prerequisite)
76
+
77
+ Collect all available evidence about the bug, then establish a
78
+ **reliable repro loop as a hard prerequisite** before advancing to
79
+ Section 3 (Hypothesize). The Phase-1-reproduce constraint comes from
80
+ `appendices/diagnose-discipline.md` and is load-bearing — you do NOT
81
+ emit any hypothesis until DEBUG.md records `repro_loop_verified: true`.
63
82
 
64
- Collect all available evidence about the bug:
83
+ Sub-steps (the existing 4 + 1 prerequisite check):
65
84
 
66
85
  1. **User description:** Extract from `$ARGUMENTS` what the issue is
67
86
  2. **Error output:** If the user provided error messages, record them verbatim
68
- 3. **Reproduce:** Attempt to reproduce the issue:
69
- - Run relevant test commands
70
- - Check logs, console output
71
- - Identify the exact failure point
87
+ 3. **Phase 1 Reproduce (prerequisite, per appendices/diagnose-discipline.md):**
88
+ Establish a reliable repro loop. The loop MUST be:
89
+ - Deterministic (same input → same failure)
90
+ - Cheap (under 10 seconds preferred; certainly under 60)
91
+ - Minimal (no irrelevant setup; just enough to fail)
92
+ Record the repro command + verification in DEBUG.md as
93
+ `repro_command: "..."` and `repro_loop_verified: true`. If you
94
+ cannot reproduce reliably, do NOT proceed to Section 3 — instead,
95
+ loop here: gather more environment context, add logging to the
96
+ target environment, ask the user for repro details. Hypothesis-driven
97
+ debugging without a reliable repro is just hope, dressed up as
98
+ method.
72
99
  4. **Context:** Note environment details (branch, recent commits, dependencies)
73
100
 
101
+ After Phase 1 succeeds, run **Phase 2 — Minimise** (also from the
102
+ appendix): strip the repro to the smallest case that still fails.
103
+ Record the minimised repro in DEBUG.md as `minimised_repro: "..."`.
104
+ Phase 2 prevents Sections 3-5 from anchoring on the first plausible
105
+ cause inside a 200-line repro.
106
+
74
107
  ```bash
75
108
  git log --oneline -10
76
109
  git diff --stat
@@ -0,0 +1,119 @@
1
+ <!--
2
+ Adapted from Matt Pocock's MIT-licensed skill suite:
3
+ https://github.com/mattpocock/skills/blob/main/skills/engineering/diagnose
4
+ Licensed under MIT. Modifications: ported as an apt:debug posture loader
5
+ so the 6-phase loop attaches to the existing 5-phase apt:debug body
6
+ without forking apt:debug's control flow. Aligned with apt:debug's
7
+ DEBUG.md state file and checkpoint conventions.
8
+ -->
9
+
10
+ # Diagnose Discipline — apt:debug posture loader (6-phase loop)
11
+
12
+ This appendix loads into `apt:debug`'s reasoning context as a posture
13
+ upgrade. The existing apt:debug body has 5 phases (Observe → Hypothesize
14
+ → Checkpoint → Test → Conclude) but its Section 2 "Observe" conflates
15
+ symptom-gathering with reproduction. Open question #1 was verified — the
16
+ gap is real, the appendix is non-trivial.
17
+
18
+ This appendix carries the 6-phase Pocock discipline. The skill body
19
+ loads it and uses Phase 1 (Reproduce) as a **hard prerequisite** before
20
+ advancing from Observe to Hypothesize.
21
+
22
+ ## The 6-phase loop
23
+
24
+ 1. **Reproduce.** Establish a reliable repro loop. Until you can
25
+ trigger the bug at will, no hypothesis is testable — you'd be
26
+ guessing about a moving target. The loop MUST be:
27
+ - Deterministic (same input → same failure)
28
+ - Cheap (under 10 seconds preferred; certainly under 60)
29
+ - Minimal (no irrelevant setup; just enough to fail)
30
+
31
+ 2. **Minimise.** Once you can repro, strip the repro to the smallest
32
+ case. Remove every component that isn't load-bearing for the
33
+ failure. A 200-line repro is a hypothesis space; a 10-line repro is
34
+ a near-confirmed cause.
35
+
36
+ 3. **Hypothesise.** ONLY after minimise: write 3-5 ranked falsifiable
37
+ hypotheses. Each hypothesis must:
38
+ - Predict an observable consequence
39
+ - Be testable by changing ONE variable
40
+ - Be ordered by prior probability + cost-to-test
41
+
42
+ 4. **Instrument.** Add the minimum logging / breakpoint / probe to test
43
+ the highest-ranked hypothesis. Change ONE variable. Re-run the
44
+ minimal repro. Observe.
45
+
46
+ 5. **Fix.** When a hypothesis confirms, write the fix. Run the minimal
47
+ repro again — it must now PASS (no more failure). Run the full test
48
+ suite — no new regressions.
49
+
50
+ 6. **Regression-test.** Write a test that pins the fix. The test must
51
+ fail on the pre-fix code and pass on the fixed code. This is what
52
+ stops the bug from coming back six months later when someone
53
+ refactors.
54
+
55
+ ## The Phase-1 prerequisite (load-bearing)
56
+
57
+ apt:debug's body enforces this constraint: **you do NOT advance from
58
+ Observe to Hypothesize until Phase 1 produces a reliable repro loop**.
59
+
60
+ If you cannot reproduce reliably:
61
+
62
+ - Spend the budget on getting the repro working before guessing causes
63
+ - Add logging in the production / target environment to gather more
64
+ evidence of the failure trigger
65
+ - Ask the user for more context (when does it happen? on what input?
66
+ intermittent or consistent?)
67
+
68
+ It is better to spend 80% of your debug budget on the repro and 20% on
69
+ the fix than to spend 100% guessing at causes. Hypothesis-driven
70
+ debugging without a reliable repro is just hope, dressed up as method.
71
+
72
+ ## Distinguishing Phase 1 from apt:debug's existing "Observe"
73
+
74
+ apt:debug's existing Section 2 collects symptom evidence (error
75
+ messages, user reports, environment). That's still valuable — it's the
76
+ *input* to Phase 1. But "I read the error and inferred the cause"
77
+ DOES NOT count as a repro. The repro is a callable artifact: a
78
+ command-line invocation, a test, a script — something the agent can
79
+ run on demand to trigger the failure.
80
+
81
+ ## Distinguishing Phase 2 (Minimise) from Phase 3 (Hypothesise)
82
+
83
+ These are different mental modes. Minimise asks "what's the smallest
84
+ thing that still fails?" — a reductive activity. Hypothesise asks
85
+ "WHY does it fail?" — an explanatory activity. Pocock's discipline
86
+ separates them because skipping Phase 2 and going straight from "I can
87
+ repro" to "here's why" tends to anchor on the first plausible cause
88
+ and miss alternatives.
89
+
90
+ ## Practical consequence for the apt:debug body
91
+
92
+ When this appendix is loaded, apt:debug's Section 2 (Observe) renames
93
+ its "Reproduce" sub-step to **Phase 1 (Reproduce — prerequisite)** and
94
+ adds a gate: the skill MUST NOT emit any hypothesis (Section 3) until
95
+ DEBUG.md records a `repro_loop_verified: true` field.
96
+
97
+ The appendix's Phase 2 (Minimise) becomes a new sub-section between
98
+ apt:debug's Section 2 (Observe) and Section 3 (Hypothesize). DEBUG.md
99
+ gains a `minimised_repro` field.
100
+
101
+ apt:debug's Sections 3-5 (Hypothesize / Checkpoint / Test / Conclude)
102
+ align with Phases 3-6 of this appendix; no structural change there.
103
+
104
+ ## Anti-patterns this discipline prevents
105
+
106
+ - **Sprint-to-hypothesis.** Agent reads the error, picks the first
107
+ plausible cause, writes a fix, and ships. The bug comes back two
108
+ days later under different inputs.
109
+ - **Stack-trace cargo cult.** Agent assumes the line at the top of the
110
+ stack trace IS the bug. Often it's an effect, not a cause.
111
+ - **Test the fix, not the bug.** Agent writes a test that proves the
112
+ fix works but doesn't exercise the original buggy condition. The
113
+ regression test is a no-op against the future regression.
114
+ - **Logging without minimising.** Agent adds 50 log lines in a 200-line
115
+ repro, then drowns in noise. Minimise first; THEN instrument the
116
+ minimal repro.
117
+
118
+ Loading this appendix and following its Phase 1 prerequisite cuts most
119
+ of these failure modes by structural constraint.