dorfl 0.1.1 → 0.2.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 (492) hide show
  1. package/dist/advance-ci-template.d.ts +3 -3
  2. package/dist/advance-ci-template.js +1 -1
  3. package/dist/advance-ci-template.js.map +1 -1
  4. package/dist/advance-classify.d.ts +5 -5
  5. package/dist/advance-classify.d.ts.map +1 -1
  6. package/dist/advance-classify.js +4 -4
  7. package/dist/advance-drivers.d.ts +8 -8
  8. package/dist/advance-drivers.d.ts.map +1 -1
  9. package/dist/advance-drivers.js +20 -8
  10. package/dist/advance-drivers.js.map +1 -1
  11. package/dist/advance-isolated.d.ts +3 -3
  12. package/dist/advance-isolated.d.ts.map +1 -1
  13. package/dist/advance-isolated.js +1 -1
  14. package/dist/advance-lifecycle-template.d.ts +2 -2
  15. package/dist/advance-lifecycle-template.d.ts.map +1 -1
  16. package/dist/advance-lifecycle-template.js +85 -13
  17. package/dist/advance-lifecycle-template.js.map +1 -1
  18. package/dist/advance-loop-driver.d.ts +3 -3
  19. package/dist/advance-loop-driver.d.ts.map +1 -1
  20. package/dist/advance-loop-driver.js +1 -1
  21. package/dist/advance-treeless-publish.d.ts +24 -1
  22. package/dist/advance-treeless-publish.d.ts.map +1 -1
  23. package/dist/advance-treeless-publish.js +41 -0
  24. package/dist/advance-treeless-publish.js.map +1 -1
  25. package/dist/advance.d.ts +69 -17
  26. package/dist/advance.d.ts.map +1 -1
  27. package/dist/advance.js +409 -102
  28. package/dist/advance.js.map +1 -1
  29. package/dist/advancing-lock.d.ts +31 -3
  30. package/dist/advancing-lock.d.ts.map +1 -1
  31. package/dist/advancing-lock.js +55 -5
  32. package/dist/advancing-lock.js.map +1 -1
  33. package/dist/agent-launch.d.ts +12 -0
  34. package/dist/agent-launch.d.ts.map +1 -1
  35. package/dist/agent-launch.js +22 -12
  36. package/dist/agent-launch.js.map +1 -1
  37. package/dist/agent-stop.d.ts +40 -2
  38. package/dist/agent-stop.d.ts.map +1 -1
  39. package/dist/agent-stop.js +30 -2
  40. package/dist/agent-stop.js.map +1 -1
  41. package/dist/apply-decide.d.ts +19 -5
  42. package/dist/apply-decide.d.ts.map +1 -1
  43. package/dist/apply-decide.js +38 -9
  44. package/dist/apply-decide.js.map +1 -1
  45. package/dist/apply-merge-action.d.ts +20 -8
  46. package/dist/apply-merge-action.d.ts.map +1 -1
  47. package/dist/apply-merge-action.js +44 -9
  48. package/dist/apply-merge-action.js.map +1 -1
  49. package/dist/apply-persist.d.ts +62 -31
  50. package/dist/apply-persist.d.ts.map +1 -1
  51. package/dist/apply-persist.js +173 -44
  52. package/dist/apply-persist.js.map +1 -1
  53. package/dist/apply-stuck-action.d.ts +151 -0
  54. package/dist/apply-stuck-action.d.ts.map +1 -0
  55. package/dist/apply-stuck-action.js +125 -0
  56. package/dist/apply-stuck-action.js.map +1 -0
  57. package/dist/brand.d.ts +12 -1
  58. package/dist/brand.d.ts.map +1 -1
  59. package/dist/brand.js +2 -1
  60. package/dist/brand.js.map +1 -1
  61. package/dist/buildable-body.d.ts +14 -14
  62. package/dist/buildable-body.js +9 -9
  63. package/dist/claim-cas.d.ts +3 -3
  64. package/dist/claim-cas.js +1 -1
  65. package/dist/claim-cas.js.map +1 -1
  66. package/dist/cli-spinner.d.ts +1 -1
  67. package/dist/cli-spinner.js +1 -1
  68. package/dist/cli.d.ts +10 -0
  69. package/dist/cli.d.ts.map +1 -1
  70. package/dist/cli.js +385 -128
  71. package/dist/cli.js.map +1 -1
  72. package/dist/close-job-template.d.ts +3 -3
  73. package/dist/close-job-template.js +9 -9
  74. package/dist/close-job.d.ts +8 -8
  75. package/dist/close-job.js +25 -25
  76. package/dist/close-job.js.map +1 -1
  77. package/dist/complete.d.ts +9 -6
  78. package/dist/complete.d.ts.map +1 -1
  79. package/dist/complete.js +99 -45
  80. package/dist/complete.js.map +1 -1
  81. package/dist/concurrency.d.ts +1 -1
  82. package/dist/concurrency.js +1 -1
  83. package/dist/config.d.ts +86 -40
  84. package/dist/config.d.ts.map +1 -1
  85. package/dist/config.js +61 -9
  86. package/dist/config.js.map +1 -1
  87. package/dist/continue-branch.d.ts +1 -1
  88. package/dist/continue-branch.d.ts.map +1 -1
  89. package/dist/continue-branch.js +23 -1
  90. package/dist/continue-branch.js.map +1 -1
  91. package/dist/cwd-section.js +1 -1
  92. package/dist/cwd-section.js.map +1 -1
  93. package/dist/decision-engine.d.ts +39 -11
  94. package/dist/decision-engine.d.ts.map +1 -1
  95. package/dist/decision-engine.js +10 -6
  96. package/dist/decision-engine.js.map +1 -1
  97. package/dist/do-autopick.d.ts +6 -6
  98. package/dist/do-autopick.d.ts.map +1 -1
  99. package/dist/do-autopick.js +16 -6
  100. package/dist/do-autopick.js.map +1 -1
  101. package/dist/do-config.d.ts +4 -4
  102. package/dist/do-config.js +3 -3
  103. package/dist/do-config.js.map +1 -1
  104. package/dist/do-remote-auto.d.ts +2 -2
  105. package/dist/do-remote-auto.js +1 -1
  106. package/dist/do.d.ts +74 -81
  107. package/dist/do.d.ts.map +1 -1
  108. package/dist/do.js +439 -50
  109. package/dist/do.js.map +1 -1
  110. package/dist/drop-source.d.ts +2 -2
  111. package/dist/env-config.d.ts.map +1 -1
  112. package/dist/env-config.js +19 -11
  113. package/dist/env-config.js.map +1 -1
  114. package/dist/failure-cause.d.ts +3 -2
  115. package/dist/failure-cause.d.ts.map +1 -1
  116. package/dist/failure-cause.js +28 -1
  117. package/dist/failure-cause.js.map +1 -1
  118. package/dist/format.d.ts +6 -6
  119. package/dist/format.d.ts.map +1 -1
  120. package/dist/format.js +13 -30
  121. package/dist/format.js.map +1 -1
  122. package/dist/frontmatter.d.ts +28 -15
  123. package/dist/frontmatter.d.ts.map +1 -1
  124. package/dist/frontmatter.js +38 -24
  125. package/dist/frontmatter.js.map +1 -1
  126. package/dist/gc.d.ts +65 -6
  127. package/dist/gc.d.ts.map +1 -1
  128. package/dist/gc.js +126 -9
  129. package/dist/gc.js.map +1 -1
  130. package/dist/github.d.ts +14 -0
  131. package/dist/github.d.ts.map +1 -1
  132. package/dist/github.js +73 -0
  133. package/dist/github.js.map +1 -1
  134. package/dist/harness.d.ts +25 -0
  135. package/dist/harness.d.ts.map +1 -1
  136. package/dist/harness.js.map +1 -1
  137. package/dist/index.d.ts +4 -1
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +2 -1
  140. package/dist/index.js.map +1 -1
  141. package/dist/install-ci-branch-protection.d.ts +133 -39
  142. package/dist/install-ci-branch-protection.d.ts.map +1 -1
  143. package/dist/install-ci-branch-protection.js +191 -49
  144. package/dist/install-ci-branch-protection.js.map +1 -1
  145. package/dist/install-ci-capabilities/advance-lifecycle.d.ts +1 -1
  146. package/dist/install-ci-capabilities/advance-lifecycle.js +1 -1
  147. package/dist/install-ci-capabilities/close-job.d.ts +1 -1
  148. package/dist/install-ci-capabilities/close-job.js +1 -1
  149. package/dist/install-ci-capabilities/example-noop.d.ts +1 -1
  150. package/dist/install-ci-capabilities/example-noop.js +1 -1
  151. package/dist/install-ci-capabilities/intake.d.ts +2 -2
  152. package/dist/install-ci-capabilities/intake.js +2 -2
  153. package/dist/install-ci-capabilities/verify.d.ts +1 -1
  154. package/dist/install-ci-capabilities/verify.js +1 -1
  155. package/dist/install-ci-core.d.ts +24 -4
  156. package/dist/install-ci-core.d.ts.map +1 -1
  157. package/dist/install-ci-core.js +12 -5
  158. package/dist/install-ci-core.js.map +1 -1
  159. package/dist/install-ci-github.d.ts +33 -1
  160. package/dist/install-ci-github.d.ts.map +1 -1
  161. package/dist/install-ci-github.js +74 -1
  162. package/dist/install-ci-github.js.map +1 -1
  163. package/dist/install-ci.d.ts +1 -1
  164. package/dist/install-ci.js +4 -4
  165. package/dist/install-ci.js.map +1 -1
  166. package/dist/install-skills.d.ts +123 -0
  167. package/dist/install-skills.d.ts.map +1 -0
  168. package/dist/install-skills.js +100 -0
  169. package/dist/install-skills.js.map +1 -0
  170. package/dist/intake-event.d.ts +6 -6
  171. package/dist/intake-event.js +6 -6
  172. package/dist/intake-marker.d.ts +3 -3
  173. package/dist/intake-marker.d.ts.map +1 -1
  174. package/dist/intake-triage.d.ts +1 -1
  175. package/dist/intake-triage.js +2 -2
  176. package/dist/intake-trigger-template.d.ts +8 -8
  177. package/dist/intake-trigger-template.d.ts.map +1 -1
  178. package/dist/intake-trigger-template.js +17 -17
  179. package/dist/intake-trigger-template.js.map +1 -1
  180. package/dist/intake.d.ts +65 -52
  181. package/dist/intake.d.ts.map +1 -1
  182. package/dist/intake.js +92 -76
  183. package/dist/intake.js.map +1 -1
  184. package/dist/integration-core.d.ts +27 -24
  185. package/dist/integration-core.d.ts.map +1 -1
  186. package/dist/integration-core.js +191 -77
  187. package/dist/integration-core.js.map +1 -1
  188. package/dist/integrator.d.ts +1 -1
  189. package/dist/integrator.d.ts.map +1 -1
  190. package/dist/integrator.js +19 -3
  191. package/dist/integrator.js.map +1 -1
  192. package/dist/isolation.d.ts +4 -4
  193. package/dist/isolation.d.ts.map +1 -1
  194. package/dist/isolation.js +9 -0
  195. package/dist/isolation.js.map +1 -1
  196. package/dist/issue-provider.d.ts +4 -4
  197. package/dist/issue-provider.js +1 -1
  198. package/dist/item-lock.d.ts +216 -149
  199. package/dist/item-lock.d.ts.map +1 -1
  200. package/dist/item-lock.js +345 -270
  201. package/dist/item-lock.js.map +1 -1
  202. package/dist/item-path.d.ts +2 -2
  203. package/dist/item-path.js +2 -2
  204. package/dist/ledger-lint.d.ts +9 -9
  205. package/dist/ledger-lint.js +9 -9
  206. package/dist/ledger-read.d.ts +57 -57
  207. package/dist/ledger-read.d.ts.map +1 -1
  208. package/dist/ledger-read.js +24 -24
  209. package/dist/ledger-read.js.map +1 -1
  210. package/dist/ledger-write.d.ts +33 -28
  211. package/dist/ledger-write.d.ts.map +1 -1
  212. package/dist/ledger-write.js +100 -122
  213. package/dist/ledger-write.js.map +1 -1
  214. package/dist/lifecycle-gather.d.ts +18 -1
  215. package/dist/lifecycle-gather.d.ts.map +1 -1
  216. package/dist/lifecycle-gather.js +23 -17
  217. package/dist/lifecycle-gather.js.map +1 -1
  218. package/dist/lifecycle-pools.d.ts +44 -7
  219. package/dist/lifecycle-pools.d.ts.map +1 -1
  220. package/dist/lifecycle-pools.js +27 -7
  221. package/dist/lifecycle-pools.js.map +1 -1
  222. package/dist/merge-question-surfacer.d.ts +18 -4
  223. package/dist/merge-question-surfacer.d.ts.map +1 -1
  224. package/dist/merge-question-surfacer.js +20 -5
  225. package/dist/merge-question-surfacer.js.map +1 -1
  226. package/dist/migrate-stuck-locks.d.ts +129 -0
  227. package/dist/migrate-stuck-locks.d.ts.map +1 -0
  228. package/dist/migrate-stuck-locks.js +355 -0
  229. package/dist/migrate-stuck-locks.js.map +1 -0
  230. package/dist/mint-adr.js +4 -4
  231. package/dist/mirror-pool-scan.d.ts +2 -2
  232. package/dist/mirror-pool-scan.js +3 -3
  233. package/dist/mirror-pool-scan.js.map +1 -1
  234. package/dist/needs-attention.d.ts +304 -27
  235. package/dist/needs-attention.d.ts.map +1 -1
  236. package/dist/needs-attention.js +542 -67
  237. package/dist/needs-attention.js.map +1 -1
  238. package/dist/orphan-sidecar.d.ts +10 -6
  239. package/dist/orphan-sidecar.d.ts.map +1 -1
  240. package/dist/orphan-sidecar.js +35 -2
  241. package/dist/orphan-sidecar.js.map +1 -1
  242. package/dist/pi-harness.d.ts +16 -0
  243. package/dist/pi-harness.d.ts.map +1 -1
  244. package/dist/pi-harness.js +82 -2
  245. package/dist/pi-harness.js.map +1 -1
  246. package/dist/placement.d.ts +8 -8
  247. package/dist/placement.js +3 -3
  248. package/dist/prd-to-spec.d.ts.map +1 -1
  249. package/dist/prd-to-spec.js +9 -5
  250. package/dist/prd-to-spec.js.map +1 -1
  251. package/dist/prompt.d.ts +16 -19
  252. package/dist/prompt.d.ts.map +1 -1
  253. package/dist/prompt.js +17 -19
  254. package/dist/prompt.js.map +1 -1
  255. package/dist/protocol/CLAIM-PROTOCOL.md +17 -10
  256. package/dist/protocol/REVIEW-PROTOCOL.md +4 -1
  257. package/dist/protocol/SURFACE-PROTOCOL.md +16 -2
  258. package/dist/protocol/TASKING-PROTOCOL.md +3 -1
  259. package/dist/protocol/WORK-CONTRACT.md +22 -18
  260. package/dist/protocol/task-template.md +1 -1
  261. package/dist/readiness.d.ts +1 -1
  262. package/dist/reap-branches.d.ts +12 -9
  263. package/dist/reap-branches.d.ts.map +1 -1
  264. package/dist/reap-branches.js +25 -7
  265. package/dist/reap-branches.js.map +1 -1
  266. package/dist/recover-isolated.d.ts +12 -0
  267. package/dist/recover-isolated.d.ts.map +1 -1
  268. package/dist/recover-isolated.js +6 -1
  269. package/dist/recover-isolated.js.map +1 -1
  270. package/dist/repo-config.d.ts +23 -2
  271. package/dist/repo-config.d.ts.map +1 -1
  272. package/dist/repo-config.js +64 -18
  273. package/dist/repo-config.js.map +1 -1
  274. package/dist/repo-mirror.d.ts.map +1 -1
  275. package/dist/repo-mirror.js +18 -2
  276. package/dist/repo-mirror.js.map +1 -1
  277. package/dist/review-gate.d.ts +3 -3
  278. package/dist/review-gate.d.ts.map +1 -1
  279. package/dist/review-gate.js +11 -10
  280. package/dist/review-gate.js.map +1 -1
  281. package/dist/review-verdict.d.ts +2 -2
  282. package/dist/review-verdict.d.ts.map +1 -1
  283. package/dist/review-verdict.js +2 -2
  284. package/dist/review-verdict.js.map +1 -1
  285. package/dist/run.d.ts +2 -2
  286. package/dist/run.d.ts.map +1 -1
  287. package/dist/run.js +58 -23
  288. package/dist/run.js.map +1 -1
  289. package/dist/scan.d.ts +26 -17
  290. package/dist/scan.d.ts.map +1 -1
  291. package/dist/scan.js +29 -15
  292. package/dist/scan.js.map +1 -1
  293. package/dist/select-order.d.ts +1 -1
  294. package/dist/select-priority.d.ts +14 -14
  295. package/dist/select-priority.d.ts.map +1 -1
  296. package/dist/select-priority.js +5 -5
  297. package/dist/select-priority.js.map +1 -1
  298. package/dist/sidecar-apply.js +1 -1
  299. package/dist/sidecar-apply.js.map +1 -1
  300. package/dist/sidecar.d.ts +47 -12
  301. package/dist/sidecar.d.ts.map +1 -1
  302. package/dist/sidecar.js +84 -4
  303. package/dist/sidecar.js.map +1 -1
  304. package/dist/skills/answer-questions/SKILL.md +89 -0
  305. package/dist/skills/capture-signal/SKILL.md +52 -0
  306. package/dist/skills/convert-from-prd-to-spec/SKILL.md +90 -0
  307. package/dist/skills/drive-tasks/SKILL.md +218 -0
  308. package/dist/skills/from-idea/SKILL.md +83 -0
  309. package/dist/skills/merge-prs/SKILL.md +70 -0
  310. package/dist/skills/orchestrate/SKILL.md +101 -0
  311. package/dist/skills/promote/SKILL.md +35 -0
  312. package/dist/skills/review/SKILL.md +16 -0
  313. package/dist/skills/setup/SKILL.md +258 -0
  314. package/dist/skills/setup/protocol/ADR-FORMAT.md +47 -0
  315. package/dist/skills/setup/protocol/CLAIM-PROTOCOL.md +224 -0
  316. package/dist/skills/setup/protocol/REVIEW-PROTOCOL.md +122 -0
  317. package/dist/skills/setup/protocol/SURFACE-PROTOCOL.md +135 -0
  318. package/dist/skills/setup/protocol/TASKING-PROTOCOL.md +124 -0
  319. package/dist/skills/setup/protocol/WORK-CONTRACT.md +280 -0
  320. package/dist/skills/setup/protocol/spec-template.md +71 -0
  321. package/dist/skills/setup/protocol/task-template.md +65 -0
  322. package/dist/skills/surface-questions/SKILL.md +16 -0
  323. package/dist/skills/to-spec/SKILL.md +34 -0
  324. package/dist/skills/to-task/SKILL.md +19 -0
  325. package/dist/skills/triage-observations/SKILL.md +78 -0
  326. package/dist/skills/work/SKILL.md +51 -0
  327. package/dist/slug-namespace.d.ts +6 -6
  328. package/dist/slug-namespace.js +8 -8
  329. package/dist/slug-namespace.js.map +1 -1
  330. package/dist/spec-complete.d.ts.map +1 -1
  331. package/dist/spec-complete.js +4 -5
  332. package/dist/spec-complete.js.map +1 -1
  333. package/dist/start.d.ts +1 -1
  334. package/dist/start.d.ts.map +1 -1
  335. package/dist/start.js +54 -60
  336. package/dist/start.js.map +1 -1
  337. package/dist/status.d.ts +3 -3
  338. package/dist/status.js +4 -4
  339. package/dist/status.js.map +1 -1
  340. package/dist/surface-gate.d.ts +2 -2
  341. package/dist/surface-gate.d.ts.map +1 -1
  342. package/dist/surface-gate.js +10 -3
  343. package/dist/surface-gate.js.map +1 -1
  344. package/dist/surface-persist.d.ts +2 -2
  345. package/dist/surface-persist.d.ts.map +1 -1
  346. package/dist/surface-persist.js +1 -1
  347. package/dist/surface-persist.js.map +1 -1
  348. package/dist/tasker-review-loop.d.ts +11 -10
  349. package/dist/tasker-review-loop.d.ts.map +1 -1
  350. package/dist/tasker-review-loop.js +8 -8
  351. package/dist/tasker-review-loop.js.map +1 -1
  352. package/dist/tasking-eligibility.d.ts +21 -21
  353. package/dist/tasking-eligibility.d.ts.map +1 -1
  354. package/dist/tasking-eligibility.js +10 -10
  355. package/dist/tasking-lock.d.ts +10 -10
  356. package/dist/tasking-lock.d.ts.map +1 -1
  357. package/dist/tasking-lock.js +69 -49
  358. package/dist/tasking-lock.js.map +1 -1
  359. package/dist/tasking.d.ts +73 -39
  360. package/dist/tasking.d.ts.map +1 -1
  361. package/dist/tasking.js +309 -95
  362. package/dist/tasking.js.map +1 -1
  363. package/dist/triage-gate.d.ts +1 -1
  364. package/dist/triage-persist.d.ts +15 -11
  365. package/dist/triage-persist.d.ts.map +1 -1
  366. package/dist/triage-persist.js +48 -18
  367. package/dist/triage-persist.js.map +1 -1
  368. package/dist/vendor/incur/agents.d.ts +58 -0
  369. package/dist/vendor/incur/agents.d.ts.map +1 -0
  370. package/dist/vendor/incur/agents.js +343 -0
  371. package/dist/vendor/incur/agents.js.map +1 -0
  372. package/dist/verify-workflow-template.d.ts +1 -1
  373. package/dist/verify-workflow-template.js +3 -3
  374. package/dist/watch-session.d.ts +11 -3
  375. package/dist/watch-session.d.ts.map +1 -1
  376. package/dist/watch-session.js +94 -7
  377. package/dist/watch-session.js.map +1 -1
  378. package/dist/work-layout.d.ts +15 -9
  379. package/dist/work-layout.d.ts.map +1 -1
  380. package/dist/work-layout.js +14 -9
  381. package/dist/work-layout.js.map +1 -1
  382. package/dist/workspace.d.ts +2 -2
  383. package/package.json +2 -2
  384. package/src/advance-ci-template.ts +4 -4
  385. package/src/advance-classify.ts +5 -5
  386. package/src/advance-drivers.ts +26 -13
  387. package/src/advance-isolated.ts +3 -3
  388. package/src/advance-lifecycle-template.ts +98 -13
  389. package/src/advance-loop-driver.ts +3 -3
  390. package/src/advance-treeless-publish.ts +46 -1
  391. package/src/advance.ts +495 -115
  392. package/src/advancing-lock.ts +102 -7
  393. package/src/agent-launch.ts +37 -12
  394. package/src/agent-stop.ts +60 -2
  395. package/src/apply-decide.ts +38 -9
  396. package/src/apply-merge-action.ts +49 -11
  397. package/src/apply-persist.ts +236 -62
  398. package/src/apply-stuck-action.ts +260 -0
  399. package/src/brand.ts +14 -2
  400. package/src/buildable-body.ts +14 -14
  401. package/src/claim-cas.ts +4 -4
  402. package/src/cli-spinner.ts +1 -1
  403. package/src/cli.ts +472 -141
  404. package/src/close-job-template.ts +9 -9
  405. package/src/close-job.ts +26 -26
  406. package/src/complete.ts +121 -63
  407. package/src/concurrency.ts +1 -1
  408. package/src/config.ts +143 -49
  409. package/src/continue-branch.ts +23 -1
  410. package/src/cwd-section.ts +1 -1
  411. package/src/decision-engine.ts +57 -19
  412. package/src/do-autopick.ts +21 -10
  413. package/src/do-config.ts +7 -7
  414. package/src/do-remote-auto.ts +2 -2
  415. package/src/do.ts +558 -85
  416. package/src/drop-source.ts +2 -2
  417. package/src/env-config.ts +19 -11
  418. package/src/failure-cause.ts +30 -1
  419. package/src/format.ts +13 -33
  420. package/src/frontmatter.ts +55 -35
  421. package/src/gc.ts +172 -9
  422. package/src/github.ts +78 -0
  423. package/src/harness.ts +25 -0
  424. package/src/index.ts +10 -0
  425. package/src/install-ci-branch-protection.ts +283 -58
  426. package/src/install-ci-capabilities/advance-lifecycle.ts +1 -1
  427. package/src/install-ci-capabilities/close-job.ts +1 -1
  428. package/src/install-ci-capabilities/example-noop.ts +1 -1
  429. package/src/install-ci-capabilities/intake.ts +2 -2
  430. package/src/install-ci-capabilities/verify.ts +1 -1
  431. package/src/install-ci-core.ts +34 -7
  432. package/src/install-ci-github.ts +87 -1
  433. package/src/install-ci.ts +4 -4
  434. package/src/install-skills.ts +166 -0
  435. package/src/intake-event.ts +6 -6
  436. package/src/intake-marker.ts +3 -3
  437. package/src/intake-triage.ts +2 -2
  438. package/src/intake-trigger-template.ts +18 -18
  439. package/src/intake.ts +138 -103
  440. package/src/integration-core.ts +234 -100
  441. package/src/integrator.ts +22 -9
  442. package/src/isolation.ts +13 -4
  443. package/src/issue-provider.ts +4 -4
  444. package/src/item-lock.ts +505 -361
  445. package/src/item-path.ts +2 -2
  446. package/src/ledger-lint.ts +9 -9
  447. package/src/ledger-read.ts +81 -81
  448. package/src/ledger-write.ts +137 -152
  449. package/src/lifecycle-gather.ts +45 -22
  450. package/src/lifecycle-pools.ts +71 -13
  451. package/src/merge-question-surfacer.ts +32 -8
  452. package/src/migrate-stuck-locks.ts +451 -0
  453. package/src/mint-adr.ts +4 -4
  454. package/src/mirror-pool-scan.ts +5 -5
  455. package/src/needs-attention.ts +877 -104
  456. package/src/orphan-sidecar.ts +49 -8
  457. package/src/pi-harness.ts +82 -2
  458. package/src/placement.ts +8 -8
  459. package/src/prd-to-spec.ts +13 -5
  460. package/src/prompt.ts +20 -25
  461. package/src/readiness.ts +1 -1
  462. package/src/reap-branches.ts +38 -14
  463. package/src/recover-isolated.ts +18 -1
  464. package/src/repo-config.ts +66 -17
  465. package/src/repo-mirror.ts +23 -1
  466. package/src/review-gate.ts +12 -11
  467. package/src/review-verdict.ts +3 -3
  468. package/src/run.ts +69 -23
  469. package/src/scan.ts +36 -22
  470. package/src/select-order.ts +1 -1
  471. package/src/select-priority.ts +15 -15
  472. package/src/sidecar-apply.ts +1 -1
  473. package/src/sidecar.ts +141 -14
  474. package/src/slug-namespace.ts +10 -10
  475. package/src/spec-complete.ts +4 -5
  476. package/src/start.ts +57 -63
  477. package/src/status.ts +7 -7
  478. package/src/surface-gate.ts +12 -5
  479. package/src/surface-persist.ts +3 -3
  480. package/src/tasker-review-loop.ts +18 -17
  481. package/src/tasking-eligibility.ts +21 -21
  482. package/src/tasking-lock.ts +75 -60
  483. package/src/tasking.ts +381 -135
  484. package/src/triage-gate.ts +1 -1
  485. package/src/triage-persist.ts +71 -27
  486. package/src/vendor/incur/LICENSE +21 -0
  487. package/src/vendor/incur/README.md +19 -0
  488. package/src/vendor/incur/agents.ts +392 -0
  489. package/src/verify-workflow-template.ts +3 -3
  490. package/src/watch-session.ts +102 -7
  491. package/src/work-layout.ts +14 -9
  492. package/src/workspace.ts +2 -2
