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
@@ -9,6 +9,7 @@ import type {IntegrationMode} from './config.js';
9
9
  import {
10
10
  routeToNeedsAttention,
11
11
  returnToBacklog,
12
+ surfaceStuckToNeedsAttention,
12
13
  type RouteToNeedsAttentionOptions,
13
14
  type RouteToNeedsAttentionResult,
14
15
  type ReturnToBacklogOptions,
@@ -17,11 +18,7 @@ import {
17
18
  type SurfaceToNeedsAttentionResult,
18
19
  type BranchPushOutcome,
19
20
  } from './needs-attention.js';
20
- import {
21
- markStuckItemLock,
22
- resumeItemLock,
23
- type TransitionOutcome,
24
- } from './item-lock.js';
21
+ import type {NewQuestion} from './sidecar.js';
25
22
 
26
23
  /**
27
24
  * The **write half** of the ledger-transition seam (ADR
@@ -89,9 +86,9 @@ export type LedgerTransitionKind =
89
86
  | 'tasking'
90
87
  | 'advancing'
91
88
  /**
92
- * The **promote** transition (prd `staging-pool-position-gate-and-trust-model`,
89
+ * The **promote** transition (spec `staging-pool-position-gate-and-trust-model`,
93
90
  * task `pre-backlog-staging-folder-and-promote-step-a`): move a STAGED task
94
- * `work/pre-backlog/<slug>.md → work/backlog/<slug>.md` to enter the
91
+ * `work/tasks/backlog/<slug>.md → work/tasks/ready/<slug>.md` to enter the
95
92
  * agent-eligible pool. A durable `main` move, the same category as `requeue`
96
93
  * (tree-less CAS via {@link applyTransition}). RUNNER/human-owned — no
97
94
  * agent-facing path performs it (governing ADR
@@ -158,14 +155,15 @@ export interface ApplyCompleteTransitionInput {
158
155
  export type ApplyCompleteTransitionResult = IntegrateResult;
159
156
 
160
157
  /**
161
- * A *prepared* NEEDS-ATTENTION transition the caller asks the seam to apply: a
162
- * stuck claimed item to bounce to `work/needs-attention/` with its reason. Like
163
- * the other inputs it is storage-agnostic — it names the slug, the reason prose,
164
- * any surfaced questions, and an OPTIONAL arbiter to also push the branch to,
165
- * NOT *where* the move commits/publishes (the sole strategy decides that: a
166
- * `git mv` from whichever of in-progress/ or done/ holds the item, the
167
- * reason-in-the-body, the ONE atomic commit, the optional branch push). This
168
- * mirrors {@link RouteToNeedsAttentionOptions} so the move mechanism is unchanged.
158
+ * A *prepared* NEEDS-ATTENTION transition the caller asks the seam to apply:
159
+ * mark a stuck claimed item on its per-item lock with the reason. Like the
160
+ * other inputs it is storage-agnostic — it names the slug, the reason prose,
161
+ * any surfaced questions, and an OPTIONAL arbiter to also push the work branch
162
+ * to, NOT *where* the surface commits/publishes (the sole strategy decides
163
+ * that: post lock-cutover, a lock amend to `state: stuck` with the reason on
164
+ * the lock entry — no `work/needs-attention/` folder write plus the optional
165
+ * branch push). This mirrors {@link RouteToNeedsAttentionOptions} so the
166
+ * mechanism stays unchanged.
169
167
  */
170
168
  export type ApplyNeedsAttentionTransitionInput = RouteToNeedsAttentionOptions;
171
169
 
@@ -174,16 +172,17 @@ export type ApplyNeedsAttentionTransitionInput = RouteToNeedsAttentionOptions;
174
172
  * move result the folder-native mechanism produces. The RECOVERABLE branch push
175
173
  * outcome rides on `branchPush` (the caller reads it rather than assuming
176
174
  * "pushed" off the local move). The OBSERVABLE half is now the per-item lock
177
- * `state: stuck` amend (prd `ledger-status-per-item-lock-refs`); there is no
175
+ * `state: stuck` amend (spec `ledger-status-per-item-lock-refs`); there is no
178
176
  * separate on-`main` surface outcome to report.
179
177
  */
180
178
  export type ApplyNeedsAttentionTransitionResult = RouteToNeedsAttentionResult;
181
179
 
182
180
  /**
183
181
  * A *prepared* RETURN-TO-BACKLOG transition: re-queue a STUCK item so it can be
184
- * re-claimed — recovered from EITHER `needs-attention/` (the resolved-surface
185
- * path) OR `in-progress/` (a claim that never surfaced), the slug's actual
186
- * current folder resolved on the arbiter and moved to `backlog/`.
182
+ * re-claimed — recovered via its per-item lock on the arbiter (post lock-cutover
183
+ * the body never moved into a status folder; it rests in `backlog/`, so requeue
184
+ * releases/clears the lock rather than moving a `.md`). Covers both a resolved
185
+ * stuck hold and a claim that never surfaced.
187
186
  * Storage-agnostic, mirroring {@link ReturnToBacklogOptions}.
188
187
  */
189
188
  export type ApplyReturnToBacklogTransitionInput = ReturnToBacklogOptions;
@@ -198,11 +197,12 @@ export type ApplyReturnToBacklogTransitionResult =
198
197
 
199
198
  /**
200
199
  * A *prepared* TREE-LESS NEEDS-ATTENTION (surface) transition: surface a stuck
201
- * AFTER-COMMIT, LEDGER-ONLY item (`in-progress/ needs-attention/`, with the
202
- * reason in the body) WITHOUT a checkout — the SURFACE-direction sibling of the
200
+ * AFTER-COMMIT, LEDGER-ONLY item (post lock-cutover mark its per-item lock
201
+ * `state: stuck` with the reason, no `in-progress/ needs-attention/` folder
202
+ * move) WITHOUT a checkout — the SURFACE-direction sibling of the
203
203
  * tree-less requeue, sharing its exact mechanism. The work is ALREADY committed
204
204
  * on the kept `work/<slug>` branch (intact on the arbiter, recoverable), so the
205
- * surface is purely the one-file `.md` move + reason — no `pushBranch`, no
205
+ * surface is purely the lock amend + reason — no `pushBranch`, no
206
206
  * worktree. Storage-agnostic, mirroring {@link SurfaceToNeedsAttentionOptions}.
207
207
  * NOT for the wip-save / gate-failed / agent-failed surfaces (which may carry
208
208
  * uncommitted work — those keep {@link applyNeedsAttentionTransition}, the
@@ -322,21 +322,22 @@ export interface LedgerWriteStrategy {
322
322
  input: ApplyCompleteTransitionInput,
323
323
  ): Promise<ApplyCompleteTransitionResult>;
324
324
  /**
325
- * Apply a NEEDS-ATTENTION transition: bounce a stuck claimed item to
326
- * `work/needs-attention/` with its reason recorded in the body. The sole
327
- * strategy delegates to the folder-native move mechanism unchanged; a future
328
- * strategy could surface the stuck item elsewhere (e.g. the cherry-pick-to-
329
- * `main` follow-on) without `complete.ts`/`run.ts` changing.
325
+ * Apply a NEEDS-ATTENTION transition: mark a stuck claimed item on its
326
+ * per-item lock with its reason (post lock-cutover no folder write). The
327
+ * sole strategy delegates to the underlying mechanism unchanged; a future
328
+ * strategy could surface the stuck item elsewhere without
329
+ * `complete.ts`/`run.ts` changing.
330
330
  */
331
331
  applyNeedsAttentionTransition(
332
332
  input: ApplyNeedsAttentionTransitionInput,
333
333
  ): Promise<ApplyNeedsAttentionTransitionResult>;
334
334
  /**
335
335
  * Apply a TREE-LESS NEEDS-ATTENTION (surface) transition: surface a stuck
336
- * AFTER-COMMIT, LEDGER-ONLY item (`in-progress/ needs-attention/`) WITHOUT a
336
+ * AFTER-COMMIT, LEDGER-ONLY item (post lock-cutover mark its per-item lock
337
+ * `state: stuck`, no `in-progress/ → needs-attention/` folder move) WITHOUT a
337
338
  * checkout, reusing the SAME tree-less mechanism `requeue` uses for the reverse
338
- * direction. The sole strategy delegates to the tree-less surface (now a pure lock amend)
339
- * (fetch + scratch-index move + throwaway-ref + leased fast-forward push). NOT
339
+ * direction. The sole strategy delegates to the tree-less surface (a pure lock
340
+ * amend CAS-published to the arbiter's lock ref). NOT
340
341
  * for the uncommitted-wip surfaces, which keep {@link
341
342
  * applyNeedsAttentionTransition} (the cwd-bound path that can commit wip first).
342
343
  */
@@ -344,10 +345,11 @@ export interface LedgerWriteStrategy {
344
345
  input: ApplyTreelessNeedsAttentionTransitionInput,
345
346
  ): ApplyTreelessNeedsAttentionTransitionResult;
346
347
  /**
347
- * Apply a RETURN-TO-BACKLOG transition: re-queue a STUCK item (in
348
- * `needs-attention/` OR `in-progress/`resolved on the arbiter) for
348
+ * Apply a RETURN-TO-BACKLOG transition: re-queue a STUCK item (recovered via
349
+ * its per-item lock on the arbiter post lock-cutover the body rests in
350
+ * `backlog/`, not a status folder) for
349
351
  * re-claiming, routed through the SAME seam. Like `claim`, it is TREE-LESS —
350
- * the move is a compare-and-swap push to the arbiter ref (it never writes the
352
+ * the amend is a compare-and-swap push to the arbiter ref (it never writes the
351
353
  * cwd tree).
352
354
  */
353
355
  applyReturnToBacklogTransition(
@@ -630,12 +632,12 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
630
632
  * bounce its `work/prd-<slug>`, a temp-branch caller pushes NOTHING.)
631
633
  *
632
634
  * Both halves are ONE operation done in ONE place: it delegates to {@link
633
- * routeToNeedsAttention}, which appends the reason as body prose (never a
634
- * frontmatter field WORK-CONTRACT rule 3), saves the aborted work as a
635
- * **wip** commit, `git mv`s the item to `work/needs-attention/` as the
636
- * **move-only** commit (the tip), and — when an `arbiter` is given — pushes the
637
- * work branch (best-effort, branch-parameterised, emptiness-guarded; SURFACE-
638
- * ONLY when `pushBranch: false`). The seam does NOT strip the arbiter: the same
635
+ * routeToNeedsAttention}, which saves the aborted work as a **wip** commit
636
+ * on the work branch (post lock-cutover no `work/needs-attention/` folder
637
+ * write ever fires here) and when an `arbiter` is given — pushes the work
638
+ * branch (best-effort, branch-parameterised, emptiness-guarded; SURFACE-
639
+ * ONLY when `pushBranch: false`). The OBSERVABLE lock amend rides on
640
+ * {@link bounceToStuckLock} directly below. The seam does NOT strip the arbiter: the same
639
641
  * arbiter both publishes the surface (here) AND drives the helper's branch push,
