dorfl 0.1.1 → 0.1.2

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 (313) 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 +7 -7
  8. package/dist/advance-drivers.d.ts.map +1 -1
  9. package/dist/advance-drivers.js +5 -5
  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.js +9 -9
  16. package/dist/advance-lifecycle-template.js.map +1 -1
  17. package/dist/advance-loop-driver.d.ts +3 -3
  18. package/dist/advance-loop-driver.d.ts.map +1 -1
  19. package/dist/advance-loop-driver.js +1 -1
  20. package/dist/advance-treeless-publish.d.ts +1 -1
  21. package/dist/advance.d.ts +11 -11
  22. package/dist/advance.d.ts.map +1 -1
  23. package/dist/advance.js +21 -21
  24. package/dist/advance.js.map +1 -1
  25. package/dist/advancing-lock.d.ts +1 -1
  26. package/dist/advancing-lock.js +5 -5
  27. package/dist/apply-decide.d.ts +2 -2
  28. package/dist/apply-decide.js +2 -2
  29. package/dist/apply-merge-action.d.ts +4 -4
  30. package/dist/apply-merge-action.js +2 -2
  31. package/dist/apply-persist.d.ts +5 -5
  32. package/dist/apply-persist.d.ts.map +1 -1
  33. package/dist/apply-persist.js +7 -7
  34. package/dist/apply-persist.js.map +1 -1
  35. package/dist/buildable-body.d.ts +14 -14
  36. package/dist/buildable-body.js +9 -9
  37. package/dist/claim-cas.d.ts +3 -3
  38. package/dist/claim-cas.js +1 -1
  39. package/dist/claim-cas.js.map +1 -1
  40. package/dist/cli.d.ts.map +1 -1
  41. package/dist/cli.js +76 -76
  42. package/dist/cli.js.map +1 -1
  43. package/dist/close-job-template.d.ts +3 -3
  44. package/dist/close-job-template.js +8 -8
  45. package/dist/close-job.d.ts +8 -8
  46. package/dist/close-job.js +25 -25
  47. package/dist/close-job.js.map +1 -1
  48. package/dist/complete.d.ts +3 -3
  49. package/dist/complete.js +8 -8
  50. package/dist/complete.js.map +1 -1
  51. package/dist/concurrency.d.ts +1 -1
  52. package/dist/concurrency.js +1 -1
  53. package/dist/config.d.ts +32 -32
  54. package/dist/config.js +5 -5
  55. package/dist/config.js.map +1 -1
  56. package/dist/continue-branch.d.ts +1 -1
  57. package/dist/continue-branch.js +1 -1
  58. package/dist/cwd-section.js +1 -1
  59. package/dist/cwd-section.js.map +1 -1
  60. package/dist/decision-engine.d.ts +2 -2
  61. package/dist/do-autopick.d.ts +6 -6
  62. package/dist/do-autopick.d.ts.map +1 -1
  63. package/dist/do-autopick.js +5 -5
  64. package/dist/do-autopick.js.map +1 -1
  65. package/dist/do-config.d.ts +3 -3
  66. package/dist/do-config.js +3 -3
  67. package/dist/do-config.js.map +1 -1
  68. package/dist/do-remote-auto.d.ts +2 -2
  69. package/dist/do-remote-auto.js +1 -1
  70. package/dist/do.d.ts +25 -25
  71. package/dist/do.d.ts.map +1 -1
  72. package/dist/do.js +20 -20
  73. package/dist/do.js.map +1 -1
  74. package/dist/drop-source.d.ts +2 -2
  75. package/dist/env-config.js +8 -8
  76. package/dist/env-config.js.map +1 -1
  77. package/dist/format.js +3 -3
  78. package/dist/format.js.map +1 -1
  79. package/dist/frontmatter.d.ts +14 -13
  80. package/dist/frontmatter.d.ts.map +1 -1
  81. package/dist/frontmatter.js +12 -24
  82. package/dist/frontmatter.js.map +1 -1
  83. package/dist/install-ci-branch-protection.d.ts +1 -1
  84. package/dist/install-ci-branch-protection.js +1 -1
  85. package/dist/install-ci-capabilities/advance-lifecycle.d.ts +1 -1
  86. package/dist/install-ci-capabilities/advance-lifecycle.js +1 -1
  87. package/dist/install-ci-capabilities/close-job.d.ts +1 -1
  88. package/dist/install-ci-capabilities/close-job.js +1 -1
  89. package/dist/install-ci-capabilities/example-noop.d.ts +1 -1
  90. package/dist/install-ci-capabilities/example-noop.js +1 -1
  91. package/dist/install-ci-capabilities/intake.d.ts +2 -2
  92. package/dist/install-ci-capabilities/intake.js +2 -2
  93. package/dist/install-ci-capabilities/verify.d.ts +1 -1
  94. package/dist/install-ci-capabilities/verify.js +1 -1
  95. package/dist/install-ci-core.d.ts +3 -3
  96. package/dist/install-ci-core.js +2 -2
  97. package/dist/install-ci-core.js.map +1 -1
  98. package/dist/install-ci-github.d.ts +1 -1
  99. package/dist/install-ci-github.js +1 -1
  100. package/dist/install-ci.d.ts +1 -1
  101. package/dist/install-ci.js +4 -4
  102. package/dist/install-ci.js.map +1 -1
  103. package/dist/intake-event.d.ts +6 -6
  104. package/dist/intake-event.js +6 -6
  105. package/dist/intake-marker.d.ts +3 -3
  106. package/dist/intake-marker.d.ts.map +1 -1
  107. package/dist/intake-triage.d.ts +1 -1
  108. package/dist/intake-triage.js +2 -2
  109. package/dist/intake-trigger-template.d.ts +8 -8
  110. package/dist/intake-trigger-template.d.ts.map +1 -1
  111. package/dist/intake-trigger-template.js +16 -16
  112. package/dist/intake-trigger-template.js.map +1 -1
  113. package/dist/intake.d.ts +50 -50
  114. package/dist/intake.d.ts.map +1 -1
  115. package/dist/intake.js +70 -70
  116. package/dist/intake.js.map +1 -1
  117. package/dist/integration-core.d.ts +17 -17
  118. package/dist/integration-core.js +17 -17
  119. package/dist/integration-core.js.map +1 -1
  120. package/dist/isolation.d.ts +3 -3
  121. package/dist/issue-provider.d.ts +4 -4
  122. package/dist/issue-provider.js +1 -1
  123. package/dist/item-lock.d.ts +21 -21
  124. package/dist/item-lock.d.ts.map +1 -1
  125. package/dist/item-lock.js +16 -16
  126. package/dist/item-path.d.ts +2 -2
  127. package/dist/item-path.js +2 -2
  128. package/dist/ledger-lint.d.ts +9 -9
  129. package/dist/ledger-lint.js +9 -9
  130. package/dist/ledger-read.d.ts +57 -57
  131. package/dist/ledger-read.d.ts.map +1 -1
  132. package/dist/ledger-read.js +24 -24
  133. package/dist/ledger-read.js.map +1 -1
  134. package/dist/ledger-write.d.ts +2 -2
  135. package/dist/ledger-write.js +1 -1
  136. package/dist/lifecycle-gather.d.ts +1 -1
  137. package/dist/lifecycle-gather.js +16 -16
  138. package/dist/lifecycle-gather.js.map +1 -1
  139. package/dist/lifecycle-pools.d.ts +4 -4
  140. package/dist/lifecycle-pools.js +1 -1
  141. package/dist/merge-question-surfacer.d.ts +3 -3
  142. package/dist/merge-question-surfacer.js +2 -2
  143. package/dist/merge-question-surfacer.js.map +1 -1
  144. package/dist/mint-adr.js +4 -4
  145. package/dist/mirror-pool-scan.d.ts +2 -2
  146. package/dist/mirror-pool-scan.js +3 -3
  147. package/dist/mirror-pool-scan.js.map +1 -1
  148. package/dist/needs-attention.d.ts +13 -13
  149. package/dist/needs-attention.d.ts.map +1 -1
  150. package/dist/needs-attention.js +11 -11
  151. package/dist/needs-attention.js.map +1 -1
  152. package/dist/orphan-sidecar.d.ts +2 -2
  153. package/dist/placement.d.ts +6 -6
  154. package/dist/placement.js +2 -2
  155. package/dist/prompt.d.ts +16 -19
  156. package/dist/prompt.d.ts.map +1 -1
  157. package/dist/prompt.js +17 -19
  158. package/dist/prompt.js.map +1 -1
  159. package/dist/readiness.d.ts +1 -1
  160. package/dist/recover-isolated.js +1 -1
  161. package/dist/repo-config.js +12 -12
  162. package/dist/repo-config.js.map +1 -1
  163. package/dist/review-gate.d.ts +3 -3
  164. package/dist/review-gate.d.ts.map +1 -1
  165. package/dist/review-gate.js +11 -10
  166. package/dist/review-gate.js.map +1 -1
  167. package/dist/review-verdict.d.ts +2 -2
  168. package/dist/review-verdict.d.ts.map +1 -1
  169. package/dist/review-verdict.js +1 -1
  170. package/dist/run.d.ts +1 -1
  171. package/dist/run.js +4 -4
  172. package/dist/run.js.map +1 -1
  173. package/dist/scan.d.ts +10 -10
  174. package/dist/scan.d.ts.map +1 -1
  175. package/dist/scan.js +8 -8
  176. package/dist/scan.js.map +1 -1
  177. package/dist/select-order.d.ts +1 -1
  178. package/dist/select-priority.d.ts +12 -12
  179. package/dist/select-priority.d.ts.map +1 -1
  180. package/dist/select-priority.js +5 -5
  181. package/dist/select-priority.js.map +1 -1
  182. package/dist/sidecar.d.ts +2 -2
  183. package/dist/sidecar.js +2 -2
  184. package/dist/sidecar.js.map +1 -1
  185. package/dist/slug-namespace.d.ts +1 -1
  186. package/dist/slug-namespace.js +3 -3
  187. package/dist/slug-namespace.js.map +1 -1
  188. package/dist/spec-complete.js +2 -2
  189. package/dist/spec-complete.js.map +1 -1
  190. package/dist/start.d.ts +1 -1
  191. package/dist/start.js +3 -3
  192. package/dist/start.js.map +1 -1
  193. package/dist/status.d.ts +3 -3
  194. package/dist/status.js +4 -4
  195. package/dist/status.js.map +1 -1
  196. package/dist/surface-gate.d.ts +2 -2
  197. package/dist/surface-gate.d.ts.map +1 -1
  198. package/dist/surface-persist.d.ts +2 -2
  199. package/dist/surface-persist.d.ts.map +1 -1
  200. package/dist/tasker-review-loop.d.ts +8 -8
  201. package/dist/tasker-review-loop.d.ts.map +1 -1
  202. package/dist/tasker-review-loop.js +8 -8
  203. package/dist/tasker-review-loop.js.map +1 -1
  204. package/dist/tasking-eligibility.d.ts +21 -21
  205. package/dist/tasking-eligibility.d.ts.map +1 -1
  206. package/dist/tasking-eligibility.js +10 -10
  207. package/dist/tasking-lock.d.ts +8 -8
  208. package/dist/tasking-lock.d.ts.map +1 -1
  209. package/dist/tasking-lock.js +20 -21
  210. package/dist/tasking-lock.js.map +1 -1
  211. package/dist/tasking.d.ts +33 -33
  212. package/dist/tasking.d.ts.map +1 -1
  213. package/dist/tasking.js +88 -86
  214. package/dist/tasking.js.map +1 -1
  215. package/dist/triage-gate.d.ts +1 -1
  216. package/dist/triage-persist.d.ts +5 -5
  217. package/dist/triage-persist.js +15 -15
  218. package/dist/triage-persist.js.map +1 -1
  219. package/dist/verify-workflow-template.d.ts +1 -1
  220. package/dist/verify-workflow-template.js +2 -2
  221. package/dist/work-layout.d.ts +9 -7
  222. package/dist/work-layout.d.ts.map +1 -1
  223. package/dist/work-layout.js +9 -7
  224. package/dist/work-layout.js.map +1 -1
  225. package/dist/workspace.d.ts +1 -1
  226. package/package.json +1 -1
  227. package/src/advance-ci-template.ts +4 -4
  228. package/src/advance-classify.ts +5 -5
  229. package/src/advance-drivers.ts +10 -10
  230. package/src/advance-isolated.ts +3 -3
  231. package/src/advance-lifecycle-template.ts +9 -9
  232. package/src/advance-loop-driver.ts +3 -3
  233. package/src/advance-treeless-publish.ts +1 -1
  234. package/src/advance.ts +30 -30
  235. package/src/advancing-lock.ts +6 -6
  236. package/src/apply-decide.ts +2 -2
  237. package/src/apply-merge-action.ts +5 -5
  238. package/src/apply-persist.ts +8 -8
  239. package/src/buildable-body.ts +14 -14
  240. package/src/claim-cas.ts +4 -4
  241. package/src/cli.ts +83 -83
  242. package/src/close-job-template.ts +8 -8
  243. package/src/close-job.ts +26 -26
  244. package/src/complete.ts +11 -11
  245. package/src/concurrency.ts +1 -1
  246. package/src/config.ts +37 -37
  247. package/src/continue-branch.ts +1 -1
  248. package/src/cwd-section.ts +1 -1
  249. package/src/decision-engine.ts +3 -3
  250. package/src/do-autopick.ts +9 -9
  251. package/src/do-config.ts +6 -6
  252. package/src/do-remote-auto.ts +2 -2
  253. package/src/do.ts +47 -47
  254. package/src/drop-source.ts +2 -2
  255. package/src/env-config.ts +8 -8
  256. package/src/format.ts +3 -3
  257. package/src/frontmatter.ts +23 -33
  258. package/src/install-ci-branch-protection.ts +1 -1
  259. package/src/install-ci-capabilities/advance-lifecycle.ts +1 -1
  260. package/src/install-ci-capabilities/close-job.ts +1 -1
  261. package/src/install-ci-capabilities/example-noop.ts +1 -1
  262. package/src/install-ci-capabilities/intake.ts +2 -2
  263. package/src/install-ci-capabilities/verify.ts +1 -1
  264. package/src/install-ci-core.ts +4 -4
  265. package/src/install-ci-github.ts +1 -1
  266. package/src/install-ci.ts +4 -4
  267. package/src/intake-event.ts +6 -6
  268. package/src/intake-marker.ts +3 -3
  269. package/src/intake-triage.ts +2 -2
  270. package/src/intake-trigger-template.ts +17 -17
  271. package/src/intake.ts +97 -97
  272. package/src/integration-core.ts +35 -35
  273. package/src/isolation.ts +3 -3
  274. package/src/issue-provider.ts +4 -4
  275. package/src/item-lock.ts +21 -21
  276. package/src/item-path.ts +2 -2
  277. package/src/ledger-lint.ts +9 -9
  278. package/src/ledger-read.ts +81 -81
  279. package/src/ledger-write.ts +3 -3
  280. package/src/lifecycle-gather.ts +16 -16
  281. package/src/lifecycle-pools.ts +4 -4
  282. package/src/merge-question-surfacer.ts +4 -4
  283. package/src/mint-adr.ts +4 -4
  284. package/src/mirror-pool-scan.ts +5 -5
  285. package/src/needs-attention.ts +22 -22
  286. package/src/orphan-sidecar.ts +2 -2
  287. package/src/placement.ts +6 -6
  288. package/src/prompt.ts +20 -25
  289. package/src/readiness.ts +1 -1
  290. package/src/recover-isolated.ts +1 -1
  291. package/src/repo-config.ts +12 -12
  292. package/src/review-gate.ts +12 -11
  293. package/src/review-verdict.ts +2 -2
  294. package/src/run.ts +5 -5
  295. package/src/scan.ts +15 -15
  296. package/src/select-order.ts +1 -1
  297. package/src/select-priority.ts +13 -13
  298. package/src/sidecar.ts +3 -3
  299. package/src/slug-namespace.ts +3 -3
  300. package/src/spec-complete.ts +2 -2
  301. package/src/start.ts +4 -4
  302. package/src/status.ts +7 -7
  303. package/src/surface-gate.ts +2 -2
  304. package/src/surface-persist.ts +2 -2
  305. package/src/tasker-review-loop.ts +15 -15
  306. package/src/tasking-eligibility.ts +21 -21
  307. package/src/tasking-lock.ts +27 -28
  308. package/src/tasking.ts +123 -121
  309. package/src/triage-gate.ts +1 -1
  310. package/src/triage-persist.ts +16 -16
  311. package/src/verify-workflow-template.ts +2 -2
  312. package/src/work-layout.ts +9 -7
  313. package/src/workspace.ts +1 -1
