@deksden-com/dd-flow-cli 0.9.0-beta.15 → 0.9.0-beta.150

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 (557) hide show
  1. package/CHANGELOG.md +895 -0
  2. package/README.md +140 -6
  3. package/dist/build-info.json +8 -8
  4. package/dist/cli/argument-values.js +38 -0
  5. package/dist/cli/command-inputs.js +386 -0
  6. package/dist/cli/command-metadata.js +232 -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/diagnostic-invocation.js +46 -0
  11. package/dist/cli/diagnostic.js +120 -0
  12. package/dist/cli/error-output.js +52 -0
  13. package/dist/cli/executor-onboarding.js +76 -0
  14. package/dist/cli/flows.js +29 -0
  15. package/dist/cli/harnesses.js +84 -0
  16. package/dist/cli/help.js +396 -19
  17. package/dist/cli/hook-ingress.js +102 -0
  18. package/dist/cli/input-preparation.js +165 -0
  19. package/dist/cli/memory-flow-admission.js +50 -0
  20. package/dist/cli/memory-init-invocation.js +85 -0
  21. package/dist/cli/memory-init.js +249 -0
  22. package/dist/cli/memory-storage-admission.js +54 -0
  23. package/dist/cli/memory-storage-qualification.js +105 -0
  24. package/dist/cli/memory-storage-transition.js +123 -0
  25. package/dist/cli/memory-upgrade.js +189 -0
  26. package/dist/cli/models.js +39 -0
  27. package/dist/cli/native-hook-ingress.js +90 -0
  28. package/dist/cli/native-hook-preparation.js +55 -0
  29. package/dist/cli/operator-profiles.js +61 -0
  30. package/dist/cli/output-options.js +35 -0
  31. package/dist/cli/response-file.js +72 -0
  32. package/dist/cli/run-cli.js +1734 -550
  33. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  34. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  35. package/dist/cli/runtime-process.js +153 -0
  36. package/dist/cli/setup.js +150 -0
  37. package/dist/cli.js +89 -2
  38. package/dist/domain/diagnostic-aspects.js +103 -0
  39. package/dist/domain/diagnostic-flows.js +8 -0
  40. package/dist/domain/stage-catalog.js +1 -1
  41. package/dist/domain/stage-handler-identities.js +28 -0
  42. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  43. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  44. package/dist/harness-runtime/bin/dd-agy.mjs +56 -0
  45. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  46. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  47. package/dist/harness-runtime/bin/dd-grok.mjs +40 -0
  48. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  49. package/dist/harness-runtime/bin/dd-zcode.mjs +87 -0
  50. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  51. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  52. package/dist/harness-runtime/lib/agy-error-boundary.mjs +58 -0
  53. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  54. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  55. package/dist/harness-runtime/lib/agy-native-inspection.mjs +216 -0
  56. package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
  57. package/dist/harness-runtime/lib/daemon-observation.d.mts +2 -0
  58. package/dist/harness-runtime/lib/daemon-observation.mjs +163 -0
  59. package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
  60. package/dist/harness-runtime/lib/daemon-operations.mjs +462 -0
  61. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
  62. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1096 -0
  63. package/dist/harness-runtime/lib/dd-agy.mjs +86 -0
  64. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  65. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +231 -0
  66. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  67. package/dist/harness-runtime/lib/dd-codex.mjs +954 -0
  68. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +141 -0
  69. package/dist/harness-runtime/lib/dd-droid.mjs +626 -0
  70. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +555 -0
  71. package/dist/harness-runtime/lib/dd-grok.mjs +180 -0
  72. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +622 -0
  73. package/dist/harness-runtime/lib/dd-opencode.mjs +390 -0
  74. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +752 -0
  75. package/dist/harness-runtime/lib/dd-zcode.mjs +1175 -0
  76. package/dist/harness-runtime/lib/delegation-instructions.d.mts +14 -0
  77. package/dist/harness-runtime/lib/delegation-instructions.mjs +157 -0
  78. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  79. package/dist/harness-runtime/lib/driver-recovery.mjs +140 -0
  80. package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
  81. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  82. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  83. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  84. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  85. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  86. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  87. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +10 -0
  88. package/dist/harness-runtime/lib/lifecycle-contract.mjs +19 -0
  89. package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
  90. package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
  91. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  92. package/dist/harness-runtime/lib/model-observations.mjs +101 -0
  93. package/dist/harness-runtime/lib/native-children.d.mts +23 -0
  94. package/dist/harness-runtime/lib/native-children.mjs +219 -0
  95. package/dist/harness-runtime/lib/native-hook-command.d.mts +7 -0
  96. package/dist/harness-runtime/lib/native-hook-command.mjs +251 -0
  97. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  98. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  99. package/dist/harness-runtime/lib/native-streams.mjs +45 -0
  100. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  101. package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
  102. package/dist/harness-runtime/lib/opencode-plugin.mjs +85 -0
  103. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  104. package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
  105. package/dist/harness-runtime/lib/operation-errors.mjs +127 -0
  106. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  107. package/dist/harness-runtime/lib/operation-progress.mjs +114 -0
  108. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  109. package/dist/harness-runtime/lib/process-json.mjs +201 -0
  110. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  111. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +15 -0
  112. package/dist/harness-runtime/lib/provider-overload-policy.mjs +151 -0
  113. package/dist/harness-runtime/lib/runner-events.mjs +202 -0
  114. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  115. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  116. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  117. package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
  118. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  119. package/dist/harness-runtime/lib/tool-observations.mjs +228 -0
  120. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  121. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  122. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  123. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  124. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  125. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  126. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  127. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  128. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  129. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  130. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  131. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  132. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  133. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  134. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  135. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  136. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  137. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  138. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  139. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  140. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  141. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  142. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  143. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  144. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  145. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  146. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  147. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  148. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  149. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  150. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  151. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  152. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  153. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  154. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  155. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  156. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  157. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  158. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  159. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  160. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  161. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  162. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  163. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  164. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  165. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  166. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  167. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  168. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  169. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  170. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  171. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  172. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  173. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  174. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  175. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  176. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  177. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  178. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  179. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  180. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  181. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  182. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  183. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  184. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  185. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  186. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  187. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  188. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  189. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  190. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  191. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  192. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  193. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  194. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  195. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  196. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  197. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  198. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  199. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  200. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  201. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  202. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  203. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  204. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  205. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  206. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  207. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  208. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  209. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  210. package/dist/protocol/local-files.js +18 -9
  211. package/dist/runtime/context.js +8 -4
  212. package/dist/schemas/agent-profile.schema.json +1 -1
  213. package/dist/schemas/code-review-decision.schema.json +9 -0
  214. package/dist/schemas/code-review-result.schema.json +1 -1
  215. package/dist/schemas/code-verification.schema.json +7 -5
  216. package/dist/schemas/code-work-batch.schema.json +2 -2
  217. package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
  218. package/dist/schemas/diagnostic-work-result.schema.json +296 -0
  219. package/dist/schemas/discovery-result.schema.json +184 -0
  220. package/dist/schemas/execution-bundle.schema.json +211 -0
  221. package/dist/schemas/execution-settings.schema.json +162 -0
  222. package/dist/schemas/flow-descriptor.schema.json +54 -0
  223. package/dist/schemas/flow-run.schema.json +29 -0
  224. package/dist/schemas/harness-catalog.schema.json +80 -0
  225. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  226. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  227. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  228. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  229. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  230. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  231. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  232. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  233. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  234. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  235. package/dist/schemas/memory-repair-work-result.schema.json +56 -0
  236. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  237. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  238. package/dist/schemas/model-catalog.schema.json +153 -0
  239. package/dist/schemas/plan-review-decision.schema.json +12 -3
  240. package/dist/schemas/plan-review-result.schema.json +2 -2
  241. package/dist/schemas/profile-settings.schema.json +122 -0
  242. package/dist/schemas/project-flow-pack-manifest.schema.json +1 -1
  243. package/dist/schemas/release-impact.schema.json +3 -3
  244. package/dist/schemas/release-manifest.schema.json +291 -0
  245. package/dist/schemas/run-control-receipt.schema.json +118 -0
  246. package/dist/schemas/run-control-request.schema.json +36 -0
  247. package/dist/schemas/run-engine-binding.schema.json +1 -1
  248. package/dist/schemas/stage-start-response.schema.json +4 -0
  249. package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
  250. package/dist/services/accepted-intent.js +139 -0
  251. package/dist/services/branch-context.js +3 -3
  252. package/dist/services/canon.js +54 -15
  253. package/dist/services/check-environment.js +21 -0
  254. package/dist/services/check-runner-evidence.js +562 -0
  255. package/dist/services/cleanup.js +133 -40
  256. package/dist/services/cli-operation-classifier.js +26 -63
  257. package/dist/services/cli-upgrade-allowlist.js +27 -0
  258. package/dist/services/code-checks.js +1398 -119
  259. package/dist/services/codex-hook-delivery.js +32 -0
  260. package/dist/services/command-context.js +80 -0
  261. package/dist/services/compatibility-preflight.js +16 -3
  262. package/dist/services/config.js +11 -8
  263. package/dist/services/continuation-outcome.js +20 -0
  264. package/dist/services/controller-child-capacity.js +13 -0
  265. package/dist/services/controller-child-observer.js +115 -0
  266. package/dist/services/controller-execution.js +94 -0
  267. package/dist/services/controller-fanout.js +226 -0
  268. package/dist/services/controller-memory-task.js +45 -0
  269. package/dist/services/controller-memory-worker.js +49 -0
  270. package/dist/services/dashboard.js +143 -58
  271. package/dist/services/descriptor-coordinator-session.js +35 -0
  272. package/dist/services/descriptor-root-work.js +53 -0
  273. package/dist/services/descriptor-run-settlement.js +107 -0
  274. package/dist/services/descriptor-run-start.js +475 -0
  275. package/dist/services/descriptor-stage-coordinator.js +250 -0
  276. package/dist/services/descriptor-stage-settlement.js +223 -0
  277. package/dist/services/descriptor-stage-start.js +175 -0
  278. package/dist/services/diagnostic-evidence.js +73 -0
  279. package/dist/services/diagnostic-report-publication.js +72 -0
  280. package/dist/services/diagnostic-report.js +67 -0
  281. package/dist/services/diagnostic-run-bundle.js +74 -0
  282. package/dist/services/diagnostic-snapshot.js +159 -0
  283. package/dist/services/diagnostic-stage-handlers.js +108 -0
  284. package/dist/services/diagnostic-stage-results.js +132 -0
  285. package/dist/services/diagnostic-start.js +84 -0
  286. package/dist/services/diagnostic-work-batch.js +34 -0
  287. package/dist/services/diagnostic-work-collection.js +97 -0
  288. package/dist/services/diagnostic-work-registration.js +101 -0
  289. package/dist/services/diagnostic-work-results.js +93 -0
  290. package/dist/services/discovery/agy-discovery.js +2 -0
  291. package/dist/services/discovery/codex-discovery.js +2 -0
  292. package/dist/services/discovery/droid-discovery.js +2 -0
  293. package/dist/services/discovery/grok-discovery.js +2 -0
  294. package/dist/services/discovery/opencode-discovery.js +2 -0
  295. package/dist/services/discovery/static.js +31 -0
  296. package/dist/services/discovery/zcode-discovery.js +2 -0
  297. package/dist/services/engines.js +354 -163
  298. package/dist/services/eval-snapshots.js +1316 -150
  299. package/dist/services/execution-bundles.js +275 -0
  300. package/dist/services/execution-policy.js +185 -0
  301. package/dist/services/executor-onboarding.js +56 -0
  302. package/dist/services/external-work-launch.js +310 -0
  303. package/dist/services/flow-catalog.js +30 -0
  304. package/dist/services/flow-descriptors.js +82 -0
  305. package/dist/services/frozen-engine.js +387 -0
  306. package/dist/services/generic-execution.js +164 -0
  307. package/dist/services/harness-adapter.js +355 -36
  308. package/dist/services/harness-config.js +2 -0
  309. package/dist/services/harness-discovery.js +29 -0
  310. package/dist/services/harness-doctor.js +75 -0
  311. package/dist/services/harness-probe-effects.js +51 -0
  312. package/dist/services/harness-version-probe.js +100 -0
  313. package/dist/services/hook-memory-routing.js +188 -0
  314. package/dist/services/hook-recovery-guard.js +14 -0
  315. package/dist/services/hook-session-observation.js +24 -0
  316. package/dist/services/hooks.js +791 -326
  317. package/dist/services/hybrid-contracts.js +474 -0
  318. package/dist/services/hybrid-digest.js +14 -0
  319. package/dist/services/ids.js +29 -1
  320. package/dist/services/installation-lock.js +95 -0
  321. package/dist/services/installed-flow-source.js +226 -0
  322. package/dist/services/lanes.js +78 -65
  323. package/dist/services/lifecycle-command.js +1 -288
  324. package/dist/services/lifecycle-contract.js +1 -0
  325. package/dist/services/lifecycle-invocations.js +2148 -0
  326. package/dist/services/managed-daemon-binding.js +38 -0
  327. package/dist/services/managed-lease-monitor.js +133 -0
  328. package/dist/services/managed-processes.js +449 -69
  329. package/dist/services/memory-accepted-composition.js +78 -0
  330. package/dist/services/memory-baseline-preservation.js +65 -0
  331. package/dist/services/memory-completed-correction-wave.js +328 -0
  332. package/dist/services/memory-compose-handler.js +400 -0
  333. package/dist/services/memory-composition-acceptance.js +375 -0
  334. package/dist/services/memory-composition-graph.js +165 -0
  335. package/dist/services/memory-composition-registration.js +161 -0
  336. package/dist/services/memory-composition-work-custody.js +156 -0
  337. package/dist/services/memory-composition-work-results.js +108 -0
  338. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  339. package/dist/services/memory-corrected-review-batch.js +37 -0
  340. package/dist/services/memory-corrected-review-findings.js +108 -0
  341. package/dist/services/memory-corrected-review-inputs.js +215 -0
  342. package/dist/services/memory-corrected-review-projection.js +78 -0
  343. package/dist/services/memory-corrected-review-receipt.js +178 -0
  344. package/dist/services/memory-corrected-review-registration.js +192 -0
  345. package/dist/services/memory-correction-check-receipt.js +235 -0
  346. package/dist/services/memory-correction-input-owner.js +6 -0
  347. package/dist/services/memory-custody-snapshot.js +36 -0
  348. package/dist/services/memory-discover-handler.js +104 -0
  349. package/dist/services/memory-finish-evidence.js +457 -0
  350. package/dist/services/memory-finish-handler.js +229 -0
  351. package/dist/services/memory-finish-integration.js +450 -0
  352. package/dist/services/memory-finish-readiness.js +169 -0
  353. package/dist/services/memory-git-integration.js +220 -0
  354. package/dist/services/memory-historical-corrected-review.js +212 -0
  355. package/dist/services/memory-historical-original-review.js +143 -0
  356. package/dist/services/memory-historical-repair-registration.js +105 -0
  357. package/dist/services/memory-historical-second-review.js +147 -0
  358. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  359. package/dist/services/memory-init-contexts.js +131 -0
  360. package/dist/services/memory-init-controller-start.js +103 -0
  361. package/dist/services/memory-init-engine-release.js +223 -0
  362. package/dist/services/memory-init-git-policy.js +165 -0
  363. package/dist/services/memory-init-lint-capability.js +203 -0
  364. package/dist/services/memory-init-native-capacity.js +309 -0
  365. package/dist/services/memory-init-preflight.js +334 -0
  366. package/dist/services/memory-init-project-bootstrap.js +599 -0
  367. package/dist/services/memory-init-request-candidate.js +213 -0
  368. package/dist/services/memory-init-request-input.js +82 -0
  369. package/dist/services/memory-init-resource-storage.js +125 -0
  370. package/dist/services/memory-init-run-allocation.js +81 -0
  371. package/dist/services/memory-init-run-bundle.js +135 -0
  372. package/dist/services/memory-init-start.js +181 -0
  373. package/dist/services/memory-init-startup-custody.js +80 -0
  374. package/dist/services/memory-init-startup-input.js +240 -0
  375. package/dist/services/memory-init-storage.js +91 -0
  376. package/dist/services/memory-init-stores.js +359 -0
  377. package/dist/services/memory-init-worktrunk-capability.js +174 -0
  378. package/dist/services/memory-layer-publication.js +611 -0
  379. package/dist/services/memory-layer.js +221 -0
  380. package/dist/services/memory-lint-config.js +194 -0
  381. package/dist/services/memory-native-review-copy.js +103 -0
  382. package/dist/services/memory-normal-flow-entry.js +87 -0
  383. package/dist/services/memory-ordinary-defaults.js +129 -0
  384. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  385. package/dist/services/memory-preflight-handler.js +274 -0
  386. package/dist/services/memory-repair-current-view.js +299 -0
  387. package/dist/services/memory-repair-document-delta.js +488 -0
  388. package/dist/services/memory-repair-history.js +496 -0
  389. package/dist/services/memory-repair-physical-binding.js +194 -0
  390. package/dist/services/memory-repair-publication-files.js +152 -0
  391. package/dist/services/memory-repair-publication-intent.js +27 -0
  392. package/dist/services/memory-repair-publication-plan.js +162 -0
  393. package/dist/services/memory-repair-publication-source.js +225 -0
  394. package/dist/services/memory-repair-publication.js +795 -0
  395. package/dist/services/memory-repair-registration.js +240 -0
  396. package/dist/services/memory-repair-work-baseline.js +415 -0
  397. package/dist/services/memory-repair-work-completion.js +117 -0
  398. package/dist/services/memory-repair-work-custody.js +73 -0
  399. package/dist/services/memory-repair-work-results.js +108 -0
  400. package/dist/services/memory-repair-workspace.js +261 -0
  401. package/dist/services/memory-repair-writer-copy.js +736 -0
  402. package/dist/services/memory-result-binding.js +239 -0
  403. package/dist/services/memory-retained-review-authority.js +138 -0
  404. package/dist/services/memory-retained-review-results.js +70 -0
  405. package/dist/services/memory-retained-second-baseline.js +102 -0
  406. package/dist/services/memory-retained-second-repairs.js +162 -0
  407. package/dist/services/memory-review-acceptance.js +214 -0
  408. package/dist/services/memory-review-correction-plan.js +206 -0
  409. package/dist/services/memory-review-handler.js +585 -0
  410. package/dist/services/memory-review-inputs.js +246 -0
  411. package/dist/services/memory-review-limits.js +10 -0
  412. package/dist/services/memory-review-receipt.js +180 -0
  413. package/dist/services/memory-review-registration.js +117 -0
  414. package/dist/services/memory-review-work-custody.js +126 -0
  415. package/dist/services/memory-review-work-input.js +91 -0
  416. package/dist/services/memory-review-work-results.js +95 -0
  417. package/dist/services/memory-second-corrected-review-inputs.js +167 -0
  418. package/dist/services/memory-second-correction-plan.js +77 -0
  419. package/dist/services/memory-second-repair-baseline.js +91 -0
  420. package/dist/services/memory-second-repair-launch.js +614 -0
  421. package/dist/services/memory-second-repair-registration.js +88 -0
  422. package/dist/services/memory-second-repair-source.js +187 -0
  423. package/dist/services/memory-second-review-acceptance.js +115 -0
  424. package/dist/services/memory-source-observations.js +117 -0
  425. package/dist/services/memory-stage-dispatch.js +65 -0
  426. package/dist/services/memory-stage-results.js +290 -0
  427. package/dist/services/memory-tool-probe.js +25 -0
  428. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  429. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  430. package/dist/services/memory-upgrade-evidence.js +100 -0
  431. package/dist/services/memory-upgrade-inventory.js +442 -0
  432. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  433. package/dist/services/memory-upgrade-publication.js +413 -0
  434. package/dist/services/memory-upgrade-selection.js +430 -0
  435. package/dist/services/memory-upgrade-start.js +60 -0
  436. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  437. package/dist/services/memory-verification-acceptance.js +156 -0
  438. package/dist/services/memory-verification-checks.js +317 -0
  439. package/dist/services/memory-verification-receipt.js +160 -0
  440. package/dist/services/memory-verify-handler.js +137 -0
  441. package/dist/services/memory-work-result-json.js +12 -0
  442. package/dist/services/memory-work-result-preparation.js +64 -0
  443. package/dist/services/merge-queue.js +228 -149
  444. package/dist/services/merge-server.js +163 -35
  445. package/dist/services/migrations.js +164 -114
  446. package/dist/services/model-catalog.js +109 -0
  447. package/dist/services/model-discovery.js +46 -0
  448. package/dist/services/native-daemon-history.js +50 -0
  449. package/dist/services/native-session-control.js +39 -0
  450. package/dist/services/operator-profiles.js +236 -0
  451. package/dist/services/physical-startup.js +45 -0
  452. package/dist/services/plan-runtime.js +26 -11
  453. package/dist/services/plans.js +28 -25
  454. package/dist/services/project-registry.js +97 -0
  455. package/dist/services/project-summary.js +1 -1
  456. package/dist/services/projects.js +17 -87
  457. package/dist/services/prompt-delivery.js +71 -0
  458. package/dist/services/prompts.js +28 -17
  459. package/dist/services/protocols.js +163 -87
  460. package/dist/services/provider-capacity.js +455 -0
  461. package/dist/services/recovery-observation-budget.js +121 -0
  462. package/dist/services/recovery-snapshot-database.js +588 -0
  463. package/dist/services/release-archive-producer.js +52 -0
  464. package/dist/services/release-archive.js +143 -0
  465. package/dist/services/release-cache.js +150 -0
  466. package/dist/services/release-compatibility.js +18 -0
  467. package/dist/services/release-download.js +67 -0
  468. package/dist/services/release-envelope.js +104 -0
  469. package/dist/services/release-manifest.js +45 -0
  470. package/dist/services/release-payload.js +114 -0
  471. package/dist/services/release-producer.js +63 -0
  472. package/dist/services/release-provenance.js +160 -0
  473. package/dist/services/release-registry.js +66 -0
  474. package/dist/services/release-source.js +194 -0
  475. package/dist/services/repair-intents.js +31 -0
  476. package/dist/services/repair-receipt.js +13 -0
  477. package/dist/services/review-copy.js +165 -0
  478. package/dist/services/review-deferral.js +23 -0
  479. package/dist/services/run-control-receipt.js +56 -0
  480. package/dist/services/run-control-worker.js +428 -0
  481. package/dist/services/run-control.js +1092 -0
  482. package/dist/services/run-controller-adapter.js +400 -0
  483. package/dist/services/run-controller-capture.js +186 -0
  484. package/dist/services/run-controller-process.js +205 -0
  485. package/dist/services/run-controller-recovery.js +295 -0
  486. package/dist/services/run-controller-state.js +97 -0
  487. package/dist/services/run-controller.js +1326 -0
  488. package/dist/services/run-engine-bindings.js +1 -1
  489. package/dist/services/run-fork.js +147 -0
  490. package/dist/services/run-health.js +149 -0
  491. package/dist/services/run-observations.js +152 -0
  492. package/dist/services/run-projection.js +22 -64
  493. package/dist/services/run-recovery-guard.js +107 -0
  494. package/dist/services/run-recovery-runtime.js +112 -0
  495. package/dist/services/run-recovery.js +456 -0
  496. package/dist/services/run-start-custody.js +189 -0
  497. package/dist/services/runs.js +1023 -246
  498. package/dist/services/runtime-budget.js +446 -0
  499. package/dist/services/runtime-command.js +43 -0
  500. package/dist/services/runtime-scope-capture.js +52 -0
  501. package/dist/services/runtime-scope-control.js +468 -0
  502. package/dist/services/runtime-scope-resume.js +605 -0
  503. package/dist/services/runtime-scope-stop.js +211 -0
  504. package/dist/services/runtime-scope-worker.js +314 -0
  505. package/dist/services/runtime-service.js +19 -14
  506. package/dist/services/schema-validation.js +10 -8
  507. package/dist/services/scope-writer-cleanup.js +27 -0
  508. package/dist/services/sessions.js +36 -91
  509. package/dist/services/setup.js +427 -0
  510. package/dist/services/stage-blocker.js +17 -7
  511. package/dist/services/stage-context.js +193 -19
  512. package/dist/services/stage-handlers.js +89 -0
  513. package/dist/services/stage-lifecycle.js +152 -116
  514. package/dist/services/stage-pause.js +202 -91
  515. package/dist/services/stage-report-renderer.js +234 -6
  516. package/dist/services/stage-work-graph.js +52 -0
  517. package/dist/services/tooling.js +41 -30
  518. package/dist/services/usage.js +49 -101
  519. package/dist/services/verification-matrix.js +393 -0
  520. package/dist/services/version-status.js +1 -1
  521. package/dist/services/vnext-code-review.js +235 -88
  522. package/dist/services/vnext-code.js +327 -226
  523. package/dist/services/vnext-contracts.js +10 -1
  524. package/dist/services/vnext-execution-profile.js +80 -5
  525. package/dist/services/vnext-fanout.js +355 -21
  526. package/dist/services/vnext-merge.js +332 -111
  527. package/dist/services/vnext-plan-review.js +287 -132
  528. package/dist/services/vnext-plan.js +228 -104
  529. package/dist/services/vnext-protocolize.js +533 -95
  530. package/dist/services/vnext-specify.js +123 -81
  531. package/dist/services/vnext-workspace-policy.js +7 -2
  532. package/dist/services/work-registry.js +1706 -200
  533. package/dist/services/workspace-bootstrap.js +53 -15
  534. package/dist/services/workspace-files.js +85 -0
  535. package/dist/services/worktrees.js +105 -48
  536. package/dist/shared/entity-references.js +1 -0
  537. package/dist/shared/errors.js +27 -0
  538. package/dist/storage/agent-output.js +26 -0
  539. package/dist/storage/data-preservation.js +65 -0
  540. package/dist/storage/database.js +930 -40
  541. package/dist/storage/foreign-key-transaction.js +39 -0
  542. package/dist/storage/immutable-input.js +45 -0
  543. package/dist/storage/import-guard.js +159 -0
  544. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  545. package/dist/storage/native-cleanup.js +52 -0
  546. package/dist/storage/paired-writer-migration.js +424 -0
  547. package/dist/storage/paths.js +17 -4
  548. package/dist/storage/projection-lock.js +73 -0
  549. package/dist/storage/work-references.js +23 -0
  550. package/dist/storage/writer-contract.js +96 -0
  551. package/dist/storage/writer-migration.js +346 -0
  552. package/dist/storage/writer-restore.js +217 -0
  553. package/package.json +50 -13
  554. package/tools/create-canon-release.mjs +33 -0
  555. package/tools/probe-codex-history.mjs +37 -0
  556. package/tools/produce-hybrid-release.mjs +41 -0
  557. package/tools/repair-paused-run-status.mjs +84 -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 { assertSourceRepairEligible } 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";
