@deksden-com/dd-flow-cli 0.9.0-beta.16 → 0.9.0-beta.161

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 (670) hide show
  1. package/CHANGELOG.md +965 -0
  2. package/README.md +139 -10
  3. package/dist/build-info.json +8 -8
  4. package/dist/cli/argument-values.js +38 -0
  5. package/dist/cli/command-inputs.js +417 -0
  6. package/dist/cli/command-metadata.js +303 -0
  7. package/dist/cli/command-option-descriptions.js +192 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/delivery.js +108 -0
  11. package/dist/cli/diagnostic-invocation.js +62 -0
  12. package/dist/cli/diagnostic.js +131 -0
  13. package/dist/cli/error-output.js +62 -0
  14. package/dist/cli/executor-onboarding.js +76 -0
  15. package/dist/cli/flows.js +29 -0
  16. package/dist/cli/harnesses.js +84 -0
  17. package/dist/cli/help.js +521 -19
  18. package/dist/cli/hook-ingress.js +89 -0
  19. package/dist/cli/input-preparation.js +193 -0
  20. package/dist/cli/interactive-invocation.js +33 -0
  21. package/dist/cli/interactive.js +114 -0
  22. package/dist/cli/memory-fix-invocation.js +52 -0
  23. package/dist/cli/memory-fix.js +100 -0
  24. package/dist/cli/memory-flow-admission.js +54 -0
  25. package/dist/cli/memory-init-invocation.js +85 -0
  26. package/dist/cli/memory-init.js +250 -0
  27. package/dist/cli/memory-storage-admission.js +54 -0
  28. package/dist/cli/memory-storage-qualification.js +105 -0
  29. package/dist/cli/memory-storage-transition.js +123 -0
  30. package/dist/cli/memory-upgrade.js +189 -0
  31. package/dist/cli/models.js +39 -0
  32. package/dist/cli/native-hook-ingress.js +94 -0
  33. package/dist/cli/native-hook-preparation.js +82 -0
  34. package/dist/cli/operator-profiles.js +61 -0
  35. package/dist/cli/output-options.js +35 -0
  36. package/dist/cli/response-file.js +72 -0
  37. package/dist/cli/run-cli.js +2020 -555
  38. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  39. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  40. package/dist/cli/runtime-process.js +153 -0
  41. package/dist/cli/setup.js +150 -0
  42. package/dist/cli.js +103 -2
  43. package/dist/domain/delivery-flows.js +8 -0
  44. package/dist/domain/diagnostic-aspects.js +103 -0
  45. package/dist/domain/diagnostic-flows.js +8 -0
  46. package/dist/domain/distill-flow.js +20 -0
  47. package/dist/domain/interactive-flow.js +1 -0
  48. package/dist/domain/memory-fix-flow.js +2 -0
  49. package/dist/domain/review-fix-flow.js +2 -0
  50. package/dist/domain/source-snapshot-flows.js +4 -0
  51. package/dist/domain/stage-catalog.js +1 -1
  52. package/dist/domain/stage-handler-identities.js +28 -0
  53. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  54. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  55. package/dist/harness-runtime/bin/dd-agy.mjs +71 -0
  56. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  57. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  58. package/dist/harness-runtime/bin/dd-grok.mjs +50 -0
  59. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  60. package/dist/harness-runtime/bin/dd-zcode.mjs +95 -0
  61. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  62. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  63. package/dist/harness-runtime/lib/agy-error-boundary.mjs +87 -0
  64. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  65. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  66. package/dist/harness-runtime/lib/agy-native-inspection.mjs +225 -0
  67. package/dist/harness-runtime/lib/agy-native-inventory.mjs +19 -0
  68. package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
  69. package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +74 -0
  70. package/dist/harness-runtime/lib/agy-transcript-stream.mjs +54 -0
  71. package/dist/harness-runtime/lib/daemon-observation.d.mts +3 -0
  72. package/dist/harness-runtime/lib/daemon-observation.mjs +171 -0
  73. package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
  74. package/dist/harness-runtime/lib/daemon-operations.mjs +512 -0
  75. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +7 -0
  76. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1362 -0
  77. package/dist/harness-runtime/lib/dd-agy.mjs +105 -0
  78. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  79. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +271 -0
  80. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  81. package/dist/harness-runtime/lib/dd-codex.mjs +986 -0
  82. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +155 -0
  83. package/dist/harness-runtime/lib/dd-droid.mjs +739 -0
  84. package/dist/harness-runtime/lib/dd-grok-daemon.d.mts +1 -0
  85. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +667 -0
  86. package/dist/harness-runtime/lib/dd-grok.mjs +182 -0
  87. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +772 -0
  88. package/dist/harness-runtime/lib/dd-opencode.mjs +411 -0
  89. package/dist/harness-runtime/lib/dd-zcode-daemon.d.mts +1 -0
  90. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +845 -0
  91. package/dist/harness-runtime/lib/dd-zcode.mjs +1239 -0
  92. package/dist/harness-runtime/lib/delegation-instructions.d.mts +16 -0
  93. package/dist/harness-runtime/lib/delegation-instructions.mjs +179 -0
  94. package/dist/harness-runtime/lib/delivery-command.mjs +84 -0
  95. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  96. package/dist/harness-runtime/lib/driver-recovery.mjs +121 -0
  97. package/dist/harness-runtime/lib/droid-observation.mjs +70 -0
  98. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  99. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  100. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  101. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  102. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  103. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  104. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +11 -0
  105. package/dist/harness-runtime/lib/lifecycle-contract.mjs +20 -0
  106. package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
  107. package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
  108. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  109. package/dist/harness-runtime/lib/model-observations.mjs +113 -0
  110. package/dist/harness-runtime/lib/native-children.d.mts +34 -0
  111. package/dist/harness-runtime/lib/native-children.mjs +265 -0
  112. package/dist/harness-runtime/lib/native-hook-command.d.mts +8 -0
  113. package/dist/harness-runtime/lib/native-hook-command.mjs +306 -0
  114. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  115. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  116. package/dist/harness-runtime/lib/native-streams.mjs +38 -0
  117. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  118. package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
  119. package/dist/harness-runtime/lib/opencode-plugin.mjs +112 -0
  120. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  121. package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
  122. package/dist/harness-runtime/lib/operation-errors.mjs +140 -0
  123. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  124. package/dist/harness-runtime/lib/operation-progress.mjs +118 -0
  125. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  126. package/dist/harness-runtime/lib/process-json.mjs +200 -0
  127. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  128. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +23 -0
  129. package/dist/harness-runtime/lib/provider-overload-policy.mjs +242 -0
  130. package/dist/harness-runtime/lib/runner-events.mjs +202 -0
  131. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  132. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  133. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  134. package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
  135. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  136. package/dist/harness-runtime/lib/tool-observations.mjs +238 -0
  137. package/dist/harness-runtime/lib/zcode-native-hook-ownership.mjs +109 -0
  138. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  139. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  140. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  141. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  142. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  143. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  144. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  145. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  146. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  147. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  148. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  149. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  150. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  151. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  152. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  153. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  154. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  155. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  156. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  157. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  158. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  159. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  160. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  161. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  162. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  163. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  164. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  165. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  166. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  167. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  168. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  169. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  170. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  171. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  172. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  173. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  174. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  175. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  176. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  177. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  178. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  179. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  180. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  181. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  182. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  183. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  184. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  185. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  186. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  187. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  188. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  189. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  190. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  191. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  192. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  193. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  194. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  195. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  196. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  197. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  198. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  199. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  200. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  201. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  202. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  203. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  204. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  205. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  206. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  207. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  208. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  209. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  210. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  211. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  212. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  213. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  214. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  215. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  216. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  217. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  218. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  219. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  220. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  221. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  222. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  223. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  224. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  225. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  226. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  227. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  228. package/dist/protocol/local-files.js +18 -9
  229. package/dist/runtime/context.js +8 -4
  230. package/dist/schemas/agent-profile.schema.json +1 -1
  231. package/dist/schemas/code-review-decision.schema.json +9 -0
  232. package/dist/schemas/code-review-result.schema.json +1 -1
  233. package/dist/schemas/code-verification.schema.json +7 -5
  234. package/dist/schemas/code-work-batch.schema.json +2 -2
  235. package/dist/schemas/code-work-result.schema.json +2 -1
  236. package/dist/schemas/delivery-stage-result.schema.json +286 -0
  237. package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
  238. package/dist/schemas/diagnostic-work-result.schema.json +296 -0
  239. package/dist/schemas/discovery-result.schema.json +184 -0
  240. package/dist/schemas/distill-stage-result.schema.json +667 -0
  241. package/dist/schemas/distill-work-result.schema.json +428 -0
  242. package/dist/schemas/execution-bundle.schema.json +215 -0
  243. package/dist/schemas/execution-settings.schema.json +162 -0
  244. package/dist/schemas/flow-descriptor.schema.json +54 -0
  245. package/dist/schemas/flow-run.schema.json +29 -0
  246. package/dist/schemas/harness-catalog.schema.json +80 -0
  247. package/dist/schemas/interactive-stage-result.schema.json +47 -0
  248. package/dist/schemas/interactive-work-result.schema.json +63 -0
  249. package/dist/schemas/mb-fix-stage-result.schema.json +93 -0
  250. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  251. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  252. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  253. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  254. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  255. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  256. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  257. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  258. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  259. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  260. package/dist/schemas/memory-repair-work-result.schema.json +56 -0
  261. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  262. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  263. package/dist/schemas/model-catalog.schema.json +153 -0
  264. package/dist/schemas/plan-review-decision.schema.json +12 -3
  265. package/dist/schemas/plan-review-result.schema.json +2 -2
  266. package/dist/schemas/profile-settings.schema.json +122 -0
  267. package/dist/schemas/project-flow-pack-manifest.schema.json +2 -2
  268. package/dist/schemas/release-impact.schema.json +3 -3
  269. package/dist/schemas/release-manifest.schema.json +291 -0
  270. package/dist/schemas/review-fix-stage-result.schema.json +210 -0
  271. package/dist/schemas/run-control-receipt.schema.json +119 -0
  272. package/dist/schemas/run-control-request.schema.json +36 -0
  273. package/dist/schemas/run-engine-binding.schema.json +1 -1
  274. package/dist/schemas/stage-start-response.schema.json +4 -0
  275. package/dist/schemas/vnext-protocol-plan.schema.json +3 -3
  276. package/dist/services/accepted-intent.js +139 -0
  277. package/dist/services/assigned-lifecycle.js +382 -0
  278. package/dist/services/branch-context.js +3 -3
  279. package/dist/services/canon.js +54 -15
  280. package/dist/services/check-environment.js +21 -0
  281. package/dist/services/check-runner-evidence.js +344 -0
  282. package/dist/services/check-runner-proof.js +373 -0
  283. package/dist/services/cleanup.js +133 -40
  284. package/dist/services/cli-operation-classifier.js +32 -64
  285. package/dist/services/cli-upgrade-allowlist.js +27 -0
  286. package/dist/services/code-checks.js +1426 -121
  287. package/dist/services/codex-capacity.js +367 -0
  288. package/dist/services/codex-hook-delivery.js +41 -0
  289. package/dist/services/command-context.js +80 -0
  290. package/dist/services/compatibility-preflight.js +16 -3
  291. package/dist/services/config.js +11 -8
  292. package/dist/services/continuation-outcome.js +25 -0
  293. package/dist/services/controller-child-capacity.js +71 -0
  294. package/dist/services/controller-child-observer.js +121 -0
  295. package/dist/services/controller-child-repair.js +117 -0
  296. package/dist/services/controller-execution.js +97 -0
  297. package/dist/services/controller-fanout.js +277 -0
  298. package/dist/services/controller-memory-task.js +45 -0
  299. package/dist/services/controller-memory-worker.js +51 -0
  300. package/dist/services/controller-result-authority.js +127 -0
  301. package/dist/services/controller-work-failure.js +198 -0
  302. package/dist/services/dashboard.js +145 -58
  303. package/dist/services/delivery-access.js +123 -0
  304. package/dist/services/delivery-approval.js +68 -0
  305. package/dist/services/delivery-artifact.js +86 -0
  306. package/dist/services/delivery-checks.js +178 -0
  307. package/dist/services/delivery-execution.js +181 -0
  308. package/dist/services/delivery-intents.js +212 -0
  309. package/dist/services/delivery-operation.js +81 -0
  310. package/dist/services/delivery-policy.js +91 -0
  311. package/dist/services/delivery-procedures.js +43 -0
  312. package/dist/services/delivery-request.js +99 -0
  313. package/dist/services/delivery-result.js +144 -0
  314. package/dist/services/delivery-stage-commands.js +26 -0
  315. package/dist/services/delivery-stage-entry.js +56 -0
  316. package/dist/services/delivery-stage-handlers.js +135 -0
  317. package/dist/services/delivery-stage-results.js +94 -0
  318. package/dist/services/descriptor-coordinator-session.js +37 -0
  319. package/dist/services/descriptor-root-work.js +53 -0
  320. package/dist/services/descriptor-run-settlement.js +107 -0
  321. package/dist/services/descriptor-run-start.js +495 -0
  322. package/dist/services/descriptor-stage-coordinator.js +318 -0
  323. package/dist/services/descriptor-stage-settlement.js +268 -0
  324. package/dist/services/descriptor-stage-start.js +175 -0
  325. package/dist/services/diagnostic-evidence.js +73 -0
  326. package/dist/services/diagnostic-repair-intake.js +123 -0
  327. package/dist/services/diagnostic-repair-source-intake.js +102 -0
  328. package/dist/services/diagnostic-report-publication.js +72 -0
  329. package/dist/services/diagnostic-report.js +97 -0
  330. package/dist/services/diagnostic-run-bundle.js +113 -0
  331. package/dist/services/diagnostic-snapshot.js +159 -0
  332. package/dist/services/diagnostic-stage-handlers.js +109 -0
  333. package/dist/services/diagnostic-stage-results.js +158 -0
  334. package/dist/services/diagnostic-start.js +134 -0
  335. package/dist/services/diagnostic-work-batch.js +34 -0
  336. package/dist/services/diagnostic-work-collection.js +97 -0
  337. package/dist/services/diagnostic-work-registration.js +101 -0
  338. package/dist/services/diagnostic-work-results.js +93 -0
  339. package/dist/services/discovery/agy-discovery.js +2 -0
  340. package/dist/services/discovery/codex-discovery.js +2 -0
  341. package/dist/services/discovery/droid-discovery.js +2 -0
  342. package/dist/services/discovery/grok-discovery.js +2 -0
  343. package/dist/services/discovery/opencode-discovery.js +2 -0
  344. package/dist/services/discovery/static.js +31 -0
  345. package/dist/services/discovery/zcode-discovery.js +2 -0
  346. package/dist/services/distill-document-publication.js +280 -0
  347. package/dist/services/distill-promotion.js +197 -0
  348. package/dist/services/distill-publication-custody.js +162 -0
  349. package/dist/services/distill-stage-handlers.js +249 -0
  350. package/dist/services/distill-stage-results.js +105 -0
  351. package/dist/services/distill-user-inputs.js +4 -0
  352. package/dist/services/distill-work-batch.js +42 -0
  353. package/dist/services/distill-work-collection.js +74 -0
  354. package/dist/services/distill-work-registration.js +93 -0
  355. package/dist/services/distill-work-results.js +98 -0
  356. package/dist/services/engines.js +354 -163
  357. package/dist/services/eval-snapshots.js +1326 -150
  358. package/dist/services/execution-bundles.js +275 -0
  359. package/dist/services/execution-policy.js +185 -0
  360. package/dist/services/executor-onboarding.js +56 -0
  361. package/dist/services/external-work-launch.js +316 -0
  362. package/dist/services/flow-catalog.js +54 -0
  363. package/dist/services/flow-descriptors.js +82 -0
  364. package/dist/services/frozen-engine.js +404 -0
  365. package/dist/services/generic-execution.js +165 -0
  366. package/dist/services/harness-adapter.js +342 -35
  367. package/dist/services/harness-config.js +2 -0
  368. package/dist/services/harness-discovery.js +29 -0
  369. package/dist/services/harness-doctor.js +75 -0
  370. package/dist/services/harness-probe-effects.js +51 -0
  371. package/dist/services/harness-version-probe.js +100 -0
  372. package/dist/services/hook-memory-routing.js +188 -0
  373. package/dist/services/hook-recovery-guard.js +14 -0
  374. package/dist/services/hook-session-observation.js +24 -0
  375. package/dist/services/hooks.js +813 -327
  376. package/dist/services/hybrid-contracts.js +479 -0
  377. package/dist/services/hybrid-digest.js +14 -0
  378. package/dist/services/ids.js +29 -1
  379. package/dist/services/installation-lock.js +95 -0
  380. package/dist/services/installed-flow-source.js +261 -0
  381. package/dist/services/interactive-attached-session.js +215 -0
  382. package/dist/services/interactive-baseline-custody.js +54 -0
  383. package/dist/services/interactive-before-versions.js +148 -0
  384. package/dist/services/interactive-bundle-data.js +85 -0
  385. package/dist/services/interactive-checks.js +179 -0
  386. package/dist/services/interactive-execution.js +33 -0
  387. package/dist/services/interactive-finish-integration.js +236 -0
  388. package/dist/services/interactive-git-baseline.js +230 -0
  389. package/dist/services/interactive-git-dispatch.js +278 -0
  390. package/dist/services/interactive-input-delivery.js +82 -0
  391. package/dist/services/interactive-mutation-scope.js +231 -0
  392. package/dist/services/interactive-request.js +287 -0
  393. package/dist/services/interactive-run-bundle.js +109 -0
  394. package/dist/services/interactive-stage-entry.js +41 -0
  395. package/dist/services/interactive-stage-handlers.js +289 -0
  396. package/dist/services/interactive-stage-observation.js +136 -0
  397. package/dist/services/interactive-stage-results.js +111 -0
  398. package/dist/services/interactive-user-inputs.js +142 -0
  399. package/dist/services/interactive-work-batch.js +43 -0
  400. package/dist/services/interactive-work-collection.js +119 -0
  401. package/dist/services/interactive-work-completion.js +180 -0
  402. package/dist/services/interactive-work-context.js +249 -0
  403. package/dist/services/interactive-work-history.js +112 -0
  404. package/dist/services/interactive-work-registration.js +124 -0
  405. package/dist/services/interactive-work-results.js +115 -0
  406. package/dist/services/interactive-work-start.js +155 -0
  407. package/dist/services/lanes.js +78 -65
  408. package/dist/services/lifecycle-command.js +1 -288
  409. package/dist/services/lifecycle-contract.js +1 -0
  410. package/dist/services/lifecycle-invocations.js +2549 -0
  411. package/dist/services/managed-daemon-binding.js +129 -0
  412. package/dist/services/managed-lease-monitor.js +133 -0
  413. package/dist/services/managed-processes.js +449 -69
  414. package/dist/services/memory-accepted-composition.js +78 -0
  415. package/dist/services/memory-baseline-preservation.js +65 -0
  416. package/dist/services/memory-completed-correction-wave.js +328 -0
  417. package/dist/services/memory-compose-handler.js +380 -0
  418. package/dist/services/memory-composition-acceptance.js +375 -0
  419. package/dist/services/memory-composition-graph.js +165 -0
  420. package/dist/services/memory-composition-registration.js +161 -0
  421. package/dist/services/memory-composition-work-custody.js +156 -0
  422. package/dist/services/memory-composition-work-results.js +108 -0
  423. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  424. package/dist/services/memory-corrected-review-batch.js +37 -0
  425. package/dist/services/memory-corrected-review-findings.js +108 -0
  426. package/dist/services/memory-corrected-review-inputs.js +215 -0
  427. package/dist/services/memory-corrected-review-projection.js +78 -0
  428. package/dist/services/memory-corrected-review-receipt.js +178 -0
  429. package/dist/services/memory-corrected-review-registration.js +192 -0
  430. package/dist/services/memory-correction-check-receipt.js +235 -0
  431. package/dist/services/memory-correction-input-owner.js +6 -0
  432. package/dist/services/memory-custody-snapshot.js +36 -0
  433. package/dist/services/memory-discover-handler.js +104 -0
  434. package/dist/services/memory-finish-evidence.js +457 -0
  435. package/dist/services/memory-finish-handler.js +229 -0
  436. package/dist/services/memory-finish-integration.js +491 -0
  437. package/dist/services/memory-finish-readiness.js +169 -0
  438. package/dist/services/memory-fix-finish-integration.js +129 -0
  439. package/dist/services/memory-fix-git-dispatch.js +139 -0
  440. package/dist/services/memory-fix-intake-custody.js +11 -0
  441. package/dist/services/memory-fix-intake-settlement.js +127 -0
  442. package/dist/services/memory-fix-publication.js +196 -0
  443. package/dist/services/memory-fix-repair-admission.js +116 -0
  444. package/dist/services/memory-fix-request.js +141 -0
  445. package/dist/services/memory-fix-run-bundle.js +83 -0
  446. package/dist/services/memory-fix-scope.js +78 -0
  447. package/dist/services/memory-fix-sources.js +85 -0
  448. package/dist/services/memory-fix-stage-entry.js +24 -0
  449. package/dist/services/memory-fix-stage-handlers.js +282 -0
  450. package/dist/services/memory-fix-stage-results.js +106 -0
  451. package/dist/services/memory-fix-workspace.js +127 -0
  452. package/dist/services/memory-flow-user-inputs.js +88 -0
  453. package/dist/services/memory-git-integration.js +220 -0
  454. package/dist/services/memory-historical-corrected-review.js +212 -0
  455. package/dist/services/memory-historical-original-review.js +143 -0
  456. package/dist/services/memory-historical-repair-registration.js +105 -0
  457. package/dist/services/memory-historical-second-review.js +147 -0
  458. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  459. package/dist/services/memory-init-contexts.js +181 -0
  460. package/dist/services/memory-init-controller-start.js +119 -0
  461. package/dist/services/memory-init-engine-release.js +223 -0
  462. package/dist/services/memory-init-git-policy.js +165 -0
  463. package/dist/services/memory-init-lint-capability.js +203 -0
  464. package/dist/services/memory-init-native-capacity.js +309 -0
  465. package/dist/services/memory-init-preflight.js +334 -0
  466. package/dist/services/memory-init-project-bootstrap.js +599 -0
  467. package/dist/services/memory-init-request-candidate.js +213 -0
  468. package/dist/services/memory-init-request-input.js +82 -0
  469. package/dist/services/memory-init-resource-storage.js +125 -0
  470. package/dist/services/memory-init-run-allocation.js +81 -0
  471. package/dist/services/memory-init-run-bundle.js +135 -0
  472. package/dist/services/memory-init-start.js +181 -0
  473. package/dist/services/memory-init-startup-custody.js +80 -0
  474. package/dist/services/memory-init-startup-input.js +240 -0
  475. package/dist/services/memory-init-storage.js +91 -0
  476. package/dist/services/memory-init-stores.js +359 -0
  477. package/dist/services/memory-init-worktrunk-capability.js +174 -0
  478. package/dist/services/memory-layer-publication.js +611 -0
  479. package/dist/services/memory-layer.js +225 -0
  480. package/dist/services/memory-lint-config.js +194 -0
  481. package/dist/services/memory-native-review-copy.js +127 -0
  482. package/dist/services/memory-normal-flow-entry.js +87 -0
  483. package/dist/services/memory-ordinary-defaults.js +129 -0
  484. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  485. package/dist/services/memory-preflight-handler.js +274 -0
  486. package/dist/services/memory-repair-current-view.js +299 -0
  487. package/dist/services/memory-repair-document-delta.js +489 -0
  488. package/dist/services/memory-repair-history.js +496 -0
  489. package/dist/services/memory-repair-physical-binding.js +194 -0
  490. package/dist/services/memory-repair-publication-files.js +152 -0
  491. package/dist/services/memory-repair-publication-intent.js +27 -0
  492. package/dist/services/memory-repair-publication-plan.js +162 -0
  493. package/dist/services/memory-repair-publication-source.js +225 -0
  494. package/dist/services/memory-repair-publication.js +795 -0
  495. package/dist/services/memory-repair-registration.js +240 -0
  496. package/dist/services/memory-repair-work-baseline.js +415 -0
  497. package/dist/services/memory-repair-work-completion.js +117 -0
  498. package/dist/services/memory-repair-work-custody.js +73 -0
  499. package/dist/services/memory-repair-work-results.js +108 -0
  500. package/dist/services/memory-repair-workspace.js +261 -0
  501. package/dist/services/memory-repair-writer-copy.js +736 -0
  502. package/dist/services/memory-result-binding.js +239 -0
  503. package/dist/services/memory-retained-review-authority.js +138 -0
  504. package/dist/services/memory-retained-review-results.js +70 -0
  505. package/dist/services/memory-retained-second-baseline.js +102 -0
  506. package/dist/services/memory-retained-second-repairs.js +162 -0
  507. package/dist/services/memory-review-acceptance.js +214 -0
  508. package/dist/services/memory-review-correction-plan.js +206 -0
  509. package/dist/services/memory-review-handler.js +585 -0
  510. package/dist/services/memory-review-inputs.js +246 -0
  511. package/dist/services/memory-review-limits.js +10 -0
  512. package/dist/services/memory-review-receipt.js +180 -0
  513. package/dist/services/memory-review-registration.js +117 -0
  514. package/dist/services/memory-review-work-custody.js +126 -0
  515. package/dist/services/memory-review-work-input.js +91 -0
  516. package/dist/services/memory-review-work-results.js +95 -0
  517. package/dist/services/memory-second-corrected-review-inputs.js +167 -0
  518. package/dist/services/memory-second-correction-plan.js +77 -0
  519. package/dist/services/memory-second-repair-baseline.js +91 -0
  520. package/dist/services/memory-second-repair-launch.js +614 -0
  521. package/dist/services/memory-second-repair-registration.js +88 -0
  522. package/dist/services/memory-second-repair-source.js +187 -0
  523. package/dist/services/memory-second-review-acceptance.js +115 -0
  524. package/dist/services/memory-source-observations.js +117 -0
  525. package/dist/services/memory-stage-dispatch.js +65 -0
  526. package/dist/services/memory-stage-results.js +290 -0
  527. package/dist/services/memory-tool-probe.js +25 -0
  528. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  529. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  530. package/dist/services/memory-upgrade-evidence.js +100 -0
  531. package/dist/services/memory-upgrade-inventory.js +442 -0
  532. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  533. package/dist/services/memory-upgrade-publication.js +413 -0
  534. package/dist/services/memory-upgrade-selection.js +430 -0
  535. package/dist/services/memory-upgrade-start.js +60 -0
  536. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  537. package/dist/services/memory-verification-acceptance.js +156 -0
  538. package/dist/services/memory-verification-checks.js +317 -0
  539. package/dist/services/memory-verification-receipt.js +160 -0
  540. package/dist/services/memory-verify-handler.js +137 -0
  541. package/dist/services/memory-work-result-json.js +12 -0
  542. package/dist/services/memory-work-result-preparation.js +64 -0
  543. package/dist/services/merge-queue.js +228 -149
  544. package/dist/services/merge-server.js +163 -35
  545. package/dist/services/migrations.js +164 -114
  546. package/dist/services/model-catalog.js +109 -0
  547. package/dist/services/model-discovery.js +46 -0
  548. package/dist/services/native-daemon-history.js +50 -0
  549. package/dist/services/native-session-control.js +39 -0
  550. package/dist/services/operator-profiles.js +236 -0
  551. package/dist/services/physical-startup.js +45 -0
  552. package/dist/services/plan-runtime.js +26 -11
  553. package/dist/services/plans.js +28 -25
  554. package/dist/services/project-flow-source.js +195 -0
  555. package/dist/services/project-git-integration.js +92 -0
  556. package/dist/services/project-registry.js +97 -0
  557. package/dist/services/project-summary.js +1 -1
  558. package/dist/services/projects.js +17 -87
  559. package/dist/services/prompt-delivery.js +71 -0
  560. package/dist/services/prompts.js +28 -17
  561. package/dist/services/protocols.js +163 -87
  562. package/dist/services/provider-capacity.js +463 -0
  563. package/dist/services/recovery-observation-budget.js +121 -0
  564. package/dist/services/recovery-snapshot-database.js +588 -0
  565. package/dist/services/release-archive-producer.js +52 -0
  566. package/dist/services/release-archive.js +143 -0
  567. package/dist/services/release-cache.js +150 -0
  568. package/dist/services/release-compatibility.js +18 -0
  569. package/dist/services/release-download.js +67 -0
  570. package/dist/services/release-envelope.js +104 -0
  571. package/dist/services/release-manifest.js +45 -0
  572. package/dist/services/release-payload.js +114 -0
  573. package/dist/services/release-producer.js +63 -0
  574. package/dist/services/release-provenance.js +160 -0
  575. package/dist/services/release-registry.js +66 -0
  576. package/dist/services/release-source.js +194 -0
  577. package/dist/services/repair-intents.js +29 -0
  578. package/dist/services/repair-receipt.js +13 -0
  579. package/dist/services/retained-native-hook.js +274 -0
  580. package/dist/services/review-copy.js +165 -0
  581. package/dist/services/review-deferral.js +23 -0
  582. package/dist/services/review-fix-handoff.js +82 -0
  583. package/dist/services/review-fix-intake-custody.js +17 -0
  584. package/dist/services/review-fix-stage-entry.js +43 -0
  585. package/dist/services/review-fix-stage-handlers.js +176 -0
  586. package/dist/services/review-fix-stage-results.js +86 -0
  587. package/dist/services/run-control-receipt.js +56 -0
  588. package/dist/services/run-control-worker.js +469 -0
  589. package/dist/services/run-control.js +1109 -0
  590. package/dist/services/run-controller-adapter.js +434 -0
  591. package/dist/services/run-controller-capture.js +186 -0
  592. package/dist/services/run-controller-process.js +226 -0
  593. package/dist/services/run-controller-recovery.js +335 -0
  594. package/dist/services/run-controller-state.js +106 -0
  595. package/dist/services/run-controller.js +1717 -0
  596. package/dist/services/run-engine-bindings.js +1 -1
  597. package/dist/services/run-fork.js +147 -0
  598. package/dist/services/run-health.js +149 -0
  599. package/dist/services/run-observations.js +152 -0
  600. package/dist/services/run-projection.js +22 -64
  601. package/dist/services/run-recovery-guard.js +107 -0
  602. package/dist/services/run-recovery-runtime.js +112 -0
  603. package/dist/services/run-recovery.js +485 -0
  604. package/dist/services/run-start-custody.js +189 -0
  605. package/dist/services/run-timeline.js +59 -0
  606. package/dist/services/runs.js +996 -271
  607. package/dist/services/runtime-budget.js +446 -0
  608. package/dist/services/runtime-command.js +43 -0
  609. package/dist/services/runtime-scope-capture.js +52 -0
  610. package/dist/services/runtime-scope-control.js +468 -0
  611. package/dist/services/runtime-scope-resume.js +605 -0
  612. package/dist/services/runtime-scope-stop.js +211 -0
  613. package/dist/services/runtime-scope-worker.js +314 -0
  614. package/dist/services/runtime-service.js +19 -14
  615. package/dist/services/schema-validation.js +10 -8
  616. package/dist/services/scope-writer-cleanup.js +27 -0
  617. package/dist/services/sessions.js +37 -91
  618. package/dist/services/setup.js +427 -0
  619. package/dist/services/stage-blocker.js +17 -7
  620. package/dist/services/stage-context.js +240 -18
  621. package/dist/services/stage-handlers.js +141 -0
  622. package/dist/services/stage-lifecycle.js +156 -119
  623. package/dist/services/stage-pause.js +222 -94
  624. package/dist/services/stage-report-renderer.js +230 -6
  625. package/dist/services/stage-work-graph.js +52 -0
  626. package/dist/services/technical-notes.js +31 -0
  627. package/dist/services/tooling.js +111 -44
  628. package/dist/services/usage.js +49 -101
  629. package/dist/services/verification-matrix.js +393 -0
  630. package/dist/services/version-status.js +1 -1
  631. package/dist/services/vnext-code-review.js +302 -91
  632. package/dist/services/vnext-code.js +325 -251
  633. package/dist/services/vnext-contracts.js +10 -1
  634. package/dist/services/vnext-execution-profile.js +80 -5
  635. package/dist/services/vnext-fanout.js +399 -20
  636. package/dist/services/vnext-merge.js +336 -114
  637. package/dist/services/vnext-plan-review.js +288 -133
  638. package/dist/services/vnext-plan.js +257 -110
  639. package/dist/services/vnext-protocolize.js +534 -96
  640. package/dist/services/vnext-specify.js +131 -84
  641. package/dist/services/vnext-workspace-policy.js +7 -2
  642. package/dist/services/work-registry.js +1950 -215
  643. package/dist/services/work-retry-context.js +55 -0
  644. package/dist/services/workspace-bootstrap.js +53 -15
  645. package/dist/services/workspace-files.js +85 -0
  646. package/dist/services/worktrees.js +108 -48
  647. package/dist/shared/entity-references.js +1 -0
  648. package/dist/shared/errors.js +27 -0
  649. package/dist/storage/agent-output.js +26 -0
  650. package/dist/storage/data-preservation.js +65 -0
  651. package/dist/storage/database.js +931 -40
  652. package/dist/storage/foreign-key-transaction.js +39 -0
  653. package/dist/storage/immutable-input.js +45 -0
  654. package/dist/storage/import-guard.js +159 -0
  655. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  656. package/dist/storage/native-cleanup.js +52 -0
  657. package/dist/storage/paired-writer-migration.js +424 -0
  658. package/dist/storage/paths.js +17 -4
  659. package/dist/storage/projection-lock.js +73 -0
  660. package/dist/storage/work-references.js +23 -0
  661. package/dist/storage/writer-contract.js +96 -0
  662. package/dist/storage/writer-migration.js +346 -0
  663. package/dist/storage/writer-restore.js +217 -0
  664. package/dist/verification-components.json +384 -0
  665. package/package.json +52 -13
  666. package/tools/create-canon-release.mjs +33 -0
  667. package/tools/probe-codex-history.mjs +37 -0
  668. package/tools/produce-hybrid-release.mjs +41 -0
  669. package/tools/repair-paused-run-status.mjs +84 -0
  670. package/tools/verification-jobs.mjs +342 -0
