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

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 (260) hide show
  1. package/CHANGELOG.md +4 -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/setup.js +149 -0
  27. package/dist/cli.js +54 -2
  28. package/dist/domain/stage-handler-identities.js +20 -0
  29. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  30. package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
  31. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +4 -2
  32. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +11 -5
  33. package/dist/harness-runtime/lib/dd-codex.mjs +22 -10
  34. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
  35. package/dist/harness-runtime/lib/dd-droid.mjs +2 -1
  36. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +4 -2
  37. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +6 -4
  38. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +9 -9
  39. package/dist/harness-runtime/lib/delegation-instructions.mjs +5 -3
  40. package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
  41. package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
  42. package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
  43. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  44. package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
  45. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  46. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  47. package/dist/harness-runtime/lib/opencode-plugin.mjs +2 -0
  48. package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
  49. package/dist/runtime/context.js +1 -1
  50. package/dist/schemas/discovery-result.schema.json +184 -0
  51. package/dist/schemas/execution-bundle.schema.json +205 -0
  52. package/dist/schemas/execution-settings.schema.json +162 -0
  53. package/dist/schemas/flow-descriptor.schema.json +54 -0
  54. package/dist/schemas/flow-run.schema.json +22 -0
  55. package/dist/schemas/harness-catalog.schema.json +80 -0
  56. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  57. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  58. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  59. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  60. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  61. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  62. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  63. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  64. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  65. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  66. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  67. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  68. package/dist/schemas/model-catalog.schema.json +153 -0
  69. package/dist/schemas/profile-settings.schema.json +122 -0
  70. package/dist/schemas/release-manifest.schema.json +291 -0
  71. package/dist/schemas/run-engine-binding.schema.json +1 -1
  72. package/dist/services/check-runner-evidence.js +51 -4
  73. package/dist/services/cli-operation-classifier.js +8 -47
  74. package/dist/services/cli-upgrade-allowlist.js +27 -0
  75. package/dist/services/code-checks.js +387 -34
  76. package/dist/services/controller-execution.js +88 -0
  77. package/dist/services/controller-fanout.js +71 -12
  78. package/dist/services/dashboard.js +8 -2
  79. package/dist/services/descriptor-coordinator-session.js +35 -0
  80. package/dist/services/descriptor-root-work.js +53 -0
  81. package/dist/services/descriptor-run-settlement.js +105 -0
  82. package/dist/services/descriptor-run-start.js +449 -0
  83. package/dist/services/descriptor-stage-coordinator.js +197 -0
  84. package/dist/services/descriptor-stage-settlement.js +222 -0
  85. package/dist/services/descriptor-stage-start.js +139 -0
  86. package/dist/services/discovery/agy-discovery.js +2 -0
  87. package/dist/services/discovery/codex-discovery.js +2 -0
  88. package/dist/services/discovery/droid-discovery.js +2 -0
  89. package/dist/services/discovery/grok-discovery.js +2 -0
  90. package/dist/services/discovery/opencode-discovery.js +2 -0
  91. package/dist/services/discovery/static.js +31 -0
  92. package/dist/services/discovery/zcode-discovery.js +2 -0
  93. package/dist/services/engines.js +39 -22
  94. package/dist/services/eval-snapshots.js +83 -25
  95. package/dist/services/execution-bundles.js +263 -0
  96. package/dist/services/execution-policy.js +20 -16
  97. package/dist/services/executor-onboarding.js +56 -0
  98. package/dist/services/external-work-launch.js +91 -11
  99. package/dist/services/flow-catalog.js +21 -0
  100. package/dist/services/flow-descriptors.js +82 -0
  101. package/dist/services/frozen-engine.js +242 -0
  102. package/dist/services/generic-execution.js +164 -0
  103. package/dist/services/harness-adapter.js +28 -2
  104. package/dist/services/harness-discovery.js +29 -0
  105. package/dist/services/harness-doctor.js +75 -0
  106. package/dist/services/harness-probe-effects.js +51 -0
  107. package/dist/services/harness-version-probe.js +100 -0
  108. package/dist/services/hooks.js +24 -6
  109. package/dist/services/hybrid-contracts.js +483 -0
  110. package/dist/services/ids.js +29 -1
  111. package/dist/services/installation-lock.js +95 -0
  112. package/dist/services/installed-flow-source.js +183 -0
  113. package/dist/services/lifecycle-invocations.js +257 -78
  114. package/dist/services/memory-accepted-composition.js +77 -0
  115. package/dist/services/memory-baseline-preservation.js +65 -0
  116. package/dist/services/memory-completed-correction-wave.js +320 -0
  117. package/dist/services/memory-compose-handler.js +258 -0
  118. package/dist/services/memory-composition-acceptance.js +199 -0
  119. package/dist/services/memory-composition-graph.js +134 -0
  120. package/dist/services/memory-composition-registration.js +146 -0
  121. package/dist/services/memory-composition-work-custody.js +151 -0
  122. package/dist/services/memory-composition-work-results.js +96 -0
  123. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  124. package/dist/services/memory-corrected-review-batch.js +30 -0
  125. package/dist/services/memory-corrected-review-findings.js +106 -0
  126. package/dist/services/memory-corrected-review-inputs.js +210 -0
  127. package/dist/services/memory-corrected-review-projection.js +78 -0
  128. package/dist/services/memory-corrected-review-receipt.js +170 -0
  129. package/dist/services/memory-corrected-review-registration.js +191 -0
  130. package/dist/services/memory-correction-check-receipt.js +219 -0
  131. package/dist/services/memory-correction-input-owner.js +6 -0
  132. package/dist/services/memory-discover-handler.js +104 -0
  133. package/dist/services/memory-finish-evidence.js +435 -0
  134. package/dist/services/memory-finish-handler.js +215 -0
  135. package/dist/services/memory-finish-integration.js +280 -0
  136. package/dist/services/memory-finish-readiness.js +122 -0
  137. package/dist/services/memory-git-integration.js +151 -0
  138. package/dist/services/memory-historical-corrected-review.js +206 -0
  139. package/dist/services/memory-historical-original-review.js +130 -0
  140. package/dist/services/memory-historical-repair-registration.js +99 -0
  141. package/dist/services/memory-historical-second-review.js +128 -0
  142. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  143. package/dist/services/memory-init-contexts.js +89 -0
  144. package/dist/services/memory-init-controller-start.js +84 -0
  145. package/dist/services/memory-init-engine-release.js +223 -0
  146. package/dist/services/memory-init-git-policy.js +136 -0
  147. package/dist/services/memory-init-lint-capability.js +185 -0
  148. package/dist/services/memory-init-native-capacity.js +241 -0
  149. package/dist/services/memory-init-preflight.js +312 -0
  150. package/dist/services/memory-init-project-bootstrap.js +599 -0
  151. package/dist/services/memory-init-request-candidate.js +157 -0
  152. package/dist/services/memory-init-request-input.js +66 -0
  153. package/dist/services/memory-init-resource-storage.js +125 -0
  154. package/dist/services/memory-init-run-allocation.js +81 -0
  155. package/dist/services/memory-init-run-bundle.js +98 -0
  156. package/dist/services/memory-init-start.js +175 -0
  157. package/dist/services/memory-init-startup-custody.js +80 -0
  158. package/dist/services/memory-init-startup-input.js +240 -0
  159. package/dist/services/memory-init-storage.js +81 -0
  160. package/dist/services/memory-init-stores.js +359 -0
  161. package/dist/services/memory-init-worktrunk-capability.js +172 -0
  162. package/dist/services/memory-layer-publication.js +611 -0
  163. package/dist/services/memory-layer.js +156 -0
  164. package/dist/services/memory-lint-config.js +85 -0
  165. package/dist/services/memory-native-review-copy.js +165 -0
  166. package/dist/services/memory-normal-flow-entry.js +75 -0
  167. package/dist/services/memory-ordinary-defaults.js +112 -0
  168. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  169. package/dist/services/memory-preflight-handler.js +259 -0
  170. package/dist/services/memory-repair-current-view.js +299 -0
  171. package/dist/services/memory-repair-document-delta.js +451 -0
  172. package/dist/services/memory-repair-history.js +491 -0
  173. package/dist/services/memory-repair-physical-binding.js +312 -0
  174. package/dist/services/memory-repair-publication-files.js +152 -0
  175. package/dist/services/memory-repair-publication-intent.js +27 -0
  176. package/dist/services/memory-repair-publication-plan.js +160 -0
  177. package/dist/services/memory-repair-publication-source.js +225 -0
  178. package/dist/services/memory-repair-publication.js +794 -0
  179. package/dist/services/memory-repair-registration.js +239 -0
  180. package/dist/services/memory-repair-work-baseline.js +413 -0
  181. package/dist/services/memory-repair-work-completion.js +97 -0
  182. package/dist/services/memory-repair-work-custody.js +73 -0
  183. package/dist/services/memory-repair-work-results.js +89 -0
  184. package/dist/services/memory-repair-workspace.js +252 -0
  185. package/dist/services/memory-repair-writer-copy.js +735 -0
  186. package/dist/services/memory-result-binding.js +173 -0
  187. package/dist/services/memory-retained-review-authority.js +129 -0
  188. package/dist/services/memory-retained-review-results.js +70 -0
  189. package/dist/services/memory-retained-second-baseline.js +102 -0
  190. package/dist/services/memory-retained-second-repairs.js +156 -0
  191. package/dist/services/memory-review-acceptance.js +214 -0
  192. package/dist/services/memory-review-correction-plan.js +171 -0
  193. package/dist/services/memory-review-handler.js +585 -0
  194. package/dist/services/memory-review-inputs.js +200 -0
  195. package/dist/services/memory-review-receipt.js +180 -0
  196. package/dist/services/memory-review-registration.js +108 -0
  197. package/dist/services/memory-review-work-custody.js +124 -0
  198. package/dist/services/memory-review-work-input.js +72 -0
  199. package/dist/services/memory-review-work-results.js +73 -0
  200. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  201. package/dist/services/memory-second-correction-plan.js +76 -0
  202. package/dist/services/memory-second-repair-baseline.js +91 -0
  203. package/dist/services/memory-second-repair-launch.js +614 -0
  204. package/dist/services/memory-second-repair-registration.js +88 -0
  205. package/dist/services/memory-second-repair-source.js +187 -0
  206. package/dist/services/memory-second-review-acceptance.js +115 -0
  207. package/dist/services/memory-source-observations.js +117 -0
  208. package/dist/services/memory-stage-dispatch.js +28 -0
  209. package/dist/services/memory-stage-results.js +199 -0
  210. package/dist/services/memory-verification-acceptance.js +135 -0
  211. package/dist/services/memory-verification-checks.js +252 -0
  212. package/dist/services/memory-verification-receipt.js +159 -0
  213. package/dist/services/memory-verify-handler.js +135 -0
  214. package/dist/services/memory-work-result-preparation.js +63 -0
  215. package/dist/services/model-catalog.js +109 -0
  216. package/dist/services/model-discovery.js +46 -0
  217. package/dist/services/operator-profiles.js +236 -0
  218. package/dist/services/projects.js +17 -2
  219. package/dist/services/recovery-snapshot-database.js +416 -1
  220. package/dist/services/release-archive-producer.js +52 -0
  221. package/dist/services/release-archive.js +143 -0
  222. package/dist/services/release-cache.js +142 -0
  223. package/dist/services/release-compatibility.js +18 -0
  224. package/dist/services/release-download.js +67 -0
  225. package/dist/services/release-envelope.js +104 -0
  226. package/dist/services/release-manifest.js +45 -0
  227. package/dist/services/release-payload.js +114 -0
  228. package/dist/services/release-producer.js +63 -0
  229. package/dist/services/release-provenance.js +160 -0
  230. package/dist/services/release-registry.js +66 -0
  231. package/dist/services/release-source.js +194 -0
  232. package/dist/services/repair-intents.js +1 -1
  233. package/dist/services/review-copy.js +10 -2
  234. package/dist/services/run-control.js +80 -9
  235. package/dist/services/run-controller-capture.js +10 -3
  236. package/dist/services/run-controller-process.js +21 -0
  237. package/dist/services/run-controller-recovery.js +3 -1
  238. package/dist/services/run-controller-state.js +1 -1
  239. package/dist/services/run-controller.js +101 -40
  240. package/dist/services/run-recovery-guard.js +2 -0
  241. package/dist/services/run-recovery.js +145 -5
  242. package/dist/services/run-start-custody.js +177 -0
  243. package/dist/services/runs.js +319 -25
  244. package/dist/services/setup.js +377 -0
  245. package/dist/services/stage-context.js +9 -1
  246. package/dist/services/stage-handlers.js +74 -0
  247. package/dist/services/stage-report-renderer.js +63 -0
  248. package/dist/services/stage-work-graph.js +17 -0
  249. package/dist/services/vnext-code.js +3 -3
  250. package/dist/services/vnext-execution-profile.js +2 -2
  251. package/dist/services/vnext-fanout.js +70 -9
  252. package/dist/services/vnext-merge.js +8 -3
  253. package/dist/services/vnext-plan-review.js +6 -4
  254. package/dist/services/work-registry.js +616 -71
  255. package/dist/services/workspace-files.js +1 -1
  256. package/dist/storage/database.js +84 -6
  257. package/dist/storage/writer-contract.js +11 -7
  258. package/package.json +13 -3
  259. package/tools/create-canon-release.mjs +33 -0
  260. package/tools/produce-hybrid-release.mjs +41 -0
