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

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 +959 -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 +230 -106
  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,280 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { hybridDigest } from "./hybrid-contracts.js";
6
+ import { MemoryRepairDocumentBaseline, orderMemoryDocumentEntries } from "./memory-repair-document-delta.js";
7
+ import { RetainedMemoryRepairPublicationPlan } from "./memory-repair-publication-plan.js";
8
+ import { stageRetainedMemoryRepairFile, verifyRetainedMemoryRepairFile } from "./memory-repair-publication-files.js";
9
+ import { acquireInstallationLock } from "./installation-lock.js";
10
+ import { publishImmutableInput } from "../storage/immutable-input.js";
11
+ import { ObservedMemorySources } from "./memory-source-observations.js";
12
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
13
+ function refuse(reason) {
14
+ throw new AppError("distill_publication_invalid", "Distillation publication requires its exact retained document plan", 2, { reason, effect: "no_effect" });
15
+ }
16
+ function beforeFiles(plan) {
17
+ const encoded = JSON.parse(plan.bytes().toString("utf8"));
18
+ const before = JSON.parse(Buffer.from(encoded.before_base64, "base64").toString("utf8"));
19
+ return before.entries.filter((entry) => entry.kind === "file" && before.write_paths.includes(entry.path))
20
+ .map((entry) => ({ path: entry.path, sha256: entry.sha256 }));
21
+ }
22
+ /** Selected original text only. Protected neighboring/private document bytes
23
+ * must never be exported as verifier context. No destination write occurs. */
24
+ export function captureDistillBeforeDocuments(root, plan) {
25
+ const selected = beforeFiles(plan), observed = ObservedMemorySources.capture({ workspace: root }, selected.map(entry => ({ root: "workspace", path: entry.path })));
26
+ return validateDistillBeforeDocuments(plan, selected.map(entry => ({ ...entry, base64: observed.bytes({ root: "workspace", path: entry.path }).toString("base64") })));
27
+ }
28
+ /** SQL decoding is filesystem-free. The original before-view, not a fresh file,
29
+ * determines exact membership and hashes, including originally empty files. */
30
+ export function validateDistillBeforeDocuments(plan, value) {
31
+ const expected = beforeFiles(plan);
32
+ if (!Array.isArray(value) || value.length !== expected.length || value.length > 4096)
33
+ refuse("original_documents_required");
34
+ let total = 0;
35
+ const seen = new Set();
36
+ for (const document of value) {
37
+ if (!document || typeof document !== "object" || Object.keys(document).sort().join() !== "base64,path,sha256"
38
+ || typeof document.base64 !== "string" || document.base64.length > 24 * 1024 * 1024 || seen.has(document.path)
39
+ || !expected.some(entry => entry.path === document.path && entry.sha256 === document.sha256))
40
+ refuse("original_document_changed");
41
+ const bytes = Buffer.from(document.base64, "base64");
42
+ total += bytes.length;
43
+ if (bytes.length > 16 * 1024 * 1024 || total > 64 * 1024 * 1024 || bytes.toString("base64") !== document.base64 || hash(bytes) !== document.sha256)
44
+ refuse("original_document_changed");
45
+ seen.add(document.path);
46
+ }
47
+ const byPath = new Map(value.map(document => [document.path, document]));
48
+ return expected.map(entry => ({ ...entry, base64: byPath.get(entry.path).base64 }));
49
+ }
50
+ export function distillBeforeDocumentReferences(plan) {
51
+ return beforeDocumentReferences(plan, "distill");
52
+ }
53
+ export function memoryFixBeforeDocumentReferences(plan) {
54
+ return beforeDocumentReferences(plan, "memory-fix");
55
+ }
56
+ function beforeDocumentReferences(plan, namespace) {
57
+ return beforeFiles(plan).map(entry => ({ destination_path: entry.path,
58
+ source: { root: "run", path: `artifacts/${namespace}/before/${entry.sha256}.md`, sha256: entry.sha256 } }));
59
+ }
60
+ /** Restore original verifier inputs from retained SQL bytes before target
61
+ * effects, including after a lost projection. Never read the changed target. */
62
+ export function publishDistillBeforeDocuments(runRoot, plan, documents) {
63
+ return publishBeforeDocuments(runRoot, plan, documents, "distill");
64
+ }
65
+ export function publishMemoryFixBeforeDocuments(runRoot, plan, documents) {
66
+ return publishBeforeDocuments(runRoot, plan, documents, "memory-fix");
67
+ }
68
+ function publishBeforeDocuments(runRoot, plan, documents, family) {
69
+ const retained = validateDistillBeforeDocuments(plan, documents);
70
+ if (!retained.length)
71
+ return;
72
+ if (!path.isAbsolute(runRoot) || fs.realpathSync(runRoot) !== runRoot || !fs.lstatSync(runRoot).isDirectory())
73
+ refuse("unsafe_baseline_home");
74
+ const artifacts = privateDirectory(runRoot, "artifacts"), namespace = privateDirectory(artifacts, family), directory = privateDirectory(namespace, "before");
75
+ for (const document of retained)
76
+ publishImmutableInput(path.join(directory, `${document.sha256}.md`), Buffer.from(document.base64, "base64"), "distill_before_document_conflict");
77
+ }
78
+ /** Physical plan only, not scope approval or RUN/Work authority. The caller
79
+ * independently selects canonical exceptions and retains this plan in SQL
80
+ * before any apply. Capture protects the entire destination Memory Bank,
81
+ * including unrelated files and opaque private/link entries. */
82
+ export function prepareDistillDocumentPlan(destinationRoot, outputs, canonicalPaths = new Set()) {
83
+ return prepareDocumentPlan(destinationRoot, outputs, canonicalPaths, "distill");
84
+ }
85
+ /** Physical bounded repair plan only. A null output explicitly requests removal
86
+ * of that selected existing document. Intake/Work/user authority belongs to the
87
+ * caller; this helper never expands selection or admits canonical exceptions. */
88
+ export function prepareMemoryFixDocumentPlan(destinationRoot, outputs) {
89
+ return prepareDocumentPlan(destinationRoot, outputs, new Set(), "memory_fix");
90
+ }
91
+ function prepareDocumentPlan(destinationRoot, outputs, canonicalPaths, family) {
92
+ const refuse = (reason) => { throw new AppError(`${family}_publication_invalid`, "Publication requires its exact retained document plan", 2, { reason, effect: "no_effect" }); };
93
+ if (!outputs.length || outputs.length > 4096 || new Set(outputs.map(output => output.path)).size !== outputs.length)
94
+ refuse("invalid_output_selection");
95
+ let total = 0;
96
+ for (const output of outputs) {
97
+ if (output.bytes === null && family === "memory_fix")
98
+ continue;
99
+ if (!(output.bytes instanceof Uint8Array) || output.bytes.length > 16 * 1024 * 1024 || (total += output.bytes.length) > 64 * 1024 * 1024)
100
+ refuse("unbounded_output");
101
+ try {
102
+ new TextDecoder("utf-8", { fatal: true }).decode(output.bytes);
103
+ }
104
+ catch {
105
+ refuse("non_text_document");
106
+ }
107
+ }
108
+ const selected = [...outputs].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
109
+ const before = MemoryRepairDocumentBaseline.capture(destinationRoot, selected.map(output => output.path), canonicalPaths);
110
+ const entries = new Map(before.entries().map(entry => [entry.path, entry]));
111
+ const actions = [];
112
+ for (const output of selected) {
113
+ if (output.bytes === null) {
114
+ const prior = entries.get(output.path);
115
+ if (!prior || prior.kind !== "file")
116
+ return refuse("delete_requires_existing_document");
117
+ entries.delete(output.path);
118
+ actions.push({ path: output.path, before: prior, after: null, bytes_base64: null });
119
+ continue;
120
+ }
121
+ const parts = output.path.split("/");
122
+ for (let length = 1; length < parts.length; length++) {
123
+ const logical = parts.slice(0, length).join("/");
124
+ if (!entries.has(logical)) {
125
+ const after = { path: logical, kind: "directory", mode: 0o755, sha256: null };
126
+ entries.set(logical, after);
127
+ actions.push({ path: logical, before: null, after, bytes_base64: null });
128
+ }
129
+ }
130
+ const prior = entries.get(output.path) ?? null;
131
+ const after = { path: output.path, kind: "file", mode: prior?.mode ?? 0o644, sha256: hash(output.bytes) };
132
+ if (hybridDigest(prior) === hybridDigest(after))
133
+ continue;
134
+ entries.set(output.path, after);
135
+ actions.push({ path: output.path, before: prior, after, bytes_base64: Buffer.from(output.bytes).toString("base64") });
136
+ }
137
+ const beforeData = JSON.parse(before.bytes().toString("utf8"));
138
+ const afterMaterial = { ...beforeData, entries: orderMemoryDocumentEntries(entries.values()) };
139
+ const after = MemoryRepairDocumentBaseline.restore(Buffer.from(JSON.stringify(afterMaterial)), hybridDigest({ ...afterMaterial, schema_id: undefined }));
140
+ const receipt = { before_sha256: before.sha256, before_base64: before.bytes().toString("base64"),
141
+ after_sha256: after.sha256, after_base64: after.bytes().toString("base64"), actions };
142
+ before.revalidate(destinationRoot);
143
+ return RetainedMemoryRepairPublicationPlan.restore(Buffer.from(JSON.stringify(receipt)), hybridDigest(receipt));
144
+ }
145
+ function privateDirectory(parent, name) {
146
+ const directory = path.join(parent, name);
147
+ if (!fs.lstatSync(directory, { throwIfNoEntry: false }))
148
+ fs.mkdirSync(directory, { mode: 0o700 });
149
+ const stat = fs.lstatSync(directory);
150
+ if (!stat.isDirectory() || fs.realpathSync(directory) !== directory)
151
+ refuse("unsafe_staging_directory");
152
+ return directory;
153
+ }
154
+ function syncDirectory(directory) {
155
+ const fd = fs.openSync(directory, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
156
+ try {
157
+ fs.fsyncSync(fd);
158
+ }
159
+ finally {
160
+ fs.closeSync(fd);
161
+ }
162
+ }
163
+ /** One recoverable physical step of an independently retained plan. This
164
+ * grants no publication authority: its owner must fence SQL/source/scope
165
+ * custody on every call, then retain the actual completion separately.
166
+ * A changed prefix is never recaptured or overwritten on retry. */
167
+ export function applyDistillDocumentStep(destinationRoot, plan, assertAuthority) {
168
+ return applyDocumentStep(destinationRoot, plan, assertAuthority, "distill");
169
+ }
170
+ /** Same prefix/recovery mechanics as distill, with selected removals moved into
171
+ * private staging rather than erased. No Stage or publication authority here. */
172
+ export function applyMemoryFixDocumentStep(destinationRoot, plan, assertAuthority) {
173
+ return applyDocumentStep(destinationRoot, plan, assertAuthority, "memory_fix");
174
+ }
175
+ function applyDocumentStep(destinationRoot, plan, assertAuthority, family) {
176
+ const refuse = (reason) => { throw new AppError(`${family}_publication_invalid`, "Publication requires its exact retained document plan", 2, { reason, effect: "no_effect" }); };
177
+ if (!(plan instanceof RetainedMemoryRepairPublicationPlan) || typeof assertAuthority !== "function")
178
+ refuse("retained_plan_and_authority_required");
179
+ const actions = plan.actions();
180
+ if (family === "distill" && actions.some(action => !action.after))
181
+ refuse("distillation_does_not_delete_documents");
182
+ assertAuthority();
183
+ const initial = plan.classify(destinationRoot);
184
+ const removedDirectory = path.join(destinationRoot, ".dd-flow/memory-fix-publications", plan.sha256);
185
+ for (const [index, action] of actions.slice(0, initial.completed).entries())
186
+ if (!action.after) {
187
+ if (fs.realpathSync(removedDirectory) !== removedDirectory || (fs.lstatSync(removedDirectory).mode & 0o7777) !== 0o700)
188
+ refuse("removed_document_custody_changed");
189
+ const logical = `removed-${index}.md`, location = { root: "workspace", path: logical };
190
+ const original = ObservedMemorySources.capture({ workspace: removedDirectory }, [location]);
191
+ const stat = fs.lstatSync(path.join(removedDirectory, logical));
192
+ if (hash(original.bytes(location)) !== action.before.sha256 || !stat.isFile() || stat.nlink !== 1
193
+ || (stat.mode & 0o7777) !== action.before.mode)
194
+ refuse("removed_document_custody_changed");
195
+ syncDirectory(removedDirectory);
196
+ }
197
+ for (const action of actions.slice(0, initial.completed))
198
+ syncDirectory(path.dirname(path.join(destinationRoot, action.path)));
199
+ if (initial.completed === initial.total) {
200
+ assertAuthority();
201
+ return { ...initial, status: "applied", replayed: true };
202
+ }
203
+ const service = privateDirectory(destinationRoot, ".dd-flow"), namespace = privateDirectory(service, family === "distill" ? "distill-publications" : "memory-fix-publications");
204
+ const directory = privateDirectory(namespace, plan.sha256);
205
+ if ((fs.lstatSync(directory).mode & 0o7777) !== 0o700)
206
+ refuse("nonprivate_staging_directory");
207
+ publishImmutableInput(path.join(directory, "owner.json"), Buffer.from(JSON.stringify({ schema_id: family === "distill" ? "dd-flow/distill-document-staging@1" : "dd-flow/memory-fix-document-staging@1", destination_root: destinationRoot, plan_sha256: plan.sha256 })), `${family}_staging_conflict`);
208
+ const lock = acquireInstallationLock(path.join(namespace, "destination.lock"), plan.sha256);
209
+ let effected = false, released = false;
210
+ const release = () => { lock.release(); released = true; };
211
+ try {
212
+ lock.assertOwnership();
213
+ assertAuthority();
214
+ const current = plan.classify(destinationRoot);
215
+ if (current.completed !== initial.completed)
216
+ refuse("publication_cursor_changed");
217
+ const action = actions[current.completed], destination = path.join(destinationRoot, action.path);
218
+ if (!action.after) {
219
+ const removed = path.join(directory, `removed-${current.completed}.md`);
220
+ if (fs.lstatSync(removed, { throwIfNoEntry: false }))
221
+ refuse("foreign_removed_document");
222
+ assertAuthority();
223
+ lock.assertOwnership();
224
+ if (plan.classify(destinationRoot).completed !== current.completed)
225
+ refuse("publication_cursor_changed");
226
+ effected = true;
227
+ fs.renameSync(destination, removed);
228
+ syncDirectory(directory);
229
+ }
230
+ else if (action.after.kind === "file") {
231
+ const staged = stageRetainedMemoryRepairFile(directory, `action-${current.completed}.tmp`, plan.output(action.path), action.after.mode);
232
+ verifyRetainedMemoryRepairFile(staged.path, plan.output(action.path), action.after.mode);
233
+ assertAuthority();
234
+ lock.assertOwnership();
235
+ if (plan.classify(destinationRoot).completed !== current.completed)
236
+ refuse("publication_cursor_changed");
237
+ effected = true;
238
+ fs.renameSync(staged.path, destination);
239
+ syncDirectory(directory);
240
+ }
241
+ else {
242
+ const staged = path.join(directory, `directory-${current.completed}.tmp`);
243
+ if (!fs.lstatSync(staged, { throwIfNoEntry: false }))
244
+ fs.mkdirSync(staged, { mode: 0o700 });
245
+ const stat = fs.lstatSync(staged);
246
+ if (!stat.isDirectory() || fs.realpathSync(staged) !== staged || fs.readdirSync(staged).length
247
+ || ![0o700, action.after.mode].includes(stat.mode & 0o7777))
248
+ refuse("foreign_staged_directory");
249
+ fs.chmodSync(staged, action.after.mode);
250
+ syncDirectory(staged);
251
+ assertAuthority();
252
+ lock.assertOwnership();
253
+ if (plan.classify(destinationRoot).completed !== current.completed)
254
+ refuse("publication_cursor_changed");
255
+ effected = true;
256
+ fs.renameSync(staged, destination);
257
+ syncDirectory(directory);
258
+ }
259
+ syncDirectory(path.dirname(destination));
260
+ const observed = plan.classify(destinationRoot);
261
+ if (observed.completed !== current.completed + 1)
262
+ refuse("unexpected_publication_effect");
263
+ release();
264
+ return { ...observed, status: observed.completed === observed.total ? "applied" : "partial", replayed: false };
265
+ }
266
+ catch (error) {
267
+ let releaseFailure;
268
+ if (!released)
269
+ try {
270
+ release();
271
+ }
272
+ catch (failure) {
273
+ releaseFailure = failure instanceof Error ? failure.message : String(failure);
274
+ }
275
+ if (!effected && !releaseFailure)
276
+ throw error;
277
+ throw new AppError(`${family}_publication_pending`, "Reconcile the same retained publication; do not prepare a new baseline", 1, { effect: effected ? "publication_pending" : "no_effect", plan_sha256: plan.sha256, cause: error instanceof Error ? error.message : String(error),
278
+ ...(releaseFailure ? { release_failure: releaseFailure } : {}) });
279
+ }
280
+ }
@@ -0,0 +1,197 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { readFlowRunExecutionBundle, assertPreparedRunBundleSqlAuthority } from "./runs.js";
6
+ import { requireProjectByRoot } from "./projects.js";
7
+ import { resolveProjectRoot } from "../storage/paths.js";
8
+ import { readDescriptorStageInput } from "./descriptor-stage-coordinator.js";
9
+ import { readAcceptedStageData, prepareStagePacket, acceptStagePacket, publishStagePacket } from "./stage-report-renderer.js";
10
+ import { diagnosticSnapshotPaths, readDiagnosticSnapshot, readDiagnosticSnapshotCustody } from "./diagnostic-snapshot.js";
11
+ import { validateDistillStageResult } from "./distill-stage-results.js";
12
+ import { PreparedDistillWorkCollection } from "./distill-work-collection.js";
13
+ import { collectDistillCandidates } from "./distill-work-results.js";
14
+ import { readDistillUserInputs } from "./distill-user-inputs.js";
15
+ import { readPreparedMemoryFlowUserInputs } from "./memory-flow-user-inputs.js";
16
+ import { prepareDistillDocumentPlan, applyDistillDocumentStep, captureDistillBeforeDocuments, publishDistillBeforeDocuments } from "./distill-document-publication.js";
17
+ import { readDistillPublication, retainDistillPublication, completeDistillPublication, distillPublicationArtifact, readDistillPublicationReference } from "./distill-publication-custody.js";
18
+ import { hybridDigest } from "./hybrid-contracts.js";
19
+ function refuse(reason) {
20
+ throw new AppError("distill_promotion_invalid", "Promotion requires accepted review, delivered agreement and its exact destination", 2, { reason, effect: "no_effect" });
21
+ }
22
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
23
+ const within = (root, target) => { const relative = path.relative(root, target); return !relative || !path.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path.sep}`); };
24
+ function destination(root, protectedRoots) {
25
+ if (!path.isAbsolute(root) || path.resolve(root) !== root || fs.realpathSync(root) !== root || !fs.lstatSync(root).isDirectory())
26
+ refuse("physical_destination_required");
27
+ for (const protectedRoot of protectedRoots) {
28
+ const resolved = fs.existsSync(protectedRoot) ? fs.realpathSync(protectedRoot) : path.resolve(protectedRoot);
29
+ if (within(resolved, root) || within(root, resolved))
30
+ refuse("destination_overlaps_source_or_runtime");
31
+ }
32
+ const stat = fs.lstatSync(root);
33
+ return { dev: stat.dev, ino: stat.ino };
34
+ }
35
+ /** The coordinator owns the semantic interpretation of agreement and proposed
36
+ * wording. This owner admits only actual user-source references and accepted
37
+ * independently reviewed candidates, then fences the full input set on effects.
38
+ * It does not infer agreement from a file named approval or from critic votes.
39
+ * No public launch/handler registration is implied by this internal owner. */
40
+ export class PreparedDistillPromotion {
41
+ #binding;
42
+ #plan;
43
+ #fence;
44
+ #publication;
45
+ #beforeDocuments;
46
+ #runRoot;
47
+ constructor(binding, plan, fence, publication, beforeDocuments, runRoot) {
48
+ this.#binding = structuredClone(binding);
49
+ this.#plan = plan;
50
+ this.#fence = fence;
51
+ this.#publication = { ...publication };
52
+ Object.freeze(this);
53
+ this.#beforeDocuments = structuredClone(beforeDocuments);
54
+ this.#runRoot = runRoot;
55
+ }
56
+ static prepare(context, input) {
57
+ if (!input.proposal || typeof input.proposal !== "object" || Array.isArray(input.proposal))
58
+ refuse("invalid_proposal_json");
59
+ const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), bundle = readFlowRunExecutionBundle(context, input);
60
+ if (!bundle || bundle.manifest.flow_id !== "mb-distill")
61
+ refuse("distill_bundle_required");
62
+ const scope = { projectId: project.id, runId: input.runId, stage: "promote" };
63
+ const stageInput = readDescriptorStageInput(context, scope, bundle);
64
+ if (stageInput.input.predecessor?.stage !== "review")
65
+ refuse("accepted_review_required");
66
+ const accepted = readAcceptedStageData(context, { ...scope, stage: "review" });
67
+ if (hybridDigest(stageInput.input.predecessor.result) !== hybridDigest(accepted.result))
68
+ refuse("review_predecessor_changed");
69
+ const frozen = bundle.execution.snapshot().scope, snapshotScope = { projectId: project.id, projectRoot: frozen.projectRoot,
70
+ sourceRoot: frozen.projectRoot, requestId: frozen.requestId, flowId: "mb-distill" };
71
+ const snapshot = readDiagnosticSnapshot(context, snapshotScope, input.runId);
72
+ if (!snapshot || snapshot.root !== frozen.workspace)
73
+ refuse("source_snapshot_required");
74
+ const reviewInput = readDescriptorStageInput(context, { ...scope, stage: "review" }, bundle, true, true);
75
+ const review = validateDistillStageResult(accepted.bytes, bundle.descriptor.stageBlob("review", "result_schema"), {
76
+ runId: input.runId, stage: "review", inputSha256: reviewInput.inputSha256, snapshotSha256: snapshot.source_sha256,
77
+ snapshotRoot: diagnosticSnapshotPaths(context, snapshot, input.runId).root, runRoot: stageInput.runRoot,
78
+ support: bundle.manifest.inventory.filter(ref => ref.path.startsWith("support/")), writeScope: null, promotionReceipt: null,
79
+ predecessors: reviewInput.input.predecessor ? [{ stage: reviewInput.input.predecessor.stage, ...reviewInput.input.predecessor.result }] : []
80
+ });
81
+ const authors = PreparedDistillWorkCollection.prepare(context, { ...input, stage: "extract" });
82
+ const critics = PreparedDistillWorkCollection.prepare(context, { ...input, stage: "review" }), criticResults = critics.results();
83
+ if (hybridDigest(review.details.candidates) !== hybridDigest(collectDistillCandidates(authors.results()).candidates))
84
+ refuse("review_candidates_changed");
85
+ for (const decision of review.details.decisions) {
86
+ if (!criticResults.some(work => work.result.decisions.some(vote => vote.candidate_id === decision.candidate_id && vote.disposition === decision.disposition)))
87
+ refuse("unsupported_review_resolution");
88
+ }
89
+ const users = readDistillUserInputs(context, input, bundle), proposal = structuredClone(input.proposal), selected = proposal.write_scope;
90
+ if (proposal.user_inputs_sha256 !== hybridDigest(users))
91
+ refuse("user_inputs_changed");
92
+ if (!selected || typeof selected.destination_root !== "string" || !Array.isArray(selected.candidate_ids) || !selected.candidate_ids.length
93
+ || new Set(selected.candidate_ids).size !== selected.candidate_ids.length || !Array.isArray(selected.paths) || !selected.paths.length
94
+ || new Set(selected.paths).size !== selected.paths.length || selected.paths.some(value => typeof value !== "string") || !selected.approval_source
95
+ || selected.approval_source.root !== "run" || !users.sources.some(source => ["request", "answer"].includes(source.role)
96
+ && source.path === selected.approval_source.path && source.sha256 === selected.approval_source.sha256))
97
+ refuse("delivered_agreement_required");
98
+ if (selected.candidate_ids.some(id => !review.details.decisions.some(decision => decision.candidate_id === id && ["adopt", "adapt"].includes(decision.disposition))))
99
+ refuse("unaccepted_candidate");
100
+ if (!Array.isArray(proposal.outputs) || !proposal.outputs.length || proposal.outputs.length > 4096
101
+ || proposal.outputs.some(output => !output || typeof output.content !== "string" || !selected.paths.includes(output.path)
102
+ || !Array.isArray(output.candidate_ids) || !output.candidate_ids.length || new Set(output.candidate_ids).size !== output.candidate_ids.length
103
+ || output.candidate_ids.some(id => !selected.candidate_ids.includes(id)))
104
+ || hybridDigest(proposal.outputs.map(output => output.path).sort()) !== hybridDigest([...selected.paths].sort())
105
+ || selected.candidate_ids.some(id => !proposal.outputs.some(output => output.candidate_ids.includes(id))))
106
+ refuse("output_scope_changed");
107
+ if (proposal.outputs.some(output => Buffer.byteLength(output.content) > 16 * 1024 * 1024)
108
+ || proposal.outputs.reduce((sum, output) => sum + Buffer.byteLength(output.content), 0) > 64 * 1024 * 1024)
109
+ refuse("unbounded_output");
110
+ const protectedRoots = [frozen.projectRoot, frozen.workspace, stageInput.runRoot, context.ddFlowHome];
111
+ const physical = destination(selected.destination_root, protectedRoots);
112
+ const binding = { project_id: project.id, run_id: input.runId, attempt: stageInput.attempt,
113
+ input_sha256: stageInput.inputSha256, bundle_sha256: bundle.sha256, review_sha256: accepted.result.sha256,
114
+ user_inputs_sha256: proposal.user_inputs_sha256, write_scope: selected };
115
+ const previous = readDistillPublication(context, binding);
116
+ const outputs = proposal.outputs.map(output => ({ path: output.path, bytes: Buffer.from(output.content) }));
117
+ const plan = previous?.plan ?? prepareDistillDocumentPlan(selected.destination_root, outputs, new Set(selected.paths));
118
+ const beforeDocuments = previous?.beforeDocuments ?? captureDistillBeforeDocuments(selected.destination_root, plan);
119
+ // Replay compares proposed bytes with the retained after-view; it never
120
+ // recaptures a partly changed destination or replaces the original intent.
121
+ const encoded = JSON.parse(plan.bytes().toString("utf8"));
122
+ const after = JSON.parse(Buffer.from(encoded.after_base64, "base64").toString("utf8"));
123
+ if (outputs.some(output => !after.entries.some((entry) => entry.path === output.path && entry.kind === "file" && entry.sha256 === hash(output.bytes))))
124
+ refuse("original_outputs_required");
125
+ const fence = (writer) => {
126
+ assertPreparedRunBundleSqlAuthority(writer, scope, bundle);
127
+ if (hybridDigest(readDescriptorStageInput(writer, scope, bundle)) !== hybridDigest(stageInput)
128
+ || hybridDigest(readAcceptedStageData(writer, { ...scope, stage: "review" })) !== hybridDigest(accepted)
129
+ || hybridDigest(readDiagnosticSnapshotCustody(writer, snapshotScope, input.runId)) !== hybridDigest(snapshot)
130
+ || hybridDigest(readPreparedMemoryFlowUserInputs(writer, scope, "mb-distill", bundle)) !== proposal.user_inputs_sha256
131
+ || hybridDigest(destination(selected.destination_root, protectedRoots)) !== hybridDigest(physical))
132
+ refuse("promotion_authority_changed");
133
+ authors.assertCustody(writer);
134
+ critics.assertCustody(writer);
135
+ };
136
+ const logical = `${bundle.descriptor.stage("promote").directory}/publication.json`;
137
+ return new PreparedDistillPromotion(binding, plan, fence, { file: path.join(stageInput.runRoot, logical), logical }, beforeDocuments, stageInput.runRoot);
138
+ }
139
+ binding() { return structuredClone(this.#binding); }
140
+ assertCustody(context) { this.#fence(context); }
141
+ applyStep(context) {
142
+ const fence = () => this.#fence(context), root = this.#binding.write_scope.destination_root;
143
+ retainDistillPublication(context, this.#binding, this.#plan, fence, this.#beforeDocuments);
144
+ publishDistillBeforeDocuments(this.#runRoot, this.#plan, this.#beforeDocuments);
145
+ const result = applyDistillDocumentStep(root, this.#plan, fence);
146
+ if (result.status !== "applied")
147
+ return { ...result, status: "partial" };
148
+ try {
149
+ const completed = completeDistillPublication(context, this.#binding, fence);
150
+ return { ...result, status: "applied", receipt: completed.receipt };
151
+ }
152
+ catch (error) {
153
+ // Files may already be published even though the final SQL observation
154
+ // failed. Do not report no_effect or let a caller replace the old intent.
155
+ throw new AppError("distill_publication_pending", "Reconcile the retained publication before claiming completion", 1, { effect: "publication_pending", plan_sha256: this.#plan.sha256, cause: error instanceof Error ? error.message : String(error) });
156
+ }
157
+ }
158
+ apply(context) {
159
+ const maximum = this.#plan.actions().length;
160
+ for (let step = 0; step <= maximum; step++) {
161
+ const result = this.applyStep(context);
162
+ if (result.status !== "applied")
163
+ continue;
164
+ try {
165
+ const packet = prepareStagePacket(this.#publication.file, distillPublicationArtifact(this.#binding, this.#plan));
166
+ context.db.writeTransaction(() => {
167
+ this.#fence(context);
168
+ const completed = readDistillPublication(context, this.#binding);
169
+ if (!completed?.completed || completed.plan.sha256 !== this.#plan.sha256)
170
+ refuse("completed_publication_required");
171
+ if (!readDistillPublicationReference(context, this.#binding, this.#plan, this.#publication.logical))
172
+ acceptStagePacket(context, { projectId: this.#binding.project_id, runId: this.#binding.run_id, stage: "promote", prepared: packet });
173
+ });
174
+ publishStagePacket(context, this.#binding.project_id, this.#binding.run_id, "promote", packet.file);
175
+ return { ...result, publication: { root: "run", path: this.#publication.logical, sha256: packet.sha256 } };
176
+ }
177
+ catch (error) {
178
+ throw new AppError("distill_publication_pending", "Published documents require their retained result projection before Stage acceptance", 1, { effect: "publication_pending", plan_sha256: this.#plan.sha256, cause: error instanceof Error ? error.message : String(error) });
179
+ }
180
+ }
181
+ return refuse("publication_did_not_progress");
182
+ }
183
+ }
184
+ export function publishDistillFromStage(context, input) {
185
+ if (!input.bytes.length || input.bytes.length > 1024 * 1024)
186
+ refuse("unbounded_proposal");
187
+ let proposal;
188
+ try {
189
+ proposal = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.bytes));
190
+ }
191
+ catch {
192
+ return refuse("invalid_proposal_json");
193
+ }
194
+ if (!proposal || typeof proposal !== "object" || Array.isArray(proposal))
195
+ refuse("invalid_proposal_json");
196
+ return PreparedDistillPromotion.prepare(context, { projectRoot: input.projectRoot, runId: input.runId, proposal }).apply(context);
197
+ }
@@ -0,0 +1,162 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ import { RetainedMemoryRepairPublicationPlan } from "./memory-repair-publication-plan.js";
3
+ import { hybridDigest } from "./hybrid-contracts.js";
4
+ import { appendAudit } from "./audit.js";
5
+ import path from "node:path";
6
+ import { createHash } from "node:crypto";
7
+ import { resolveStagePublicationPath } from "./stage-report-renderer.js";
8
+ import { validateDistillBeforeDocuments, distillBeforeDocumentReferences } from "./distill-document-publication.js";
9
+ const intentEvent = "distill.publication_intent", completeEvent = "distill.publication_complete";
10
+ const key = (binding) => `distill_publication:${hybridDigest({ project_id: binding.project_id, run_id: binding.run_id })}`;
11
+ function refuse(reason) {
12
+ throw new AppError("distill_publication_custody_invalid", "Publication requires its original approved binding and retained plan", 1, { reason, effect: "no_effect" });
13
+ }
14
+ const receipt = (binding, plan, completed = false) => ({
15
+ schema_id: completed ? "dd-flow/distill-publication-complete@1" : "dd-flow/distill-publication-intent@1",
16
+ run_id: binding.run_id, binding_sha256: hybridDigest(binding), plan_sha256: plan.sha256
17
+ });
18
+ /** SQL custody only. The caller derives binding from the active Stage,
19
+ * accepted review and delivered user input, never from model authority fields.
20
+ * An existing intent cannot adopt today's partly changed destination as baseline. */
21
+ export function readDistillPublication(context, binding) {
22
+ return context.db.readSnapshot(() => {
23
+ const row = context.db.get("SELECT value_json FROM runtime_config WHERE key=?", [key(binding)]);
24
+ const events = (type) => context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type=? AND json_extract(payload_json,'$.run_id')=? LIMIT 2", [binding.project_id, type, binding.run_id]);
25
+ const intents = events(intentEvent), completions = events(completeEvent);
26
+ if (!row && !intents.length && !completions.length)
27
+ return null;
28
+ if (!row || intents.length !== 1 || completions.length > 1 || Buffer.byteLength(row.value_json) > 180 * 1024 * 1024
29
+ || [...intents, ...completions].some(value => Buffer.byteLength(value.payload_json) > 32768))
30
+ refuse("missing_or_unbounded_custody");
31
+ try {
32
+ const value = JSON.parse(row.value_json);
33
+ if (!value || Object.keys(value).sort().join() !== "before_documents,binding,plan_json,plan_sha256" || hybridDigest(value.binding) !== hybridDigest(binding)
34
+ || typeof value.plan_json !== "string")
35
+ refuse("binding_changed");
36
+ const plan = RetainedMemoryRepairPublicationPlan.restore(Buffer.from(value.plan_json), value.plan_sha256);
37
+ const beforeDocuments = validateDistillBeforeDocuments(plan, value.before_documents);
38
+ if (hybridDigest(JSON.parse(intents[0].payload_json)) !== hybridDigest(receipt(binding, plan))
39
+ || completions.length && hybridDigest(JSON.parse(completions[0].payload_json)) !== hybridDigest(receipt(binding, plan, true)))
40
+ refuse("receipt_changed");
41
+ return { plan, beforeDocuments, completed: completions.length === 1 };
42
+ }
43
+ catch (error) {
44
+ if (error instanceof AppError)
45
+ throw error;
46
+ return refuse("invalid_retained_publication");
47
+ }
48
+ });
49
+ }
50
+ export function retainDistillPublication(context, binding, plan, assertAuthority, beforeDocuments = []) {
51
+ if (!(plan instanceof RetainedMemoryRepairPublicationPlan) || typeof assertAuthority !== "function")
52
+ refuse("prepared_plan_required");
53
+ const paths = JSON.parse(Buffer.from(JSON.parse(plan.bytes().toString("utf8")).before_base64, "base64").toString("utf8")).write_paths;
54
+ if (hybridDigest([...paths].sort()) !== hybridDigest([...binding.write_scope.paths].sort()))
55
+ refuse("plan_scope_changed");
56
+ const originals = validateDistillBeforeDocuments(plan, beforeDocuments);
57
+ return context.db.writeTransaction(() => {
58
+ assertAuthority();
59
+ const prior = readDistillPublication(context, binding);
60
+ if (prior) {
61
+ if (prior.plan.sha256 !== plan.sha256 || hybridDigest(prior.beforeDocuments) !== hybridDigest(originals))
62
+ refuse("original_plan_required");
63
+ return { changed: false, plan: prior.plan };
64
+ }
65
+ // A new intent must describe the original destination, not an already
66
+ // applied prefix or a different directory with coincidentally similar paths.
67
+ if (plan.classify(binding.write_scope.destination_root).completed !== 0)
68
+ refuse("original_destination_required");
69
+ const now = context.now();
70
+ const value = JSON.stringify({ binding, plan_json: plan.bytes().toString("utf8"), plan_sha256: plan.sha256, before_documents: originals });
71
+ if (Buffer.byteLength(value) > 180 * 1024 * 1024)
72
+ refuse("unbounded_publication_custody");
73
+ context.db.run("INSERT INTO runtime_config(key,value_json,created_at,updated_at) VALUES (?,?,?,?)", [key(binding), value, now, now]);
74
+ appendAudit(context, { projectId: binding.project_id, eventType: intentEvent, payload: receipt(binding, plan) });
75
+ if (readDistillPublication(context, binding)?.plan.sha256 !== plan.sha256)
76
+ refuse("intent_not_retained");
77
+ return { changed: true, plan };
78
+ });
79
+ }
80
+ /** Physical readback precedes the short SQL writer; the owner fences its
81
+ * accepted inputs in that writer. This receipt is not independent verification
82
+ * or terminal RUN acceptance. */
83
+ export function completeDistillPublication(context, binding, assertAuthority) {
84
+ if (typeof assertAuthority !== "function")
85
+ refuse("authority_fence_required");
86
+ const retained = readDistillPublication(context, binding);
87
+ if (!retained)
88
+ refuse("intent_required");
89
+ const actual = retained.plan.classify(binding.write_scope.destination_root);
90
+ if (actual.completed !== actual.total)
91
+ refuse("publication_not_applied");
92
+ return context.db.writeTransaction(() => {
93
+ assertAuthority();
94
+ const current = readDistillPublication(context, binding);
95
+ if (!current || current.plan.sha256 !== retained.plan.sha256)
96
+ refuse("intent_changed");
97
+ // The authority fence may perform reads/callbacks. Never certify an earlier
98
+ // filesystem observation if the destination changed while it ran.
99
+ const observed = current.plan.classify(binding.write_scope.destination_root);
100
+ if (observed.completed !== observed.total)
101
+ refuse("publication_not_applied");
102
+ if (!current.completed)
103
+ appendAudit(context, { projectId: binding.project_id, eventType: completeEvent, payload: receipt(binding, current.plan, true) });
104
+ if (!readDistillPublication(context, binding)?.completed)
105
+ refuse("completion_not_retained");
106
+ return { changed: !current.completed, plan: current.plan, receipt: receipt(binding, current.plan, true) };
107
+ });
108
+ }
109
+ /** Read original completed intent for downstream Stage handoff, never infer a
110
+ * write scope from its result proposal or recapture today's destination. */
111
+ export function readCompletedDistillPublication(context, expected) {
112
+ return context.db.readSnapshot(() => {
113
+ const row = context.db.get("SELECT value_json FROM runtime_config WHERE key=?", [key(expected)]);
114
+ if (!row || Buffer.byteLength(row.value_json) > 180 * 1024 * 1024)
115
+ refuse("completed_intent_required");
116
+ let binding;
117
+ try {
118
+ binding = JSON.parse(row.value_json).binding;
119
+ }
120
+ catch {
121
+ return refuse("invalid_retained_publication");
122
+ }
123
+ if (!binding || !binding.write_scope || !Array.isArray(binding.write_scope.paths)
124
+ || typeof binding.user_inputs_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(binding.user_inputs_sha256)
125
+ || hybridDigest(binding) !== hybridDigest({ ...expected, write_scope: binding.write_scope, user_inputs_sha256: binding.user_inputs_sha256 }))
126
+ refuse("binding_changed");
127
+ const retained = readDistillPublication(context, binding);
128
+ if (!retained?.completed)
129
+ refuse("publication_not_complete");
130
+ return { binding: structuredClone(binding), plan: retained.plan, beforeDocuments: retained.beforeDocuments };
131
+ });
132
+ }
133
+ /** Serialization only, not proof of effects or Stage acceptance. Both publisher
134
+ * and handoff reader use exactly these bytes selected from committed intent. */
135
+ export function distillPublicationArtifact(binding, plan) {
136
+ const encoded = JSON.parse(plan.bytes().toString("utf8"));
137
+ const after = JSON.parse(Buffer.from(encoded.after_base64, "base64").toString("utf8"));
138
+ return Buffer.from(JSON.stringify({ schema_id: "dd-flow/distill-publication@1", binding, plan_sha256: plan.sha256,
139
+ documents: after.entries.filter((entry) => binding.write_scope.paths.includes(entry.path)),
140
+ before_documents: distillBeforeDocumentReferences(plan), receipt: receipt(binding, plan, true) }));
141
+ }
142
+ /** Retained packet custody, not a file with a persuasive name. Return null only
143
+ * when publication has not retained this projection; conflicting custody refuses.
144
+ * Identical old retries remain readable, but publishers must not append more. */
145
+ export function readDistillPublicationReference(context, binding, plan, logicalPath) {
146
+ if (!logicalPath || path.isAbsolute(logicalPath) || logicalPath.includes("\\") || logicalPath.split("/").some(part => !part || part === "." || part === ".."))
147
+ refuse("invalid_publication_locator");
148
+ const run = context.db.get("SELECT run_root FROM runs WHERE project_id=? AND id=?", [binding.project_id, binding.run_id]);
149
+ if (!run?.run_root)
150
+ refuse("run_home_required");
151
+ const file = path.join(run.run_root, logicalPath), bytes = distillPublicationArtifact(binding, plan), sha256 = createHash("sha256").update(bytes).digest("hex");
152
+ const rows = context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type='flow_run.stage_packet' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.stage')='promote' AND json_extract(payload_json,'$.attempt')=? LIMIT 33", [binding.project_id, binding.run_id, binding.attempt]);
153
+ if (rows.length > 32 || rows.some(row => Buffer.byteLength(row.payload_json) > 8 * 1024 * 1024))
154
+ refuse("unbounded_publication_packets");
155
+ const packets = rows.map(row => JSON.parse(row.payload_json)).filter(packet => typeof packet.file === "string"
156
+ && resolveStagePublicationPath(context, binding.project_id, binding.run_id, packet.file) === file);
157
+ if (!packets.length)
158
+ return null;
159
+ if (packets.some(packet => packet.sha256 !== sha256 || packet.base64 !== bytes.toString("base64")))
160
+ refuse("publication_packet_changed");
161
+ return { root: "run", path: logicalPath, sha256 };
162
+ }