12
+ import { runtimeCommand, checkRetryArgs } from "./runtime-command.js";
11
13
  import { assertStageStartHookEvent } from "./hooks.js";
12
14
  import { requireVnextWorkspaceRoute } from "./vnext-workspace-policy.js";
13
- import { addVnextCodeRepair } from "./vnext-code.js";
14
- import { finalCodeCheckDeclarations, runCodeChecks, unchangedFinalGateFailures, 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 } 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,40 +185,56 @@ 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");
@@ -172,41 +245,95 @@ export async function finishVnextCodeReview(context, input) {
172
245
  const outcome = decision.findings.some((item) => item.disposition === "defer") ? "accepted_with_DEF" : "accepted";
173
246
  const repairs = reviewRepairWorks(context, project.id, run.id, root, cycle);
174
247
  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
- const unchangedFailures = unchangedFinalGateFailures(context, { projectId: project.id, runId: run.id, workspaceRoot: run.workspace_root, declarations: finalChecks });
176
- if (unchangedFailures.length)
177
- throw new AppError("code_review_gate_repair_required", "CODE-REVIEW final gate already failed for the unchanged workspace; repair the evidenced failure before retrying", 2, { outcome: "repair_required", retry_after_workspace_change: true, workspace_fingerprint: unchangedFailures[0].workspace_fingerprint, failures: unchangedFailures });
178
- 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 } : {}) });
248
+ if (input.retryCheckId) {
249
+ validateFailedCheckRetry(context, { projectId: project.id, runId: run.id, receiptId: input.retryCheckId, declarations: finalChecks, reason: input.retryReason });
250
+ appendFlowRunTimelineEvent(context, project.id, run.id, { type: "check_retry_requested", check_receipt_id: input.retryCheckId, stage, reason: input.retryReason ?? "operator retry" });
251
+ }
252
+ 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 } : {}) });
253
+ const matrix = prepareRunVerificationMatrix(context, { projectId: project.id, runId: run.id, stage, role: "output", receipts, semanticFile: decisionFile });
179
254
  const failed = receipts.filter((receipt) => receipt.status !== "passed");