@@ -57,8 +57,8 @@ import {isAncestor} from './gc.js';
57
57
  * integrates), so verify-then-review holds on the merged tree, never split across
58
58
  * two trees. Any failure routes to needs-attention.
59
59
  *
60
- * It is the CORE in the head / core / tail decomposition (prd
61
- * `work/prds/tasked/run-do-integrate-convergence.md`): the caller-specific HEAD
60
+ * It is the CORE in the head / core / tail decomposition (spec
61
+ * `work/specs/tasked/run-do-integrate-convergence.md`): the caller-specific HEAD
62
62
  * (repo/arbiter/branch checks, source resolution, the `recovering` flag) and TAIL
63
63
  * (switch-to-main / `syncLocalMain` / delete-local-branch / `--no-switch` / the
64
64
  * propose next-step block, or — for `run` — the job-record + worktree reap) stay
@@ -98,7 +98,7 @@ export type IntegrationCoreOutcome =
98
98
  /**
99
99
  * The CORE's input — everything the band needs, nothing caller-shaped. Every
100
100
  * divergence between the human `complete` path and the autonomous `do`/`run` path
101
- * maps to a FIELD VALUE here, not an `if (caller === …)` branch (prd: "zero
101
+ * maps to a FIELD VALUE here, not an `if (caller === …)` branch (spec: "zero
102
102
  * caller-identity leakage"). In-place vs worktree = `cwd`; arbiter name =
103
103
  * `arbiter`; human vs autonomous surfacing = `surfaceArbiter`; do's recovery =
104
104
  * `source` + `recovering`; per-repo/lang gate = `verify`.
@@ -108,9 +108,9 @@ export type IntegrationCoreOutcome =
108
108
  * task-shaped done-move + title source. The shared band
109
109
  * (verify→review→commit→rebase→integrate→propose-PR-with-title/body) is
110
110
  * IDENTICAL; only the "which item move + which file to read the title from" step
111
- * is caller-supplied. This is the seam the `do prd:<slug>` TASKING transition
112
- * rides (task `slice-output-through-integration`): its "item move" is the prd
113
- * LIFECYCLE move (`work/prds/ready/<slug>.md → work/prds/tasked/<slug>.md`, residence =
111
+ * is caller-supplied. This is the seam the `do spec:<slug>` TASKING transition
112
+ * rides (task `slice-output-through-integration`): its "item move" is the spec
113
+ * LIFECYCLE move (`work/specs/ready/<slug>.md → work/specs/tasked/<slug>.md`, residence =
114
114
  * tasked-ness) plus its EMITTED backlog files — NOT a task done-move. Supplying it
115
115
  * makes every integrate-time arg (`--propose`/`--merge`, provider, title/body)
116
116
  * apply to tasking BY CONSTRUCTION, because they resolve ONCE here.
@@ -127,7 +127,7 @@ export interface IntegrationLifecycle {
127
127
  /**
128
128
  * Absolute path to the item file whose `title:` frontmatter seeds the default
129
129
  * commit summary AND the synthesised propose-mode PR title. For the tasking
130
- * transition this is the held prd (`work/prds/ready/<slug>.md`) — read BEFORE
130
+ * transition this is the held spec (`work/specs/ready/<slug>.md`) — read BEFORE
131
131
  * {@link stage} moves it. IGNORED when {@link title} is supplied (the explicit
132
132
  * title wins — no file read).
133
133
  */