@@ -3,14 +3,16 @@ import path from "node:path";
3
3
  import { AppError } from "../shared/errors.js";
4
4
  import { resolveProjectRoot } from "../storage/paths.js";
5
5
  import { requireProjectByRoot } from "./projects.js";
6
- import { getFlowRunVariables, appendFlowRunTimelineEvent } from "./runs.js";
6
+ import { getFlowRunVariables, appendFlowRunTimelineEvent, readFlowRunExecutionBundle } from "./runs.js";
7
7
  import { resolveExecutionPolicy } from "./execution-policy.js";
8
- import { listWorks, failWork, cancelWork } from "./work-registry.js";
8
+ import { listWorks, failWork, cancelWork, readWorkBatchCustody } from "./work-registry.js";
9
9
  import { storageSessionId } from "./session-identity.js";
10
10
  import { reconcileUnfinishedChecks } from "./code-checks.js";
11
11
  import { vnextStageDirectory } from "../domain/stage-catalog.js";
12
12
  import { stageWorkIds, stageGraphScope } from "./stage-work-graph.js";
13
13
  import { eligibleCodexChildOverload } from "./codex-capacity.js";
14
+ import { readDescriptorRootWork } from "./descriptor-root-work.js";
15
+ import { selectMemoryCompositionRegistration } from "./memory-composition-registration.js";
14
16
  import { safeNativeFailure } from "../harness-runtime/lib/native-children.mjs";