640
642
  * so "record stuck" and "save the work" can never drift apart. The human-vs-
641
643
  * autonomous gate rides on whether an `arbiter` is given at all (human
@@ -657,9 +659,10 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
657
659
  // outage-retried), so the partial work travels cross-machine and a `requeue`
658
660
  // continues from the tip. The work-branch push is NOT a `main` write.
659
661
  const saved = await routeToNeedsAttention(input);
660
- const stuck = await bounceToStuckLock({
662
+ const surfaced = await bounceThroughSurface({
661
663
  cwd: input.cwd,
662
664
  slug: input.slug,
665
+ item: `task:${input.slug}`,
663
666
  reason: input.reason,
664
667
  questions: input.questions,
665
668
  arbiter: input.arbiter,
@@ -667,11 +670,12 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
667
670
  note: input.note,
668
671
  });
669
672
  return {
670
- // `moved` reflects the OBSERVABLE half (the stuck record): the lock amend.
671
- moved: stuck.moved,
672
- reasonNotMoved: stuck.reasonNotMoved,
673
+ // `moved` reflects the OBSERVABLE half (the surface record): the sidecar +
674
+ // `needsAnswers:true` on `<arbiter>/main` (or the human-local no-op).
675
+ moved: surfaced.moved,
676
+ reasonNotMoved: surfaced.reasonNotMoved,
673
677
  // The branch push outcome is the honest RECOVERABLE report (`do`/`run` read
674
- // it). The on-`main` surface half is GONE (the lock is the surface now).
678
+ // it).
675
679
  branchPush: saved.branchPush,
676
680
  pushError: saved.pushError,
677
681
  };
@@ -680,7 +684,7 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
680
684
  /**
681
685
  * The return-to-backlog transition under the SAME strategy: re-queue the
682
686
  * stuck item by delegating to {@link returnToBacklog}, which moves the slug's
683
- * current `work/<needs-attention|in-progress>/<slug>.md → work/backlog/<slug>.md`
687
+ * current `work/<needs-attention|in-progress>/<slug>.md → work/tasks/ready/<slug>.md`
684
688
  * TREE-LESSLY — it
685
689
  * builds the move off `<arbiter>/main` with plumbing and CAS-publishes it back
686
690
  * THROUGH this same write seam (`applyTransition`, the very push+lease+verify
@@ -693,165 +697,146 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
693
697
  },
694
698
 
695
699
  /**
696
- * The tree-less surface transition under the SAME strategy: surface the stuck
697
- * AFTER-COMMIT, LEDGER-ONLY item by delegating to the tree-less surface (now a pure lock amend),
698
- * which moves `work/in-progress/<slug>.md work/needs-attention/<slug>.md`
699
- * (reason in the body) TREE-LESSLY it builds the move off `<arbiter>/main` with
700
- * plumbing and CAS-publishes it THROUGH this same write seam
701
- * (`applyTransition`, the very push+lease+verify `claim`/`requeue` use), never
702
- * staging/committing in the cwd working tree. The reverse of
700
+ * The tree-less surface transition under the SAME strategy: surface the
701
+ * stuck AFTER-COMMIT, LEDGER-ONLY item by delegating to the tree-less
702
+ * surface post lock-cutover a pure LOCK AMEND (`state: stuck` with the
703
+ * reason on the lock entry), CAS-published to the arbiter's lock ref via
704
+ * the same push+lease+verify seam `claim`/`requeue` use, never staging or
705
+ * committing in the cwd working tree. The reverse of
703
706
  * {@link applyReturnToBacklogTransition}, the same one mechanism.
704
707
  */
705
708
  async applyTreelessNeedsAttentionTransition(
706
709
  input: ApplyTreelessNeedsAttentionTransitionInput,
707
710
  ): ApplyTreelessNeedsAttentionTransitionResult {
708
- // PURE LOCK AMEND (task
709
- // `cutover-needs-attention-becomes-lock-stuck-recovery-surface`, decision i+):
710
- // the after-commit / ledger-only surface (continue-push-failure /
711
- // continue-rebase-conflict) is now the SAME `active stuck` lock amend as the
712
- // cwd-bound bounce NO `git mv`, NO `main` write. The recoverable work is
713
- // already committed on the kept `work/<slug>` branch (intact on the arbiter);
714
- // the stuck reason + questions ride on the lock entry. A re-surface of an
715
- // already-stuck item is a tolerated idempotent no-op (`wrong-state`).
716
- const moved = await bounceToStuckLock({
711
+ // PR-2b surface cutover (spec
712
+ // `surface-stuck-as-questions-and-retire-stuck-lock-state`, decision #1): the
713
+ // after-commit / ledger-only surface (continue-push-failure / continue-rebase-
714
+ // conflict) surfaces the item on `<arbiter>/main` (a `stuck`-kind sidecar +
715
+ // `needsAnswers:true` on the item body in ONE commit) THEN releases the per-
716
+ // item lock. Surface-FIRST, release-SECOND, with `main`-authoritative crash
717
+ // recovery inherited from {@link runTreelessLedgerMove}. The recoverable work
718
+ // is already committed on the kept `work/<slug>` branch (intact on the arbiter).
719
+ const surfaced = await bounceThroughSurface({
717
720
  cwd: input.cwd,
718
721
  slug: input.slug,
722
+ item: `task:${input.slug}`,
719
723
  reason: input.reason,
720
724
  questions: input.questions,
721
725
  arbiter: input.arbiter,
722
726
  env: input.env,
723
727
  note: input.note,
724
728
  });
725
- return {moved: moved.moved, reasonNotMoved: moved.reasonNotMoved};
729
+ return {moved: surfaced.moved, reasonNotMoved: surfaced.reasonNotMoved};
726
730
  },
727
731
 
728
732
  /**
729
733
  * The resolve-needs-attention transition under the SAME strategy — satisfying
730
- * the INTENT "clear the stuck surface + restore in-progress." It delegates to
731
- * the resume lock amend (reverse `git mv` needs-attention →
732
- * in-progress, committed) and, when an `arbiter` is given, publishes that
733
- * reverse move-only commit to the arbiter's `main` CLEARING the stuck surface
734
- * there (the item is back in in-progress on the ledger). Same all-or-nothing,
735
- * never-`--force` publish. "Reverse-move on `main`" is a detail of THIS
736
- * strategy; the seam's contract is only the intent "clear the surface."
734
+ * the INTENT "clear the stuck surface + restore active." It delegates to
735
+ * the resume lock amend (post lock-cutover — `stuck → active` on the per-item
736
+ * lock, no reverse `needs-attention/ → in-progress/` folder move) and, when an
737
+ * `arbiter` is given, CAS-publishes that lock amend to the arbiter's lock ref
738
+ * CLEARING the stuck surface there (the item is active again). Same
739
+ * all-or-nothing, never-`--force` publish. The lock-ref amend is a detail of
740
+ * THIS strategy; the seam's contract is only the intent "clear the surface."
737
741
  */
738
742
  async applyResolveNeedsAttentionTransition(
739
- input: ApplyResolveNeedsAttentionTransitionInput,
743
+ _input: ApplyResolveNeedsAttentionTransitionInput,
740
744
  ): Promise<ApplyResolveNeedsAttentionTransitionResult> {
741
- // PURE LOCK AMEND (task
742
- // `cutover-needs-attention-becomes-lock-stuck-recovery-surface`, decision i+):
743
- // resolving a stuck item is `stuck → active` on the per-item lock (a human is
744
- // picking it up), NOT a `needs-attention/ → in-progress/` folder move. NO `main`
745
- // write the body already rests in `backlog/` (task 9a) and the work stays on
746
- // the kept `work/<slug>` branch. Without an arbiter there is no lock ref to
747
- // amend (the human-local face), so it is a recorded no-op success.
748
- if (!input.arbiter) {
749
- return {moved: true};
750
- }
751
- const r = await resumeItemLock({
752
- item: `task:${input.slug}`,
753
- cwd: input.cwd,
754
- arbiter: input.arbiter,
755
- env: input.env,
756
- });
757
- if (r.outcome === 'transitioned') {
758
- return {moved: true};
759
- }
760
- // `wrong-state` (already active — not actually stuck) is tolerated as a no-op
761
- // success: the item is already in-flight, the caller onboards onto it anyway.
762
- if (r.outcome === 'wrong-state') {
763
- return {moved: true};
764
- }
765
- return {
766
- moved: false,
767
- reasonNotMoved: `could not resume '${input.slug}' (${r.outcome}: ${r.message}).`,
768
- };
745
+ // Post-`retire-stuck-lock-state`: the `stuck` lock state is retired, so
746
+ // there is no `stuck active` lock amend to perform. A parked item is
747
+ // now a `needsAnswers:true` pool item on `main` with a sidecar, drained
748
+ // by the apply rung (answer the sidecar), not by a resolve verb. The seam
749
+ // is kept for source compatibility of its remaining legacy callers
750
+ // (start.ts's legacy `needs-attention/` folder branch), where it is a
751
+ // recorded no-op success.
752
+ return {moved: true};
769
753
  },
770
754
  };
771
755
 
772
756
  /**
773
- * The SOLE stuck-state RECORD: amend the item's HELD per-item lock
774
- * `active → stuck` + the FULL reason prose + any agent-surfaced questions, via the
775
- * state machine's mark-stuck CAS amend ({@link markStuckItemLock}) task
776
- * `cutover-needs-attention-becomes-lock-stuck-recovery-surface` (decision i+; prd
777
- * `ledger-status-per-item-lock-refs` US #5/#8; ADR
778
- * `ledger-status-on-per-item-lock-refs`). This REPLACES the `git mv
779
- * needs-attention/` folder bounce + its on-`main` surface + branch push: the
780
- * bounce now touches ONLY the lock ref (NO `main` write so a protected-`main`
781
- * bounce succeeds, and a work branch cut from `main` inherits no stuck record).
782
- *
783
- * The bounce holds the TASK's `implement` lock that `claim` acquired (task
784
- * `claim-acquires-unified-lock-no-body-move`), so the normal stuck path is a plain
785
- * `active → stuck` amend (`transitioned`). The OUTCOME MAPPING onto `{moved}`:
786
- * - `transitioned` — the lock is now stuck (the stuck state is recorded) ⇒
787
- * `moved: true`.
788
- * - `wrong-state` — the lock is ALREADY `stuck` (an idempotent re-surface of a
789
- * still-stuck item) ⇒ `moved: true` (the stuck record stands).
790
- * - `not-held` — there is NO held lock to amend (an item that predates the
791
- * lock, or a flow where claim did not acquire) ⇒ `moved: false` honestly: with
792
- * the folder retired there is no other substrate to record the stuck state on,
793
- * so the caller reports the bounce did NOT land (retry/resolve) rather than
794
- * fake a success.
795
- * - `lost`/`error` — a concurrent CAS race / environment fault ⇒ `moved: false`.
796
- * - no arbiter — a human local-only `complete` (no arbiter handle): the lock
797
- * ref lives on the arbiter, so there is no lock to amend; treat as a recorded
798
- * no-op (`moved: true`) — a human is right there (the same human-vs-autonomous
799
- * posture the old local-only folder move took). NOTE this records nothing
800
- * durable, by design: the human is in the loop.
757
+ * The SOLE stuck-state RECORD (PR-2b, spec
758
+ * `surface-stuck-as-questions-and-retire-stuck-lock-state`, user stories 1/3/8,
759
+ * decisions #1/#4): surface the bounced item as a `stuck`-kind sidecar +
760
+ * `needsAnswers:true` on the item body in ONE commit on `<arbiter>/main`, THEN
761
+ * release the per-item lock. Surface-FIRST, release-SECOND the ordering is
762
+ * load-bearing so a crash between them is recoverable from `main` (the classifier
763
+ * fold in `item-lock.ts` re-derives `cleared-stale` from the main-side truth
764
+ * PR-2a landed). This REPLACES the retired `active stuck` lock amend: no
765
+ * bounce leaves a `stuck` lock; a bounced item rests as a plain `needsAnswers:true`
766
+ * pool item (`eligible:false` by construction).
801
767
  *
802
- * Keyed on `task:<slug>` (the bounce surfaces a TASK; the prd/observation locks
803
- * are tasking/advance holds whose own bounce paths are separate).
768
+ * The OUTCOME MAPPING onto `{moved}`:
769
+ * - `surfaced` — the sidecar + `needsAnswers:true` commit landed on
770
+ * `<arbiter>/main` and the lock was released ⇒ `moved: true`.
771
+ * - `bodyAbsent` — the D1 probe found no body for the item on `main` (a
772
+ * bounce for an item whose body never landed — e.g. a claim that lost/raced).
773
+ * The surface is a CLEAN NO-OP; the lock is STILL released so the bounce is
774
+ * never a dead-end held lock ⇒ `moved: true` (nothing to record, nothing left
775
+ * stuck).
776
+ * - `!surfaced` — the surface commit did NOT land (contention exhausted,
777
+ * item missing on main by explicit path, environment fault) ⇒ `moved: false`
778
+ * with `reasonNotMoved` so the caller reports the honest not-landed state.
779
+ * - no arbiter — a human local-only `complete` (no arbiter handle): the
780
+ * surface primitive requires an arbiter, so this is a recorded no-op (`moved:
781
+ * true`) — a human is right there (the same human-vs-autonomous posture the
782
+ * retired lock amend took). NOTE this records nothing durable, by design.
804
783
  */
805
- async function bounceToStuckLock(params: {
784
+ async function bounceThroughSurface(params: {
806
785
  cwd: string;
807
786
  slug: string;
787
+ item: string;
808
788
  reason: string;
809
789
  questions?: string[];
810
790
  arbiter?: string;
811
791
  env?: NodeJS.ProcessEnv;
812
792
  note?: (message: string) => void;
813
793
  }): Promise<{moved: boolean; reasonNotMoved?: string}> {
814
- const {cwd, slug, reason, questions, arbiter, env} = params;
794
+ const {cwd, slug, item, reason, questions, arbiter, env} = params;
815
795
  const note = params.note ?? (() => {});
816
796
  if (!arbiter) {
817
- // No arbiter handle ⇒ no lock ref to amend. A human local-only `complete`:
818
- // the human is right there, so this is a recorded no-op (parity with the old
819
- // local-only folder move that wrote nothing cross-machine).
797
+ // No arbiter handle ⇒ no `<arbiter>/main` to surface on. A human local-only
798
+ // `complete`: the human is right there, so this is a recorded no-op (parity
799
+ // with the retired local-only lock amend that wrote nothing cross-machine).
820
800
  note(
821
- `'${slug}' bounced locally (no arbiter) — the stuck reason is not recorded ` +
822
- 'on a lock ref (a human is right here).',
801
+ `'${slug}' bounced locally (no arbiter) — the stuck reason is not surfaced ` +
802
+ 'on <arbiter>/main (a human is right here).',
823
803
  );
824
804
  return {moved: true};
825
805
  }
806
+ const asNewQuestions: NewQuestion[] | undefined = questions?.map((q) => ({
807
+ question: q,
808
+ kind: 'stuck' as const,
809
+ }));
826
810
  try {
827
- const r = await markStuckItemLock({
828
- item: `task:${slug}`,
829
- reason,
830
- questions,
811
+ const r = await surfaceStuckToNeedsAttention({
831
812
  cwd,
813
+ slug,
814
+ item,
815
+ reason,
816
+ questions: asNewQuestions,
832
817
  arbiter,
833
818
  env,
819
+ note,
834
820
  });
835
- const movedOutcomes: TransitionOutcome[] = ['transitioned', 'wrong-state'];
836
- if (movedOutcomes.includes(r.outcome)) {
837
- if (r.outcome === 'transitioned') {
838
- note(`Marked the per-item lock for '${slug}' stuck: ${reason}`);
839
- } else {
840
- note(`The per-item lock for '${slug}' is already stuck (re-surface).`);
841
- }
821
+ if (r.surfaced) {
822
+ note(`Surfaced '${item}' on ${arbiter}/main (stuck): ${reason}`);
823
+ return {moved: true};
824
+ }
825
+ if (r.bodyAbsent) {
826
+ note(
827
+ `'${item}' has no body on ${arbiter}/main — surface skipped as a clean ` +
828
+ 'no-op; the lock was still released to avoid a dead-end held lock.',
829
+ );
842
830
  return {moved: true};
843
831
  }
844
832
  const reasonNotMoved =
845
- r.outcome === 'not-held'
846
- ? `'${slug}' has no held lock to mark stuck (the bounce could not record ` +
847
- 'the stuck state — the item is not lock-held).'
848
- : `could not mark the per-item lock for '${slug}' stuck (${r.outcome}: ` +
849
- `${r.message}).`;
833
+ r.reasonNotSurfaced ??
834
+ `could not surface '${item}' on ${arbiter}/main (unknown reason).`;
850
835
  note(reasonNotMoved);
851
836
  return {moved: false, reasonNotMoved};
852
837
  } catch (err) {
853
838
  const reasonNotMoved =
854
- `could not mark the per-item lock for '${slug}' stuck ` +
839
+ `could not surface '${item}' on ${arbiter}/main ` +
855
840
  `(${err instanceof Error ? err.message : String(err)}).`;
856
841
  note(reasonNotMoved);
857
842
  return {moved: false, reasonNotMoved};
@@ -65,8 +65,8 @@ function readSidecarInPlace(
65
65
  }
66
66
 
67
67
  /**
68
- * Collect every `needsAnswers:true` task (from `work/backlog`) + prd (from
69
- * `work/prds`) for the in-place repo, through the read seam (the SAME readers the
68
+ * Collect every `needsAnswers:true` task (from `work/backlog`) + spec (from
69
+ * `work/specs`) for the in-place repo, through the read seam (the SAME readers the
70
70
  * build-pool scan uses). These are the SURFACE/APPLY candidates this task draws
71
71
  * into the selection (today they are build/task-INELIGIBLE, so nothing else
72
72
  * surfaces them).
@@ -89,25 +89,25 @@ function blockedItemsInPlace(
89
89
  out.push({namespace: 'spec', slug: spec.slug});
90
90
  }
91
91
  }
92
- // TASKED resting prds (`prds/tasked/`) — enumerated UNCONDITIONALLY (NOT behind
93
- // `surfaceStaging`), because a prd may legitimately carry `needsAnswers:true`
94
- // while resting in `prds/tasked/` (WORK-CONTRACT "A PRD that has drifted AFTER
95
- // it was TASKED"). This is NOT a staging widening: a tasked prd is a durable
92
+ // TASKED resting prds (`specs/tasked/`) — enumerated UNCONDITIONALLY (NOT behind
93
+ // `surfaceStaging`), because a spec may legitimately carry `needsAnswers:true`
94
+ // while resting in `specs/tasked/` (WORK-CONTRACT "A SPEC that has drifted AFTER
95
+ // it was TASKED"). This is NOT a staging widening: a tasked spec is a durable
96
96
  // resting state, like the pool, so it is enumerated like the pool. Routing
97
97
  // still respects the gates in `buildLifecyclePools` (an ANSWERED sidecar -> the
98
98
  // always-on APPLY pool so the human's answer is never STRANDED; a NO-sidecar
99
- // tasked prd -> SURFACE, still gated by `surfaceBlockers`). Without this, a
100
- // tasked prd's answered sidecar is enumerated by no pool and apply never runs
99
+ // tasked spec -> SURFACE, still gated by `surfaceBlockers`). Without this, a
100
+ // tasked spec's answered sidecar is enumerated by no pool and apply never runs
101
101
  // on it (observation `tasked-prd-needsanswers-sidecar-stranded-no-apply-pool`).
102
102
  for (const spec of read.resolveLocalSpecTasked({repoPath})) {
103
103
  if (spec.needsAnswers === true) {
104
104
  out.push({namespace: 'spec', slug: spec.slug});
105
105
  }
106
106
  }
107
- // SURFACE-on-STAGING widening (prd
107
+ // SURFACE-on-STAGING widening (spec
108
108
  // `staging-surface-and-apply-promote-safety` F2): when `surfaceStaging` is
109
109
  // ON, the candidate set ADDITIONALLY enumerates `needsAnswers` items resting
110
- // in STAGING (`tasks/backlog/` + `prds/proposed/`), so a tasked item
110
+ // in STAGING (`tasks/backlog/` + `specs/proposed/`), so a tasked item
111
111
  // surfaces its questions BEFORE the human promotes it. BUILD/claim still
112
112
  // reads POOL-only (`scoreItems` over `state.ready`); only the surface polarity
113
113
  // widens here.
@@ -136,9 +136,27 @@ export function gatherLifecycleInPlace(input: {
136
136
  repoPath: string;
137
137
  read?: LedgerReadStrategy;
138
138
  gates?: LifecyclePoolGates;
139
+ /**
140
+ * The HELD TASK slugs to SUBTRACT from the triage/surface/apply candidate
141
+ * inputs before {@link buildLifecyclePools} routes them (task
142
+ * `in-place-scan-subtracts-held-locked-slugs-from-propose-matrix`).
143
+ *
144
+ * Symmetric to the pool-side subtraction `scoreItems` already runs on
145
+ * `state.ready`: without it, a `needsAnswers` TASK whose per-item lock is
146
+ * currently held (state `active`/`stuck`) still slips into the surface / apply
147
+ * pool, so `scan --json` enumerates a matrix leg for it that then always loses
148
+ * the claim CAS (`claim-cas.ts:127-132`) — reddening the propose tick every
149
+ * cadence for as long as the item is held. Narrowly TASK-scoped (this is what
150
+ * {@link heldTaskSlugs} returns): an observation triage entry / a spec surface
151
+ * entry is NOT filtered here, because the lock ref prefix `task-<slug>` only
152
+ * gates the task namespace. Defaults empty (byte-identical to pre-fix
153
+ * behaviour) so callers who cannot resolve a lock read still work.
154
+ */
155
+ heldSlugs?: Set<string>;
139
156
  }): SelectedLifecyclePools {
140
157
  const read = input.read ?? ledgerRead;
141
158
  const repoPath = input.repoPath;
159
+ const heldSlugs = input.heldSlugs ?? new Set<string>();
142
160
 
143
161
  const rawObservations = read.resolveLocalState({repoPath}).observations;
144
162
  const observations: ObservationCandidate[] = rawObservations.map((obs) => ({
@@ -151,12 +169,17 @@ export function gatherLifecycleInPlace(input: {
151
169
  read,
152
170
  repoPath,
153
171
  surfaceStaging,
154
- ).map((item) => ({
155
- repoPath,
156
- namespace: item.namespace,
157
- slug: item.slug,
158
- sidecar: readSidecarInPlace(repoPath, item.namespace, item.slug),
159
- }));
172
+ )
173
+ // Held-slug subtraction (task-scoped): a `needsAnswers` TASK whose per-item
174
+ // lock is currently held is EXCLUDED from surface/apply enumeration. Spec /
175
+ // observation entries are untouched — the lock ref set here is task-only.
176
+ .filter((item) => !(item.namespace === 'task' && heldSlugs.has(item.slug)))
177
+ .map((item) => ({
178
+ repoPath,
179
+ namespace: item.namespace,
180
+ slug: item.slug,
181
+ sidecar: readSidecarInPlace(repoPath, item.namespace, item.slug),
182
+ }));
160
183
 
161
184
  return buildLifecyclePools({
162
185
  repoPath,
@@ -195,7 +218,7 @@ async function readSidecarMirror(
195
218
  * Gather + build the lifecycle pools for a MIRROR-SIDE bare hub mirror (async).
196
219
  * Reads the SAME logical inputs as {@link gatherLifecycleInPlace} \u2014 observations +
197
220
  * the `needsAnswers` pool from the mirror's committed `main` (via
198
- * `resolveMirrorState`), the prd pool via `resolveMirrorSpecPool`, and each item's
221
+ * `resolveMirrorState`), the spec pool via `resolveMirrorSpecPool`, and each item's
199
222
  * sidecar via `git show` \u2014 then hands them to the SAME shared
200
223
  * {@link buildLifecyclePools}, so the in-place + mirror enumerations AGREE.
201
224
  */
@@ -232,9 +255,9 @@ export async function gatherLifecycleMirror(input: {
232
255
  blocked.push({namespace: 'spec', slug: spec.slug});
233
256
  }
234
257
  }
235
- // TASKED resting prds (`<ref>:work/prds/tasked/`) — enumerated UNCONDITIONALLY,
236
- // the mirror-side counterpart of the in-place tasked-prd enumeration above
237
- // (so a `needsAnswers` tasked prd's answered sidecar is never stranded on the
258
+ // TASKED resting prds (`<ref>:work/specs/tasked/`) — enumerated UNCONDITIONALLY,
259
+ // the mirror-side counterpart of the in-place tasked-spec enumeration above
260
+ // (so a `needsAnswers` tasked spec's answered sidecar is never stranded on the
238
261
  // mirror/CI advance path either). Routing still respects the gates.
239
262
  const specTasked = await read.resolveMirrorSpecTasked({mirrorPath, ref, env});
240
263
  for (const spec of specTasked) {
@@ -242,10 +265,10 @@ export async function gatherLifecycleMirror(input: {
242
265
  blocked.push({namespace: 'spec', slug: spec.slug});
243
266
  }
244
267
  }
245
- // SURFACE-on-STAGING widening (prd
268
+ // SURFACE-on-STAGING widening (spec
246
269
  // `staging-surface-and-apply-promote-safety` F2): mirror-side counterpart of
247
270
  // the in-place widening above — enumerate `needsAnswers` items in
248
- // STAGING (`tasks/backlog/` + `prds/proposed/`) from the bare mirror's
271
+ // STAGING (`tasks/backlog/` + `specs/proposed/`) from the bare mirror's
249
272
  // committed `<ref>` tree, so the in-place + mirror surfaces AGREE. The
250
273
  // staging reads are skipped entirely when the gate is OFF (no extra git
251
274
  // ls-tree work in the legacy mode).