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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (670) hide show
  1. package/CHANGELOG.md +965 -0
  2. package/README.md +139 -10
  3. package/dist/build-info.json +8 -8
  4. package/dist/cli/argument-values.js +38 -0
  5. package/dist/cli/command-inputs.js +417 -0
  6. package/dist/cli/command-metadata.js +303 -0
  7. package/dist/cli/command-option-descriptions.js +192 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/delivery.js +108 -0
  11. package/dist/cli/diagnostic-invocation.js +62 -0
  12. package/dist/cli/diagnostic.js +131 -0
  13. package/dist/cli/error-output.js +62 -0
  14. package/dist/cli/executor-onboarding.js +76 -0
  15. package/dist/cli/flows.js +29 -0
  16. package/dist/cli/harnesses.js +84 -0
  17. package/dist/cli/help.js +521 -19
  18. package/dist/cli/hook-ingress.js +89 -0
  19. package/dist/cli/input-preparation.js +193 -0
  20. package/dist/cli/interactive-invocation.js +33 -0
  21. package/dist/cli/interactive.js +114 -0
  22. package/dist/cli/memory-fix-invocation.js +52 -0
  23. package/dist/cli/memory-fix.js +100 -0
  24. package/dist/cli/memory-flow-admission.js +54 -0
  25. package/dist/cli/memory-init-invocation.js +85 -0
  26. package/dist/cli/memory-init.js +250 -0
  27. package/dist/cli/memory-storage-admission.js +54 -0
  28. package/dist/cli/memory-storage-qualification.js +105 -0
  29. package/dist/cli/memory-storage-transition.js +123 -0
  30. package/dist/cli/memory-upgrade.js +189 -0
  31. package/dist/cli/models.js +39 -0
  32. package/dist/cli/native-hook-ingress.js +94 -0
  33. package/dist/cli/native-hook-preparation.js +82 -0
  34. package/dist/cli/operator-profiles.js +61 -0
  35. package/dist/cli/output-options.js +35 -0
  36. package/dist/cli/response-file.js +72 -0
  37. package/dist/cli/run-cli.js +2020 -555
  38. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  39. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  40. package/dist/cli/runtime-process.js +153 -0
  41. package/dist/cli/setup.js +150 -0
  42. package/dist/cli.js +103 -2
  43. package/dist/domain/delivery-flows.js +8 -0
  44. package/dist/domain/diagnostic-aspects.js +103 -0
  45. package/dist/domain/diagnostic-flows.js +8 -0
  46. package/dist/domain/distill-flow.js +20 -0
  47. package/dist/domain/interactive-flow.js +1 -0
  48. package/dist/domain/memory-fix-flow.js +2 -0
  49. package/dist/domain/review-fix-flow.js +2 -0
  50. package/dist/domain/source-snapshot-flows.js +4 -0
  51. package/dist/domain/stage-catalog.js +1 -1
  52. package/dist/domain/stage-handler-identities.js +28 -0
  53. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  54. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  55. package/dist/harness-runtime/bin/dd-agy.mjs +71 -0
  56. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  57. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  58. package/dist/harness-runtime/bin/dd-grok.mjs +50 -0
  59. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  60. package/dist/harness-runtime/bin/dd-zcode.mjs +95 -0
  61. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  62. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  63. package/dist/harness-runtime/lib/agy-error-boundary.mjs +87 -0
  64. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  65. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  66. package/dist/harness-runtime/lib/agy-native-inspection.mjs +225 -0
  67. package/dist/harness-runtime/lib/agy-native-inventory.mjs +19 -0
  68. package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
  69. package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +74 -0
  70. package/dist/harness-runtime/lib/agy-transcript-stream.mjs +54 -0
  71. package/dist/harness-runtime/lib/daemon-observation.d.mts +3 -0
  72. package/dist/harness-runtime/lib/daemon-observation.mjs +171 -0
  73. package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
  74. package/dist/harness-runtime/lib/daemon-operations.mjs +512 -0
  75. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +7 -0
  76. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1362 -0
  77. package/dist/harness-runtime/lib/dd-agy.mjs +105 -0
  78. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  79. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +271 -0
  80. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  81. package/dist/harness-runtime/lib/dd-codex.mjs +986 -0
  82. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +155 -0
  83. package/dist/harness-runtime/lib/dd-droid.mjs +739 -0
  84. package/dist/harness-runtime/lib/dd-grok-daemon.d.mts +1 -0
  85. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +667 -0
  86. package/dist/harness-runtime/lib/dd-grok.mjs +182 -0
  87. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +772 -0
  88. package/dist/harness-runtime/lib/dd-opencode.mjs +411 -0
  89. package/dist/harness-runtime/lib/dd-zcode-daemon.d.mts +1 -0
  90. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +845 -0
  91. package/dist/harness-runtime/lib/dd-zcode.mjs +1239 -0
  92. package/dist/harness-runtime/lib/delegation-instructions.d.mts +16 -0
  93. package/dist/harness-runtime/lib/delegation-instructions.mjs +179 -0
  94. package/dist/harness-runtime/lib/delivery-command.mjs +84 -0
  95. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  96. package/dist/harness-runtime/lib/driver-recovery.mjs +121 -0
  97. package/dist/harness-runtime/lib/droid-observation.mjs +70 -0
  98. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  99. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  100. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  101. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  102. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  103. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  104. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +11 -0
  105. package/dist/harness-runtime/lib/lifecycle-contract.mjs +20 -0
  106. package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
  107. package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
  108. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  109. package/dist/harness-runtime/lib/model-observations.mjs +113 -0
  110. package/dist/harness-runtime/lib/native-children.d.mts +34 -0
  111. package/dist/harness-runtime/lib/native-children.mjs +265 -0
  112. package/dist/harness-runtime/lib/native-hook-command.d.mts +8 -0
  113. package/dist/harness-runtime/lib/native-hook-command.mjs +306 -0
  114. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  115. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  116. package/dist/harness-runtime/lib/native-streams.mjs +38 -0
  117. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  118. package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
  119. package/dist/harness-runtime/lib/opencode-plugin.mjs +112 -0
  120. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  121. package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
  122. package/dist/harness-runtime/lib/operation-errors.mjs +140 -0
  123. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  124. package/dist/harness-runtime/lib/operation-progress.mjs +118 -0
  125. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  126. package/dist/harness-runtime/lib/process-json.mjs +200 -0
  127. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  128. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +23 -0
  129. package/dist/harness-runtime/lib/provider-overload-policy.mjs +242 -0
  130. package/dist/harness-runtime/lib/runner-events.mjs +202 -0
  131. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  132. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  133. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  134. package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
  135. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  136. package/dist/harness-runtime/lib/tool-observations.mjs +238 -0
  137. package/dist/harness-runtime/lib/zcode-native-hook-ownership.mjs +109 -0
  138. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  139. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  140. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  141. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  142. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  143. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  144. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  145. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  146. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  147. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  148. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  149. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  150. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  151. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  152. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  153. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  154. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  155. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  156. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  157. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  158. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  159. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  160. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  161. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  162. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  163. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  164. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  165. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  166. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  167. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  168. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  169. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  170. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  171. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  172. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  173. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  174. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  175. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  176. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  177. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  178. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  179. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  180. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  181. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  182. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  183. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  184. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  185. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  186. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  187. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  188. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  189. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  190. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  191. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  192. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  193. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  194. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  195. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  196. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  197. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  198. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  199. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  200. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  201. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  202. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  203. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  204. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  205. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  206. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  207. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  208. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  209. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  210. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  211. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  212. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  213. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  214. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  215. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  216. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  217. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  218. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  219. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  220. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  221. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  222. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  223. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  224. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  225. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  226. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  227. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  228. package/dist/protocol/local-files.js +18 -9
  229. package/dist/runtime/context.js +8 -4
  230. package/dist/schemas/agent-profile.schema.json +1 -1
  231. package/dist/schemas/code-review-decision.schema.json +9 -0
  232. package/dist/schemas/code-review-result.schema.json +1 -1
  233. package/dist/schemas/code-verification.schema.json +7 -5
  234. package/dist/schemas/code-work-batch.schema.json +2 -2
  235. package/dist/schemas/code-work-result.schema.json +2 -1
  236. package/dist/schemas/delivery-stage-result.schema.json +286 -0
  237. package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
  238. package/dist/schemas/diagnostic-work-result.schema.json +296 -0
  239. package/dist/schemas/discovery-result.schema.json +184 -0
  240. package/dist/schemas/distill-stage-result.schema.json +667 -0
  241. package/dist/schemas/distill-work-result.schema.json +428 -0
  242. package/dist/schemas/execution-bundle.schema.json +215 -0
  243. package/dist/schemas/execution-settings.schema.json +162 -0
  244. package/dist/schemas/flow-descriptor.schema.json +54 -0
  245. package/dist/schemas/flow-run.schema.json +29 -0
  246. package/dist/schemas/harness-catalog.schema.json +80 -0
  247. package/dist/schemas/interactive-stage-result.schema.json +47 -0
  248. package/dist/schemas/interactive-work-result.schema.json +63 -0
  249. package/dist/schemas/mb-fix-stage-result.schema.json +93 -0
  250. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  251. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  252. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  253. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  254. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  255. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  256. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  257. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  258. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  259. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  260. package/dist/schemas/memory-repair-work-result.schema.json +56 -0
  261. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  262. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  263. package/dist/schemas/model-catalog.schema.json +153 -0
  264. package/dist/schemas/plan-review-decision.schema.json +12 -3
  265. package/dist/schemas/plan-review-result.schema.json +2 -2
  266. package/dist/schemas/profile-settings.schema.json +122 -0
  267. package/dist/schemas/project-flow-pack-manifest.schema.json +2 -2
  268. package/dist/schemas/release-impact.schema.json +3 -3
  269. package/dist/schemas/release-manifest.schema.json +291 -0
  270. package/dist/schemas/review-fix-stage-result.schema.json +210 -0
  271. package/dist/schemas/run-control-receipt.schema.json +119 -0
  272. package/dist/schemas/run-control-request.schema.json +36 -0
  273. package/dist/schemas/run-engine-binding.schema.json +1 -1
  274. package/dist/schemas/stage-start-response.schema.json +4 -0
  275. package/dist/schemas/vnext-protocol-plan.schema.json +3 -3
  276. package/dist/services/accepted-intent.js +139 -0
  277. package/dist/services/assigned-lifecycle.js +382 -0
  278. package/dist/services/branch-context.js +3 -3
  279. package/dist/services/canon.js +54 -15
  280. package/dist/services/check-environment.js +21 -0
  281. package/dist/services/check-runner-evidence.js +344 -0
  282. package/dist/services/check-runner-proof.js +373 -0
  283. package/dist/services/cleanup.js +133 -40
  284. package/dist/services/cli-operation-classifier.js +32 -64
  285. package/dist/services/cli-upgrade-allowlist.js +27 -0
  286. package/dist/services/code-checks.js +1426 -121
  287. package/dist/services/codex-capacity.js +367 -0
  288. package/dist/services/codex-hook-delivery.js +41 -0
  289. package/dist/services/command-context.js +80 -0
  290. package/dist/services/compatibility-preflight.js +16 -3
  291. package/dist/services/config.js +11 -8
  292. package/dist/services/continuation-outcome.js +25 -0
  293. package/dist/services/controller-child-capacity.js +71 -0
  294. package/dist/services/controller-child-observer.js +121 -0
  295. package/dist/services/controller-child-repair.js +117 -0
  296. package/dist/services/controller-execution.js +97 -0
  297. package/dist/services/controller-fanout.js +277 -0
  298. package/dist/services/controller-memory-task.js +45 -0
  299. package/dist/services/controller-memory-worker.js +51 -0
  300. package/dist/services/controller-result-authority.js +127 -0
  301. package/dist/services/controller-work-failure.js +198 -0
  302. package/dist/services/dashboard.js +145 -58
  303. package/dist/services/delivery-access.js +123 -0
  304. package/dist/services/delivery-approval.js +68 -0
  305. package/dist/services/delivery-artifact.js +86 -0
  306. package/dist/services/delivery-checks.js +178 -0
  307. package/dist/services/delivery-execution.js +181 -0
  308. package/dist/services/delivery-intents.js +212 -0
  309. package/dist/services/delivery-operation.js +81 -0
  310. package/dist/services/delivery-policy.js +91 -0
  311. package/dist/services/delivery-procedures.js +43 -0
  312. package/dist/services/delivery-request.js +99 -0
  313. package/dist/services/delivery-result.js +144 -0
  314. package/dist/services/delivery-stage-commands.js +26 -0
  315. package/dist/services/delivery-stage-entry.js +56 -0
  316. package/dist/services/delivery-stage-handlers.js +135 -0
  317. package/dist/services/delivery-stage-results.js +94 -0
  318. package/dist/services/descriptor-coordinator-session.js +37 -0
  319. package/dist/services/descriptor-root-work.js +53 -0
  320. package/dist/services/descriptor-run-settlement.js +107 -0
  321. package/dist/services/descriptor-run-start.js +495 -0
  322. package/dist/services/descriptor-stage-coordinator.js +318 -0
  323. package/dist/services/descriptor-stage-settlement.js +268 -0
  324. package/dist/services/descriptor-stage-start.js +175 -0
  325. package/dist/services/diagnostic-evidence.js +73 -0
  326. package/dist/services/diagnostic-repair-intake.js +123 -0
  327. package/dist/services/diagnostic-repair-source-intake.js +102 -0
  328. package/dist/services/diagnostic-report-publication.js +72 -0
  329. package/dist/services/diagnostic-report.js +97 -0
  330. package/dist/services/diagnostic-run-bundle.js +113 -0
  331. package/dist/services/diagnostic-snapshot.js +159 -0
  332. package/dist/services/diagnostic-stage-handlers.js +109 -0
  333. package/dist/services/diagnostic-stage-results.js +158 -0
  334. package/dist/services/diagnostic-start.js +134 -0
  335. package/dist/services/diagnostic-work-batch.js +34 -0
  336. package/dist/services/diagnostic-work-collection.js +97 -0
  337. package/dist/services/diagnostic-work-registration.js +101 -0
  338. package/dist/services/diagnostic-work-results.js +93 -0
  339. package/dist/services/discovery/agy-discovery.js +2 -0
  340. package/dist/services/discovery/codex-discovery.js +2 -0
  341. package/dist/services/discovery/droid-discovery.js +2 -0
  342. package/dist/services/discovery/grok-discovery.js +2 -0
  343. package/dist/services/discovery/opencode-discovery.js +2 -0
  344. package/dist/services/discovery/static.js +31 -0
  345. package/dist/services/discovery/zcode-discovery.js +2 -0
  346. package/dist/services/distill-document-publication.js +280 -0
  347. package/dist/services/distill-promotion.js +197 -0
  348. package/dist/services/distill-publication-custody.js +162 -0
  349. package/dist/services/distill-stage-handlers.js +249 -0
  350. package/dist/services/distill-stage-results.js +105 -0
  351. package/dist/services/distill-user-inputs.js +4 -0
  352. package/dist/services/distill-work-batch.js +42 -0
  353. package/dist/services/distill-work-collection.js +74 -0
  354. package/dist/services/distill-work-registration.js +93 -0
  355. package/dist/services/distill-work-results.js +98 -0
  356. package/dist/services/engines.js +354 -163
  357. package/dist/services/eval-snapshots.js +1326 -150
  358. package/dist/services/execution-bundles.js +275 -0
  359. package/dist/services/execution-policy.js +185 -0
  360. package/dist/services/executor-onboarding.js +56 -0
  361. package/dist/services/external-work-launch.js +316 -0
  362. package/dist/services/flow-catalog.js +54 -0
  363. package/dist/services/flow-descriptors.js +82 -0
  364. package/dist/services/frozen-engine.js +404 -0
  365. package/dist/services/generic-execution.js +165 -0
  366. package/dist/services/harness-adapter.js +342 -35
  367. package/dist/services/harness-config.js +2 -0
  368. package/dist/services/harness-discovery.js +29 -0
  369. package/dist/services/harness-doctor.js +75 -0
  370. package/dist/services/harness-probe-effects.js +51 -0
  371. package/dist/services/harness-version-probe.js +100 -0
  372. package/dist/services/hook-memory-routing.js +188 -0
  373. package/dist/services/hook-recovery-guard.js +14 -0
  374. package/dist/services/hook-session-observation.js +24 -0
  375. package/dist/services/hooks.js +813 -327
  376. package/dist/services/hybrid-contracts.js +479 -0
  377. package/dist/services/hybrid-digest.js +14 -0
  378. package/dist/services/ids.js +29 -1
  379. package/dist/services/installation-lock.js +95 -0
  380. package/dist/services/installed-flow-source.js +261 -0
  381. package/dist/services/interactive-attached-session.js +215 -0
  382. package/dist/services/interactive-baseline-custody.js +54 -0
  383. package/dist/services/interactive-before-versions.js +148 -0
  384. package/dist/services/interactive-bundle-data.js +85 -0
  385. package/dist/services/interactive-checks.js +179 -0
  386. package/dist/services/interactive-execution.js +33 -0
  387. package/dist/services/interactive-finish-integration.js +236 -0
  388. package/dist/services/interactive-git-baseline.js +230 -0
  389. package/dist/services/interactive-git-dispatch.js +278 -0
  390. package/dist/services/interactive-input-delivery.js +82 -0
  391. package/dist/services/interactive-mutation-scope.js +231 -0
  392. package/dist/services/interactive-request.js +287 -0
  393. package/dist/services/interactive-run-bundle.js +109 -0
  394. package/dist/services/interactive-stage-entry.js +41 -0
  395. package/dist/services/interactive-stage-handlers.js +289 -0
  396. package/dist/services/interactive-stage-observation.js +136 -0
  397. package/dist/services/interactive-stage-results.js +111 -0
  398. package/dist/services/interactive-user-inputs.js +142 -0
  399. package/dist/services/interactive-work-batch.js +43 -0
  400. package/dist/services/interactive-work-collection.js +119 -0
  401. package/dist/services/interactive-work-completion.js +180 -0
  402. package/dist/services/interactive-work-context.js +249 -0
  403. package/dist/services/interactive-work-history.js +112 -0
  404. package/dist/services/interactive-work-registration.js +124 -0
  405. package/dist/services/interactive-work-results.js +115 -0
  406. package/dist/services/interactive-work-start.js +155 -0
  407. package/dist/services/lanes.js +78 -65
  408. package/dist/services/lifecycle-command.js +1 -288
  409. package/dist/services/lifecycle-contract.js +1 -0
  410. package/dist/services/lifecycle-invocations.js +2549 -0
  411. package/dist/services/managed-daemon-binding.js +129 -0
  412. package/dist/services/managed-lease-monitor.js +133 -0
  413. package/dist/services/managed-processes.js +449 -69
  414. package/dist/services/memory-accepted-composition.js +78 -0
  415. package/dist/services/memory-baseline-preservation.js +65 -0
  416. package/dist/services/memory-completed-correction-wave.js +328 -0
  417. package/dist/services/memory-compose-handler.js +380 -0
  418. package/dist/services/memory-composition-acceptance.js +375 -0
  419. package/dist/services/memory-composition-graph.js +165 -0
  420. package/dist/services/memory-composition-registration.js +161 -0
  421. package/dist/services/memory-composition-work-custody.js +156 -0
  422. package/dist/services/memory-composition-work-results.js +108 -0
  423. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  424. package/dist/services/memory-corrected-review-batch.js +37 -0
  425. package/dist/services/memory-corrected-review-findings.js +108 -0
  426. package/dist/services/memory-corrected-review-inputs.js +215 -0
  427. package/dist/services/memory-corrected-review-projection.js +78 -0
  428. package/dist/services/memory-corrected-review-receipt.js +178 -0
  429. package/dist/services/memory-corrected-review-registration.js +192 -0
  430. package/dist/services/memory-correction-check-receipt.js +235 -0
  431. package/dist/services/memory-correction-input-owner.js +6 -0
  432. package/dist/services/memory-custody-snapshot.js +36 -0
  433. package/dist/services/memory-discover-handler.js +104 -0
  434. package/dist/services/memory-finish-evidence.js +457 -0
  435. package/dist/services/memory-finish-handler.js +229 -0
  436. package/dist/services/memory-finish-integration.js +491 -0
  437. package/dist/services/memory-finish-readiness.js +169 -0
  438. package/dist/services/memory-fix-finish-integration.js +129 -0
  439. package/dist/services/memory-fix-git-dispatch.js +139 -0
  440. package/dist/services/memory-fix-intake-custody.js +11 -0
  441. package/dist/services/memory-fix-intake-settlement.js +127 -0
  442. package/dist/services/memory-fix-publication.js +196 -0
  443. package/dist/services/memory-fix-repair-admission.js +116 -0
  444. package/dist/services/memory-fix-request.js +141 -0
  445. package/dist/services/memory-fix-run-bundle.js +83 -0
  446. package/dist/services/memory-fix-scope.js +78 -0
  447. package/dist/services/memory-fix-sources.js +85 -0
  448. package/dist/services/memory-fix-stage-entry.js +24 -0
  449. package/dist/services/memory-fix-stage-handlers.js +282 -0
  450. package/dist/services/memory-fix-stage-results.js +106 -0
  451. package/dist/services/memory-fix-workspace.js +127 -0
  452. package/dist/services/memory-flow-user-inputs.js +88 -0
  453. package/dist/services/memory-git-integration.js +220 -0
  454. package/dist/services/memory-historical-corrected-review.js +212 -0
  455. package/dist/services/memory-historical-original-review.js +143 -0
  456. package/dist/services/memory-historical-repair-registration.js +105 -0
  457. package/dist/services/memory-historical-second-review.js +147 -0
  458. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  459. package/dist/services/memory-init-contexts.js +181 -0
  460. package/dist/services/memory-init-controller-start.js +119 -0
  461. package/dist/services/memory-init-engine-release.js +223 -0
  462. package/dist/services/memory-init-git-policy.js +165 -0
  463. package/dist/services/memory-init-lint-capability.js +203 -0
  464. package/dist/services/memory-init-native-capacity.js +309 -0
  465. package/dist/services/memory-init-preflight.js +334 -0
  466. package/dist/services/memory-init-project-bootstrap.js +599 -0
  467. package/dist/services/memory-init-request-candidate.js +213 -0
  468. package/dist/services/memory-init-request-input.js +82 -0
  469. package/dist/services/memory-init-resource-storage.js +125 -0
  470. package/dist/services/memory-init-run-allocation.js +81 -0
  471. package/dist/services/memory-init-run-bundle.js +135 -0
  472. package/dist/services/memory-init-start.js +181 -0
  473. package/dist/services/memory-init-startup-custody.js +80 -0
  474. package/dist/services/memory-init-startup-input.js +240 -0
  475. package/dist/services/memory-init-storage.js +91 -0
  476. package/dist/services/memory-init-stores.js +359 -0
  477. package/dist/services/memory-init-worktrunk-capability.js +174 -0
  478. package/dist/services/memory-layer-publication.js +611 -0
  479. package/dist/services/memory-layer.js +225 -0
  480. package/dist/services/memory-lint-config.js +194 -0
  481. package/dist/services/memory-native-review-copy.js +127 -0
  482. package/dist/services/memory-normal-flow-entry.js +87 -0
  483. package/dist/services/memory-ordinary-defaults.js +129 -0
  484. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  485. package/dist/services/memory-preflight-handler.js +274 -0
  486. package/dist/services/memory-repair-current-view.js +299 -0
  487. package/dist/services/memory-repair-document-delta.js +489 -0
  488. package/dist/services/memory-repair-history.js +496 -0
  489. package/dist/services/memory-repair-physical-binding.js +194 -0
  490. package/dist/services/memory-repair-publication-files.js +152 -0
  491. package/dist/services/memory-repair-publication-intent.js +27 -0
  492. package/dist/services/memory-repair-publication-plan.js +162 -0
  493. package/dist/services/memory-repair-publication-source.js +225 -0
  494. package/dist/services/memory-repair-publication.js +795 -0
  495. package/dist/services/memory-repair-registration.js +240 -0
  496. package/dist/services/memory-repair-work-baseline.js +415 -0
  497. package/dist/services/memory-repair-work-completion.js +117 -0
  498. package/dist/services/memory-repair-work-custody.js +73 -0
  499. package/dist/services/memory-repair-work-results.js +108 -0
  500. package/dist/services/memory-repair-workspace.js +261 -0
  501. package/dist/services/memory-repair-writer-copy.js +736 -0
  502. package/dist/services/memory-result-binding.js +239 -0
  503. package/dist/services/memory-retained-review-authority.js +138 -0
  504. package/dist/services/memory-retained-review-results.js +70 -0
  505. package/dist/services/memory-retained-second-baseline.js +102 -0
  506. package/dist/services/memory-retained-second-repairs.js +162 -0
  507. package/dist/services/memory-review-acceptance.js +214 -0
  508. package/dist/services/memory-review-correction-plan.js +206 -0
  509. package/dist/services/memory-review-handler.js +585 -0
  510. package/dist/services/memory-review-inputs.js +246 -0
  511. package/dist/services/memory-review-limits.js +10 -0
  512. package/dist/services/memory-review-receipt.js +180 -0
  513. package/dist/services/memory-review-registration.js +117 -0
  514. package/dist/services/memory-review-work-custody.js +126 -0
  515. package/dist/services/memory-review-work-input.js +91 -0
  516. package/dist/services/memory-review-work-results.js +95 -0
  517. package/dist/services/memory-second-corrected-review-inputs.js +167 -0
  518. package/dist/services/memory-second-correction-plan.js +77 -0
  519. package/dist/services/memory-second-repair-baseline.js +91 -0
  520. package/dist/services/memory-second-repair-launch.js +614 -0
  521. package/dist/services/memory-second-repair-registration.js +88 -0
  522. package/dist/services/memory-second-repair-source.js +187 -0
  523. package/dist/services/memory-second-review-acceptance.js +115 -0
  524. package/dist/services/memory-source-observations.js +117 -0
  525. package/dist/services/memory-stage-dispatch.js +65 -0
  526. package/dist/services/memory-stage-results.js +290 -0
  527. package/dist/services/memory-tool-probe.js +25 -0
  528. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  529. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  530. package/dist/services/memory-upgrade-evidence.js +100 -0
  531. package/dist/services/memory-upgrade-inventory.js +442 -0
  532. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  533. package/dist/services/memory-upgrade-publication.js +413 -0
  534. package/dist/services/memory-upgrade-selection.js +430 -0
  535. package/dist/services/memory-upgrade-start.js +60 -0
  536. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  537. package/dist/services/memory-verification-acceptance.js +156 -0
  538. package/dist/services/memory-verification-checks.js +317 -0
  539. package/dist/services/memory-verification-receipt.js +160 -0
  540. package/dist/services/memory-verify-handler.js +137 -0
  541. package/dist/services/memory-work-result-json.js +12 -0
  542. package/dist/services/memory-work-result-preparation.js +64 -0
  543. package/dist/services/merge-queue.js +228 -149
  544. package/dist/services/merge-server.js +163 -35
  545. package/dist/services/migrations.js +164 -114
  546. package/dist/services/model-catalog.js +109 -0
  547. package/dist/services/model-discovery.js +46 -0
  548. package/dist/services/native-daemon-history.js +50 -0
  549. package/dist/services/native-session-control.js +39 -0
  550. package/dist/services/operator-profiles.js +236 -0
  551. package/dist/services/physical-startup.js +45 -0
  552. package/dist/services/plan-runtime.js +26 -11
  553. package/dist/services/plans.js +28 -25
  554. package/dist/services/project-flow-source.js +195 -0
  555. package/dist/services/project-git-integration.js +92 -0
  556. package/dist/services/project-registry.js +97 -0
  557. package/dist/services/project-summary.js +1 -1
  558. package/dist/services/projects.js +17 -87
  559. package/dist/services/prompt-delivery.js +71 -0
  560. package/dist/services/prompts.js +28 -17
  561. package/dist/services/protocols.js +163 -87
  562. package/dist/services/provider-capacity.js +463 -0
  563. package/dist/services/recovery-observation-budget.js +121 -0
  564. package/dist/services/recovery-snapshot-database.js +588 -0
  565. package/dist/services/release-archive-producer.js +52 -0
  566. package/dist/services/release-archive.js +143 -0
  567. package/dist/services/release-cache.js +150 -0
  568. package/dist/services/release-compatibility.js +18 -0
  569. package/dist/services/release-download.js +67 -0
  570. package/dist/services/release-envelope.js +104 -0
  571. package/dist/services/release-manifest.js +45 -0
  572. package/dist/services/release-payload.js +114 -0
  573. package/dist/services/release-producer.js +63 -0
  574. package/dist/services/release-provenance.js +160 -0
  575. package/dist/services/release-registry.js +66 -0
  576. package/dist/services/release-source.js +194 -0
  577. package/dist/services/repair-intents.js +29 -0
  578. package/dist/services/repair-receipt.js +13 -0
  579. package/dist/services/retained-native-hook.js +274 -0
  580. package/dist/services/review-copy.js +165 -0
  581. package/dist/services/review-deferral.js +23 -0
  582. package/dist/services/review-fix-handoff.js +82 -0
  583. package/dist/services/review-fix-intake-custody.js +17 -0
  584. package/dist/services/review-fix-stage-entry.js +43 -0
  585. package/dist/services/review-fix-stage-handlers.js +176 -0
  586. package/dist/services/review-fix-stage-results.js +86 -0
  587. package/dist/services/run-control-receipt.js +56 -0
  588. package/dist/services/run-control-worker.js +469 -0
  589. package/dist/services/run-control.js +1109 -0
  590. package/dist/services/run-controller-adapter.js +434 -0
  591. package/dist/services/run-controller-capture.js +186 -0
  592. package/dist/services/run-controller-process.js +226 -0
  593. package/dist/services/run-controller-recovery.js +335 -0
  594. package/dist/services/run-controller-state.js +106 -0
  595. package/dist/services/run-controller.js +1717 -0
  596. package/dist/services/run-engine-bindings.js +1 -1
  597. package/dist/services/run-fork.js +147 -0
  598. package/dist/services/run-health.js +149 -0
  599. package/dist/services/run-observations.js +152 -0
  600. package/dist/services/run-projection.js +22 -64
  601. package/dist/services/run-recovery-guard.js +107 -0
  602. package/dist/services/run-recovery-runtime.js +112 -0
  603. package/dist/services/run-recovery.js +485 -0
  604. package/dist/services/run-start-custody.js +189 -0
  605. package/dist/services/run-timeline.js +59 -0
  606. package/dist/services/runs.js +996 -271
  607. package/dist/services/runtime-budget.js +446 -0
  608. package/dist/services/runtime-command.js +43 -0
  609. package/dist/services/runtime-scope-capture.js +52 -0
  610. package/dist/services/runtime-scope-control.js +468 -0
  611. package/dist/services/runtime-scope-resume.js +605 -0
  612. package/dist/services/runtime-scope-stop.js +211 -0
  613. package/dist/services/runtime-scope-worker.js +314 -0
  614. package/dist/services/runtime-service.js +19 -14
  615. package/dist/services/schema-validation.js +10 -8
  616. package/dist/services/scope-writer-cleanup.js +27 -0
  617. package/dist/services/sessions.js +37 -91
  618. package/dist/services/setup.js +427 -0
  619. package/dist/services/stage-blocker.js +17 -7
  620. package/dist/services/stage-context.js +240 -18
  621. package/dist/services/stage-handlers.js +141 -0
  622. package/dist/services/stage-lifecycle.js +156 -119
  623. package/dist/services/stage-pause.js +222 -94
  624. package/dist/services/stage-report-renderer.js +230 -6
  625. package/dist/services/stage-work-graph.js +52 -0
  626. package/dist/services/technical-notes.js +31 -0
  627. package/dist/services/tooling.js +111 -44
  628. package/dist/services/usage.js +49 -101
  629. package/dist/services/verification-matrix.js +393 -0
  630. package/dist/services/version-status.js +1 -1
  631. package/dist/services/vnext-code-review.js +302 -91
  632. package/dist/services/vnext-code.js +325 -251
  633. package/dist/services/vnext-contracts.js +10 -1
  634. package/dist/services/vnext-execution-profile.js +80 -5
  635. package/dist/services/vnext-fanout.js +399 -20
  636. package/dist/services/vnext-merge.js +336 -114
  637. package/dist/services/vnext-plan-review.js +288 -133
  638. package/dist/services/vnext-plan.js +257 -110
  639. package/dist/services/vnext-protocolize.js +534 -96
  640. package/dist/services/vnext-specify.js +131 -84
  641. package/dist/services/vnext-workspace-policy.js +7 -2
  642. package/dist/services/work-registry.js +1950 -215
  643. package/dist/services/work-retry-context.js +55 -0
  644. package/dist/services/workspace-bootstrap.js +53 -15
  645. package/dist/services/workspace-files.js +85 -0
  646. package/dist/services/worktrees.js +108 -48
  647. package/dist/shared/entity-references.js +1 -0
  648. package/dist/shared/errors.js +27 -0
  649. package/dist/storage/agent-output.js +26 -0
  650. package/dist/storage/data-preservation.js +65 -0
  651. package/dist/storage/database.js +931 -40
  652. package/dist/storage/foreign-key-transaction.js +39 -0
  653. package/dist/storage/immutable-input.js +45 -0
  654. package/dist/storage/import-guard.js +159 -0
  655. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  656. package/dist/storage/native-cleanup.js +52 -0
  657. package/dist/storage/paired-writer-migration.js +424 -0
  658. package/dist/storage/paths.js +17 -4
  659. package/dist/storage/projection-lock.js +73 -0
  660. package/dist/storage/work-references.js +23 -0
  661. package/dist/storage/writer-contract.js +96 -0
  662. package/dist/storage/writer-migration.js +346 -0
  663. package/dist/storage/writer-restore.js +217 -0
  664. package/dist/verification-components.json +384 -0
  665. package/package.json +52 -13
  666. package/tools/create-canon-release.mjs +33 -0
  667. package/tools/probe-codex-history.mjs +37 -0
  668. package/tools/produce-hybrid-release.mjs +41 -0
  669. package/tools/repair-paused-run-status.mjs +84 -0
  670. package/tools/verification-jobs.mjs +342 -0
