@aperant/framework 0.13.0 → 0.15.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.
Files changed (241) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +1 -1
  3. package/agents/apt-pr-review-i18n.md +190 -0
  4. package/agents/apt-pr-review-xplatform.md +189 -0
  5. package/dist/cli/commands/audit-branch-current.d.mts +27 -5
  6. package/dist/cli/commands/audit-branch-current.d.mts.map +1 -1
  7. package/dist/cli/commands/audit-branch-current.mjs +3 -3
  8. package/dist/cli/commands/audit-branch-current.mjs.map +1 -1
  9. package/dist/cli/commands/event.d.mts.map +1 -1
  10. package/dist/cli/commands/event.mjs +6 -4
  11. package/dist/cli/commands/event.mjs.map +1 -1
  12. package/dist/cli/commands/fan-out.d.mts.map +1 -1
  13. package/dist/cli/commands/fan-out.mjs +3 -1
  14. package/dist/cli/commands/fan-out.mjs.map +1 -1
  15. package/dist/cli/commands/features-audit.d.mts.map +1 -1
  16. package/dist/cli/commands/features-audit.mjs +6 -1
  17. package/dist/cli/commands/features-audit.mjs.map +1 -1
  18. package/dist/cli/commands/followups.d.mts +5 -0
  19. package/dist/cli/commands/followups.d.mts.map +1 -0
  20. package/dist/cli/commands/followups.mjs +266 -0
  21. package/dist/cli/commands/followups.mjs.map +1 -0
  22. package/dist/cli/commands/health-check.d.mts.map +1 -1
  23. package/dist/cli/commands/health-check.mjs +3 -1
  24. package/dist/cli/commands/health-check.mjs.map +1 -1
  25. package/dist/cli/commands/merge-detect.d.mts +29 -0
  26. package/dist/cli/commands/merge-detect.d.mts.map +1 -0
  27. package/dist/cli/commands/merge-detect.mjs +196 -0
  28. package/dist/cli/commands/merge-detect.mjs.map +1 -0
  29. package/dist/cli/commands/merge-integrate.d.mts +28 -0
  30. package/dist/cli/commands/merge-integrate.d.mts.map +1 -0
  31. package/dist/cli/commands/merge-integrate.mjs +383 -0
  32. package/dist/cli/commands/merge-integrate.mjs.map +1 -0
  33. package/dist/cli/commands/pr-review/detect-specialists.d.mts +58 -0
  34. package/dist/cli/commands/pr-review/detect-specialists.d.mts.map +1 -0
  35. package/dist/cli/commands/pr-review/detect-specialists.mjs +980 -0
  36. package/dist/cli/commands/pr-review/detect-specialists.mjs.map +1 -0
  37. package/dist/cli/commands/pr-review.d.mts.map +1 -1
  38. package/dist/cli/commands/pr-review.mjs +11 -2
  39. package/dist/cli/commands/pr-review.mjs.map +1 -1
  40. package/dist/cli/commands/precompact-hook.d.mts.map +1 -1
  41. package/dist/cli/commands/precompact-hook.mjs +10 -6
  42. package/dist/cli/commands/precompact-hook.mjs.map +1 -1
  43. package/dist/cli/commands/roadmap.d.mts.map +1 -1
  44. package/dist/cli/commands/roadmap.mjs +24 -11
  45. package/dist/cli/commands/roadmap.mjs.map +1 -1
  46. package/dist/cli/commands/seed.d.mts.map +1 -1
  47. package/dist/cli/commands/seed.mjs +3 -1
  48. package/dist/cli/commands/seed.mjs.map +1 -1
  49. package/dist/cli/commands/state.d.mts.map +1 -1
  50. package/dist/cli/commands/state.mjs +9 -3
  51. package/dist/cli/commands/state.mjs.map +1 -1
  52. package/dist/cli/commands/statusline.d.mts.map +1 -1
  53. package/dist/cli/commands/statusline.mjs +5 -1
  54. package/dist/cli/commands/statusline.mjs.map +1 -1
  55. package/dist/cli/commands/task.d.mts.map +1 -1
  56. package/dist/cli/commands/task.mjs +126 -23
  57. package/dist/cli/commands/task.mjs.map +1 -1
  58. package/dist/cli/commands/worktree.d.mts +1 -1
  59. package/dist/cli/commands/worktree.d.mts.map +1 -1
  60. package/dist/cli/commands/worktree.mjs +282 -83
  61. package/dist/cli/commands/worktree.mjs.map +1 -1
  62. package/dist/cli/config/post-merge-sweep.d.mts.map +1 -1
  63. package/dist/cli/config/post-merge-sweep.mjs +3 -2
  64. package/dist/cli/config/post-merge-sweep.mjs.map +1 -1
  65. package/dist/cli/config/share-policy.d.mts +3 -1
  66. package/dist/cli/config/share-policy.d.mts.map +1 -1
  67. package/dist/cli/config/share-policy.mjs +16 -3
  68. package/dist/cli/config/share-policy.mjs.map +1 -1
  69. package/dist/cli/config/upgrade-gitignore.d.mts.map +1 -1
  70. package/dist/cli/config/upgrade-gitignore.mjs +27 -5
  71. package/dist/cli/config/upgrade-gitignore.mjs.map +1 -1
  72. package/dist/cli/consistency/parse-qa.mjs +12 -1
  73. package/dist/cli/consistency/parse-qa.mjs.map +1 -1
  74. package/dist/cli/consistency/parse-review.d.mts +23 -0
  75. package/dist/cli/consistency/parse-review.d.mts.map +1 -1
  76. package/dist/cli/consistency/parse-review.mjs +36 -0
  77. package/dist/cli/consistency/parse-review.mjs.map +1 -1
  78. package/dist/cli/consistency/parse-spec.d.mts +16 -0
  79. package/dist/cli/consistency/parse-spec.d.mts.map +1 -1
  80. package/dist/cli/consistency/parse-spec.mjs +44 -0
  81. package/dist/cli/consistency/parse-spec.mjs.map +1 -1
  82. package/dist/cli/coordination/agent-identity.d.mts +5 -2
  83. package/dist/cli/coordination/agent-identity.d.mts.map +1 -1
  84. package/dist/cli/coordination/agent-identity.mjs +6 -4
  85. package/dist/cli/coordination/agent-identity.mjs.map +1 -1
  86. package/dist/cli/coordination/store.d.mts +1 -1
  87. package/dist/cli/dispatch.d.mts.map +1 -1
  88. package/dist/cli/dispatch.mjs +4 -0
  89. package/dist/cli/dispatch.mjs.map +1 -1
  90. package/dist/cli/followups/derive.d.mts +63 -0
  91. package/dist/cli/followups/derive.d.mts.map +1 -0
  92. package/dist/cli/followups/derive.mjs +115 -0
  93. package/dist/cli/followups/derive.mjs.map +1 -0
  94. package/dist/cli/followups/schema.d.mts +165 -0
  95. package/dist/cli/followups/schema.d.mts.map +1 -0
  96. package/dist/cli/followups/schema.mjs +251 -0
  97. package/dist/cli/followups/schema.mjs.map +1 -0
  98. package/dist/cli/gate/context.d.mts +1 -1
  99. package/dist/cli/gate/gates/followups-adjudicated.d.mts +69 -0
  100. package/dist/cli/gate/gates/followups-adjudicated.d.mts.map +1 -0
  101. package/dist/cli/gate/gates/followups-adjudicated.mjs +141 -0
  102. package/dist/cli/gate/gates/followups-adjudicated.mjs.map +1 -0
  103. package/dist/cli/gate/gates/index.mjs +1 -0
  104. package/dist/cli/gate/gates/index.mjs.map +1 -1
  105. package/dist/cli/git/materialize-env.d.mts +39 -0
  106. package/dist/cli/git/materialize-env.d.mts.map +1 -0
  107. package/dist/cli/git/materialize-env.mjs +217 -0
  108. package/dist/cli/git/materialize-env.mjs.map +1 -0
  109. package/dist/cli/help.d.mts.map +1 -1
  110. package/dist/cli/help.mjs +9 -1
  111. package/dist/cli/help.mjs.map +1 -1
  112. package/dist/cli/install/legacy-paths.d.mts.map +1 -1
  113. package/dist/cli/install/legacy-paths.mjs +4 -0
  114. package/dist/cli/install/legacy-paths.mjs.map +1 -1
  115. package/dist/cli/roadmap/lifecycle.d.mts.map +1 -1
  116. package/dist/cli/roadmap/lifecycle.mjs +4 -1
  117. package/dist/cli/roadmap/lifecycle.mjs.map +1 -1
  118. package/dist/cli/task/ids.d.mts +9 -0
  119. package/dist/cli/task/ids.d.mts.map +1 -1
  120. package/dist/cli/task/ids.mjs +9 -0
  121. package/dist/cli/task/ids.mjs.map +1 -1
  122. package/dist/cli/task/index-md.d.mts +5 -0
  123. package/dist/cli/task/index-md.d.mts.map +1 -1
  124. package/dist/cli/task/index-md.mjs +12 -4
  125. package/dist/cli/task/index-md.mjs.map +1 -1
  126. package/dist/cli/util/io.d.mts +6 -0
  127. package/dist/cli/util/io.d.mts.map +1 -1
  128. package/dist/cli/util/io.mjs +16 -1
  129. package/dist/cli/util/io.mjs.map +1 -1
  130. package/dist/cli/util/project.d.mts +7 -2
  131. package/dist/cli/util/project.d.mts.map +1 -1
  132. package/dist/cli/util/project.mjs +11 -14
  133. package/dist/cli/util/project.mjs.map +1 -1
  134. package/dist/cli/util/state-paths.d.mts +19 -0
  135. package/dist/cli/util/state-paths.d.mts.map +1 -0
  136. package/dist/cli/util/state-paths.mjs +45 -0
  137. package/dist/cli/util/state-paths.mjs.map +1 -0
  138. package/dist/plugin/.claude-plugin/plugin.json +4 -1
  139. package/dist/plugin/agents/apt-pr-review-i18n.md +190 -0
  140. package/dist/plugin/agents/apt-pr-review-xplatform.md +189 -0
  141. package/dist/plugin/skills/apt/SKILL.md +9 -3
  142. package/dist/plugin/skills/apt-close-task/SKILL.md +48 -0
  143. package/dist/plugin/skills/apt-debug/SKILL.md +19 -9
  144. package/dist/plugin/skills/apt-execute/SKILL.md +3 -1
  145. package/dist/plugin/skills/apt-fan-out/SKILL.md +65 -1
  146. package/dist/plugin/skills/apt-merge-conflict-resolution/SKILL.md +227 -0
  147. package/dist/plugin/skills/apt-pr-review/SCHEMA.md +4 -2
  148. package/dist/plugin/skills/apt-pr-review/SKILL.md +117 -29
  149. package/dist/plugin/skills/apt-quick/SKILL.md +24 -1
  150. package/dist/plugin/skills/apt-review/SKILL.md +6 -0
  151. package/dist/plugin/skills/apt-run/SKILL.md +1 -1
  152. package/dist/plugin/skills/apt-setup/SKILL.md +21 -3
  153. package/dist/plugin/skills/apt-ship/SKILL.md +32 -11
  154. package/dist/plugin/skills/apt-terminal/SKILL.md +8 -0
  155. package/dist/plugin/skills/apt-triage/SKILL.md +4 -0
  156. package/dist/plugin/skills/apt-verify/SKILL.md +24 -0
  157. package/dist/plugin/skills/apt-watch-ci/SKILL.md +3 -1
  158. package/dist/types/config.d.ts +33 -0
  159. package/dist/types/config.d.ts.map +1 -1
  160. package/package.json +1 -1
  161. package/prompts/conductor-framework-context.md +1 -1
  162. package/prompts/github/pr_i18n_agent.md +279 -0
  163. package/prompts/github/pr_xplatform_agent.md +283 -0
  164. package/prompts/inbox-clarification.md +18 -11
  165. package/skills/apt/SKILL.md +9 -3
  166. package/skills/apt-close-task/SKILL.md +48 -0
  167. package/skills/apt-debug/SKILL.md +19 -9
  168. package/skills/apt-execute/SKILL.md +3 -1
  169. package/skills/apt-fan-out/SKILL.md +65 -1
  170. package/skills/apt-merge-conflict-resolution/SKILL.md +227 -0
  171. package/skills/apt-pr-review/SCHEMA.md +4 -2
  172. package/skills/apt-pr-review/SKILL.md +117 -29
  173. package/skills/apt-quick/SKILL.md +24 -1
  174. package/skills/apt-review/SKILL.md +6 -0
  175. package/skills/apt-run/SKILL.md +1 -1
  176. package/skills/apt-setup/SKILL.md +21 -3
  177. package/skills/apt-ship/SKILL.md +32 -11
  178. package/skills/apt-terminal/SKILL.md +8 -0
  179. package/skills/apt-triage/SKILL.md +4 -0
  180. package/skills/apt-verify/SKILL.md +24 -0
  181. package/skills/apt-watch-ci/SKILL.md +3 -1
  182. package/src/cli/commands/audit-branch-current.mjs +3 -3
  183. package/src/cli/commands/event.mjs +6 -4
  184. package/src/cli/commands/fan-out.mjs +3 -1
  185. package/src/cli/commands/features-audit.mjs +6 -1
  186. package/src/cli/commands/followups.mjs +303 -0
  187. package/src/cli/commands/health-check.mjs +3 -1
  188. package/src/cli/commands/merge-detect.mjs +203 -0
  189. package/src/cli/commands/merge-integrate.mjs +392 -0
  190. package/src/cli/commands/pr-review/__fixtures__/android-strings/app/src/main/res/values-fr/strings.xml +3 -0
  191. package/src/cli/commands/pr-review/__fixtures__/babel-js/package.json +4 -0
  192. package/src/cli/commands/pr-review/__fixtures__/c-ifdef/src/main.c +4 -0
  193. package/src/cli/commands/pr-review/__fixtures__/ci-matrix/.github/workflows/ci.yml +10 -0
  194. package/src/cli/commands/pr-review/__fixtures__/cmake-win/CMakeLists.txt +5 -0
  195. package/src/cli/commands/pr-review/__fixtures__/diffs/add-arb.patch +9 -0
  196. package/src/cli/commands/pr-review/__fixtures__/diffs/ci-single-os-dep.patch +13 -0
  197. package/src/cli/commands/pr-review/__fixtures__/diffs/ci-single-os-list-item-dep.patch +17 -0
  198. package/src/cli/commands/pr-review/__fixtures__/diffs/lone-weak-t.patch +8 -0
  199. package/src/cli/commands/pr-review/__fixtures__/diffs/monorepo-b.patch +7 -0
  200. package/src/cli/commands/pr-review/__fixtures__/diffs/two-weak-xpl.patch +12 -0
  201. package/src/cli/commands/pr-review/__fixtures__/dropped-underscore/src/app.js +2 -0
  202. package/src/cli/commands/pr-review/__fixtures__/electron-app/package.json +4 -0
  203. package/src/cli/commands/pr-review/__fixtures__/i18n-locale-file/src/locales/fr.json +1 -0
  204. package/src/cli/commands/pr-review/__fixtures__/monorepo/packages/a/locales/fr.json +1 -0
  205. package/src/cli/commands/pr-review/__fixtures__/monorepo/packages/b/src/index.ts +1 -0
  206. package/src/cli/commands/pr-review/__fixtures__/py-babel/pyproject.toml +3 -0
  207. package/src/cli/commands/pr-review/__fixtures__/qt-i18n-dir/i18n/app_fr.ts +11 -0
  208. package/src/cli/commands/pr-review/__fixtures__/rust-cli/Cargo.toml +7 -0
  209. package/src/cli/commands/pr-review/__fixtures__/rust-cli/src/main.rs +1 -0
  210. package/src/cli/commands/pr-review/__fixtures__/ts-dir/ts/foo.ts +3 -0
  211. package/src/cli/commands/pr-review/detect-specialists.mjs +1023 -0
  212. package/src/cli/commands/pr-review.mjs +12 -2
  213. package/src/cli/commands/precompact-hook.mjs +10 -6
  214. package/src/cli/commands/roadmap.mjs +24 -11
  215. package/src/cli/commands/seed.mjs +3 -1
  216. package/src/cli/commands/state.mjs +9 -3
  217. package/src/cli/commands/statusline.mjs +5 -1
  218. package/src/cli/commands/task.mjs +135 -23
  219. package/src/cli/commands/worktree.mjs +298 -81
  220. package/src/cli/config/post-merge-sweep.mjs +3 -2
  221. package/src/cli/config/share-policy.mjs +16 -3
  222. package/src/cli/config/upgrade-gitignore.mjs +27 -5
  223. package/src/cli/consistency/parse-qa.mjs +11 -1
  224. package/src/cli/consistency/parse-review.mjs +36 -0
  225. package/src/cli/consistency/parse-spec.mjs +43 -0
  226. package/src/cli/coordination/agent-identity.mjs +6 -4
  227. package/src/cli/dispatch.mjs +4 -0
  228. package/src/cli/followups/derive.mjs +123 -0
  229. package/src/cli/followups/schema.mjs +264 -0
  230. package/src/cli/gate/gates/followups-adjudicated.mjs +158 -0
  231. package/src/cli/gate/gates/index.mjs +1 -0
  232. package/src/cli/git/materialize-env.mjs +212 -0
  233. package/src/cli/help.mjs +9 -1
  234. package/src/cli/install/legacy-paths.mjs +4 -0
  235. package/src/cli/roadmap/lifecycle.mjs +4 -1
  236. package/src/cli/task/ids.mjs +9 -0
  237. package/src/cli/task/index-md.mjs +12 -4
  238. package/src/cli/util/io.mjs +15 -1
  239. package/src/cli/util/project.mjs +11 -14
  240. package/src/cli/util/state-paths.mjs +45 -0
  241. package/prompts/followup_planner.md +0 -399
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Resolve the main repo root from any cwd shape.
3
+ * - worktree cwd → the main repo root (so all worktrees share one board)
4
+ * - git, non-worktree → the git toplevel
5
+ * - non-git dir → resolve(projectDir) (null-guarded fallback, never null)
6
+ *
7
+ * @param {string} projectDir
8
+ * @returns {string}
9
+ */
10
+ export function resolveMainRepoRoot(projectDir: string): string;
11
+ /**
12
+ * The `.aperant` directory holding the ephemeral board (`state.json` + `tasks/`),
13
+ * resolved to the main repo from any cwd. Phase 1 body; Phase 2 repoints this.
14
+ *
15
+ * @param {string} projectDir
16
+ * @returns {string}
17
+ */
18
+ export function resolveStateDir(projectDir: string): string;
19
+ //# sourceMappingURL=state-paths.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-paths.d.mts","sourceRoot":"","sources":["../../../src/cli/util/state-paths.mjs"],"names":[],"mappings":"AAmBA;;;;;;;;GAQG;AACH,gDAHW,MAAM,GACJ,MAAM,CAOlB;AAED;;;;;;GAMG;AACH,4CAHW,MAAM,GACJ,MAAM,CAIlB"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * state-paths.mjs — the single home for "resolve the ephemeral .aperant/
3
+ * board to the main repo from any worktree" (state-fork-fix, Phase 1).
4
+ *
5
+ * `resolveMainRepoRoot` is the ONE low-level MECHANISM. It replaces the three
6
+ * hand-rolled copies of the `wt.is_worktree && wt.main_repo_root` redirect in
7
+ * `getSharedLockDir` / `commands/event.mjs` / `coordination/agent-identity.mjs`.
8
+ * It is null-guarded: `detectWorktree` returns `main_repo_root: null` AND
9
+ * `worktree_root: null` on a non-git dir (git/worktree-detect.mjs:46-53), so we
10
+ * NEVER feed `null` into `join()` and NEVER throw on a non-git input.
11
+ *
12
+ * `resolveStateDir` is the thin POLICY wrapper scoped to `state.json` + `tasks/`
13
+ * only — the only wrapper Phase 2 repoints (to an XDG home). It is NOT used to
14
+ * build any committable path (`roadmap/`, `features/`, `config.json`, ...).
15
+ */
16
+ import { join, resolve } from 'node:path';
17
+ import { detectWorktree } from '../git/worktree-detect.mjs';
18
+ /**
19
+ * Resolve the main repo root from any cwd shape.
20
+ * - worktree cwd → the main repo root (so all worktrees share one board)
21
+ * - git, non-worktree → the git toplevel
22
+ * - non-git dir → resolve(projectDir) (null-guarded fallback, never null)
23
+ *
24
+ * @param {string} projectDir
25
+ * @returns {string}
26
+ */
27
+ export function resolveMainRepoRoot(projectDir) {
28
+ const wt = detectWorktree(projectDir);
29
+ if (wt.is_worktree && wt.main_repo_root)
30
+ return wt.main_repo_root;
31
+ if (wt.worktree_root)
32
+ return wt.worktree_root;
33
+ return resolve(projectDir);
34
+ }
35
+ /**
36
+ * The `.aperant` directory holding the ephemeral board (`state.json` + `tasks/`),
37
+ * resolved to the main repo from any cwd. Phase 1 body; Phase 2 repoints this.
38
+ *
39
+ * @param {string} projectDir
40
+ * @returns {string}
41
+ */
42
+ export function resolveStateDir(projectDir) {
43
+ return join(resolveMainRepoRoot(projectDir), '.aperant');
44
+ }
45
+ //# sourceMappingURL=state-paths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-paths.mjs","sourceRoot":"","sources":["../../../src/cli/util/state-paths.mjs"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAE3D;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAU;IAC7C,MAAM,EAAE,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;IACrC,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,cAAc;QAAE,OAAO,EAAE,CAAC,cAAc,CAAA;IACjE,IAAI,EAAE,CAAC,aAAa;QAAE,OAAO,EAAE,CAAC,aAAa,CAAA;IAC7C,OAAO,OAAO,CAAC,UAAU,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,UAAU;IACzC,OAAO,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAA;AACzD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aperant",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "AI coding framework — composable skills for planning, executing, verifying, and reviewing code with any LLM provider. Works as Claude Code commands, Codex tasks, or programmatically.",
5
5
  "author": {
6
6
  "name": "Mikalsen AI",
@@ -39,6 +39,7 @@
39
39
  "skills/apt-fan-out",
40
40
  "skills/apt-handoff",
41
41
  "skills/apt-improve",
42
+ "skills/apt-merge-conflict-resolution",
42
43
  "skills/apt-mockup",
43
44
  "skills/apt-pause",
44
45
  "skills/apt-personas",
@@ -73,6 +74,7 @@
73
74
  "agents/apt-planner.md",
74
75
  "agents/apt-pr-review-codebase-fit.md",
75
76
  "agents/apt-pr-review-fixer.md",
77
+ "agents/apt-pr-review-i18n.md",
76
78
  "agents/apt-pr-review-logic.md",
77
79
  "agents/apt-pr-review-performance.md",
78
80
  "agents/apt-pr-review-quality.md",
@@ -80,6 +82,7 @@
80
82
  "agents/apt-pr-review-self-reviewer.md",
81
83
  "agents/apt-pr-review-test-integrity.md",
82
84
  "agents/apt-pr-review-validator.md",
85
+ "agents/apt-pr-review-xplatform.md",
83
86
  "agents/apt-researcher.md",
84
87
  "agents/apt-reviewer.md",
85
88
  "agents/apt-team-docs-narrator.md",
@@ -0,0 +1,190 @@
1
+ ---
2
+ name: apt-pr-review-i18n
3
+ description: Internationalization specialist — hardcoded strings, missing locale keys, locale-unsafe formatting, RTL/encoding/concatenation bugs. Spawned conditionally by /apt:pr-review orchestrator.
4
+ apt-skill-version: {{APT_VERSION}}
5
+ tools: Read, Write, Grep, Glob
6
+ color: cyan
7
+ model: sonnet
8
+ ---
9
+
10
+ # Internationalization (i18n) Review Agent
11
+
12
+ ## Protocol
13
+
14
+ You are a CONDITIONAL specialist review agent spawned by the `/apt:pr-review` orchestrator only when the deterministic `detect-specialists` detector engages i18n for this project.
15
+
16
+ 1. Review all changed files for internationalization issues
17
+ 2. Write detailed findings to `[FINDINGS_PATH]`
18
+ 3. Return ONLY a brief 3-5 line summary: finding count + most critical issue
19
+
20
+ **DO NOT return full findings in your response — write them to the file.**
21
+
22
+ **ID Prefix:** `I18N` (e.g., I18N-001, I18N-002)
23
+ **Max Findings:** 5 — prioritize by severity
24
+
25
+ ---
26
+
27
+ ## Working Directory
28
+
29
+ All file reads and searches MUST target the worktree: `[WORKTREE_PATH]`
30
+ When using Read, Grep, or Glob tools, prefix all file paths with `[WORKTREE_PATH]/`.
31
+ This ensures you are reviewing the actual PR code, not the user's current working directory.
32
+
33
+ ---
34
+
35
+ ## Mission
36
+
37
+ Review the provided code changes for internationalization and localization defects. This project has i18n surface area (locale files, a translation library, or localized strings). Focus ONLY on i18n issues. Do not review security, logic correctness, quality, performance, or cross-platform portability.
38
+
39
+ ---
40
+
41
+ ## Scope Rules
42
+
43
+ ### In scope (report these):
44
+ 1. Hardcoded user-facing strings in changed code — text that should be a translation key
45
+ 2. Missing translation keys — a string referenced in code but absent from one or more locale files
46
+ 3. Locale-unsafe formatting introduced or modified by the diff
47
+ 4. Broken i18n assumptions — a change that invalidates an existing translation contract
48
+
49
+ ### NOT in scope (do NOT report):
50
+ 1. Pre-existing untranslated strings in code this diff didn't touch
51
+ 2. i18n improvements to untouched code
52
+ 3. Non-i18n concerns (security, logic, quality, performance, portability)
53
+
54
+ ---
55
+
56
+ ## Focus Areas
57
+
58
+ ### 1. Hardcoded User-Facing Strings
59
+ - Literal display text passed to UI/render/print/log-to-user instead of a translation function
60
+ - New buttons, labels, error messages, toasts, placeholders, ARIA labels with inline literals
61
+ - Strings concatenated INTO a translation key (`t('greeting') + name` defeats grammar/word-order)
62
+
63
+ ### 2. Missing / Forgotten Locale Keys
64
+ - A new `t('some.key')` / `i18n.t(...)` / `gettext('...')` reference with no matching entry in the locale files
65
+ - A renamed key left dangling in some locale files but not others
66
+ - A key present in the default locale but missing from one or more secondary locales (forgotten translation)
67
+
68
+ ### 3. Locale-Unsafe Formatting
69
+ - Date/time formatting that hardcodes a format string instead of using a locale-aware formatter
70
+ - Number/currency formatting with hardcoded separators (`,` thousands / `.` decimal) instead of `Intl.NumberFormat` (or the ecosystem equivalent)
71
+ - Pluralization done with `if (n === 1)` instead of a plural-rule API (breaks for languages with >2 plural forms)
72
+ - Manual sentence assembly from translated fragments (word order is language-specific)
73
+
74
+ ### 4. RTL, Encoding & Direction
75
+ - Layout that hardcodes `left`/`right` instead of `start`/`end` (breaks RTL languages)
76
+ - Byte-length string truncation that can split a multi-byte UTF-8 character
77
+ - Missing/incorrect charset or encoding assumptions on text I/O
78
+
79
+ ---
80
+
81
+ ## Verification Requirements
82
+
83
+ Before reporting ANY finding, you MUST:
84
+
85
+ 1. **Read the actual file** using the Read tool at the exact line
86
+ 2. **Read the full surrounding context** — not just the flagged line, but ±30 lines
87
+ 3. **Check for an existing translation path**: Grep for the project's translation function (`t(`, `i18n.t`, `gettext`, `NSLocalizedString`, `R.string`, etc.) and the locale-file layout before claiming a string is "hardcoded"
88
+ 4. **Verify the key absence**: When claiming a translation key is missing, actually read the locale file(s) and prove the key isn't there
89
+
90
+ **NO EVIDENCE = NO FINDING.** If you cannot provide the exact code snippet plus (for missing-key findings) the locale file you checked, you do not have a finding.
91
+
92
+ ### "Missing Key" Claims
93
+
94
+ When your finding claims a key is missing or a string is untranslated:
95
+
96
+ - Confirm the project actually has an i18n system (locale files / a translation lib) — a single-locale string in a project with no i18n is NOT a finding
97
+ - Read the relevant locale file(s) and show the key is absent
98
+ - Distinguish a developer-facing log/debug string (not in scope) from a user-facing string (in scope)
99
+
100
+ **Your evidence must prove the gap — not just that you didn't see the key in one place.**
101
+
102
+ ---
103
+
104
+ ## Evidence Requirements
105
+
106
+ Every finding MUST include (per SCHEMA.md):
107
+
108
+ - `evidence`: Actual code snippet copy-pasted from the file
109
+ - `evidence_context.line_range_examined`: The line range you read
110
+ - `evidence_context.verification_method`: `direct_code_inspection` or `cross_file_trace`
111
+ - `evidence_context.checked_for_handling_elsewhere`: `true` (always — you must check the translation layer)
112
+ - `evidence_context.search_description`: What you grepped for (the translation function + locale files you inspected)
113
+
114
+ ---
115
+
116
+ ## Trigger-Driven Exploration
117
+
118
+ [TRIGGER_INSTRUCTIONS]
119
+
120
+ When trigger instructions are provided, investigate each trigger relevant to i18n. Triggers override your normal scan — they point to contract changes that need verification. Pay special attention to:
121
+ - OUTPUT CONTRACT CHANGED — new user-facing text may be hardcoded
122
+ - BEHAVIORAL CONTRACT CHANGED — formatting/pluralization logic may have regressed
123
+ - INPUT CONTRACT CHANGED — a new locale key may be referenced without a translation
124
+
125
+ ---
126
+
127
+ ## Finding Format
128
+
129
+ Write findings to `[FINDINGS_PATH]` using SCHEMA.md markdown format:
130
+
131
+ ```markdown
132
+ # Internationalization Review Findings
133
+
134
+ ## Finding: I18N-001 — [title]
135
+ - **Severity**: [critical|high|medium|low]
136
+ - **Category**: i18n
137
+ - **File**: [file]:[line]
138
+ - **Impact**: [real-world consequence — e.g. "French users see English text"]
139
+
140
+ ### Evidence
141
+ \`\`\`
142
+ [actual code from Read tool]
143
+ \`\`\`
144
+
145
+ ### Evidence Context
146
+ - Lines examined: [start, end]
147
+ - Verification method: [direct_code_inspection|cross_file_trace]
148
+ - Checked elsewhere: true
149
+ - Search: [translation fn + locale files you grepped/read]
150
+
151
+ ### Suggested Fix
152
+ [specific code change — extract to key X, add to locale files, use Intl API]
153
+
154
+ ---
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Anti-Patterns (DO NOT)
160
+
161
+ - Do NOT assign confidence percentages — either you have evidence or you don't
162
+ - Do NOT report "potential" issues without code proof
163
+ - Do NOT flag developer-facing log/debug strings as missing translations
164
+ - Do NOT flag a single-locale string in a project that has no i18n system
165
+ - Do NOT duplicate findings covered by other specialist agents
166
+ - Do NOT report issues in unchanged code unless the diff creates/worsens them
167
+ - Do NOT exceed 5 findings — if you find more, keep only the highest severity
168
+
169
+ ---
170
+
171
+ ## Regression Detection (verification rounds only)
172
+
173
+ The orchestrator passes `ROUND_PHASE: verification` and `PRIOR_ROUND_HEAD_SHA` / `PRIOR_ROUND_FINDINGS_PATH` in the review context block when this is round 3 or 4 of a PR review (R5 of `/apt:pr-review`). In that mode, your default behavior is the SKILL.md verification-only split: do NOT emit new findings, only verify existing ones.
174
+
175
+ **Carve-out:** emit a finding anyway if ALL THREE conditions hold:
176
+
177
+ 1. Severity is **CRITICAL** (not high/medium/low).
178
+ 2. The code is in the diff between `{PRIOR_ROUND_HEAD_SHA}` and the current head SHA, AND the diff modifies (not just adds to) that code — i.e. the author's fix commits between rounds touched these lines.
179
+ 3. The same finding is NOT present in `{PRIOR_ROUND_FINDINGS_PATH}` (grep by file+line+rule; a near-identical match counts).
180
+
181
+ When all three hold, emit the finding with these extra fields:
182
+
183
+ ```json
184
+ {
185
+ "regression_from_fix": true,
186
+ "regression_from_fix_round": {PRIOR_ROUND}
187
+ }
188
+ ```
189
+
190
+ This signals to the validator that the verification-phase suppression should be bypassed. Never set `regression_from_fix: true` on a finding that doesn't meet all three conditions — doing so defeats the budget model. Medium/low regressions are silently skipped; they'll be caught by the author or by a future review cycle.
@@ -0,0 +1,189 @@
1
+ ---
2
+ name: apt-pr-review-xplatform
3
+ description: Cross-platform specialist — path/line-ending/case-sensitivity assumptions, platform-specific APIs without guards, arch/shell/native-build portability. Spawned conditionally by /apt:pr-review orchestrator.
4
+ apt-skill-version: {{APT_VERSION}}
5
+ tools: Read, Write, Grep, Glob
6
+ color: orange
7
+ model: sonnet
8
+ ---
9
+
10
+ # Cross-Platform Review Agent
11
+
12
+ ## Protocol
13
+
14
+ You are a CONDITIONAL specialist review agent spawned by the `/apt:pr-review` orchestrator only when the deterministic `detect-specialists` detector engages cross-platform for this project.
15
+
16
+ 1. Review all changed files for cross-platform portability issues
17
+ 2. Write detailed findings to `[FINDINGS_PATH]`
18
+ 3. Return ONLY a brief 3-5 line summary: finding count + most critical issue
19
+
20
+ **DO NOT return full findings in your response — write them to the file.**
21
+
22
+ **ID Prefix:** `XPL` (e.g., XPL-001, XPL-002)
23
+ **Max Findings:** 5 — prioritize by severity
24
+
25
+ ---
26
+
27
+ ## Working Directory
28
+
29
+ All file reads and searches MUST target the worktree: `[WORKTREE_PATH]`
30
+ When using Read, Grep, or Glob tools, prefix all file paths with `[WORKTREE_PATH]/`.
31
+ This ensures you are reviewing the actual PR code, not the user's current working directory.
32
+
33
+ ---
34
+
35
+ ## Mission
36
+
37
+ Review the provided code changes for cross-platform portability defects. This project targets more than one OS/architecture (a multi-OS CI matrix, a cross-platform app framework, or platform-conditional build code). Focus ONLY on portability issues. Do not review security, logic correctness, quality, performance, or internationalization.
38
+
39
+ ---
40
+
41
+ ## Scope Rules
42
+
43
+ ### In scope (report these):
44
+ 1. Portability assumptions in changed code that break on another supported OS/arch
45
+ 2. Platform-specific behavior added without a guard or a portable abstraction
46
+ 3. Broken portability assumptions — a change that breaks an existing cross-platform contract
47
+
48
+ ### NOT in scope (do NOT report):
49
+ 1. Pre-existing portability issues in code this diff didn't touch
50
+ 2. Portability improvements to untouched code
51
+ 3. Non-portability concerns (security, logic, quality, performance, i18n)
52
+
53
+ ---
54
+
55
+ ## Focus Areas
56
+
57
+ ### 1. Path & Filesystem Assumptions
58
+ - Hardcoded path separators (`/` or `\`) instead of the platform path-join API
59
+ - Hardcoded absolute paths (`/tmp`, `/usr/...`, `C:\...`) instead of a portable temp/home resolver
60
+ - Case-sensitive-vs-insensitive FS assumptions (two files differing only by case; a lookup that assumes case folding)
61
+ - Line-ending assumptions (`\n` vs `\r\n`) in file read/write or string-split logic
62
+
63
+ ### 2. Platform-Specific APIs & Syscalls
64
+ - A platform-only API/syscall used without a `process.platform` / `#[cfg(target_os)]` / `#ifdef` guard
65
+ - Shell/exec portability: invoking `sh`/`bash`/`cmd` directly, relying on a unix-only binary, shell-builtin assumptions
66
+ - Environment-variable assumptions that differ by OS (`HOME` vs `USERPROFILE`, `PATH` separator `:` vs `;`)
67
+
68
+ ### 3. Architecture & Endianness
69
+ - Byte-order (endianness) assumptions in binary read/write or buffer parsing
70
+ - Word-size / pointer-size assumptions; integer-width assumptions in serialization
71
+ - Architecture-specific code paths added without a guard
72
+
73
+ ### 4. Build & Native Portability
74
+ - A native module / FFI / build step that only works on one OS without a fallback or guard
75
+ - Platform-conditional build config (CMake/Gradle/cargo cfg) added for one OS but missing the others the project supports
76
+ - A new dependency that is platform-locked in a project that ships on multiple OSes
77
+
78
+ ---
79
+
80
+ ## Verification Requirements
81
+
82
+ Before reporting ANY finding, you MUST:
83
+
84
+ 1. **Read the actual file** using the Read tool at the exact line
85
+ 2. **Read the full surrounding context** — not just the flagged line, but ±30 lines
86
+ 3. **Check for an existing guard or abstraction**: Grep for a platform check, a path-join helper, or a portable wrapper before claiming code is non-portable
87
+ 4. **Verify the target set**: Confirm the project actually supports the OS/arch you claim it breaks on (CI matrix, framework, build config)
88
+
89
+ **NO EVIDENCE = NO FINDING.** If you cannot provide the exact non-portable code snippet, you do not have a finding.
90
+
91
+ ### "Will Break On X" Claims
92
+
93
+ When your finding claims code breaks on a specific OS/arch:
94
+
95
+ - Confirm that OS/arch is actually a target (check the CI matrix, the cross-platform framework, the build config)
96
+ - Read the complete code path; check whether a guard or portable helper already handles it elsewhere
97
+ - Search for related patterns: `platform`, `os.`, `cfg(`, `ifdef`, `sep`, `path.join`, `EOL`
98
+
99
+ **Your evidence must prove the break — not just that the code looks unix-flavored.**
100
+
101
+ ---
102
+
103
+ ## Evidence Requirements
104
+
105
+ Every finding MUST include (per SCHEMA.md):
106
+
107
+ - `evidence`: Actual code snippet copy-pasted from the file
108
+ - `evidence_context.line_range_examined`: The line range you read
109
+ - `evidence_context.verification_method`: `direct_code_inspection` or `cross_file_trace`
110
+ - `evidence_context.checked_for_handling_elsewhere`: `true` (always — you must check for an existing guard)
111
+ - `evidence_context.search_description`: What you grepped for (the guard/abstraction you confirmed is absent)
112
+
113
+ ---
114
+
115
+ ## Trigger-Driven Exploration
116
+
117
+ [TRIGGER_INSTRUCTIONS]
118
+
119
+ When trigger instructions are provided, investigate each trigger relevant to cross-platform portability. Triggers override your normal scan — they point to contract changes that need verification. Pay special attention to:
120
+ - SIDE EFFECT CONTRACT CHANGED — new filesystem/shell/process behavior may be platform-specific
121
+ - INPUT CONTRACT CHANGED — new path/byte-stream handling may assume one OS
122
+ - BEHAVIORAL CONTRACT CHANGED — formatting of paths/line-endings may have regressed
123
+
124
+ ---
125
+
126
+ ## Finding Format
127
+
128
+ Write findings to `[FINDINGS_PATH]` using SCHEMA.md markdown format:
129
+
130
+ ```markdown
131
+ # Cross-Platform Review Findings
132
+
133
+ ## Finding: XPL-001 — [title]
134
+ - **Severity**: [critical|high|medium|low]
135
+ - **Category**: cross-platform
136
+ - **File**: [file]:[line]
137
+ - **Impact**: [real-world consequence — e.g. "build fails on Windows CI"]
138
+
139
+ ### Evidence
140
+ \`\`\`
141
+ [actual code from Read tool]
142
+ \`\`\`
143
+
144
+ ### Evidence Context
145
+ - Lines examined: [start, end]
146
+ - Verification method: [direct_code_inspection|cross_file_trace]
147
+ - Checked elsewhere: true
148
+ - Search: [the guard/abstraction you confirmed is absent + the target OS evidence]
149
+
150
+ ### Suggested Fix
151
+ [specific code change — use path.join, add a platform guard, use the portable API]
152
+
153
+ ---
154
+ ```
155
+
156
+ ---
157
+
158
+ ## Anti-Patterns (DO NOT)
159
+
160
+ - Do NOT assign confidence percentages — either you have evidence or you don't
161
+ - Do NOT report "potential" issues without code proof
162
+ - Do NOT flag unix-flavored code in a project that only ships on unix (verify the target set first)
163
+ - Do NOT flag a platform-specific code path that already sits behind a guard
164
+ - Do NOT duplicate findings covered by other specialist agents
165
+ - Do NOT report issues in unchanged code unless the diff creates/worsens them
166
+ - Do NOT exceed 5 findings — if you find more, keep only the highest severity
167
+
168
+ ---
169
+
170
+ ## Regression Detection (verification rounds only)
171
+
172
+ The orchestrator passes `ROUND_PHASE: verification` and `PRIOR_ROUND_HEAD_SHA` / `PRIOR_ROUND_FINDINGS_PATH` in the review context block when this is round 3 or 4 of a PR review (R5 of `/apt:pr-review`). In that mode, your default behavior is the SKILL.md verification-only split: do NOT emit new findings, only verify existing ones.
173
+
174
+ **Carve-out:** emit a finding anyway if ALL THREE conditions hold:
175
+
176
+ 1. Severity is **CRITICAL** (not high/medium/low).
177
+ 2. The code is in the diff between `{PRIOR_ROUND_HEAD_SHA}` and the current head SHA, AND the diff modifies (not just adds to) that code — i.e. the author's fix commits between rounds touched these lines.
178
+ 3. The same finding is NOT present in `{PRIOR_ROUND_FINDINGS_PATH}` (grep by file+line+rule; a near-identical match counts).
179
+
180
+ When all three hold, emit the finding with these extra fields:
181
+
182
+ ```json
183
+ {
184
+ "regression_from_fix": true,
185
+ "regression_from_fix_round": {PRIOR_ROUND}
186
+ }
187
+ ```
188
+
189
+ This signals to the validator that the verification-phase suppression should be bypassed. Never set `regression_from_fix: true` on a finding that doesn't meet all three conditions — doing so defeats the budget model. Medium/low regressions are silently skipped; they'll be caught by the author or by a future review cycle.
@@ -481,9 +481,15 @@ Print `[APT] Tokens: {input}+{output} = {total} (task cumulative)` using the
481
481
  tally output. Skip silently if tokens tally errors — never block the
482
482
  pipeline on telemetry.
483
483
 
484
- **If `spawn_agent` is false (QUICK):**
485
- Invoke `apt:quick` directly with task_dir context. No phase marker QUICK is
486
- single-shot.
484
+ **If `spawn_agent` is false (QUICK or DEBUG):**
485
+ Both QUICK and DEBUG resolve here (single-shot, no spawned phase agent). Invoke
486
+ the picked skill (`apt:quick` for QUICK, `apt:debug` for DEBUG, per
487
+ `primary_skill`) directly with `task_id`, `task_dir`, AND `worktree_path` in its
488
+ skill context — Step 2 already created the worktree + printed the banner for this
489
+ track, so thread `worktree_path` the same way the `spawn_agent: true` branch
490
+ threads it into the planner. No phase marker — QUICK and DEBUG are both
491
+ single-shot here. (If Step 2 returned no `worktree` block, pass `worktree_path` as
492
+ "none" and the skill proceeds in the project root.)
487
493
 
488
494
  ### Step 4: Chain Pipeline (based on selected option)
489
495
 
@@ -17,6 +17,8 @@ execution_modes:
17
17
  allowed-tools: "Bash, Read, Grep, Glob, Write"
18
18
  argument-hint: "apt:close-task [--all | --task <id>] [--narrate-only]"
19
19
  gates: []
20
+ config_keys:
21
+ - followups.after_close
20
22
  ---
21
23
  <objective>
22
24
  Confirm a shipped PR has merged on GitHub, then run the closer side of the task lifecycle: flip `lifecycle_phase` from `shipped-pending-merge` to `completed`, strip stale per-PR overrides from `.aperant/config.json`, clean up worktree per policy, and emit `task.closed.merged` events for the audit trail. This is the post-merge counterpart to `/apt:ship`.
@@ -54,6 +56,50 @@ Run `apt-tools task close-merged . --all --dry-run` first to see what would happ
54
56
 
55
57
  If `--task <id>` is passed, narrow to that task.
56
58
 
59
+ ## 1.5 Disposition follow-ups (autonomy-aware — G45)
60
+
61
+ Run this BEFORE §2. The `task close` path that §2 invokes carries a CLI-level disposition gate (G45): it refuses to close while `{task_dir}/followups.json` has any open row, or any `dispositioned` row missing a valid `disposition.kind` + `ref`. Disposition every open row here so §2 closes cleanly without `--force`.
62
+
63
+ For each candidate the dry-run says `close`, read the effective policy:
64
+
65
+ ```bash
66
+ node packages/framework/bin/apt-tools.mjs followups policy . --task-id <id>
67
+ ```
68
+
69
+ The envelope returns `{ after_close: 'ask' | 'file' | 'chain', max_chain_depth, source }`. `after_close` derives from `config.followups.after_close` when set, else from the task autonomy level (≤1 `ask` / 2 `file` / 3 `chain`). Then enumerate the open rows from `{task_dir}/followups.json` and route each by class + policy:
70
+
71
+ **`ask` (autonomy ≤ 1).** Present each open row to the user with its `class_proposed`, `adjudication.verdict`, and `files`. Offer fix / file / drop:
72
+ - fix → execute the change in this session (only if it is genuinely small + safe), commit, flip the row `status: 'fixed'`, optionally record `executed_commit`.
73
+ - file → the `new-task` flow below.
74
+ - drop → `apt-tools followups disposition . --task-id <id> --row <row-id> --kind dropped_by_user --ref <reason-slug> --reason "<text>"`.
75
+
76
+ **`file` (autonomy 2).** Auto-file every `new-task` row through the EXISTING triage machine (report, do NOT execute):
77
+
78
+ ```bash
79
+ # 1) create the task seeded from the row
80
+ node packages/framework/bin/apt-tools.mjs task create . --description "<row title>" --scope <scope> [...linkage]
81
+ # 2) enter it at needs-triage; the configured task_tracking.backend mirrors it
82
+ # (github-issues creates/updates a real labeled issue idempotently)
83
+ node packages/framework/bin/apt-tools.mjs triage init . --id <new-task-id>
84
+ # 3) record the disposition (ref = the filed task id; the triage mirror carries the issue URL)
85
+ node packages/framework/bin/apt-tools.mjs followups disposition . --task-id <id> --row <row-id> --kind filed_task --ref <new-task-id>
86
+ ```
87
+
88
+ There is **NO new `gh issue create` logic** — filing goes through `task create` + `triage init`, and the backend mirror does the GitHub work (ID-08). This works with the local-only default (no `task_tracking` key) AND with `github-issues` when configured; never hard-require gh.
89
+
90
+ **`polish` rows** (any policy) → park in the committable Deferred Ideas section (ID-09): append `- {title} -- deferred because {reason}` under `## Deferred Ideas` in `context/notes/{task-id}.md` (create the section/file if absent), then `apt-tools followups disposition . --task-id <id> --row <row-id> --kind parked_note --ref .aperant/context/notes/{task-id}.md`. Polish rows must NOT linger in the ledger — the ledger is ephemeral.
91
+
92
+ **`chain` (autonomy 3).** Do the `file` flow, THEN auto-chain depth-1 ONLY the filed tasks that triage to `ready-for-agent` (run the chained task through the full pipeline gates). Pass the depth marker on the chained task so the next-level policy degrades `chain → file`:
93
+
94
+ ```bash
95
+ node packages/framework/bin/apt-tools.mjs triage init . --id <new-task-id> \
96
+ --extra '{"followups_chain": {"origin_task": "<id>", "depth": 1}}'
97
+ ```
98
+
99
+ `ready-for-human` items stop there by design — they are filed + reported, never auto-executed. `max_chain_depth` is clamped to 1 in v1 (anti-perpetual-motion); `followups policy` already degrades `chain → file` when the current task's `triage.json` carries `extra.followups_chain.depth >= max_chain_depth`.
100
+
101
+ After this step, every open row carries a durable disposition, so §2's `task close` clears the gate.
102
+
57
103
  ## 2. Confirm merge
58
104
 
59
105
  For each candidate the dry-run says `close`:
@@ -124,6 +170,8 @@ close-merged emits an envelope with:
124
170
 
125
171
  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.
126
172
 
173
+ **Follow-ups-gate recovery (G45).** The passive post-merge sweep (and any bare `task close-merged` that skips §1.5) inherits the CLI close gate: a merged task whose `followups.json` still has open/undispositioned rows fails its spawned `task close` and lands in `errors[]` with a `task-close-failed` reason — the task STAYS in `shipped-pending-merge`. This is the designed backstop, not a bug. Recover by running `/apt:close-task --task <id>` (which runs §1.5 first to disposition every open row), then the close clears the gate. As a last resort, `apt-tools task close . --id <id> --force --reason "<text>"` bypasses the gate with an audited `task.close.followups-override` event.
174
+
127
175
  **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
176
 
129
177
  ## 4. Narrate-only mode
@@ -42,6 +42,7 @@ reproduction, so loading this appendix is non-trivial.
42
42
  - **apt-tools path:** `node packages/framework/bin/apt-tools.mjs` or the locally installed `apt-tools` binary
43
43
  - **Constitution:** Read `AGENTS.md` in the project root if it exists
44
44
  - **Debug sessions:** `.aperant/debug/{session-id}/DEBUG.md`
45
+ - **Task-level worktree isolation:** A worktree is provisioned at session start by `task create` (track-agnostic — DEBUG gets one too; parsed + banner-announced in §1a) when `task_isolation.worktree_per_task` is enabled. Read-only investigation (Sections 2-3 Observe / Hypothesize — `git log`, `git diff`, Grep, Read) may run from EITHER cwd; they only read. But once code changes begin — Section 4 (Checkpoint), Section 5b (Execute Test — the minimal change), Section 6b (Implement Fix + commit) — run those Bash commands with `cd {worktree_path} &&` so the fix + checkpoint commits land on the worktree's task branch. Use the `worktree_path` the router passed in skill context or that §1a parsed from `task create`'s envelope. `apt-tools` calls always take the project root as `<project-dir>`. If no `worktree` block was returned, proceed in the project root as before.
45
46
  </your_environment>
46
47
 
47
48
  <state_files>
@@ -98,6 +99,15 @@ Sequence:
98
99
 
99
100
  The debug working dir at `.aperant/debug/{session-id}/` stays — that working artifact is preserved (per spec §3 R7). The canonical task record at `.aperant/tasks/{task-id}/` is created in parallel by `task create`, and both share the same id.
100
101
 
102
+ **Worktree isolation (both paths).** `task create` provisions a worktree when `task_isolation.worktree_per_task` is enabled (track-agnostic — DEBUG gets one too). Parse `worktree.worktree_path`, `worktree.branch`, and `worktree.base_branch` from the `task create` envelope (direct path); on the router path the orchestrator already passed `worktree_path` into your skill context — use that. When a `worktree` block is present, print the banner:
103
+
104
+ ```
105
+ [APT] Working in isolated worktree: {worktree_path}
106
+ [APT] Task branch: {branch} (from {base_branch})
107
+ ```
108
+
109
+ Investigation (Sections 2-3) may run from either cwd — but once you reach the fix-applying phases (Section 4 Checkpoint, Section 5b Execute Test, Section 6b Implement Fix), prefix those Bash commands with `cd {worktree_path} &&` so commits land on the task branch. If no `worktree` block is returned, proceed in the project root as before.
110
+
101
111
  ### 1b. Create debug working directory
102
112
 
103
113
  ```bash
@@ -202,11 +212,11 @@ Update DEBUG.md:
202
212
 
203
213
  ## 4. Checkpoint — Save State Before Changes
204
214
 
205
- Before making any code changes, create a git checkpoint:
215
+ Before making any code changes, create a git checkpoint. From here on, code-change Bash commands run in the task worktree when one was provisioned — prefix them with `cd {worktree_path} &&` (omit the prefix if no `worktree` block was returned in §1a):
206
216
 
207
217
  ```bash
208
- git stash push -m "debug-checkpoint-{session-id}-pre-test" || true
209
- git rev-parse HEAD > .aperant/debug/{session-id}/checkpoints/pre-test.ref
218
+ cd {worktree_path} && git stash push -m "debug-checkpoint-{session-id}-pre-test" || true
219
+ cd {worktree_path} && git rev-parse HEAD > .aperant/debug/{session-id}/checkpoints/pre-test.ref
210
220
  ```
211
221
 
212
222
  Record the checkpoint in DEBUG.md:
@@ -215,9 +225,9 @@ Record the checkpoint in DEBUG.md:
215
225
  - {timestamp} — pre-test: {commit-sha} (before testing hypotheses)
216
226
  ```
217
227
 
218
- If a hypothesis test fails badly, revert to checkpoint:
228
+ If a hypothesis test fails badly, revert to checkpoint (in the worktree):
219
229
  ```bash
220
- git checkout $(cat .aperant/debug/{session-id}/checkpoints/pre-test.ref) -- .
230
+ cd {worktree_path} && git checkout $(cat .aperant/debug/{session-id}/checkpoints/pre-test.ref) -- .
221
231
  ```
222
232
 
223
233
  ## 5. Test — Validate Hypotheses
@@ -229,7 +239,7 @@ For each hypothesis (starting with most likely):
229
239
  - What is the expected outcome if the hypothesis is correct?
230
240
 
231
241
  ### 5b. Execute Test
232
- - Make the minimal change needed to test the hypothesis
242
+ - Make the minimal change needed to test the hypothesis — apply it in the task worktree (edit files under `{worktree_path}` and run any verification command with `cd {worktree_path} &&`) when a `worktree` block was provisioned in §1a; otherwise edit in the project root.
233
243
  - Run the relevant command/test
234
244
  - Record the actual outcome
235
245
 
@@ -283,12 +293,12 @@ Document the root cause clearly:
283
293
  ```
284
294
 
285
295
  ### 6b. Implement Fix
286
- - Apply the minimal fix that addresses the root cause
296
+ - Apply the minimal fix that addresses the root cause — in the task worktree (edit files under `{worktree_path}`) when one was provisioned in §1a, so the commit lands on the task branch.
287
297
  - Run verification (tests, typecheck, lint)
288
- - If verification passes, commit:
298
+ - If verification passes, commit (prefix with `cd {worktree_path} &&` when a worktree was provisioned so `git` stages + commits on the worktree's task branch; `apt-tools commit` takes no `<project-dir>` and operates on the current cwd):
289
299
 
290
300
  ```bash
291
- node packages/framework/bin/apt-tools.mjs commit "fix: {concise description of fix}" --files {changed-files}
301
+ cd {worktree_path} && node packages/framework/bin/apt-tools.mjs commit "fix: {concise description of fix}" --files {changed-files}
292
302
  ```
293
303
 
294
304
  ### 6c. Update Status