@@ -1,24 +1,35 @@
1
+ import { managedLifecycleCommand } from "./lifecycle-invocations.js";
2
+ import { stageLifecycleInstruction } from "../harness-runtime/lib/delegation-instructions.mjs";
1
3
  import crypto from "node:crypto";
2
4
  import fs from "node:fs";
3
5
  import path from "node:path";
4
- import { execFileSync } from "node:child_process";
5
6
  import { AppError } from "../shared/errors.js";
7
+ import { assertCheckDiagnosisEligible } from "./check-runner-evidence.js";
6
8
  import { resolveProjectRoot } from "../storage/paths.js";
7
9
  import { requireProjectByRoot } from "./projects.js";
8
- import { advanceFlowRun, appendFlowRunTimelineEvent, attachFlowRunStage, completeFlowRun, completeFlowRunStage, freezeFlowRunReviewMode, gitFacts } from "./runs.js";
10
+ import { advanceFlowRun, appendFlowRunTimelineEvent, attachFlowRunStage, completeFlowRun, completeFlowRunStage, prepareFlowRunStageCompletion, freezeFlowRunReviewMode, gitFacts } from "./runs.js";
9
11
  import { validateSchema } from "./schema-validation.js";
10
- import { flowCommand } from "./stage-pause.js";
11
- import { assertStageStartHookEvent } from "./hooks.js";
12
+ import { runtimeCommand, checkRetryArgs } from "./runtime-command.js";
13
+ import { assertAssignedStageStart as assertStageStartHookEvent } from "./assigned-lifecycle.js";
12
14
  import { requireVnextWorkspaceRoute } from "./vnext-workspace-policy.js";