15
17
  export const subagentCapacityKey = "runtime.subagent.available_slots";
16
18
  /** External concurrency is policy, never evidence of native child qualification. */
@@ -20,17 +22,29 @@ export function getStageFanoutCapacity(context, input) {
20
22
  const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [project.id, input.runId]);
21
23
  if (!run)
22
24
  throw new AppError("not_found", "RUN is unavailable", 1);
23
- const frozen = JSON.parse(run.index_json).execution_profile;
24
- if (frozen?.settings.execution) {
25
+ const index = JSON.parse(run.index_json);
26
+ const bundle = index.execution_bundle ? readFlowRunExecutionBundle(context, { projectRoot, runId: input.runId }) : null;
27
+ const generic = bundle?.execution.work(input.stage).delegation;
28
+ if (generic?.mode === "external")
29
+ return input.nativeOnly
30
+ ? { run_key: null, available_slots: null, source: "harness_qualification" }
31
+ : { run_key: null, available_slots: generic.max_parallel, source: "external_policy" };
32
+ // Generic native admission already requires a scoped capacity receipt whose
33
+ // observed count covers this frozen limit. Mutable legacy variables cannot
34
+ // replace that receipt or silently prevent its productive dispatch.
35
+ if (generic?.mode === "native")
36
+ return { run_key: null, available_slots: generic.max_parallel, source: "harness_qualification" };
37
+ const frozen = index.execution_profile;
38
+ if (!bundle && frozen?.settings.execution) {
25
39
  if (!frozen.agent_profiles)
26
40
  throw new AppError("execution_profile_not_frozen", "Fan-out needs the RUN's frozen profiles", 1);
27
41
  const resolved = resolveExecutionPolicy({ ddFlowHome: context.ddFlowHome, policy: frozen.settings.execution, profiles: frozen.agent_profiles, stage: input.stage });
28
- if (resolved.delegation.mode === "external")
42
+ if (resolved.delegation.mode === "external" && !input.nativeOnly)
29
43
  return { run_key: null, available_slots: resolved.delegation.max_parallel, source: "external_policy" };
30
44
  }
31
45
  const variables = getFlowRunVariables(context, { projectRoot, runId: input.runId });
32
46
  const available = variables.variables[subagentCapacityKey];
33
- return { run_key: subagentCapacityKey, available_slots: typeof available === "number" && Number.isInteger(available) && available >= 0 ? available : null, source: "harness_qualification" };
47
+ return { run_key: subagentCapacityKey, available_slots: typeof available === "number" && Number.isInteger(available) && available >= 0 ? Math.min(available, generic?.max_parallel ?? available) : null, source: "harness_qualification" };
34
48
  }
