@deksden-com/dd-flow-cli 0.9.0-beta.137 → 0.9.0-beta.139

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 (283) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +9 -0
  3. package/dist/build-info.json +6 -6
  4. package/dist/cli/argument-values.js +5 -5
  5. package/dist/cli/command-inputs.js +89 -20
  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 +240 -6
  15. package/dist/cli/input-preparation.js +54 -5
  16. package/dist/cli/memory-flow-admission.js +44 -0
  17. package/dist/cli/memory-init-invocation.js +78 -0
  18. package/dist/cli/memory-init.js +240 -0
  19. package/dist/cli/memory-storage-admission.js +53 -0
  20. package/dist/cli/models.js +39 -0
  21. package/dist/cli/native-hook-ingress.js +1 -1
  22. package/dist/cli/operator-profiles.js +61 -0
  23. package/dist/cli/output-options.js +35 -0
  24. package/dist/cli/response-file.js +71 -0
  25. package/dist/cli/run-cli.js +283 -160
  26. package/dist/cli/runtime-process.js +1 -1
  27. package/dist/cli/setup.js +149 -0
  28. package/dist/cli.js +56 -2
  29. package/dist/domain/stage-handler-identities.js +20 -0
  30. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  31. package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
  32. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +53 -22
  33. package/dist/harness-runtime/lib/dd-agy.mjs +16 -5
  34. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +12 -6
  35. package/dist/harness-runtime/lib/dd-codex.mjs +24 -12
  36. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
  37. package/dist/harness-runtime/lib/dd-droid.mjs +32 -9
  38. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +11 -3
  39. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +100 -15
  40. package/dist/harness-runtime/lib/dd-opencode.mjs +51 -20
  41. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +22 -10
  42. package/dist/harness-runtime/lib/dd-zcode.mjs +17 -4
  43. package/dist/harness-runtime/lib/delegation-instructions.d.mts +1 -0
  44. package/dist/harness-runtime/lib/delegation-instructions.mjs +16 -3
  45. package/dist/harness-runtime/lib/lease-renewal.mjs +2 -1
  46. package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
  47. package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
  48. package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
  49. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  50. package/dist/harness-runtime/lib/native-children.d.mts +2 -0
  51. package/dist/harness-runtime/lib/native-children.mjs +20 -1
  52. package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
  53. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  54. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  55. package/dist/harness-runtime/lib/opencode-plugin.mjs +32 -9
  56. package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
  57. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +13 -0
  58. package/dist/harness-runtime/lib/provider-overload-policy.mjs +138 -0
  59. package/dist/runtime/context.js +1 -1
  60. package/dist/schemas/discovery-result.schema.json +184 -0
  61. package/dist/schemas/execution-bundle.schema.json +205 -0
  62. package/dist/schemas/execution-settings.schema.json +162 -0
  63. package/dist/schemas/flow-descriptor.schema.json +54 -0
  64. package/dist/schemas/flow-run.schema.json +26 -0
  65. package/dist/schemas/harness-catalog.schema.json +80 -0
  66. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  67. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  68. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  69. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  70. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  71. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  72. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  73. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  74. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  75. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  76. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  77. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  78. package/dist/schemas/model-catalog.schema.json +153 -0
  79. package/dist/schemas/profile-settings.schema.json +122 -0
  80. package/dist/schemas/release-manifest.schema.json +291 -0
  81. package/dist/schemas/run-engine-binding.schema.json +1 -1
  82. package/dist/services/check-runner-evidence.js +51 -4
  83. package/dist/services/cli-operation-classifier.js +8 -47
  84. package/dist/services/cli-upgrade-allowlist.js +27 -0
  85. package/dist/services/code-checks.js +387 -34
  86. package/dist/services/controller-child-capacity.js +13 -0
  87. package/dist/services/controller-child-observer.js +18 -2
  88. package/dist/services/controller-execution.js +88 -0
  89. package/dist/services/controller-fanout.js +71 -12
  90. package/dist/services/dashboard.js +8 -2
  91. package/dist/services/descriptor-coordinator-session.js +35 -0
  92. package/dist/services/descriptor-root-work.js +53 -0
  93. package/dist/services/descriptor-run-settlement.js +105 -0
  94. package/dist/services/descriptor-run-start.js +449 -0
  95. package/dist/services/descriptor-stage-coordinator.js +197 -0
  96. package/dist/services/descriptor-stage-settlement.js +222 -0
  97. package/dist/services/descriptor-stage-start.js +139 -0
  98. package/dist/services/discovery/agy-discovery.js +2 -0
  99. package/dist/services/discovery/codex-discovery.js +2 -0
  100. package/dist/services/discovery/droid-discovery.js +2 -0
  101. package/dist/services/discovery/grok-discovery.js +2 -0
  102. package/dist/services/discovery/opencode-discovery.js +2 -0
  103. package/dist/services/discovery/static.js +31 -0
  104. package/dist/services/discovery/zcode-discovery.js +2 -0
  105. package/dist/services/engines.js +39 -22
  106. package/dist/services/eval-snapshots.js +83 -25
  107. package/dist/services/execution-bundles.js +263 -0
  108. package/dist/services/execution-policy.js +20 -16
  109. package/dist/services/executor-onboarding.js +56 -0
  110. package/dist/services/external-work-launch.js +93 -15
  111. package/dist/services/flow-catalog.js +21 -0
  112. package/dist/services/flow-descriptors.js +82 -0
  113. package/dist/services/frozen-engine.js +250 -0
  114. package/dist/services/generic-execution.js +164 -0
  115. package/dist/services/harness-adapter.js +28 -2
  116. package/dist/services/harness-discovery.js +29 -0
  117. package/dist/services/harness-doctor.js +75 -0
  118. package/dist/services/harness-probe-effects.js +51 -0
  119. package/dist/services/harness-version-probe.js +100 -0
  120. package/dist/services/hooks.js +24 -6
  121. package/dist/services/hybrid-contracts.js +483 -0
  122. package/dist/services/ids.js +29 -1
  123. package/dist/services/installation-lock.js +95 -0
  124. package/dist/services/installed-flow-source.js +183 -0
  125. package/dist/services/lifecycle-invocations.js +257 -78
  126. package/dist/services/managed-processes.js +31 -10
  127. package/dist/services/memory-accepted-composition.js +77 -0
  128. package/dist/services/memory-baseline-preservation.js +65 -0
  129. package/dist/services/memory-completed-correction-wave.js +320 -0
  130. package/dist/services/memory-compose-handler.js +258 -0
  131. package/dist/services/memory-composition-acceptance.js +199 -0
  132. package/dist/services/memory-composition-graph.js +134 -0
  133. package/dist/services/memory-composition-registration.js +146 -0
  134. package/dist/services/memory-composition-work-custody.js +151 -0
  135. package/dist/services/memory-composition-work-results.js +96 -0
  136. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  137. package/dist/services/memory-corrected-review-batch.js +30 -0
  138. package/dist/services/memory-corrected-review-findings.js +106 -0
  139. package/dist/services/memory-corrected-review-inputs.js +210 -0
  140. package/dist/services/memory-corrected-review-projection.js +78 -0
  141. package/dist/services/memory-corrected-review-receipt.js +170 -0
  142. package/dist/services/memory-corrected-review-registration.js +191 -0
  143. package/dist/services/memory-correction-check-receipt.js +219 -0
  144. package/dist/services/memory-correction-input-owner.js +6 -0
  145. package/dist/services/memory-discover-handler.js +104 -0
  146. package/dist/services/memory-finish-evidence.js +435 -0
  147. package/dist/services/memory-finish-handler.js +215 -0
  148. package/dist/services/memory-finish-integration.js +280 -0
  149. package/dist/services/memory-finish-readiness.js +122 -0
  150. package/dist/services/memory-git-integration.js +151 -0
  151. package/dist/services/memory-historical-corrected-review.js +206 -0
  152. package/dist/services/memory-historical-original-review.js +130 -0
  153. package/dist/services/memory-historical-repair-registration.js +99 -0
  154. package/dist/services/memory-historical-second-review.js +128 -0
  155. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  156. package/dist/services/memory-init-contexts.js +89 -0
  157. package/dist/services/memory-init-controller-start.js +84 -0
  158. package/dist/services/memory-init-engine-release.js +223 -0
  159. package/dist/services/memory-init-git-policy.js +136 -0
  160. package/dist/services/memory-init-lint-capability.js +185 -0
  161. package/dist/services/memory-init-native-capacity.js +296 -0
  162. package/dist/services/memory-init-preflight.js +330 -0
  163. package/dist/services/memory-init-project-bootstrap.js +599 -0
  164. package/dist/services/memory-init-request-candidate.js +157 -0
  165. package/dist/services/memory-init-request-input.js +66 -0
  166. package/dist/services/memory-init-resource-storage.js +125 -0
  167. package/dist/services/memory-init-run-allocation.js +81 -0
  168. package/dist/services/memory-init-run-bundle.js +98 -0
  169. package/dist/services/memory-init-start.js +181 -0
  170. package/dist/services/memory-init-startup-custody.js +80 -0
  171. package/dist/services/memory-init-startup-input.js +240 -0
  172. package/dist/services/memory-init-storage.js +81 -0
  173. package/dist/services/memory-init-stores.js +359 -0
  174. package/dist/services/memory-init-worktrunk-capability.js +178 -0
  175. package/dist/services/memory-layer-publication.js +611 -0
  176. package/dist/services/memory-layer.js +156 -0
  177. package/dist/services/memory-lint-config.js +85 -0
  178. package/dist/services/memory-native-review-copy.js +165 -0
  179. package/dist/services/memory-normal-flow-entry.js +75 -0
  180. package/dist/services/memory-ordinary-defaults.js +112 -0
  181. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  182. package/dist/services/memory-preflight-handler.js +259 -0
  183. package/dist/services/memory-repair-current-view.js +299 -0
  184. package/dist/services/memory-repair-document-delta.js +451 -0
  185. package/dist/services/memory-repair-history.js +491 -0
  186. package/dist/services/memory-repair-physical-binding.js +312 -0
  187. package/dist/services/memory-repair-publication-files.js +152 -0
  188. package/dist/services/memory-repair-publication-intent.js +27 -0
  189. package/dist/services/memory-repair-publication-plan.js +160 -0
  190. package/dist/services/memory-repair-publication-source.js +225 -0
  191. package/dist/services/memory-repair-publication.js +794 -0
  192. package/dist/services/memory-repair-registration.js +239 -0
  193. package/dist/services/memory-repair-work-baseline.js +413 -0
  194. package/dist/services/memory-repair-work-completion.js +97 -0
  195. package/dist/services/memory-repair-work-custody.js +73 -0
  196. package/dist/services/memory-repair-work-results.js +89 -0
  197. package/dist/services/memory-repair-workspace.js +252 -0
  198. package/dist/services/memory-repair-writer-copy.js +735 -0
  199. package/dist/services/memory-result-binding.js +173 -0
  200. package/dist/services/memory-retained-review-authority.js +129 -0
  201. package/dist/services/memory-retained-review-results.js +70 -0
  202. package/dist/services/memory-retained-second-baseline.js +102 -0
  203. package/dist/services/memory-retained-second-repairs.js +156 -0
  204. package/dist/services/memory-review-acceptance.js +214 -0
  205. package/dist/services/memory-review-correction-plan.js +171 -0
  206. package/dist/services/memory-review-handler.js +585 -0
  207. package/dist/services/memory-review-inputs.js +200 -0
  208. package/dist/services/memory-review-receipt.js +180 -0
  209. package/dist/services/memory-review-registration.js +108 -0
  210. package/dist/services/memory-review-work-custody.js +124 -0
  211. package/dist/services/memory-review-work-input.js +72 -0
  212. package/dist/services/memory-review-work-results.js +73 -0
  213. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  214. package/dist/services/memory-second-correction-plan.js +76 -0
  215. package/dist/services/memory-second-repair-baseline.js +91 -0
  216. package/dist/services/memory-second-repair-launch.js +614 -0
  217. package/dist/services/memory-second-repair-registration.js +88 -0
  218. package/dist/services/memory-second-repair-source.js +187 -0
  219. package/dist/services/memory-second-review-acceptance.js +115 -0
  220. package/dist/services/memory-source-observations.js +117 -0
  221. package/dist/services/memory-stage-dispatch.js +28 -0
  222. package/dist/services/memory-stage-results.js +199 -0
  223. package/dist/services/memory-verification-acceptance.js +135 -0
  224. package/dist/services/memory-verification-checks.js +252 -0
  225. package/dist/services/memory-verification-receipt.js +159 -0
  226. package/dist/services/memory-verify-handler.js +135 -0
  227. package/dist/services/memory-work-result-preparation.js +63 -0
  228. package/dist/services/merge-server.js +2 -4
  229. package/dist/services/model-catalog.js +109 -0
  230. package/dist/services/model-discovery.js +46 -0
  231. package/dist/services/operator-profiles.js +236 -0
  232. package/dist/services/projects.js +17 -2
  233. package/dist/services/{codex-capacity.js → provider-capacity.js} +34 -16
  234. package/dist/services/recovery-snapshot-database.js +417 -2
  235. package/dist/services/release-archive-producer.js +52 -0
  236. package/dist/services/release-archive.js +143 -0
  237. package/dist/services/release-cache.js +142 -0
  238. package/dist/services/release-compatibility.js +18 -0
  239. package/dist/services/release-download.js +67 -0
  240. package/dist/services/release-envelope.js +104 -0
  241. package/dist/services/release-manifest.js +45 -0
  242. package/dist/services/release-payload.js +114 -0
  243. package/dist/services/release-producer.js +63 -0
  244. package/dist/services/release-provenance.js +160 -0
  245. package/dist/services/release-registry.js +66 -0
  246. package/dist/services/release-source.js +194 -0
  247. package/dist/services/repair-intents.js +1 -1
  248. package/dist/services/review-copy.js +10 -2
  249. package/dist/services/run-control.js +80 -9
  250. package/dist/services/run-controller-adapter.js +1 -1
  251. package/dist/services/run-controller-capture.js +10 -3
  252. package/dist/services/run-controller-process.js +21 -0
  253. package/dist/services/run-controller-recovery.js +5 -5
  254. package/dist/services/run-controller-state.js +1 -1
  255. package/dist/services/run-controller.js +158 -64
  256. package/dist/services/run-recovery-guard.js +5 -3
  257. package/dist/services/run-recovery-runtime.js +3 -3
  258. package/dist/services/run-recovery.js +145 -5
  259. package/dist/services/run-start-custody.js +177 -0
  260. package/dist/services/runs.js +413 -30
  261. package/dist/services/setup.js +377 -0
  262. package/dist/services/stage-context.js +9 -1
  263. package/dist/services/stage-handlers.js +74 -0
  264. package/dist/services/stage-report-renderer.js +63 -0
  265. package/dist/services/stage-work-graph.js +17 -0
  266. package/dist/services/vnext-code-review.js +1 -1
  267. package/dist/services/vnext-code.js +6 -6
  268. package/dist/services/vnext-execution-profile.js +2 -2
  269. package/dist/services/vnext-fanout.js +73 -11
  270. package/dist/services/vnext-merge.js +8 -3
  271. package/dist/services/vnext-plan-review.js +7 -5
  272. package/dist/services/vnext-plan.js +3 -3
  273. package/dist/services/vnext-protocolize.js +20 -6
  274. package/dist/services/vnext-workspace-policy.js +7 -2
  275. package/dist/services/work-registry.js +616 -71
  276. package/dist/services/workspace-files.js +1 -1
  277. package/dist/storage/database.js +84 -6
  278. package/dist/storage/writer-contract.js +11 -7
  279. package/package.json +13 -3
  280. package/tools/create-canon-release.mjs +33 -0
  281. package/tools/produce-hybrid-release.mjs +41 -0
  282. package/dist/harness-runtime/lib/codex-capacity-policy.d.mts +0 -10
  283. package/dist/harness-runtime/lib/codex-capacity-policy.mjs +0 -102