180
- if (failed.length)
255
+ if (failed.length) {
256
+ assertSourceRepairEligible(failed);
257
+ context.db.writeTransaction(() => acceptVerificationMatrix(context, matrix));
258
+ publishVerificationMatrix(context, matrix);
181
259
  throw new AppError("code_review_gate_failed", "CODE-REVIEW repair changed the project but the aggregate gate failed", 2, {
182
260
  failures: failed,
183
261
  outcome: "repair_required",
184
262
  retry_after_workspace_change: true,
185
263
  workspace_fingerprint: failed[0].workspace_fingerprint,
186
- 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`
264
+ continuation: registerAggregateCodeRepair(context, { projectRoot, runId: run.id, stage, failures: failed, checks: finalChecks, generation }),
265
+ ...(matrix ? { verification_matrix: matrix.metadata } : {}),
266
+ 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")}`
187
267
  });
268
+ }
188
269
  const stopTarget = executionStopTarget(run);
189
270
  const nextAction = stopTarget === "merge_completed" ? "start_merge" : "code_review_completed";
190
271
  const now = context.now();
191
272
  const startedAt = stageStartedAt(run, now);
192
- 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" } };
273
+ 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" } };
193
274
  // The request must exist before CODE-REVIEW becomes terminal. Otherwise a