35
49
  function nativeFailureController(context, projectId, runId, stage, parent) {
36
50
  if (!context.db.get("SELECT 1 FROM sqlite_master WHERE type='table' AND name='run_controllers'"))
@@ -113,17 +127,64 @@ export function readFanoutDescriptor(stageRoot) {
113
127
  }
114
128
  return value;
115
129
  }
130
+ /** Memory graphs are SQL-owned; a mutable/missing fanout.json is not their
131
+ * dispatch authority. Domain registrations and Work launch owners still fence
132
+ * productive assignments, including reviewer/correction waves.
133
+ */
134
+ export function memoryStageFanoutDescriptor(context, input) {
135
+ if (!["compose", "review"].includes(input.stage))
136
+ return null;
137
+ const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
138
+ const run = context.db.get("SELECT flow_kind,index_json FROM runs WHERE project_id=? AND id=?", [project.id, input.runId]);
139
+ if (run?.flow_kind !== "mb-init")
140
+ return null;
141
+ const bundle = readFlowRunExecutionBundle(context, input);
142
+ if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
143
+ throw new AppError("stage_graph_compatibility_required", "Memory graph requires its admitted RUN bundle", 1);
144
+ const index = JSON.parse(run.index_json);
145
+ if (index.current_stage !== input.stage || !index.stage_runs.some(stage => stage.stage === input.stage && stage.status === "running"))
146
+ return null;
147
+ const root = readDescriptorRootWork(context, { projectId: project.id, runId: input.runId }, bundle);
148
+ const scope = stageGraphScope(context, project.id, input.runId, input.stage), members = stageWorkIds(context, project.id, input.runId, input.stage);
149
+ if (root.status !== "running" || !members.has(root.workId))
150
+ throw new AppError("stage_graph_conflict", "Memory graph lost its active coordinator", 1);
151
+ for (const id of members) {
152
+ if (id === root.workId)
153
+ continue;
154
+ const work = context.db.get("SELECT parent_work_id,result_schema FROM works WHERE project_id=? AND run_id=? AND work_id=?", [project.id, input.runId, id]);
155
+ const schemas = input.stage === "compose" ? ["dd-flow/memory-composition-work-result@1"] : ["dd-flow/memory-review-work-result@1", "dd-flow/memory-repair-work-result@1"];
156
+ if (!work || work.parent_work_id !== root.workId || !schemas.includes(work.result_schema ?? ""))
157
+ throw new AppError("stage_graph_conflict", "Memory graph contains an unassigned Work", 1);
158
+ const custody = readWorkBatchCustody(context, id);
159
+ if (custody.scope.project_id !== scope.project_id || custody.scope.run_id !== scope.run_id || custody.scope.attempt !== scope.attempt
160
+ || custody.scope.cycle !== scope.cycle || custody.scope.stage !== input.stage || custody.scope.parent_work_id !== root.workId)
161
+ throw new AppError("stage_graph_conflict", "Memory graph contains foreign allocation custody", 1);
162
+ }
163
+ if (input.stage === "compose") {
164
+ const children = context.db.all("SELECT work_id FROM works WHERE project_id=? AND run_id=? AND parent_work_id=?", [project.id, input.runId, root.workId]).filter(work => members.has(work.work_id));
165
+ const registered = context.db.get("SELECT 1 FROM audit_events WHERE project_id=? AND event_type='memory.composition_registration' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.scope.attempt')=? AND json_extract(payload_json,'$.scope.cycle')=? LIMIT 1", [project.id, input.runId, scope.attempt, scope.cycle]);
166
+ if (children.length || registered) {
167
+ const registration = selectMemoryCompositionRegistration(context, { ...scope, stage: "compose", parent_work_id: root.workId });
168
+ const ids = new Set(Object.values(registration.work_ids));
169
+ if (ids.size !== children.length || children.some(work => !ids.has(work.work_id)))
170
+ throw new AppError("stage_graph_conflict", "Memory composition differs from its registered graph", 1);
171
+ }
172
+ }
173
+ return { schema_id: "dd-flow/work-fanout@2", kind: "work_fanout", scope, stage: input.stage, parent_work_id: root.workId, dispatch: "none", capacity_required: true };
174
+ }
116
175
  /** Read-only projection for an external orchestrator. dd-flow keeps the graph authority. */
