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
@@ -1,12 +1,12 @@
1
1
  /**
2
- * The `install-ci` CLOSE-JOB capability (prd `runner-in-ci`, task
2
+ * The `install-ci` CLOSE-JOB capability (spec `runner-in-ci`, task
3
3
  * `install-ci-close-job-workflow`; capability E: close issues when their work
4
4
  * lands). This module GENERATES the one fixed workflow file for the close-job and
5
5
  * STRUCTURALLY VALIDATES it, mirroring the snapshot-assertion style of
6
6
  * `advance-lifecycle-template.ts` / `advance-ci-template.ts` (the package depends on
7
7
  * NO YAML lib, so the checks are presence/shape assertions over the raw text).
8
8
  *
9
- * The discipline (from the prd capability-E row + the Out-of-Scope fence):
9
+ * The discipline (from the spec capability-E row + the Out-of-Scope fence):
10
10
  *
11
11
  * - TRIGGER: a MERGE to `main`. There is no native "PR merged" event, so the
12
12
  * workflow uses `push: {branches: [main]}` (NOT `pull_request: closed`): it
@@ -16,7 +16,7 @@
16
16
  * cannot close. (See the `## Decisions` block in the task.)
17
17
  * - The job INVOKES the close machinery via `dorfl close-merged-issues`,
18
18
  * which CONSUMES the UNCHANGED engine pieces: the resolution
19
- * (`resolveClosingIssue`), the "prd complete?" query (`prd-complete-query`,
19
+ * (`resolveClosingIssue`), the "spec complete?" query (`prd-complete-query`,
20
20
  * done), and `IssueProvider.closeIssue`. CI owns ONLY the job + trigger; it
21
21
  * re-implements NONE of those (the Out-of-Scope fence).
22
22
  * - CI runs IN-PLACE (the CI container IS the isolation): no
@@ -54,7 +54,7 @@ export const CLOSE_JOB_WORKFLOW_PATH = 'workflows/close-job.yml';
54
54
  */