13
- import { addVnextCodeRepair } from "./vnext-code.js";
14
- import { finalCodeCheckDeclarations, runCodeChecks, unchangedFinalGateFailures, validateFailedCheckRetry, workspaceFingerprint } from "./code-checks.js";
15
- import { addWorkBatch, bindStageCoordinatorWork, finishWork, refreshRunWorkProjection } from "./work-registry.js";
15
+ import { addVnextCodeRepair, prepareVnextCodeRepair, registerAggregateCodeRepair, resumeAcceptedCodeStage } from "./vnext-code.js";
16
+ import { finalCodeCheckDeclarations, runCodeChecks, validateFailedCheckRetry, workspaceChangedPaths, workspaceFingerprint } from "./code-checks.js";
17
+ import { addWorkBatch, prepareWorkBatch, bindStageCoordinatorWork, finishStageCoordinatorWork, refreshRunWorkProjection } from "./work-registry.js";
18
+ import { withStageSettlement, prepareFlowRunStageAttachment } from "./runs.js";
16
19
  import { vnextStageDirectory } from "../domain/stage-catalog.js";
17
- import { writeStageReport } from "./stage-report-renderer.js";
18
- import { applyExternalStageContext } from "./stage-context.js";
20
+ import { acceptStageReport, prepareStageReport } from "./stage-report-renderer.js";
21
+ import { prepareRunVerificationMatrix, acceptVerificationMatrix, commitVerificationMatrixStart, resumeVerificationMatrix, verificationMatrixInstruction, latestRunVerificationMatrix, publishVerificationMatrix } from "./verification-matrix.js";
22
+ import { currentStagePrompt, applyExternalStageContext, prepareExternalStageContext } from "./stage-context.js";
19
23
  import { readFanoutDescriptor, writeFanoutDescriptor } from "./vnext-fanout.js";
20
- import { ensureVnextMergeRequest } from "./vnext-merge.js";
24
+ import { stageGraphScope } from "./stage-work-graph.js";
25
+ import { prepareVnextMergeRequest } from "./vnext-merge.js";
21
26
  import { validateVnextCodeHandoff } from "./vnext-plan.js";
27
+ import { assertRunMutationAllowed } from "./run-recovery.js";
28
+ import { prepareJsonFile, prepareOutputFile } from "../cli/input-preparation.js";
29
+ import { reviewerSourceInputs, reviewerSourceInstruction } from "./review-copy.js";
30
+ import { reviewDefEvidence } from "./review-deferral.js";
31
+ import { acceptedIntentReviewFingerprint, validateAcceptedIntentReview, assertAcceptedIntentReviewCurrent } from "./accepted-intent.js";
32
+ import { stageSuccessor } from "./vnext-contracts.js";
22
33
  const stage = "code-review";
23
34
  const stageDir = vnextStageDirectory(stage);
24
35
  const baselineAspects = ["goal_traceability", "coding_standards_design_review", "verification_evidence_review"];
@@ -26,57 +37,93 @@ export function isVnextCodeReviewRun(context, input) {
26
37
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
27
38
  return Boolean(context.db.get("SELECT id FROM runs WHERE project_id = ? AND id = ? AND flow_kind = 'vnext_protocolize'", [project.id, input.runId]));
28
39
  }