@@ -0,0 +1,97 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ import { hybridDigest } from "./hybrid-contracts.js";
3
+ import { collectDiagnosticCandidates } from "./diagnostic-work-results.js";
4
+ function refuse(reason) { throw new AppError("diagnostic_report_invalid", "Diagnostic report requires the reviewed candidate and critic registers", 2, { reason, effect: "no_effect" }); }
5
+ /** Projection only. The handler separately owns source checks, physical critic
6
+ * independence, SQL custody, publication and terminal RUN settlement. */
7
+ export function prepareDiagnosticReport(result, analysis, critics) {
8
+ if (result.stage !== "report" || !critics.length
9
+ || [...analysis, ...critics].some(work => work.workId !== work.result.work_id || work.result.run_id !== result.run_id || work.result.flow_id !== result.flow_id))
10
+ refuse("foreign_work");
11
+ const candidates = collectDiagnosticCandidates(analysis);
12
+ if (hybridDigest(candidates.findings) !== hybridDigest(result.details.findings))
13
+ refuse("candidate_register_changed");
14
+ for (const critic of critics) {
15
+ const ids = critic.result.decisions.map(value => value.finding_id);
16
+ if (critic.result.stage !== "review" || critic.result.findings.length || new Set(ids).size !== ids.length
17
+ || ids.length !== candidates.findings.length || candidates.findings.some(value => !ids.includes(value.id)))
18
+ refuse("incomplete_critic");
19
+ }
20
+ const decisions = new Map(result.details.decisions.map(value => [value.finding_id, value]));
21
+ if (decisions.size !== candidates.findings.length || result.details.decisions.length !== decisions.size
22
+ || candidates.findings.some(value => !decisions.has(value.id)))
23
+ refuse("incomplete_resolution");
24
+ const findings = candidates.findings.map((finding, index) => ({ ...finding, origin: candidates.origins[index],
25
+ resolution: decisions.get(finding.id),
26
+ critic_decisions: critics.map(work => ({ work_id: work.workId, decision: work.result.decisions.find(value => value.finding_id === finding.id) })) }));
27
+ const incomplete = result.details.coverage.some(value => value.applicability === "blocked" || value.applicability === "out_of_scope")
28
+ || result.details.missing_expected_sources.length > 0 || result.details.limitations.length > 0;
29
+ const accepted = findings.filter(value => !["rejected", "duplicate"].includes(value.resolution.disposition));
30
+ const sourceMap = new Map();
31
+ for (const source of [...result.details.sources, ...result.details.coverage.flatMap(value => value.evidence),
32
+ ...analysis.flatMap(value => value.result.sources), ...critics.flatMap(value => value.result.sources),
33
+ ...findings.flatMap(value => [...value.evidence, ...value.resolution.evidence, ...value.critic_decisions.flatMap(critic => critic.decision.evidence)])]) {
34
+ if (sourceMap.has(source.path) && sourceMap.get(source.path).sha256 !== source.sha256)
35
+ refuse("conflicting_source_versions");
36
+ sourceMap.set(source.path, structuredClone(source));
37
+ }
38
+ return {
39
+ schema_id: "dd-flow/diagnostic-report@1",
40
+ run: { id: result.run_id, flow_id: result.flow_id, snapshot_sha256: result.snapshot_sha256 },
41
+ summary: result.summary, review_focus: structuredClone(result.details.focus), source_map: [...sourceMap.values()],
42
+ aspect_coverage: structuredClone(result.details.coverage),
43
+ critic_pass: critics.map(work => ({ work_id: work.workId, role: work.result.aspect_id, summary: work.result.summary,
44
+ semantic_sha256: hybridDigest(work.result), decisions: structuredClone(work.result.decisions), limitations: [...work.result.limitations] })),
45
+ findings_register: findings,
46
+ conformance_summary: { assessment: incomplete ? "incomplete" : accepted.length ? "findings" : "no_accepted_findings_in_selected_scope",
47
+ accepted_findings: accepted.length, rejected_or_duplicate_findings: findings.length - accepted.length,
48
+ applicable_aspects: result.details.coverage.filter(value => value.applicability === "applicable").length,
49
+ blocked_aspects: result.details.coverage.filter(value => value.applicability === "blocked").length,
50
+ missing_expected_sources: [...result.details.missing_expected_sources] },
51
+ review_fix_recommendation: { authorization: "not_granted", candidate_ids: findings.filter(value => value.resolution.disposition === "review_fix_candidate").map(value => value.id) },
52
+ deferrals: { authorization: "not_granted", candidate_ids: findings.filter(value => value.resolution.disposition === "def_candidate").map(value => value.id),
53
+ observed_sources: [...sourceMap.values()].filter(value => /(?:^|\/)DEF(?:-MBU)?-[^/]+/.test(value.path)) },
54
+ limitations: [...result.details.limitations],
55
+ dashboard_links: critics.map(work => ({ work_id: work.workId, result: `run://${result.run_id}/works/${work.workId}/result.json` }))
56
+ };
57
+ }
58
+ /** Pure repair-intake selection, not acceptance or mutation authority. The
59
+ * caller must obtain report bytes from the completed RUN's committed custody,
60
+ * then separately bind the user's approved write scope. Never infer selection
61
+ * from severity, recommendations or a non-empty findings register. */
62
+ export function selectDiagnosticFindings(report, findingIds) {
63
+ const invalid = (reason) => {
64
+ throw new AppError("repair_selection_invalid", "Select exact reviewed finding IDs before preparing repair scope", 2, { reason, effect: "no_effect" });
65
+ };
66
+ if (!Array.isArray(findingIds) || !findingIds.length || findingIds.length > 4096
67
+ || findingIds.some(id => typeof id !== "string" || !id.trim()) || new Set(findingIds).size !== findingIds.length)
68
+ invalid("explicit_unique_selection_required");
69
+ const register = new Map(report.findings_register.map(finding => [finding.id, finding]));
70
+ if (register.size !== report.findings_register.length)
71
+ invalid("ambiguous_finding_register");
72
+ const selected = findingIds.map(id => {
73
+ const finding = register.get(id);
74
+ if (!finding)
75
+ return invalid("unknown_finding");
76
+ if (!["accepted", "downgraded", "def_candidate", "review_fix_candidate"].includes(finding.resolution.disposition))
77
+ invalid("finding_not_accepted");
78
+ return structuredClone(finding);
79
+ });
80
+ return {
81
+ source: { ...structuredClone(report.run), report_sha256: hybridDigest(report) },
82
+ selected_findings: selected,
83
+ unselected_ids: report.findings_register.filter(finding => !findingIds.includes(finding.id)).map(finding => finding.id),
84
+ limitations: [...report.limitations],
85
+ authorization: "not_granted"
86
+ };
87
+ }
88
+ /** HTML embeds exactly the authoritative JSON value; untrusted prose is text,
89
+ * never HTML or executable script. Markdown remains a compact companion. */
90
+ export function renderDiagnosticReport(report) {
91
+ const json = Buffer.from(JSON.stringify(report, null, 2) + "\n");
92
+ const escape = (text) => text.replace(/[&<>"']/g, value => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[value]);
93
+ const embedded = json.toString("utf8").replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
94
+ const markdown = Buffer.from(`# ${report.run.flow_id} · ${report.run.id}\n\n${report.summary}\n\nAssessment: ${report.conformance_summary.assessment}\n\n${report.findings_register.length} findings retained; ${report.critic_pass.length} independent critic passes.\n\nAuthoritative data: diagnostic-report.json\n`);
95
+ const html = Buffer.from(`<!doctype html><html lang="en"><meta charset="utf-8"><title>${escape(report.run.flow_id)} · ${escape(report.run.id)}</title><body><h1>${escape(report.review_focus.title)}</h1><p>${escape(report.summary)}</p><p>${escape(report.conformance_summary.assessment)}</p><h2>Coverage</h2><ul>${report.aspect_coverage.map(value => `<li>${escape(value.id)}: ${escape(value.applicability)} — ${escape(value.reason)}</li>`).join("")}</ul><h2>Findings</h2><pre>${escape(JSON.stringify(report.findings_register, null, 2))}</pre><script id="diagnostic-report-data" type="application/json">${embedded}</script></body></html>\n`);
96
+ return { json, markdown, html };
97
+ }
@@ -0,0 +1,113 @@
1
+ import { createHash } from "node:crypto";
2
+ import { AppError } from "../shared/errors.js";
3
+ import { isSourceSnapshotFlow } from "../domain/source-snapshot-flows.js";
4
+ import { isDeliveryFlow } from "../domain/delivery-flows.js";
5
+ import { PreparedInstalledFlowSource } from "./installed-flow-source.js";
6
+ import { FrozenGenericExecution } from "./generic-execution.js";
7
+ import { AdmittedFrozenEngine } from "./frozen-engine.js";
8
+ import { RetainedExecutionBundle } from "./execution-bundles.js";
9
+ import { readDiagnosticSnapshot } from "./diagnostic-snapshot.js";
10
+ import { requireProjectByRoot } from "./projects.js";
11
+ import { nextDescriptorRunId } from "./descriptor-run-start.js";
12
+ import { bundledHandlerContext } from "./stage-handlers.js";
13
+ import { hybridDigest } from "./hybrid-contracts.js";
14
+ import { readDiagnosticRequest } from "./diagnostic-start.js";
15
+ const bytes = (value) => Buffer.from(JSON.stringify(value));
16
+ const hash = (value) => createHash("sha256").update(value).digest("hex");
17
+ function refuse(reason) { throw new AppError("diagnostic_run_bundle_invalid", "Diagnostic bundle requires its frozen source, execution and snapshot", 2, { reason, effect: "no_effect" }); }
18
+ /** Initial construction only. Retry after allocation restores the retained RUN
19
+ * bundle, never current operator settings/canon. boundAt belongs to the request. */
20
+ export function prepareDiagnosticRunBundle(context, input) {
21
+ return prepareRequestRunBundle(context, input, "source_snapshot");
22
+ }
23
+ /** Delivery shares immutable request/engine/profile retention, not diagnosis's
24
+ * read-only cloned workspace or its permission model. No effect is admitted. */
25
+ export function prepareDeliveryRunBundle(context, input) {
26
+ return prepareRequestRunBundle(context, input, "delivery");
27
+ }
28
+ function prepareRequestRunBundle(context, input, mode) {
29
+ if (!(input.source instanceof PreparedInstalledFlowSource) || !(input.execution instanceof FrozenGenericExecution)
30
+ || !(input.engine instanceof AdmittedFrozenEngine) || !Number.isFinite(Date.parse(input.boundAt)))
31
+ refuse("unprepared_selection");
32
+ const frozen = input.execution.snapshot(), flowId = frozen.settings.flow_id;
33
+ if (mode === "delivery" ? !isDeliveryFlow(flowId) : !isSourceSnapshotFlow(flowId))
34
+ refuse("registered_request_flow_required");
35
+ if (mode === "delivery" && frozen.settings.stage_session_mode === "same_session")
36
+ refuse("independent_delivery_verifier_session_required");
37
+ if (flowId === "review-fix" && frozen.settings.stage_session_mode === "same_session")
38
+ refuse("independent_scope_review_session_required");
39
+ if ((mode === "delivery" || flowId === "mb-distill" || flowId === "review-fix") && (typeof input.requestText !== "string" || !input.requestText.trim()
40
+ || Buffer.byteLength(input.requestText) > 64 * 1024))
41
+ refuse(mode === "delivery" ? "original_delivery_request_required" : flowId === "mb-distill" ? "original_distill_request_required" : "original_review_fix_request_required");
42
+ const request = flowId === "review-fix" ? readDiagnosticRequest(context, { projectRoot: frozen.scope.projectRoot,
43
+ requestId: frozen.scope.requestId, flowId }) : null;
44
+ if (flowId === "review-fix" && (!request?.repair_source || request.created_at !== input.boundAt
45
+ || request.objective !== input.requestText || request.source_sha256 !== input.source.sha256
46
+ || request.execution_sha256 !== input.execution.sha256))
47
+ refuse("original_repair_request_required");
48
+ const project = requireProjectByRoot(context, frozen.scope.projectRoot);
49
+ const snapshot = isSourceSnapshotFlow(flowId) ? readDiagnosticSnapshot(context, { projectId: project.id, projectRoot: frozen.scope.projectRoot,
50
+ sourceRoot: frozen.scope.projectRoot, requestId: frozen.scope.requestId, flowId }) : null;
51
+ if (mode === "source_snapshot" && (!snapshot || snapshot.root !== frozen.scope.workspace))
52
+ refuse("snapshot_selection_changed");
53
+ input.source.revalidate();
54
+ const flow = input.source.resolveRegisteredFlow();
55
+ if (flow.descriptor.id !== flowId || flow.sha256 !== frozen.settings.descriptor_sha256)
56
+ refuse("flow_selection_changed");
57
+ if (isDeliveryFlow(flowId))
58
+ input.engine.admitDeliveryFlow(input.source, flowId);
59
+ else if (flowId === "review-fix")
60
+ input.engine.admitReviewFixFlow(input.source);
61
+ else if (flowId === "mb-distill")
62
+ input.engine.admitDistillFlow(input.source);
63
+ else if (flowId === "mb-audit" || flowId === "project-review")
64
+ input.engine.admitDiagnosticFlow(input.source, flowId);
65
+ else
66
+ refuse("registered_request_flow_required");
67
+ const manifest = input.engine.manifest(), checksum = manifest.integrity.checksum;
68
+ if (typeof checksum !== "string")
69
+ refuse("engine_identity_missing");
70
+ const runId = nextDescriptorRunId(context, { projectRoot: frozen.scope.projectRoot, requestId: frozen.scope.requestId, slug: flowId });
71
+ const binding = { schema_id: "dd-flow/run-engine-binding@1", run_id: runId,
72
+ project_root: frozen.scope.projectRoot, bound_at: input.boundAt, source: "run_creation", reason: isDeliveryFlow(flowId) ? "Request-bound delivery; startup grants no productive mutation approval" : flowId === "review-fix" ? "Request-bound selected finding scope and explicit formalization handoff" : flowId === "mb-distill" ? "Request-bound practice distillation with separate destination authority" : "Request-bound read-only diagnostic",
73
+ engine: { package_name: manifest.package_name, package_version: manifest.package_version, engine_version: manifest.engine_version,
74
+ integrity_checksum: checksum, snapshot_root: manifest.snapshot_root }, probe: { status: "not_required", command: null } };
75
+ const blobs = input.source.blobs();
76
+ const put = (logical, content) => {
77
+ if (blobs.has(logical))
78
+ refuse("bundle_path_collision");
79
+ blobs.set(logical, content);
80
+ return { path: logical, sha256: hash(content) };
81
+ };
82
+ // Use the retained request verbatim, not the coordinator's interpretation or
83
+ // a later mutable intake file. It is task data, never implicit write scope.
84
+ if (mode === "delivery" || flowId === "mb-distill" || flowId === "review-fix")
85
+ put("runtime/source-request.md", Buffer.from(input.requestText));
86
+ if (request?.repair_source)
87
+ put(request.repair_source.path, Buffer.from(request.repair_source.base64, "base64"));
88
+ for (const ref of [frozen.settings.attached_session_receipt, frozen.settings.delegation.native_capacity_receipt]) {
89
+ if (!ref)
90
+ continue;
91
+ const content = input.receiptBytes?.get(ref.sha256);
92
+ if (!content || hash(content) !== ref.sha256 || !input.receipts?.has(ref.sha256))
93
+ refuse("execution_receipt_missing");
94
+ put(ref.path, Buffer.from(content));
95
+ }
96
+ const profiles = { schema_id: "dd-flow/profile-settings@1", profiles: frozen.profiles, aliases: {}, default_profile: null };
97
+ const profile = put("runtime/profiles.json", bytes({ ...profiles, revision: hybridDigest(profiles) }));
98
+ const execution = put("runtime/execution.json", bytes(frozen.settings));
99
+ const engineBinding = put("runtime/engine-binding.json", bytes(binding));
100
+ const engineManifest = put("runtime/engine-manifest.json", input.engine.manifestBytes());
101
+ if (snapshot)
102
+ put("runtime/diagnostic-snapshot.json", bytes(snapshot));
103
+ const provenance = { canon: input.source.canonProvenance(), project_pack: null };
104
+ const bundle = { schema_id: "dd-flow/execution-bundle@1", run_id: runId, flow_id: flowId,
105
+ descriptor: input.source.descriptorReference(), execution_settings: execution, profile_settings: profile,
106
+ engine_binding: engineBinding, engine_manifest: engineManifest, bootstrap_receipts: [], ...provenance,
107
+ inventory: [...blobs].map(([logical, content]) => ({ path: logical, sha256: hash(content) })) };
108
+ const encoded = bytes(bundle);
109
+ return RetainedExecutionBundle.admit(encoded, hash(encoded), blobs, { runId, executionScope: frozen.scope,
110
+ bundleProjectRoot: frozen.scope.projectRoot, descriptorSha256: flow.sha256, engineChecksum: checksum,
111
+ engineBindingSha256: engineBinding.sha256, engineManifestSha256: engineManifest.sha256,
112
+ descriptorContext: bundledHandlerContext(new Map()), bundleProvenance: provenance, receipts: input.receipts ?? new Map() });
113
+ }
@@ -0,0 +1,159 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { execFileSync } from "node:child_process";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { isSourceSnapshotFlow } from "../domain/source-snapshot-flows.js";
6
+ import { hybridDigest } from "./hybrid-contracts.js";
7
+ import { appendAudit } from "./audit.js";
8
+ import { reviewSourceHash, reviewSourceFilter, reviewExecutionCopyHash } from "./review-copy.js";
9
+ import { projectPacketLocators, runContextRelocations } from "./stage-context.js";
10
+ const intentEvent = "diagnostic.snapshot_intent", readyEvent = "diagnostic.snapshot_ready";
11
+ function refuse(reason) { throw new AppError("diagnostic_snapshot_invalid", "Read-only diagnosis requires its retained unchanged snapshot", 1, { reason, effect: "no_effect" }); }
12
+ const inside = (root, file) => { const relative = path.relative(root, file); return relative === "" || !relative.startsWith(".." + path.sep) && relative !== ".." && !path.isAbsolute(relative); };
13
+ function rows(context, input, event) {
14
+ return context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type=? AND json_extract(payload_json,'$.requestId')=? LIMIT 2", [input.projectId, event, input.requestId]);
15
+ }
16
+ function destination(context, input) {
17
+ return path.join(context.ddFlowHome, "diagnostic-snapshots", hybridDigest(input), "workspace");
18
+ }
19
+ /** Deterministic destination for freezing execution before the first copy. */
20
+ export function diagnosticSnapshotRoot(context, input) {
21
+ validate(context, input);
22
+ return destination(context, input);
23
+ }
24
+ function physicalSnapshot(context, value, runId) {
25
+ return runId ? JSON.parse(projectPacketLocators(JSON.stringify(value), runContextRelocations(context, value.projectId, runId))) : value;
26
+ }
27
+ /** Only physical locators are projected through existing RUN import receipts.
28
+ * The immutable source selection and SQL custody remain byte-for-byte original. */
29
+ export function diagnosticSnapshotPaths(context, value, runId) {
30
+ const physical = physicalSnapshot(context, value, runId);
31
+ return { root: physical.root, sourceRoot: physical.sourceRoot };
32
+ }
33
+ function validate(context, input, runId) {
34
+ const physical = physicalSnapshot(context, input, runId);
35
+ if (!isSourceSnapshotFlow(input.flowId) || !input.requestId?.trim() || input.requestId.length > 200
36
+ || !path.isAbsolute(physical.projectRoot) || physical.projectRoot !== physical.sourceRoot
37
+ || fs.realpathSync(physical.sourceRoot) !== physical.sourceRoot)
38
+ refuse("invalid_selection");
39
+ const project = context.db.get("SELECT root,status FROM projects WHERE id=?", [input.projectId]);
40
+ if (project?.root !== physical.projectRoot || project.status !== "active")
41
+ refuse("project_not_active");
42
+ if (inside(physical.sourceRoot, context.ddFlowHome))
43
+ refuse("runtime_inside_source");
44
+ }
45
+ function retained(context, input, runId) {
46
+ const records = rows(context, input, intentEvent);
47
+ if (records.length > 1)
48
+ refuse("ambiguous_snapshot");
49
+ if (!records.length)
50
+ return null;
51
+ if (Buffer.byteLength(records[0].payload_json) > 16 * 1024)
52
+ refuse("unbounded_snapshot");
53
+ const value = JSON.parse(records[0].payload_json);
54
+ if (value.schema_id !== "dd-flow/diagnostic-snapshot@1" || physicalSnapshot(context, value, runId).root !== destination(context, input)
55
+ || hybridDigest({ ...value, ...input }) !== hybridDigest(value) || !/^[a-f0-9]{64}$/.test(value.source_sha256))
56
+ refuse("snapshot_selection_changed");
57
+ return value;
58
+ }
59
+ function verifyFiles(value, requirePrivateGit = true) {
60
+ if (!fs.lstatSync(value.root).isDirectory() || fs.realpathSync(value.root) !== value.root
61
+ || reviewSourceHash(value.sourceRoot) !== value.source_sha256
62
+ || reviewExecutionCopyHash(value.root, value.sourceRoot, false) !== value.source_sha256)
63
+ refuse("source_or_copy_changed");
64
+ if (requirePrivateGit && !fs.lstatSync(path.join(value.root, ".git")).isDirectory())
65
+ refuse("private_git_required");
66
+ }
67
+ function seal(context, input, value) {
68
+ context.db.writeTransaction(() => {
69
+ if (hybridDigest(retained(context, input)) !== hybridDigest(value))
70
+ refuse("snapshot_custody_changed");
71
+ const ready = rows(context, input, readyEvent);
72
+ if (ready.length > 1 || ready.length === 1 && hybridDigest(JSON.parse(ready[0].payload_json)) !== hybridDigest(value))
73
+ refuse("snapshot_custody_changed");
74
+ if (!ready.length)
75
+ appendAudit(context, { projectId: input.projectId, eventType: readyEvent, payload: { ...value } });
76
+ });
77
+ }
78
+ /** SQL-owned selection plus freshly checked physical source/copy; never adopts a caller's claimed path. */
79
+ export function readDiagnosticSnapshot(context, input, runId) {
80
+ validate(context, input, runId);
81
+ const value = readDiagnosticSnapshotCustody(context, input, runId);
82
+ if (!value)
83
+ return null;
84
+ verifyFiles(physicalSnapshot(context, value, runId));
85
+ return value;
86
+ }
87
+ /** SQL-only custody check for an already physically validated selection.
88
+ * Callers must perform readDiagnosticSnapshot before entering a writer. */
89
+ export function readDiagnosticSnapshotCustody(context, input, runId) {
90
+ const value = retained(context, input, runId);
91
+ if (!value)
92
+ return null;
93
+ const ready = rows(context, input, readyEvent);
94
+ if (ready.length !== 1 || hybridDigest(JSON.parse(ready[0].payload_json)) !== hybridDigest(value))
95
+ refuse("snapshot_not_ready");
96
+ return value;
97
+ }
98
+ export function assertDiagnosticSnapshot(context, snapshot) {
99
+ const input = { projectId: snapshot.projectId, projectRoot: snapshot.projectRoot, sourceRoot: snapshot.sourceRoot, requestId: snapshot.requestId, flowId: snapshot.flowId };
100
+ const selected = readDiagnosticSnapshot(context, input);
101
+ if (!selected || hybridDigest(selected) !== hybridDigest(snapshot))
102
+ refuse("snapshot_binding_changed");
103
+ }
104
+ /** Copies only established review-visible inputs, never environment files or Git internals.
105
+ * Existing partial copies are verified, not overwritten. Reports belong outside this workspace. */
106
+ export function prepareDiagnosticSnapshot(context, input) {
107
+ validate(context, input);
108
+ const prior = retained(context, input);
109
+ if (prior) {
110
+ if (rows(context, input, readyEvent).length)
111
+ return readDiagnosticSnapshot(context, input);
112
+ verifyFiles(prior);
113
+ seal(context, input, prior);
114
+ return prior;
115
+ }
116
+ const root = destination(context, input), env = { ...context.env, GIT_OPTIONAL_LOCKS: "0" };
117
+ for (const key of Object.keys(env))
118
+ if (key.startsWith("GIT_") && key !== "GIT_OPTIONAL_LOCKS")
119
+ delete env[key];
120
+ const git = (...args) => {
121
+ try {
122
+ return execFileSync("git", ["-c", "core.fsmonitor=false", "-C", input.sourceRoot, ...args], { env, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], maxBuffer: 1024 * 1024 }).trim();
123
+ }
124
+ catch {
125
+ return null;
126
+ } // Git absence is explicit missing evidence, never a clean verdict.
127
+ };
128
+ const value = { ...input, schema_id: "dd-flow/diagnostic-snapshot@1", root, source_sha256: reviewSourceHash(input.sourceRoot),
129
+ git: { head: git("rev-parse", "HEAD"), branch: git("symbolic-ref", "--quiet", "--short", "HEAD"), status: git("status", "--porcelain=v1") } };
130
+ let current = context.ddFlowHome;
131
+ for (const part of path.relative(context.ddFlowHome, path.dirname(root)).split(path.sep)) {
132
+ current = path.join(current, part);
133
+ if (fs.existsSync(current)) {
134
+ if (!fs.lstatSync(current).isDirectory() || fs.realpathSync(current) !== current)
135
+ refuse("unsafe_snapshot_parent");
136
+ }
137
+ else
138
+ fs.mkdirSync(current, { mode: 0o700 });
139
+ }
140
+ if (fs.existsSync(root))
141
+ refuse("unowned_snapshot_directory");
142
+ context.db.writeTransaction(() => {
143
+ if (rows(context, input, intentEvent).length)
144
+ refuse("snapshot_already_reserved");
145
+ appendAudit(context, { projectId: input.projectId, eventType: intentEvent, payload: { ...value } });
146
+ });
147
+ fs.mkdirSync(root, { mode: 0o700 });
148
+ fs.cpSync(input.sourceRoot, root, { recursive: true, verbatimSymlinks: true, force: false, errorOnExist: true, filter: reviewSourceFilter(input.sourceRoot) });
149
+ verifyFiles(value, false);
150
+ // A private, independent index makes ordinary controller Git observations safe.
151
+ // No project worktree/index, hooks, commits or branch is changed.
152
+ execFileSync("git", ["-c", "init.templateDir=", "init", "--quiet", "--initial-branch=diagnostic-snapshot", root], { env, stdio: "pipe" });
153
+ // A tracked source can also match .gitignore. Keep the selected safe files
154
+ // tracked in the private index so subsequent review copies cannot omit it.
155
+ execFileSync("git", ["-C", root, "add", "--force", "--all", "--", "."], { env, stdio: "pipe" });
156
+ verifyFiles(value);
157
+ seal(context, input, value);
158
+ return value;
159
+ }
@@ -0,0 +1,109 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ import { isDiagnosticFlow, diagnosticFlowStages } from "../domain/diagnostic-flows.js";
3
+ import { readFlowRunExecutionBundle } from "./runs.js";
4
+ import { requireProjectByRoot } from "./projects.js";
5
+ import { resolveProjectRoot } from "../storage/paths.js";
6
+ import { diagnosticSnapshotPaths, readDiagnosticSnapshot, readDiagnosticSnapshotCustody } from "./diagnostic-snapshot.js";
7
+ import { PreparedDescriptorStageStart } from "./descriptor-stage-start.js";
8
+ import { PreparedDescriptorStageCoordinator, readDescriptorStageInput } from "./descriptor-stage-coordinator.js";
9
+ import { PreparedDescriptorStageSettlement } from "./descriptor-stage-settlement.js";
10
+ import { PreparedDescriptorRunSettlement } from "./descriptor-run-settlement.js";
11
+ import { assertDiagnosticCriticResolution, assertDiagnosticReportData, assertDiagnosticStageScope, materializeDiagnosticRetainedFields, sealDiagnosticStageLimitations, validateDiagnosticStageResult } from "./diagnostic-stage-results.js";
12
+ import { readAcceptedStageData } from "./stage-report-renderer.js";
13
+ import { registerDiagnosticStageGraph } from "./diagnostic-work-registration.js";
14
+ import { PreparedDiagnosticWorkCollection } from "./diagnostic-work-collection.js";
15
+ import { collectDiagnosticCandidates, sealDiagnosticCandidateIds } from "./diagnostic-work-results.js";
16
+ import { hybridDigest } from "./hybrid-contracts.js";
17
+ import { prepareDiagnosticReport } from "./diagnostic-report.js";
18
+ import { prepareDiagnosticReportPublication } from "./diagnostic-report-publication.js";
19
+ export const diagnosticStageHandlers = Object.freeze(Object.entries(diagnosticFlowStages).flatMap(([flowId, stages]) => stages.map(stage => Object.freeze({ flowId, stage, entryId: "diagnostic-stage-entry", finishId: "diagnostic-stage-finish",
20
+ entry: startDiagnosticStage, finish: finishDiagnosticStage }))));
21
+ function refuse(reason) { throw new AppError("diagnostic_stage_invalid", "Diagnostic stage cannot accept this result", 2, { reason, effect: "no_effect" }); }
22
+ function select(context, input) {
23
+ const bundle = readFlowRunExecutionBundle(context, input), project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
24
+ if (!bundle || !isDiagnosticFlow(bundle.manifest.flow_id)
25
+ || !diagnosticFlowStages[bundle.manifest.flow_id].includes(input.stage))
26
+ refuse("registered_diagnostic_stage_required");
27
+ const frozen = bundle.execution.snapshot().scope;
28
+ const snapshotSelection = { projectId: project.id, projectRoot: frozen.projectRoot, sourceRoot: frozen.projectRoot,
29
+ requestId: frozen.requestId, flowId: bundle.manifest.flow_id };
30
+ const snapshot = readDiagnosticSnapshot(context, snapshotSelection, input.runId);
31
+ if (!snapshot || snapshot.root !== frozen.workspace)
32
+ refuse("snapshot_required");
33
+ return { bundle, snapshot, snapshotSelection, scope: { projectId: project.id, runId: input.runId, stage: input.stage } };
34
+ }
35
+ export function startDiagnosticStage(context, input) {
36
+ const selected = select(context, input);
37
+ const fence = (writer) => {
38
+ if (hybridDigest(readDiagnosticSnapshotCustody(writer, selected.snapshotSelection, input.runId)) !== hybridDigest(selected.snapshot))
39
+ refuse("snapshot_changed");
40
+ };
41
+ const start = PreparedDescriptorStageStart.prepare(context, input).apply(context);
42
+ const coordinator = PreparedDescriptorStageCoordinator.prepare(context, input).apply(context, fence);
43
+ if (["audit", "analyze", "review"].includes(input.stage))
44
+ registerDiagnosticStageGraph(context, input);
45
+ return { ...start, ...coordinator };
46
+ }
47
+ /** Findings are data, not permission to repair. Only registered independent Work
48
+ * may contribute analysis/criticism; terminal acceptance closes runtime only. */
49
+ export function finishDiagnosticStage(context, input) {
50
+ const selected = select(context, input), { bundle, snapshot, scope } = selected;
51
+ const stageInput = readDescriptorStageInput(context, scope, bundle, true, true);
52
+ const previousStage = stageInput.input.predecessor?.stage;
53
+ const previous = previousStage ? readAcceptedStageData(context, { ...scope, stage: previousStage }) : null;
54
+ const prior = previous ? JSON.parse(previous.bytes.toString("utf8")) : null;
55
+ const collection = ["audit", "analyze", "review"].includes(input.stage) ? PreparedDiagnosticWorkCollection.prepare(context, input) : null;
56
+ const proposal = materializeDiagnosticRetainedFields(input.bytes, prior, input.stage);
57
+ const candidates = ["audit", "analyze"].includes(input.stage) ? sealDiagnosticCandidateIds(proposal, collection.results()) : proposal;
58
+ const bytes = sealDiagnosticStageLimitations(candidates, [
59
+ ...(prior?.details.limitations ?? []), ...(collection?.results() ?? []).flatMap(work => work.result.limitations)
60
+ ], prior?.details.missing_expected_sources ?? []);
61
+ const result = validateDiagnosticStageResult(bytes, bundle.descriptor.stageBlob(input.stage, "result_schema"), {
62
+ flowId: selected.snapshotSelection.flowId, runId: input.runId, stage: input.stage,
63
+ inputSha256: stageInput.inputSha256, snapshotSha256: snapshot.source_sha256, snapshotRoot: diagnosticSnapshotPaths(context, snapshot, input.runId).root,
64
+ predecessors: stageInput.input.predecessor ? [{ stage: stageInput.input.predecessor.stage,
65
+ path: stageInput.input.predecessor.result.path, sha256: stageInput.input.predecessor.result.sha256 }] : []
66
+ });
67
+ if (prior) {
68
+ assertDiagnosticStageScope(result, prior);
69
+ if (prior.details.limitations.some(value => !result.details.limitations.includes(value)))
70
+ refuse("limitation_dropped");
71
+ }
72
+ if (collection) {
73
+ const works = collection.results();
74
+ if (works.some(work => work.result.limitations.some(value => !result.details.limitations.includes(value))))
75
+ refuse("worker_limitation_dropped");
76
+ if (input.stage !== "review") {
77
+ if (hybridDigest(result.details.findings) !== hybridDigest(collectDiagnosticCandidates(works).findings))
78
+ refuse("analysis_not_from_work");
79
+ }
80
+ else {
81
+ if (!prior || hybridDigest(result.details.findings) !== hybridDigest(prior.details.findings))
82
+ refuse("candidate_register_changed");
83
+ for (const decision of result.details.decisions) {
84
+ assertDiagnosticCriticResolution(decision, works.map(work => work.result.decisions));
85
+ }
86
+ }
87
+ }
88
+ if (input.stage === "report")
89
+ assertDiagnosticReportData(result, prior);
90
+ const analysis = input.stage === "report" ? PreparedDiagnosticWorkCollection.prepare(context, { ...input, stage: snapshot.flowId === "mb-audit" ? "audit" : "analyze" }) : null;
91
+ const critics = input.stage === "report" ? PreparedDiagnosticWorkCollection.prepare(context, { ...input, stage: "review" }) : null;
92
+ const publication = analysis && critics ? prepareDiagnosticReportPublication(context, { ...scope, attempt: stageInput.attempt, inputSha256: stageInput.inputSha256 }, prepareDiagnosticReport(result, analysis.results(), critics.results())) : null;
93
+ publication?.publish();
94
+ const fence = (writer) => {
95
+ if (hybridDigest(readDiagnosticSnapshotCustody(writer, selected.snapshotSelection, input.runId)) !== hybridDigest(snapshot))
96
+ refuse("snapshot_changed");
97
+ if (previous && hybridDigest(readAcceptedStageData(writer, { ...scope, stage: previousStage })) !== hybridDigest(previous))
98
+ refuse("predecessor_changed");
99
+ collection?.assertCustody(writer);
100
+ analysis?.assertCustody(writer);
101
+ critics?.assertCustody(writer);
102
+ publication?.retain(writer);
103
+ };
104
+ const settlement = PreparedDescriptorStageSettlement.prepare(context, { ...input, bytes }).apply(context, fence);
105
+ if (input.stage === "report")
106
+ return { ...settlement,
107
+ ...PreparedDescriptorRunSettlement.prepare(context, input).apply(context, fence), reports: publication.manifest.artifacts };
108
+ return settlement;
109
+ }
@@ -0,0 +1,158 @@
1
+ import { Ajv2020 } from "ajv/dist/2020.js";
2
+ import { diagnosticFlowStages } from "../domain/diagnostic-flows.js";
3
+ import { diagnosticAspects } from "../domain/diagnostic-aspects.js";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { hybridDigest } from "./hybrid-contracts.js";
6
+ import { verifyDiagnosticCoverage, verifyDiagnosticSources } from "./diagnostic-evidence.js";
7
+ const refuse = (reason) => {
8
+ throw new AppError("diagnostic_stage_result_invalid", "Diagnostic result does not match its frozen stage", 2, { reason, effect: "no_effect", ...(reason === "result_schema_invalid" ? { phase: "prepare", recoverable: true } : {}) });
9
+ };
10
+ /** Retained fields are CLI data, not a transcription task for the coordinator. */
11
+ export function materializeDiagnosticRetainedFields(bytes, prior, stage) {
12
+ if (!prior || !bytes.length || bytes.length > 1024 * 1024)
13
+ return bytes;
14
+ let value;
15
+ try {
16
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
17
+ }
18
+ catch {
19
+ return bytes;
20
+ }
21
+ if (!value || typeof value !== "object" || !value.details || typeof value.details !== "object" || Array.isArray(value.details))
22
+ return bytes;
23
+ const retained = stage === "report" ? Object.entries(prior.details).filter(([key]) => key !== "limitations")
24
+ : ["focus", "coverage"].map(key => [key, prior.details[key]]);
25
+ for (const [key, expected] of retained) {
26
+ if (Object.hasOwn(value.details, key) && hybridDigest(value.details[key]) !== hybridDigest(expected))
27
+ throw new AppError("diagnostic_stage_invalid", "A proposal cannot replace CLI-retained predecessor data", 2, { reason: `accepted_${key}_changed`, effect: "no_effect", phase: "prepare", recoverable: true });
28
+ value.details[key] = structuredClone(expected);
29
+ }
30
+ if (!Object.hasOwn(value.details, "limitations"))
31
+ value.details.limitations = [];
32
+ if (!Object.hasOwn(value.details, "missing_expected_sources"))
33
+ value.details.missing_expected_sources = structuredClone(prior.details.missing_expected_sources);
34
+ return Buffer.from(JSON.stringify(value));
35
+ }
36
+ /** Accepted limitations and missing-source observations belong to predecessor/Work custody, not a coordinator's
37
+ * transcription. Keep its annotations too; validate the complete sealed result
38
+ * with the frozen schema afterwards, without truncating overflowing data. */
39
+ export function sealDiagnosticStageLimitations(bytes, required, acceptedMissingSources = []) {
40
+ if ((!required.length && !acceptedMissingSources.length) || !bytes.length || bytes.length > 1024 * 1024)
41
+ return bytes;
42
+ let value;
43
+ try {
44
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
45
+ }
46
+ catch {
47
+ return bytes;
48
+ }
49
+ let changed = false;
50
+ for (const [key, expected] of [["limitations", required], ["missing_expected_sources", acceptedMissingSources]]) {
51
+ if (!expected.length)
52
+ continue;
53
+ const proposed = value?.details?.[key];
54
+ if (!Array.isArray(proposed) || proposed.some(item => typeof item !== "string"))
55
+ return bytes;
56
+ const missing = [...new Set(expected.filter(item => !proposed.includes(item)))];
57
+ if (missing.length) {
58
+ value.details[key] = [...missing, ...proposed];
59
+ changed = true;
60
+ }
61
+ }
62
+ return changed ? Buffer.from(JSON.stringify(value)) : bytes;
63
+ }
64
+ export function assertDiagnosticStageScope(result, prior) {
65
+ const coverageScope = (value) => value.details.coverage.map(({ id, applicability }) => ({ id, applicability }));
66
+ if (result.details.focus.mode !== prior.details.focus.mode
67
+ // New source gaps are analytical observations, not an expansion of scope.
68
+ // Previously accepted gaps still cannot disappear from the result.
69
+ || prior.details.missing_expected_sources.some(source => !result.details.missing_expected_sources.includes(source))
70
+ || hybridDigest(coverageScope(result)) !== hybridDigest(coverageScope(prior)))
71
+ throw new AppError("diagnostic_stage_invalid", "Diagnostic stage cannot accept this result", 2, { reason: "accepted_scope_changed", effect: "no_effect" });
72
+ // Focus prose is retained selection, not a new stage heading. A different
73
+ // proposal is never accepted, but can copy the exact predecessor and retry.
74
+ if (hybridDigest(result.details.focus) !== hybridDigest(prior.details.focus))
75
+ throw new AppError("diagnostic_stage_invalid", "Copy details.focus unchanged from the accepted predecessor; put the stage summary in summary, not the retained focus", 2, { reason: "accepted_focus_changed", effect: "no_effect", phase: "prepare", recoverable: true });
76
+ // Applicability is already accepted. Analytical progress belongs in findings,
77
+ // sources and limitations, not edits to the retained preflight annotations.
78
+ if (hybridDigest(result.details.coverage) !== hybridDigest(prior.details.coverage))
79
+ throw new AppError("diagnostic_stage_invalid", "Copy details.coverage unchanged from the accepted predecessor; put new observations in findings, sources or limitations", 2, { reason: "accepted_coverage_annotations_changed", effect: "no_effect", phase: "prepare", recoverable: true });
80
+ }
81
+ export function assertDiagnosticReportData(result, prior) {
82
+ // Reporting may disclose additional uncertainty, never revise reviewed facts
83
+ // or erase any accepted limitation. This comparison does not rewrite either result.
84
+ if (!prior || prior.details.limitations.some(value => !result.details.limitations.includes(value))
85
+ || hybridDigest({ ...result.details, limitations: prior.details.limitations }) !== hybridDigest(prior.details))
86
+ throw new AppError("diagnostic_stage_invalid", "Diagnostic stage cannot accept this result", 2, { reason: "report_changed_reviewed_data", effect: "no_effect" });
87
+ }
88
+ export function assertDiagnosticCriticResolution(decision, critics) {
89
+ const selected = decision;
90
+ const votes = critics.flat().filter(item => item.finding_id === decision.finding_id);
91
+ // Duplicate/rejected entries remain trace, not accepted findings. Their
92
+ // supported severity may be reconciled separately without inventing a vote.
93
+ // An accepted finding still requires one critic to endorse the whole pair.
94
+ const nonAccepting = ["duplicate", "rejected"].includes(selected.disposition);
95
+ if (votes.some(item => item.disposition === selected.disposition && item.severity === selected.severity)
96
+ || nonAccepting && votes.some(item => item.disposition === selected.disposition)
97
+ && votes.some(item => item.severity === selected.severity))
98
+ return;
99
+ throw new AppError("diagnostic_stage_invalid", "Use a supported critic resolution; preserve all independent critic decisions and explain disagreements", 2, { reason: "unsupported_critic_resolution", effect: "no_effect", phase: "prepare", recoverable: true,
100
+ finding_id: selected.finding_id, supported_resolutions: votes.map(item => ({ disposition: item.disposition, severity: item.severity })) });
101
+ }
102
+ /** Frozen schema and exact CLI-issued identity precede semantic evidence checks.
103
+ * This does not assert that independent Work/critics have settled. */
104
+ export function validateDiagnosticStageResult(bytes, schemaBytes, binding) {
105
+ if (!bytes.length || bytes.length > 1024 * 1024 || schemaBytes.length > 1024 * 1024)
106
+ refuse("result_exceeds_bound");
107
+ const validate = (() => {
108
+ try {
109
+ const schema = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(schemaBytes));
110
+ if (schema.$id !== "dd-flow/diagnostic-stage-result@1")
111
+ refuse("frozen_schema_invalid");
112
+ return new Ajv2020({ strict: false, validateFormats: false }).compile(schema);
113
+ }
114
+ catch {
115
+ return refuse("frozen_schema_invalid");
116
+ }
117
+ })();
118
+ let value;
119
+ try {
120
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
121
+ }
122
+ catch {
123
+ return refuse("result_schema_invalid");
124
+ }
125
+ if (!validate(value))
126
+ refuse("result_schema_invalid");
127
+ if (value.flow_id !== binding.flowId || value.run_id !== binding.runId || value.stage !== binding.stage
128
+ || !diagnosticFlowStages[binding.flowId].includes(binding.stage)
129
+ || value.input_sha256 !== binding.inputSha256 || value.snapshot_sha256 !== binding.snapshotSha256
130
+ || hybridDigest(value.predecessors) !== hybridDigest(binding.predecessors))
131
+ refuse("foreign_result_binding");
132
+ if ((binding.flowId === "mb-audit") !== (value.details.focus.mode === "memory_bank"))
133
+ refuse("foreign_focus");
134
+ verifyDiagnosticCoverage(binding.snapshotRoot, diagnosticAspects[binding.flowId].map(item => item.id), value.details.coverage);
135
+ verifyDiagnosticSources(binding.snapshotRoot, value.details.sources);
136
+ const ids = new Set();
137
+ for (const finding of value.details.findings) {
138
+ if (ids.has(finding.id) || !value.details.coverage.some(item => item.id === finding.aspect_id && item.applicability === "applicable")
139
+ || !finding.evidence.length)
140
+ refuse("finding_outside_coverage");
141
+ ids.add(finding.id);
142
+ verifyDiagnosticSources(binding.snapshotRoot, finding.evidence);
143
+ }
144
+ const decided = new Set();
145
+ for (const decision of value.details.decisions) {
146
+ if (!ids.has(decision.finding_id) || decided.has(decision.finding_id))
147
+ refuse("foreign_or_duplicate_decision");
148
+ decided.add(decision.finding_id);
149
+ verifyDiagnosticSources(binding.snapshotRoot, decision.evidence);
150
+ }
151
+ if (binding.stage === "preflight" && (ids.size || decided.size))
152
+ refuse("preflight_cannot_claim_analysis");
153
+ if (["audit", "analyze"].includes(binding.stage) && decided.size)
154
+ refuse("analysis_cannot_claim_independent_review");
155
+ if (["review", "report"].includes(binding.stage) && decided.size !== ids.size)
156
+ refuse("unresolved_finding");
157
+ return value;
158
+ }