194
275
  // merge-gate error creates an irrecoverable `done` report with no MRG-*.
195
276
  const acceptedPaths = changedPaths(run.workspace_root);
196
- const mergeRequest = nextAction === "start_merge" ? ensureVnextMergeRequest(context, { projectRoot, runId: run.id, acceptedPaths }) : null;
197
- writeReport(root, report);
198
- 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" });
199
- appendFlowRunTimelineEvent(context, project.id, run.id, { type: "code_review_completed", work_id: rootWork.work_id, outcome });
200
- if (nextAction === "start_merge")
201
- advanceFlowRun(context, { projectRoot, runId: run.id, status: "running", verdict: "code_review_completed", nextAction });
202
- else {
203
- await finishWork(context, rootWork.work_id, JSON.stringify(report, null, 2));
204
- completeFlowRun(context, { projectRoot, runId: run.id, status: "done", verdict: "code_review_completed", nextAction: undefined });
277
+ let mergeRequest = null;
278
+ assertRunMutationAllowed(context, project.id, run.id, generation);
279
+ const prepareMerge = nextAction === "start_merge" ? prepareVnextMergeRequest(context, { projectRoot, runId: run.id, acceptedPaths }) : null;
280
+ if (matrix)
281
+ Object.assign(report.semantic, { verification_matrix: matrix.metadata });
282
+ if (JSON.stringify(defEvidence) !== JSON.stringify(decision.findings.filter(item => item.disposition === "defer").map(item => reviewDefEvidence(run.workspace_root, item.def_id))))
283
+ throw new AppError("deferral_invalid", "DEF evidence changed while final checks ran", 2);
284
+ Object.assign(report.semantic, { def_evidence: defEvidence });
285
+ if (intentEvidence)
286
+ Object.assign(report.semantic, { accepted_intent_review: intentEvidence });
287
+ const preparedReport = prepareStageReport(report);
288
+ 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 };
289
+ withStageSettlement(context, () => {
290
+ assertAcceptedIntentReviewCurrent(context, { projectId: project.id, runId: run.id }, intentEvidence);
291
+ assertRunMutationAllowed(context, project.id, run.id, generation);
292
+ const currentReviewers = reviewerWorks(context, project.id, run.id, cycle);
293
+ const currentRepairs = reviewRepairWorks(context, project.id, run.id, root, cycle);
294
+ 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))) {
295
+ throw new AppError("reviewer_jobs_incomplete", "Review or repair results changed while the final checks were running", 2);
296
+ }
297
+ mergeRequest = prepareMerge?.() ?? null;
298
+ const preparedCompletion = prepareFlowRunStageCompletion(context, completionInput);
299
+ acceptVerificationMatrix(context, matrix);
300
+ acceptStageReport(context, { projectId: project.id, runId: run.id, stage, root, prepared: preparedReport });
301
+ completeFlowRunStage(context, completionInput, preparedCompletion);
302
+ appendFlowRunTimelineEvent(context, project.id, run.id, { type: "code_review_completed", work_id: rootWork.work_id, outcome });
303
+ if (nextAction === "start_merge")
304
+ advanceFlowRun(context, { settlementStage: "code-review", projectRoot, runId: run.id, status: "running", verdict: "code_review_completed", nextAction });
305
+ else {
306
+ finishStageCoordinatorWork(context, rootWork.work_id, JSON.stringify(report, null, 2));
307
+ completeFlowRun(context, { projectRoot, runId: run.id, status: "done", verdict: "code_review_completed", nextAction: undefined });
308
+ }
309
+ refreshRunWorkProjection(context, project.id, run.id);
310
+ });
311
+ 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"]) }) } : {}) };
312
+ }
313
+ export function readCodeReviewDecision(file, accepted, explicit = false, prepared) {
314
+ if (!accepted)
315
+ return prepared ?? prepareJsonFile(file, "CODE-REVIEW decision").value;
316
+ if ((prepared !== undefined || (explicit && fs.existsSync(file))) && JSON.stringify(prepared ?? prepareJsonFile(file, "CODE-REVIEW decision").value) !== JSON.stringify(accepted)) {
317
+ throw new AppError("review_decision_changed", "This review cycle already accepted a different decision", 2, { decision_file: file });
205
318
  }
206
- refreshRunWorkProjection(context, project.id, run.id);
207
- 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` } } : {}) };
319
+ return accepted;
320
+ }
321
+ function disabledReviewDecision() {
322
+ return { schema_id: "dd-flow/code-review-decision@3", summary: "CODE-REVIEW is disabled by RUN configuration.", findings: [] };
208
323
  }
209
- function reviewGroups(home) {
324
+ /** Retained decisions remain authoritative after their caller file is gone. */
325
+ export function prepareCodeReviewDecision(runRoot, file) {
326
+ const root = path.join(runRoot, "06-code-review");
327
+ const context = readJson(path.join(root, "review-context.json"));
328
+ const source = path.resolve(file ?? path.join(root, "decision.json"));
329
+ if (context.accepted_decision && !fs.existsSync(source))
330
+ return { value: context.accepted_decision };
331
+ if (context.mode === "off" && !file && !fs.existsSync(source))
332
+ return { value: disabledReviewDecision() };
333
+ const prepared = prepareJsonFile(source, "CODE-REVIEW decision");
334
+ return { value: readCodeReviewDecision(source, context.accepted_decision, Boolean(file), prepared.value), text: prepared.text };
335
+ }
336
+ export function reviewGroups(home) {
210
337
  const expected = new Set(baselineAspects);
211
338
  const declared = [];
212
339
  for (const file of findFiles(path.join(home, "03-plan"), "aspect-map.json")) {
@@ -221,19 +348,40 @@ function reviewGroups(home) {
221
348
  if (!declared.length)
222
349
  return [{ key: "baseline", aspect_ids: [...expected].sort() }];
223
350
  const assigned = new Set();
351
+ const scoped = new Set();
224
352
  for (const group of declared)
225
353
  for (const aspectId of group.aspect_ids) {
226
- if (assigned.has(aspectId))
227
- throw new AppError("code_review_groups_invalid", "A CODE-REVIEW aspect appears in more than one accepted group", 2, { aspect_id: aspectId });
354
+ const assignment = `${group.key.slice(0, group.key.lastIndexOf("/"))}/${aspectId}`;
355
+ if (scoped.has(assignment))
356
+ 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 });
357
+ scoped.add(assignment);
228
358
  assigned.add(aspectId);
229
359
  }
230
360
  const missing = [...expected].filter((aspectId) => !assigned.has(aspectId)).sort();
231
361
  return [...declared, ...(missing.length ? [{ key: "baseline", aspect_ids: missing }] : [])];
232
362
  }
363
+ export function assertCodeReviewCoverage(groups, reviewers) {
364
+ const expected = new Map(groups.map(group => [group.key, [...group.aspect_ids].sort()]));
365
+ if (!expected.size || expected.size !== groups.length)
366
+ throw new AppError("reviewer_coverage_invalid", "CODE-REVIEW expected group identities must be nonempty and unique", 2);
367
+ const seen = new Set();
368
+ for (const work of reviewers) {
369
+ const group = readJsonString(work.payload_json).group;
370
+ 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)))
371
+ throw new AppError("reviewer_coverage_invalid", "CODE-REVIEW Work does not match its expected group", 2, { work_id: work.work_id });
372
+ seen.add(group.key);
373
+ }
374
+ const missing = [...expected.keys()].filter(key => !seen.has(key));
375
+ if (missing.length || !expected.size)
376
+ throw new AppError("reviewer_coverage_invalid", "CODE-REVIEW requires every expected reviewer group", 2, { missing_groups: missing });
377
+ }
233
378
  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.`; }