package/dist/cli.js CHANGED
@@ -218,10 +218,10 @@ function buildRegistrySetAdvanceTick(options) {
218
218
  lifecycleGates: {
219
219
  triage: config.observationTriage !== 'off',
220
220
  surface: config.surfaceBlockers,
221
- // `surfaceStaging` widens the SURFACE candidate set into STAGING (prd
221
+ // `surfaceStaging` widens the SURFACE candidate set into STAGING (spec
222
222
  // `staging-surface-and-apply-promote-safety` F2). Default `true` — a
223
- // tasked `needsAnswers` task in `tasks/backlog/` (or prd in
224
- // `prds/proposed/`) surfaces its questions BEFORE promotion. BUILD/claim
223
+ // tasked `needsAnswers` task in `tasks/backlog/` (or spec in
224
+ // `specs/proposed/`) surfaces its questions BEFORE promotion. BUILD/claim
225
225
  // stays pool-only either way.
226
226
  surfaceStaging: config.surfaceStaging,
227
227
  },
@@ -249,10 +249,10 @@ function buildRegistrySetAdvanceTick(options) {
249
249
  identity: config.identity,
250
250
  autoTask: config.autoTask,
251
251
  integration: config.integration,
252
- // The per-TRANSITION TASKING override: the `do prd:` tasking path threads
252
+ // The per-TRANSITION TASKING override: the `do spec:` tasking path threads
253
253
  // `taskingIntegration ?? integration`; the build path stays on `integration`.
254
254
  taskingIntegration: config.taskingIntegration,
255
- // The TASK-PLACEMENT configured default (`do prd:` tasking output:
255
+ // The TASK-PLACEMENT configured default (`do spec:` tasking output:
256
256
  // `pre-backlog` staged vs `ready` pool). No operator flag on this
257
257
  // registry-driven advance context, so only the configured default rung is
258
258
  // threaded (the resolver still layers untrusted-origin force + built-in floor).
@@ -261,7 +261,7 @@ function buildRegistrySetAdvanceTick(options) {
261
261
  verify: config.verify,
262
262
  // Single-job build path: gate the REBASED tip (the default) unconditionally.
263
263
  freshWorktreeGate: config.freshWorktreeGate,
264
- // Cross-job merge-serialiser CAS-retry cap (prd `land-time-reverify-and-
264
+ // Cross-job merge-serialiser CAS-retry cap (spec `land-time-reverify-and-
265
265
  // parallel-merge-ceiling` Story 5 / Applied Answer q1 (a)) — resolved per-repo
266
266
  // and threaded so the registry-driven advance path's `do` inherits it.
267
267
  mergeRetries: config.mergeRetries,
@@ -300,7 +300,7 @@ function buildRegistrySetAdvanceTick(options) {
300
300
  triageGate: harnessTriageGate({ harness, agentCmd: config.agentCmd }),
301
301
  triageModel: config.model,
302
302
  // The ANSWERED-MERGE LAND DISPATCH context (task
303
- // `apply-rung-merge-disposition`, prd `land-time-reverify-and-parallel-
303
+ // `apply-rung-merge-disposition`, spec `land-time-reverify-and-parallel-
304
304
  // merge-ceiling`): the dispatcher cuts a per-job worktree via
305
305
  // `workspace.ts` `createJob` off the hub mirror (so we thread the resolved
306
306
  // `workspacesDir` + the real arbiter URL — the per-mirror tree-less
@@ -396,7 +396,7 @@ function runFlagOverrides(flags, command) {
396
396
  // fleet conditional lives in `runOnce`, not in this flag mapping).
397
397
  Object.assign(overrides, freshWorktreeGateFlagOverrides(flags));
398
398
  // `--merge-retries <n>` rides the SAME chain: the cross-job merge-serialiser
399
- // CAS-retry cap (prd `land-time-reverify-and-parallel-merge-ceiling` Story 5 /
399
+ // CAS-retry cap (spec `land-time-reverify-and-parallel-merge-ceiling` Story 5 /
400
400
  // Applied Answer q1 (a)). The `run` fleet inherits the resolved cap through
401
401
  // the converged `performIntegration` core (config.mergeRetries threads into
402
402
  // the merge loop, replacing the bare `DEFAULT_MERGE_RETRIES` fallback).
@@ -409,7 +409,7 @@ function formatItemLine(item) {
409
409
  }
410
410
  /**
411
411
  * Resolve the EXPLICIT operator placement override from `--tasks-land-in <where>`
412
- * (the top of the `do prd:` tasking-placement precedence — task
412
+ * (the top of the `do spec:` tasking-placement precedence — task
413
413
  * `runner-deterministic-slice-placement-policy-and-precedence`). Mirrors the
414
414
  * `flagMode === 'merge'` ⇒ `explicitMerge: true` shape: it contributes
415
415
  * `explicitTasksLandIn` ONLY when the operator actually typed the flag, so an
@@ -498,7 +498,7 @@ function printPrdToSpecReport(result) {
498
498
  return;
499
499
  }
500
500
  if (result.leaks.length === 0) {
501
- console.log('Leak scan: GREEN (no surviving prd data ref).');
501
+ console.log('Leak scan: GREEN (no surviving spec data ref).');
502
502
  }
503
503
  else {
504
504
  console.error(`Leak scan: FAILED (${result.leaks.length} leak(s)):`);
@@ -513,11 +513,12 @@ function printLeak(leak) {
513
513
  /**
514
514
  * Resolve a task-only command's slug argument through the §3a namespace guard
515
515
  * (`resolveTaskOnlyArg`): accept bare (= task) + `task:` (explicit alias),
516
- * REJECT `spec:` with a clear "operates on tasks, not specs" error (and the
517
- * legacy `prd:` with "operates on tasks, not prds", still accepted through the
518
- * cutover). On rejection it prints the error to stderr and exits 1 (the task-only
519
- * commands never act on a spec). An OMITTED slug (`start`/`complete`/`prompt`
520
- * infer it from the branch) passes through untouched.
516
+ * REJECT `spec:` with a clear "operates on tasks, not specs" error. On rejection
517
+ * it prints the error to stderr and exits 1 (the task-only commands never act on
518
+ * a spec). An OMITTED slug (`start`/`complete`/`prompt` infer it from the branch)
519
+ * passes through untouched. (The legacy `prd:` prefix is a DEAD namespace token
520
+ * after the hard cutover — it is neither special-cased nor rejected here; a
521
+ * `prd:<slug>` arg resolves as a bare literal task slug.)
521
522
  *
522
523
  * `do` is the ONE command that spans both namespaces; it consumes the full
523
524
  * `resolveSlug` (with the cross-namespace collision check) in the `do-in-place`
@@ -595,10 +596,10 @@ function buildInteractiveLauncher(flags, configPath, repoPath) {
595
596
  * switching to its `work/<slug>` branch WITHOUT claiming). The runtime
596
597
  * difference is exactly the `resume` flag — `resume` forces it on (its only mode
597
598
  * is to re-engage), while `start` honours the (now hidden) `--resume` alias.
598
- * Both are task-only (§3a: accept bare + `task:`, reject `prd:`).
599
+ * Both are task-only (§3a: accept bare + `task:`, reject `spec:`).
599
600
  */
600
601
  async function runStartAction(rawSlug, flags, resume) {
601
- // Task-only command (§3a): accept bare + `task:`, reject `prd:`.
602
+ // Task-only command (§3a): accept bare + `task:`, reject `spec:`.
602
603
  const slug = resolveTaskOnlySlug(rawSlug);
603
604
  const cwd = process.cwd();
604
605
  // `resume --isolated <slug>`: re-engage the slug's RETAINED job worktree (the
@@ -914,7 +915,7 @@ export function buildProgram() {
914
915
  .option('--dry-run', 'show the intended push without mutating the arbiter')
915
916
  .option('--ignore-not-ready', 'override the readiness guard: claim despite an unmet blockedBy, and silence the needsAnswers warning (loud, never default)')
916
917
  .action(async (rawSlug, flags) => {
917
- // Task-only command (§3a): accept bare + `task:`, reject `prd:`.
918
+ // Task-only command (§3a): accept bare + `task:`, reject `spec:`.
918
919
  const slug = resolveTaskOnlySlug(rawSlug);
919
920
  // Wrap ONLY this CLI surface's `performClaim` call with the spinner
920
921
  // helper (task `claim-cas-spinner`): the push can take seconds, so the
@@ -1022,7 +1023,7 @@ export function buildProgram() {
1022
1023
  const remote = flags.remote !== undefined && flags.remote.trim() !== ''
1023
1024
  ? flags.remote
1024
1025
  : undefined;
1025
- // Task-only command (§3a): accept bare + `task:`, reject `prd:`.
1026
+ // Task-only command (§3a): accept bare + `task:`, reject `spec:`.
1026
1027
  const theSlug = resolveTaskOnlySlug(rawSlug);
1027
1028
  const configPath = flags.config ?? defaultConfigPath();
1028
1029
  const { dir: configuredRoot, config } = loadHumanWorktreesDir(configPath);
@@ -1066,10 +1067,10 @@ export function buildProgram() {
1066
1067
  program
1067
1068
  .command('prompt')
1068
1069
  .helpGroup(ADVANCED_GROUP)
1069
- .description("Print to stdout the work-agent prompt for a task: the canonical CLAIM-PROTOCOL wrapper + the task's own ## Prompt (with <slug> and source prd substituted). Resolves work/in-progress/<slug>.md then work/backlog/<slug>.md; infers <slug> from a work/<slug> branch when omitted. Read-only, stdout only — the same assembly the autonomous runner feeds agentCmd.")
1070
+ .description("Print to stdout the work-agent prompt for a task: the canonical CLAIM-PROTOCOL wrapper + the task's own ## Prompt (with <slug> and source spec substituted). Resolves work/in-progress/<slug>.md then work/backlog/<slug>.md; infers <slug> from a work/<slug> branch when omitted. Read-only, stdout only — the same assembly the autonomous runner feeds agentCmd.")
1070
1071
  .argument('[slug]', 'the slug to render (inferred from a work/<slug> branch if omitted)')
1071
1072
  .action((rawSlug) => {
1072
- // Task-only command (§3a): accept bare + `task:`, reject `prd:`.
1073
+ // Task-only command (§3a): accept bare + `task:`, reject `spec:`.
1073
1074
  const slug = resolveTaskOnlySlug(rawSlug);
1074
1075
  // Resolve the `promptGuidance` NUDGE namespace through the SAME chain the
1075
1076
  // gate family uses (env > per-repo > global > default), so e.g. a
@@ -1112,7 +1113,7 @@ export function buildProgram() {
1112
1113
  .option('--no-fresh-worktree-gate', 'run the acceptance gate in the current checkout (the pre-rebase tree) — the opt-out for when the per-gate install cost is too high')
1113
1114
  .option('--merge-retries <n>', 'cross-job merge-serialiser CAS-retry cap (see `run --help`); resolved flag > env > per-repo > global > default 1000.')
1114
1115
  .action(async (rawSlug, flags) => {
1115
- // Task-only command (§3a): accept bare + `task:`, reject `prd:`.
1116
+ // Task-only command (§3a): accept bare + `task:`, reject `spec:`.
1116
1117
  const slug = resolveTaskOnlySlug(rawSlug);
1117
1118
  const cwd = process.cwd();
1118
1119
  const { global, override } = loadGlobalAndOverride(flags.config);
@@ -1172,7 +1173,7 @@ export function buildProgram() {
1172
1173
  // `--fresh-worktree-gate`/`--no-fresh-worktree-gate` rides the SAME chain.
1173
1174
  ...freshWorktreeGateFlagOverrides(flags),
1174
1175
  // `--merge-retries <n>` rides the SAME chain: the cross-job merge-serialiser
1175
- // CAS-retry cap (prd `land-time-reverify-and-parallel-merge-ceiling` Story 5
1176
+ // CAS-retry cap (spec `land-time-reverify-and-parallel-merge-ceiling` Story 5
1176
1177
  // / Applied Answer q1 (a)).
1177
1178
  ...mergeRetriesFlagOverrides(flags),
1178
1179
  // `--no-pr` (the PR-INTENT axis) rides the SAME chain.
@@ -1212,7 +1213,7 @@ export function buildProgram() {
1212
1213
  // a single-job path, so the resolved flag is passed UNCONDITIONALLY (no
1213
1214
  // fleet downgrade).
1214
1215
  freshWorktreeGate: config.freshWorktreeGate,
1215
- // Cross-job merge-serialiser CAS-retry cap (prd `land-time-reverify-and-
1216
+ // Cross-job merge-serialiser CAS-retry cap (spec `land-time-reverify-and-
1216
1217
  // parallel-merge-ceiling` Story 5 / Applied Answer q1 (a)) — the resolved
1217
1218
  // per-repo value reaches the merge loop via `performComplete`→
1218
1219
  // `performIntegration`.
@@ -1243,13 +1244,13 @@ export function buildProgram() {
1243
1244
  program
1244
1245
  .command('do')
1245
1246
  .helpGroup(HEADLINE_GROUP)
1246
- .description('The per-repo WORKER (the CI command): claim + onboard onto work/<slug>, run the agent, gate, integrate, and exit. In the CURRENT checkout by default (refuses on a dirty tree, integrates in-place). With --remote <r>: against a REGISTERED repo with NO checkout — materialise a hub mirror + job worktree in the agents\u2019 area, run the same pipeline there, then reap. do <slug> | do task:<slug> | do spec:<slug> (the tasking path; the legacy prd:<slug> is still accepted) | do (auto-pick one) | do <a> <b> (those, in sequence) | do -n <x> (x eligible, in sequence). Auto-pick draws TASKS-FIRST then SPECS-to-task by default (per-repo selectionOrder reorders the pools). --propose (default) / --merge resolved at integrate-time. Supersedes ar-run.sh.')
1247
+ .description('The per-repo WORKER (the CI command): claim + onboard onto work/<slug>, run the agent, gate, integrate, and exit. In the CURRENT checkout by default (refuses on a dirty tree, integrates in-place). With --remote <r>: against a REGISTERED repo with NO checkout — materialise a hub mirror + job worktree in the agents\u2019 area, run the same pipeline there, then reap. do <slug> | do task:<slug> | do spec:<slug> (the tasking path) | do (auto-pick one) | do <a> <b> (those, in sequence) | do -n <x> (x eligible, in sequence). Auto-pick draws TASKS-FIRST then SPECS-to-task by default (per-repo selectionOrder reorders the pools). --propose (default) / --merge resolved at integrate-time. Supersedes ar-run.sh.')
1247
1248
  // EXTENSIBLE argument grammar (the three do-* tasks grow this one block):
1248
1249
  // `do-autopick` widens the single optional positional into a VARIADIC one so
1249
1250
  // `do` (zero args = auto-pick), `do <a> <b> …` (named, in sequence), and
1250
1251
  // `do <slug>` (exactly one) all share the one command. `-n <x>` is the count
1251
1252
  // for the auto-pick form. `do` stays SEQUENTIAL (parallelism is `run`).
1252
- .argument('[slugs...]', 'the item(s) to do: bare (= the task), task:<slug>, or spec:<slug> (task the spec; the legacy prd:<slug> is still accepted). Zero args = auto-pick; multiple = do them in sequence.')
1253
+ .argument('[slugs...]', 'the item(s) to do: bare (= the task), task:<slug>, or spec:<slug> (task the spec). Zero args = auto-pick; multiple = do them in sequence.')
1253
1254
  .option('-c, --config <path>', 'config file path', defaultConfigPath())
1254
1255
  .option('--arbiter <remote>', 'name of the arbiter git remote (default: per-repo/global defaultArbiter)')
1255
1256
  .option('-n, --number <x>', 'AUTO-PICK x eligible items and do them IN SEQUENCE (ordered by selectionOrder, default drain = tasks-first then prds-to-task). Sequential — never a parallelism knob (that is `run`). Mutually exclusive with naming items.')
@@ -1258,7 +1259,7 @@ export function buildProgram() {
1258
1259
  .option('--isolated', "build in an ISOLATED job worktree off THIS repo's arbiter (inferred from cwd) instead of taking over the current checkout, then integrate + reap \u2014 the in-place-but-isolated form. Shares the same grammar as the no-checkout forms: a single named item, multiple named items (in sequence), AND -n/auto-pick over the mirror-side eligible-pool scan. Always SEQUENTIAL (parallelism is `run` / the CI matrix). Orthogonal to --remote (a foreign repo); with --remote, remote wins (isolation is already implied).")
1259
1260
  .option('--merge', 'integrate in merge mode this invocation (mutually exclusive with --propose; overrides config)')
1260
1261
  .option('--propose', 'integrate in propose mode this invocation (default; mutually exclusive with --merge; overrides config)')
1261
- .option('--tasks-land-in <where>', 'where `do prd:<slug>` tasking output lands: `pre-backlog` (staged, not agent-eligible) or `ready` (the agent POOL). The EXPLICIT operator override at the top of the placement precedence (explicit flag > untrusted-origin forces staging > tasksLandIn default > built-in). Resolved flag > env (DORFL_TASKS_LAND_IN) > per-repo > global > built-in.')
1262
+ .option('--tasks-land-in <where>', 'where `do spec:<slug>` tasking output lands: `pre-backlog` (staged, not agent-eligible) or `ready` (the agent POOL). The EXPLICIT operator override at the top of the placement precedence (explicit flag > untrusted-origin forces staging > tasksLandIn default > built-in). Resolved flag > env (DORFL_TASKS_LAND_IN) > per-repo > global > built-in.')
1262
1263
  .option('--no-pr', 'propose without opening a PR: push the branch but deliberately skip the review request, even on an authed GitHub arbiter (the explicit suppress-PR intent). Resolved flag > env > per-repo > global > default off.')
1263
1264
  .option('--ignore-diverged-main', 'override the in-place divergence guard: run even when local main is ahead of <arbiter>/main (unpushed). The work still lands on the arbiter; local main is left for you to `git rebase`. In-place only; loud, never default.')
1264
1265
  .option('--allow-backlog', 'do task:<slug> ONLY: also FIND, CLAIM, and COMPLETE a task that lives in tasks/backlog/ (staging), driving it in place WITHOUT promoting it to the pool (so no advance leg / run daemon can claim it out from under you). The done-move goes tasks/backlog/ -> tasks/done/ directly (your explicit drive IS the promotion). EXPLICIT-INVOCATION-ONLY: default off, never set by run/auto-pick/advance or config/env.')
@@ -1272,9 +1273,9 @@ export function buildProgram() {
1272
1273
  .option('--no-review', 'do NOT run Gate 2 this invocation (overrides config)')
1273
1274
  .option('--review-model <id>', 'model the Gate-2 review agent runs on (de-correlated from the builder; routing intent). Resolved flag > env > per-repo > global > default.')
1274
1275
  .option('--review-max-rounds <n>', 'bound the revise/review loop; on exhaustion force needs-attention (default 2)')
1275
- .option('--tasker-loop', 'run the tasker IMPROVER loop on `do prd:<slug>` (review→edit→converge over the produced task set). ON by default; --no-tasker-loop skips it. DISTINCT from the acceptance gate (--review).')
1276
- .option('--no-tasker-loop', 'skip the tasker improver loop on `do prd:<slug>`')
1277
- .option('--tasker-loop-max <n>', 'cap the tasker improver loop on `do prd:<slug>` (in-context review passes); on exhaustion with blockers, reject via needsAnswers / route the prd to needs-attention (default 3)')
1276
+ .option('--tasker-loop', 'run the tasker IMPROVER loop on `do spec:<slug>` (review→edit→converge over the produced task set). ON by default; --no-tasker-loop skips it. DISTINCT from the acceptance gate (--review).')
1277
+ .option('--no-tasker-loop', 'skip the tasker improver loop on `do spec:<slug>`')
1278
+ .option('--tasker-loop-max <n>', 'cap the tasker improver loop on `do spec:<slug>` (in-context review passes); on exhaustion with blockers, reject via needsAnswers / route the spec to needs-attention (default 3)')
1278
1279
  .option('--tasker-loop-model <id>', 'model the tasker improver loop review agent runs on (de-correlated from the tasker; routing intent). Resolved flag > env > per-repo > global > default. DISTINCT from --review-model.')
1279
1280
  .option('--fresh-worktree-gate', 'run the acceptance gate (prepare then verify) against the REBASED tip in a CLEAN throwaway worktree (the tree that actually integrates), so a green gate provably describes the merged artifact. ON by default. Resolved flag > env > per-repo > global > default on.')
1280
1281
  .option('--no-fresh-worktree-gate', "run the acceptance gate in the agent's build worktree (the pre-rebase tree) as before — the opt-out for when the per-gate install cost is too high")
@@ -1411,7 +1412,7 @@ export function buildProgram() {
1411
1412
  // Host-only runner IDENTITY — scopes git/provider ops only (not the
1412
1413
  // agent launch); absent ⇒ ambient.
1413
1414
  identity: remoteConfig.identity,
1414
- // `do --remote prd:<slug>` tasking-gate policy (task-build path ignores it).
1415
+ // `do --remote spec:<slug>` tasking-gate policy (task-build path ignores it).
1415
1416
  autoTask: remoteConfig.autoTask,
1416
1417
  // The resolved `promptGuidance` nudge — threaded into the remote worker
1417
1418
  // prompt (runRemotePipeline → buildAgentPrompt), mirroring in-place `do`.
@@ -1419,7 +1420,7 @@ export function buildProgram() {
1419
1420
  integration: remoteConfig.integration,
1420
1421
  // EXPLICIT `--merge` override for the untrusted-origin build-propose rule.
1421
1422
  explicitMerge: flagMode === 'merge',
1422
- // Per-TRANSITION TASKING override (the `do --remote prd:` tasking path).
1423
+ // Per-TRANSITION TASKING override (the `do --remote spec:` tasking path).
1423
1424
  taskingIntegration: remoteConfig.taskingIntegration,
1424
1425
  // TASK-PLACEMENT: the configured default + the EXPLICIT operator override
1425
1426
  // (`--tasks-land-in`), the top of the placement precedence — mirrors
@@ -1431,7 +1432,7 @@ export function buildProgram() {
1431
1432
  // Single-job build path: gate the REBASED tip (the default) unconditionally.
1432
1433
  freshWorktreeGate: remoteConfig.freshWorktreeGate,
1433
1434
  // Cross-job merge-serialiser CAS-retry cap (resolved through the per-repo
1434
- // chain on the arbiter-side `.dorfl.json` too) — prd
1435
+ // chain on the arbiter-side `.dorfl.json` too) — spec
1435
1436
  // `land-time-reverify-and-parallel-merge-ceiling` Story 5.
1436
1437
  mergeRetries: remoteConfig.mergeRetries,
1437
1438
  noPR: remoteConfig.noPR,
@@ -1448,7 +1449,7 @@ export function buildProgram() {
1448
1449
  agentCmd: remoteConfig.agentCmd,
1449
1450
  })
1450
1451
  : undefined,
1451
- // The tasker IMPROVER loop on the `do --remote prd:` path is ON by default
1452
+ // The tasker IMPROVER loop on the `do --remote spec:` path is ON by default
1452
1453
  // (auto-tasking has no `verify` floor, so the loop is the task path's
1453
1454
  // quality engine). `--tasker-loop`/`--no-tasker-loop` gates wiring the seam;
1454
1455
  // `taskerLoopMax`/`taskerLoopModel` resolve per-repo (flag > env > per-repo
@@ -1461,7 +1462,7 @@ export function buildProgram() {
1461
1462
  : undefined,
1462
1463
  taskerLoopMax: remoteConfig.taskerLoopMax,
1463
1464
  taskerLoopModel: remoteConfig.taskerLoopModel,
1464
- // The task-SET ACCEPTANCE GATE on the `do --remote prd:` path too.
1465
+ // The task-SET ACCEPTANCE GATE on the `do --remote spec:` path too.
1465
1466
  taskReviewGate: remoteConfig.review
1466
1467
  ? harnessTaskAcceptanceGate({
1467
1468
  harness: remoteHarness,
@@ -1565,7 +1566,7 @@ export function buildProgram() {
1565
1566
  // ops (claim, push, integrate, `gh`) — NEVER the agent launch. Absent ⇒
1566
1567
  // ambient (today's behaviour). Mapped Config → DoOptions like model/agentCmd.
1567
1568
  identity: config.identity,
1568
- // `do prd:<slug>` tasking-gate policy (the task-build path ignores it).
1569
+ // `do spec:<slug>` tasking-gate policy (the task-build path ignores it).
1569
1570
  autoTask: config.autoTask,
1570
1571
  // The resolved `promptGuidance` NUDGE namespace (e.g. `testFirst`),
1571
1572
  // threaded into the worker prompt by performDo → buildAgentPrompt so a
@@ -1578,11 +1579,11 @@ export function buildProgram() {
1578
1579
  // typed `--merge` (`flagMode`), never when `merge` came from config — so an
1579
1580
  // untrusted-origin task still forces propose under a config `merge`.
1580
1581
  explicitMerge: flagMode === 'merge',
1581
- // Per-TRANSITION TASKING override: the `do prd:` tasking path threads
1582
+ // Per-TRANSITION TASKING override: the `do spec:` tasking path threads
1582
1583
  // `taskingIntegration ?? integration`; the task-build path stays on
1583
1584
  // `integration`. Unset ⇒ tasking falls back to `integration` (today's behaviour).
1584
1585
  taskingIntegration: config.taskingIntegration,
1585
- // TASK-PLACEMENT (`do prd:` tasking output): the configured default rung +
1586
+ // TASK-PLACEMENT (`do spec:` tasking output): the configured default rung +
1586
1587
  // the EXPLICIT operator override `--tasks-land-in` (top of the precedence).
1587
1588
  // `explicitTasksLandIn` is set ONLY when the flag was typed (mirrors
1588
1589
  // `explicitMerge`), so an untrusted-origin staging force still wins under a
@@ -1595,7 +1596,7 @@ export function buildProgram() {
1595
1596
  verify: config.verify,
1596
1597
  // Single-job build path: gate the REBASED tip (the default) unconditionally.
1597
1598
  freshWorktreeGate: config.freshWorktreeGate,
1598
- // Cross-job merge-serialiser CAS-retry cap (prd `land-time-reverify-and-
1599
+ // Cross-job merge-serialiser CAS-retry cap (spec `land-time-reverify-and-
1599
1600
  // parallel-merge-ceiling` Story 5 / Applied Answer q1 (a)) — resolved per-repo
1600
1601
  // and threaded to `performComplete`→`performIntegration`.
1601
1602
  mergeRetries: config.mergeRetries,
@@ -1619,7 +1620,7 @@ export function buildProgram() {
1619
1620
  reviewGate: config.review
1620
1621
  ? harnessReviewGate({ harness, agentCmd: config.agentCmd })
1621
1622
  : undefined,
1622
- // The tasker IMPROVER loop on the `do prd:` tasking path is ON by default
1623
+ // The tasker IMPROVER loop on the `do spec:` tasking path is ON by default
1623
1624
  // (auto-tasking has no `verify` floor — the loop is the task path's quality
1624
1625
  // engine). `--tasker-loop`/`--no-tasker-loop` gates wiring the seam;
1625
1626
  // `taskerLoopMax`/`taskerLoopModel` resolve per-repo (flag > env > per-repo
@@ -1646,7 +1647,7 @@ export function buildProgram() {
1646
1647
  note: (message) => console.error(`>> ${message}`),
1647
1648
  noteBlock: (message) => console.error(message),
1648
1649
  };
1649
- // `--allow-backlog` is EXPLICIT-SINGLE-TASK-ONLY (prd
1650
+ // `--allow-backlog` is EXPLICIT-SINGLE-TASK-ONLY (spec
1650
1651
  // `do-allow-backlog-drive-staged-tasks-without-promotion`, decision 4): it
1651
1652
  // drives ONE named staged task in place. It must NOT combine with the
1652
1653
  // AUTO-PICK (zero-args / -n) or MULTI-ITEM forms — those select FROM the
@@ -1700,33 +1701,33 @@ export function buildProgram() {
1700
1701
  process.exit(result.exitCode);
1701
1702
  });
1702
1703
  // `advance` — the SIBLING top-level verb (NOT a `do` subcommand; `do`
1703
- // subcommands + a standalone `task` verb are REJECTED in prd `advance-loop`).
1704
+ // subcommands + a standalone `task` verb are REJECTED in spec `advance-loop`).
1704
1705
  // It reuses the SAME shared `prefix:arg` resolver `do` uses, EXTENDED with the
1705
1706
  // `obs:` namespace, and wires the classify → lock → execute SKELETON: classify
1706
1707
  // the rung (read-only, no model, no lock), take the `advancing` CAS borrow, then
1707
- // dispatch winner-only — build/task rungs ORCHESTRATE `do`/`do prd:` (never a
1708
+ // dispatch winner-only — build/task rungs ORCHESTRATE `do`/`do spec:` (never a
1708
1709
  // duplicate), surface/apply/triage dispatch to a named executor seam later
1709
1710
  // tasks fill. The DRIVERS (one-shot/loop) + `-n` + per-action gates and the
1710
1711
  // rung BODIES are LATER tasks; the bare eligible-SET form errors clearly here.
1711
1712
  program
1712
1713
  .command('advance')
1713
1714
  .helpGroup(HEADLINE_GROUP)
1714
- .description('Advance work/ item(s) one lifecycle rung toward ready/built (PRD advance-loop), the SEQUENTIAL one-shot driver over the advance tick. advance <slug> (bare = the task) | advance spec:<slug> (the spec tasking rung; the legacy prd:<slug> is still accepted) | advance obs:<slug> (triage an observation) | advance (auto-pick one eligible) | advance <a> <b> (those, in sequence) | advance -n <x> (x eligible, in sequence). Each item: classify (read-only, no model, no lock) → take the `advancing` CAS lock → dispatch winner-only — build/task rungs ORCHESTRATE `do`/`do spec:`, surface/apply always run, triage respects observationTriage (off|ask|auto). The bare/`-n` selection respects the per-action gates (build→autoBuild, task→autoTask, triage→observationTriage); `-n` is ALWAYS sequential (parallelism is `run` / the CI matrix).')
1715
- .argument('[slugs...]', 'the item(s) to advance: bare (= the task), task:<slug>, spec:<slug> (the legacy prd:<slug> is still accepted), or obs:<slug> (an observation). Zero args = auto-pick one eligible; multiple = advance them in sequence.')
1715
+ .description('Advance work/ item(s) one lifecycle rung toward ready/built (SPEC advance-loop), the SEQUENTIAL one-shot driver over the advance tick. advance <slug> (bare = the task) | advance spec:<slug> (the spec tasking rung) | advance obs:<slug> (triage an observation) | advance (auto-pick one eligible) | advance <a> <b> (those, in sequence) | advance -n <x> (x eligible, in sequence). Each item: classify (read-only, no model, no lock) → take the `advancing` CAS lock → dispatch winner-only — build/task rungs ORCHESTRATE `do`/`do spec:`, surface/apply always run, triage respects observationTriage (off|ask|auto). The bare/`-n` selection respects the per-action gates (build→autoBuild, task→autoTask, triage→observationTriage); `-n` is ALWAYS sequential (parallelism is `run` / the CI matrix).')
1716
+ .argument('[slugs...]', 'the item(s) to advance: bare (= the task), task:<slug>, spec:<slug>, or obs:<slug> (an observation). Zero args = auto-pick one eligible; multiple = advance them in sequence.')
1716
1717
  .option('-c, --config <path>', 'config file path', defaultConfigPath())
1717
1718
  .option('--arbiter <remote>', 'name of the arbiter git remote (default: per-repo/global defaultArbiter)')
1718
1719
  .option('-n, --number <x>', 'AUTO-PICK x eligible items and advance them IN SEQUENCE (ordered by selectionOrder, default drain = tasks-first then prds-to-task). Sequential — never a parallelism knob (that is `run` / the CI matrix). Mutually exclusive with naming items.')
1719
1720
  .option('--isolated', "advance in an ISOLATED worktree off THIS repo's arbiter (inferred from cwd) instead of taking over the current checkout, then integrate + reap — the in-place-but-isolated form. Shares the same grammar: a single named item, multiple named items (in sequence), AND -n/auto-pick over the mirror-side eligible-pool scan. Always SEQUENTIAL (parallelism is `run` / the CI matrix). Lets you advance from a busy/dirty checkout or anywhere with a participating arbiter.")
1720
1721
  .option('--selection-order <order>', 'order the auto-pick pools (build/task/surface/triage; apply is always first): a preset keyword (drain (default) | groom) or an explicit comma-separated pool list. Resolved flag > env > per-repo > global > default.')
1721
1722
  .option('--observation-triage <mode>', 'the observation-inbox gate (off|ask|auto): off (default) leaves observations untouched (the triage pool is dropped from auto-pick); ask surfaces a promote/keep/delete question for each untriaged observation; auto auto-disposes the no-question cases (duplicate/map) and asks about the rest. Resolved flag > env > per-repo > global > default. An explicit `advance obs:<slug>` bypasses the selection gate and runs in ask-mode (auto-disposes only under `auto`).')
1722
- .option('--surface-blockers', 'the declared-blocked-work gate (the orthogonal peer of --observation-triage): render a task/prd carrying needsAnswers:true into an answerable question sidecar (the needsAnswers-blocked pool is enumerated into auto-pick). Resolved flag > env > per-repo > global > default off. An explicit `advance <slug>`/`advance prd:<slug>` bypasses this selection gate and surfaces regardless. Does NOT gate apply (an answered sidecar still applies) or needs-attention (always on).')
1723
- .option('--no-surface-blockers', 'leave a needsAnswers:true task/prd silently blocked (default; the blocked pool is dropped from auto-pick)')
1724
- .option('--strict-merge-approval', 'opt in to the host-agnostic "dismiss stale approvals on base change" discipline (prd `land-time-reverify-and-parallel-merge-ceiling` sidecar OQ6): when the merge-base CHANGED between the human’s merge-answer and the apply step, RE-SURFACE the merge-question (clear the answer back to no-answer; re-author the question on main/runner under the advancing lock) instead of auto-landing on a green re-verify. Default OFF (a green re-verify is trusted as sufficient; honour the prior answer). Story #16’s RED-re-verify refusal is UNCHANGED and independent of this flag. Resolved flag > env > per-repo > global > default off.')
1723
+ .option('--surface-blockers', 'the declared-blocked-work gate (the orthogonal peer of --observation-triage): render a task/spec carrying needsAnswers:true into an answerable question sidecar (the needsAnswers-blocked pool is enumerated into auto-pick). Resolved flag > env > per-repo > global > default off. An explicit `advance <slug>`/`advance spec:<slug>` bypasses this selection gate and surfaces regardless. Does NOT gate apply (an answered sidecar still applies) or needs-attention (always on).')
1724
+ .option('--no-surface-blockers', 'leave a needsAnswers:true task/spec silently blocked (default; the blocked pool is dropped from auto-pick)')
1725
+ .option('--strict-merge-approval', 'opt in to the host-agnostic "dismiss stale approvals on base change" discipline (spec `land-time-reverify-and-parallel-merge-ceiling` sidecar OQ6): when the merge-base CHANGED between the human’s merge-answer and the apply step, RE-SURFACE the merge-question (clear the answer back to no-answer; re-author the question on main/runner under the advancing lock) instead of auto-landing on a green re-verify. Default OFF (a green re-verify is trusted as sufficient; honour the prior answer). Story #16’s RED-re-verify refusal is UNCHANGED and independent of this flag. Resolved flag > env > per-repo > global > default off.')
1725
1726
  .option('--no-strict-merge-approval', 'honour the prior merge-answer and land when the rebased tip re-verifies GREEN even if the merge-base changed (default; the cheap green-re-verify-is-enough path)')
1726
1727
  .option('--merge-questions <mode>', 'the merge-question SURFACER gate (off|ask|auto): off drops the surfacer (only for a repo that lands by some other means); ask (default) enumerates unmerged `work/*` branches and surfaces a merge-question sidecar a human answers; auto self-supplies the `merge` answer and lands via the SAME deterministic apply-time re-verify (the merge-mode-like fast path). SEPARATE axis from --observation-triage with a HIGHER default (a dropped merge-question means pushed work never lands). Resolved flag > env > per-repo > global > default ask.')
1727
1728
  .option('--merge', 'integrate the advanced item(s) in merge mode this invocation (mutually exclusive with --propose; overrides config). The CI merge shape is a SINGLE SEQUENTIAL job, so this rides the `-n`/named-sequence path, never the matrix.')
1728
1729
  .option('--propose', 'integrate the advanced item(s) in propose mode this invocation (default; mutually exclusive with --merge; overrides config). The CI propose shape is the parallel matrix (one PR per item).')
1729
- .option('--tasks-land-in <where>', 'where `advance prd:<slug>` tasking output lands: `pre-backlog` (staged) or `ready` (the agent POOL). The EXPLICIT operator override at the top of the placement precedence. Resolved flag > env (DORFL_TASKS_LAND_IN) > per-repo > global > built-in.')
1730
+ .option('--tasks-land-in <where>', 'where `advance spec:<slug>` tasking output lands: `pre-backlog` (staged) or `ready` (the agent POOL). The EXPLICIT operator override at the top of the placement precedence. Resolved flag > env (DORFL_TASKS_LAND_IN) > per-repo > global > built-in.')
1730
1731
  .option('--watch', "stream the build agent's high-signal events live by tailing the pi session log (requires harness: pi; READ-ONLY observer — does not change outcome/gate/git). The same view `do --watch` gives, threaded through the build rung; CI uses it so the job log shows the agent working instead of freezing.")
1731
1732
  .action(async (rawSlugs, flags) => {
1732
1733
  // Variadic grammar (mirrors `do`): zero args = AUTO-PICK; one = the single
@@ -1842,7 +1843,7 @@ export function buildProgram() {
1842
1843
  integration: remoteConfig.integration,
1843
1844
  // EXPLICIT `--merge` override for the untrusted-origin build-propose rule.
1844
1845
  explicitMerge: flagMode === 'merge',
1845
- // Per-TRANSITION TASKING override (the isolated `do --remote prd:` path).
1846
+ // Per-TRANSITION TASKING override (the isolated `do --remote spec:` path).
1846
1847
  taskingIntegration: remoteConfig.taskingIntegration,
1847
1848
  // TASK-PLACEMENT: configured default + EXPLICIT `--tasks-land-in` override
1848
1849
  // (set only when typed, mirroring `explicitMerge`).
@@ -1852,7 +1853,7 @@ export function buildProgram() {
1852
1853
  verify: remoteConfig.verify,
1853
1854
  // Single-job build path: gate the REBASED tip (the default) unconditionally.
1854
1855
  freshWorktreeGate: remoteConfig.freshWorktreeGate,
1855
- // Cross-job merge-serialiser CAS-retry cap — prd
1856
+ // Cross-job merge-serialiser CAS-retry cap — spec
1856
1857
  // `land-time-reverify-and-parallel-merge-ceiling` Story 5.
1857
1858
  mergeRetries: remoteConfig.mergeRetries,
1858
1859
  noPR: remoteConfig.noPR,
@@ -1980,7 +1981,7 @@ export function buildProgram() {
1980
1981
  // EXPLICIT `--merge` override for the untrusted-origin build-propose rule (a
1981
1982
  // bare `advance` auto-pick passes no flag ⇒ unset ⇒ untrusted forces propose).
1982
1983
  explicitMerge: flagMode === 'merge',
1983
- // Per-TRANSITION TASKING override (the `do prd:` tasking path threads
1984
+ // Per-TRANSITION TASKING override (the `do spec:` tasking path threads
1984
1985
  // `taskingIntegration ?? integration`; the build path stays on `integration`).
1985
1986
  taskingIntegration: config.taskingIntegration,
1986
1987
  // TASK-PLACEMENT: configured default + EXPLICIT `--tasks-land-in` override
@@ -1991,7 +1992,7 @@ export function buildProgram() {
1991
1992
  verify: config.verify,
1992
1993
  // Single-job build path: gate the REBASED tip (the default) unconditionally.
1993
1994
  freshWorktreeGate: config.freshWorktreeGate,
1994
- // Cross-job merge-serialiser CAS-retry cap (prd `land-time-reverify-and-
1995
+ // Cross-job merge-serialiser CAS-retry cap (spec `land-time-reverify-and-
1995
1996
  // parallel-merge-ceiling` Story 5 / Applied Answer q1 (a)).
1996
1997
  mergeRetries: config.mergeRetries,
1997
1998
  noPR: config.noPR,
@@ -2118,7 +2119,7 @@ export function buildProgram() {
2118
2119
  .action(async (flags) => {
2119
2120
  const config = resolveGlobalConfig(loadConfig(flags.config), {});
2120
2121
  const workspacesDir = flags.workspace ?? config.workspacesDir;
2121
- // The `gc`-STYLE ledger SWEEP (prd `ledger-integrity` story 3): a SEPARATE
2122
+ // The `gc`-STYLE ledger SWEEP (spec `ledger-integrity` story 3): a SEPARATE
2122
2123
  // surface from the worktree reaper below — it REPORTS one-slug-one-folder
2123
2124
  // violations in a repo's `work/` lifecycle ledger and NEVER deletes (a human
2124
2125
  // resolves each). Distinct `work/`: the ledger, not the execution substrate.
@@ -2126,7 +2127,7 @@ export function buildProgram() {
2126
2127
  const repoPath = typeof flags.ledger === 'string' ? flags.ledger : process.cwd();
2127
2128
  const result = sweepLedgerDuplicates(repoPath);
2128
2129
  // The UNIFIED-LOCK stuck/orphaned-lock REPORT (task
2129
- // `release-lock-verb-and-gc-stuck-report`, prd
2130
+ // `release-lock-verb-and-gc-stuck-report`, spec
2130
2131
  // `ledger-status-per-item-lock-refs` US #12/#13/#14): generalises the
2131
2132
  // advancing-marker report from advancing-only to the unified per-item
2132
2133
  // lock. The locks live on the ARBITER ref (`refs/dorfl/lock/*`),
@@ -2202,7 +2203,7 @@ export function buildProgram() {
2202
2203
  // ALL are REPORTED here (never auto-deleted — no automatic sweep exists; a
2203
2204
  // human clears a NAMED unified lock via `release-lock`).
2204
2205
  //
2205
- // SCOPED to the ATTENTION verdicts only (prd US#14/#21, ADR
2206
+ // SCOPED to the ATTENTION verdicts only (spec US#14/#21, ADR
2206
2207
  // `ledger-status-on-per-item-lock-refs`: this surface is the STUCK /
2207
2208
  // crash-orphaned lock, NOT every held one): a `kept-stuck` (terminal +
2208
2209
  // stuck) or a `cleared-stale`-eligible (terminal + stale active = orphaned)
@@ -2229,7 +2230,7 @@ export function buildProgram() {
2229
2230
  dryRun: flags.dryRun === true,
2230
2231
  note: (message) => console.error(`>> ${message}`),
2231
2232
  });
2232
- // The ORPHAN-SIDECAR sweep (prd
2233
+ // The ORPHAN-SIDECAR sweep (spec
2233
2234
  // `agentic-question-resolution-retire-disposition-vocabulary`, US #10) rides
2234
2235
  // the SAME `--remote-branches` invocation the SCHEDULED CI lifecycle workflow
2235
2236
  // runs (`dorfl gc --remote-branches --arbiter origin`) — so the reap of a
@@ -2427,7 +2428,7 @@ export function buildProgram() {
2427
2428
  .option('--reset', 'DISCARD the kept work: delete the remote work/<slug> branch FIRST, then move to backlog so the next claim starts FRESH (guarded; a deliberate departure from the never-delete-the-remote-branch invariant). Never the default.')
2428
2429
  .option('-m, --message <note>', 'append a dated handoff note to the item body for the next agent (append-only; applies to both default and --reset)')
2429
2430
  .action(async (rawSlug, flags) => {
2430
- // Task-only command (§3a): accept bare + `task:`, reject `prd:`.
2431
+ // Task-only command (§3a): accept bare + `task:`, reject `spec:`.
2431
2432
  const slug = resolveTaskOnlySlug(rawSlug);
2432
2433
  const cwd = flags.cwd ?? process.cwd();
2433
2434
  // Route the requeue (default keep+continue / --reset discard / -m handoff)
@@ -2463,12 +2464,12 @@ export function buildProgram() {
2463
2464
  : ' (kept the work branch; next claim continues from its tip)';
2464
2465
  console.log(`Requeued '${slug}' to backlog for re-claiming.${how}`);
2465
2466
  });
2466
- // `promote [item]` (prd `staging-pool-position-gate-and-trust-model`, tasks
2467
+ // `promote [item]` (spec `staging-pool-position-gate-and-trust-model`, tasks
2467
2468
  // `pre-backlog-staging-folder-and-promote-step-a` /
2468
2469
  // `pre-prd-staging-pool-split-and-untrusted-prd-placement`): the HUMAN/runner-
2469
2470
  // owned verb that moves a STAGED item into its agent-eligible POOL — a task
2470
- // `work/pre-backlog/<slug>.md → work/backlog/<slug>.md`, a prd
2471
- // `work/prds/proposed/<slug>.md → work/prds/ready/<slug>.md` — as a tree-less CAS on the
2471
+ // `work/pre-backlog/<slug>.md → work/backlog/<slug>.md`, a spec
2472
+ // `work/specs/proposed/<slug>.md → work/specs/ready/<slug>.md` — as a tree-less CAS on the
2472
2473
  // arbiter, the SAME trust model + mechanism as `requeue`. The agent emits STAGED;
2473
2474
  // only this verb (a human, or the runner) admits it to the pool. With NO argument
2474
2475
  // it LISTS what is promotable (the "what is staged waiting for me?" discovery), so
@@ -2476,7 +2477,7 @@ export function buildProgram() {
2476
2477
  program
2477
2478
  .command('promote [item]')
2478
2479
  .helpGroup(HEADLINE_GROUP)
2479
- .description('Admit a STAGED item into its agent-eligible POOL (the runner/human side of the staging gate): a task `work/pre-backlog/<slug>.md → work/backlog/<slug>.md`, a prd `work/prds/proposed/<slug>.md → work/prds/ready/<slug>.md`, published as a TREE-LESS compare-and-swap to the arbiter ref (EXACTLY like requeue/claim — it never stages/commits in the cwd tree). The agent only ever CREATES staged; this verb is the gate a human (or the runner) opens. Accepts `task:<slug>` / `prd:<slug>` / a bare `<slug>` (= task). With NO argument, LISTS every promotable item (the tasks in pre-backlog/ + the prds in prds/proposed/ on the arbiter) so you can see what is staged waiting for promotion. Idempotent: promoting an already-pooled slug is a clean no-op success.')
2480
+ .description(`Admit a STAGED item into its agent-eligible POOL (the runner/human side of the staging gate): a task \`work/pre-backlog/<slug>.md → work/backlog/<slug>.md\`, a spec \`${workFolderPrefix('specs-proposed')}<slug>.md → ${workFolderPrefix('specs-ready')}<slug>.md\`, published as a TREE-LESS compare-and-swap to the arbiter ref (EXACTLY like requeue/claim — it never stages/commits in the cwd tree). The agent only ever CREATES staged; this verb is the gate a human (or the runner) opens. Accepts \`task:<slug>\` / \`spec:<slug>\` / a bare \`<slug>\` (= task). With NO argument, LISTS every promotable item (the tasks in pre-backlog/ + the specs in specs/proposed/ on the arbiter) so you can see what is staged waiting for promotion. Idempotent: promoting an already-pooled slug is a clean no-op success.`)
2480
2481
  .option('-c, --config <path>', 'config file path', defaultConfigPath())
2481
2482
  .option('--cwd <dir>', 'the repo/working clone whose arbiter remote the tree-less move is resolved FROM (default: cwd) — an ORIGIN SOURCE only; the move is published to the arbiter, never to this tree')
2482
2483
  .option('--arbiter <remote>', 'the arbiter git remote the promotion is CAS-published to / the staging folders are listed from (default: origin)')
@@ -2495,7 +2496,7 @@ export function buildProgram() {
2495
2496
  process.exit(1);
2496
2497
  }
2497
2498
  if (listed.items.length === 0) {
2498
- console.log(`Nothing staged to promote on ${arbiter}/main (work/pre-backlog/ and work/prds/proposed/ are empty).`);
2499
+ console.log(`Nothing staged to promote on ${arbiter}/main (work/pre-backlog/ and ${workFolderPrefix('specs-proposed')} are empty).`);
2499
2500
  return;
2500
2501
  }
2501
2502
  console.log('Staged, awaiting promotion (run `promote <item>`):');
@@ -2504,11 +2505,10 @@ export function buildProgram() {
2504
2505
  }
2505
2506
  return;
2506
2507
  }
2507
- // AN ITEM → promote it. `task:`/`spec:` are explicit (the legacy `prd:`
2508
- // prefix is still ACCEPTED as an input alias through the cutover — the
2509
- // contract task drops it); a bare slug defaults to a task (mirrors
2510
- // `requeue`). An `obs:`/`observation:` prefix is rejected (observations have
2511
- // no pool).
2508
+ // AN ITEM → promote it. `task:`/`spec:` are explicit; a bare slug defaults to
2509
+ // a task (mirrors `requeue`). An `obs:`/`observation:` prefix is rejected
2510
+ // (observations have no pool). A legacy `prd:` prefix is a DEAD namespace token
2511
+ // after the hard cutover it resolves as a bare literal task slug, not a spec.
2512
2512
  const parsed = parseSlugArg(rawItem);
2513
2513
  if (parsed.explicit === 'observation') {
2514
2514
  console.error(`error: promote takes a task or spec, not an observation ('${rawItem}'). Observations have no agent pool.`);
@@ -2535,7 +2535,7 @@ export function buildProgram() {
2535
2535
  // the `work/advancing/<entry>.md` marker is gone and an advance hold is now just
2536
2536
  // `action: advance` on the UNIFIED per-item lock, so `release-lock <item>` (below)
2537
2537
  // is the SOLE named human release for ALL holds (implement/task/advance).
2538
- // `release-lock <item>` (task `release-lock-verb-and-gc-stuck-report`, prd
2538
+ // `release-lock <item>` (task `release-lock-verb-and-gc-stuck-report`, spec
2539
2539
  // `ledger-status-per-item-lock-refs` US #14): the HUMAN-invoked named release of
2540
2540
  // a stuck/orphaned UNIFIED per-item lock (`refs/dorfl/lock/<entry>`) —
2541
2541
  // the GENERALISATION of `release-advancing` from the advancing-only marker to
@@ -2551,7 +2551,7 @@ export function buildProgram() {
2551
2551
  program
2552
2552
  .command('release-lock <item>')
2553
2553
  .helpGroup(HEADLINE_GROUP)
2554
- .description('Clear a NAMED stuck/orphaned UNIFIED per-item lock (refs/dorfl/lock/<entry>) by DELETING the ref on the arbiter — the recovery verb for a lock the system orphaned (a crashed build/task/advance that left the hold behind). The generalisation of `release-advancing` from the advancing marker to the ONE lock per item. Same trust model as `requeue`: a HUMAN asserts the lock is dead by NAMING it; the tool never guesses liveness (the lock has NO heartbeat, so there is NO automatic sweep / age-based reaper anywhere). Accepts the same item forms as the lock API: `task:<slug>` / `prd:<slug>` / `obs:<slug>` / a bare `<slug>` (= task). Idempotent — re-running on an already-cleared lock is a clean exit-0 no-op (deleting the lock ref is “all locks released”, recoverable). NEVER `--force`. Discoverable via `gc --ledger` (it REPORTS every lingering lock, never deletes).')
2554
+ .description('Clear a NAMED stuck/orphaned UNIFIED per-item lock (refs/dorfl/lock/<entry>) by DELETING the ref on the arbiter — the recovery verb for a lock the system orphaned (a crashed build/task/advance that left the hold behind). The generalisation of `release-advancing` from the advancing marker to the ONE lock per item. Same trust model as `requeue`: a HUMAN asserts the lock is dead by NAMING it; the tool never guesses liveness (the lock has NO heartbeat, so there is NO automatic sweep / age-based reaper anywhere). Accepts the same item forms as the lock API: `task:<slug>` / `spec:<slug>` / `obs:<slug>` / a bare `<slug>` (= task). Idempotent — re-running on an already-cleared lock is a clean exit-0 no-op (deleting the lock ref is “all locks released”, recoverable). NEVER `--force`. Discoverable via `gc --ledger` (it REPORTS every lingering lock, never deletes).')
2555
2555
  .option('-c, --config <path>', 'config file path', defaultConfigPath())
2556
2556
  .option('--cwd <dir>', 'the repo/working clone whose arbiter remote the lock ref is DELETED on (default: cwd)')
2557
2557
  .option('--arbiter <remote>', 'the arbiter git remote the lock ref is deleted on (default: origin)')
@@ -2580,7 +2580,7 @@ export function buildProgram() {
2580
2580
  console.error(`error: ${result.message}`);
2581
2581
  process.exit(1);
2582
2582
  });
2583
- // `drop <slug>` (prd `agentic-question-resolution-retire-disposition-vocabulary`,
2583
+ // `drop <slug>` (spec `agentic-question-resolution-retire-disposition-vocabulary`,
2584
2584
  // US #5/#11; task `direct-delete-question-cli-helper`): the DIRECT "throw it
2585
2585
  // away" verb — `git rm` a source item AND its question sidecar (when present) in
2586
2586
  // ONE revertible commit, the reason in the commit MESSAGE (git history is the
@@ -2594,7 +2594,7 @@ export function buildProgram() {
2594
2594
  program
2595
2595
  .command('drop <slug>')
2596
2596
  .helpGroup(HEADLINE_GROUP)
2597
- .description('DIRECTLY delete a source item + its question sidecar (when present) in ONE revertible commit — the "I just want to throw this away" path that does NOT round-trip through the decision engine or any agent. Resolves the source by its namespaced identity (`task:<slug>` / `prd:<slug>` / `obs:<slug>` / a bare `<slug>` = task), `git rm`s the source AND its sidecar together, and records your --reason in the commit MESSAGE (git history is the archive). A single revertible commit, so a wrong delete is recoverable via `git revert`. DISTINCT from `remote rm` (the hub-mirror deleter). A LOCAL working-tree commit (like the apply rung); it does not touch the arbiter — push/integrate it as you normally would. If the named source is already gone it is a clean no-op (nothing to throw away).')
2597
+ .description('DIRECTLY delete a source item + its question sidecar (when present) in ONE revertible commit — the "I just want to throw this away" path that does NOT round-trip through the decision engine or any agent. Resolves the source by its namespaced identity (`task:<slug>` / `spec:<slug>` / `obs:<slug>` / a bare `<slug>` = task), `git rm`s the source AND its sidecar together, and records your --reason in the commit MESSAGE (git history is the archive). A single revertible commit, so a wrong delete is recoverable via `git revert`. DISTINCT from `remote rm` (the hub-mirror deleter). A LOCAL working-tree commit (like the apply rung); it does not touch the arbiter — push/integrate it as you normally would. If the named source is already gone it is a clean no-op (nothing to throw away).')
2598
2598
  .option('-c, --config <path>', 'config file path', defaultConfigPath())
2599
2599
  .option('--cwd <dir>', 'the working clone the revertible delete commit is made in (default: cwd)')
2600
2600
  .option('--reason <text>', 'why you are throwing this away — recorded in the commit MESSAGE (git history is the archive). Optional; recorded as "(no reason given)" when omitted.')
@@ -2664,7 +2664,7 @@ export function buildProgram() {
2664
2664
  console.error(`>> ${resolved.message}`);
2665
2665
  }
2666
2666
  const config = resolved.config;
2667
- // Resolve the PER-OUTCOME integration modes (prd US #9): `intake` decides
2667
+ // Resolve the PER-OUTCOME integration modes (spec US #9): `intake` decides
2668
2668
  // the artifact TYPE at runtime, so a single --merge/--propose can't express
2669
2669
  // a type-conditional policy. The granular flags override the aggregate; an
2670
2670
  // UNSET type falls back to the per-repo/global `integration` (the SAME chain
@@ -2740,17 +2740,17 @@ export function buildProgram() {
2740
2740
  }
2741
2741
  process.exit(result.exitCode);
2742
2742
  });
2743
- // The CI CLOSE-JOB driver (prd `runner-in-ci`, capability E; task
2743
+ // The CI CLOSE-JOB driver (spec `runner-in-ci`, capability E; task
2744
2744
  // `install-ci-close-job-workflow`). The thin JOB the emitted close-job workflow
2745
2745
  // invokes on a merge to main: resolve which source issue(s) the landed work
2746
- // closes (resolveClosingIssue), run the "prd complete?" query for the prd case
2746
+ // closes (resolveClosingIssue), run the "spec complete?" query for the spec case
2747
2747
  // (prd-complete-query, done), and close via the IssueProvider seam — all
2748
2748
  // UNCHANGED engine pieces, CONSUMED not re-built (the Out-of-Scope fence). CI
2749
2749
  // owns ONLY the job + trigger. Local-runnable too (a manual catch-up close).
2750
2750
  program
2751
2751
  .command('close-merged-issues')
2752
2752
  .helpGroup(ADVANCED_GROUP)
2753
- .description('Close source issues whose work has landed on main (CI capability E, prd runner-in-ci). Resolves each closing issue from the work/ tree (resolveClosingIssue: a lone task closes its own `issue:`; a fanned task reaches the number via `task.prd: → prd issue:`), runs the existing "prd complete?" query for the prd case (closes ONLY when ALL its prd:<slug> tasks are in work/done/), and closes via the IssueProvider seam (atomic comment+close; NO direct gh). Re-implements NONE of the resolution/query/close — it WIRES them. Invoked by the emitted close-job workflow on a merge to main; DEGRADES (never crashes) on a missing/unauthenticated gh.')
2753
+ .description('Close source issues whose work has landed on main (CI capability E, spec runner-in-ci). Resolves each closing issue from the work/ tree (resolveClosingIssue: a lone task closes its own `issue:`; a fanned task reaches the number via `task.spec: → spec issue:`), runs the existing "spec complete?" query for the spec case (closes ONLY when ALL its spec:<slug> tasks are in work/done/), and closes via the IssueProvider seam (atomic comment+close; NO direct gh). Re-implements NONE of the resolution/query/close — it WIRES them. Invoked by the emitted close-job workflow on a merge to main; DEGRADES (never crashes) on a missing/unauthenticated gh.')
2754
2754
  .option('--cwd <dir>', 'the repo working dir whose work/ tree to scan (default: cwd)')
2755
2755
  .option('--gh-bin <bin>', 'the gh CLI binary (default: gh on PATH)')
2756
2756
  .option('--json', 'output the raw result as JSON')