29
- export function startVnextCodeReview(context, input) {
40
+ export function prepareVnextCodeReviewStart(context, input) {
30
41
  const projectRoot = resolveProjectRoot(input.projectRoot);
31
42
  const project = requireProjectByRoot(context, projectRoot);
32
43
  const run = requireRun(context, project.id, input.runId);
33
44
  const home = requireHome(run);
34
- assertStageStartHookEvent(context, { projectId: project.id, eventKey: input.hookEventId, runId: run.id, stage, projectRoot, ...(input.contextSha256 ? { contextSha256: input.contextSha256 } : {}) });
35
- requireVnextWorkspaceRoute({ projectRoot, runId: run.id, runHome: home, workspaceRoot: run.workspace_root, stage });
45
+ assertRunMutationAllowed(context, project.id, run.id);
46
+ requireVnextWorkspaceRoute(context, { projectRoot, runId: run.id, runHome: home, workspaceRoot: run.workspace_root, stage });
36
47
  if (!fs.existsSync(path.join(home, "05-code", "stage-report.json")))
37
- throw new AppError("not_found", "CODE-REVIEW requires an accepted CODE report", 1);
48
+ throw new AppError("runtime_artifact_missing", "CODE-REVIEW requires an accepted CODE report", 1);
38
49
  const root = path.join(home, stageDir);
39
- fs.mkdirSync(root, { recursive: true });
40
50
  const rootWork = requireRootWork(context, project.id, run.id);
41
51
  const prior = stageStatus(run, stage);
42
52
  const existingPrompt = path.join(root, "stage-prompt.md");
43
- if (prior && fs.existsSync(existingPrompt)) {
44
- const externalContext = applyExternalStageContext({ stageRoot: root, promptPath: existingPrompt, ...(input.externalContext ? { loaded: input.externalContext } : {}) });
45
- const binding = bindStageCoordinatorWork(context, { workId: rootWork.work_id, hookEventId: input.hookEventId, stage, promptPath: existingPrompt, resultPath: path.join(root, "stage-report.json"), ...(input.contextSha256 ? { contextSha256: input.contextSha256 } : {}) });
46
- const prompt = fs.readFileSync(existingPrompt, "utf8");
47
- const orchestration = readFanoutDescriptor(root);
48
- return { ok: true, resumed: true, run_id: run.id, stage, stage_status: prior, id: binding.work_session_id, prompt_path: existingPrompt, worker_prompt_markdown: prompt, ...(externalContext ? { external_context: externalContext } : {}), ...(orchestration ? { orchestration } : {}), next: { finish_command: finishCommand(context, run.id, projectRoot, path.join(root, "decision.json")) } };
49
- }
53
+ if (input.externalContext)
54
+ prepareExternalStageContext({ stageRoot: root, loaded: input.externalContext });
55
+ prepareOutputFile(existingPrompt);
56
+ const common = { projectRoot, project, run, home, root, rootWork, existingPrompt };
57
+ if (prior && fs.existsSync(existingPrompt))
58
+ return { ...common, resumed: true, prior, prompt: fs.readFileSync(existingPrompt, "utf8"), orchestration: readFanoutDescriptor(root) };
59
+ const attachment = prepareFlowRunStageAttachment(context, { projectRoot, runId: run.id, stage, dir: stageDir, status: "running", dataSchemaId: "dd-flow/stage-report@1" });
50
60
  const mode = effectiveMode(home, run);
51
61
  const cycle = reviewCycle(run);
62
+ const codeReportSha256 = sha256File(path.join(home, "05-code", "stage-report.json"));
63
+ const groups = mode.mode === "off" ? [] : reviewGroups(home);
64
+ const reviewerInputs = mode.mode === "off" ? [] : reviewerSourceInputs(run.workspace_root, groups.flatMap(group => group.aspect_ids));
65
+ const batch = { works: groups.map((group, index) => ({ key: `code-review-${index + 1}`, task: `${reviewerTask(home, group)}\n${reviewerSourceInstruction(run.workspace_root, group.aspect_ids)}`, launch_policy: "fresh_agent_required", result_schema: "dd-flow/code-review-result@1", payload: { kind: "code-review", review_cycle: cycle, group, read_only: true } })) };
66
+ const items = mode.mode === "off" ? [] : prepareWorkBatch(context, { parentWorkId: rootWork.work_id, value: batch });
67
+ const template = mode.mode === "off" ? "" : read(path.join(run.workspace_root, ".memory-bank", "dd-flow", "vnext", "code-review.md"));
68
+ const checks = mode.mode === "off" ? [] : acceptedCodeChecks(context, project.id, run.id).map(({ id, purpose }) => ({ id, purpose }));
69
+ for (const name of ["review-context.json", ...(mode.mode === "off" ? ["decision.json"] : ["review-work-batch.json", "fanout.json"])])
70
+ prepareOutputFile(path.join(root, name));
71
+ const matrix = mode.mode === "off" ? null : prepareRunVerificationMatrix(context, { projectId: project.id, runId: run.id, stage, role: "input", stageAttempt: attachment.attempt });
72
+ return { ...common, resumed: false, mode, cycle, codeReportSha256, groups, batch, items, template, checks, matrix, reviewerInputs };
73
+ }
74
+ export function startVnextCodeReview(context, input, prepared = prepareVnextCodeReviewStart(context, input)) {
75
+ const { projectRoot, project, run, root, rootWork, existingPrompt } = prepared;
76
+ assertRunMutationAllowed(context, project.id, run.id);
77
+ assertStageStartHookEvent(context, { projectId: project.id, eventKey: input.hookEventId, runId: run.id, stage, projectRoot, ...(input.contextSha256 ? { contextSha256: input.contextSha256 } : {}) });
78
+ fs.mkdirSync(root, { recursive: true });
79
+ if (prepared.resumed) {
80
+ if (effectiveMode(prepared.home, run).mode !== "off")
81
+ resumeVerificationMatrix(context, project.id, run.id, stage);
82
+ const externalContext = applyExternalStageContext({ context, stageRoot: root, promptPath: existingPrompt, ...(input.externalContext ? { loaded: input.externalContext } : {}) });
83
+ const binding = bindStageCoordinatorWork(context, { workId: rootWork.work_id, hookEventId: input.hookEventId, stage, promptPath: existingPrompt, resultPath: path.join(root, "stage-report.json"), ...(input.contextSha256 ? { contextSha256: input.contextSha256 } : {}) });
84
+ const delivered = currentStagePrompt(context, existingPrompt);
85
+ const orchestration = prepared.orchestration;
86
+ return { ok: true, resumed: true, run_id: run.id, stage, stage_status: prepared.prior, id: binding.work_session_id, ...delivered, ...(externalContext ? { external_context: externalContext } : {}), ...(orchestration ? { orchestration } : {}), next: { finish_command: finishCommand(context, run.id, projectRoot, path.join(root, "decision.json")) } };
87
+ }
88
+ const { mode, cycle, groups, batch, items, template, checks, codeReportSha256 } = prepared;
89
+ prepareFlowRunStageAttachment(context, { projectRoot, runId: run.id, stage, dir: stageDir, status: "running", dataSchemaId: "dd-flow/stage-report@1" }, true);
90
+ const aspectMapChecksums = mode.mode === "off" ? [] : fs.readdirSync(path.join(run.run_root, "03-plan"), { withFileTypes: true })
91
+ .filter(entry => entry.isDirectory() && fs.existsSync(path.join(run.run_root, "03-plan", entry.name, "aspect-map.json")))
92
+ .map(entry => ({ path: `03-plan/${entry.name}/aspect-map.json`, sha256: sha256File(path.join(run.run_root, "03-plan", entry.name, "aspect-map.json")) }))
93
+ .sort((a, b) => a.path.localeCompare(b.path));
52
94
  freezeFlowRunReviewMode(context, { projectRoot, runId: run.id, review: "code", mode: mode.mode, source: mode.source, reason: mode.reason });
53
95
  const promptPath = path.join(root, "stage-prompt.md");
54
96
  const reviewContextPath = path.join(root, "review-context.json");
55
- fs.writeFileSync(reviewContextPath, `${JSON.stringify({ schema_id: "dd-flow/code-review-context@1", cycle, mode: mode.mode, mode_source: mode.source, mode_reason: mode.reason, workspace_fingerprint: workspaceFingerprint(run.workspace_root), code_report_sha256: sha256File(path.join(home, "05-code", "stage-report.json")) }, null, 2)}\n`);
97
+ fs.writeFileSync(reviewContextPath, `${JSON.stringify({ schema_id: "dd-flow/code-review-context@1", accepted_intent_review_fingerprint: acceptedIntentReviewFingerprint(prepared.matrix?.metadata.accepted_sources), reviewer_inputs: prepared.reviewerInputs, cycle, mode: mode.mode, mode_source: mode.source, mode_reason: mode.reason, ...(mode.mode !== "off" ? { read_only_input: { parent_work_id: rootWork.work_id, version: 3 } } : {}), code_report_sha256: codeReportSha256, review_batch_sha256: sha256Value(`${JSON.stringify(batch, null, 2)}\n`), aspect_map_checksums: aspectMapChecksums }, null, 2)}\n`);
56
98
  if (mode.mode === "off") {
57
- const prompt = `<stage_identity>\n- RUN: ${run.id}\n- stage: code-review\n- mode: off\n</stage_identity>\n\nCODE-REVIEW is disabled by the frozen RUN configuration. Finish with: ${finishCommand(context, run.id, projectRoot, path.join(root, "decision.json"))}\n`;
99
+ fs.writeFileSync(path.join(root, "decision.json"), `${JSON.stringify(disabledReviewDecision(), null, 2)}\n`);
100
+ const prompt = `<stage_identity>\n- RUN: ${run.id}\n- stage: code-review\n- mode: off\n</stage_identity>\n\nCODE-REVIEW is disabled by the frozen RUN configuration. Finish with: ${finishCommand(context, run.id, projectRoot, path.join(root, "decision.json"))}\n${stageLifecycleInstruction}\n`;
58
101
  fs.writeFileSync(promptPath, prompt);
59
- const externalContext = applyExternalStageContext({ stageRoot: root, promptPath, ...(input.externalContext ? { loaded: input.externalContext } : {}) });
102
+ const externalContext = applyExternalStageContext({ context, stageRoot: root, promptPath, ...(input.externalContext ? { loaded: input.externalContext } : {}) });
60
103
  const binding = bindStageCoordinatorWork(context, { workId: rootWork.work_id, hookEventId: input.hookEventId, stage, promptPath, resultPath: path.join(root, "stage-report.json"), ...(input.contextSha256 ? { contextSha256: input.contextSha256 } : {}) });
61
- attachFlowRunStage(context, { projectRoot, runId: run.id, stage, dir: stageDir, status: "running", dataSchemaId: "dd-flow/stage-report@1" });
62
- return { ok: true, run_id: run.id, stage, mode: mode.mode, mode_source: mode.source, id: binding.work_session_id, prompt_path: promptPath, worker_prompt_markdown: fs.readFileSync(promptPath, "utf8"), ...(externalContext ? { external_context: externalContext } : {}), next: { finish_command: finishCommand(context, run.id, projectRoot, path.join(root, "decision.json")) } };
104
+ const attachmentInput = { projectRoot, runId: run.id, stage, dir: stageDir, status: "running", dataSchemaId: "dd-flow/stage-report@1" };
105
+ attachFlowRunStage(context, attachmentInput, prepareFlowRunStageAttachment(context, attachmentInput));
106
+ return { ok: true, run_id: run.id, stage, mode: mode.mode, mode_source: mode.source, id: binding.work_session_id, ...currentStagePrompt(context, promptPath), ...(externalContext ? { external_context: externalContext } : {}), next: { finish_command: finishCommand(context, run.id, projectRoot, path.join(root, "decision.json")) } };
63
107
  }
64
- const groups = reviewGroups(home);
65
- const batch = { works: groups.map((group, index) => ({ key: `code-review-${index + 1}`, task: reviewerTask(home, group), launch_policy: "fresh_agent_required", result_schema: "dd-flow/code-review-result@1", payload: { kind: "code-review", review_cycle: cycle, group, read_only: true } })) };
66
108
  const batchFile = path.join(root, "review-work-batch.json");
67
109
  fs.writeFileSync(batchFile, `${JSON.stringify(batch, null, 2)}\n`);
68
- const prompt = orchestratorPrompt(context, { projectRoot, run, root, rootWork, mode: mode.mode, groups });
110
+ const prompt = `${orchestratorPrompt(context, { projectRoot, run, root, rootWork, mode: mode.mode, groups, template, checks })}\n${stageLifecycleInstruction}\n${verificationMatrixInstruction(prepared.matrix?.metadata ?? null, prepared.home, "reviewing whether current evidence proves the accepted obligations")}\n`;
69
111
  fs.writeFileSync(promptPath, prompt);
70
- const externalContext = applyExternalStageContext({ stageRoot: root, promptPath, ...(input.externalContext ? { loaded: input.externalContext } : {}) });
112
+ const externalContext = applyExternalStageContext({ context, stageRoot: root, promptPath, ...(input.externalContext ? { loaded: input.externalContext } : {}) });
71
113
  const binding = bindStageCoordinatorWork(context, { workId: rootWork.work_id, hookEventId: input.hookEventId, stage, promptPath, resultPath: path.join(root, "stage-report.json"), ...(input.contextSha256 ? { contextSha256: input.contextSha256 } : {}) });
72
- const registered = addWorkBatch(context, { parentWorkId: rootWork.work_id, file: batchFile });
73
- const orchestration = writeFanoutDescriptor(root, { stage, parent_work_id: rootWork.work_id, dispatch: "none", capacity_required: true });
74
- attachFlowRunStage(context, { projectRoot, runId: run.id, stage, dir: stageDir, status: "running", dataSchemaId: "dd-flow/stage-report@1" });
114
+ const registered = addWorkBatch(context, { parentWorkId: rootWork.work_id, value: batch, prepared: items, stage, cycle });
115
+ const orchestration = writeFanoutDescriptor(root, { stage, parent_work_id: rootWork.work_id, dispatch: "none", capacity_required: true, scope: stageGraphScope(context, project.id, run.id, stage) });
116
+ const attachmentInput = { projectRoot, runId: run.id, stage, dir: stageDir, status: "running", dataSchemaId: "dd-flow/stage-report@1", inputSha256: sha256Value(JSON.stringify({ batch: sha256File(batchFile), aspect_maps: aspectMapChecksums })) };
117
+ const attachment = prepareFlowRunStageAttachment(context, attachmentInput);
118
+ commitVerificationMatrixStart(context, prepared.matrix, () => attachFlowRunStage(context, attachmentInput, attachment));
75
119
  appendFlowRunTimelineEvent(context, project.id, run.id, { type: "code_review_started", work_id: rootWork.work_id, mode: mode.mode, mode_source: mode.source, groups, registered });
76
- return { ok: true, run_id: run.id, stage, mode: mode.mode, mode_source: mode.source, id: binding.work_session_id, prompt_path: promptPath, worker_prompt_markdown: fs.readFileSync(promptPath, "utf8"), ...(externalContext ? { external_context: externalContext } : {}), orchestration, review: { groups, works: registered }, next: { finish_command: finishCommand(context, run.id, projectRoot, path.join(root, "decision.json")) } };
120
+ return { ok: true, run_id: run.id, stage, mode: mode.mode, mode_source: mode.source, id: binding.work_session_id, ...currentStagePrompt(context, promptPath), ...(externalContext ? { external_context: externalContext } : {}), orchestration, review: { groups, works: registered }, next: { finish_command: finishCommand(context, run.id, projectRoot, path.join(root, "decision.json")) } };
77
121
  }
78
- /** Create a narrow CODE repair from accepted independent-review evidence. */
79
- export function addVnextCodeReviewRepair(context, input) {
122
+ export function prepareVnextCodeReviewRepair(context, input) {
123
+ if (!Array.isArray(input.findingIds) || !input.findingIds.length || input.findingIds.some(id => typeof id !== "string" || !id.trim()))
124
+ throw new AppError("validation", "Repair requires nonempty finding IDs", 2);
125
+ if (!input.checkRefsByFinding || typeof input.checkRefsByFinding !== "object" || Array.isArray(input.checkRefsByFinding) || Object.entries(input.checkRefsByFinding).some(([id, refs]) => !input.findingIds.includes(id) || !Array.isArray(refs) || refs.some(ref => typeof ref !== "string" || !ref.trim())))
126
+ throw new AppError("validation", "Repair check references must map selected findings to check IDs", 2);
80
127
  const projectRoot = resolveProjectRoot(input.projectRoot);
81
128
  const project = requireProjectByRoot(context, projectRoot);
82
129
  const run = requireRun(context, project.id, input.runId);
@@ -100,10 +147,8 @@ export function addVnextCodeReviewRepair(context, input) {
100
147
  const unknown = requestedCheckRefs.filter((ref) => !checks.has(ref));
101
148
  if (unknown.length)
102
149
  throw new AppError("review_check_reference_unknown", "CODE-REVIEW finding cites a check absent from the accepted CODE handoff", 2, { check_refs: unknown });
103
- const reviewChecks = requestedCheckRefs.map((ref) => checks.get(ref)).filter((check) => check.run_at !== "external");
104
- if (!reviewChecks.length)
105
- throw new AppError("review_repair_executable_check_required", "CODE-REVIEW repair requires at least one executable causal check; external-only evidence cannot validate a repair Work", 2, { finding_ids: input.findingIds, check_refs: requestedCheckRefs });
106
- return addVnextCodeRepair(context, {
150
+ const reviewChecks = requestedCheckRefs.map((ref) => checks.get(ref));
151
+ const repairInput = {
107
152
  projectRoot,
108
153
  runId: run.id,
109
154
  reviewFindings: selected.map(({ finding_ref, finding }) => ({ finding_ref, priority: finding.priority, problem: finding.problem, impact: finding.impact, required_outcome: finding.required_outcome, evidence_refs: finding.evidence_refs, obligation_refs: finding.obligation_refs, decision_reason: input.decisionReasonsByFinding?.[finding_ref] ?? input.objective, check_refs: input.checkRefsByFinding[finding_ref] ?? [] })),
@@ -111,7 +156,11 @@ export function addVnextCodeReviewRepair(context, input) {
111
156
  originWorkIds: origins,
112
157
  objective: input.objective,
113
158
  reviewCycle: reviewCycle(run)
114
- });
159
+ };
160
+ return { input: repairInput, value: prepareVnextCodeRepair(context, repairInput) };
161
+ }
162
+ export function addVnextCodeReviewRepair(context, input, prepared = prepareVnextCodeReviewRepair(context, input)) {
163
+ return addVnextCodeRepair(context, prepared.input, prepared.value);
115
164
  }
116
165
  export async function finishVnextCodeReview(context, input) {
117
166
  const projectRoot = resolveProjectRoot(input.projectRoot);
@@ -119,6 +168,14 @@ export async function finishVnextCodeReview(context, input) {
119
168
  const run = requireRun(context, project.id, input.runId);
120
169
  const home = requireHome(run);
121
170
  const root = path.join(home, stageDir);
171
+ const generation = assertRunMutationAllowed(context, project.id, run.id);
172
+ const reportPath = path.join(root, "stage-report.json");
173
+ if (stageStatus(run, stage) === "done" && fs.existsSync(reportPath)) {
174
+ const report = readJson(reportPath);
175
+ const next = report.semantic?.next_action ?? "code_review_completed";
176
+ resumeAcceptedCodeStage(context, run, projectRoot, stage, report, next);
177
+ return { ok: true, resumed: true, run_id: run.id, stage, outcome: "accepted", report_path: reportPath, next_action: next };
178
+ }
122
179
  const reviewContext = readJson(path.join(root, "review-context.json"));
123
180
  const mode = reviewContext.mode;
124
181
  if (!mode)
@@ -128,90 +185,163 @@ export async function finishVnextCodeReview(context, input) {
128
185
  const handoffFailures = validateVnextCodeHandoff(context, { projectRoot, workspaceRoot: run.workspace_root, runId: run.id, home });
129
186
  if (handoffFailures.length)
130
187
  throw new AppError("validation", "CODE-REVIEW handoff no longer matches the accepted PLAN", 2, { errors: handoffFailures });
131
- const reportPath = path.join(root, "stage-report.json");
132
- if (stageStatus(run, stage) === "done" && fs.existsSync(reportPath)) {
133
- const report = readJson(reportPath);
134
- return { ok: true, resumed: true, run_id: run.id, stage, outcome: "accepted", report_path: reportPath, next_action: report.semantic?.next_action ?? "code_review_completed" };
135
- }
136
188
  const rootWork = requireRootWork(context, project.id, run.id);
137
189
  const coordinator = context.db.get("SELECT session_id, result_path FROM work_sessions WHERE work_id = ? AND status = 'running' ORDER BY created_at DESC LIMIT 1", [rootWork.work_id]);
138
190
  if (!coordinator || path.resolve(coordinator.result_path ?? "") !== path.resolve(reportPath))
139
191
  throw new AppError("code_review_session_binding_conflict", "CODE-REVIEW can finish only after its successful stage start bound the coordinator Session and report path", 1, { run_id: run.id, expected_result_path: reportPath, actual_result_path: coordinator?.result_path ?? null });
140
- const decisionFile = input.decisionFile ?? path.join(root, "decision.json");
141
- if (!fs.existsSync(decisionFile) && mode === "off")
142
- fs.writeFileSync(decisionFile, `${JSON.stringify({ schema_id: "dd-flow/code-review-decision@3", summary: "CODE-REVIEW is disabled by RUN configuration.", findings: [] }, null, 2)}\n`);
143
- validateSchema({ schemaName: "code-review-decision", file: decisionFile, projectRoot: run.workspace_root, ddFlowHome: context.ddFlowHome, runId: run.id, runRoot: home });
144
- const decision = readJson(decisionFile);
192
+ const decisionFile = path.resolve(input.decisionFile ?? path.join(root, "decision.json"));
193
+ const disabledDecision = disabledReviewDecision();
194
+ // The implicit review-off decision is the one deliberate no-file path. An
195
+ // explicitly supplied --decision-file is still caller input and must be
196
+ // readable before any lifecycle work can proceed.
197
+ const decision = mode === "off" && !input.decision && !input.decisionFile && !fs.existsSync(decisionFile)
198
+ ? disabledDecision
199
+ : readCodeReviewDecision(decisionFile, reviewContext.accepted_decision, Boolean(input.decisionFile), input.decision);
200
+ validateSchema({ schemaName: "code-review-decision", file: decisionFile, data: decision, projectRoot: run.workspace_root, ddFlowHome: context.ddFlowHome, runId: run.id, runRoot: home });
201
+ const intentEvidence = mode === "off" ? null : validateAcceptedIntentReview(context, { projectId: project.id, runId: run.id, home, stage, decisionFrozen: Boolean(reviewContext.accepted_decision) }, latestRunVerificationMatrix(context, project.id, run.id, stage, "input")?.metadata.accepted_sources, reviewContext.accepted_intent_review_fingerprint, decision.accepted_intent_acknowledgement);
145
202
  const cycle = reviewContext.cycle ?? "initial";
146
203
  const reviewers = reviewerWorks(context, project.id, run.id, cycle);
204
+ const defEvidence = decision.findings.filter(item => item.disposition === "defer").map(item => reviewDefEvidence(run.workspace_root, item.def_id));
147
205
  if (mode !== "off") {
206
+ assertCodeReviewCoverage(reviewGroups(home), reviewers);
148
207
  const incomplete = reviewers.filter((work) => work.status !== "completed");
149
208
  if (incomplete.length)
150
209
  throw new AppError("reviewer_jobs_incomplete", "CODE-REVIEW cannot finish while reviewer Work is unsettled", 2, { works: incomplete.map((work) => ({ work_id: work.work_id, status: work.status })) });
151
210
  for (const work of reviewers)
152
211
  validateReviewerResult(context, work, run);
153
212
  const canonical = reviewDecisionForRepair(decision, reviewers);
213
+ if (reviewContext.accepted_decision && JSON.stringify(reviewContext.def_evidence ?? []) !== JSON.stringify(defEvidence))
214
+ throw new AppError("deferral_invalid", "Accepted DEF evidence changed during review repair", 2);
154
215
  const checkRefsByFinding = validateRepairChecks(context, { projectId: project.id, runId: run.id, decision: canonical.decision });
155
216
  let repairs = reviewRepairWorks(context, project.id, run.id, root, cycle);
156
- const decisionSha = sha256File(decisionFile);
157
217
  const frozenShaFile = path.join(root, ".decision-sha256");
158
- if (fs.existsSync(frozenShaFile) && fs.readFileSync(frozenShaFile, "utf8").trim() !== decisionSha)
218
+ const decisionHash = sha256Value(input.decisionText ?? JSON.stringify(decision));
219
+ if (!reviewContext.accepted_decision && fs.existsSync(frozenShaFile) && fs.readFileSync(frozenShaFile, "utf8").trim() !== decisionHash)
159
220
  throw new AppError("review_decision_changed", "The accepted CODE-REVIEW decision cannot change during repair", 2, { decision_file: decisionFile });
160
221
  const fixIds = canonical.fix_ids;
161
222
  if (fixIds.length && repairs.length === 0) {
223
+ // The fresh repair sees the coordinator's newly accepted clarification,
224
+ // without pretending that the earlier independent review covered it.
225
+ if (intentEvidence?.coordinator_clarification_refs.length) {
226
+ const correctionMatrix = prepareRunVerificationMatrix(context, { projectId: project.id, runId: run.id, stage, role: "output", semanticFile: decisionFile });
227
+ context.db.writeTransaction(() => { assertAcceptedIntentReviewCurrent(context, { projectId: project.id, runId: run.id }, intentEvidence); acceptVerificationMatrix(context, correctionMatrix); });
228
+ publishVerificationMatrix(context, correctionMatrix);
229
+ }
230
+ // Accept the value once. Repairs consume this decision, not a mutable
231
+ // operator file. Reuse the existing context artifact and review cycle.
232
+ const contextFile = path.join(root, "review-context.json"), temporary = `${contextFile}.tmp-${crypto.randomUUID()}`;
233
+ fs.writeFileSync(temporary, `${JSON.stringify({ ...reviewContext, accepted_decision: decision, def_evidence: defEvidence }, null, 2)}\n`);
234
+ fs.renameSync(temporary, contextFile);
162
235
  const repair = addVnextCodeReviewRepair(context, { projectRoot, runId: run.id, findingIds: fixIds, checkRefsByFinding, decisionReasonsByFinding: Object.fromEntries(canonical.decision.findings.map((item) => [item.finding_ref, item.reason])), objective: `Resolve accepted CODE-REVIEW findings: ${fixIds.join(", ")}` });
163
- fs.writeFileSync(frozenShaFile, `${decisionSha}\n`);
164
- return { ok: true, run_id: run.id, stage, outcome: "repair_required", decision_sha256: decisionSha, repair, instruction: "Run the returned repair Work in one fresh child session. When it completes, invoke the same stage finish command again with the unchanged decision file.", next: { finish_command: finishCommand(context, run.id, projectRoot, decisionFile) } };
236
+ const retained = latestRunVerificationMatrix(context, project.id, run.id, stage, intentEvidence?.coordinator_clarification_refs.length ? "output" : "input");
237
+ return { ok: true, run_id: run.id, stage, outcome: "repair_required", repair, ...(retained ? { verification_matrix: retained.metadata } : {}), instruction: `The repair Work is already registered: do not invoke its start_command in this coordinator Session. End this Turn so the controller can launch it in a fresh child Session. When it completes, invoke next.finish_command; this review cycle uses the decision already accepted by the runtime.\n${verificationMatrixInstruction(retained?.metadata ?? null, home, "the accepted review decision and repair")}`, next: { finish_command: finishCommand(context, run.id, projectRoot, decisionFile) } };
165
238
  }
166
239
  repairs = reviewRepairWorks(context, project.id, run.id, root, cycle);
167
240
  const incompleteRepairs = repairs.filter((work) => work.status !== "completed");
168
241
  if (incompleteRepairs.length)
169
242
  throw new AppError("review_repair_incomplete", "CODE-REVIEW cannot finish while a repair Work is unsettled", 2, { works: incompleteRepairs.map((work) => ({ work_id: work.work_id, status: work.status })) });
243
+ const reconciliation = reconcileNoChangeProposals(context, { projectRoot, run, rootWork, cycle, decisionFile, works: [...codeWorks(context, project.id, run.id), ...repairs] });
244
+ if (reconciliation)
245
+ return reconciliation;
170
246
  validateDecision(context, { decision: canonical.decision, reviewers: canonical.reviewers, repairs, workspaceRoot: run.workspace_root });
171
247
  }
248
+ if (mode === "off") {
249
+ const reconciliation = reconcileNoChangeProposals(context, { projectRoot, run, rootWork, cycle, decisionFile, works: [...codeWorks(context, project.id, run.id), ...reviewRepairWorks(context, project.id, run.id, root, cycle)] });
250
+ if (reconciliation)
251
+ return reconciliation;
252
+ }
172
253
  const outcome = decision.findings.some((item) => item.disposition === "defer") ? "accepted_with_DEF" : "accepted";
173
254
  const repairs = reviewRepairWorks(context, project.id, run.id, root, cycle);
174
255
  const finalChecks = finalCodeCheckDeclarations(run.workspace_root, codeWorks(context, project.id, run.id).flatMap((work) => { const payload = readJsonString(work.payload_json); return Array.isArray(payload.checks) ? payload.checks : []; }));
175
256
  if (input.retryCheckId) {
176
- validateFailedCheckRetry(context, { projectId: project.id, runId: run.id, receiptId: input.retryCheckId, declarations: finalChecks });
257
+ validateFailedCheckRetry(context, { projectId: project.id, runId: run.id, receiptId: input.retryCheckId, declarations: finalChecks, reason: input.retryReason });
177
258
  appendFlowRunTimelineEvent(context, project.id, run.id, { type: "check_retry_requested", check_receipt_id: input.retryCheckId, stage, reason: input.retryReason ?? "operator retry" });
178
259
  }
179
- const unchangedFailures = unchangedFinalGateFailures(context, { projectId: project.id, runId: run.id, workspaceRoot: run.workspace_root, declarations: finalChecks, ...(input.retryCheckId ? { retryReceiptId: input.retryCheckId } : {}) });
180
- if (unchangedFailures.length)
181
- throw new AppError("code_review_gate_repair_required", "CODE-REVIEW final gate already failed for the unchanged workspace; choose source repair or restore the environment and retry that receipt", 2, { outcome: "repair_required", retry_after_workspace_change: true, workspace_fingerprint: unchangedFailures[0].workspace_fingerprint, failures: unchangedFailures, retry_command: `${finishCommand(context, run.id, projectRoot, decisionFile)} --retry-check ${unchangedFailures[0].id} --reason "<environment recovery evidence>"` });
182
- const receipts = await runCodeChecks(context, { projectId: project.id, runId: run.id, runHome: home, workspaceRoot: run.workspace_root, artifactDir: stageDir, scope: "aggregate", checks: finalChecks, ...(input.progress ? { progress: input.progress } : {}) });
260
+ const receipts = await runCodeChecks(context, { projectId: project.id, runId: run.id, runHome: home, workspaceRoot: run.workspace_root, artifactDir: stageDir, scope: "aggregate", checks: finalChecks, ...(input.retryCheckId ? { retryReceiptId: input.retryCheckId, retryReason: input.retryReason } : {}), ...(input.progress ? { progress: input.progress } : {}) });
261
+ const matrix = prepareRunVerificationMatrix(context, { projectId: project.id, runId: run.id, stage, role: "output", receipts, semanticFile: decisionFile });
183
262
  const failed = receipts.filter((receipt) => receipt.status !== "passed");
184
- if (failed.length)
263
+ if (failed.length) {
264
+ assertCheckDiagnosisEligible(failed, run.workspace_root);
265
+ context.db.writeTransaction(() => acceptVerificationMatrix(context, matrix));
266
+ publishVerificationMatrix(context, matrix);
185
267
  throw new AppError("code_review_gate_failed", "CODE-REVIEW repair changed the project but the aggregate gate failed", 2, {
186
268
  failures: failed,
187
269
  outcome: "repair_required",
188
270
  retry_after_workspace_change: true,
189
271
  workspace_fingerprint: failed[0].workspace_fingerprint,
190
- repair_command: `${flowCommand(context)} work repair add --run ${run.id} --from-check ${failed[0].id} --origin-work <WORK-ID> --task-stdin --project-root ${JSON.stringify(projectRoot)} --json`,
191
- retry_command: `${finishCommand(context, run.id, projectRoot, decisionFile)} --retry-check ${failed[0].id} --reason "<environment recovery evidence>"`
272
+ continuation: registerAggregateCodeRepair(context, { projectRoot, runId: run.id, stage, failures: failed, checks: finalChecks, generation }),
273
+ ...(matrix ? { verification_matrix: matrix.metadata } : {}),
274
+ instruction: `Repair Work is already registered. End this Turn so the controller can launch a fresh child; after it finishes, repeat finish with the already accepted review decision. Do not redo review.\n${verificationMatrixInstruction(matrix?.metadata ?? null, home, "the current aggregate failures and repair")}`
192
275
  });
276
+ }
193
277
  const stopTarget = executionStopTarget(run);
194
278
  const nextAction = stopTarget === "merge_completed" ? "start_merge" : "code_review_completed";
195
279
  const now = context.now();
196
280
  const startedAt = stageStartedAt(run, now);
197
- const report = { schema_id: "dd-flow/stage-report@1", run_id: run.id, stage, generated_at: now, verdict: "done", semantic: { result: `Independent CODE review completed: ${reviewers.length} reviewer Work(s), ${repairs.length} repair Work(s).`, acceptance: ["all_selected_review_groups_completed", "all_material_findings_classified", ...(repairs.length ? ["all_accepted_repairs_completed"] : []), "current_final_gate_passed"], run_changed_files: changedPaths(run.workspace_root), checks: receipts.map((receipt) => receipt.command), evidence: [...reviewers.flatMap((work) => readJsonString(work.result).findings.flatMap((finding) => finding.evidence_refs)), ...receipts.map((receipt) => runRef(run.id, home, receipt.receipt_path))], next_action: nextAction, code_review: { mode, reviewer_work_ids: reviewers.map((work) => work.work_id), repair_work_ids: repairs.map((work) => work.work_id), decision } }, mechanical: { started_at: startedAt, finished_at: now, wall_clock_ms: Math.max(0, Date.parse(now) - Date.parse(startedAt)), git: gitFacts(run.workspace_root), session_stats_command: `${flowCommand(context)} stat run sessions ls --run ${run.id} --project-root ${JSON.stringify(projectRoot)} --json`, usage_stats_command: `${flowCommand(context)} stat usage --run ${run.id} --project-root ${JSON.stringify(projectRoot)} --json` }, artifacts: { json: "stage-report.json", markdown: "stage-report.md", html: "stage-report.html" }, validation: { status: "passed" } };
281
+ const report = { schema_id: "dd-flow/stage-report@1", run_id: run.id, stage, generated_at: now, verdict: "done", semantic: { result: `Independent CODE review completed: ${reviewers.length} reviewer Work(s), ${repairs.length} repair Work(s).`, acceptance: ["all_selected_review_groups_completed", "all_material_findings_classified", ...(repairs.length ? ["all_accepted_repairs_completed"] : []), "current_final_gate_passed"], run_changed_files: changedPaths(run.workspace_root), checks: receipts.map((receipt) => receipt.command), evidence: [...reviewers.flatMap((work) => readJsonString(work.result).findings.flatMap((finding) => finding.evidence_refs)), ...receipts.map((receipt) => runRef(run.id, home, receipt.receipt_path))], next_action: nextAction, code_review: { mode, reviewer_work_ids: reviewers.map((work) => work.work_id), repair_work_ids: repairs.map((work) => work.work_id), decision } }, mechanical: { started_at: startedAt, finished_at: now, wall_clock_ms: Math.max(0, Date.parse(now) - Date.parse(startedAt)), git: gitFacts(run.workspace_root), session_stats_command: runtimeCommand(context, ["stat", "run", "sessions", "ls", "--run", run.id, "--project-root", projectRoot, "--json"]), usage_stats_command: runtimeCommand(context, ["stat", "usage", "--run", run.id, "--project-root", projectRoot, "--json"]) }, artifacts: { json: "stage-report.json", markdown: "stage-report.md", html: "stage-report.html" }, validation: { status: "passed" } };
198
282
  // The request must exist before CODE-REVIEW becomes terminal. Otherwise a
199
283
  // merge-gate error creates an irrecoverable `done` report with no MRG-*.
200
284
  const acceptedPaths = changedPaths(run.workspace_root);
201
- const mergeRequest = nextAction === "start_merge" ? ensureVnextMergeRequest(context, { projectRoot, runId: run.id, acceptedPaths }) : null;
202
- writeReport(root, report);
203
- completeFlowRunStage(context, { projectRoot, runId: run.id, stage, status: "done", data: "stage-report.json", dataSchemaId: "dd-flow/stage-report@1", report: "stage-report.md", stageReport: "stage-report.html" });
204
- appendFlowRunTimelineEvent(context, project.id, run.id, { type: "code_review_completed", work_id: rootWork.work_id, outcome });
205
- if (nextAction === "start_merge")
206
- advanceFlowRun(context, { projectRoot, runId: run.id, status: "running", verdict: "code_review_completed", nextAction });
207
- else {
208
- await finishWork(context, rootWork.work_id, JSON.stringify(report, null, 2));
209
- completeFlowRun(context, { projectRoot, runId: run.id, status: "done", verdict: "code_review_completed", nextAction: undefined });
285
+ let mergeRequest = null;
286
+ assertRunMutationAllowed(context, project.id, run.id, generation);
287
+ const prepareMerge = nextAction === "start_merge" ? prepareVnextMergeRequest(context, { projectRoot, runId: run.id, acceptedPaths }) : null;
288
+ if (matrix)
289
+ Object.assign(report.semantic, { verification_matrix: matrix.metadata });
290
+ if (JSON.stringify(defEvidence) !== JSON.stringify(decision.findings.filter(item => item.disposition === "defer").map(item => reviewDefEvidence(run.workspace_root, item.def_id))))
291
+ throw new AppError("deferral_invalid", "DEF evidence changed while final checks ran", 2);
292
+ Object.assign(report.semantic, { def_evidence: defEvidence });
293
+ if (intentEvidence)
294
+ Object.assign(report.semantic, { accepted_intent_review: intentEvidence });
295
+ const preparedReport = prepareStageReport(report);
296
+ const completionInput = { projectRoot, runId: run.id, stage, status: "done", data: "stage-report.json", dataSchemaId: "dd-flow/stage-report@1", report: "stage-report.md", stageReport: "stage-report.html", dataSha256: preparedReport.sha256, git: report.mechanical.git };
297
+ withStageSettlement(context, () => {
298
+ assertAcceptedIntentReviewCurrent(context, { projectId: project.id, runId: run.id }, intentEvidence);
299
+ assertRunMutationAllowed(context, project.id, run.id, generation);
300
+ const currentReviewers = reviewerWorks(context, project.id, run.id, cycle);
301
+ const currentRepairs = reviewRepairWorks(context, project.id, run.id, root, cycle);
302
+ if (currentReviewers.length !== reviewers.length || currentRepairs.length !== repairs.length || [...currentReviewers, ...currentRepairs].some(work => work.status !== "completed" || ![...reviewers, ...repairs].some(accepted => accepted.work_id === work.work_id && accepted.result === work.result))) {
303
+ throw new AppError("reviewer_jobs_incomplete", "Review or repair results changed while the final checks were running", 2);
304
+ }
305
+ mergeRequest = prepareMerge?.() ?? null;
306
+ const preparedCompletion = prepareFlowRunStageCompletion(context, completionInput);
307
+ acceptVerificationMatrix(context, matrix);
308
+ acceptStageReport(context, { projectId: project.id, runId: run.id, stage, root, prepared: preparedReport });
309
+ completeFlowRunStage(context, completionInput, preparedCompletion);
310
+ appendFlowRunTimelineEvent(context, project.id, run.id, { type: "code_review_completed", work_id: rootWork.work_id, outcome });
311
+ if (nextAction === "start_merge")
312
+ advanceFlowRun(context, { settlementStage: "code-review", projectRoot, runId: run.id, status: "running", verdict: "code_review_completed", nextAction });
313
+ else {
314
+ finishStageCoordinatorWork(context, rootWork.work_id, JSON.stringify(report, null, 2));
315
+ completeFlowRun(context, { projectRoot, runId: run.id, status: "done", verdict: "code_review_completed", nextAction: undefined });
316
+ }
317
+ refreshRunWorkProjection(context, project.id, run.id);
318
+ });
319
+ return { ok: true, run_id: run.id, stage, outcome, report_path: path.join(root, "stage-report.json"), next_action: nextAction, ...(mergeRequest ? { merge_request: mergeRequest, next: stageSuccessor(context, { projectRoot, runId: run.id, stage: "merge", command: runtimeCommand(context, ["stage", "start", run.id, "--stage", "merge", "--project-root", projectRoot, "--json", "--progress-jsonl"]) }) } : {}) };
320
+ }
321
+ export function readCodeReviewDecision(file, accepted, explicit = false, prepared) {
322
+ if (!accepted)
323
+ return prepared ?? prepareJsonFile(file, "CODE-REVIEW decision").value;
324
+ if ((prepared !== undefined || (explicit && fs.existsSync(file))) && JSON.stringify(prepared ?? prepareJsonFile(file, "CODE-REVIEW decision").value) !== JSON.stringify(accepted)) {
325
+ throw new AppError("review_decision_changed", "This review cycle already accepted a different decision", 2, { decision_file: file });
210
326
  }
211
- refreshRunWorkProjection(context, project.id, run.id);
212
- return { ok: true, run_id: run.id, stage, outcome, report_path: path.join(root, "stage-report.json"), next_action: nextAction, ...(mergeRequest ? { merge_request: mergeRequest, next: { kind: "start_stage", stage: "merge", command: `${flowCommand(context)} stage start ${run.id} --stage merge --project-root ${JSON.stringify(projectRoot)} --json --progress-jsonl` } } : {}) };
327
+ return accepted;
213
328
  }
214
- function reviewGroups(home) {
329
+ function disabledReviewDecision() {
330
+ return { schema_id: "dd-flow/code-review-decision@3", summary: "CODE-REVIEW is disabled by RUN configuration.", findings: [] };
331
+ }
332
+ /** Retained decisions remain authoritative after their caller file is gone. */
333
+ export function prepareCodeReviewDecision(runRoot, file) {
334
+ const root = path.join(runRoot, "06-code-review");
335
+ const context = readJson(path.join(root, "review-context.json"));
336
+ const source = path.resolve(file ?? path.join(root, "decision.json"));
337
+ if (context.accepted_decision && !fs.existsSync(source))
338
+ return { value: context.accepted_decision };
339
+ if (context.mode === "off" && !file && !fs.existsSync(source))
340
+ return { value: disabledReviewDecision() };
341
+ const prepared = prepareJsonFile(source, "CODE-REVIEW decision");
342
+ return { value: readCodeReviewDecision(source, context.accepted_decision, Boolean(file), prepared.value), text: prepared.text };
343
+ }
344
+ export function reviewGroups(home) {
215
345
  const expected = new Set(baselineAspects);
216
346
  const declared = [];
217
347
  for (const file of findFiles(path.join(home, "03-plan"), "aspect-map.json")) {
@@ -226,19 +356,40 @@ function reviewGroups(home) {
226
356
  if (!declared.length)
227
357
  return [{ key: "baseline", aspect_ids: [...expected].sort() }];
228
358
  const assigned = new Set();
359
+ const scoped = new Set();
229
360
  for (const group of declared)
230
361
  for (const aspectId of group.aspect_ids) {
231
- if (assigned.has(aspectId))
232
- throw new AppError("code_review_groups_invalid", "A CODE-REVIEW aspect appears in more than one accepted group", 2, { aspect_id: aspectId });
362
+ const assignment = `${group.key.slice(0, group.key.lastIndexOf("/"))}/${aspectId}`;
363
+ if (scoped.has(assignment))
364
+ throw new AppError("code_review_groups_invalid", "A CODE-REVIEW aspect appears in more than one group of the same protocol", 2, { aspect_id: aspectId });
365
+ scoped.add(assignment);
233
366
  assigned.add(aspectId);
234
367
  }
235
368
  const missing = [...expected].filter((aspectId) => !assigned.has(aspectId)).sort();
236
369
  return [...declared, ...(missing.length ? [{ key: "baseline", aspect_ids: missing }] : [])];
237
370
  }
371
+ export function assertCodeReviewCoverage(groups, reviewers) {
372
+ const expected = new Map(groups.map(group => [group.key, [...group.aspect_ids].sort()]));
373
+ if (!expected.size || expected.size !== groups.length)
374
+ throw new AppError("reviewer_coverage_invalid", "CODE-REVIEW expected group identities must be nonempty and unique", 2);
375
+ const seen = new Set();
376
+ for (const work of reviewers) {
377
+ const group = readJsonString(work.payload_json).group;
378
+ if (!group?.key || seen.has(group.key) || !expected.has(group.key) || !Array.isArray(group.aspect_ids) || JSON.stringify([...group.aspect_ids].sort()) !== JSON.stringify(expected.get(group.key)))
379
+ throw new AppError("reviewer_coverage_invalid", "CODE-REVIEW Work does not match its expected group", 2, { work_id: work.work_id });
380
+ seen.add(group.key);
381
+ }
382
+ const missing = [...expected.keys()].filter(key => !seen.has(key));
383
+ if (missing.length || !expected.size)
384
+ throw new AppError("reviewer_coverage_invalid", "CODE-REVIEW requires every expected reviewer group", 2, { missing_groups: missing });
385
+ }
238
386
  export function reviewerTask(home, group) { return `Read-only independent CODE review for ${group.key}. Assess every assigned aspect exactly once: ${group.aspect_ids.join(", ")}. Read the accepted PLAN, ${path.join(home, "05-code", "stage-report.json")}, and any files needed under the bounded CODE evidence root ${path.join(home, "05-code")}. Verify that universal and exclusive constraints (only, any, all, never, whole) and stated exceptions were not narrowed. For every changed mutation guarded by membership, ownership, authorization or parent lifecycle state, trace the decision to the write boundary: the predicate must remain in the write statement or the guard and write must share one explicit transaction with the needed lock. A separate earlier read is not proof of current authority or lifecycle state; report a material finding when this invariant is broken. Evidence closes a claim only when it exercises the named failure mechanism; a sequential negative test does not prove a concurrency race, and proof limits cannot waive an accepted obligation. Report only material, evidenced defects: a violated obligation or rule, direct evidence, impact, and minimum required outcome. Do not report taste, cosmetics, or untargeted refactoring. Use local finding ids FIND-001, FIND-002, and so on; dd-flow adds the Work-qualified canonical reference. Return dd-flow/code-review-result@1.`; }
239
- function orchestratorPrompt(context, input) { const template = read(path.join(input.run.workspace_root, ".memory-bank", "dd-flow", "vnext", "code-review.md")); const decision = path.join(input.root, "decision.json"); const checks = acceptedCodeChecks(context, input.run.project_id, input.run.id).map(({ id, purpose }) => ({ id, purpose })); return ["<stage_identity>", `- RUN: ${input.run.id}`, `- root Work: ${input.rootWork.work_id}`, `- stage: ${stage}`, `- mode: ${input.mode}`, "</stage_identity>", "", "<trusted_runtime_context>", `- project root: ${input.projectRoot}`, `- immutable write workspace: ${input.run.workspace_root}`, `- stage workspace: ${input.root}`, `- bounded CODE evidence root: ${path.join(input.run.run_root, "05-code")}`, "CODE is already semantically verified and all declared checks passed. Do not redo CODE verification; conduct independent quality review.", "</trusted_runtime_context>", "", "<review_groups>", ...input.groups.map((group) => `- ${group.key}: ${group.aspect_ids.join(", ")}`), "</review_groups>", "", "<execution_commands>", "Each reviewer Work must run in one fresh child session. The coordinator must never claim a reviewer Work itself. Start each ready Work with its exact start_command from the work graph; it receives the task and result schema. Reviewers are read-only and must not create subagents. Do not interrupt a quiet worker.", `Ready reviewer Works: ${flowCommand(context)} work ls --run ${input.run.id} --ready --project-root ${JSON.stringify(input.projectRoot)} --json`, `Finish only after every reviewer Work settles and you have written ${decision}: ${finishCommand(context, input.run.id, input.projectRoot, decision)}`, "Reviewer results use local FIND-NNN ids. Classify them by the canonical WRK-.../FIND-NNN finding_ref returned by dd-flow. Fix P0/P1. Fix bounded safe P2 by default; defer only a legitimate P2 with a named DEF. P3 is an observation or a reasoned rejection, not automatic repair/DEF. For every disposition fix, check_refs is mandatory: choose the one or more causal checks from the accepted list below that the repair must rerun. Do not guess a CHK id or copy every check. The first successful Finish freezes this decision and creates one repair Work when needed. Run it, then call the same Finish command again. Review is not repeated.", "If the post-repair aggregate gate fails, do not stop after `code_review_gate_failed`: that rejected finish does not create a repair Work. In the same coordinator Turn, use the returned repair command with the failed receipt, a relevant completed origin Work ID, and a concise repair objective; then stop so the runner can dispatch the new repair. Do not edit invisibly in the root orchestrator.", `Accepted repair checks: ${JSON.stringify(checks)}`, "```json", JSON.stringify({ schema_id: "dd-flow/code-review-decision@3", summary: "Evidence-backed conclusion.", findings: [{ finding_ref: "WRK-001-review/FIND-001", disposition: "fix | defer | reject | duplicate", reason: "Why this classification is correct.", check_refs: ["CHK-CAUSAL-CHECK only when disposition is fix"], def_id: "DEF-0001 only for an allowed P2 deferral", duplicate_of: "canonical finding_ref only for duplicate" }] }, null, 2), "```", "</execution_commands>", "", "<stage_instructions>", template, "</stage_instructions>", ""].join("\n"); }
387
+ function orchestratorPrompt(context, input) { const { template, checks } = input; const decision = path.join(input.root, "decision.json"); return ["<stage_identity>", `- RUN: ${input.run.id}`, `- root Work: ${input.rootWork.work_id}`, `- stage: ${stage}`, `- mode: ${input.mode}`, "</stage_identity>", "", "<trusted_runtime_context>", `- project root: ${input.projectRoot}`, `- immutable write workspace: ${input.run.workspace_root}`, `- stage workspace: ${input.root}`, `- bounded CODE evidence root: ${path.join(input.run.run_root, "05-code")}`, "CODE passed its declared checks; each check proves only its named contour and proof limits, not complete semantic acceptance. Conduct independent quality review and do not manually rerun every declared check.", "</trusted_runtime_context>", "", "<review_groups>", ...input.groups.map((group) => `- ${group.key}: ${group.aspect_ids.join(", ")}`), "</review_groups>", "", "<execution_commands>", "Do not choose a provider delegation tool from this stage prompt. At the Work-graph boundary, return immediately; the shared controller supplies the selected adapter's native tool, exact parameters, child task, and wait contract. Each reviewer Work must run in one fresh child session. The coordinator must never invoke a Work start_command itself: a child runs its exact start_command after native delegation. Reviewers are read-only and must not create subagents. Do not interrupt a quiet worker.", "Ready reviewer Works: " + runtimeCommand(context, ["work", "ls", "--run", input.run.id, "--ready", "--project-root", input.projectRoot, "--json"]), `Write the decision to this exact absolute path, not a relative look-alike: ${decision}`, `Finish only after every reviewer Work settles and that exact file exists: ${finishCommand(context, input.run.id, input.projectRoot, decision)}`, "Reviewer results use local FIND-NNN ids. Classify them by the canonical WRK-.../FIND-NNN finding_ref returned by dd-flow. Fix P0/P1. Fix bounded safe P2 by default; defer only a legitimate P2 with a named DEF. P3 is an observation or a reasoned rejection, not automatic repair/DEF. For every disposition fix, check_refs is mandatory: choose the one or more causal checks from the accepted list below that the repair must rerun. Do not guess a CHK id or copy every check. The first successful Finish freezes this decision and creates one repair Work when needed. Do not invoke that Work's start_command from the coordinator Session: end this Turn so the controller can launch a fresh child, then call the returned next.finish_command after it completes. Internal invocation IDs are runtime-owned and must not be copied or reused. Ordinary review is not repeated. Explicit already_satisfied/disputed or already-current document proposals require a fresh independent selective re-review registered by the runtime; a passing repair author's claim never substitutes for that decision.", "If the aggregate gate fails with repair_required, its repair Work is already registered with all causal checks. End this Turn so the controller launches a fresh child. Do not copy receipt IDs, create another repair, invoke its start_command in the coordinator, or edit invisibly in the root orchestrator.", `Accepted repair checks: ${JSON.stringify(checks)}`, "```json", JSON.stringify({ schema_id: "dd-flow/code-review-decision@3", summary: "Evidence-backed conclusion.", findings: [{ finding_ref: "WRK-001-review/FIND-001", disposition: "fix | defer | reject | duplicate", reason: "Why this classification is correct.", check_refs: ["CHK-CAUSAL-CHECK only when disposition is fix"], def_id: "DEF-0001 only for an allowed P2 deferral", duplicate_of: "canonical finding_ref only for duplicate" }] }, null, 2), "```", "</execution_commands>", "", "<stage_instructions>", template, "</stage_instructions>", ""].join("\n"); }
240
388
  function canonicalReviewEvidence(decision, reviewers) {
241
- const known = new Set(canonicalCodeFindings(reviewers).map((item) => item.finding_ref));
389
+ const known = new Map(canonicalCodeFindings(reviewers).map((item) => [item.finding_ref, item.finding]));
390
+ const refs = decision.findings.map(item => item.finding_ref);
391
+ if (new Set(refs).size !== refs.length || refs.some(ref => !known.has(ref)))
392
+ throw new AppError("review_evidence_invalid", "CODE decisions must use unique known canonical finding references", 2, { finding_refs: refs });
242
393
  const items = new Map(decision.findings.map((item) => [item.finding_ref, item]));
243
394
  const duplicates = new Set();
244
395
  for (const item of decision.findings.filter((entry) => entry.disposition === "duplicate")) {
@@ -254,6 +405,9 @@ function canonicalReviewEvidence(decision, reviewers) {
254
405
  }
255
406
  if (!cursor)
256
407
  throw new AppError("review_evidence_invalid", "Duplicate finding chain must end at a decided canonical finding", 2, { finding_ref: item.finding_ref });
408
+ if (["p0", "p1"].includes(known.get(item.finding_ref).priority) && cursor.disposition !== "fix") {
409
+ throw new AppError("review_material_disposition_invalid", "P0/P1 duplicate findings must resolve to a fixed canonical finding", 2, { finding_ref: item.finding_ref, canonical_finding_ref: cursor.finding_ref, disposition: cursor.disposition });
410
+ }
257
411
  duplicates.add(item.finding_ref);
258
412
  }
259
413
  return {
@@ -304,8 +458,7 @@ function validateDecision(context, input) {
304
458
  if (item.disposition === "fix" && !repaired.some((work) => requiredChecks.every((ref) => reviewCheckRefs(work).includes(ref))))
305
459
  throw new AppError("review_repair_check_missing", "A fixed CODE-REVIEW finding needs a repair Work that retains every selected causal check", 2, { finding_ref: findingRef, check_refs: requiredChecks });
306
460
  if (finding.priority === "p2" && item.disposition === "defer") {
307
- if (!item.def_id || !fs.existsSync(path.join(input.workspaceRoot, ".memory-bank", "defs", `${item.def_id}.md`)))
308
- throw new AppError("deferral_invalid", "A deferred P2 requires a named durable DEF", 2, { finding_ref: findingRef, def_id: item.def_id ?? null });
461
+ reviewDefEvidence(input.workspaceRoot, item.def_id);
309
462
  }
310
463
  if (finding.priority === "p3" && item.disposition === "defer")
311
464
  throw new AppError("deferral_invalid", "P3 observations are not deferred as DEF", 2, { finding_ref: findingRef });
@@ -328,6 +481,65 @@ function validateReviewerResult(_context, work, _run) {
328
481
  if (result.aspects.some((aspect) => aspect.verdict === "blocked"))
329
482
  throw new AppError("review_blocked", "A blocked review aspect must be resolved before CODE-REVIEW can finish", 2, { work_id: work.work_id });
330
483
  }
484
+ /** A later completed correction supersedes the earlier proposal, not its history. */
485
+ export function codeNoChangeProposals(works) {
486
+ const latest = new Map();
487
+ for (const work of new Map(works.map(work => [work.work_id, work])).values()) {
488
+ if (work.status !== "completed")
489
+ continue;
490
+ const result = readJsonString(work.result);
491
+ const resolutions = (Array.isArray(result.resolutions) ? result.resolutions : []);
492
+ for (const item of resolutions)
493
+ latest.set(`finding:${item.finding_ref}`, { work, entry: ["already_satisfied", "disputed"].includes(item.disposition ?? "fixed") ? { ref: item.finding_ref, summary: item.summary, evidence_refs: item.evidence_refs } : null });
494
+ const documents = (Array.isArray(readJsonString(work.payload_json).document_updates) ? readJsonString(work.payload_json).document_updates : []);
495
+ const docResolutions = (Array.isArray(result.document_resolutions) ? result.document_resolutions : []);
496
+ for (const document of documents) {
497
+ const item = docResolutions.find(item => item.path === document.path);
498
+ latest.set(`document:${document.path}`, { work, entry: item ? { ref: document.path, summary: item.summary, evidence_refs: item.evidence_refs } : null });
499
+ }
500
+ }
501
+ const grouped = new Map();
502
+ for (const { work, entry } of latest.values())
503
+ if (entry) {
504
+ const proposal = grouped.get(work.work_id) ?? { work, entries: [] };
505
+ proposal.entries.push(entry);
506
+ grouped.set(work.work_id, proposal);
507
+ }
508
+ return [...grouped.values()];
509
+ }
510
+ export function reconcileNoChangeProposals(context, input) {
511
+ const all = context.db.all("SELECT * FROM works WHERE project_id = ? AND run_id = ? ORDER BY created_at, work_id", [input.run.project_id, input.run.id]);
512
+ // Include a pending correction too: it must settle before any proposal can close.
513
+ const corrections = all.filter(work => readJsonString(work.payload_json).reconciliation_correction && readJsonString(work.payload_json).review_cycle === input.cycle);
514
+ if (corrections.some(work => work.status !== "completed"))
515
+ throw new AppError("review_repair_incomplete", "A reconciliation correction is still unsettled", 2, { works: corrections.map(work => ({ work_id: work.work_id, status: work.status })) });
516
+ const next = { finish_command: finishCommand(context, input.run.id, input.projectRoot, input.decisionFile) };
517
+ for (const proposal of codeNoChangeProposals([...input.works, ...corrections])) {
518
+ const identity = sha256Value(JSON.stringify({ work_id: proposal.work.work_id, result: proposal.work.result, entries: proposal.entries, workspace_fingerprint: workspaceFingerprint(input.run.workspace_root) }));
519
+ const reviewer = all.find(work => readJsonString(work.payload_json).reconciliation_identity === identity);
520
+ if (!reviewer) {
521
+ const batch = { works: [{ key: `code-reconcile-${identity.slice(0, 12)}`, task: `Independently re-review only this no-change proposal. Do not change files or create subagents. Check the current candidate and the assigned accepted requirements, not the author's confidence. A pass confirms every proposed outcome is already satisfied; if any remains unresolved return findings and explain why with current evidence. Assess the verification_evidence_review aspect exactly once. Proposal: ${JSON.stringify(proposal.entries)}. Original Work packet: ${proposal.work.payload_json}. Original result: ${proposal.work.result}. Read ${path.join(requireHome(input.run), "05-code", "stage-report.json")} for context; it does not prove these proposals. Return dd-flow/code-review-result@1.`, launch_policy: "fresh_agent_required", result_schema: "dd-flow/code-review-result@1", payload: { kind: "code-reconciliation", read_only: true, review_cycle: input.cycle, reconciliation_identity: identity, group: { key: `reconcile-${identity.slice(0, 12)}`, aspect_ids: ["verification_evidence_review"] } } }] };
522
+ const registered = addWorkBatch(context, { parentWorkId: input.rootWork.work_id, value: batch, stage, cycle: input.cycle, requestKey: `reconcile-${identity}` });
523
+ return { ok: true, run_id: input.run.id, stage, outcome: "repair_required", repair: registered, instruction: "An independent read-only reconciliation Work is registered. End this Turn for native dispatch; do not accept the author's no-change proposal yourself. After it settles use next.finish_command.", next };
524
+ }
525
+ if (reviewer.status !== "completed")
526
+ throw new AppError("reviewer_jobs_incomplete", "No-change proposal awaits independent re-review", 2, { works: [{ work_id: reviewer.work_id, status: reviewer.status }] });
527
+ validateReviewerResult(context, reviewer, input.run);
528
+ const verdict = readJsonString(reviewer.result);
529
+ if (verdict.verdict === "pass")
530
+ continue;
531
+ // One bounded correction after a rejected proposal; another no-change
532
+ // rejection reports an honest blocker instead of an unbounded debate.
533
+ if (readJsonString(proposal.work.payload_json).reconciliation_correction)
534
+ throw new AppError("review_reconciliation_rejected", "Independent re-review rejected the repeated no-change proposal", 2, { work_id: proposal.work.work_id, reviewer_work_id: reviewer.work_id, recoverable: false });
535
+ const payload = { ...readJsonString(proposal.work.payload_json), review_cycle: input.cycle, reconciliation_correction: identity };
536
+ // A new allocation inherits the task contract, never its predecessor's custody.
537
+ delete payload._dd_flow_batch_request;
538
+ const registered = addWorkBatch(context, { parentWorkId: input.rootWork.work_id, value: { works: [{ key: `code-reconcile-correction-${identity.slice(0, 12)}`, task: `Independent re-review rejected your predecessor's no-change proposal. Diagnose and resolve the assigned requirement without cosmetic changes or weakened tests. Reviewer evidence: ${reviewer.result}. Preserve the original Work contract: ${proposal.work.payload_json}. A repeated unsupported no-change proposal exhausts this bounded correction.`, launch_policy: "fresh_agent_required", result_schema: "dd-flow/code-work-result@3", payload }] }, stage, cycle: input.cycle, requestKey: `reconcile-correction-${identity}` });
539
+ return { ok: true, run_id: input.run.id, stage, outcome: "repair_required", repair: registered, instruction: "Independent re-review rejected the proposal; a bounded correction Work is registered. End this Turn for dispatch, then use next.finish_command.", next };
540
+ }
541
+ return null;
542
+ }
331
543
  function reviewerWorks(context, projectId, runId, cycle) { return context.db.all("SELECT * FROM works WHERE project_id = ? AND run_id = ? ORDER BY created_at, work_id", [projectId, runId]).filter((work) => { const payload = readJsonString(work.payload_json); return Boolean(payload.kind === "code-review" && (typeof payload.review_cycle === "string" ? payload.review_cycle : "initial") === cycle); }); }
332
544
  function codeWorks(context, projectId, runId) { return context.db.all("SELECT * FROM works WHERE project_id = ? AND run_id = ? AND status = 'completed' ORDER BY created_at, work_id", [projectId, runId]).filter((work) => readJsonString(work.payload_json).schema_id === "dd-flow/code-work-packet@5" && !reviewFindingIds(work).length); }
333
545
  function acceptedCodeChecks(context, projectId, runId) { return codeWorks(context, projectId, runId).flatMap((work) => { const payload = readJsonString(work.payload_json); return Array.isArray(payload.checks) ? payload.checks : []; }); }
@@ -342,6 +554,8 @@ function validateRepairChecks(context, input) { const known = new Set(acceptedCo
342
554
  } return selected; }
343
555
  function reviewRepairWorks(context, projectId, runId, root, cycle) { return context.db.all("SELECT * FROM works WHERE project_id = ? AND run_id = ? ORDER BY created_at, work_id", [projectId, runId]).filter((work) => { const payload = readJsonString(work.payload_json); return isCodeReviewStageRepair(work, root) && (typeof payload.review_cycle === "string" ? payload.review_cycle : "initial") === cycle; }); }
344
556
  export function isCodeReviewStageRepair(work, root) {
557
+ if (readJsonString(work.payload_json).reconciliation_correction)
558
+ return true;
345
559
  if (reviewFindingIds(work).length)
346
560
  return true;
347
561
  const repair = readJsonString(work.payload_json).repair;
@@ -362,13 +576,9 @@ function effectiveMode(home, run) { const index = JSON.parse(run.index_json); if
362
576
  return { mode: "standard", source: "project_policy", reason: "A failed integration gate requires independent review of its source repair." }; const configured = index.settings?.code_review; const requested = configured?.mode ?? "auto"; if (requested !== "auto")
363
577
  return { mode: requested, source: configured?.source === "user_instruction" ? "user_instruction" : "project_policy", reason: configured?.reason ?? "Frozen RUN configuration." }; const assessments = findFiles(path.join(home, "03-plan"), "plan.json").map((file) => readJson(file)); const deep = assessments.some((plan) => plan.assessment?.failure_impact?.level === "high" || plan.assessment?.solution_uncertainty?.level === "high"); return { mode: deep ? "deep" : "standard", source: "plan_assessment", reason: deep ? "Accepted PLAN assessment records high impact or uncertainty." : "Accepted PLAN assessment requires the standard independent review." }; }
364
578
  function executionStopTarget(run) { return JSON.parse(run.index_json).execution_profile?.settings?.stop_target ?? "code_review_completed"; }
365
- function changedPaths(workspaceRoot) { try {
366
- return execFileSync("git", ["status", "--porcelain=v1", "--untracked-files=all"], { cwd: workspaceRoot, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).split(/\r?\n/).filter(Boolean).map((line) => line.slice(3).replace(/^.* -> /, ""));
367
- }
368
- catch {
369
- return [];
370
- } }
579
+ function changedPaths(workspaceRoot) { return workspaceChangedPaths(workspaceRoot); }
371
580
  function sha256File(file) { return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex"); }
581
+ function sha256Value(value) { return crypto.createHash("sha256").update(value).digest("hex"); }
372
582
  function stageStatus(run, name) { try {
373
583
  return JSON.parse(run.index_json).stage_runs?.find((item) => item.stage === name)?.status ?? null;
374
584
  }
@@ -396,7 +606,9 @@ function requireRun(context, projectId, runId) { const run = context.db.get("SEL
396
606
  throw new AppError("not_found", "RUN is not registered", 1); return run; }
397
607
  function requireHome(run) { if (!run.run_root)
398
608
  throw new AppError("runtime_missing", "RUN artifact root is unavailable", 1); return run.run_root; }
399
- function finishCommand(context, runId, projectRoot, decision) { return `${flowCommand(context)} stage finish ${runId} --stage code-review --decision-file ${JSON.stringify(decision)} --project-root ${JSON.stringify(projectRoot)} --json --progress-jsonl`; }
609
+ export function finishCommand(context, runId, projectRoot, decision, retryCheckId) {
610
+ return managedLifecycleCommand(context, runtimeCommand(context, ["stage", "finish", runId, "--stage", "code-review", "--decision-file", decision, "--project-root", projectRoot, "--json", "--progress-jsonl", ...checkRetryArgs(context, projectRoot, runId, retryCheckId)]));
611
+ }
400
612
  function findFiles(root, name) { if (!fs.existsSync(root))
401
613
  return []; const out = []; for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
402
614
  const file = path.join(root, entry.name);
@@ -414,4 +626,3 @@ function readJsonString(value) { try {
414
626
  catch {
415
627
  return {};
416
628
  } }
417
- function writeReport(root, report) { writeStageReport(root, report); }