@@ -0,0 +1,181 @@
1
+ import { createContext } from "../runtime/context.js";
2
+ import { resolveDdFlowHome } from "../storage/paths.js";
3
+ import { withStoreCleanup } from "../storage/native-cleanup.js";
4
+ import { PreparedMemoryInitTarget } from "./memory-init-preflight.js";
5
+ import { AppError, errorRecord } from "../shared/errors.js";
6
+ import { hybridDigest } from "./hybrid-contracts.js";
7
+ import { validateMemoryInitStartupScope, readMemoryInitStartupInput, validateMemoryInitObjective } from "./memory-init-startup-custody.js";
8
+ import { PreparedMemoryInitStartupInput } from "./memory-init-startup-input.js";
9
+ import { bootstrapMemoryInit, readMemoryInitBootstrapReadiness } from "./memory-init-bootstrap-readiness.js";
10
+ import { readMemoryInitRunAllocation, reserveMemoryInitRunAllocation } from "./memory-init-run-allocation.js";
11
+ import { readRunStartRequest } from "./run-start-custody.js";
12
+ import { prepareMemoryInitRunBundle } from "./memory-init-run-bundle.js";
13
+ import { PreparedDescriptorRunStart } from "./descriptor-run-start.js";
14
+ import { readSetupStatus } from "./setup.js";
15
+ import { readOperatorProfiles } from "./operator-profiles.js";
16
+ import { FrozenGenericExecution } from "./generic-execution.js";
17
+ import { PreparedInstalledFlowSource } from "./installed-flow-source.js";
18
+ import { PreparedMemoryLayer } from "./memory-layer.js";
19
+ import { selectMemoryInitInstalledEngine } from "./memory-init-engine-release.js";
20
+ import { PreparedMemoryInitGitPolicy } from "./memory-init-git-policy.js";
21
+ import { openMemoryInitStores } from "./memory-init-stores.js";
22
+ import { prepareMemoryInitRequestCandidate } from "./memory-init-request-candidate.js";
23
+ import { prepareMemoryInitHarnessCommands } from "./memory-init-project-bootstrap.js";
24
+ import { readMemoryInitRequestInput } from "./memory-init-request-input.js";
25
+ import { publishSetup } from "../harness-runtime/lib/setup-progress.mjs";
26
+ function refuse(reason) {
27
+ throw new AppError("memory_init_start_invalid", "Memory init requires its exact startup request", 1, { reason, effect: "no_effect", next_action: "reconcile_exact_request" });
28
+ }
29
+ const selections = new WeakMap();
30
+ function requestMaterial(scope, input) {
31
+ return { schema_id: "dd-flow/memory-init-request-selection@1", scope,
32
+ execution: input.execution, git_policy: input.gitPolicy, objective: input.objective, engine_checksum: input.engineChecksum ?? null,
33
+ receipts: [...(input.receipts ?? [])].sort(([left], [right]) => left.localeCompare(right)) };
34
+ }
35
+ /** Private factory witness: genuine candidate A cannot be grafted onto another
36
+ * prepared selection B, even when both have the same scope and objective. */
37
+ export function assertMemoryInitRequestSelection(input, home, scope, request) {
38
+ const witness = selections.get(input), current = input;
39
+ if (!witness)
40
+ refuse("unprepared_request_selection");
41
+ const original = readMemoryInitRequestInput(request, scope, witness.objective ?? "");
42
+ if (witness.home !== home || witness.scopeSha256 !== hybridDigest(scope) || witness.requestSha256 !== hybridDigest(original.selection)
43
+ || current.objective !== witness.objective || Object.entries(witness.owners).some(([key, owner]) => current[key] !== owner)
44
+ || !(current.receipts instanceof Map) || hybridDigest([...current.receipts].sort(([left], [right]) => String(left).localeCompare(String(right)))) !== witness.receiptsSha256)
45
+ refuse("request_selection_changed");
46
+ }
47
+ /** Fresh selection before any runtime-store open. This is not storage,
48
+ * bootstrap readiness or retained-request authority; the startup aggregate
49
+ * still admits those separately before its first project publication. */
50
+ export function prepareMemoryInitSelection(context, scope, input) {
51
+ validateMemoryInitStartupScope(scope);
52
+ if (Object.hasOwn(input, "objective"))
53
+ validateMemoryInitObjective(input.objective);
54
+ const installation = readSetupStatus(context.ddFlowHome).installation;
55
+ if (!installation)
56
+ refuse("installed_release_required");
57
+ const target = PreparedMemoryInitTarget.prepare(scope, context.env);
58
+ const source = PreparedInstalledFlowSource.fromInstalledRelease(context.ddFlowHome, installation.manifest_sha256, "mb-init");
59
+ const layer = PreparedMemoryLayer.fromInstalledRelease(context.ddFlowHome, installation.manifest_sha256, context.now());
60
+ const execution = FrozenGenericExecution.prepare(source.resolveRegisteredFlow(), readOperatorProfiles(context.ddFlowHome), input.execution, { requestId: scope.requestId, projectRoot: scope.projectRoot, workspace: scope.workspaceRoot }, input.receipts);
61
+ prepareMemoryInitHarnessCommands(context, execution);
62
+ const engine = selectMemoryInitInstalledEngine(context.ddFlowHome, installation.manifest_sha256, input.engineChecksum);
63
+ const gitPolicy = PreparedMemoryInitGitPolicy.prepareFresh(context.env, { target, selection: input.gitPolicy });
64
+ const selected = { target, source, layer, execution, engine, gitPolicy, receipts: new Map(input.receipts ?? []),
65
+ receiptBytes: new Map([...input.receiptBytes ?? []].map(([key, bytes]) => [key, Uint8Array.from(bytes)])),
66
+ ...(input.objective === undefined ? {} : { objective: input.objective }) };
67
+ selections.set(selected, { home: context.ddFlowHome, scopeSha256: hybridDigest(scope), requestSha256: hybridDigest(requestMaterial(scope, input)),
68
+ objective: input.objective, owners: { target, source, layer, execution, engine, gitPolicy }, receiptsSha256: hybridDigest(requestMaterial(scope, input).receipts) });
69
+ return selected;
70
+ }
71
+ /** Complete admission against already prepared stores. Retention remains one
72
+ * atomic aggregate; published/replayed requests must restore their inputs. */
73
+ export function prepareMemoryInitRequest(context, scope, input) {
74
+ validateMemoryInitStartupScope(scope);
75
+ if (Object.hasOwn(input, "objective"))
76
+ validateMemoryInitObjective(input.objective);
77
+ if (context.db.isOwnedWriteTransaction?.())
78
+ refuse("startup_outside_writer_required");
79
+ if (readMemoryInitStartupInput(context, scope))
80
+ refuse("restore_existing_startup_input");
81
+ return PreparedMemoryInitStartupInput.prepare(context, prepareMemoryInitSelection(context, scope, input));
82
+ }
83
+ /** Fresh public preparation owns its connection and may create only a jointly
84
+ * retained pristine store pair. A retained startup is rejected before ambient
85
+ * selection: its caller must take the existing restore/replay path instead.
86
+ * Does not retain startup, publish a project, create a RUN or dispatch. */
87
+ export function prepareMemoryInitFreshRequest(env, scope, input, rawIntake = Buffer.from(input.objective ?? "")) {
88
+ validateMemoryInitStartupScope(scope);
89
+ validateMemoryInitObjective(input.objective);
90
+ const raw = structuredClone(input);
91
+ const material = requestMaterial(scope, raw);
92
+ const materialBytes = Buffer.from(JSON.stringify(material));
93
+ if (materialBytes.length > 256 * 1024)
94
+ refuse("unbounded_raw_selection");
95
+ const reader = createContext(env, "read_existing");
96
+ withStoreCleanup(() => {
97
+ if (readMemoryInitStartupInput(reader, scope))
98
+ refuse("restore_existing_startup_input");
99
+ }, () => reader.db.close?.());
100
+ const candidate = prepareMemoryInitRequestCandidate(resolveDdFlowHome(env), scope, materialBytes, rawIntake);
101
+ if (candidate.objective !== raw.objective)
102
+ refuse("raw_intake_objective_mismatch");
103
+ publishSetup("probe_completed", "memory-init:request-candidate");
104
+ const selection = prepareMemoryInitSelection({ ddFlowHome: resolveDdFlowHome(env), env, now: () => new Date().toISOString() }, scope, raw);
105
+ publishSetup("probe_completed", "memory-init:selection");
106
+ // A known incompatible delivered reader refuses before candidate/store
107
+ // effects. Historical SDK requests still use their original @1/@2 contract.
108
+ selection.engine.admitMemoryInitFlow(selection.source, "dd-flow/memory-init-startup-input@3");
109
+ publishSetup("probe_completed", "memory-init:flow-admission");
110
+ const retained = candidate.retain();
111
+ let stores;
112
+ try {
113
+ stores = openMemoryInitStores(env, { scope, selectionSha256: hybridDigest(material) });
114
+ }
115
+ catch (error) {
116
+ if (!retained.created)
117
+ throw error;
118
+ throw new AppError("memory_init_fresh_preparation_incomplete", "Request candidate remains retained; store admission did not complete", 1, { effect: "partial", request_id: scope.requestId, cause: errorRecord(error), next_action: "reconcile_exact_request" });
119
+ }
120
+ publishSetup("probe_completed", "memory-init:stores");
121
+ let admitted = false;
122
+ return withStoreCleanup(() => {
123
+ try {
124
+ const prepared = PreparedMemoryInitStartupInput.prepare(stores.context, selection, candidate);
125
+ publishSetup("probe_completed", "memory-init:startup-input");
126
+ admitted = true;
127
+ return { ...stores, prepared };
128
+ }
129
+ catch (error) {
130
+ if (stores.created || retained.created)
131
+ throw new AppError("memory_init_fresh_preparation_incomplete", "Retained request/stores remain owned; startup admission did not complete", 1, { effect: "partial", store_home: stores.context.ddFlowHome, next_action: "reconcile_exact_request", cause: error instanceof AppError
132
+ ? { code: error.code, message: error.message, details: error.details } : String(error) });
133
+ throw error;
134
+ }
135
+ }, () => { if (!admitted)
136
+ stores.context.db.close?.(); });
137
+ }
138
+ /** Public startup's shared orchestration. The fresh selector is lazy: a retry
139
+ * never consults current canon/profiles, and a published RUN is restored before
140
+ * reconstructing its original project baseline. Does not dispatch a Session;
141
+ * the existing controller owns that subsequent operation. */
142
+ export function startMemoryInitRun(context, scope, prepareFresh) {
143
+ validateMemoryInitStartupScope(scope);
144
+ if (context.db.isOwnedWriteTransaction?.())
145
+ refuse("startup_outside_writer_required");
146
+ const retained = readMemoryInitStartupInput(context, scope);
147
+ const ready = readMemoryInitBootstrapReadiness(context, scope);
148
+ const project = context.db.get("SELECT id FROM projects WHERE root=?", [scope.projectRoot]);
149
+ const request = project ? readRunStartRequest(context, project.id, scope.requestId) : null;
150
+ if (request && !ready)
151
+ refuse("run_bootstrap_missing");
152
+ if (ready) {
153
+ const allocation = readMemoryInitRunAllocation(context, scope);
154
+ if (request) {
155
+ if (!retained || !allocation || project?.id !== ready.projectId || request.payload.run_id !== allocation.run_id
156
+ || request.payload.project_root !== scope.projectRoot || request.payload.workspace_root !== scope.workspaceRoot
157
+ || request.payload.initial_index.flow_kind !== "mb-init")
158
+ refuse("run_request_changed");
159
+ return PreparedDescriptorRunStart.restore(context, { projectRoot: scope.projectRoot, requestId: scope.requestId }).apply(context);
160
+ }
161
+ if (allocation && context.db.get("SELECT 1 FROM runs WHERE project_id=? AND id=?", [allocation.project_id, allocation.run_id]))
162
+ refuse("run_request_missing");
163
+ }
164
+ let selected;
165
+ if (retained)
166
+ selected = PreparedMemoryInitStartupInput.restore(context, scope);
167
+ else {
168
+ if (!prepareFresh)
169
+ refuse("fresh_selection_required");
170
+ selected = prepareFresh();
171
+ if (!(selected instanceof PreparedMemoryInitStartupInput))
172
+ refuse("unprepared_startup_input");
173
+ const facts = selected.inputs().target.facts();
174
+ if (hybridDigest(scope) !== hybridDigest({ requestId: facts.request_id, projectRoot: facts.project_root, workspaceRoot: facts.workspace_root }))
175
+ refuse("foreign_startup_input");
176
+ selected.retain(context);
177
+ }
178
+ bootstrapMemoryInit(context, { bootstrap: selected.bootstrap(), engine: selected.inputs().engine });
179
+ reserveMemoryInitRunAllocation(context, scope);
180
+ return PreparedDescriptorRunStart.prepare(context, { bundle: prepareMemoryInitRunBundle(context, selected.inputs()) }).apply(context);
181
+ }
@@ -0,0 +1,80 @@
1
+ import path from "node:path";
2
+ import { AppError } from "../shared/errors.js";
3
+ import { hybridDigest } from "./hybrid-contracts.js";
4
+ import { readMemoryInitReleaseSelection } from "./memory-init-project-bootstrap.js";
5
+ import { readMemoryInitGitPolicy } from "./memory-init-git-policy.js";
6
+ import { readMemoryInitRequestInput } from "./memory-init-request-input.js";
7
+ export const memoryInitStartupInputEvent = "memory.init_startup_input";
8
+ export const memoryInitStartupInputIntentEvent = "memory.init_startup_input_intent";
9
+ export const memoryInitStartupInputLimit = 64 * 1024 * 1024;
10
+ export const memoryInitStartupInputSchemas = Object.freeze(["dd-flow/memory-init-startup-input@1", "dd-flow/memory-init-startup-input@2", "dd-flow/memory-init-startup-input@3"]);
11
+ const exact = (value, keys) => value !== null && typeof value === "object" && !Array.isArray(value)
12
+ && Object.keys(value).sort().join() === [...keys].sort().join();
13
+ const digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
14
+ export function validateMemoryInitObjective(value) {
15
+ if (typeof value !== "string" || !value.trim() || Buffer.byteLength(value) > 64 * 1024)
16
+ refuseMemoryInitStartupInput("invalid_objective");
17
+ }
18
+ export function refuseMemoryInitStartupInput(reason) {
19
+ throw new AppError("memory_init_startup_input_invalid", "Init requires its complete independently retained startup input", 1, { reason, phase: "prepare", effect: "no_effect", next_action: "reconcile_exact_request" });
20
+ }
21
+ export function validateMemoryInitStartupScope(scope) {
22
+ if (!scope || Object.keys(scope).sort().join() !== "projectRoot,requestId,workspaceRoot"
23
+ || typeof scope.requestId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_.-]{0,95}$/.test(scope.requestId)
24
+ || [scope.projectRoot, scope.workspaceRoot].some(value => typeof value !== "string" || !path.isAbsolute(value) || path.resolve(value) !== value))
25
+ refuseMemoryInitStartupInput("invalid_scope");
26
+ }
27
+ /** SQL-only historical custody. Never imports the executable handler registry,
28
+ * reconstructs physical owners or consults current canon/operator settings. */
29
+ export function readMemoryInitStartupInput(context, scope) {
30
+ return context.db.readSnapshot(() => {
31
+ try {
32
+ validateMemoryInitStartupScope(scope);
33
+ const rows = (type) => context.db.all(`SELECT project_id,payload_json FROM audit_events WHERE event_type=?
34
+ AND json_extract(payload_json,'$.scope.requestId')=? AND json_extract(payload_json,'$.scope.projectRoot')=? LIMIT 2`, [type, scope.requestId, scope.projectRoot]);
35
+ const values = rows(memoryInitStartupInputEvent), intents = rows(memoryInitStartupInputIntentEvent);
36
+ if (!values.length && !intents.length) {
37
+ if (context.db.get(`SELECT 1 FROM audit_events WHERE event_type IN
38
+ ('memory.init_release_selection','memory.init_project_bootstrap_intent','memory.init_project_bootstrap','memory.bootstrap_ready','memory.bootstrap_readiness_intent')
39
+ AND ((json_extract(payload_json,'$.scope.requestId')=? AND json_extract(payload_json,'$.scope.projectRoot')=?)
40
+ OR (json_extract(payload_json,'$.request_id')=? AND json_extract(payload_json,'$.project_root')=?)) LIMIT 1`, [scope.requestId, scope.projectRoot, scope.requestId, scope.projectRoot]))
41
+ refuseMemoryInitStartupInput("startup_input_missing_after_release_selection");
42
+ return null;
43
+ }
44
+ if (values.length !== 1 || intents.length !== 1)
45
+ refuseMemoryInitStartupInput("startup_pair_missing_or_ambiguous");
46
+ if (values[0].project_id !== null || intents[0].project_id !== null)
47
+ refuseMemoryInitStartupInput("foreign_startup_owner");
48
+ if (Buffer.byteLength(values[0].payload_json) > memoryInitStartupInputLimit || Buffer.byteLength(intents[0].payload_json) > 16 * 1024)
49
+ refuseMemoryInitStartupInput("unbounded_input");
50
+ const payload = JSON.parse(values[0].payload_json), sha256 = hybridDigest(payload), intent = JSON.parse(intents[0].payload_json);
51
+ const requestVersion = payload.schema_id === "dd-flow/memory-init-startup-input@3";
52
+ const objectiveVersion = payload.schema_id === "dd-flow/memory-init-startup-input@2" || requestVersion;
53
+ if (objectiveVersion)
54
+ validateMemoryInitObjective(payload.objective);
55
+ if (requestVersion)
56
+ readMemoryInitRequestInput(payload.request_input, scope, payload.objective);
57
+ if (!exact(payload, ["engine", "execution", "git_policy_sha256", "layer", "release", "schema_id", "scope", "source", "target", ...(objectiveVersion ? ["objective"] : []), ...(requestVersion ? ["request_input"] : [])])
58
+ || !exact(payload.target, ["sha256", "facts"]) || !exact(payload.layer, ["sha256", "installation_sha256", "files"])
59
+ || !exact(payload.source, ["sha256", "snapshot"]) || !exact(payload.execution, ["sha256", "snapshot", "receipts", ...(Object.hasOwn(payload.execution, "receipt_blobs") ? ["receipt_blobs"] : [])])
60
+ || !exact(payload.engine, ["identity", "manifest_sha256", "flow_admission_sha256", "release_pairing"])
61
+ || !exact(payload.engine.release_pairing, ["facts", "sha256"]) || !digest(payload.engine.release_pairing.sha256)
62
+ || hybridDigest(payload.engine.release_pairing.facts) !== payload.engine.release_pairing.sha256
63
+ || [payload.target.sha256, payload.layer.sha256, payload.layer.installation_sha256, payload.source.sha256,
64
+ payload.execution.sha256, payload.engine.manifest_sha256, payload.engine.flow_admission_sha256, payload.git_policy_sha256].some(value => !digest(value))
65
+ || !Array.isArray(payload.execution.receipts) || payload.execution.receipts.length > 2
66
+ || payload.execution.receipt_blobs !== undefined && (!Array.isArray(payload.execution.receipt_blobs) || payload.execution.receipt_blobs.length > 2)
67
+ || !memoryInitStartupInputSchemas.includes(payload.schema_id) || hybridDigest(payload.scope) !== hybridDigest(scope)
68
+ || hybridDigest(intent) !== hybridDigest({ schema_id: "dd-flow/memory-init-startup-input-intent@1", scope, input_sha256: sha256 })
69
+ || hybridDigest(readMemoryInitReleaseSelection(context, scope)) !== hybridDigest(payload.release)
70
+ || hybridDigest(readMemoryInitGitPolicy(context, scope)) !== payload.git_policy_sha256)
71
+ refuseMemoryInitStartupInput("startup_custody_changed");
72
+ return { payload, sha256 };
73
+ }
74
+ catch (error) {
75
+ if (error instanceof AppError)
76
+ throw error;
77
+ return refuseMemoryInitStartupInput("invalid_retained_input");
78
+ }
79
+ });
80
+ }
@@ -0,0 +1,240 @@
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 { appendAudit } from "./audit.js";
6
+ import { hybridDigest } from "./hybrid-contracts.js";
7
+ import { PreparedInstalledFlowSource } from "./installed-flow-source.js";
8
+ import { FrozenGenericExecution } from "./generic-execution.js";
9
+ import { AdmittedFrozenEngine } from "./frozen-engine.js";
10
+ import { PreparedMemoryInitTarget } from "./memory-init-preflight.js";
11
+ import { PreparedMemoryLayer } from "./memory-layer.js";
12
+ import { readRetainedMemoryLayer } from "./memory-layer-publication.js";
13
+ import { PreparedMemoryInitProjectBootstrap } from "./memory-init-project-bootstrap.js";
14
+ import { prepareMemoryInitBootstrapSchema } from "./memory-init-bootstrap-readiness.js";
15
+ import { PreparedMemoryInitGitPolicy, readMemoryInitGitPolicy } from "./memory-init-git-policy.js";
16
+ import { PreparedMemoryInitRuntimeStorage } from "./memory-init-storage.js";
17
+ import { prepareMemoryInitEngineRelease, revalidateMemoryInitEngineRelease } from "./memory-init-engine-release.js";
18
+ import { captureMemoryInitRequestCandidate } from "./memory-init-request-candidate.js";
19
+ import { assertMemoryInitRequestSelection } from "./memory-init-start.js";
20
+ import { readMemoryInitStartupInput as read, validateMemoryInitStartupScope as scopeValid, refuseMemoryInitStartupInput as refuse, memoryInitStartupInputEvent as event, memoryInitStartupInputIntentEvent as intentEvent, memoryInitStartupInputLimit as limit, validateMemoryInitObjective } from "./memory-init-startup-custody.js";
21
+ export { readMemoryInitStartupInput } from "./memory-init-startup-custody.js";
22
+ /** Fresh admission cannot be supplied by a self-hashed restore snapshot. */
23
+ function revalidateFreshSource(context, input) {
24
+ const actual = PreparedInstalledFlowSource.fromInstalledRelease(context.ddFlowHome, input.source.installationSha256(), "mb-init");
25
+ if (actual.sha256 !== input.source.sha256)
26
+ refuse("source_not_verified_installation");
27
+ let installedAt;
28
+ try {
29
+ installedAt = JSON.parse(input.layer.files().get("dd-flow/manifest.json").toString("utf8")).installed_at;
30
+ }
31
+ catch {
32
+ return refuse("invalid_layer_manifest");
33
+ }
34
+ if (typeof installedAt !== "string" || PreparedMemoryLayer.fromInstalledRelease(context.ddFlowHome, input.layer.installationSha256, installedAt).sha256 !== input.layer.sha256)
35
+ refuse("layer_not_verified_installation");
36
+ }
37
+ /** One prepared selection before project effects. Existing bootstrap/RUN
38
+ * owners still perform their own engine/storage/physical admission and writes. */
39
+ export class PreparedMemoryInitStartupInput {
40
+ sha256;
41
+ #payload;
42
+ #storage;
43
+ #input;
44
+ #bootstrap;
45
+ constructor(payload, storage, input, bootstrap) {
46
+ this.#payload = structuredClone(payload);
47
+ this.sha256 = hybridDigest(payload);
48
+ this.#storage = storage;
49
+ this.#input = input;
50
+ this.#bootstrap = bootstrap;
51
+ Object.freeze(this);
52
+ }
53
+ static prepare(context, input, requestCandidate) {
54
+ if (context.db.isOwnedWriteTransaction?.())
55
+ refuse("preparation_outside_writer_required");
56
+ if (Object.hasOwn(input, "objective"))
57
+ validateMemoryInitObjective(input.objective);
58
+ if (!(input.target instanceof PreparedMemoryInitTarget) || !(input.layer instanceof PreparedMemoryLayer)
59
+ || !(input.source instanceof PreparedInstalledFlowSource) || !(input.execution instanceof FrozenGenericExecution)
60
+ || !(input.engine instanceof AdmittedFrozenEngine))
61
+ refuse("unprepared_selection");
62
+ const facts = input.target.facts(), scope = { requestId: facts.request_id, projectRoot: facts.project_root, workspaceRoot: facts.workspace_root };
63
+ scopeValid(scope);
64
+ const prior = context.db.readSnapshot(() => read(context, scope));
65
+ if (prior)
66
+ refuse("restore_existing_startup_input");
67
+ if (input.requestCandidate !== undefined)
68
+ refuse("unexpected_request_candidate");
69
+ const requestInput = requestCandidate === undefined ? undefined
70
+ : captureMemoryInitRequestCandidate(requestCandidate, context.ddFlowHome, scope, input.objective ?? "");
71
+ if (requestInput)
72
+ assertMemoryInitRequestSelection(input, context.ddFlowHome, scope, requestInput);
73
+ const schemaId = requestInput ? "dd-flow/memory-init-startup-input@3" : input.objective === undefined ? "dd-flow/memory-init-startup-input@1" : "dd-flow/memory-init-startup-input@2";
74
+ revalidateFreshSource(context, input);
75
+ input.target.revalidate();
76
+ const flow = input.source.resolveRegisteredFlow(), snapshot = input.execution.snapshot(), receipts = input.receipts ?? new Map();
77
+ FrozenGenericExecution.restore(snapshot, input.execution.sha256, flow, { requestId: scope.requestId, projectRoot: scope.projectRoot, workspace: scope.workspaceRoot }, receipts);
78
+ const selectedReceipts = new Map([snapshot.settings.attached_session_receipt,
79
+ snapshot.settings.delegation.native_capacity_receipt].filter(reference => reference !== null)
80
+ .map(reference => [reference.sha256, structuredClone(receipts.get(reference.sha256))]));
81
+ const receiptBlobs = [];
82
+ for (const checksum of selectedReceipts.keys()) {
83
+ const bytes = input.receiptBytes?.get(checksum);
84
+ if (!bytes || bytes.byteLength > 256 * 1024 || createHash("sha256").update(bytes).digest("hex") !== checksum)
85
+ refuse("execution_receipt_bytes_required");
86
+ receiptBlobs.push([checksum, Buffer.from(bytes).toString("base64")]);
87
+ }
88
+ if (input.source.installationSha256() !== input.layer.installationSha256)
89
+ refuse("foreign_layer_selection");
90
+ prepareMemoryInitBootstrapSchema(input.engine);
91
+ const pairing = prepareMemoryInitEngineRelease(context.ddFlowHome, input.source.installationSha256(), input.engine);
92
+ const admittedFlow = input.engine.admitMemoryInitFlow(input.source, schemaId === "dd-flow/memory-init-startup-input@1" ? undefined : schemaId);
93
+ const bootstrap = PreparedMemoryInitProjectBootstrap.prepare(context, input), release = bootstrap.releaseSelection();
94
+ if (input.gitPolicy !== undefined && !(input.gitPolicy instanceof PreparedMemoryInitGitPolicy))
95
+ refuse("unprepared_git_policy");
96
+ const priorPolicy = readMemoryInitGitPolicy(context, scope), policy = input.gitPolicy?.value() ?? priorPolicy;
97
+ if (priorPolicy && hybridDigest(priorPolicy) !== hybridDigest(policy))
98
+ refuse("git_policy_changed");
99
+ if (policy && hybridDigest(policy.scope) !== hybridDigest(scope))
100
+ refuse("foreign_git_policy");
101
+ if (!policy || policy.target_sha256 !== input.target.sha256)
102
+ refuse("explicit_git_policy_required");
103
+ const manifest = input.engine.manifest(), selectedRelease = JSON.parse(Buffer.from(release.installation_manifest_base64, "base64").toString("utf8"));
104
+ if (manifest.package_name !== selectedRelease.engine.package || manifest.package_version !== selectedRelease.engine.version
105
+ || typeof manifest.integrity.checksum !== "string")
106
+ refuse("foreign_engine_selection");
107
+ const identity = { package_name: manifest.package_name, package_version: manifest.package_version, engine_version: manifest.engine_version,
108
+ snapshot_root: manifest.snapshot_root, integrity_checksum: manifest.integrity.checksum };
109
+ const payload = { schema_id: schemaId, scope,
110
+ ...(input.objective === undefined ? {} : { objective: input.objective }),
111
+ ...(requestInput === undefined ? {} : { request_input: requestInput }),
112
+ target: { sha256: input.target.sha256, facts },
113
+ layer: { sha256: input.layer.sha256, installation_sha256: input.layer.installationSha256,
114
+ files: [...input.layer.files()].map(([logical, content]) => ({ path: logical, base64: content.toString("base64") })) },
115
+ source: { sha256: input.source.sha256, snapshot: input.source.snapshot() },
116
+ execution: { sha256: input.execution.sha256, snapshot, receipts: [...selectedReceipts], ...(receiptBlobs.length ? { receipt_blobs: receiptBlobs } : {}) },
117
+ engine: { identity, manifest_sha256: input.engine.manifestSha256, flow_admission_sha256: admittedFlow.sha256, release_pairing: pairing }, release, git_policy_sha256: hybridDigest(policy) };
118
+ if (Buffer.byteLength(JSON.stringify(payload)) > limit)
119
+ refuse("unbounded_input");
120
+ return new PreparedMemoryInitStartupInput(payload, PreparedMemoryInitRuntimeStorage.prepare(context), { ...input, receipts: new Map(receipts), ...(requestCandidate ? { requestCandidate } : {}) }, bootstrap);
121
+ }
122
+ retain(context) {
123
+ const p = this.#payload;
124
+ // Fresh publication rechecks physical selection outside the writer. A reply
125
+ // replay only reads custody and cannot reselect current canon/profile bytes.
126
+ const prior = context.db.readSnapshot(() => read(context, p.scope));
127
+ if (prior) {
128
+ if (prior.sha256 !== this.sha256)
129
+ refuse("request_selection_changed");
130
+ return { sha256: this.sha256, changed: false };
131
+ }
132
+ revalidateFreshSource(context, this.#input);
133
+ this.#input.target.revalidate();
134
+ if (p.request_input && hybridDigest(captureMemoryInitRequestCandidate(this.#input.requestCandidate, context.ddFlowHome, p.scope, p.objective)) !== hybridDigest(p.request_input))
135
+ refuse("request_candidate_changed");
136
+ if (prepareMemoryInitEngineRelease(context.ddFlowHome, this.#input.source.installationSha256(), this.#input.engine).sha256 !== p.engine.release_pairing.sha256)
137
+ refuse("engine_release_pairing_changed");
138
+ if (this.#input.engine.admitMemoryInitFlow(this.#input.source, p.schema_id === "dd-flow/memory-init-startup-input@1" ? undefined : p.schema_id).sha256 !== p.engine.flow_admission_sha256)
139
+ refuse("engine_flow_admission_changed");
140
+ return context.db.writeTransaction(() => {
141
+ if (context.db.isOwnedWriteTransaction?.() !== true)
142
+ refuse("owned_writer_required");
143
+ this.#storage.assertCompatibility(context);
144
+ const current = read(context, p.scope);
145
+ if (current) {
146
+ if (current.sha256 !== this.sha256)
147
+ refuse("request_selection_changed");
148
+ return { sha256: this.sha256, changed: false };
149
+ }
150
+ this.#input.gitPolicy?.retainPreparedSql(context);
151
+ if (hybridDigest(readMemoryInitGitPolicy(context, p.scope)) !== p.git_policy_sha256)
152
+ refuse("git_policy_changed");
153
+ appendAudit(context, { eventType: "memory.init_release_selection", payload: p.release });
154
+ appendAudit(context, { eventType: intentEvent, payload: { schema_id: "dd-flow/memory-init-startup-input-intent@1", scope: p.scope, input_sha256: this.sha256 } });
155
+ appendAudit(context, { eventType: event, payload: p });
156
+ if (read(context, p.scope)?.sha256 !== this.sha256)
157
+ refuse("startup_readback_failed");
158
+ return { sha256: this.sha256, changed: true };
159
+ }, "memoryInit.retainStartupInput");
160
+ }
161
+ /** Actual paired SQL owner supplies all expected digests. No ambient profile,
162
+ * canon or release selection is read while reconstructing this request. */
163
+ static restore(context, scope) {
164
+ const retained = context.db.readSnapshot(() => read(context, scope));
165
+ if (!retained)
166
+ refuse("startup_input_required");
167
+ try {
168
+ const p = retained.payload, source = PreparedInstalledFlowSource.restoreRetained(p.source.snapshot, p.source.sha256);
169
+ if (!Array.isArray(p.layer.files) || p.layer.files.length > 20_000)
170
+ refuse("invalid_layer_input");
171
+ const files = new Map();
172
+ for (const entry of p.layer.files) {
173
+ if (!entry || Object.keys(entry).sort().join() !== "base64,path" || typeof entry.path !== "string" || files.has(entry.path)
174
+ || typeof entry.base64 !== "string" || entry.base64.length > 2 * 1024 * 1024)
175
+ refuse("invalid_layer_input");
176
+ const content = Buffer.from(entry.base64, "base64");
177
+ if (content.toString("base64") !== entry.base64)
178
+ refuse("invalid_layer_input");
179
+ files.set(entry.path, content);
180
+ }
181
+ const layer = PreparedMemoryLayer.restoreRetained(files, p.layer.sha256, p.layer.installation_sha256);
182
+ if (!Array.isArray(p.execution.receipts) || p.execution.receipts.length > 2
183
+ || p.execution.receipts.some(entry => !Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string" || !/^[a-f0-9]{64}$/.test(entry[0])))
184
+ refuse("invalid_execution_receipts");
185
+ const receipts = new Map(p.execution.receipts);
186
+ const receiptBytes = new Map();
187
+ for (const entry of p.execution.receipt_blobs ?? []) {
188
+ if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string" || typeof entry[1] !== "string" || receiptBytes.has(entry[0]))
189
+ refuse("invalid_execution_receipt_bytes");
190
+ const bytes = Buffer.from(entry[1], "base64");
191
+ if (bytes.byteLength > 256 * 1024 || bytes.toString("base64") !== entry[1] || createHash("sha256").update(bytes).digest("hex") !== entry[0])
192
+ refuse("execution_receipt_bytes_changed");
193
+ receiptBytes.set(entry[0], bytes);
194
+ }
195
+ if (receiptBytes.size !== receipts.size || [...receipts.keys()].some(key => !receiptBytes.has(key)))
196
+ refuse("execution_receipt_bytes_required");
197
+ if (receipts.size !== p.execution.receipts.length)
198
+ refuse("duplicate_execution_receipt");
199
+ const execution = FrozenGenericExecution.restore(p.execution.snapshot, p.execution.sha256, source.resolveRegisteredFlow(), { requestId: scope.requestId, projectRoot: scope.projectRoot, workspace: scope.workspaceRoot }, receipts);
200
+ const referenced = new Set([execution.settings.attached_session_receipt, execution.settings.delegation.native_capacity_receipt]
201
+ .filter(reference => reference !== null).map(reference => reference.sha256));
202
+ if (receipts.size !== referenced.size || [...receipts.keys()].some(sha => !referenced.has(sha)))
203
+ refuse("unused_execution_receipt");
204
+ const engine = AdmittedFrozenEngine.admitSelection(p.engine.identity, p.engine.manifest_sha256);
205
+ if (p.engine.release_pairing.facts.installation_sha256 !== p.layer.installation_sha256)
206
+ refuse("foreign_engine_release_pairing");
207
+ revalidateMemoryInitEngineRelease(p.engine.release_pairing.facts, p.engine.release_pairing.sha256, engine);
208
+ if (engine.admitMemoryInitFlow(source, p.schema_id === "dd-flow/memory-init-startup-input@1" ? undefined : p.schema_id).sha256 !== p.engine.flow_admission_sha256)
209
+ refuse("engine_flow_admission_changed");
210
+ let target;
211
+ if (fs.existsSync(path.join(scope.workspaceRoot, ".memory-bank"))) {
212
+ readRetainedMemoryLayer(context.ddFlowHome, { ...scope, targetSha256: p.target.sha256, layerSha256: layer.sha256, installationSha256: layer.installationSha256 });
213
+ target = PreparedMemoryInitTarget.restoreOwnedPublication(p.target.facts, p.target.sha256, context.env);
214
+ }
215
+ else {
216
+ target = PreparedMemoryInitTarget.prepare(scope, context.env);
217
+ if (target.sha256 !== p.target.sha256 || hybridDigest(target.facts()) !== hybridDigest(p.target.facts))
218
+ refuse("target_changed");
219
+ }
220
+ const input = { target, layer, source, execution, engine, receipts, receiptBytes, ...(p.objective === undefined ? {} : { objective: p.objective }) };
221
+ const bootstrap = PreparedMemoryInitProjectBootstrap.prepare(context, input);
222
+ if (hybridDigest(bootstrap.releaseSelection()) !== hybridDigest(p.release))
223
+ refuse("bootstrap_selection_changed");
224
+ const result = new PreparedMemoryInitStartupInput(p, PreparedMemoryInitRuntimeStorage.prepare(context), input, bootstrap);
225
+ if (result.sha256 !== retained.sha256)
226
+ refuse("restored_input_changed");
227
+ return result;
228
+ }
229
+ catch (error) {
230
+ if (error instanceof AppError)
231
+ throw error;
232
+ return refuse("invalid_retained_input");
233
+ }
234
+ }
235
+ inputs() {
236
+ return { ...this.#input, receipts: new Map(structuredClone(this.#payload.execution.receipts)),
237
+ receiptBytes: new Map((this.#payload.execution.receipt_blobs ?? []).map(([checksum, bytes]) => [checksum, Buffer.from(bytes, "base64")])) };
238
+ }
239
+ bootstrap() { return this.#bootstrap; }
240
+ }
@@ -0,0 +1,81 @@
1
+ import path from "node:path";
2
+ import { AppError } from "../shared/errors.js";
3
+ import { STORE_WRITER_VERSION, storeWriterTriggerSql } from "../storage/writer-contract.js";
4
+ import { hybridDigest } from "./hybrid-contracts.js";
5
+ const footprint = {
6
+ projects: ["id", "short_id", "slug", "root", "status", "state_root", "created_at", "updated_at"],
7
+ runs: ["id", "short_id", "slug", "project_id", "project_root", "workspace_root", "flow_kind", "subject_type", "subject_id", "status", "verdict",
8
+ "next_action", "runtime_path", "run_dir", "run_index_path", "run_home_path", "run_root", "layout_version", "artifact_root_kind", "index_json", "created_at", "updated_at", "completed_at"],
9
+ works: ["work_id", "project_id", "run_id", "parent_work_id", "task", "payload_json", "status", "result_schema"],
10
+ work_sessions: ["id", "work_id", "session_id", "status", "result_path", "start_receipt_json", "result_receipt_json"],
11
+ stage_work_memberships: ["project_id", "run_id", "work_id", "stage", "attempt", "cycle"],
12
+ audit_events: ["id", "protocol_id", "project_id", "event_type", "forced", "reason", "payload_json", "created_at"]
13
+ };
14
+ const primaryKeys = {
15
+ projects: ["id"], runs: ["project_id", "id"], works: ["work_id"],
16
+ work_sessions: ["id"], stage_work_memberships: ["project_id", "run_id", "work_id", "stage", "attempt", "cycle"],
17
+ audit_events: ["id"]
18
+ };
19
+ function refuse(reason) { throw new AppError("memory_init_storage_incompatible", "Executing CLI cannot admit memory-init runtime storage without migration or repair", 1, { reason, effect: "no_effect" }); }
20
+ const normalize = (sql) => sql.replace(/\s+/g, " ").trim().replace(/;$/, "");
21
+ function inspect(context) {
22
+ if (!context.db.writable || !path.isAbsolute(context.ddFlowHome) || path.resolve(context.db.path) !== path.join(path.resolve(context.ddFlowHome), "db.sqlite"))
23
+ refuse("foreign_or_readonly_store");
24
+ const contract = context.db.all("SELECT id, version FROM dd_flow_writer_contract");
25
+ if (contract.length !== 1 || contract[0]?.id !== 1 || contract[0].version !== STORE_WRITER_VERSION
26
+ || context.db.get("SELECT dd_flow_writer_version() AS version")?.version !== STORE_WRITER_VERSION)
27
+ refuse("writer_contract_mismatch");
28
+ const schema = {};
29
+ for (const [table, required] of Object.entries(footprint)) {
30
+ const columns = context.db.all(`PRAGMA table_info("${table}")`);
31
+ if (required.some(name => !columns.some(column => column.name === name)))
32
+ refuse(`missing_operation_column:${table}`);
33
+ if (required.some(name => columns.find(column => column.name === name)?.type.toUpperCase() !== (table === "audit_events" && ["id", "forced"].includes(name) ? "INTEGER" : "TEXT")))
34
+ refuse(`operation_column_type_mismatch:${table}`);
35
+ const key = columns.filter(column => column.pk > 0).sort((a, b) => a.pk - b.pk).map(column => column.name);
36
+ if (JSON.stringify(key) !== JSON.stringify(primaryKeys[table]))
37
+ refuse(`operation_primary_key_mismatch:${table}`);
38
+ const fences = [];
39
+ for (const action of ["INSERT", "UPDATE", "DELETE"]) {
40
+ const expected = storeWriterTriggerSql(table, action);
41
+ const actual = context.db.get("SELECT sql FROM sqlite_schema WHERE type = 'trigger' AND name = ? AND tbl_name = ?", [expected.name, table]);
42
+ if (!actual || normalize(actual.sql) !== normalize(expected.sql))
43
+ refuse(`writer_fence_mismatch:${table}`);
44
+ fences.push(normalize(actual.sql));
45
+ }
46
+ schema[table] = { columns: columns.map(({ name, type, notnull, pk }) => ({ name, type, notnull, pk })), fences };
47
+ }
48
+ return { schema_id: "dd-flow/memory-init-runtime-storage@1", operation: "memory-init",
49
+ store_kind: "run", store_path: context.db.path, executing_writer_version: STORE_WRITER_VERSION,
50
+ schema_sha256: hybridDigest(schema), route: "verified-no-op", outcome: "no-op" };
51
+ }
52
+ /** Current executing CLI only: never inferred support for another engine.
53
+ * No migrations, schema installation, writer probes or filesystem writes.
54
+ * Shared process stores/provider readiness require separate admission.
55
+ */
56
+ export class PreparedMemoryInitRuntimeStorage {
57
+ sha256;
58
+ #facts;
59
+ constructor(facts) { this.#facts = facts; this.sha256 = hybridDigest(facts); Object.freeze(this); }
60
+ static prepare(context) {
61
+ try {
62
+ return context.db.readSnapshot(() => {
63
+ const facts = inspect(context), integrity = context.db.all("PRAGMA quick_check");
64
+ if (integrity.length !== 1 || integrity[0]?.quick_check !== "ok" || context.db.all("PRAGMA foreign_key_check").length)
65
+ refuse("storage_integrity_failed");
66
+ return new PreparedMemoryInitRuntimeStorage(facts);
67
+ });
68
+ }
69
+ catch (error) {
70
+ if (error instanceof AppError)
71
+ throw error;
72
+ return refuse("storage_observation_failed");
73
+ }
74
+ }
75
+ facts() { return { ...this.#facts }; }
76
+ /** Writer-safe metadata fence; expensive integrity scan remains preparation. */
77
+ assertCompatibility(context) {
78
+ if (hybridDigest(inspect(context)) !== this.sha256)
79
+ refuse("storage_changed_after_preparation");
80
+ }
81
+ }