@deksden-com/dd-flow-cli 0.9.0-beta.14 → 0.9.0-beta.140

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 (493) hide show
  1. package/CHANGELOG.md +733 -0
  2. package/README.md +143 -1
  3. package/dist/build-info.json +8 -8
  4. package/dist/cli/argument-values.js +38 -0
  5. package/dist/cli/command-inputs.js +376 -0
  6. package/dist/cli/command-metadata.js +197 -0
  7. package/dist/cli/command-option-descriptions.js +191 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/error-output.js +52 -0
  11. package/dist/cli/executor-onboarding.js +76 -0
  12. package/dist/cli/flows.js +29 -0
  13. package/dist/cli/harnesses.js +84 -0
  14. package/dist/cli/help.js +328 -18
  15. package/dist/cli/hook-ingress.js +78 -0
  16. package/dist/cli/input-preparation.js +165 -0
  17. package/dist/cli/memory-flow-admission.js +44 -0
  18. package/dist/cli/memory-init-invocation.js +78 -0
  19. package/dist/cli/memory-init.js +240 -0
  20. package/dist/cli/memory-storage-admission.js +53 -0
  21. package/dist/cli/models.js +39 -0
  22. package/dist/cli/native-hook-ingress.js +80 -0
  23. package/dist/cli/operator-profiles.js +61 -0
  24. package/dist/cli/output-options.js +35 -0
  25. package/dist/cli/response-file.js +71 -0
  26. package/dist/cli/run-cli.js +1689 -545
  27. package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
  28. package/dist/cli/runtime-maintenance-ingress.js +52 -0
  29. package/dist/cli/runtime-process.js +153 -0
  30. package/dist/cli/setup.js +149 -0
  31. package/dist/cli.js +71 -2
  32. package/dist/domain/stage-catalog.js +1 -1
  33. package/dist/domain/stage-handler-identities.js +20 -0
  34. package/dist/harness-runtime/DD-ZCODE.md +112 -0
  35. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  36. package/dist/harness-runtime/bin/dd-agy.mjs +56 -0
  37. package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
  38. package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
  39. package/dist/harness-runtime/bin/dd-grok.mjs +40 -0
  40. package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
  41. package/dist/harness-runtime/bin/dd-zcode.mjs +87 -0
  42. package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
  43. package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
  44. package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
  45. package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
  46. package/dist/harness-runtime/lib/daemon-observation.d.mts +2 -0
  47. package/dist/harness-runtime/lib/daemon-observation.mjs +163 -0
  48. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  49. package/dist/harness-runtime/lib/daemon-operations.mjs +371 -0
  50. package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
  51. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +724 -0
  52. package/dist/harness-runtime/lib/dd-agy.mjs +70 -0
  53. package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
  54. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +196 -0
  55. package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
  56. package/dist/harness-runtime/lib/dd-codex.mjs +817 -0
  57. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +129 -0
  58. package/dist/harness-runtime/lib/dd-droid.mjs +584 -0
  59. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +498 -0
  60. package/dist/harness-runtime/lib/dd-grok.mjs +177 -0
  61. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +507 -0
  62. package/dist/harness-runtime/lib/dd-opencode.mjs +354 -0
  63. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +750 -0
  64. package/dist/harness-runtime/lib/dd-zcode.mjs +1145 -0
  65. package/dist/harness-runtime/lib/delegation-instructions.d.mts +14 -0
  66. package/dist/harness-runtime/lib/delegation-instructions.mjs +157 -0
  67. package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
  68. package/dist/harness-runtime/lib/driver-recovery.mjs +139 -0
  69. package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
  70. package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
  71. package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
  72. package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
  73. package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
  74. package/dist/harness-runtime/lib/lifecycle-contract.d.mts +10 -0
  75. package/dist/harness-runtime/lib/lifecycle-contract.mjs +19 -0
  76. package/dist/harness-runtime/lib/managed-daemon.d.mts +13 -0
  77. package/dist/harness-runtime/lib/managed-daemon.mjs +654 -0
  78. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  79. package/dist/harness-runtime/lib/model-observations.mjs +101 -0
  80. package/dist/harness-runtime/lib/native-children.d.mts +16 -0
  81. package/dist/harness-runtime/lib/native-children.mjs +113 -0
  82. package/dist/harness-runtime/lib/native-hook-command.d.mts +7 -0
  83. package/dist/harness-runtime/lib/native-hook-command.mjs +251 -0
  84. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  85. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  86. package/dist/harness-runtime/lib/native-streams.mjs +45 -0
  87. package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
  88. package/dist/harness-runtime/lib/observation-clock.mjs +92 -0
  89. package/dist/harness-runtime/lib/opencode-plugin.mjs +85 -0
  90. package/dist/harness-runtime/lib/operation-context.mjs +5 -0
  91. package/dist/harness-runtime/lib/operation-errors.d.mts +14 -0
  92. package/dist/harness-runtime/lib/operation-errors.mjs +116 -0
  93. package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
  94. package/dist/harness-runtime/lib/operation-progress.mjs +114 -0
  95. package/dist/harness-runtime/lib/process-json.d.mts +5 -0
  96. package/dist/harness-runtime/lib/process-json.mjs +201 -0
  97. package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
  98. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +13 -0
  99. package/dist/harness-runtime/lib/provider-overload-policy.mjs +138 -0
  100. package/dist/harness-runtime/lib/runner-events.mjs +200 -0
  101. package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
  102. package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
  103. package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
  104. package/dist/harness-runtime/lib/setup-progress.mjs +51 -0
  105. package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
  106. package/dist/harness-runtime/lib/tool-observations.mjs +228 -0
  107. package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
  108. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  109. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  110. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  111. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  112. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  113. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  114. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  115. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  116. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  117. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  118. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  119. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  120. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  121. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  122. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  123. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  124. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  125. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  126. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  127. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  128. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  129. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  130. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  131. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  132. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  133. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  134. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  135. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  136. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  137. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  138. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  139. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  140. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  141. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  142. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  143. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  144. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  145. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  146. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  147. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  148. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  149. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  150. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  151. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  152. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  153. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  154. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  155. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  156. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  157. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  158. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  159. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  160. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  161. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  162. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  163. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  164. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  165. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  166. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  167. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  168. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  169. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  170. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  171. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  172. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  173. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  174. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  175. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  176. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  177. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  178. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  179. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  180. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  181. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  182. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  183. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  184. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  185. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  186. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  187. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  188. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  189. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  190. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  191. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  192. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  193. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  194. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  195. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  196. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  197. package/dist/protocol/local-files.js +18 -9
  198. package/dist/runtime/context.js +8 -4
  199. package/dist/schemas/agent-profile.schema.json +1 -1
  200. package/dist/schemas/code-review-result.schema.json +1 -1
  201. package/dist/schemas/code-verification.schema.json +7 -5
  202. package/dist/schemas/code-work-batch.schema.json +2 -2
  203. package/dist/schemas/discovery-result.schema.json +184 -0
  204. package/dist/schemas/execution-bundle.schema.json +205 -0
  205. package/dist/schemas/execution-settings.schema.json +162 -0
  206. package/dist/schemas/flow-descriptor.schema.json +54 -0
  207. package/dist/schemas/flow-run.schema.json +28 -0
  208. package/dist/schemas/harness-catalog.schema.json +80 -0
  209. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  210. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  211. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  212. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  213. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  214. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  215. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  216. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  217. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  218. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  219. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  220. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  221. package/dist/schemas/model-catalog.schema.json +153 -0
  222. package/dist/schemas/plan-review-decision.schema.json +3 -3
  223. package/dist/schemas/plan-review-result.schema.json +2 -2
  224. package/dist/schemas/profile-settings.schema.json +122 -0
  225. package/dist/schemas/release-manifest.schema.json +291 -0
  226. package/dist/schemas/run-control-receipt.schema.json +118 -0
  227. package/dist/schemas/run-control-request.schema.json +36 -0
  228. package/dist/schemas/run-engine-binding.schema.json +1 -1
  229. package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
  230. package/dist/services/branch-context.js +3 -3
  231. package/dist/services/canon.js +11 -8
  232. package/dist/services/check-runner-evidence.js +168 -0
  233. package/dist/services/cleanup.js +133 -40
  234. package/dist/services/cli-operation-classifier.js +25 -62
  235. package/dist/services/cli-upgrade-allowlist.js +27 -0
  236. package/dist/services/code-checks.js +1156 -107
  237. package/dist/services/codex-hook-delivery.js +32 -0
  238. package/dist/services/command-context.js +80 -0
  239. package/dist/services/compatibility-preflight.js +13 -3
  240. package/dist/services/config.js +11 -8
  241. package/dist/services/continuation-outcome.js +20 -0
  242. package/dist/services/controller-child-capacity.js +13 -0
  243. package/dist/services/controller-child-observer.js +115 -0
  244. package/dist/services/controller-execution.js +88 -0
  245. package/dist/services/controller-fanout.js +202 -0
  246. package/dist/services/dashboard.js +143 -58
  247. package/dist/services/descriptor-coordinator-session.js +35 -0
  248. package/dist/services/descriptor-root-work.js +53 -0
  249. package/dist/services/descriptor-run-settlement.js +105 -0
  250. package/dist/services/descriptor-run-start.js +449 -0
  251. package/dist/services/descriptor-stage-coordinator.js +197 -0
  252. package/dist/services/descriptor-stage-settlement.js +222 -0
  253. package/dist/services/descriptor-stage-start.js +139 -0
  254. package/dist/services/discovery/agy-discovery.js +2 -0
  255. package/dist/services/discovery/codex-discovery.js +2 -0
  256. package/dist/services/discovery/droid-discovery.js +2 -0
  257. package/dist/services/discovery/grok-discovery.js +2 -0
  258. package/dist/services/discovery/opencode-discovery.js +2 -0
  259. package/dist/services/discovery/static.js +31 -0
  260. package/dist/services/discovery/zcode-discovery.js +2 -0
  261. package/dist/services/engines.js +294 -153
  262. package/dist/services/eval-snapshots.js +1215 -116
  263. package/dist/services/execution-bundles.js +263 -0
  264. package/dist/services/execution-policy.js +185 -0
  265. package/dist/services/executor-onboarding.js +56 -0
  266. package/dist/services/external-work-launch.js +308 -0
  267. package/dist/services/flow-catalog.js +21 -0
  268. package/dist/services/flow-descriptors.js +82 -0
  269. package/dist/services/frozen-engine.js +250 -0
  270. package/dist/services/generic-execution.js +164 -0
  271. package/dist/services/harness-adapter.js +355 -36
  272. package/dist/services/harness-config.js +2 -0
  273. package/dist/services/harness-discovery.js +29 -0
  274. package/dist/services/harness-doctor.js +75 -0
  275. package/dist/services/harness-probe-effects.js +51 -0
  276. package/dist/services/harness-version-probe.js +100 -0
  277. package/dist/services/hooks.js +771 -325
  278. package/dist/services/hybrid-contracts.js +483 -0
  279. package/dist/services/ids.js +29 -1
  280. package/dist/services/installation-lock.js +95 -0
  281. package/dist/services/installed-flow-source.js +183 -0
  282. package/dist/services/lanes.js +78 -65
  283. package/dist/services/lifecycle-command.js +1 -288
  284. package/dist/services/lifecycle-contract.js +1 -0
  285. package/dist/services/lifecycle-invocations.js +2007 -0
  286. package/dist/services/managed-daemon-binding.js +38 -0
  287. package/dist/services/managed-lease-monitor.js +133 -0
  288. package/dist/services/managed-processes.js +475 -55
  289. package/dist/services/memory-accepted-composition.js +77 -0
  290. package/dist/services/memory-baseline-preservation.js +65 -0
  291. package/dist/services/memory-completed-correction-wave.js +320 -0
  292. package/dist/services/memory-compose-handler.js +258 -0
  293. package/dist/services/memory-composition-acceptance.js +199 -0
  294. package/dist/services/memory-composition-graph.js +134 -0
  295. package/dist/services/memory-composition-registration.js +146 -0
  296. package/dist/services/memory-composition-work-custody.js +151 -0
  297. package/dist/services/memory-composition-work-results.js +96 -0
  298. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  299. package/dist/services/memory-corrected-review-batch.js +30 -0
  300. package/dist/services/memory-corrected-review-findings.js +106 -0
  301. package/dist/services/memory-corrected-review-inputs.js +210 -0
  302. package/dist/services/memory-corrected-review-projection.js +78 -0
  303. package/dist/services/memory-corrected-review-receipt.js +170 -0
  304. package/dist/services/memory-corrected-review-registration.js +191 -0
  305. package/dist/services/memory-correction-check-receipt.js +219 -0
  306. package/dist/services/memory-correction-input-owner.js +6 -0
  307. package/dist/services/memory-discover-handler.js +104 -0
  308. package/dist/services/memory-finish-evidence.js +435 -0
  309. package/dist/services/memory-finish-handler.js +215 -0
  310. package/dist/services/memory-finish-integration.js +280 -0
  311. package/dist/services/memory-finish-readiness.js +122 -0
  312. package/dist/services/memory-git-integration.js +151 -0
  313. package/dist/services/memory-historical-corrected-review.js +206 -0
  314. package/dist/services/memory-historical-original-review.js +130 -0
  315. package/dist/services/memory-historical-repair-registration.js +99 -0
  316. package/dist/services/memory-historical-second-review.js +128 -0
  317. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  318. package/dist/services/memory-init-contexts.js +89 -0
  319. package/dist/services/memory-init-controller-start.js +84 -0
  320. package/dist/services/memory-init-engine-release.js +223 -0
  321. package/dist/services/memory-init-git-policy.js +136 -0
  322. package/dist/services/memory-init-lint-capability.js +185 -0
  323. package/dist/services/memory-init-native-capacity.js +296 -0
  324. package/dist/services/memory-init-preflight.js +330 -0
  325. package/dist/services/memory-init-project-bootstrap.js +599 -0
  326. package/dist/services/memory-init-request-candidate.js +157 -0
  327. package/dist/services/memory-init-request-input.js +66 -0
  328. package/dist/services/memory-init-resource-storage.js +125 -0
  329. package/dist/services/memory-init-run-allocation.js +81 -0
  330. package/dist/services/memory-init-run-bundle.js +98 -0
  331. package/dist/services/memory-init-start.js +181 -0
  332. package/dist/services/memory-init-startup-custody.js +80 -0
  333. package/dist/services/memory-init-startup-input.js +240 -0
  334. package/dist/services/memory-init-storage.js +81 -0
  335. package/dist/services/memory-init-stores.js +359 -0
  336. package/dist/services/memory-init-worktrunk-capability.js +178 -0
  337. package/dist/services/memory-layer-publication.js +611 -0
  338. package/dist/services/memory-layer.js +156 -0
  339. package/dist/services/memory-lint-config.js +85 -0
  340. package/dist/services/memory-native-review-copy.js +165 -0
  341. package/dist/services/memory-normal-flow-entry.js +75 -0
  342. package/dist/services/memory-ordinary-defaults.js +112 -0
  343. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  344. package/dist/services/memory-preflight-handler.js +259 -0
  345. package/dist/services/memory-repair-current-view.js +299 -0
  346. package/dist/services/memory-repair-document-delta.js +451 -0
  347. package/dist/services/memory-repair-history.js +491 -0
  348. package/dist/services/memory-repair-physical-binding.js +312 -0
  349. package/dist/services/memory-repair-publication-files.js +152 -0
  350. package/dist/services/memory-repair-publication-intent.js +27 -0
  351. package/dist/services/memory-repair-publication-plan.js +160 -0
  352. package/dist/services/memory-repair-publication-source.js +225 -0
  353. package/dist/services/memory-repair-publication.js +794 -0
  354. package/dist/services/memory-repair-registration.js +239 -0
  355. package/dist/services/memory-repair-work-baseline.js +413 -0
  356. package/dist/services/memory-repair-work-completion.js +97 -0
  357. package/dist/services/memory-repair-work-custody.js +73 -0
  358. package/dist/services/memory-repair-work-results.js +89 -0
  359. package/dist/services/memory-repair-workspace.js +252 -0
  360. package/dist/services/memory-repair-writer-copy.js +735 -0
  361. package/dist/services/memory-result-binding.js +173 -0
  362. package/dist/services/memory-retained-review-authority.js +129 -0
  363. package/dist/services/memory-retained-review-results.js +70 -0
  364. package/dist/services/memory-retained-second-baseline.js +102 -0
  365. package/dist/services/memory-retained-second-repairs.js +156 -0
  366. package/dist/services/memory-review-acceptance.js +214 -0
  367. package/dist/services/memory-review-correction-plan.js +171 -0
  368. package/dist/services/memory-review-handler.js +585 -0
  369. package/dist/services/memory-review-inputs.js +200 -0
  370. package/dist/services/memory-review-receipt.js +180 -0
  371. package/dist/services/memory-review-registration.js +108 -0
  372. package/dist/services/memory-review-work-custody.js +124 -0
  373. package/dist/services/memory-review-work-input.js +72 -0
  374. package/dist/services/memory-review-work-results.js +73 -0
  375. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  376. package/dist/services/memory-second-correction-plan.js +76 -0
  377. package/dist/services/memory-second-repair-baseline.js +91 -0
  378. package/dist/services/memory-second-repair-launch.js +614 -0
  379. package/dist/services/memory-second-repair-registration.js +88 -0
  380. package/dist/services/memory-second-repair-source.js +187 -0
  381. package/dist/services/memory-second-review-acceptance.js +115 -0
  382. package/dist/services/memory-source-observations.js +117 -0
  383. package/dist/services/memory-stage-dispatch.js +28 -0
  384. package/dist/services/memory-stage-results.js +199 -0
  385. package/dist/services/memory-verification-acceptance.js +135 -0
  386. package/dist/services/memory-verification-checks.js +252 -0
  387. package/dist/services/memory-verification-receipt.js +159 -0
  388. package/dist/services/memory-verify-handler.js +135 -0
  389. package/dist/services/memory-work-result-preparation.js +63 -0
  390. package/dist/services/merge-queue.js +228 -149
  391. package/dist/services/merge-server.js +161 -35
  392. package/dist/services/migrations.js +37 -16
  393. package/dist/services/model-catalog.js +109 -0
  394. package/dist/services/model-discovery.js +46 -0
  395. package/dist/services/native-daemon-history.js +49 -0
  396. package/dist/services/native-session-control.js +39 -0
  397. package/dist/services/operator-profiles.js +236 -0
  398. package/dist/services/plan-runtime.js +26 -11
  399. package/dist/services/plans.js +28 -25
  400. package/dist/services/projects.js +37 -17
  401. package/dist/services/prompts.js +28 -17
  402. package/dist/services/protocols.js +163 -87
  403. package/dist/services/provider-capacity.js +385 -0
  404. package/dist/services/recovery-observation-budget.js +121 -0
  405. package/dist/services/recovery-snapshot-database.js +560 -0
  406. package/dist/services/release-archive-producer.js +52 -0
  407. package/dist/services/release-archive.js +143 -0
  408. package/dist/services/release-cache.js +142 -0
  409. package/dist/services/release-compatibility.js +18 -0
  410. package/dist/services/release-download.js +67 -0
  411. package/dist/services/release-envelope.js +104 -0
  412. package/dist/services/release-manifest.js +45 -0
  413. package/dist/services/release-payload.js +114 -0
  414. package/dist/services/release-producer.js +63 -0
  415. package/dist/services/release-provenance.js +160 -0
  416. package/dist/services/release-registry.js +66 -0
  417. package/dist/services/release-source.js +194 -0
  418. package/dist/services/repair-intents.js +42 -0
  419. package/dist/services/review-copy.js +165 -0
  420. package/dist/services/review-deferral.js +23 -0
  421. package/dist/services/run-control-receipt.js +56 -0
  422. package/dist/services/run-control-worker.js +411 -0
  423. package/dist/services/run-control.js +1056 -0
  424. package/dist/services/run-controller-adapter.js +399 -0
  425. package/dist/services/run-controller-capture.js +186 -0
  426. package/dist/services/run-controller-process.js +208 -0
  427. package/dist/services/run-controller-recovery.js +289 -0
  428. package/dist/services/run-controller-state.js +97 -0
  429. package/dist/services/run-controller.js +1205 -0
  430. package/dist/services/run-engine-bindings.js +1 -1
  431. package/dist/services/run-fork.js +147 -0
  432. package/dist/services/run-health.js +149 -0
  433. package/dist/services/run-observations.js +152 -0
  434. package/dist/services/run-projection.js +22 -64
  435. package/dist/services/run-recovery-guard.js +77 -0
  436. package/dist/services/run-recovery-runtime.js +112 -0
  437. package/dist/services/run-recovery.js +489 -0
  438. package/dist/services/run-start-custody.js +177 -0
  439. package/dist/services/runs.js +1019 -247
  440. package/dist/services/runtime-budget.js +430 -0
  441. package/dist/services/runtime-command.js +43 -0
  442. package/dist/services/runtime-scope-capture.js +52 -0
  443. package/dist/services/runtime-scope-control.js +468 -0
  444. package/dist/services/runtime-scope-resume.js +599 -0
  445. package/dist/services/runtime-scope-stop.js +210 -0
  446. package/dist/services/runtime-scope-worker.js +287 -0
  447. package/dist/services/runtime-service.js +96 -0
  448. package/dist/services/schema-validation.js +10 -8
  449. package/dist/services/scope-writer-cleanup.js +27 -0
  450. package/dist/services/sessions.js +35 -69
  451. package/dist/services/setup.js +377 -0
  452. package/dist/services/stage-blocker.js +17 -7
  453. package/dist/services/stage-context.js +193 -19
  454. package/dist/services/stage-handlers.js +74 -0
  455. package/dist/services/stage-lifecycle.js +100 -108
  456. package/dist/services/stage-pause.js +89 -75
  457. package/dist/services/stage-report-renderer.js +234 -6
  458. package/dist/services/stage-work-graph.js +52 -0
  459. package/dist/services/tooling.js +32 -23
  460. package/dist/services/usage.js +49 -101
  461. package/dist/services/verification-matrix.js +374 -0
  462. package/dist/services/vnext-code-review.js +223 -88
  463. package/dist/services/vnext-code.js +327 -226
  464. package/dist/services/vnext-contracts.js +10 -1
  465. package/dist/services/vnext-execution-profile.js +80 -5
  466. package/dist/services/vnext-fanout.js +311 -19
  467. package/dist/services/vnext-merge.js +332 -111
  468. package/dist/services/vnext-plan-review.js +279 -127
  469. package/dist/services/vnext-plan.js +229 -104
  470. package/dist/services/vnext-protocolize.js +411 -86
  471. package/dist/services/vnext-specify.js +119 -81
  472. package/dist/services/vnext-workspace-policy.js +7 -2
  473. package/dist/services/work-registry.js +1627 -199
  474. package/dist/services/workspace-bootstrap.js +52 -15
  475. package/dist/services/workspace-files.js +85 -0
  476. package/dist/services/worktrees.js +98 -44
  477. package/dist/shared/entity-references.js +8 -0
  478. package/dist/shared/errors.js +17 -0
  479. package/dist/storage/agent-output.js +26 -0
  480. package/dist/storage/database.js +891 -39
  481. package/dist/storage/foreign-key-transaction.js +39 -0
  482. package/dist/storage/immutable-input.js +45 -0
  483. package/dist/storage/import-guard.js +102 -0
  484. package/dist/storage/native-cleanup.js +52 -0
  485. package/dist/storage/paths.js +17 -4
  486. package/dist/storage/projection-lock.js +73 -0
  487. package/dist/storage/work-references.js +23 -0
  488. package/dist/storage/writer-contract.js +89 -0
  489. package/dist/storage/writer-migration.js +85 -0
  490. package/package.json +43 -13
  491. package/tools/create-canon-release.mjs +33 -0
  492. package/tools/produce-hybrid-release.mjs +41 -0
  493. package/tools/repair-paused-run-status.mjs +84 -0