234
- 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"); }
379
+ 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. Review is not repeated.", "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"); }
235
380
  function canonicalReviewEvidence(decision, reviewers) {
236
- const known = new Set(canonicalCodeFindings(reviewers).map((item) => item.finding_ref));
381
+ const known = new Map(canonicalCodeFindings(reviewers).map((item) => [item.finding_ref, item.finding]));
382
+ const refs = decision.findings.map(item => item.finding_ref);
383
+ if (new Set(refs).size !== refs.length || refs.some(ref => !known.has(ref)))
384
+ throw new AppError("review_evidence_invalid", "CODE decisions must use unique known canonical finding references", 2, { finding_refs: refs });
237
385
  const items = new Map(decision.findings.map((item) => [item.finding_ref, item]));
238
386
  const duplicates = new Set();
239
387
  for (const item of decision.findings.filter((entry) => entry.disposition === "duplicate")) {
@@ -249,6 +397,9 @@ function canonicalReviewEvidence(decision, reviewers) {
249
397
  }
250
398
  if (!cursor)
251
399
  throw new AppError("review_evidence_invalid", "Duplicate finding chain must end at a decided canonical finding", 2, { finding_ref: item.finding_ref });
400
+ if (["p0", "p1"].includes(known.get(item.finding_ref).priority) && cursor.disposition !== "fix") {
401
+ 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 });
402
+ }
252
403
  duplicates.add(item.finding_ref);