117
176
  export function getVnextFanoutStatus(context, input) {
118
177
  const projectRoot = resolveProjectRoot(input.projectRoot);
119
178
  const project = requireProjectByRoot(context, projectRoot);
120
- const run = context.db.get("SELECT run_root FROM runs WHERE project_id = ? AND id = ?", [project.id, input.runId]);
179
+ const run = context.db.get("SELECT run_root, index_json FROM runs WHERE project_id = ? AND id = ?", [project.id, input.runId]);
121
180
  if (!run)
122
181
  throw new AppError("not_found", "RUN is not registered", 1, { run_id: input.runId });
123
182
  if (!run.run_root)
124
183
  throw new AppError("runtime_artifact_missing", "RUN artifact root is unavailable", 1, { run_id: input.runId });
125
- const stageRoot = path.join(run.run_root, vnextStageDirectory(input.stage));
126
- let descriptor = readFanoutDescriptor(stageRoot);
184
+ const index = JSON.parse(run.index_json);
185
+ const bundle = index.execution_bundle ? readFlowRunExecutionBundle(context, { projectRoot, runId: input.runId }) : null;
186
+ const stageRoot = path.join(run.run_root, bundle ? bundle.descriptor.stage(input.stage).directory : vnextStageDirectory(input.stage));
187
+ let descriptor = memoryStageFanoutDescriptor(context, input) ?? readFanoutDescriptor(stageRoot);
127
188
  // Registration is authoritative even if projection publication was interrupted,
128
189
  // or an otherwise review-off stage acquired an aggregate repair graph.
129
190
  if (!descriptor && context.db.get("SELECT 1 FROM sqlite_master WHERE name = 'repair_intents'")) {
@@ -232,6 +232,7 @@ export function applyVnextMerge(context, input) {
232
232
  throw new AppError("merge_apply_receipt_invalid", "Existing merge apply receipt does not match the active request", 1, { receipt_path: receiptFile });
233
233
  return receipt;
234
234
  }
235
+ requireBootstrapCommand(requireRun(context, request.project_id, request.run_id));
235
236
  heartbeatLaneLock(context, { projectRoot: input.projectRoot, lane: "merge", workerId: request.executor_work_id, workspacePath: request.target_workspace, ttlSeconds: 7200 });
236
237
  assertExecutionBaseline(request);
237
238
  input.progress?.(`applying ${request.source_commit} to ${request.target_branch}`);
@@ -316,7 +317,7 @@ export async function finishVnextMerge(context, input, prepared = prepareVnextMe
316
317
  if (failed.length) {
317
318
  context.db.run("UPDATE merge_requests SET status = 'action_required', last_error_json = ?, updated_at = ? WHERE merge_request_id = ?", [JSON.stringify({ code: "merge_gate_failed", failures: failed }), context.now(), request.merge_request_id]);
318
319
  const sourceRepair = failed.every(receipt => checkRepairDisposition(receipt) === "source_repair");
319
- throw new AppError("merge_gate_failed", "Integrated target checks failed. Only assertion-backed failures permit source repair; tooling or unknown evidence requires diagnosis/settlement first.", 2, { failures: failed, ...(sourceRepair ? { repair_command: repairCommand(context, request, projectRoot) } : { outcome: "blocked", recoverable: false }), continuation: { ...recoveryEvidenceInput(run.run_root, failed[0].id), command_after_input: finishCommand(context, run.id, request, projectRoot, failed[0].id) } });
320
+ throw new AppError("merge_gate_failed", "Integrated target checks failed. Only candidate-source-backed failures permit source repair; tooling or unknown evidence requires diagnosis/settlement first.", 2, { failures: failed, ...(sourceRepair ? { repair_command: repairCommand(context, request, projectRoot), continuation: { ...recoveryEvidenceInput(run.run_root, failed[0].id), command_after_input: finishCommand(context, run.id, request, projectRoot, failed[0].id) } } : { outcome: "blocked", recoverable: false }) });
320
321
  }
321
322
  const passedRefs = new Set(receipts.flatMap((receipt) => receipt.check_refs));
322
323
  const missingRefs = frozenGateRefs(gate).filter((ref) => !passedRefs.has(ref));
@@ -567,10 +568,14 @@ function protocolIds(home) { const root = path.join(home, "03-plan"); if (!fs.ex
567
568
  function workspaceRoute(home) { const file = path.join(home, "02-protocolize", "workspace-route.json"); const value = JSON.parse(fs.readFileSync(file, "utf8")); if (!value.policy?.integration_branch)
568
569
  throw new AppError("workspace_route_missing", "MERGE requires the frozen integration branch", 1, { file }); return { integration_branch: value.policy.integration_branch }; }
569
570
  function executionSettings(run) { return JSON.parse(run.index_json).execution_profile?.settings ?? {}; }
570
- async function runBootstrap(context, run, cwd, mergeId, progress) {
571
+ function requireBootstrapCommand(run) {
571
572
  const command = executionSettings(run).code_bootstrap?.command;
572
573
  if (!command)
573
- throw new AppError("execution_profile_invalid", "MERGE requires a frozen workspace bootstrap command", 2);
574
+ throw new AppError("execution_profile_invalid", "MERGE requires an evidenced bootstrap command in the frozen RUN profile; configure code_bootstrap before starting a code-ready RUN", 2);
575
+ return command;
576
+ }
577
+ async function runBootstrap(context, run, cwd, mergeId, progress) {
578
+ const command = requireBootstrapCommand(run);
574
579
  const result = await runWorkspaceBootstrap(context, { projectId: run.project_id, runId: run.id, runHome: requireHome(run), workspaceRoot: cwd, command, artifactDir: `${stageDir}/${mergeId}/readiness`, progress });
575
580
  if (result.exit_code !== 0 || result.error)
576
581
  throw new AppError("merge_bootstrap_failed", "Integrated target bootstrap failed; inspect its retained logs", 2, { command, ...result });
@@ -1,6 +1,6 @@
1
1
  import { managedLifecycleCommand } from "./lifecycle-invocations.js";
2
2
  import crypto from "node:crypto";
3
- import { withStageSettlement, prepareFlowRunStageAttachment, prepareFlowRunStageCompletion } from "./runs.js";
3
+ import { withStageSettlement, prepareFlowRunStageAttachment, prepareFlowRunStageCompletion, readFlowRunExecutionBundle } from "./runs.js";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import { AppError } from "../shared/errors.js";
@@ -132,6 +132,7 @@ export function startVnextPlanReview(context, input, prepared = prepareVnextPlan
132
132
  commitVerificationMatrixStart(context, prepared.matrix, () => attachFlowRunStage(context, attachmentInput, attachment));
133
133
  const reportGit = gitFacts(run.workspace_root);
134
134
  const next = codeSuccessor(context, run.id, projectRoot);
135
+ const completionBundle = readFlowRunExecutionBundle(context, { projectRoot, runId: run.id });
135
136
  return withStageSettlement(context, () => {
136
137
  const registered = addWorkBatch(context, { parentWorkId: rootWork, prepared: prepared.codeItems, stage: "code" });
137
138
  const report = reportFor(context, { run, mode: effective, requested, outcome: "off", groups: [], batchChecksum, planChecksum, code: registered, now, projectRoot, flow: flowCommand(context), git: reportGit, ...(next.command ? { nextCommand: next.command } : {}) });
@@ -141,7 +142,7 @@ export function startVnextPlanReview(context, input, prepared = prepareVnextPlan
141
142
  const preparedReport = prepareStageReport(report);
142
143
  acceptStageReport(context, { projectId: project.id, runId: run.id, stage, root, prepared: preparedReport });
143
144
  const completionInput = { projectRoot, runId: run.id, stage, status: "done", data: "stage-report.json", dataSchemaId: "dd-flow/stage-report@1", report: "stage-report.md", stageReport: "stage-report.html", dataSha256: preparedReport.sha256, git: reportGit };
144
- completeFlowRunStage(context, completionInput, prepareFlowRunStageCompletion(context, completionInput));
145
+ completeFlowRunStage(context, completionInput, prepareFlowRunStageCompletion(context, completionInput, completionBundle));
145
146
  advanceFlowRun(context, { settlementStage: "plan-review", projectRoot, runId: run.id, status: "running", verdict: "plan_review_off", nextAction: "start_code" });
146
147
  appendFlowRunTimelineEvent(context, project.id, run.id, { type: "plan_review_opened", mode: effective, outcome: "off" });
147
148
  return { ok: true, run_id: run.id, stage, outcome: "review_off", ...(externalContext ? { external_context: externalContext } : {}), plan_review: { requested_mode: requested, effective_mode: effective, policy_source: policySource(run), reason: "No applicable independent review group." }, next };
@@ -209,7 +210,7 @@ export function dispatchVnextPlanReview(context, input) {
209
210
  }
210
211
  const created = context.db.all("SELECT work_id, task, status, launch_policy, created_at FROM works WHERE project_id = ? AND run_id = ? AND parent_work_id = ?", [project.id, run.id, parent.work_id]);
211
212
  const reviews = groups.map((group) => { const work = created.find((item) => item.task === group.task); if (!work)
212
- throw new AppError("runtime_missing", "Reviewer Work was not created", 1, { group: group.key }); const ready = work.status === "created" && isReviewWorkReady(context, work.work_id); return { group: group.key, work_id: work.work_id, status: work.status, depends_on: group.depends_on, ready, ...(ready ? { start_command: workStartCommand(context, { ...work, project_id: project.id, run_id: run.id }) } : {}) }; });
213
+ throw new AppError("runtime_missing", "Reviewer Work was not created", 1, { group: group.key }); const ready = work.status === "created" && isReviewWorkReady(context, work.work_id); return { group: group.key, work_id: work.work_id, status: work.status, depends_on: group.depends_on, ready, ...(ready ? { start_command: workStartCommand(context, { ...work, project_id: project.id, run_id: run.id }, { preview: true }) } : {}) }; });
213
214
  refreshRunWorkProjection(context, project.id, run.id);
214
215
  appendFlowRunTimelineEvent(context, project.id, run.id, { type: "plan_review_dispatched", work_id: parent.work_id, groups: reviews.map((item) => ({ group: item.group, work_id: item.work_id })) });
215
216
  const waves = plannedReviewWaves(groups, capacity.availableSlots);
@@ -329,6 +330,7 @@ function finishPlanReviewOwned(context, input) {
329
330
  const reportGit = gitFacts(run.workspace_root);
330
331
  const next = codeSuccessor(context, run.id, projectRoot);
331
332
  const matrix = prepareRunVerificationMatrix(context, { projectId: project.id, runId: run.id, stage, role: "output", semanticFile: decisionPath });
333
+ const completionBundle = readFlowRunExecutionBundle(context, { projectRoot, runId: run.id });
332
334
  return withStageSettlement(context, () => {
333
335
  const registered = addWorkBatch(context, { parentWorkId: codeParentId, prepared: codeItems, stage: "code" });
334
336
  const now = context.now();
@@ -343,7 +345,7 @@ function finishPlanReviewOwned(context, input) {
343
345
  acceptStagePacket(context, { projectId: project.id, runId: run.id, stage, prepared: decisionReceipt });
344
346
  acceptStageReport(context, { projectId: project.id, runId: run.id, stage, root, prepared: preparedReport });
345
347
  const completionInput = { projectRoot, runId: run.id, stage, status: "done", data: "stage-report.json", dataSchemaId: "dd-flow/stage-report@1", report: "stage-report.md", stageReport: "stage-report.html", dataSha256: preparedReport.sha256, git: reportGit };
346
- completeFlowRunStage(context, completionInput, prepareFlowRunStageCompletion(context, completionInput));
348
+ completeFlowRunStage(context, completionInput, prepareFlowRunStageCompletion(context, completionInput, completionBundle));
347
349
  refreshRunWorkProjection(context, project.id, run.id);
348
350
  advanceFlowRun(context, { settlementStage: "plan-review", projectRoot, runId: run.id, status: "running", verdict: "plan_review_accepted", nextAction: "start_code" });
349
351
  appendFlowRunTimelineEvent(context, project.id, run.id, { type: "plan_review_accepted", work_id: parent.work_id, code: registered });