@@ -0,0 +1,258 @@
1
+ import path from "node:path";
2
+ import { AppError } from "../shared/errors.js";
3
+ import { assertMemoryOrdinaryConfigurationCoverage, assertMemoryOrdinaryConfigurationOutputs } from "./memory-ordinary-defaults.js";
4
+ import { hybridDigest } from "./hybrid-contracts.js";
5
+ import { runtimeHarness } from "./execution-policy.js";
6
+ import { readFlowRunExecutionBundle, assertPreparedRunBundleSqlAuthority } from "./runs.js";
7
+ import { requireProjectByRoot } from "./projects.js";
8
+ import { resolveProjectRoot } from "../storage/paths.js";
9
+ import { PreparedDescriptorStageCoordinator, readDescriptorStageInput } from "./descriptor-stage-coordinator.js";
10
+ import { readDescriptorRootWork } from "./descriptor-root-work.js";
11
+ import { stageGraphScope } from "./stage-work-graph.js";
12
+ import { PreparedMemoryResultBinding } from "./memory-result-binding.js";
13
+ import { PreparedMemoryStageResult, memorySourceKey } from "./memory-stage-results.js";
14
+ import { captureMemoryPreflightSources } from "./memory-preflight-handler.js";
15
+ import { registerMemoryComposition, selectMemoryCompositionRegistration } from "./memory-composition-registration.js";
16
+ import { PreparedMemoryBaselinePreservation } from "./memory-baseline-preservation.js";
17
+ import { PreparedDescriptorStageStart } from "./descriptor-stage-start.js";
18
+ import { PreparedDescriptorStageSettlement } from "./descriptor-stage-settlement.js";
19
+ import { PreparedMemoryCompositionAcceptance } from "./memory-composition-acceptance.js";
20
+ import { readAcceptedStageData } from "./stage-report-renderer.js";
21
+ import { ObservedMemorySources } from "./memory-source-observations.js";
22
+ import { PreparedCheckEvidence } from "./code-checks.js";
23
+ function refuse(reason) {
24
+ throw new AppError("memory_compose_handler_invalid", "Memory composition lacks retained scope, plan or output custody", 2, { reason, effect: "no_effect" });
25
+ }
26
+ function selected(context, input) {
27
+ if (!(input.bytes instanceof Uint8Array) || input.bytes.length > 1024 * 1024)
28
+ refuse("invalid_input_bytes");
29
+ const bundle = readFlowRunExecutionBundle(context, input);
30
+ if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.descriptor.successor("discover", "accepted") !== "compose"
31
+ || bundle.descriptor.successor("compose", "accepted") !== "verify")
32
+ refuse("registered_memory_bundle_required");
33
+ const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId, stage: "compose" };
34
+ const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), index = JSON.parse(run.index_json);
35
+ return { bundle, scope, run, accepted: index.stage_runs.find((stage) => stage.stage === "compose")?.status === "done" };
36
+ }
37
+ /** SQL-only physical binding proof; allocation/prompt custody is checked
38
+ * separately. No new Session, hook claim or provider invocation is created.
39
+ */
40
+ function coordinatorSession(context, scope, bundle, workId) {
41
+ const rows = context.db.all("SELECT ws.id,ws.session_id,ws.hook_event_id,ws.prompt_path,ws.result_path,s.harness,s.provider_session_id FROM work_sessions ws JOIN sessions s ON s.session_id=ws.session_id AND s.project_id=? WHERE ws.work_id=? AND ws.status='running' AND s.run_id=? AND s.current_stage=? AND s.status='active' LIMIT 2", [scope.projectId, workId, scope.runId, scope.stage]);
42
+ if (rows.length !== 1)
43
+ refuse("active_coordinator_session_required");
44
+ const session = rows[0], route = bundle.execution.stage(scope.stage);
45
+ const input = readDescriptorStageInput(context, scope, bundle), directory = bundle.descriptor.stage(scope.stage).directory;
46
+ if (session.prompt_path !== path.join(input.runRoot, directory, "coordinator-prompt.md")
47
+ || session.result_path !== path.join(input.runRoot, directory, "result-input.json"))
48
+ refuse("coordinator_packet_link_changed");
49
+ if (session.harness !== runtimeHarness(route.profile)
50
+ || !context.db.get("SELECT 1 FROM hook_events WHERE project_id=? AND event_key=? AND session_id=? AND harness=? AND provider_session_id=? AND status='claimed' AND event_name='PreToolUse'", [scope.projectId, session.hook_event_id, session.session_id, session.harness, session.provider_session_id]))
51
+ refuse("coordinator_start_custody_missing");
52
+ const bindings = context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type='stage.coordinator_binding' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.scope.stage')=? AND json_extract(payload_json,'$.work_session_id')=? LIMIT 33", [scope.projectId, scope.runId, scope.stage, session.id]);
53
+ if (!bindings.length || bindings.length > 32 || bindings.some(row => Buffer.byteLength(row.payload_json) > 32768))
54
+ refuse("physical_binding_missing");
55
+ const binding = JSON.parse(bindings[0].payload_json);
56
+ if (bindings.some(row => hybridDigest(JSON.parse(row.payload_json)) !== hybridDigest(binding))
57
+ || binding.work_id !== workId || binding.session_id !== session.session_id || binding.harness !== session.harness || binding.provider_session_id !== session.provider_session_id
58
+ || binding.execution_sha256 !== bundle.execution.sha256 || binding.profile_id !== route.profile.id || binding.profile_sha256 !== hybridDigest(route.profile)
59
+ || binding.session_mode !== route.session_mode || hybridDigest(binding.scope) !== hybridDigest({ ...stageGraphScope(context, scope.projectId, scope.runId, scope.stage), stage: scope.stage }))
60
+ refuse("physical_binding_changed");
61
+ return hybridDigest({ session, binding });
62
+ }
63
+ /** Actual registration path for the composition handler, awaiting complete
64
+ * memory-flow admission. Registers the immutable blueprint before workers run;
65
+ * it is NOT final composition acceptance or proof of produced artifacts.
66
+ */
67
+ export function registerMemoryCompositionFromStage(context, input) {
68
+ if (!(input.bytes instanceof Uint8Array) || !input.bytes.length || input.bytes.length > 1024 * 1024)
69
+ refuse("invalid_plan_bytes");
70
+ const { bundle, scope, accepted } = selected(context, input);
71
+ if (accepted)
72
+ refuse("use_accepted_finish_replay");
73
+ const coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage: "compose" });
74
+ const allocated = context.db.readSnapshot(() => {
75
+ coordinator.assertAllocatedCustody(context);
76
+ const root = readDescriptorRootWork(context, scope, bundle);
77
+ return { workId: root.workId, physical: coordinatorSession(context, scope, bundle, root.workId) };
78
+ });
79
+ const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle,
80
+ sources: captureMemoryPreflightSources(context, bundle, input.bytes) });
81
+ let composition;
82
+ try {
83
+ composition = PreparedMemoryStageResult.prepare(input.bytes, bundle.descriptor, binding.binding());
84
+ }
85
+ catch (error) {
86
+ // Only proposal validation is correctable here: no registration writer has
87
+ // run. Source/coordinator custody failures and registration conflicts remain
88
+ // outside this boundary and cannot authorize another authoring attempt.
89
+ if (error instanceof AppError && error.code === "memory_stage_result_invalid"
90
+ && error.details.phase === "prepare" && error.details.effect === "no_effect")
91
+ error.details.recoverable = true;
92
+ throw error;
93
+ }
94
+ const ordinaryDefaults = readDescriptorStageInput(context, scope, bundle).input.ordinary_defaults;
95
+ if (ordinaryDefaults) {
96
+ assertMemoryOrdinaryConfigurationCoverage(composition.value(), ordinaryDefaults);
97
+ if (ordinaryDefaults.missing.length && !context.db.get("SELECT 1 FROM audit_events WHERE project_id=? AND event_type='flow_run.stage_resumed' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.stage')='compose' LIMIT 1", [scope.projectId, scope.runId])) {
98
+ throw new AppError("memory_stage_result_invalid", "Resolve the missing ordinary configuration choice through the existing compose pause/answer path before registering Work", 2, { phase: "prepare", effect: "no_effect", recoverable: true, reason: "ordinary_configuration_choice_required", missing: ordinaryDefaults.missing });
99
+ }
100
+ }
101
+ binding.revalidate(context);
102
+ return registerMemoryComposition(context, { parentWorkId: allocated.workId, requestKey: input.requestKey, composition,
103
+ binding: { runId: input.runId, inputSha256: binding.binding().inputSha256, executionSha256: bundle.execution.sha256 } }, writer => {
104
+ binding.assertCustody(writer);
105
+ coordinator.assertAllocatedCustody(writer);
106
+ if (coordinatorSession(writer, scope, bundle, allocated.workId) !== allocated.physical)
107
+ refuse("coordinator_changed");
108
+ });
109
+ }
110
+ /** Unregistered until all six memory handlers are complete. Entry consumes
111
+ * accepted discovery/preflight; it does not create a second RUN or dispatch.
112
+ */
113
+ export function startMemoryComposition(context, input) {
114
+ const { bundle, scope, accepted } = selected(context, input);
115
+ if (accepted)
116
+ refuse("use_accepted_finish_replay");
117
+ const preservation = PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
118
+ const inherited = context.db.readSnapshot(() => ({ discovery: readAcceptedStageData(context, { ...scope, stage: "discover" }), preflight: readAcceptedStageData(context, { ...scope, stage: "preflight" }) }));
119
+ const preflight = JSON.parse(inherited.preflight.bytes.toString("utf8")), discovery = JSON.parse(inherited.discovery.bytes.toString("utf8"));
120
+ if (preflight.schema_id !== "dd-flow/mb-init-preflight-result@1" || preflight.run_id !== input.runId || preflight.outcome !== "accepted"
121
+ || discovery.schema_id !== "dd-flow/mb-init-discover-result@1"
122
+ || discovery.run_id !== input.runId || discovery.outcome !== "accepted")
123
+ refuse("accepted_discovery_and_baseline_required");
124
+ const fence = (writer) => {
125
+ preservation.assertCustody(writer);
126
+ if (readAcceptedStageData(writer, { ...scope, stage: "discover" }).authority_sha256 !== inherited.discovery.authority_sha256
127
+ || readAcceptedStageData(writer, { ...scope, stage: "preflight" }).authority_sha256 !== inherited.preflight.authority_sha256)
128
+ refuse("inherited_custody_changed");
129
+ };
130
+ const start = PreparedDescriptorStageStart.prepare(context, { ...input, stage: "compose" });
131
+ preservation.revalidate(context);
132
+ const stage = start.apply(context, fence), coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage: "compose" });
133
+ preservation.revalidate(context);
134
+ return { ...stage, ...coordinator.apply(context, fence) };
135
+ }
136
+ /** Agent references are selectors, not permissions. Supplement independent
137
+ * baseline evidence only with current outputs admitted by completed Work.
138
+ */
139
+ export function captureMemoryCompositionSources(context, bundle, runRoot, bytes, outputs, checks, proposalSha256) {
140
+ let value;
141
+ try {
142
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
143
+ }
144
+ catch {
145
+ refuse("invalid_result_json");
146
+ }
147
+ const pending = [{ value, role: "source" }], hashes = outputs.outputHashes(), historical = outputs.historicalEvidence();
148
+ let count = 0;
149
+ const rejectSelectedReference = (reason, root, path, sha256) => {
150
+ if (proposalSha256 === undefined)
151
+ refuse(reason);
152
+ throw new AppError("memory_compose_handler_invalid", "Correct the proposed evidence reference to the selected bytes below, or omit the unsupported citation. Do not rerun settled checks or change the accepted output", 2, { reason, phase: "prepare", effect: "no_effect", recoverable: true, result_sha256: proposalSha256, selected_reference: { root, path, sha256 } });
153
+ };
154
+ const executionScope = bundle.execution.snapshot().scope;
155
+ const sharedProjectWorkspace = resolveProjectRoot(executionScope.projectRoot) === resolveProjectRoot(executionScope.workspace);
156
+ const workResults = new Map(outputs.resultEvidence().map(ref => [memorySourceKey(ref.root, ref.path), ref.sha256])), resultLocations = new Map();
157
+ if (checks !== undefined) {
158
+ if (!(checks instanceof PreparedCheckEvidence))
159
+ refuse("prepared_checks_required");
160
+ const scope = bundle.execution.snapshot().scope;
161
+ checks.assertOwner({ projectId: requireProjectByRoot(context, scope.projectRoot).id, runId: bundle.manifest.run_id });
162
+ checks.assertCustody(context);
163
+ for (const ref of checks.sourceReferences()) {
164
+ hashes.set(memorySourceKey(ref.root, ref.path), ref.sha256);
165
+ resultLocations.set(memorySourceKey(ref.root, ref.path), { root: ref.root, path: ref.path });
166
+ }
167
+ }
168
+ while (pending.length) {
169
+ if (++count > 100000)
170
+ refuse("result_tree_exceeds_bound");
171
+ const { value: node, role } = pending.pop();
172
+ if (Array.isArray(node)) {
173
+ for (const child of node)
174
+ pending.push({ value: child, role });
175
+ continue;
176
+ }
177
+ if (!node || typeof node !== "object")
178
+ continue;
179
+ const record = node;
180
+ if (typeof record.root === "string" && typeof record.path === "string" && typeof record.sha256 === "string") {
181
+ // Inherited blueprint evidence describes the prior input, not today's
182
+ // artifact bytes. Its prepared original owner retains source custody.
183
+ const inherited = role === "evidence" && historical.has(`${memorySourceKey(record.root, record.path)}\0${record.sha256}`);
184
+ const resultSha = role === "evidence" ? workResults.get(memorySourceKey(record.root, record.path)) : undefined;
185
+ if (resultSha !== undefined) {
186
+ if (record.sha256 !== resultSha)
187
+ rejectSelectedReference("unsettled_work_result_reference", record.root, record.path, resultSha);
188
+ resultLocations.set(memorySourceKey(record.root, record.path), { root: record.root, path: record.path });
189
+ }
190
+ const key = memorySourceKey(record.root, record.path);
191
+ const expected = hashes.get(key) ?? (sharedProjectWorkspace && record.root === "project"
192
+ && ["evidence", "artifacts"].includes(role) ? hashes.get(memorySourceKey("workspace", record.path)) : undefined);
193
+ if (expected !== undefined && !inherited) {
194
+ if (record.sha256 !== expected)
195
+ rejectSelectedReference("unsettled_output_reference", record.root, record.path, expected);
196
+ hashes.set(key, expected);
197
+ resultLocations.set(key, { root: record.root, path: record.path });
198
+ }
199
+ if (expected !== undefined || inherited || resultSha !== undefined) {
200
+ delete record.root;
201
+ delete record.path;
202
+ delete record.sha256;
203
+ }
204
+ }
205
+ for (const [key, child] of Object.entries(record))
206
+ pending.push({ value: child, role: key === "evidence" || key === "artifacts" ? key : role });
207
+ }
208
+ // Keep evidence/artifact roles for the shared collector; settled child output
209
+ // references already have their independent output owner above.
210
+ const observedBaseline = captureMemoryPreflightSources(context, bundle, Buffer.from(JSON.stringify(value))), locations = new Map();
211
+ for (const key of observedBaseline.hashes().keys()) {
212
+ const [root, logical] = key.split("\0");
213
+ locations.set(key, { root: root, path: logical });
214
+ }
215
+ for (const location of outputs.outputLocations())
216
+ locations.set(memorySourceKey(location.root, location.path), location);
217
+ for (const [key, location] of resultLocations)
218
+ locations.set(key, location);
219
+ const scope = bundle.execution.snapshot().scope, observations = ObservedMemorySources.capture({ project: scope.projectRoot, workspace: scope.workspace,
220
+ canon: path.join(scope.workspace, ".memory-bank"), run: runRoot }, [...locations.values()]);
221
+ const actual = observations.hashes();
222
+ for (const [key, expected] of [...observedBaseline.hashes(), ...hashes, ...[...workResults].filter(([key]) => resultLocations.has(key))])
223
+ if (actual.get(key) !== expected)
224
+ refuse("source_changed_during_final_preparation");
225
+ return observations;
226
+ }
227
+ /** Final acceptance keeps the registration blueprint immutable. Fresh/replay
228
+ * RUN/input/coordinator authority is selected independently; registered child
229
+ * outputs and their current bytes are rechecked before and within settlement.
230
+ * Semantic quality remains the following VERIFY and independent REVIEW gates.
231
+ */
232
+ export function finishMemoryComposition(context, input) {
233
+ const { bundle, scope, run, accepted } = selected(context, input), root = readDescriptorRootWork(context, scope, bundle);
234
+ if (!input.bytes.length)
235
+ refuse("invalid_result_bytes");
236
+ const registration = selectMemoryCompositionRegistration(context, { ...stageGraphScope(context, scope.projectId, scope.runId, scope.stage), stage: "compose", parent_work_id: root.workId });
237
+ const registrationScope = registration.scope;
238
+ const blueprintBinding = PreparedMemoryResultBinding.prepareRegisteredComposition(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle,
239
+ registrationScope, acceptedReplay: accepted });
240
+ const outputs = PreparedMemoryCompositionAcceptance.prepare(context, { scope: registrationScope, flow: bundle.descriptor, engine: bundle.engine(), binding: blueprintBinding.binding() });
241
+ const sources = captureMemoryCompositionSources(context, bundle, run.run_root ?? run.run_dir, input.bytes, outputs);
242
+ const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle, sources, acceptedReplay: accepted, historicalEvidence: outputs.historicalEvidence() });
243
+ const replay = binding.acceptedBytes();
244
+ if (replay && !replay.equals(input.bytes))
245
+ refuse("accepted_result_changed");
246
+ const result = PreparedMemoryStageResult.prepare(input.bytes, bundle.descriptor, binding.binding());
247
+ outputs.assertResult(result);
248
+ const ordinaryDefaults = readDescriptorStageInput(context, scope, bundle, true, accepted).input.ordinary_defaults;
249
+ if (ordinaryDefaults && !replay) {
250
+ const selected = bundle.execution.snapshot().scope;
251
+ assertMemoryOrdinaryConfigurationOutputs(context, selected.workspace, ordinaryDefaults, result.value().units.flatMap(unit => unit.artifacts), { requestId: selected.requestId, projectRoot: selected.projectRoot, workspaceRoot: selected.workspace });
252
+ }
253
+ const settlement = PreparedDescriptorStageSettlement.prepare(context, { ...input, stage: "compose", bytes: result.bytes() });
254
+ blueprintBinding.revalidate(context);
255
+ binding.revalidate(context);
256
+ outputs.revalidate(context);
257
+ return settlement.apply(context, writer => { blueprintBinding.assertCustody(writer); binding.assertCustody(writer); outputs.assertCustody(writer); outputs.assertResult(result); });
258
+ }
@@ -0,0 +1,199 @@
1
+ import path from "node:path";
2
+ import { createHash } from "node:crypto";
3
+ import { AppError } from "../shared/errors.js";
4
+ import { hybridDigest } from "./hybrid-contracts.js";
5
+ import { runtimeHarness } from "./execution-policy.js";
6
+ import { PreparedMemoryStageResult, memorySourceKey } from "./memory-stage-results.js";
7
+ import { ObservedMemorySources } from "./memory-source-observations.js";
8
+ import { readWorkBatchCustody } from "./work-registry.js";
9
+ import { readMemoryCompositionRegistration, readRegisteredMemoryComposition } from "./memory-composition-registration.js";
10
+ import { validateMemoryCompositionWorkResult } from "./memory-composition-work-results.js";
11
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
12
+ function refuse(reason) {
13
+ throw new AppError("memory_composition_acceptance_invalid", "Composition lacks registered, settled and current output custody", 2, { reason, effect: "no_effect" });
14
+ }
15
+ function object(bytes, reason) {
16
+ try {
17
+ const value = JSON.parse(bytes);
18
+ if (!value || typeof value !== "object" || Array.isArray(value))
19
+ refuse(reason);
20
+ return value;
21
+ }
22
+ catch {
23
+ return refuse(reason);
24
+ }
25
+ }
26
+ function roots(context, scope) {
27
+ const row = context.db.get("SELECT workspace_root,run_root,run_dir FROM runs WHERE project_id=? AND id=?", [scope.project_id, scope.run_id]);
28
+ if (!row || !path.isAbsolute(row.workspace_root) || !path.isAbsolute(row.run_root ?? row.run_dir))
29
+ refuse("assigned_roots_missing");
30
+ return { workspace: row.workspace_root, run: row.run_root ?? row.run_dir };
31
+ }
32
+ /** SQL-only selection. Neither a completed status nor a mutable result file
33
+ * can substitute for the output-preparation receipt committed by the memory
34
+ * Work writer together with its result and WorkSession.
35
+ */
36
+ function settled(context, scope, workId, harness, registrationSha256, assigned) {
37
+ const allocation = readWorkBatchCustody(context, workId);
38
+ if (hybridDigest(allocation.scope) !== hybridDigest(scope))
39
+ refuse("foreign_work_allocation");
40
+ const work = context.db.get("SELECT status,result,result_schema FROM works WHERE project_id=? AND run_id=? AND work_id=?", [scope.project_id, scope.run_id, workId]);
41
+ if (!work || work.status !== "completed" || work.result_schema !== "dd-flow/memory-composition-work-result@1"
42
+ || typeof work.result !== "string" || !work.result.length || Buffer.byteLength(work.result) > 1024 * 1024)
43
+ refuse("work_not_settled");
44
+ const rows = context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type='memory.composition_work_settlement' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.work_id')=? LIMIT 2", [scope.project_id, scope.run_id, workId]);
45
+ if (rows.length !== 1 || Buffer.byteLength(rows[0].payload_json) > 32768)
46
+ refuse("work_settlement_receipt_missing");
47
+ const receipt = object(rows[0].payload_json, "invalid_work_settlement_receipt");
48
+ const links = context.db.all("SELECT id,session_id,status,result_path,result_receipt_json FROM work_sessions WHERE work_id=? AND status='completed' LIMIT 2", [workId]);
49
+ if (links.length !== 1 || !links[0].result_receipt_json || Buffer.byteLength(links[0].result_receipt_json) > 32768
50
+ || context.db.get("SELECT 1 FROM work_sessions WHERE work_id=? AND status='running'", [workId]))
51
+ refuse("completed_work_session_missing");
52
+ const link = links[0], publication = object(link.result_receipt_json, "invalid_work_result_receipt");
53
+ const session = context.db.get("SELECT provider_session_id FROM sessions WHERE project_id=? AND session_id=? AND run_id=? AND harness=?", [scope.project_id, link.session_id, scope.run_id, harness]);
54
+ if (!session)
55
+ refuse("work_session_identity_changed");
56
+ const bytes = Buffer.from(work.result), resultSha256 = hash(bytes);
57
+ if (hybridDigest(receipt) !== hybridDigest({ schema_id: "dd-flow/memory-composition-work-settlement@1", run_id: scope.run_id, work_id: workId,
58
+ work_session_id: link.id, session_id: link.session_id, harness, provider_session_id: session.provider_session_id,
59
+ scope, registration_sha256: registrationSha256, allocation_sha256: hybridDigest(allocation), roots: assigned, result_sha256: resultSha256 }))
60
+ refuse("work_settlement_custody_changed");
61
+ if (publication.work_id !== workId || publication.work_session_id !== link.id || publication.status !== "completed" || publication.result_sha256 !== resultSha256
62
+ || publication.previous_sha256 !== null && (typeof publication.previous_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(publication.previous_sha256)))
63
+ refuse("work_result_receipt_changed");
64
+ if (link.result_path !== path.join(assigned.run, "works", workId, "result.json"))
65
+ refuse("work_result_path_changed");
66
+ return { bytes, authority: hybridDigest({ receipt, publication }), assigned,
67
+ evidence: { root: "run", path: `works/${workId}/result.json`, sha256: resultSha256 } };
68
+ }
69
+ /** Final compose output custody, not semantic verification/review/finish.
70
+ * The blueprint is restored from registration; it is never rewritten using
71
+ * the final result. Historical worker bytes are schema-checked without
72
+ * asserting that a dependent assembly left their artifacts untouched.
73
+ */
74
+ export class PreparedMemoryCompositionAcceptance {
75
+ #scope;
76
+ #original;
77
+ #registrationSha256;
78
+ #workers;
79
+ #artifacts;
80
+ #observed;
81
+ constructor(scope, original, registrationSha256, workers, artifacts, observed) {
82
+ this.#scope = structuredClone(scope);
83
+ this.#original = original;
84
+ this.#registrationSha256 = registrationSha256;
85
+ this.#workers = workers;
86
+ this.#artifacts = artifacts;
87
+ this.#observed = observed;
88
+ Object.freeze(this);
89
+ }
90
+ static prepare(context, input) {
91
+ const registration = readMemoryCompositionRegistration(context, input.scope);
92
+ const original = readRegisteredMemoryComposition(context, input), value = original.value();
93
+ const works = value.details.works;
94
+ const batch = original.compositionBatch({ runId: input.scope.run_id, inputSha256: input.binding.inputSha256, executionSha256: input.binding.executionSha256, resultSchema: "dd-flow/memory-composition-work-result@1" });
95
+ const routes = new Map(original.compositionRoutes().map(route => [route.key, runtimeHarness(route.execution.worker)]));
96
+ const registrationSha256 = hybridDigest(registration), assigned = roots(context, input.scope);
97
+ const selected = context.db.readSnapshot(() => works.map(work => {
98
+ const id = registration.work_ids[work.key], harness = routes.get(work.key);
99
+ return { key: work.key, id, harness, ...settled(context, input.scope, id, harness, registrationSha256, assigned) };
100
+ }));
101
+ const outputs = new Map(selected.map(item => [item.key, validateMemoryCompositionWorkResult(item.bytes, input.engine, {
102
+ runId: input.scope.run_id, inputSha256: input.binding.inputSha256, executionSha256: input.binding.executionSha256,
103
+ workId: item.id, workKey: item.key, composition: original, compositionSha256: original.sha256
104
+ })]));
105
+ // The admitted graph has ordered all overlapping writers. Use its real
106
+ // dependencies, not array order, wall-clock timestamps or agent claims.
107
+ const remaining = new Map(works.map(work => [work.key, work.depends_on.length])), children = new Map();
108
+ for (const work of works)
109
+ for (const dependency of work.depends_on)
110
+ children.set(dependency, [...(children.get(dependency) ?? []), work.key]);
111
+ const ready = works.filter(work => !work.depends_on.length).map(work => work.key);
112
+ const current = new Map(), aliases = new Map();
113
+ for (let index = 0; index < ready.length; index++) {
114
+ const key = ready[index], output = outputs.get(key), emitted = new Map();
115
+ for (const unit of output.units)
116
+ for (const artifact of unit.artifacts) {
117
+ const identity = memorySourceKey(artifact.root, artifact.path), alias = memorySourceKey(artifact.root, artifact.path.normalize("NFC").toLowerCase());
118
+ if (aliases.has(alias) && aliases.get(alias) !== identity)
119
+ refuse("aliased_output_paths");
120
+ aliases.set(alias, identity);
121
+ const record = emitted.get(identity) ?? { artifact, units: new Set() };
122
+ record.units.add(unit.id);
123
+ emitted.set(identity, record);
124
+ }
125
+ for (const [identity, record] of emitted)
126
+ current.set(identity, record);
127
+ for (const child of children.get(key) ?? []) {
128
+ const count = remaining.get(child) - 1;
129
+ remaining.set(child, count);
130
+ if (!count)
131
+ ready.push(child);
132
+ }
133
+ }
134
+ if (ready.length !== batch.works.length)
135
+ refuse("registered_graph_changed");
136
+ const artifacts = new Map();
137
+ for (const record of current.values())
138
+ for (const id of record.units)
139
+ artifacts.set(id, [...(artifacts.get(id) ?? []), record.artifact]);
140
+ const observed = ObservedMemorySources.capture(assigned, [...current.values()].map(record => ({ root: record.artifact.root, path: record.artifact.path })));
141
+ const hashes = observed.hashes();
142
+ if ([...current.values()].some(record => hashes.get(memorySourceKey(record.artifact.root, record.artifact.path)) !== record.artifact.sha256))
143
+ refuse("current_output_bytes_changed");
144
+ const prepared = new PreparedMemoryCompositionAcceptance(input.scope, original, registrationSha256, selected.map(item => ({ id: item.id, harness: item.harness, authority: item.authority, evidence: item.evidence })), artifacts, observed);
145
+ prepared.assertCustody(context);
146
+ return prepared;
147
+ }
148
+ /** Only these independently settled output locations may supplement baseline
149
+ * evidence in the final result binding. The returned map is a defensive copy.
150
+ */
151
+ outputHashes() { return this.#observed.hashes(); }
152
+ historicalEvidence() {
153
+ const units = this.#original.value().units;
154
+ return new Set(units.flatMap(unit => unit.evidence.map(ref => `${memorySourceKey(ref.root, ref.path)}\0${ref.sha256}`)));
155
+ }
156
+ resultEvidence() { return this.#workers.map(worker => structuredClone(worker.evidence)); }
157
+ outputLocations() {
158
+ const selected = new Map();
159
+ for (const artifacts of this.#artifacts.values())
160
+ for (const artifact of artifacts)
161
+ selected.set(memorySourceKey(artifact.root, artifact.path), { root: artifact.root, path: artifact.path });
162
+ return [...selected.values()];
163
+ }
164
+ assertResult(result) {
165
+ if (!(result instanceof PreparedMemoryStageResult))
166
+ refuse("prepared_result_required");
167
+ const original = this.#original.value(), final = result.value(), value = final;
168
+ const identity = ["schema_id", "run_id", "input_sha256", "predecessors"];
169
+ if (hybridDigest(identity.map(field => original[field])) !== hybridDigest(identity.map(field => final[field])))
170
+ refuse("foreign_result_identity");
171
+ if (value.stage !== "compose" || value.outcome !== "accepted" || hybridDigest(value.details) !== hybridDigest(original.details)
172
+ || value.findings.some(finding => finding.severity !== "minor" && finding.status !== "resolved"))
173
+ refuse("composition_not_accepted_or_plan_changed");
174
+ const inventory = new Map(original.units.map(unit => [unit.id, unit]));
175
+ if (value.units.length !== inventory.size || new Set(value.units.map(unit => unit.id)).size !== inventory.size)
176
+ refuse("changed_unit_coverage");
177
+ for (const unit of value.units) {
178
+ const initial = inventory.get(unit.id);
179
+ if (!initial || unit.aspect !== initial.aspect || unit.applicability !== initial.applicability || unit.applicability === "unknown"
180
+ || unit.outcome !== (unit.applicability === "not-applicable" ? "not-applicable" : "accepted"))
181
+ refuse("unaccepted_unit_or_changed_assignment");
182
+ const expected = this.#artifacts.get(unit.id) ?? [], identities = new Set(unit.artifacts.map(artifact => hybridDigest(artifact)));
183
+ if (unit.applicability !== "not-applicable" && !expected.length || identities.size !== expected.length
184
+ || expected.some(artifact => !identities.has(hybridDigest(artifact))))
185
+ refuse("unit_outputs_not_settled");
186
+ }
187
+ }
188
+ assertCustody(context) {
189
+ context.db.readSnapshot(() => {
190
+ if (hybridDigest(readMemoryCompositionRegistration(context, this.#scope)) !== this.#registrationSha256)
191
+ refuse("registration_changed");
192
+ const assigned = roots(context, this.#scope);
193
+ for (const worker of this.#workers)
194
+ if (settled(context, this.#scope, worker.id, worker.harness, this.#registrationSha256, assigned).authority !== worker.authority)
195
+ refuse("work_settlement_changed");
196
+ });
197
+ }
198
+ revalidate(context) { this.#observed.revalidate(); this.assertCustody(context); }
199
+ }
@@ -0,0 +1,134 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ import { localEnvironmentAllowed } from "./workspace-files.js";
3
+ function refuse(reason) {
4
+ throw new AppError("memory_stage_result_invalid", "Memory composition graph cannot be dispatched", 2, { reason, phase: "prepare", effect: "no_effect" });
5
+ }
6
+ // Portable scopes must remain safe on case-insensitive/normalizing filesystems.
7
+ const physicalPath = (value) => value.normalize("NFC").toLowerCase();
8
+ const projectConfigurationPaths = [".memory-bank/dd-flow/project-execution.json", ".memory-bank/dd-flow/project-workspace.json"];
9
+ /** Exact project-owned defaults, never directory or case aliases of canon. */
10
+ export function memoryProjectConfigurationPath(value) { return projectConfigurationPaths.includes(value); }
11
+ /** Check both assigned directories and their concrete output descendants. */
12
+ export function memoryCompositionOutputAllowed(value) {
13
+ if (overlaps(value, ".memory-bank/dd-flow") && !memoryProjectConfigurationPath(value))
14
+ return false;
15
+ return value.split("/").every(part => localEnvironmentAllowed(part)
16
+ && ![".git", "node_modules", ".dd-flow"].includes(physicalPath(part)));
17
+ }
18
+ function overlaps(left, right) {
19
+ const a = physicalPath(left), b = physicalPath(right);
20
+ return a === "." || b === "." || a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`);
21
+ }
22
+ /** Called only after strict result-schema and contained-path admission. These
23
+ * semantic graph checks precede Work allocation, not merely worker dispatch.
24
+ * They do not grant filesystem access or replace frozen profile/Work custody.
25
+ */
26
+ export function validateMemoryCompositionGraph(value) {
27
+ const result = value;
28
+ const unresolved = result.units.findIndex(unit => unit.applicability === "unknown");
29
+ if (unresolved !== -1)
30
+ throw new AppError("memory_stage_result_invalid", "Resolve the composition target before assigning Work; missing facts may remain explicit in its content", 2, { reason: "unresolved_composition_applicability", phase: "prepare", effect: "no_effect", unit_id: result.units[unresolved].id,
31
+ pointer: `/units/${unresolved}/applicability`, hint: "Choose applicable for an intended document or compact shelf, or not-applicable with a reason and no assigned writer. Do not invent missing project facts." });
32
+ const works = result.details.works;
33
+ const byKey = new Map(works.map(work => [work.key, work]));
34
+ if (byKey.size !== works.length || new Set(works.map(work => physicalPath(work.key))).size !== works.length)
35
+ refuse("duplicate_composition_work");
36
+ for (const work of works) {
37
+ if (work.depends_on.some(key => !byKey.has(key)))
38
+ refuse("unknown_composition_dependency");
39
+ for (const scopes of [work.read_scopes, work.write_scopes]) {
40
+ if (new Set(scopes.map(scope => `${scope.root}\0${physicalPath(scope.path)}`)).size !== scopes.length)
41
+ refuse("duplicate_composition_scope");
42
+ }
43
+ for (const scope of work.write_scopes) {
44
+ if (scope.path === ".")
45
+ refuse("unbounded_composition_write");
46
+ if (scope.root === "workspace" && (scope.path !== ".memory-bank" && !scope.path.startsWith(".memory-bank/")))
47
+ refuse("foreign_composition_write");
48
+ // These exact files are project-owned defaults consumed by ordinary
49
+ // entry, not selected canon. Never grant their enclosing directory or
50
+ // case/normalization aliases; the installed prompt/schema pack is sealed.
51
+ const projectConfig = memoryProjectConfigurationPath(scope.path);
52
+ if (scope.root === "workspace" && !projectConfig && [".memory-bank/mbb", ".memory-bank/dd-flow"].some(canonical => overlaps(scope.path, canonical)))
53
+ refuse("canonical_composition_write");
54
+ // A contained semantic scope is not permission to alter credentials,
55
+ // repository metadata, installed dependencies or runtime state.
56
+ if (!memoryCompositionOutputAllowed(scope.path))
57
+ refuse("private_composition_write");
58
+ if (scope.root === "run" && ["execution-bundle", "run.json"].some(authority => overlaps(scope.path, authority)))
59
+ refuse("authority_composition_write");
60
+ // Mechanical RUN files and another Work's evidence are never semantic outputs.
61
+ if (scope.root === "run") {
62
+ const namespace = `memory-artifacts/compose/${work.key}`;
63
+ if (scope.path !== namespace && !scope.path.startsWith(`${namespace}/`))
64
+ refuse("foreign_composition_run_write");
65
+ }
66
+ }
67
+ }
68
+ // Iterative topological order avoids recursion on an agent-sized graph.
69
+ const remaining = new Map(works.map(work => [work.key, work.depends_on.length]));
70
+ const children = new Map();
71
+ for (const work of works)
72
+ for (const dependency of work.depends_on) {
73
+ const list = children.get(dependency) ?? [];
74
+ list.push(work.key);
75
+ children.set(dependency, list);
76
+ }
77
+ const ready = works.filter(work => !work.depends_on.length).map(work => work.key);
78
+ const positions = new Map(works.map((work, index) => [work.key, index]));
79
+ const ancestors = new Map();
80
+ const dependsOn = (work, dependency) => {
81
+ const position = positions.get(dependency);
82
+ return Boolean(ancestors.get(work)[position >>> 5] & (1 << (position & 31)));
83
+ };
84
+ for (let cursor = 0; cursor < ready.length; cursor++) {
85
+ const key = ready[cursor], work = byKey.get(key);
86
+ const inherited = new Uint32Array(Math.ceil(works.length / 32));
87
+ for (const dependency of work.depends_on) {
88
+ const position = positions.get(dependency);
89
+ inherited[position >>> 5] |= 1 << (position & 31);
90
+ const prior = ancestors.get(dependency);
91
+ for (let word = 0; word < prior.length; word++)
92
+ inherited[word] |= prior[word];
93
+ }
94
+ ancestors.set(key, inherited);
95
+ for (const child of children.get(key) ?? []) {
96
+ const count = remaining.get(child) - 1;
97
+ remaining.set(child, count);
98
+ if (!count)
99
+ ready.push(child);
100
+ }
101
+ }
102
+ if (ready.length !== works.length)
103
+ refuse("cyclic_composition_dependency");
104
+ const assemblies = works.filter(work => work.role === "index-assembly");
105
+ const declared = new Set(result.details.assembly_work_keys);
106
+ if (declared.size !== result.details.assembly_work_keys.length || declared.size !== assemblies.length
107
+ || assemblies.some(work => !declared.has(work.key)))
108
+ refuse("invalid_assembly_membership");
109
+ const applicable = new Set(result.units.filter(unit => unit.applicability !== "not-applicable").map(unit => unit.id));
110
+ for (const work of works)
111
+ if (work.unit_ids.some(id => !applicable.has(id)))
112
+ refuse("inapplicable_composition_work");
113
+ for (const unit of applicable) {
114
+ const authors = works.filter(work => work.unit_ids.includes(unit));
115
+ const writers = authors.filter(work => work.role === "writer");
116
+ const collectors = assemblies.filter(work => work.unit_ids.includes(unit));
117
+ if (!authors.length || !collectors.length)
118
+ refuse("incomplete_composition_coverage");
119
+ if (collectors.some(collector => writers.some(writer => !dependsOn(collector.key, writer.key))))
120
+ refuse("assembly_precedes_unit_writers");
121
+ }
122
+ for (let index = 0; index < works.length; index++) {
123
+ const left = works[index];
124
+ for (const right of works.slice(index + 1)) {
125
+ if (dependsOn(left.key, right.key) || dependsOn(right.key, left.key))
126
+ continue;
127
+ if (left.write_scopes.some(a => right.write_scopes.some(b => a.root === b.root && overlaps(a.path, b.path))))
128
+ refuse("unordered_composition_writers");
129
+ if (left.write_scopes.some(a => right.read_scopes.some(b => a.root === b.root && overlaps(a.path, b.path)))
130
+ || right.write_scopes.some(a => left.read_scopes.some(b => a.root === b.root && overlaps(a.path, b.path))))
131
+ refuse("unordered_composition_read_write");
132
+ }
133
+ }
134
+ }