253
404
  }
254
405
  return {
@@ -299,8 +450,7 @@ function validateDecision(context, input) {
299
450
  if (item.disposition === "fix" && !repaired.some((work) => requiredChecks.every((ref) => reviewCheckRefs(work).includes(ref))))
300
451
  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 });
301
452
  if (finding.priority === "p2" && item.disposition === "defer") {
302
- if (!item.def_id || !fs.existsSync(path.join(input.workspaceRoot, ".memory-bank", "defs", `${item.def_id}.md`)))
303
- throw new AppError("deferral_invalid", "A deferred P2 requires a named durable DEF", 2, { finding_ref: findingRef, def_id: item.def_id ?? null });
453
+ reviewDefEvidence(input.workspaceRoot, item.def_id);
304
454
  }
305
455
  if (finding.priority === "p3" && item.disposition === "defer")
306
456
  throw new AppError("deferral_invalid", "P3 observations are not deferred as DEF", 2, { finding_ref: findingRef });
@@ -357,13 +507,9 @@ function effectiveMode(home, run) { const index = JSON.parse(run.index_json); if
357
507
  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")
358
508
  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." }; }
359
509
  function executionStopTarget(run) { return JSON.parse(run.index_json).execution_profile?.settings?.stop_target ?? "code_review_completed"; }
360
- function changedPaths(workspaceRoot) { try {
361
- 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(/^.* -> /, ""));
362
- }
363
- catch {
364
- return [];
365
- } }
510
+ function changedPaths(workspaceRoot) { return workspaceChangedPaths(workspaceRoot); }
366
511
  function sha256File(file) { return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex"); }
512
+ function sha256Value(value) { return crypto.createHash("sha256").update(value).digest("hex"); }
367
513
  function stageStatus(run, name) { try {
368
514
  return JSON.parse(run.index_json).stage_runs?.find((item) => item.stage === name)?.status ?? null;
369
515
  }
@@ -391,7 +537,9 @@ function requireRun(context, projectId, runId) { const run = context.db.get("SEL
391
537
  throw new AppError("not_found", "RUN is not registered", 1); return run; }
392
538
  function requireHome(run) { if (!run.run_root)
393
539
  throw new AppError("runtime_missing", "RUN artifact root is unavailable", 1); return run.run_root; }
394
- 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`; }
540
+ export function finishCommand(context, runId, projectRoot, decision, retryCheckId) {
541
+ 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)]));
542
+ }
395
543
  function findFiles(root, name) { if (!fs.existsSync(root))
396
544
  return []; const out = []; for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
397
545
  const file = path.join(root, entry.name);
@@ -409,4 +557,3 @@ function readJsonString(value) { try {
409
557
  catch {
410
558
  return {};
411
559
  } }
412
- function writeReport(root, report) { writeStageReport(root, report); }