55
55
  export function generateCloseJobWorkflow(_config: ResolvedCIConfig): string {
56
56
  return `\
57
- # dorfl — the ISSUE CLOSE-JOB in CI (capability E, prd runner-in-ci).
57
+ # dorfl — the ISSUE CLOSE-JOB in CI (capability E, spec runner-in-ci).
58
58
  # EMITTED by \`dorfl install-ci\`; the human commits it. DO NOT hand-edit a
59
59
  # copy — re-run install-ci to upgrade the shell.
60
60
  #
@@ -69,9 +69,9 @@ export function generateCloseJobWorkflow(_config: ResolvedCIConfig): string {
69
69
  # the landed work closes and closes them. CI owns ONLY this job + the trigger; the
70
70
  # command CONSUMES the engine's UNCHANGED pieces and re-implements none of them:
71
71
  # * the RESOLUTION (resolveClosingIssue): a lone task closes its own \`issue:\`;
72
- # a fanned task reaches the number via \`task.prd: → prd issue:\`.
73
- # * the "prd complete?" QUERY (prd-complete-query, done): a prd's issue closes
74
- # ONLY when ALL its \`prd:<slug>\` tasks are in work/done/.
72
+ # a fanned task reaches the number via \`task.spec: → spec issue:\`.
73
+ # * the "spec complete?" QUERY (prd-complete-query, done): a spec's issue closes
74
+ # ONLY when ALL its \`spec:<slug>\` tasks are in work/done/.
75
75
  # * the CLOSE (IssueProvider.closeIssue): the atomic comment+close seam — NO
76
76
  # direct \`gh\` in the engine core; any comment rides this close, never the PR
77
77
  # comment seam.
@@ -110,14 +110,14 @@ jobs:
110
110
  close-merged-issues:
111
111
  runs-on: ubuntu-latest
112
112
  steps:
113
- - uses: actions/checkout@v4
113
+ - uses: actions/checkout@v5
114
114
  with:
115
115
  fetch-depth: 0
116
116
  - uses: ./.github/actions/dorfl-setup
117
117
  - name: close issues whose work has landed on main
118
118
  # In-place in this checkout (no --isolated/--remote): the CI container IS
119
119
  # the isolation. Resolves the closing issue(s) from the work/ tree, runs
120
- # the "prd complete?" query for the prd case, and closes via the provider
120
+ # the "spec complete?" query for the spec case, and closes via the provider
121
121
  # seam — all UNCHANGED engine pieces, consumed not re-built.
122
122
  env:
123
123
  GH_TOKEN: \${{ secrets.GITHUB_TOKEN }}
package/src/close-job.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  /**
2
- * The CI CLOSE-JOB driver (prd `runner-in-ci`, capability E; task
2
+ * The CI CLOSE-JOB driver (spec `runner-in-ci`, capability E; task
3
3
  * `install-ci-close-job-workflow`). When work lands on `main`, this resolves which
4
4
  * source issue(s) the landed work closes and closes them — but it OWNS none of the
5
5
  * machinery it relies on. It is the thin JOB that WIRES three UNCHANGED engine
6
6
  * pieces together (the Out-of-Scope fence: do NOT re-build them):
7
7
  *
8
8
  * - the RESOLUTION — {@link resolveClosingIssue} (`frontmatter.ts`): an artifact
9
- * uses `issue:` XOR `prd:`; a lone task closes its own `issue:` directly, a
10
- * fanned task reaches the number via `task.prd: → work/prds/<prd>.md prd
11
- * issue:`, and `prd:` WINS on a (hand-edited) conflict;
9
+ * uses `issue:` XOR `spec:`; a lone task closes its own `issue:` directly, a
10
+ * fanned task reaches the number via `task.spec: → work/specs/<spec>.md spec
11
+ * issue:`, and `spec:` WINS on a (hand-edited) conflict;
12
12
  * - the QUERY — {@link isSpecComplete} (`spec-complete.ts`, task
13
13
  * `prd-complete-query`, done): a spec is COMPLETE iff ≥1 `spec:<slug>` task AND
14
14
  * all such tasks are in `work/done/`;
@@ -19,12 +19,12 @@
19
19
  *
20
20
  * The closure conditions, per artifact kind:
21
21
  *
22
- * - a **lone task** (`issue:`, no `prd:`) that resides in `work/done/` — its PR
22
+ * - a **lone task** (`issue:`, no `spec:`) that resides in `work/done/` — its PR
23
23
  * merged, so its own issue closes (reason `completed`);
24
- * - a **prd** (`issue:`) — closes ONLY when {@link isSpecComplete} says ALL its
24
+ * - a **spec** (`issue:`) — closes ONLY when {@link isSpecComplete} says ALL its
25
25
  * `spec:<slug>` tasks are in `work/done/` (reason `completed`).
26
26
  *
27
- * A prd whose query is NOT yet complete is left OPEN (the final fanned task's
27
+ * A spec whose query is NOT yet complete is left OPEN (the final fanned task's
28
28
  * merge tick closes it). A lone task still outside `work/done/` is skipped. The
29
29
  * close DEGRADES (never throws) on a missing/unauthenticated provider, exactly
30
30
  * like intake's bounce close — the run reports the real cause and stays exit-0.
@@ -62,7 +62,7 @@ const SPEC_LIFECYCLE_FOLDERS = SPEC_FOLDERS;
62
62
  /** Why the close-job acted (or did not act) on a candidate issue. */
63
63
  export type CloseDecision =
64
64
  | 'closed' // the issue was closed via the provider seam
65
- | 'not-complete' // a prd whose query says it is not yet complete → left open
65
+ | 'not-complete' // a spec whose query says it is not yet complete → left open
66
66
  | 'not-landed' // a lone task not yet in work/done/ → left open
67
67
  | 'close-failed'; // closure condition held but the provider close degraded
68
68
 
@@ -111,9 +111,9 @@ function listMarkdown(repoPath: string, folder: WorkFolderKey): string[] {
111
111
  }
112
112
 
113
113
  /**
114
- * Read a prd's `issue:` number by slug, scanning the prd folders. Returns
115
- * `undefined` when no prd with that slug carries an `issue:` (a prd with no source
116
- * issue, or a typo'd `prd:` hop — degrades to "no issue to close", never crashes).
114
+ * Read a spec's `issue:` number by slug, scanning the spec folders. Returns
115
+ * `undefined` when no spec with that slug carries an `issue:` (a spec with no source
116
+ * issue, or a typo'd `spec:` hop — degrades to "no issue to close", never crashes).
117
117
  */
118
118
  function specIssueNumber(
119
119
  repoPath: string,
@@ -137,14 +137,14 @@ function specIssueNumber(
137
137
  * Resolve the DEDUPLICATED set of closure candidates from the `work/` tree, each
138
138
  * via the UNCHANGED {@link resolveClosingIssue}:
139
139
  *
140
- * - every prd carrying `issue:` (in `work/prds/ready/` or `work/prds/tasked/`) is a
141
- * prd-kind candidate keyed on its own `prd:` query;
142
- * - every LONE task (`issue:` and NO `prd:`) is an `issue`-kind candidate.
140
+ * - every spec carrying `issue:` (in `work/specs/ready/` or `work/specs/tasked/`) is a
141
+ * spec-kind candidate keyed on its own `spec:` query;
142
+ * - every LONE task (`issue:` and NO `spec:`) is an `issue`-kind candidate.
143
143
  *
144
- * A fanned task carries `prd:` (NOT its own `issue:`), so it reaches the number
145
- * through its prd's candidate, never as its own — the issue number lives ONLY on
146
- * the prd. Deduplicated by issue number: a prd enumerated once even though many
147
- * tasks point at it. Prd candidates are listed before lone-task candidates, each
144
+ * A fanned task carries `spec:` (NOT its own `issue:`), so it reaches the number
145
+ * through its spec's candidate, never as its own — the issue number lives ONLY on
146
+ * the spec. Deduplicated by issue number: a spec enumerated once even though many
147
+ * tasks point at it. Spec candidates are listed before lone-task candidates, each
148
148
  * group slug-sorted, for a deterministic log.
149
149
  */
150
150
  function resolveCandidates(repoPath: string): {
@@ -165,9 +165,9 @@ function resolveCandidates(repoPath: string): {
165
165
  );
166
166
  const slug = fm.slug ?? basename(file, '.md');
167
167
  const closing = resolveClosingIssue(fm);
168
- // A prd's own closing link is its `issue:` (a prd has no `prd:`); on the
169
- // hand-edit conflict `prd:` wins via resolveClosingIssue, so only a true
170
- // `issue:`-bearing prd becomes a candidate here.
168
+ // A spec's own closing link is its `issue:` (a spec has no `spec:`); on the
169
+ // hand-edit conflict `spec:` wins via resolveClosingIssue, so only a true
170
+ // `issue:`-bearing spec becomes a candidate here.
171
171
  if (closing?.via === 'issue' && !seen.has(closing.issue)) {
172
172
  seen.add(closing.issue);
173
173
  specCandidates.push({issueNumber: closing.issue, via: 'spec', slug});
@@ -175,7 +175,7 @@ function resolveCandidates(repoPath: string): {
175
175
  }
176
176
  }
177
177
 
178
- // Lone-task candidates: a task with `issue:` and NO `prd:` closes its OWN
178
+ // Lone-task candidates: a task with `issue:` and NO `spec:` closes its OWN
179
179
  // issue directly when it lands in work/done/.
180
180
  for (const folder of TASK_FOLDERS) {
181
181
  for (const file of listMarkdown(repoPath, folder)) {
@@ -184,9 +184,9 @@ function resolveCandidates(repoPath: string): {
184
184
  );
185
185
  const slug = fm.slug ?? basename(file, '.md');
186
186
  const closing = resolveClosingIssue(fm);
187
- // `resolveClosingIssue` returns `via: 'issue'` ONLY when there is no `prd:`
188
- // (prd wins on conflict), so a fanned task never lands here — it reaches
189
- // its issue through the prd candidate above.
187
+ // `resolveClosingIssue` returns `via: 'issue'` ONLY when there is no `spec:`
188
+ // (spec wins on conflict), so a fanned task never lands here — it reaches
189
+ // its issue through the spec candidate above.
190
190
  if (closing?.via === 'issue' && !seen.has(closing.issue)) {
191
191
  seen.add(closing.issue);
192
192
  taskCandidates.push({issueNumber: closing.issue, via: 'issue', slug});
@@ -222,7 +222,7 @@ function closeComment(via: 'issue' | 'spec', slug: string): string {
222
222
 
223
223
  /**
224
224
  * Run the close-job over a repo's `work/` tree: resolve the closure candidates,
225
- * apply the per-kind closure condition (a landed lone task; a prd whose
225
+ * apply the per-kind closure condition (a landed lone task; a spec whose
226
226
  * {@link isSpecComplete} query holds), and close the qualifying issues through the
227
227
  * {@link IssueProvider.closeIssue} seam (reason `completed`, an informational
228
228
  * comment riding the SAME atomic close). REUSES the unchanged resolution + query +
package/src/complete.ts CHANGED
@@ -13,6 +13,8 @@ import {
13
13
  import {ledgerWrite} from './ledger-write.js';
14
14
  import {releaseItemLock} from './item-lock.js';
15
15
  import {workBranchRef, parseWorkBranchRef} from './slug-namespace.js';
16
+ import {isProvablyMergedForReap} from './gc.js';
17
+ import type {SidecarType} from './sidecar.js';
16
18
  import type {ReviewProvider} from './integrator.js';
17
19
  import type {IntegrationMode} from './config.js';
18
20
  import {runAsync, localMainAheadCount, type RunResult} from './git.js';
@@ -160,7 +162,7 @@ export interface CompleteOptions {
160
162
  */
161
163
  freshWorktreeGate?: boolean;
162
164
  /**
163
- * **The cross-job merge-serialiser CAS-retry cap** (config `mergeRetries`, prd
165
+ * **The cross-job merge-serialiser CAS-retry cap** (config `mergeRetries`, spec
164
166
  * `land-time-reverify-and-parallel-merge-ceiling` Story 5 / Applied Answer q1
165
167
  * (a)). Threaded verbatim into {@link performIntegration} as `mergeRetries` so
166
168
  * the resolved per-repo value controls how many re-rebase-and-retry attempts
@@ -172,7 +174,7 @@ export interface CompleteOptions {
172
174
  /** Skip the acceptance gate (human-only escape hatch; never used unattended). */
173
175
  skipVerify?: boolean;
174
176
  /**
175
- * **`--allow-backlog`** (prd
177
+ * **`--allow-backlog`** (spec
176
178
  * `do-allow-backlog-drive-staged-tasks-without-promotion`): TREAT a
177
179
  * `tasks/backlog/`-resident body (staging) as a VALID build source, so a
178
180
  * staged task driven in place done-moves `tasks/backlog/ → tasks/done/`
@@ -185,7 +187,7 @@ export interface CompleteOptions {
185
187
  */
186
188
  allowBacklog?: boolean;
187
189
  /**
188
- * **Gate 2 — the PR/code review gate** (GATES prd `work/prds/tasked/review.md`). When
190
+ * **Gate 2 — the PR/code review gate** (GATES spec `work/specs/tasked/review.md`). When
189
191
  * `true`, after the green `verify` and BEFORE the done-move, run the `review`
190
192
  * SKILL as a FRESH-CONTEXT agent (its own harness launch) and route its verdict:
191
193
  * `approve` → proceed to done-move/commit/integrate; `block` → route to
@@ -315,9 +317,12 @@ export interface CompleteResult {
315
317
  outcome: CompleteOutcome;
316
318
  /**
317
319
  * True iff a FAILURE outcome (gate-failed / rebase-conflict) was routed to
318
- * `work/needs-attention/` via the shared mechanism (ADR §12), rather than left
319
- * dangling. Undefined/false on the success, `--skip-verify`, refused, and
320
- * usage-error paths (none of which move the item to needs-attention).
320
+ * the shared needs-attention mechanism (ADR §12) post lock-cutover, the
321
+ * per-item lock is amended to `state: stuck` with the reason recorded on the
322
+ * lock entry (there is no `work/needs-attention/` folder write anymore),
323
+ * rather than the item being left dangling. Undefined/false on the success,
324
+ * `--skip-verify`, refused, and usage-error paths (none of which mark the
325
+ * item stuck).
321
326
  */
322
327
  routedToNeedsAttention?: boolean;
323
328
  /** The work branch that was completed, when one was resolved. */
@@ -417,7 +422,7 @@ export async function performComplete(
417
422
  return await runComplete(options, note);
418
423
  } catch (err) {
419
424
  // AUTONOMOUS-STRAND SURFACE (task
420
- // `autonomous-integration-refusal-surfaces-not-strands-in-progress`, prd
425
+ // `autonomous-integration-refusal-surfaces-not-strands-in-progress`, spec
421
426
  // `ledger-integrity` story 7). On the AUTONOMOUS path (`surfaceArbiter` set
422
427
  // — the human-vs-autonomous gate the core's other failures use), a SOURCE-
423
428
  // STRAND `CompleteRefusal` (the slug-is-stuck `nothing to complete`) and the
@@ -489,13 +494,11 @@ function strandRefusalSlug(err: unknown): string | undefined {
489
494
  }
490
495
 
491
496
  /**
492
- * Surface an autonomous-path strand refusal to `needs-attention/` on the
493
- * arbiter via the TREE-LESS seam ({@link
494
- * ledgerWrite.applyTreelessNeedsAttentionTransition}). The mechanism is the
495
- * one `requeue`/`continue` already use in reverse: fetch `<arbiter>/main`,
496
- * resolve the slug's actual current folder ON THE ARBITER (arbiter-is-truth),
497
- * build the one-file `work/<src>/<slug>.md → work/needs-attention/<slug>.md`
498
- * move on a scratch index, and CAS-publish it. It NEVER touches the caller's
497
+ * Surface an autonomous-path strand refusal via the TREE-LESS seam ({@link
498
+ * ledgerWrite.applyTreelessNeedsAttentionTransition}). Post lock-cutover the
499
+ * seam is a pure LOCK AMEND — the item's per-item lock is moved to
500
+ * `state: stuck` with the reason on the lock entry; no folder move, no
501
+ * `work/needs-attention/` write. It NEVER touches the caller's
499
502
  * working tree / HEAD / index — important here because the refusal was raised
500
503
  * precisely because the working tree does NOT hold an `.md` to `git mv`. It is
501
504
  * idempotent (a re-surface of an already-surfaced slug is a no-op) and reports
@@ -523,11 +526,13 @@ async function surfaceAutonomousStrand(params: {
523
526
  });
524
527
  if (surfaced.moved) {
525
528
  const message =
526
- `'${slug}' refused (${reason}); surfaced to work/needs-attention/ on ` +
527
- `${arbiter}/main so the next autonomous tick does NOT re-claim it.`;
529
+ `'${slug}' refused (${reason}); surfaced on ${arbiter}/main as a stuck ` +
530
+ 'question (needsAnswers) so the next autonomous tick does NOT re-claim it.';
528
531
  note(message);
532
+ // PR-2b D3: a clean surface is GREEN (exitCode 0). The autonomous strand
533
+ // surface is one of the cleanly-surfaced bounce sites this policy applies to.
529
534
  return {
530
- exitCode: 1,
535
+ exitCode: 0,
531
536
  outcome: 'strand-surfaced',
532
537
  routedToNeedsAttention: true,
533
538
  message,
@@ -633,7 +638,7 @@ async function runComplete(
633
638
  );
634
639
  }
635
640
  // The branch HEAD is on when it IS a work branch for this slug (so an explicit
636
- // `prd:`-style recovery still completes the branch it is standing on); else
641
+ // `spec:`-style recovery still completes the branch it is standing on); else
637
642
  // synthesise the task branch.
638
643
  const branch =
639
644
  headParsed && headParsed.slug === slug
@@ -668,15 +673,17 @@ async function runComplete(
668
673
  // removes it from THERE, so the move can never disagree with what the arbiter
669
674
  // holds even when the local tree diverges (ledger-integrity defect 1). The
670
675
  // `source` we pass is the arbiter-content fallback for the degenerate "arbiter
671
- // holds nothing" case, not the authority. `in-progress/` is RETAINED below for
672
- // the legacy/bounce surfaces that may still source from it until its folder
673
- // removal (9c, OUT of this task's scope).
676
+ // holds nothing" case, not the authority. The legacy `in-progress/` FOLDER PROBE
677
+ // is GONE (task `finish-in-progress-folder-cutover-remove-legacy-recovery-readers`):
678
+ // the per-item-lock cutover moved claim OFF writing `work/in-progress/` (the body
679
+ // rests in `tasks/backlog/`, liveness is the held lock), so nothing writes that
680
+ // folder anymore and the `existsSync(inProgress)` arm could not fire. Liveness is
681
+ // the lock, not the folder.
674
682
  const backlog = workItemPath(cwd, 'tasks-ready', slug);
675
683
  const staged = workItemPath(cwd, 'tasks-backlog', slug);
676
- const inProgress = workItemPath(cwd, 'in-progress', slug);
677
684
  const done = workItemPath(cwd, 'done', slug);
678
685
  const onBacklog = existsSync(backlog);
679
- // `--allow-backlog` drive (prd
686
+ // `--allow-backlog` drive (spec
680
687
  // `do-allow-backlog-drive-staged-tasks-without-promotion`): a staged task driven
681
688
  // in place RESTS in `tasks/backlog/` (claim never moved it). Detect it as a build
682
689
  // source so the done-move goes `tasks/backlog/ → tasks/done/` DIRECTLY (the
@@ -686,7 +693,6 @@ async function runComplete(
686
693
  // strand `complete` must REFUSE (the honest "not finished, not done" position),
687
694
  // NOT silently integrate — only the deliberate drive promotes from staging.
688
695
  const onPreBacklog = options.allowBacklog === true && existsSync(staged);
689
- const onInProgress = existsSync(inProgress);
690
696
  // SELF-RENAMING FOLDER task backstop: the binary-known `work/done/<slug>.md`,
691
697
  // OR — when none of the binary-known ledger folders hold the record — the slug
692
698
  // at a RENAMED done-position the migration agent placed it in (e.g.
@@ -695,13 +701,10 @@ async function runComplete(
695
701
  // resolution is byte-for-byte unchanged.
696
702
  const onDone =
697
703
  existsSync(done) ||
698
- (!onBacklog &&
699
- !onPreBacklog &&
700
- !onInProgress &&
701
- recordAtRenamedDonePosition(cwd, slug));
702
- // STRANDED-DONE AUTO-RECOVER (prd `ledger-integrity` story 6, the autonomous
703
- // half of `finish-already-committed-branch`). When neither in-progress/ nor
704
- // needs-attention/ holds the slug on the BRANCH tree BUT done/ does, the work
704
+ (!onBacklog && !onPreBacklog && recordAtRenamedDonePosition(cwd, slug));
705
+ // STRANDED-DONE AUTO-RECOVER (spec `ledger-integrity` story 6, the autonomous
706
+ // half of `finish-already-committed-branch`). When the pool/staging does NOT
707
+ // hold the slug on the BRANCH tree BUT done/ does, the work
705
708
  // branch was already built + done-moved + committed by a prior run that never
706
709
  // landed on the arbiter (a terminal push failed, or the PR never merged). The
707
710
  // autonomous `do`/`advance`/plain-`complete` path used to refuse this with
@@ -713,8 +716,7 @@ async function runComplete(
713
716
  // `<arbiter>/main` returns `already-integrated` (clean no-op, NEVER a
714
717
  // re-push/double-integrate). Mutually exclusive with the build-path source +
715
718
  // `recovering` flags — the core ignores them when `committedRecovery` is set.
716
- const folderShapeStranded =
717
- !onBacklog && !onPreBacklog && !onInProgress && onDone;
719
+ const folderShapeStranded = !onBacklog && !onPreBacklog && onDone;
718
720
  // DIRTY-CONTINUE GATE (task `recover-autodetect-gated-on-nothing-to-commit`).
719
721
  // The folder-shape stranded-done auto-detect is necessary but NOT sufficient on
720
722
  // a CONTINUE: a requeued task whose prior attempt already done-moved the slug
@@ -749,24 +751,19 @@ async function runComplete(
749
751
  // "nothing to complete" CompleteRefusal). We default `source` to `'tasks-ready'`
750
752
  // so `sourcePath` resolves to the canonical pool path the refusal message
751
753
  // names; the refusal fires because that file does not exist on disk.
752
- const source: 'tasks-ready' | 'tasks-backlog' | 'in-progress' | 'done' =
753
- dirtyContinue
754
- ? 'done'
755
- : onBacklog
756
- ? 'tasks-ready'
757
- : onInProgress
758
- ? 'in-progress'
759
- : onPreBacklog
760
- ? 'tasks-backlog'
761
- : 'tasks-ready';
754
+ const source: 'tasks-ready' | 'tasks-backlog' | 'done' = dirtyContinue
755
+ ? 'done'
756
+ : onBacklog
757
+ ? 'tasks-ready'
758
+ : onPreBacklog
759
+ ? 'tasks-backlog'
760
+ : 'tasks-ready';
762
761
  const sourcePath =
763
762
  source === 'tasks-ready'
764
763
  ? backlog
765
764
  : source === 'tasks-backlog'
766
765
  ? staged
767
- : source === 'in-progress'
768
- ? inProgress
769
- : done;
766
+ : done;
770
767
  if (dirtyContinue) {
771
768
  // Announce LOUDLY (parallel to the `committedRecovery` recovery note above):
772
769
  // the autonomous integrate path took the CONTINUE-BUILD branch, not the
@@ -892,7 +889,7 @@ async function runComplete(
892
889
  freshWorktreeGate: options.freshWorktreeGate,
893
890
  // The cross-job merge-serialiser CAS-retry cap (config `mergeRetries`) — the
894
891
  // git-alone FLOOR of the cross-job land-queue, resolved through the gate-family
895
- // precedence chain (prd `land-time-reverify-and-parallel-merge-ceiling` Story
892
+ // precedence chain (spec `land-time-reverify-and-parallel-merge-ceiling` Story
896
893
  // 5). Threaded so a wide-matrix CI's raised cap actually reaches the merge loop.
897
894
  mergeRetries: options.mergeRetries,
898
895
  skipVerify: options.skipVerify,
@@ -924,9 +921,19 @@ async function runComplete(
924
921
 
925
922
  // The FAILURE outcomes map 1:1 onto `complete`'s — the core already note()'d
926
923
  // the reason and did any routing; the tail never runs for them.
924
+ // PR-2b exit-code policy (spec
925
+ // `surface-stuck-as-questions-and-retire-stuck-lock-state`, decision #4 / D3):
926
+ // a cleanly-surfaced bounce is GREEN (`exitCode: 0`) iff its surface transition
927
+ // SUCCEEDED (`routedToNeedsAttention: true`); a FAILED surface stays non-zero
928
+ // (retry/resolve). Applies to `prepare-failed`/`gate-failed`/`review-blocked`/
929
+ // `review-unparseable`/`rebase-conflict`. The empty-diff backstop is owned by
930
+ // task `empty-diff-bounce-surfaces-dispose-defaulted-question` and is NOT
931
+ // reached here.
932
+ const surfaceExit = (routed: boolean | undefined): 0 | 1 =>
933
+ routed === true ? 0 : 1;
927
934
  if (core.outcome === 'prepare-failed') {
928
935
  return {
929
- exitCode: 1,
936
+ exitCode: surfaceExit(core.routedToNeedsAttention),
930
937
  outcome: 'prepare-failed',
931
938
  routedToNeedsAttention: core.routedToNeedsAttention,
932
939
  branch: core.branch,
@@ -935,7 +942,7 @@ async function runComplete(
935
942
  }
936
943
  if (core.outcome === 'gate-failed') {
937
944
  return {
938
- exitCode: 1,
945
+ exitCode: surfaceExit(core.routedToNeedsAttention),
939
946
  outcome: 'gate-failed',
940
947
  routedToNeedsAttention: core.routedToNeedsAttention,
941
948
  branch: core.branch,
@@ -944,7 +951,7 @@ async function runComplete(
944
951
  }
945
952
  if (core.outcome === 'review-blocked') {
946
953
  return {
947
- exitCode: 1,
954
+ exitCode: surfaceExit(core.routedToNeedsAttention),
948
955
  outcome: 'review-blocked',
949
956
  routedToNeedsAttention: core.routedToNeedsAttention,
950
957
  branch: core.branch,
@@ -958,7 +965,7 @@ async function runComplete(
958
965
  // `do`/`run` tail re-labels its cause `transient-infra` (NOT a reviewer block) off
959
966
  // the parse-failure phrase in `core.reason`.
960
967
  return {
961
- exitCode: 1,
968
+ exitCode: surfaceExit(core.routedToNeedsAttention),
962
969
  outcome: 'review-unparseable',
963
970
  routedToNeedsAttention: core.routedToNeedsAttention,
964
971
  branch: core.branch,
@@ -967,7 +974,7 @@ async function runComplete(
967
974
  }
968
975
  if (core.outcome === 'rebase-conflict') {
969
976
  return {
970
- exitCode: 1,
977
+ exitCode: surfaceExit(core.routedToNeedsAttention),
971
978
  outcome: 'rebase-conflict',
972
979
  routedToNeedsAttention: core.routedToNeedsAttention,
973
980
  branch: core.branch,
@@ -983,7 +990,7 @@ async function runComplete(
983
990
  // because the work is already integrated and the branch may or may not
984
991
  // still exist locally.
985
992
  //
986
- // CROSS-SUBSTRATE RELEASE (prd `ledger-status-per-item-lock-refs` US #9/#10;
993
+ // CROSS-SUBSTRATE RELEASE (spec `ledger-status-per-item-lock-refs` US #9/#10;
987
994
  // task `complete-lock-then-durable-main-move-crash-safe`): the durable
988
995
  // `main` record is already terminal (the kept tip is provably on
989
996
  // `<arbiter>/main`), so the per-item lock claim took is now stale: release it
@@ -1021,7 +1028,7 @@ async function runComplete(
1021
1028
  const commitMessage = core.commitMessage;
1022
1029
  const mode = result.mode;
1023
1030
 
1024
- // CROSS-SUBSTRATE RELEASE, gated on the work being DURABLY ON `main` (prd
1031
+ // CROSS-SUBSTRATE RELEASE, gated on the work being DURABLY ON `main` (spec
1025
1032
  // `ledger-status-per-item-lock-refs` US #9/#10; ADR
1026
1033
  // `ledger-status-on-per-item-lock-refs`; the trail's Amendment 6; task
1027
1034
  // `complete-lock-then-durable-main-move-crash-safe`). ORDER MATTERS: the
@@ -1120,6 +1127,43 @@ async function runComplete(
1120
1127
  // ONE thing the human must act on, so it is emitted as a visually-distinct
1121
1128
  // block (blank lines + heading + TTY-aware color) ON TOP of the plain summary
1122
1129
  // note below — cosmetic only; the structured result is unchanged.
1130
+ //
1131
+ // BENIGN ALREADY-LANDED RACE TAIL (task `propose-push-survives-stale-lease-
1132
+ // on-reaped-work-ref`, follow-up
1133
+ // `complete-propose-honour-already-landed-and-rename-continue-branch-module`):
1134
+ // when the integrator's propose push observed a REAPED `work/<slug>` ref AND
1135
+ // the work was provably on `<arbiter>/main`, it returns `alreadyLanded: true`
1136
+ // with a custom `instruction`. In that case NOTHING was pushed and there is
1137
+ // NO ref for a PR to point at, so emitting the generic
1138
+ // `formatProposeNextStep` push+PR block ("Pushed ... Open a PR/MR ...") would
1139
+ // misreport a clean no-op as unfinished work. Surface the integrator's
1140
+ // `instruction` VERBATIM instead — it is already the correct clean-no-op
1141
+ // prose (the CI-dominant recovery path via `performIntegration` already does
1142
+ // the same; this is the sibling `complete.ts` caller's honest report). The
1143
+ // tail (switch-to-main / delete-local-branch / `--no-switch`) is UNCHANGED
1144
+ // — only the emitted next-step + summary text differ.
1145
+ if (result.alreadyLanded === true) {
1146
+ const instruction =
1147
+ result.instruction ??
1148
+ `${branch}: already on ${arbiter}/main (clean no-op).`;
1149
+ const tail = options.noSwitch
1150
+ ? `; left on ${branch} (--no-switch).`
1151
+ : deletedLocalBranch
1152
+ ? `; switched to main and deleted ${branch}.`
1153
+ : '; switched to main.';
1154
+ const message = `Completed '${slug}': ${instruction}${tail}`;
1155
+ note(message);
1156
+ return {
1157
+ exitCode: 0,
1158
+ outcome: 'completed',
1159
+ branch,
1160
+ commitMessage,
1161
+ mergedToMain: false,
1162
+ switchedTo,
1163
+ deletedLocalBranch,
1164
+ message,
1165
+ };
1166
+ }
1123
1167
  const color = options.color ?? shouldUseColor(process.stdout);
1124
1168
  const noteBlock = options.noteBlock ?? note;
1125
1169
  noteBlock(
@@ -1158,7 +1202,7 @@ async function runComplete(
1158
1202
  /**
1159
1203
  * Release the per-item lock `claim` ALSO acquired (`action: implement`, keyed
1160
1204
  * `task:<slug>`) AFTER the durable `main` move has landed — the SECOND, lock-
1161
- * release half of complete's cross-substrate ordering (prd
1205
+ * release half of complete's cross-substrate ordering (spec
1162
1206
  * `ledger-status-per-item-lock-refs` US #9/#10; task
1163
1207
  * `complete-lock-then-durable-main-move-crash-safe`).
1164
1208
  *
@@ -1316,15 +1360,29 @@ export async function isLocalBranchProvablyOnArbiter(
1316
1360
  // Refresh remote-tracking refs against the live arbiter (best-effort).
1317
1361
  await gitSoft(['fetch', '--quiet', arbiter], cwd, env);
1318
1362
 
1319
- // Merged: tip is an ancestor of <arbiter>/main.
1363
+ // Merged: the tip is provably on <arbiter>/main — fast-path ancestor OR
1364
+ // squash-aware fallback (durable done/dropped record on main + branch
1365
+ // carries nothing main lacks). The SAME predicate `gc.ts`'s worktree reaper
1366
+ // and `reap-branches.ts`'s remote sweep use — do not fork it.
1367
+ const parsed = parseWorkBranchRef(branch);
1368
+ const arbiterMainRef = `${arbiter}/main`;
1320
1369
  const merged =
1321
- (
1322
- await gitSoft(
1323
- ['merge-base', '--is-ancestor', localTip, `${arbiter}/main`],
1324
- cwd,
1325
- env,
1326
- )
1327
- ).status === 0;
1370
+ parsed === undefined
1371
+ ? (
1372
+ await gitSoft(
1373
+ ['merge-base', '--is-ancestor', localTip, arbiterMainRef],
1374
+ cwd,
1375
+ env,
1376
+ )
1377
+ ).status === 0
1378
+ : isProvablyMergedForReap({
1379
+ cwd,
1380
+ tip: localTip,
1381
+ arbiterMain: arbiterMainRef,
1382
+ namespace: parsed.namespace as SidecarType,
1383
+ slug: parsed.slug,
1384
+ env,
1385
+ });
1328
1386
  if (merged) {
1329
1387
  return true;
1330
1388
  }
@@ -49,7 +49,7 @@ export interface RunConcurrentOptions<I, T> {
49
49
  /**
50
50
  * A per-key async serialiser: `withKeyedLock(key, fn)` runs `fn` to completion
51
51
  * before the next caller for the SAME key starts; different keys never block each
52
- * other. Used to serialise the prd, shared-working-tree CLAIM step PER REPO
52
+ * other. Used to serialise the spec, shared-working-tree CLAIM step PER REPO
53
53
  * inside the otherwise-concurrent tick.
54
54
  *
55
55
  * Two concurrent claims in ONE repo would prepare their claim micro-commit in the