@@ -137,16 +137,16 @@ export interface IntegrationLifecycle {
137
137
  * uses THIS as the title source for the default commit summary AND the synthesised
138
138
  * propose-mode PR title, INSTEAD of reading {@link titlePath}. This is the seam for
139
139
  * a lifecycle whose output file does NOT yet exist at title-read time — the intake
140
- * lone-task / prd path WRITES `work/backlog/<slug>.md` / `work/prds/ready/<slug>.md` in
140
+ * lone-task / spec path WRITES `work/backlog/<slug>.md` / `work/specs/ready/<slug>.md` in
141
141
  * {@link stage}, which runs AFTER the title read, so a `titlePath` read would race
142
- * the write and fall back to a generic subject. The `do prd:` tasking transition
143
- * leaves this unset (its `titlePath` is an already-existing held prd, read fine).
142
+ * the write and fall back to a generic subject. The `do spec:` tasking transition
143
+ * leaves this unset (its `titlePath` is an already-existing held spec, read fine).
144
144
  */
145
145
  title?: string;
146
146
  /**
147
147
  * STAGE the lifecycle move + emitted files into the index on the current work
148
148
  * branch (runner-owned git; the agent never does git). For the tasking
149
- * transition: `git mv work/prds/ready/<slug>.md → work/prds/tasked/<slug>.md`
149
+ * transition: `git mv work/specs/ready/<slug>.md → work/specs/tasked/<slug>.md`
150
150
  * (residence = tasked-ness; no marker), and write+`git add` the produced
151
151
  * `work/backlog/*.md` files. The band's subsequent `git add -A` + atomic commit
152
152
  * folds this staging
@@ -165,8 +165,8 @@ export interface IntegrationLifecycle {
165
165
 
166
166
  /**
167
167
  * The default LIVENESS CEILING for the merge-mode `${branch}:main` push (the
168
- * durable promotions `tasks/ready → tasks/done` and, via `lifecycle`, `prds/ready
169
- * → prds/tasked`). Task `c2-rebase-until-real-on-durable-main-promotions` turned
168
+ * durable promotions `tasks/ready → tasks/done` and, via `lifecycle`, `specs/ready
169
+ * → specs/tasked`). Task `c2-rebase-until-real-on-durable-main-promotions` turned
170
170
  * the previous SMALL FIXED CAP (was 5, the `run-fleet-claim-integrate-and-sibling-
171
171
  * rebase-concurrency-safe` Race-1 budget) into rebase-until-real-conflict: a CLEAN
172
172
  * re-rebase no longer counts against a tiny give-up budget — only a GENUINE
@@ -271,7 +271,7 @@ export interface IntegrationCoreInput {
271
271
  * `work/<type>-<slug>` identity. When omitted, the core derives it from the
272
272
  * branch HEAD is on (the robust default — the type is encoded IN the name). A
273
273
  * caller that knows the type explicitly may pass it (e.g. the tasking path
274
- * passes its `work/prds/ready-<slug>`).
274
+ * passes its `work/specs/ready-<slug>`).
275
275
  */
276
276
  branch?: string;
277
277
  /**
@@ -279,7 +279,7 @@ export interface IntegrationCoreInput {
279
279
  * freshly-built path — since claim no longer moves the body, a freshly-built
280
280
  * task RESTS in the pool on `main`, task
281
281
  * `cutover-claim-body-stays-and-complete-sources-from-backlog`),
282
- * `tasks-backlog` (the `--allow-backlog` staged-drive path, prd
282
+ * `tasks-backlog` (the `--allow-backlog` staged-drive path, spec
283
283
  * `do-allow-backlog-drive-staged-tasks-without-promotion`: a human drove a
284
284
  * STAGED task in place, so the done-move goes `tasks/backlog/ → tasks/done/`
285
285
  * DIRECTLY — the explicit drive IS the promotion, never bouncing through the
@@ -313,8 +313,8 @@ export interface IntegrationCoreInput {
313
313
  // like a normal build.
314
314
  source: 'tasks-ready' | 'tasks-backlog' | 'in-progress' | 'done';
315
315
  /**
316
- * Vestigial: was `true` when completing FROM `work/needs-attention/` (a
317
- * recovery finish under the legacy folder model). The per-item-lock cutover
316
+ * Vestigial: was `true` when completing FROM the retired `needs-attention/`
317
+ * folder (a recovery finish under the legacy folder model). The per-item-lock cutover
318
318
  * (`cutover-needs-attention-becomes-lock-stuck-recovery-surface`) retired
319
319
  * that folder — a stuck item is now the lock `state: stuck` and the body
320
320
  * stays in `tasks/ready/`, so a recovery `complete` is structurally a normal
@@ -325,7 +325,7 @@ export interface IntegrationCoreInput {
325
325
  */
326
326
  recovering: boolean;
327
327
  /**
328
- * **RECOVER an already-committed, already-done-moved STRANDED branch** (prd
328
+ * **RECOVER an already-committed, already-done-moved STRANDED branch** (spec
329
329
  * `ledger-integrity` story 6, the `finish-already-committed-branch` task). When
330
330
  * `true`, the work is ALREADY committed on the work branch with the task already
331
331
  * `git mv`'d into `work/done/` (a terminal push failed AFTER steps 2–3, leaving
@@ -564,7 +564,7 @@ export interface IntegrationCoreInput {
564
564
  * `slice-output-through-integration`). When set, the band reads the title from
565
565
  * its {@link IntegrationLifecycle.titlePath}, calls its
566
566
  * {@link IntegrationLifecycle.stage} INSTEAD of the task `git mv → work/done/`,
567
- * and uses the plain rebase ({@link recovering} is irrelevant). The `do prd:`
567
+ * and uses the plain rebase ({@link recovering} is irrelevant). The `do spec:`
568
568
  * TASKING transition supplies it; `do`/`complete`/`run` leave it unset (the
569
569
  * task done-move is unchanged).
570
570
  */
@@ -579,9 +579,11 @@ export interface IntegrationCoreResult {
579
579
  /** What the core resolved (the tail maps this 1:1 onto its own outcome). */
580
580
  outcome: IntegrationCoreOutcome;
581
581
  /**
582
- * True iff a FAILURE outcome was routed to `work/needs-attention/` via the
583
- * shared mechanism. False on the success path and when a failure was NOT moved
584
- * (e.g. a red re-gate that stays put in recovery).
582
+ * True iff a FAILURE outcome was routed through the shared needs-attention
583
+ * mechanism post lock-cutover, the per-item lock was amended to
584
+ * `state: stuck` with the reason on the lock entry (no folder move). False
585
+ * on the success path and when a failure was NOT surfaced (e.g. a red
586
+ * re-gate that stays put in recovery).
585
587
  */
586
588
  routedToNeedsAttention: boolean;
587
589
  /** The work branch that was processed (`work/<slug>`). */
@@ -606,8 +608,8 @@ export interface IntegrationCoreResult {
606
608
  * needs-attention routing can record the findings as the item-body prose. The
607
609
  * tasking path (task `slice-acceptance-gate`) reads this: the core's build
608
610
  * `applyNeedsAttentionTransition` is keyed on a TASK lock, so the tasking path
609
- * routes the prd itself via the lock release's needs-attention redirect (amend the
610
- * `prd:<slug>` unified lock `active -> stuck`, no folder move), using THIS
611
+ * routes the spec itself via the lock release's needs-attention redirect (amend the
612
+ * `spec:<slug>` unified lock `active -> stuck`, no folder move), using THIS
611
613
  * findings text as the body. Absent on every non-`review-blocked` outcome. (The
612
614
  * build path ignores it — its routing already records the findings in-body.)
613
615
  */
@@ -667,7 +669,7 @@ export async function performIntegration(
667
669
  // in the `run` caller, not here.
668
670
  const freshWorktreeGate = input.freshWorktreeGate === true;
669
671
 
670
- // RECOVER an already-committed, already-done-moved STRANDED branch (prd
672
+ // RECOVER an already-committed, already-done-moved STRANDED branch (spec
671
673
  // `ledger-integrity` story 6). The work + the done-move are ALREADY committed on
672
674
  // the work branch (a terminal push failed AFTER steps 2–3); SKIP steps 0–3
673
675
  // (prepare / gate / review / done-move / commit) and run ONLY the
@@ -687,8 +689,21 @@ export async function performIntegration(
687
689
  recoveryRebaseJitterMs: input.recoveryRebaseJitterMs,
688
690
  recoveryRebaseSleep: input.recoveryRebaseSleep,
689
691
  recoveryRebaseRandom: input.recoveryRebaseRandom,
692
+ // GATE-2 REVIEW on the recovery path (task
693
+ // `committed-recovery-always-reviews`): a stranded already-complete
694
+ // branch is NOT "already reviewed" — its earlier attempt's PR never
695
+ // merged and Gate 2 may never have run on it. So when `review` is on we
696
+ // MUST run Gate 2 on the rebased tip here too (the SAME reasoning that
697
+ // forces the re-verify: `<arbiter>/main` moved, the merged tree is new).
698
+ // Pass the whole `input` so the recovery tail can call `runGate2Review`
699
+ // with the identical gate/model/watch/round wiring the build path uses.
700
+ input,
701
+ // PR BODY on the recovery path: the recovery has NO fresh agent output
702
+ // (no rebuild), so carry whatever `body` the caller supplied so the PR
703
+ // gets a description instead of degrading to a blank `gh --fill`.
704
+ body: input.body,
690
705
  // Answered-merge land (task `committed-recovery-honours-fresh-worktree-gate`,
691
- // prd `land-time-reverify-and-parallel-merge-ceiling`): the apply-rung
706
+ // spec `land-time-reverify-and-parallel-merge-ceiling`): the apply-rung
692
707
  // dispatches an answered `merge` through this committed-recovery tail (the
693
708
  // branch already carries its done-move commit, so the build path's
694
709
  // `git mv`+`add -A`+commit would raise `IntegrationNothingStaged`). UNLIKE
@@ -713,7 +728,7 @@ export async function performIntegration(
713
728
  }
714
729
 
715
730
  // The file whose `title:` seeds the commit summary + PR title. For a TASKING
716
- // transition (a non-task `lifecycle`) this is the held prd it supplies; for a
731
+ // transition (a non-task `lifecycle`) this is the held spec it supplies; for a
717
732
  // build it is the task in its source folder. Read BEFORE any move.
718
733
  const lifecycle = input.lifecycle;
719
734
  // CONTINUE-BUILD (`source: 'done'`, task
@@ -740,7 +755,7 @@ export async function performIntegration(
740
755
  // passes no flag, so there an untrusted-origin task RELIABLY forces propose.
741
756
  //
742
757
  // SCOPE: the task BUILD transition ONLY. It NEVER fires for a `lifecycle`
743
- // transition (tasking / intake-emit — a prd/task FILE landing on main is inert;
758
+ // transition (tasking / intake-emit — a spec/task FILE landing on main is inert;
744
759
  // intake's OWN per-emit resolver already decided that mode), and the source file
745
760
  // here is the task being built. A `trusted`/unset task ⇒ untouched (zero
746
761
  // behaviour change for the normal human path).
@@ -793,10 +808,11 @@ export async function performIntegration(
793
808
  }
794
809
  if (!prep.passed) {
795
810
  const reason = `prepare (env-prep) failed (exit ${prep.exitCode})`;
796
- // Bounce from in-progress/ straight to needs-attention/ (the SAME seam a red
797
- // gate uses) — recording the prepare-failed reason + committing the move
798
- // (with the agent's uncommitted work) as ONE atomic transition. We NEVER
799
- // run `verify` on an env that could not be made ready.
811
+ // Mark the item stuck on its per-item lock (the SAME seam a red gate uses)
812
+ // — recording the prepare-failed reason on the lock entry + saving the
813
+ // agent's uncommitted work as a wip commit (post lock-cutover: a lock amend,
814
+ // no `in-progress/ needs-attention/` folder move). We NEVER run `verify`
815
+ // on an env that could not be made ready.
800
816
  const routed = await ledgerWrite.applyNeedsAttentionTransition({
801
817
  cwd,
802
818
  slug,
@@ -810,10 +826,10 @@ export async function performIntegration(
810
826
  routedToNeedsAttention: routed.moved,
811
827
  branch,
812
828
  reason: routed.moved
813
- ? `Env-prep (prepare) failed (exit ${prep.exitCode}); routed '${slug}' ` +
814
- 'to work/needs-attention/ (the environment could not be made ready, ' +
829
+ ? `Env-prep (prepare) failed (exit ${prep.exitCode}); marked '${slug}' ` +
830
+ 'stuck on its per-item lock (the environment could not be made ready, ' +
815
831
  'so the acceptance gate was NOT run). Fix the prepare command, then ' +
816
- 'return it to backlog/.'
832
+ '`requeue` to release the stuck lock.'
817
833
  : `Env-prep (prepare) failed (exit ${prep.exitCode}); not completing ` +
818
834
  `'${slug}' (the environment could not be made ready, so the ` +
819
835
  'acceptance gate was NOT run). Fix the prepare command, then retry.',
@@ -832,12 +848,12 @@ export async function performIntegration(
832
848
  note('Running the acceptance gate (verify)…');
833
849
  const gate = await runVerify({cwd, verify: input.verify, env});
834
850
  if (!gate.passed) {
835
- // Don't leave the item dangling in in-progress/: route it to
836
- // needs-attention/ with the reason (ADR §12) THROUGH the ledger write
837
- // seam's needs-attention transition. The item has NOT been committed/moved
838
- // yet, so the move bounces it straight from in-progress/ recording the
839
- // reason + committing the move (with the agent's uncommitted work) as ONE
840
- // atomic transition. No partial state.
851
+ // Don't leave the item dangling: mark it stuck on its per-item lock with
852
+ // the reason (ADR §12) THROUGH the ledger write seam's needs-attention
853
+ // transition. Post lock-cutover this is a lock amend (`state: stuck` + the
854
+ // reason on the lock entry, no `in-progress/ needs-attention/` folder
855
+ // move) plus saving the agent's uncommitted work as a wip commit. No
856
+ // partial state.
841
857
  const reason = `acceptance gate failed (exit ${gate.exitCode})`;
842
858
  const routed = await ledgerWrite.applyNeedsAttentionTransition({
843
859
  cwd,
@@ -860,16 +876,16 @@ export async function performIntegration(
860
876
  routedToNeedsAttention: routed.moved,
861
877
  branch,
862
878
  reason: routed.moved
863
- ? `Acceptance gate failed (exit ${gate.exitCode}); routed '${slug}' ` +
864
- 'to work/needs-attention/ (surfaced by status; return to backlog/ ' +
865
- 'once resolved). Fix the work, or use --skip-verify to override.'
879
+ ? `Acceptance gate failed (exit ${gate.exitCode}); marked '${slug}' ` +
880
+ 'stuck on its per-item lock (surfaced by status; `requeue` once ' +
881
+ 'resolved). Fix the work, or use --skip-verify to override.'
866
882
  : `Acceptance gate failed (exit ${gate.exitCode}); not completing ` +
867
883
  `'${slug}'. Fix the work, or use --skip-verify to override.`,
868
884
  };
869
885
  }
870
886
  }
871
887
 
872
- // 1b. Gate 2 — the PR/code REVIEW gate (GATES prd `work/prds/tasked/review.md`). It is a
888
+ // 1b. Gate 2 — the PR/code REVIEW gate (GATES spec `work/specs/tasked/review.md`). It is a
873
889
  // JUDGEMENT gate layered ON TOP of the deterministic `verify` floor (ADR §8)
874
890
  // — NEVER a replacement, and ALWAYS verify-THEN-review on the SAME tree.
875
891
  //
@@ -924,10 +940,10 @@ export async function performIntegration(
924
940
  // never be the multi-line commit-subject run-on `--fill` would derive.
925
941
  //
926
942
  // When the lifecycle supplies an EXPLICIT `title`, use it DIRECTLY (no file read):
927
- // the intake lone-task / prd path writes its output file in `stage()`, which runs
943
+ // the intake lone-task / spec path writes its output file in `stage()`, which runs
928
944
  // AFTER this point, so a `titlePath` read would race the write and degrade the
929
- // subject/PR title to the generic fallback. The `do prd:` tasking path leaves
930
- // `title` unset and keeps reading its already-existing held prd (unchanged).
945
+ // subject/PR title to the generic fallback. The `do spec:` tasking path leaves
946
+ // `title` unset and keeps reading its already-existing held spec (unchanged).
931
947
  const explicitTitle = lifecycle?.title;
932
948
  const taskTitle =
933
949
  explicitTitle !== undefined ? explicitTitle : readTaskTitle(sourcePath);
@@ -943,7 +959,7 @@ export async function performIntegration(
943
959
 
944
960
  // 2. STAGE the item move into the index. For a build that is the task done-move
945
961
  // (`work/<source>/<slug>.md → work/done/<slug>.md`); for a TASKING
946
- // transition (a non-task `lifecycle`) it is the caller-supplied prd
962
+ // transition (a non-task `lifecycle`) it is the caller-supplied spec
947
963
  // lifecycle move + emitted backlog files (the runner stages them, the agent
948
964
  // never does git). Either way the subsequent `git add -A` folds the agent's
949
965
  // uncommitted work + this staging into ONE atomic commit.
@@ -1001,7 +1017,7 @@ export async function performIntegration(
1001
1017
  // they are TRACKED, not dropped/untracked. Rule B is extended HERE: the runner REPORTS
1002
1018
  // exactly which note files landed (honest reporting — what actually reached the commit,
1003
1019
  // read from the staged set, not assumed). This is the ONE shared place — BOTH the build
1004
- // path (`do <task>`/`run`/`complete`) and the tasking path (`do prd:`, via the
1020
+ // path (`do <task>`/`run`/`complete`) and the tasking path (`do spec:`, via the
1005
1021
  // `lifecycle` seam) route through it, so the channel is NOT forked. Zero notes ⇒ no
1006
1022
  // report (the no-note case is byte-for-byte unchanged).
1007
1023
  await reportScoopedNotes(cwd, env, note);
@@ -1038,16 +1054,14 @@ export async function performIntegration(
1038
1054
  // 4. Rebase-before-integrate (ADR §10): rebase the work branch onto the
1039
1055
  // latest <arbiter>/main. Clean → continue. Conflict → abort + stop.
1040
1056
  //
1041
- // RECOVERY reconciliation: when completing FROM needs-attention/, the work
1042
- // branch's history still carries the original `in-progress needs-attention`
1043
- // MOVE-ONLY commit, and `<arbiter>/main` was SURFACED with that same move
1044
- // (the item is in needs-attention/ on main). Replaying that historical move
1045
- // onto main conflicts (main has no in-progress/<slug>.md) exactly the
1046
- // rebase conflict the human hit doing this by hand. So we DROP that move-only
1047
- // commit during the rebase: the replay becomes `wip + (needs-attention →
1048
- // done)`, which applies cleanly onto the surfaced main (it HAS the item in
1049
- // needs-attention/). The done-move thus SUPERSEDES the surfaced state — no
1050
- // leftover/conflicting on-`main` surface for the human to resolve.
1057
+ // RECOVERY reconciliation: post the per-item-lock cut-over, a stuck item's
1058
+ // body never moved into a `needs-attention/` folder (stuck is the lock
1059
+ // `state: stuck`; the body rests in `backlog/`), so a recovery `complete`'s
1060
+ // kept branch carries NO historical `in-progress needs-attention`
1061
+ // move-only commit to drop and `<arbiter>/main` holds no surface move to
1062
+ // conflict with. The old recovery drop (`rebaseDroppingNeedsAttentionSurface`,
1063
+ // drop-bookkeeping-rebase) is deleted; recovery is now the SAME plain replay
1064
+ // onto `<arbiter>/main` as any other build (see the plain-rebase note below).
1051
1065
  // Fetch the arbiter's `main` into the `<arbiter>/main` remote-tracking ref
1052
1066
  // EXPLICITLY. A `run` JOB WORKTREE is cut from a bare hub mirror whose remote
1053
1067
  // has no fetch refspec (so `<arbiter>/main` would not otherwise resolve / would
@@ -1099,7 +1113,7 @@ export async function performIntegration(
1099
1113
  };
1100
1114
  }
1101
1115
  }
1102
- // PLAIN rebase. After the per-item-lock cut-over (prd
1116
+ // PLAIN rebase. After the per-item-lock cut-over (spec
1103
1117
  // `ledger-status-per-item-lock-refs`, tasks 9a–9d) no transient status
1104
1118
  // lands on a work branch: needs-attention is the lock `state: stuck` (not a
1105
1119
  // `git mv` to `needs-attention/`), the body rests in `backlog/` while
@@ -1209,12 +1223,12 @@ export async function performIntegration(
1209
1223
  // recovery above can fall through to integrate while a genuine code conflict
1210
1224
  // still routes here.
1211
1225
  async function rebaseConflictRoute(): Promise<IntegrationCoreResult> {
1212
- // Then route the item to needs-attention/ with the conflict reason (ADR
1213
- // §12) THROUGH the ledger write seam's needs-attention transition, rather
1214
- // than leaving it dangling in done/. The done-move was already committed
1215
- // above, so the item sits in work/done/; the move bounces it from there and
1216
- // commits the in-progress→needs-attention move (here done→needs-attention)
1217
- // as ONE transition. No partial state.
1226
+ // Then mark the item stuck on its per-item lock with the conflict reason
1227
+ // (ADR §12) THROUGH the ledger write seam's needs-attention transition,
1228
+ // rather than leaving it dangling. Post lock-cutover this is a lock amend
1229
+ // (`state: stuck` + the reason on the lock entry, no `done/
1230
+ // needs-attention/` folder move); the done-move already committed above
1231
+ // stands. No partial state.
1218
1232
  const reason = `rebase onto ${arbiter}/main conflicted (aborted, never auto-resolved)`;
1219
1233
  const routed = await ledgerWrite.applyNeedsAttentionTransition({
1220
1234
  cwd,
@@ -1236,9 +1250,9 @@ export async function performIntegration(
1236
1250
  commitMessage,
1237
1251
  reason: routed.moved
1238
1252
  ? `Rebasing ${branch} onto ${arbiter}/main conflicted; the rebase was ` +
1239
- `aborted (never auto-resolved) and '${slug}' was routed to ` +
1240
- 'work/needs-attention/ (surfaced by status). Resolve against the ' +
1241
- 'latest main, then return it to backlog/ and re-run.'
1253
+ `aborted (never auto-resolved) and '${slug}' was marked stuck on ` +
1254
+ 'its per-item lock (surfaced by status). Resolve against the latest ' +
1255
+ 'main, then `requeue` to release the stuck lock and re-run.'
1242
1256
  : `Rebasing ${branch} onto ${arbiter}/main conflicted; the rebase was ` +
1243
1257
  'aborted (never auto-resolved). Resolve against the latest main, ' +
1244
1258
  'then re-run complete.',
@@ -1318,9 +1332,9 @@ export async function performIntegration(
1318
1332
  branch,
1319
1333
  commitMessage,
1320
1334
  reason: routed.moved
1321
- ? `${what} on the rebased tip; routed '${slug}' to ` +
1322
- 'work/needs-attention/ (surfaced by status; return to backlog/ ' +
1323
- 'once resolved). Fix the work, or use --skip-verify to override.'
1335
+ ? `${what} on the rebased tip; marked '${slug}' stuck on its ` +
1336
+ 'per-item lock (surfaced by status; `requeue` once resolved). ' +
1337
+ 'Fix the work, or use --skip-verify to override.'
1324
1338
  : `${what} on the rebased tip; not completing '${slug}'. Fix the ` +
1325
1339
  'work, or use --skip-verify to override.',
1326
1340
  };
@@ -1335,7 +1349,8 @@ export async function performIntegration(
1335
1349
  if (gated.review) {
1336
1350
  if (gated.review.kind === 'blocked') {
1337
1351
  // The done-move was already committed (steps 2–3), so the slug sits in
1338
- // work/done/; the routing bounced it from there to needs-attention/.
1352
+ // work/done/; the routing marked it stuck on its per-item lock (post
1353
+ // lock-cutover — a lock amend, no folder move).
1339
1354
  return gated.review.result;
1340
1355
  }
1341
1356
  approvedVerdict = gated.review.verdict;
@@ -1503,9 +1518,10 @@ export async function performIntegration(
1503
1518
  commitMessage,
1504
1519
  reason: routed.moved
1505
1520
  ? `Integrating ${branch} onto ${arbiter}/main kept hitting a ` +
1506
- `non-fast-forward push (a sibling advanced main); '${slug}' was routed ` +
1507
- `to work/needs-attention/ (surfaced by status). Resolve against the ` +
1508
- `latest main, then return it to backlog/ and re-run.`
1521
+ `non-fast-forward push (a sibling advanced main); '${slug}' was ` +
1522
+ `marked stuck on its per-item lock (surfaced by status). Resolve ` +
1523
+ `against the latest main, then \`requeue\` to release the stuck ` +
1524
+ `lock and re-run.`
1509
1525
  : `Integrating ${branch} onto ${arbiter}/main kept hitting a ` +
1510
1526
  `non-fast-forward push (a sibling advanced main). Resolve against the ` +
1511
1527
  `latest main, then re-run complete.`,
@@ -1580,7 +1596,7 @@ export async function performIntegration(
1580
1596
  }
1581
1597
 
1582
1598
  /**
1583
- * RECOVER an already-committed, already-done-moved STRANDED branch (prd
1599
+ * RECOVER an already-committed, already-done-moved STRANDED branch (spec
1584
1600
  * `ledger-integrity` story 6, the `finish-already-committed-branch` task). The
1585
1601
  * green work AND the `git mv → work/done/` are ALREADY committed on the work
1586
1602
  * branch (a terminal push failed AFTER `performIntegration`'s steps 2–3), and the
@@ -1590,7 +1606,7 @@ export async function performIntegration(
1590
1606
  * primitive the build path uses.
1591
1607
  *
1592
1608
  * RE-GATE on the REBASED TIP (task `committed-recovery-honours-fresh-worktree-
1593
- * gate`, prd `land-time-reverify-and-parallel-merge-ceiling`): when the caller
1609
+ * gate`, spec `land-time-reverify-and-parallel-merge-ceiling`): when the caller
1594
1610
  * sets `freshWorktreeGate` (and not `skipVerify`), the EXISTING
1595
1611
  * `runFreshWorktreeGate` runs on the rebased tip AFTER the rebase loop and
1596
1612
  * BEFORE `applyCompleteTransition`, mirroring the build path's
@@ -1635,7 +1651,7 @@ async function recoverAlreadyCommitted(params: {
1635
1651
  /**
1636
1652
  * Run the EXISTING `runFreshWorktreeGate` (`prepare` then `verify`) on the
1637
1653
  * rebased tip AFTER the rebase loop and BEFORE `applyCompleteTransition`
1638
- * (task `committed-recovery-honours-fresh-worktree-gate`, prd
1654
+ * (task `committed-recovery-honours-fresh-worktree-gate`, spec
1639
1655
  * `land-time-reverify-and-parallel-merge-ceiling`). The original stranded-
1640
1656
  * recovery caller (`complete --integration`'s already-built strand) leaves
1641
1657
  * this UNSET ⇒ no gate, no extra fetch — byte-identical to before. The
@@ -1653,6 +1669,23 @@ async function recoverAlreadyCommitted(params: {
1653
1669
  prepare?: VerifyConfig;
1654
1670
  /** Acceptance gate config for the fresh gate (mirrors the build path). */
1655
1671
  verify?: VerifyConfig;
1672
+ /**
1673
+ * The full integration input, threaded so the recovery tail can run Gate 2
1674
+ * (`runGate2Review`) with the identical gate/model/watch/round wiring the
1675
+ * build path uses (task `committed-recovery-always-reviews`). Gate 2 runs on
1676
+ * the rebased tip when `input.review` is on and the fresh gate ran green — a
1677
+ * stranded already-complete branch is NOT trusted as already-reviewed (its
1678
+ * earlier attempt never merged). Optional so the pre-existing non-review
1679
+ * callers (and tests) that do not thread it stay byte-identical.
1680
+ */
1681
+ input?: IntegrationCoreInput;
1682
+ /**
1683
+ * The propose-mode PR BODY (task `committed-recovery-always-reviews`): the
1684
+ * recovery has NO fresh agent output (no rebuild), so the caller passes
1685
+ * whatever advisory body it has so the PR carries a description instead of a
1686
+ * blank `gh --fill`. Undefined ⇒ today's `--fill` fallback.
1687
+ */
1688
+ body?: string;
1656
1689
  /**
1657
1690
  * Autonomous needs-attention surface (mirrors the build path): when set, a
1658
1691
  * red rebased-tip gate cherry-picks the bounce onto `main` + pushes the
@@ -1704,6 +1737,14 @@ async function recoverAlreadyCommitted(params: {
1704
1737
  // (`isAncestor` is the SAME reachability predicate `gc.ts` uses; do not fork it.)
1705
1738
  // KEPT before the retry loop: a no-op MUST short-circuit before we burn any
1706
1739
  // re-fetch/re-rebase budget.
1740
+ //
1741
+ // DELIBERATELY the RAW ancestry predicate, NOT `isProvablyMergedForReap`
1742
+ // (task `reap-squash-merged-remote-work-branches`, ratified): this is an
1743
+ // integration-IDEMPOTENCY check, not reap-safety. A squash-landed LOOKALIKE
1744
+ // whose tip is NOT genuinely reachable would falsely read "already
1745
+ // integrated" here and skip a needed rebase/re-push. The squash-aware helper
1746
+ // is scoped to reap-safety ONLY; see gc.ts `isProvablyMergedForReap` and
1747
+ // work/notes/observations/reap-squash-helper-scope-2026-07-10.md.
1707
1748
  if (isAncestor(cwd, tip, `refs/remotes/${arbiter}/main`, env)) {
1708
1749
  const message =
1709
1750
  `Nothing to recover for '${slug}': its work branch tip is already on ` +
@@ -1801,7 +1842,7 @@ async function recoverAlreadyCommitted(params: {
1801
1842
  }
1802
1843
 
1803
1844
  // FRESH-WORKTREE GATE on the REBASED TIP (task `committed-recovery-honours-
1804
- // fresh-worktree-gate`, prd `land-time-reverify-and-parallel-merge-ceiling`):
1845
+ // fresh-worktree-gate`, spec `land-time-reverify-and-parallel-merge-ceiling`):
1805
1846
  // when `freshWorktreeGate` is set (the answered-merge land caller) and not
1806
1847
  // `--skip-verify`, re-run the acceptance gate on the rebased tip BEFORE we
1807
1848
  // integrate, mirroring the build path's `freshWorktreeGate && !skipVerify &&
@@ -1812,13 +1853,23 @@ async function recoverAlreadyCommitted(params: {
1812
1853
  // clean-rebase-but-broken merge. With `freshWorktreeGate` UNSET (the original
1813
1854
  // stranded-recovery caller, whose pre-strand build already gated) this whole
1814
1855
  // block is skipped and behaviour is byte-identical to before.
1856
+ // Carry an approved Gate-2 verdict (when review ran) so its authored `review`
1857
+ // prose is posted as a PR comment AFTER the integrate below — the SAME audit
1858
+ // trail the build path keeps (task `committed-recovery-always-reviews`).
1859
+ let approvedVerdict: ReviewVerdict | undefined;
1815
1860
  if (params.freshWorktreeGate && !params.skipVerify) {
1816
1861
  const tip = (
1817
1862
  await gitSoft(['rev-parse', '--verify', '--quiet', 'HEAD'], cwd, env)
1818
1863
  ).stdout.trim();
1819
- // No `review:` callback here: the recovery tail re-verifies an already-
1820
- // reviewed, already-committed result, so Gate-2 review semantics do not
1821
- // apply on this path.
1864
+ // GATE-2 REVIEW callback (task `committed-recovery-always-reviews`): when
1865
+ // `input.review` is on, run Gate 2 on the rebased tip AFTER the green verify
1866
+ // EXACTLY the build path's fresh-gate `review:` callback. A stranded
1867
+ // already-complete branch is NOT trusted as already-reviewed (its earlier
1868
+ // attempt's PR never merged, and Gate 2 may never have run on it); the same
1869
+ // reasoning that forces the re-verify here (`<arbiter>/main` moved, so the
1870
+ // merged tree is new) forces the re-review. The needs-attention ROUTING
1871
+ // targets `cwd` (the work branch + ledger), identical to the build path.
1872
+ const reviewInput = params.input;
1822
1873
  const gated = await runFreshWorktreeGate({
1823
1874
  cwd,
1824
1875
  commit: tip,
@@ -1826,6 +1877,19 @@ async function recoverAlreadyCommitted(params: {
1826
1877
  verify: params.verify,
1827
1878
  env,
1828
1879
  note,
1880
+ review:
1881
+ reviewInput?.review === true
1882
+ ? (reviewCwd) =>
1883
+ runGate2Review({
1884
+ reviewCwd,
1885
+ input: reviewInput,
1886
+ slug,
1887
+ branch,
1888
+ cwd,
1889
+ env,
1890
+ note,
1891
+ })
1892
+ : undefined,
1829
1893
  });
1830
1894
  if (!gated.passed) {
1831
1895
  const outcome: IntegrationCoreOutcome =
@@ -1851,15 +1915,43 @@ async function recoverAlreadyCommitted(params: {
1851
1915
  routedToNeedsAttention: routed.moved,
1852
1916
  branch,
1853
1917
  reason: routed.moved
1854
- ? `${what} on the rebased tip during committed-recovery; routed ` +
1855
- `'${slug}' to work/needs-attention/ (surfaced by status; return ` +
1856
- 'to backlog/ once resolved). Fix the work, or use --skip-verify ' +
1918
+ ? `${what} on the rebased tip during committed-recovery; marked ` +
1919
+ `'${slug}' stuck on its per-item lock (surfaced by status; ` +
1920
+ '`requeue` once resolved). Fix the work, or use --skip-verify ' +
1857
1921
  'to override.'
1858
1922
  : `${what} on the rebased tip during committed-recovery; not ` +
1859
1923
  `completing '${slug}'. Fix the work, or use --skip-verify to ` +
1860
1924
  'override.',
1861
1925
  };
1862
1926
  }
1927
+ // GATE-2 REVIEW outcome on the rebased tip: a BLOCK routes to needs-attention
1928
+ // exactly as the build path (only the reviewed tree moved, not the routing).
1929
+ // On APPROVE: carry the verdict for the post-integrate PR comment and write
1930
+ // the per-run non-blocking-nits observation. UNLIKE the build path this branch
1931
+ // integrates the ALREADY-committed kept tip (no upcoming done-move/commit to
1932
+ // sweep the nits file into), so we FOLD the observation into the kept commit
1933
+ // via `commit --amend` — mirroring the build path's fresh-gate amend so the
1934
+ // nits still land in the SAME commit that integrates (no separate commit).
1935
+ if (gated.review) {
1936
+ if (gated.review.kind === 'blocked') {
1937
+ return gated.review.result;
1938
+ }
1939
+ approvedVerdict = gated.review.verdict;
1940
+ const nitsBefore = await stagedCaptureNotes(cwd, env);
1941
+ writeReviewNitsObservation({
1942
+ cwd,
1943
+ slug,
1944
+ findings: gated.review.verdict?.findings ?? [],
1945
+ note,
1946
+ });
1947
+ await gitHard(['add', '-A'], cwd, env);
1948
+ if (!(await nothingStaged(cwd, env))) {
1949
+ const nitsAfter = await stagedCaptureNotes(cwd, env);
1950
+ if (nitsAfter.length > nitsBefore.length) {
1951
+ await gitHard(['commit', '-q', '--amend', '--no-edit'], cwd, env);
1952
+ }
1953
+ }
1954
+ }
1863
1955
  }
1864
1956
 
1865
1957
  // Integrate the rebased kept commit through the SAME complete-transition
@@ -1872,12 +1964,27 @@ async function recoverAlreadyCommitted(params: {
1872
1964
  (params.openPr
1873
1965
  ? bridgeProvider(params.openPr)
1874
1966
  : selectProvider({arbiterUrl: await arbiterUrl(cwd, arbiter, env)}));
1967
+ // PR TITLE + BODY on the recovery path (task `committed-recovery-always-
1968
+ // reviews`): the stranded branch already holds the task in `work/done/`, so
1969
+ // synthesise the SAME single-line `<type>(<slug>): <title>` PR title the build
1970
+ // path does (from the done-resident task file, never agent text) and scaffold
1971
+ // the task-pointer body around the caller-supplied advisory `body`. Undefined
1972
+ // body ⇒ `composeProposeBody` returns undefined ⇒ the provider degrades to
1973
+ // `gh --fill` (no regression); a supplied body gives the PR a real description
1974
+ // instead of the blank one the recovery path used to open.
1975
+ const prTitle = synthesiseProposeTitle({
1976
+ type: (params.input?.type ?? DEFAULT_TYPE).trim() || DEFAULT_TYPE,
1977
+ slug,
1978
+ title: readTaskTitle(workItemPath(cwd, 'done', slug)),
1979
+ });
1875
1980
  const integration = await ledgerWrite.applyCompleteTransition({
1876
1981
  arbiter,
1877
1982
  branch,
1878
1983
  mode,
1879
1984
  provider,
1880
1985
  noPR: params.noPR,
1986
+ title: prTitle,
1987
+ body: composeProposeBody({slug, body: params.body}),
1881
1988
  deleteMergedHead: true,
1882
1989
  cwd,
1883
1990
  env,
@@ -1889,6 +1996,32 @@ async function recoverAlreadyCommitted(params: {
1889
1996
  `(absorbed a moving ${arbiter}/main across ${attempt} re-fetch+re-` +
1890
1997
  `rebase attempt${attempt === 1 ? '' : 's'}).`,
1891
1998
  );
1999
+ // Post the Gate-2 review as a PR comment (task `committed-recovery-always-
2000
+ // reviews`): the SAME post-integrate audit trail the build path keeps — the
2001
+ // approved verdict's authored `review` prose, on the opened PR. Advisory only
2002
+ // (a block never reaches here — it returned above); the same URL/branch
2003
+ // precedence the build path uses (parsed url wins; else a branch-resolved
2004
+ // fallback when a PR opened but its url was unparseable). `postPRComment*`
2005
+ // never throws. A clean no-op in merge mode / push-only propose (no PR).
2006
+ if (approvedVerdict?.review !== undefined) {
2007
+ if (integration.url !== undefined) {
2008
+ const posted = provider.postPRComment({
2009
+ cwd,
2010
+ url: integration.url,
2011
+ body: approvedVerdict.review,
2012
+ env,
2013
+ });
2014
+ note(posted.instruction);
2015
+ } else if (integration.requestOpened) {
2016
+ const posted = provider.postPRCommentOnBranch({
2017
+ cwd,
2018
+ branch,
2019
+ body: approvedVerdict.review,
2020
+ env,
2021
+ });
2022
+ note(posted.instruction);
2023
+ }
2024
+ }
1892
2025
  return {
1893
2026
  outcome: 'completed',
1894
2027
  routedToNeedsAttention: false,
@@ -1931,8 +2064,9 @@ function resolveWorkBranch(
1931
2064
  *
1932
2065
  * Carries the {@link slug} so the autonomous-strand surface in `complete.ts`
1933
2066
  * (which catches this error in `performComplete`'s outer try/catch, OUTSIDE the
1934
- * `runComplete` slug scope) can publish the `in-progress/ needs-attention/`
1935
- * tree-less move without re-deriving the slug from the error message.
2067
+ * `runComplete` slug scope) can mark the item stuck on its per-item lock (post
2068
+ * lock-cutover the tree-less lock amend, no `in-progress/ needs-attention/`
2069
+ * folder move) without re-deriving the slug from the error message.
1936
2070
  */
1937
2071
  export class IntegrationNothingStaged extends Error {
1938
2072
  constructor(
@@ -2113,8 +2247,8 @@ export function composeProposeBody(input: {
2113
2247
  * On a review APPROVE that carries ≥1 NON-BLOCKING finding, write ONE per-run
2114
2248
  * observation `work/notes/observations/review-nits-<slug>-<YYYY-MM-DD>.md` capturing all
2115
2249
  * of this run's non-blocking nits, so they get a durable, contract-native home
2116
- * instead of evaporating (the block path already routes BLOCKING findings to
2117
- * needs-attention/; the approve path dropped non-blocking ones — see
2250
+ * instead of evaporating (the block path already records BLOCKING findings as the
2251
+ * stuck reason on the item's per-item lock; the approve path dropped non-blocking ones — see
2118
2252
  * `work/findings/review-nonblocking-findings-disposition.md`).
2119
2253
  *
2120
2254
  * The RUNNER writes it (the review agent stays write-free). It is a PLAIN
@@ -2322,7 +2456,7 @@ async function stagedCaptureNotes(
2322
2456
  * The DURABLE `work/` status folders a slug's ledger file can resting-live in (the
2323
2457
  * one-slug-one-folder set the invariant is asserted over). After the capstone
2324
2458
  * cut-over (task `cutover-retire-slicing-advancing-markers-and-trim-folder-sets`,
2325
- * prd `ledger-status-per-item-lock-refs`) the ONLY `work/` moves on `main` are the
2459
+ * spec `ledger-status-per-item-lock-refs`) the ONLY `work/` moves on `main` are the
2326
2460
  * durable resting transitions, so the source a build completes FROM is `backlog/`
2327
2461
  * (claim no longer moves the body, task
2328
2462
  * `cutover-claim-body-stays-and-complete-sources-from-backlog`) and the canonical
@@ -2337,7 +2471,7 @@ async function stagedCaptureNotes(
2337
2471
  * The folders {@link readArbiterLedgerPlacement} scans for a slug's source on the
2338
2472
  * arbiter: the durable `LEDGER_STATUS_FOLDERS` (`tasks-ready`/`done`/`cancelled`)
2339
2473
  * PLUS `tasks-backlog` (staging). Staging is included ONLY for the arbiter-side
2340
- * source RESOLUTION of a `--allow-backlog` done-move (prd
2474
+ * source RESOLUTION of a `--allow-backlog` done-move (spec
2341
2475
  * `do-allow-backlog-drive-staged-tasks-without-promotion`) and the one-slug-one-
2342
2476
  * folder guard over the malformed "same slug in `tasks/ready/` AND `tasks/backlog/`"
2343
2477
  * state; it is DELIBERATELY NOT added to the shared `LEDGER_STATUS_FOLDERS` (which
@@ -2384,12 +2518,12 @@ interface ArbiterLedgerPlacement {
2384
2518
  * destination is unambiguous), mirroring the manual `279b542` cleanup.
2385
2519
  *
2386
2520
  * It scans {@link ARBITER_PLACEMENT_FOLDERS} — the durable `LEDGER_STATUS_FOLDERS`
2387
- * PLUS `tasks-backlog`, so a `--allow-backlog` staged drive (prd
2521
+ * PLUS `tasks-backlog`, so a `--allow-backlog` staged drive (spec
2388
2522
  * `do-allow-backlog-drive-staged-tasks-without-promotion`) whose done-move sources
2389
2523
  * from `tasks/backlog/` is DISCOVERED here too (the arbiter is the authority for
2390
2524
  * the actual source folder; the local `source` is the fallback). Including staging
2391
2525
  * also makes the one-slug-one-folder guard cover the malformed "same slug in both
2392
- * `tasks/ready/` and `tasks/backlog/`" state (the prd's decision 5): it FAILS LOUD
2526
+ * `tasks/ready/` and `tasks/backlog/`" state (the spec's decision 5): it FAILS LOUD
2393
2527
  * rather than the resolver silently arbitrating a collision the contract forbids.
2394
2528
  */
2395
2529
  function readArbiterLedgerPlacement(
@@ -2841,8 +2975,8 @@ async function runGate2Review(params: {
2841
2975
  });
2842
2976
  const message = routed.moved
2843
2977
  ? `PR/code review (Gate 2) produced an UNPARSEABLE verdict for '${slug}'; ` +
2844
- 'routed it to work/needs-attention/ (work branch pushed + surfaced; ' +
2845
- 'transient-infra — re-run). NOT integrated.'
2978
+ 'marked it stuck on its per-item lock (work branch pushed + lock ' +
2979
+ 'surfaced; transient-infra — re-run). NOT integrated.'
2846
2980
  : `PR/code review (Gate 2) produced an UNPARSEABLE verdict for '${slug}'; ` +
2847
2981
  'NOT integrating.';
2848
2982
  note(message);
@@ -2888,9 +3022,9 @@ async function runGate2Review(params: {
2888
3022
  note,
2889
3023
  });
2890
3024
  const message = routed.moved
2891
- ? `PR/code review (Gate 2) blocked '${slug}'; routed it to ` +
2892
- 'work/needs-attention/ (surfaced by status; the blocking findings are ' +
2893
- 'recorded in the item body). NOT integrated.'
3025
+ ? `PR/code review (Gate 2) blocked '${slug}'; marked it stuck on its ` +
3026
+ 'per-item lock (surfaced by status; the blocking findings are ' +
3027
+ 'recorded on the lock entry). NOT integrated.'
2894
3028
  : `PR/code review (Gate 2) blocked '${slug}'; NOT integrating.`;
2895
3029
  note(message);
2896
3030
  return {