@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
@@ -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
@@ -555,10 +555,12 @@ Read `state.active_tasks[<task-id>].install_status`. Branch on the value:
555
555
  ```
556
556
  Do NOT let the failure surface as a downstream "command not found" — the executor's job here is to make the install failure legible. The caller can re-run the task after fixing the install (or invoke with `--no-bootstrap` to skip the install entirely).
557
557
 
558
+ > **State resolves to the main repo from any cwd (state-fork-fix).** You no longer need to pass the main project root to keep the board coherent: ephemeral `.aperant/` state — `state.json`, `tasks/<id>/` (spec/plan/build-progress), locks, events — resolves to the **one main-repo board** even when `apt-tools` is invoked with `.` from a worktree cwd. The board never forks. (Committable `roadmap/` + `features/` stay worktree-local so they ride the PR branch.) `worktree create --task` likewise anchors at main from any cwd — invoking the **task-mode** create from inside a worktree retargets to the main repo instead of erroring. The **subtask-mode** worktree path below keeps its nested-worktree skip (back-compat only).
559
+
558
560
  **2b. Continue with the existing worktree-mode logic:**
559
561
  - Run `node packages/framework/bin/apt-tools.mjs detect-worktree .` — if `is_worktree: true`:
560
562
  - Log: "Skipping worktree isolation (already in worktree)"
561
- - Do NOT create worktrees (prevents nested worktrees)
563
+ - Do NOT create SUBTASK-mode worktrees from here (the legacy subtask-mode path refuses nesting; task-mode `worktree create --task` is safe — it anchors at main)
562
564
  - Agents execute in the current working directory directly
563
565
  - Note: locks still coordinate correctly (apt-tools uses shared lock dir via git common dir)
564
566
  - If `use_worktrees` is `true` AND `is_worktree` is `false` AND no task-level `worktree_path` is present: set `WORKTREE_MODE=true`
@@ -85,6 +85,15 @@ node packages/framework/bin/apt-tools.mjs worktree create --task ${task_id}
85
85
 
86
86
  (Skip if `state.active_tasks[task_id].worktree_path` is already set — the create command is idempotent.)
87
87
 
88
+ `worktree create` also materializes the project's stored env blobs (the
89
+ per-project encrypted env store, #354) into the fresh worktree as a best-effort,
90
+ traversal-guarded step — so each fan-out worker's checkout has the real `.env*`
91
+ files instead of crashing in no-cloud mode. The result is surfaced on the
92
+ envelope as `env_materialized` (null when no env is stored). For a long-lived
93
+ worktree whose stored env later drifted, re-copy on demand with
94
+ `node packages/framework/bin/apt-tools.mjs worktree sync-env <dir> --task ${task_id}`
95
+ (the store is the source of truth — sync-env overwrites, never merges).
96
+
88
97
  ## 3. Spawn N apt-executor subagents
89
98
 
90
99
  Read the `parallelization.max_tasks` cap from `.aperant/config.json` (or default 4). Slice `task_ids` into batches of size `min(cap, task_ids.length)`. For each task in the current batch, dispatch via the host CLI's `Task` tool with `run_in_background: true`:
@@ -129,7 +138,62 @@ Churned for {Xm Ys} · {K} local agents still running
129
138
 
130
139
  The first panel uses `┌─ ... │` (top-with-stem); the LAST panel uses `└─ ... ` (bottom corner). Footer line: "Churned" = elapsed since the most recent lifecycle event across all in-flight workers; "K local agents still running" = count of workers whose `lifecycle_phase` is non-terminal AND `assigned_to` is non-null.
131
140
 
132
- ## 5. Report
141
+ ## 5. Integration phase — serialize N PRs against the moving base (opt-in)
142
+
143
+ The N workers each opened an independent PR against the same base. Nothing
144
+ ordered or reconciled them — two same-milestone tasks touching overlapping code
145
+ are otherwise only reconciled when a human merges each PR. This phase closes
146
+ that gap. It is **opt-in** via `pipeline.resolve_merge_conflicts` (default
147
+ false) in `.aperant/config.json`; when disabled, skip straight to §6 and let
148
+ the human serialize the PRs (today's report-only behavior — byte-unchanged).
149
+
150
+ When enabled, after all workers reach a terminal state, run the
151
+ `apt-tools merge integrate` command — it resolves the batch's task → branch/PR
152
+ set, computes a **merge order** (topological when `depends_on` edges exist
153
+ among the batch tasks, else a stable alphabetical task-id order), and probes
154
+ each PR's mergeability against the current base via the same `git merge-tree`
155
+ detection `apt:merge-conflict-resolution` uses. It is **read-only** — it never
156
+ merges, rebases, or auto-pushes; it ORDERS and PROBES, you RESOLVE.
157
+
158
+ First fetch the latest base tips so the probes are against the moving base, then
159
+ call `integrate` with the batch's task list (or `--batch ${batch_id}` to recover
160
+ it from the worker rows):
161
+
162
+ ```bash
163
+ git -C "$conductor_root" fetch origin "$base_branch"
164
+ node packages/framework/bin/apt-tools.mjs merge integrate . --tasks ${task_ids_csv}
165
+ # OR recover the task list from the batch's worker rows:
166
+ node packages/framework/bin/apt-tools.mjs merge integrate . --batch ${batch_id}
167
+ ```
168
+
169
+ Returns a structured integration report:
170
+ ```json
171
+ {
172
+ "status": "ok",
173
+ "command": "merge-integrate",
174
+ "order_strategy": "topological",
175
+ "order": ["task-a", "task-b"],
176
+ "summary": { "total": 2, "mergeable": 1, "conflicted": 1, "needs_human": 0 },
177
+ "tasks": [
178
+ { "task_id": "task-a", "status": "mergeable", "action": "advance", "mergeable": true },
179
+ { "task_id": "task-b", "status": "conflicted", "action": "resolve-conflict",
180
+ "conflicts_preview": ["src/x.ts"],
181
+ "resolution": { "skill": "apt:merge-conflict-resolution", "worktree_path": "…", "base": "origin/main" } }
182
+ ]
183
+ }
184
+ ```
185
+
186
+ Walk the `tasks` array **in `order`** (the command already serialized it):
187
+
188
+ 1. **`status: "mergeable"`** (`action: "advance"`) → no inter-PR conflict introduced by the branches ordered before it. Nothing to do; continue.
189
+ 2. **`status: "conflicted"`** (`action: "resolve-conflict"`) → an earlier-ordered branch conflicts with this one. Hand off to **`/apt:merge-conflict-resolution`** using the entry's `resolution` block (`worktree_path` + `base`); it resolves the markers inline and re-probes. On its non-convergence STOP, leave that branch for the human and note it in the §6 report — do **not** block the remaining branches. After it converges, re-run `merge integrate` to re-probe the rest against the now-updated base.
190
+ 3. **`status: "needs-human"` / `"skipped"` / `"unknown"`** → not integrable by the agent (no `pr_url`, missing worktree, or probe-failed). Carry the `reason` into the §6 report and move on.
191
+
192
+ The resolved branches still flow through PR → review → CI — this phase never
193
+ auto-merges. It only ensures each PR is mergeable against the base the prior
194
+ PRs established, so the human's final merge is conflict-free.
195
+
196
+ ## 6. Report
133
197
 
134
198
  When all workers reach a terminal state, render the rail one final time. For each shipped worker (lifecycle `shipped-pending-merge` + `pr_url` set), collapse that panel to the SHIPPED variant:
135
199
 
@@ -0,0 +1,227 @@
1
+ ---
2
+ name: apt:merge-conflict-resolution
3
+ description: "Agent-inline merge-conflict resolution — detect conflicts via apt-tools merge, resolve markers inline, re-probe, fall back to STOP"
4
+ apt-skill-version: {{APT_VERSION}}
5
+ stage: ship
6
+ intent: x-merge-resolve
7
+ when_to_use: "A clean fast-forward rebase or merge is impossible because the task branch conflicts with its base (apt:ship §0.7, a fan-out integration sweep, or an apt:watch-ci diverged-bailed branch) and you want the executing agent to resolve the conflicts inline before re-probing mergeability."
8
+ user_invocable: true
9
+ internal: false
10
+ spawns_agent: false
11
+ agent_name: null
12
+ task_context: require-existing
13
+ default_execution_mode: auto
14
+ execution_modes:
15
+ - auto
16
+ - step
17
+ allowed-tools: "Bash, Read, Write, Edit, Grep, Glob"
18
+ argument-hint: "apt:merge-conflict-resolution [--base <ref>] [--head <ref>]"
19
+ gates: []
20
+ ---
21
+
22
+ # /apt:merge-conflict-resolution — Agent-Inline Merge Conflict Resolution
23
+
24
+ <objective>
25
+ You are the Aperant merge-conflict resolver. When a task branch can no longer
26
+ fast-forward or rebase cleanly onto its base, you resolve the conflicting
27
+ files **inline** — reading the conflict markers, deciding the correct merged
28
+ content with full repository context, and writing it back — then re-probe
29
+ mergeability and continue. You are the opt-in resolution path the three
30
+ framework merge gates fall into instead of hard-STOPping: `apt:ship` §0.7
31
+ (single-task base-drift), the fan-out integration sweep (inter-PR conflicts
32
+ as each branch lands), and `apt:watch-ci`'s `diverged-bailed` branch
33
+ (self-heal instead of bail).
34
+
35
+ The decisive architectural rule: resolution is **agent-inline**, never a
36
+ programmatic provider client. The framework CLI is self-contained ESM and
37
+ declares no `@aperant/core` dependency, so there is no app credential store
38
+ or LLM transport to call from `.mjs`. The agent driving the CLI is already
39
+ an LLM with a transport — you read the markers `apt-tools merge` surfaces and
40
+ resolve them with your own reasoning. Detection is deterministic (`git
41
+ merge-tree`); resolution is yours.
42
+
43
+ The human stays the final gate. A resolved merge still flows through PR →
44
+ review → CI; you never push to a protected branch and never auto-merge.
45
+ </objective>
46
+
47
+ <your_environment>
48
+ - **Working directory:** The task worktree (or project root) whose branch needs to integrate its base. All `apt-tools` and `git` calls run with this as the cwd / `<project-dir>` argument.
49
+ - **apt-tools path:** `node packages/framework/bin/apt-tools.mjs` (or `node .aperant/deps/node_modules/@aperant/framework/bin/apt-tools.mjs` when running from an install mirror).
50
+ - **Detection primitive:** `apt-tools merge detect <dir> [--base <ref>] [--head <ref>]` — a read-only trial-merge probe (`git merge-tree --write-tree`) that reuses the exact detection from `audit branch-current`. Emits `{ mergeable, conflicts_preview? }`. NO history rewrite, NO index mutation. `--base` defaults to `origin/main`; `--head` defaults to `HEAD`.
51
+ - **Marker reader:** `apt-tools merge markers <dir>` — after a real `git merge`/`git rebase` leaves the worktree conflicted, lists the unmerged paths and reads each file's full content (markers and all) so you can resolve them inline. Emits `{ conflicted, files: [{ path, content }] }`.
52
+ - **git:** You drive the actual `git merge` / `git rebase` / `git add` / `git rebase --continue` yourself — the CLI only observes, it never mutates. Requires git ≥ 2.38 for the `detect` probe.
53
+ </your_environment>
54
+
55
+ <state_files>
56
+ ## State Files
57
+
58
+ **Reads:**
59
+ - `.aperant/state.json` — `active_tasks[{task-id}].autonomy` (autonomy gating) and `autonomy.default` fallback.
60
+ - The conflicted source files themselves, via `apt-tools merge markers` (full content with markers).
61
+
62
+ **Writes:**
63
+ - The resolved source files in the worktree (via Edit/Write — your inline resolution).
64
+ - The git index + a merge/rebase-continuation commit, via `git add` + `git commit` / `git rebase --continue` (you drive git; the CLI never does).
65
+
66
+ This skill writes NO `.aperant/` state of its own — it is a leaf resolution
67
+ step invoked by `apt:ship`, `apt:fan-out`, or `apt:watch-ci`, each of which
68
+ owns its own state. Detection (`apt-tools merge detect|markers`) is pure
69
+ read-only.
70
+ </state_files>
71
+
72
+ <process>
73
+
74
+ ## 1. Probe mergeability
75
+
76
+ Resolve the base and head refs (defaults: `--base origin/main`, `--head HEAD`).
77
+ Fetch the base first so the probe is against the live remote tip:
78
+
79
+ ```bash
80
+ git -C "$dir" fetch origin "$base_branch"
81
+ node packages/framework/bin/apt-tools.mjs merge detect "$dir" --base "origin/$base_branch"
82
+ ```
83
+
84
+ Branch on the envelope:
85
+
86
+ - **`mergeable === true`** → nothing to resolve. Return to the caller (or run the clean rebase the caller requested). DONE.
87
+ - **`mergeable === null`** (`audit_warning: "git-version-too-old"` or `"merge-tree-probe-failed"`) → STOP. You cannot safely probe. Emit the warning verbatim and hand back to the human:
88
+ ```
89
+ [APT:merge] Cannot resolve — mergeability is unprobeable ({audit_warning}). Upgrade git ≥ 2.38 or rebase manually, then re-run.
90
+ ```
91
+ - **`mergeable === false`** → conflicts exist. Print `conflicts_preview` verbatim and proceed to §2.
92
+
93
+ ## 2. Materialize the conflict in the worktree
94
+
95
+ The `detect` probe is read-only — it never touched your index. To resolve, you
96
+ need the real conflicted state on disk. Drive git yourself (the SKILL owns
97
+ history changes, the CLI never does):
98
+
99
+ ```bash
100
+ git -C "$dir" rebase "origin/$base_branch" # or: git -C "$dir" merge "origin/$base_branch"
101
+ ```
102
+
103
+ Prefer `rebase` for single-task base-drift (apt:ship §0.7) and the fan-out
104
+ integration sweep so the branch stays linear; prefer `merge` only when the
105
+ caller explicitly asked for it. The command will exit non-zero and leave the
106
+ worktree in a conflicted (rebasing/merging) state — that is expected.
107
+
108
+ ## 3. Read the markers + resolve inline
109
+
110
+ ```bash
111
+ node packages/framework/bin/apt-tools.mjs merge markers "$dir"
112
+ ```
113
+
114
+ For each entry in `files`, the `content` field carries the file verbatim with
115
+ `<<<<<<<` / `=======` / `>>>>>>>` markers. For every conflicted file:
116
+
117
+ 1. **Understand both sides.** The `HEAD` side (above `=======`) is the current
118
+ branch's change; the other side (below `=======`, up to `>>>>>>>`) is the
119
+ base's change. Read the surrounding file and, when the conflict is
120
+ semantic, the related modules — you have full repository context the
121
+ deterministic merger does not.
122
+ 2. **Resolve with intent, not by picking a side.** Produce the content that
123
+ correctly carries BOTH intents where they are compatible (e.g. both sides
124
+ added an import → keep both; both edited the same function → reconcile the
125
+ two edits). Pick one side only when the changes are genuinely mutually
126
+ exclusive and you can justify which wins.
127
+ 3. **Remove every marker.** The resolved file MUST contain no `<<<<<<<`,
128
+ `=======`, or `>>>>>>>` line. Write it back with Edit/Write.
129
+ 4. **Stage it.** `git -C "$dir" add "<path>"`.
130
+
131
+ Do this for every conflicted path before continuing.
132
+
133
+ ## 4. Continue the merge/rebase
134
+
135
+ ```bash
136
+ git -C "$dir" rebase --continue # or: git -C "$dir" commit --no-edit (for a merge)
137
+ ```
138
+
139
+ A rebase may surface a SECOND round of conflicts on the next replayed commit.
140
+ If so, loop back to §3 (`apt-tools merge markers` again) and resolve the new
141
+ round. Repeat until the rebase/merge completes.
142
+
143
+ ## 5. Re-probe + verify
144
+
145
+ Confirm the branch is now clean against the base and the tree is whole:
146
+
147
+ ```bash
148
+ node packages/framework/bin/apt-tools.mjs merge detect "$dir" --base "origin/$base_branch"
149
+ grep -rEn '^(<<<<<<<|=======|>>>>>>>)' "$dir" --include='*.*' && echo "STRAY MARKERS — re-resolve" || true
150
+ ```
151
+
152
+ - **`mergeable === true` AND no stray markers** → resolution succeeded. Hand
153
+ back to the caller, which proceeds to its push / PR / re-run-CI step. The
154
+ resolved branch still goes through PR → review → CI; you do NOT auto-merge.
155
+ - **Still `mergeable === false`** → you missed a conflict. Loop back to §3.
156
+ - **Loop budget exhausted** (you have re-entered §3 more than **3** times, or
157
+ the same files keep re-conflicting) → STOP. Abort the in-progress operation
158
+ to leave a clean tree, and hand back to the human:
159
+ ```bash
160
+ git -C "$dir" rebase --abort # or: git -C "$dir" merge --abort
161
+ ```
162
+ ```
163
+ [APT:merge] Could not converge after 3 resolution rounds — handing back. Conflicts: {paths}. Resolve manually, then re-run.
164
+ ```
165
+
166
+ ## 6. Insertion points (where this skill is invoked from)
167
+
168
+ This skill is the opt-in resolution path for three existing framework gates.
169
+ Each gate decides — by autonomy level + config — whether to fall into this
170
+ skill or keep its legacy hard-STOP. The references are doc-only here; the
171
+ gates document the hand-off in their own SKILL.md:
172
+
173
+ - **`apt:ship` §0.7** — the `mergeable === false` branch. Legacy behavior is a
174
+ hard STOP ("resolve manually"). With resolution opted in, the branch hands
175
+ to §2 of this skill instead, then resumes §1 of apt:ship on success.
176
+ - **`apt:fan-out` integration sweep** — the new serialization phase between
177
+ spawn and report. As each worker's branch lands against the moving base,
178
+ re-probe via `apt-tools merge detect` and resolve inter-PR conflicts here
179
+ before the next branch integrates.
180
+ - **`apt:watch-ci` `diverged-bailed`** — instead of bailing on a rebase
181
+ conflict, run this skill to self-heal, then push the resolved branch and let
182
+ the watcher reschedule.
183
+
184
+ </process>
185
+
186
+ <rationalization>
187
+ Common ways an agent rationalizes the wrong move — and why each is wrong:
188
+
189
+ - "I'll just `git checkout --theirs` / `--ours` to clear the conflict fast." →
190
+ That blindly discards one side's intent. The whole reason this is
191
+ agent-inline (not the deterministic core merger) is that you reconcile BOTH
192
+ intents with repository context. Side-picking is the last resort in §3.2,
193
+ not the default.
194
+ - "The probe said `mergeable: false`, I'll resolve from the `conflicts_preview`
195
+ list without reading the files." → The preview is only a path list. You MUST
196
+ materialize the conflict (§2) and read the actual markers (§3) before
197
+ editing — guessing from filenames produces wrong merges.
198
+ - "I resolved the markers, I can skip the re-probe and push." → Without §5 you
199
+ can ship stray markers or an incomplete rebase. Always re-probe + grep for
200
+ stray markers before handing back.
201
+ - "It's still conflicting after a few tries, I'll force it through." → A
202
+ non-converging conflict is a human decision. After 3 rounds, abort to a clean
203
+ tree and hand back — never leave a half-rebased worktree or force a bad
204
+ resolution into a PR.
205
+ - "I'll just merge the PR since I resolved it." → You are not the final gate.
206
+ Resolved branches flow through PR → review → CI. Never auto-merge.
207
+ </rationalization>
208
+
209
+ <autonomy_interaction>
210
+ Read the active task's autonomy level from `.aperant/state.json`
211
+ (`active_tasks[{task-id}].autonomy`, falling back to `autonomy.default`):
212
+
213
+ - **Autonomy 0–1 (plan-only / step)** — after §1 detects conflicts, print the
214
+ `conflicts_preview` and ask `Resolve these N conflicts inline? [Y/n]` before
215
+ driving the rebase in §2. On `N`, exit so the human can resolve manually.
216
+ After resolving each file in §3, show the diff and confirm before staging at
217
+ higher-stakes files (anything under a path the task did not touch).
218
+ - **Autonomy 2 (auto-chain)** — resolve silently through §2–§5; STOP per §5 on
219
+ non-convergence after 3 rounds.
220
+ - **Autonomy 3 (YOLO)** — same as 2: silent on convergence, STOP on
221
+ non-convergence. Even at YOLO you do NOT auto-merge the resulting PR — the
222
+ human/CI gate is non-negotiable.
223
+
224
+ This skill is recoverable by construction: every STOP path (§1 unprobeable,
225
+ §5 non-convergence) aborts the in-progress git operation to leave a clean tree
226
+ before handing back, so a bailout never strands a half-rebased worktree.
227
+ </autonomy_interaction>
@@ -26,7 +26,7 @@ Every finding produced by a review agent MUST conform to this schema:
26
26
  {
27
27
  "id": "SEC-001",
28
28
  "severity": "critical|high|medium|low",
29
- "category": "security|quality|logic|codebase-fit|test-integrity|performance|auto-checks",
29
+ "category": "security|quality|logic|codebase-fit|test-integrity|performance|i18n|cross-platform|auto-checks",
30
30
  "title": "Short description (max 80 chars)",
31
31
  "description": "Detailed explanation of the issue",
32
32
  "impact": "Real-world consequences if not fixed",
@@ -62,7 +62,7 @@ Every finding MUST include all of the following. A finding missing any required
62
62
  |-------|------|-------------|
63
63
  | `id` | `string` | Unique identifier. Format: `{CATEGORY_PREFIX}-{NNN}`. See [ID Prefixes](#id-prefixes) below. |
64
64
  | `severity` | `enum` | One of: `critical`, `high`, `medium`, `low`. See [Severity Definitions](#severity-definitions). |
65
- | `category` | `enum` | One of: `security`, `quality`, `logic`, `codebase-fit`, `test-integrity`, `performance`, `auto-checks`. |
65
+ | `category` | `enum` | One of: `security`, `quality`, `logic`, `codebase-fit`, `test-integrity`, `performance`, `i18n`, `cross-platform`, `auto-checks`. The `i18n` and `cross-platform` categories are emitted only by the two CONDITIONAL specialists, which the orchestrator spawns when `detect-specialists` engages them. |
66
66
  | `title` | `string` | Short description, max 80 characters. Must be specific enough to act on without reading the full description. |
67
67
  | `description` | `string` | Detailed explanation of what the issue is and why it matters. No filler -- every sentence must add information. |
68
68
  | `impact` | `string` | Real-world consequences if this issue is not fixed. Must describe a concrete scenario, not a vague risk statement. |
@@ -100,6 +100,8 @@ Each category has a standard prefix for finding IDs:
100
100
  | `codebase-fit` | `FIT` | `FIT-001` |
101
101
  | `test-integrity` | `TST` | `TST-001` |
102
102
  | `performance` | `PRF` | `PRF-001` |
103
+ | `i18n` | `I18N` | `I18N-001` |
104
+ | `cross-platform` | `XPL` | `XPL-001` |
103
105
  | `auto-checks` | `CHK` | `CHK-001` |
104
106
 
105
107
  Each agent numbers its findings sequentially starting from 001.