@deksden-com/dd-flow-cli 0.9.0-beta.144 → 0.9.0-beta.149

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 (254) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +13 -8
  3. package/dist/build-info.json +7 -7
  4. package/dist/cli/command-inputs.js +13 -3
  5. package/dist/cli/command-metadata.js +51 -16
  6. package/dist/cli/diagnostic-invocation.js +46 -0
  7. package/dist/cli/diagnostic.js +120 -0
  8. package/dist/cli/help.js +67 -1
  9. package/dist/cli/hook-ingress.js +27 -3
  10. package/dist/cli/memory-flow-admission.js +9 -3
  11. package/dist/cli/memory-init-invocation.js +10 -3
  12. package/dist/cli/memory-init.js +77 -68
  13. package/dist/cli/memory-storage-admission.js +3 -2
  14. package/dist/cli/memory-storage-qualification.js +105 -0
  15. package/dist/cli/memory-storage-transition.js +123 -0
  16. package/dist/cli/memory-upgrade.js +189 -0
  17. package/dist/cli/native-hook-ingress.js +14 -4
  18. package/dist/cli/native-hook-preparation.js +55 -0
  19. package/dist/cli/response-file.js +2 -1
  20. package/dist/cli/run-cli.js +79 -40
  21. package/dist/cli/setup.js +2 -1
  22. package/dist/cli.js +18 -0
  23. package/dist/domain/diagnostic-aspects.js +103 -0
  24. package/dist/domain/diagnostic-flows.js +8 -0
  25. package/dist/domain/stage-handler-identities.js +8 -0
  26. package/dist/harness-runtime/bin/dd-agy.mjs +3 -3
  27. package/dist/harness-runtime/bin/dd-grok.mjs +3 -3
  28. package/dist/harness-runtime/bin/dd-zcode.mjs +5 -5
  29. package/dist/harness-runtime/lib/agy-error-boundary.mjs +58 -0
  30. package/dist/harness-runtime/lib/agy-native-inspection.mjs +216 -0
  31. package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
  32. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  33. package/dist/harness-runtime/lib/daemon-operations.mjs +84 -10
  34. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +366 -52
  35. package/dist/harness-runtime/lib/dd-agy.mjs +17 -3
  36. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +27 -13
  37. package/dist/harness-runtime/lib/dd-codex.mjs +4 -0
  38. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +4 -3
  39. package/dist/harness-runtime/lib/dd-droid.mjs +71 -29
  40. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +73 -16
  41. package/dist/harness-runtime/lib/dd-grok.mjs +6 -3
  42. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +66 -20
  43. package/dist/harness-runtime/lib/dd-opencode.mjs +30 -3
  44. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +7 -6
  45. package/dist/harness-runtime/lib/dd-zcode.mjs +44 -14
  46. package/dist/harness-runtime/lib/delegation-instructions.mjs +1 -1
  47. package/dist/harness-runtime/lib/driver-recovery.mjs +9 -8
  48. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  49. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  50. package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -1
  51. package/dist/harness-runtime/lib/managed-daemon.mjs +24 -9
  52. package/dist/harness-runtime/lib/native-children.d.mts +8 -1
  53. package/dist/harness-runtime/lib/native-children.mjs +114 -8
  54. package/dist/harness-runtime/lib/native-hook-command.mjs +4 -4
  55. package/dist/harness-runtime/lib/native-request-proof.mjs +1 -1
  56. package/dist/harness-runtime/lib/observation-clock.d.mts +2 -2
  57. package/dist/harness-runtime/lib/observation-clock.mjs +7 -4
  58. package/dist/harness-runtime/lib/opencode-plugin.mjs +3 -3
  59. package/dist/harness-runtime/lib/operation-errors.mjs +1 -1
  60. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +5 -3
  61. package/dist/harness-runtime/lib/provider-overload-policy.mjs +20 -7
  62. package/dist/harness-runtime/lib/runner-events.mjs +3 -1
  63. package/dist/harness-runtime/lib/setup-progress.mjs +8 -6
  64. package/dist/harness-runtime/lib/tool-observations.mjs +1 -1
  65. package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
  66. package/dist/schemas/diagnostic-work-result.schema.json +296 -0
  67. package/dist/schemas/execution-bundle.schema.json +7 -1
  68. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  69. package/dist/schemas/memory-repair-work-result.schema.json +9 -2
  70. package/dist/schemas/project-flow-pack-manifest.schema.json +1 -1
  71. package/dist/schemas/release-impact.schema.json +3 -3
  72. package/dist/schemas/stage-start-response.schema.json +4 -0
  73. package/dist/services/accepted-intent.js +13 -1
  74. package/dist/services/canon.js +43 -7
  75. package/dist/services/check-environment.js +21 -0
  76. package/dist/services/check-runner-evidence.js +267 -15
  77. package/dist/services/cli-operation-classifier.js +1 -1
  78. package/dist/services/cli-upgrade-allowlist.js +1 -1
  79. package/dist/services/code-checks.js +34 -19
  80. package/dist/services/compatibility-preflight.js +5 -2
  81. package/dist/services/controller-execution.js +10 -4
  82. package/dist/services/controller-fanout.js +34 -10
  83. package/dist/services/controller-memory-task.js +45 -0
  84. package/dist/services/controller-memory-worker.js +49 -0
  85. package/dist/services/dashboard.js +2 -2
  86. package/dist/services/descriptor-run-settlement.js +5 -3
  87. package/dist/services/descriptor-run-start.js +46 -20
  88. package/dist/services/descriptor-stage-coordinator.js +66 -13
  89. package/dist/services/descriptor-stage-settlement.js +2 -1
  90. package/dist/services/descriptor-stage-start.js +40 -4
  91. package/dist/services/diagnostic-evidence.js +73 -0
  92. package/dist/services/diagnostic-report-publication.js +72 -0
  93. package/dist/services/diagnostic-report.js +67 -0
  94. package/dist/services/diagnostic-run-bundle.js +74 -0
  95. package/dist/services/diagnostic-snapshot.js +159 -0
  96. package/dist/services/diagnostic-stage-handlers.js +108 -0
  97. package/dist/services/diagnostic-stage-results.js +132 -0
  98. package/dist/services/diagnostic-start.js +84 -0
  99. package/dist/services/diagnostic-work-batch.js +34 -0
  100. package/dist/services/diagnostic-work-collection.js +97 -0
  101. package/dist/services/diagnostic-work-registration.js +101 -0
  102. package/dist/services/diagnostic-work-results.js +93 -0
  103. package/dist/services/engines.js +64 -14
  104. package/dist/services/eval-snapshots.js +186 -119
  105. package/dist/services/execution-bundles.js +19 -7
  106. package/dist/services/external-work-launch.js +5 -3
  107. package/dist/services/flow-catalog.js +13 -4
  108. package/dist/services/frozen-engine.js +148 -11
  109. package/dist/services/hook-memory-routing.js +188 -0
  110. package/dist/services/hook-recovery-guard.js +14 -0
  111. package/dist/services/hook-session-observation.js +24 -0
  112. package/dist/services/hooks.js +27 -8
  113. package/dist/services/hybrid-contracts.js +4 -13
  114. package/dist/services/hybrid-digest.js +14 -0
  115. package/dist/services/installed-flow-source.js +47 -4
  116. package/dist/services/lifecycle-invocations.js +179 -38
  117. package/dist/services/memory-accepted-composition.js +5 -4
  118. package/dist/services/memory-completed-correction-wave.js +23 -15
  119. package/dist/services/memory-compose-handler.js +163 -21
  120. package/dist/services/memory-composition-acceptance.js +186 -10
  121. package/dist/services/memory-composition-graph.js +42 -11
  122. package/dist/services/memory-composition-registration.js +23 -8
  123. package/dist/services/memory-composition-work-custody.js +14 -9
  124. package/dist/services/memory-composition-work-results.js +15 -3
  125. package/dist/services/memory-corrected-review-batch.js +10 -3
  126. package/dist/services/memory-corrected-review-findings.js +4 -2
  127. package/dist/services/memory-corrected-review-inputs.js +10 -5
  128. package/dist/services/memory-corrected-review-receipt.js +17 -9
  129. package/dist/services/memory-corrected-review-registration.js +3 -2
  130. package/dist/services/memory-correction-check-receipt.js +20 -4
  131. package/dist/services/memory-custody-snapshot.js +36 -0
  132. package/dist/services/memory-finish-evidence.js +44 -22
  133. package/dist/services/memory-finish-handler.js +37 -23
  134. package/dist/services/memory-finish-integration.js +218 -48
  135. package/dist/services/memory-finish-readiness.js +66 -19
  136. package/dist/services/memory-git-integration.js +87 -18
  137. package/dist/services/memory-historical-corrected-review.js +21 -15
  138. package/dist/services/memory-historical-original-review.js +22 -9
  139. package/dist/services/memory-historical-repair-registration.js +14 -8
  140. package/dist/services/memory-historical-second-review.js +30 -11
  141. package/dist/services/memory-init-contexts.js +44 -2
  142. package/dist/services/memory-init-controller-start.js +27 -8
  143. package/dist/services/memory-init-git-policy.js +50 -21
  144. package/dist/services/memory-init-lint-capability.js +24 -6
  145. package/dist/services/memory-init-native-capacity.js +17 -4
  146. package/dist/services/memory-init-preflight.js +21 -17
  147. package/dist/services/memory-init-request-candidate.js +73 -17
  148. package/dist/services/memory-init-request-input.js +23 -7
  149. package/dist/services/memory-init-run-bundle.js +49 -12
  150. package/dist/services/memory-init-storage.js +17 -7
  151. package/dist/services/memory-init-worktrunk-capability.js +3 -7
  152. package/dist/services/memory-layer.js +71 -6
  153. package/dist/services/memory-lint-config.js +111 -2
  154. package/dist/services/memory-native-review-copy.js +5 -67
  155. package/dist/services/memory-normal-flow-entry.js +12 -0
  156. package/dist/services/memory-ordinary-defaults.js +22 -5
  157. package/dist/services/memory-preflight-handler.js +15 -0
  158. package/dist/services/memory-repair-current-view.js +1 -1
  159. package/dist/services/memory-repair-document-delta.js +70 -33
  160. package/dist/services/memory-repair-history.js +12 -7
  161. package/dist/services/memory-repair-physical-binding.js +1 -119
  162. package/dist/services/memory-repair-publication-plan.js +5 -3
  163. package/dist/services/memory-repair-publication-source.js +1 -1
  164. package/dist/services/memory-repair-publication.js +3 -2
  165. package/dist/services/memory-repair-registration.js +2 -1
  166. package/dist/services/memory-repair-work-baseline.js +4 -2
  167. package/dist/services/memory-repair-work-completion.js +32 -12
  168. package/dist/services/memory-repair-work-results.js +21 -2
  169. package/dist/services/memory-repair-workspace.js +11 -2
  170. package/dist/services/memory-repair-writer-copy.js +2 -1
  171. package/dist/services/memory-result-binding.js +78 -12
  172. package/dist/services/memory-retained-review-authority.js +17 -8
  173. package/dist/services/memory-retained-second-baseline.js +1 -1
  174. package/dist/services/memory-retained-second-repairs.js +12 -6
  175. package/dist/services/memory-review-correction-plan.js +47 -12
  176. package/dist/services/memory-review-handler.js +17 -17
  177. package/dist/services/memory-review-inputs.js +55 -9
  178. package/dist/services/memory-review-limits.js +10 -0
  179. package/dist/services/memory-review-receipt.js +2 -2
  180. package/dist/services/memory-review-registration.js +13 -4
  181. package/dist/services/memory-review-work-custody.js +3 -1
  182. package/dist/services/memory-review-work-input.js +26 -7
  183. package/dist/services/memory-review-work-results.js +26 -4
  184. package/dist/services/memory-second-corrected-review-inputs.js +5 -3
  185. package/dist/services/memory-second-correction-plan.js +2 -1
  186. package/dist/services/memory-second-repair-launch.js +4 -4
  187. package/dist/services/memory-second-repair-source.js +1 -1
  188. package/dist/services/memory-stage-dispatch.js +38 -1
  189. package/dist/services/memory-stage-results.js +113 -22
  190. package/dist/services/memory-tool-probe.js +25 -0
  191. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  192. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  193. package/dist/services/memory-upgrade-evidence.js +100 -0
  194. package/dist/services/memory-upgrade-inventory.js +442 -0
  195. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  196. package/dist/services/memory-upgrade-publication.js +413 -0
  197. package/dist/services/memory-upgrade-selection.js +430 -0
  198. package/dist/services/memory-upgrade-start.js +60 -0
  199. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  200. package/dist/services/memory-verification-acceptance.js +38 -17
  201. package/dist/services/memory-verification-checks.js +92 -27
  202. package/dist/services/memory-verification-receipt.js +6 -5
  203. package/dist/services/memory-verify-handler.js +15 -13
  204. package/dist/services/memory-work-result-json.js +12 -0
  205. package/dist/services/memory-work-result-preparation.js +5 -4
  206. package/dist/services/merge-server.js +4 -2
  207. package/dist/services/migrations.js +127 -98
  208. package/dist/services/native-daemon-history.js +2 -1
  209. package/dist/services/physical-startup.js +45 -0
  210. package/dist/services/project-registry.js +97 -0
  211. package/dist/services/project-summary.js +1 -1
  212. package/dist/services/projects.js +3 -93
  213. package/dist/services/prompt-delivery.js +71 -0
  214. package/dist/services/provider-capacity.js +112 -46
  215. package/dist/services/recovery-snapshot-database.js +32 -4
  216. package/dist/services/release-cache.js +8 -0
  217. package/dist/services/repair-intents.js +1 -12
  218. package/dist/services/repair-receipt.js +13 -0
  219. package/dist/services/run-control-worker.js +35 -18
  220. package/dist/services/run-control.js +2 -1
  221. package/dist/services/run-controller-adapter.js +2 -1
  222. package/dist/services/run-controller-process.js +4 -7
  223. package/dist/services/run-controller-recovery.js +8 -2
  224. package/dist/services/run-controller.js +215 -94
  225. package/dist/services/run-fork.js +1 -1
  226. package/dist/services/run-recovery-guard.js +30 -0
  227. package/dist/services/run-recovery.js +11 -44
  228. package/dist/services/run-start-custody.js +17 -5
  229. package/dist/services/runs.js +6 -1
  230. package/dist/services/runtime-scope-resume.js +12 -6
  231. package/dist/services/runtime-scope-stop.js +3 -2
  232. package/dist/services/runtime-scope-worker.js +46 -19
  233. package/dist/services/runtime-service.js +2 -1
  234. package/dist/services/sessions.js +3 -24
  235. package/dist/services/setup.js +63 -13
  236. package/dist/services/stage-handlers.js +22 -7
  237. package/dist/services/stage-pause.js +111 -44
  238. package/dist/services/version-status.js +1 -1
  239. package/dist/services/vnext-code.js +2 -2
  240. package/dist/services/vnext-fanout.js +51 -9
  241. package/dist/services/vnext-plan-review.js +3 -5
  242. package/dist/services/work-registry.js +117 -39
  243. package/dist/services/workspace-bootstrap.js +2 -1
  244. package/dist/services/workspace-files.js +1 -1
  245. package/dist/shared/entity-references.js +1 -8
  246. package/dist/storage/data-preservation.js +65 -0
  247. package/dist/storage/database.js +53 -19
  248. package/dist/storage/import-guard.js +84 -27
  249. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  250. package/dist/storage/paired-writer-migration.js +424 -0
  251. package/dist/storage/writer-contract.js +11 -4
  252. package/dist/storage/writer-migration.js +313 -52
  253. package/dist/storage/writer-restore.js +217 -0
  254. package/package.json +13 -6
@@ -14,21 +14,46 @@ import { PreparedMemoryBaselinePreservation } from "./memory-baseline-preservati
14
14
  import { readBoundedReleaseFile } from "./release-source.js";
15
15
  import { codeCheckProfileHash, projectPolicyCheckDeclarationsFromProfile, readCodeCheckProfile, runCodeChecks, PreparedCheckEvidence } from "./code-checks.js";
16
16
  import { ObservedMemorySources } from "./memory-source-observations.js";
17
- import { memoryVerificationActivePaths, validateMemoryLintConfig } from "./memory-lint-config.js";
17
+ import { memoryVerificationActivePaths, memoryUpgradeLintGuidance, memoryVerificationSupplementalLintFiles, memoryCanonicalLintExceptions, memoryCanonicalTemplatePaths } from "./memory-lint-config.js";
18
18
  import { isMemoryCorrectionInputOwner } from "./memory-correction-input-owner.js";
19
+ import { readMemoryUpgradeBootstrapReadiness } from "./memory-upgrade-bootstrap-readiness.js";
20
+ import { readUpgradeStorageReadiness } from "./memory-upgrade-storage-readiness.js";
21
+ import { PreparedAcceptedMemoryComposition } from "./memory-accepted-composition.js";
22
+ import { RetainedExecutionBundle } from "./execution-bundles.js";
23
+ import { retainedBrowserEnvironment, validateCheckEnvironment } from "./check-environment.js";
19
24
  const token = Symbol("memory-verification-checks");
20
25
  const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
21
26
  const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
22
27
  const profilePath = ".memory-bank/spec/engineering/code-check-profile.json";
28
+ export function memorySupplementalLintCommand(executable, workspace, files, exceptions = []) {
29
+ const config = JSON.stringify(exceptions.length ? { ignoreFindings: exceptions } : {});
30
+ return `printf '%s\\n' ${quote(config)} > "$DD_FLOW_EVIDENCE_DIR/mb-lint-active-config.json" && ${quote(executable)} --root ${quote(workspace)} --config "$DD_FLOW_EVIDENCE_DIR/mb-lint-active-config.json" --files ${files.map(quote).join(" ")} --format json > "$DD_FLOW_EVIDENCE_DIR/mb-lint-active.json"`;
31
+ }
23
32
  function refuse(reason) {
24
33
  throw new AppError("memory_verification_checks_invalid", "Verification checks lack admitted tool, policy or accepted composition custody", 2, { reason, effect: "no_effect" });
25
34
  }
35
+ /** First introduction adds obligations to mandatory lint; an existing policy
36
+ * remains immutable, including in the next correction wave. */
37
+ export function assertRetainedMemoryVerificationPolicy(previous, current) {
38
+ if (previous !== null && current !== previous)
39
+ refuse("correction_policy_requires_readmission");
40
+ }
26
41
  /** Finite project checks use the original Codex home, never a temporary
27
42
  * provider Session overlay. Keep every other application environment input. */
28
43
  export function memoryCheckEnvironment(context, projectId, runId) {
44
+ let browser = retainedBrowserEnvironment(context.env);
29
45
  if (!context.db.get("SELECT 1 FROM sqlite_schema WHERE type='table' AND name='run_controllers'"))
30
- return undefined;
31
- const controllers = context.db.all("SELECT state_json FROM run_controllers WHERE project_id=? AND run_id=?", [projectId, runId]);
46
+ return browser;
47
+ const controllers = context.db.all("SELECT state_json,manifest_json FROM run_controllers WHERE project_id=? AND run_id=?", [projectId, runId]);
48
+ const retained = new Set(controllers.flatMap(controller => {
49
+ const manifest = JSON.parse(controller.manifest_json);
50
+ const value = validateCheckEnvironment(manifest.check_environment)?.PLAYWRIGHT_BROWSERS_PATH;
51
+ return value === undefined ? [] : [value];
52
+ }));
53
+ if (retained.size > 1)
54
+ refuse("ambiguous_check_browser_resource");
55
+ if (retained.size)
56
+ browser = { PLAYWRIGHT_BROWSERS_PATH: [...retained][0] };
32
57
  const targets = new Set();
33
58
  for (const controller of controllers) {
34
59
  const state = JSON.parse(controller.state_json);
@@ -37,7 +62,7 @@ export function memoryCheckEnvironment(context, projectId, runId) {
37
62
  targets.add(session.codex_home);
38
63
  }
39
64
  if (!targets.size)
40
- return undefined;
65
+ return browser;
41
66
  const current = process.env.CODEX_HOME;
42
67
  if (current && !targets.has(current) && context.db.get("SELECT 1 FROM sqlite_schema WHERE type='table' AND name='work_launches'")) {
43
68
  const launches = context.db.all("SELECT l.state_dir FROM work_launches l JOIN works w ON w.work_id=l.work_id WHERE w.project_id=? AND w.run_id=?", [projectId, runId]);
@@ -60,7 +85,7 @@ export function memoryCheckEnvironment(context, projectId, runId) {
60
85
  const base = [...sources][0];
61
86
  if (current === undefined ? base !== path.join(os.homedir(), ".codex") : current !== base && !targets.has(current))
62
87
  refuse("foreign_check_home");
63
- return { CODEX_HOME: base };
88
+ return { ...browser, CODEX_HOME: base };
64
89
  }
65
90
  function lintConfig(workspace) {
66
91
  const file = path.join(workspace, ".mb-lint.json");
@@ -86,19 +111,29 @@ function accepted(context, input) {
86
111
  }
87
112
  const frozen = input.execution.snapshot(), scope = { requestId: frozen.scope.requestId, projectRoot: frozen.scope.projectRoot, workspaceRoot: frozen.scope.workspace };
88
113
  const run = context.db.get("SELECT workspace_root,project_root,run_root,run_dir,index_json FROM runs WHERE project_id=? AND id=?", [input.projectId, input.runId]);
89
- const bootstrap = readMemoryInitBootstrapReadiness(context, scope), lint = readMemoryInitProjectBootstrapLintCapability(context, scope);
114
+ const upgrade = input.flow.descriptor.id === "mb-upgrade";
115
+ const init = upgrade ? null : readMemoryInitBootstrapReadiness(context, scope);
116
+ const updated = upgrade ? readMemoryUpgradeBootstrapReadiness(context, scope) : null;
117
+ const bootstrap = init ?? updated;
118
+ const lint = upgrade ? updated?.authority.binding.lint ? { facts: updated.authority.binding.lint, sha256: hybridDigest(updated.authority.binding.lint) } : null
119
+ : readMemoryInitProjectBootstrapLintCapability(context, scope);
90
120
  if (!run || run.project_root !== scope.projectRoot || run.workspace_root !== scope.workspaceRoot || !bootstrap || !lint
91
121
  || bootstrap.projectId !== input.projectId || bootstrap.authority.binding.execution_sha256 !== input.execution.sha256)
92
122
  refuse("accepted_bootstrap_scope_required");
93
- const compose = readAcceptedStageData(context, { projectId: input.projectId, runId: input.runId, stage: "compose" });
94
- if (compose.data_schema_id !== "dd-flow/mb-init-compose-result@1")
123
+ const authoring = upgrade ? "upgrade" : "compose";
124
+ const compose = readAcceptedStageData(context, { projectId: input.projectId, runId: input.runId, stage: authoring });
125
+ if (compose.data_schema_id !== (upgrade ? "dd-flow/mb-upgrade-stage-result@1" : "dd-flow/mb-init-compose-result@1"))
95
126
  refuse("accepted_composition_required");
127
+ const baselineProfile = upgrade ? readUpgradeStorageReadiness(context, scope)?.selection?.payload.current.inventory.inventory.entries
128
+ .find(entry => entry.path === profilePath.slice(13))?.current?.sha256 ?? null : null;
96
129
  const active = input.corrected ? "review" : "verify";
97
130
  const { index_json, ...roots } = run, index = JSON.parse(index_json), stage = index.stage_runs.find((stage) => stage.stage === active);
98
131
  if (index.current_stage !== active || stage?.status !== "running" || typeof stage.input_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(stage.input_sha256))
99
132
  refuse(input.corrected ? "active_corrected_review_required" : "active_verification_required");
100
133
  const phase = { attempt: stage.attempt ?? null, cycle: stage.cycle ?? null, input_sha256: stage.input_sha256 };
101
- return { run: roots, bootstrap, lint, compose, scope, authority: hybridDigest({ run: roots, phase, bootstrap: bootstrap.authority, lint, compose: compose.authority_sha256,
134
+ const probe = init?.authority.binding.target.tool_probes?.["mb-lint"] ?? updated?.authority.binding.lint;
135
+ const executable = init?.authority.binding.target.tools["mb-lint"] ?? updated?.authority.binding.lint?.executable;
136
+ return { run: roots, bootstrap, lint, compose, scope, probe, executable, baselineProfile, authority: hybridDigest({ run: roots, phase, bootstrap: bootstrap.authority, lint, compose: compose.authority_sha256,
102
137
  ...(input.corrected ? { corrected_sha256: input.corrected.sha256 } : {}) }) };
103
138
  }
104
139
  /** Owning CLI policy, not agent-proposed commands. The bootstrap-selected
@@ -147,30 +182,52 @@ export class PreparedMemoryVerificationChecks {
147
182
  if (context.db.isOwnedWriteTransaction?.())
148
183
  refuse("preparation_outside_writer_required");
149
184
  if (!(input.execution instanceof FrozenGenericExecution) || !(input.flow instanceof ResolvedFlowDescriptor)
150
- || input.flow.descriptor.id !== "mb-init" || input.execution.settings.flow_id !== "mb-init"
185
+ || !["mb-init", "mb-upgrade"].includes(input.flow.descriptor.id) || input.execution.settings.flow_id !== input.flow.descriptor.id
151
186
  || input.execution.settings.descriptor_sha256 !== input.flow.sha256)
152
187
  refuse("frozen_memory_selection_required");
153
188
  input.corrected?.revalidate(context);
154
189
  const selected = context.db.readSnapshot(() => accepted(context, input)), value = JSON.parse(selected.compose.bytes.toString("utf8"));
155
- const schema = JSON.parse(input.flow.stageBlob("compose", "result_schema").toString("utf8"));
190
+ const upgrade = input.flow.descriptor.id === "mb-upgrade", authoring = upgrade ? "upgrade" : "compose";
191
+ const schema = JSON.parse(input.flow.stageBlob(authoring, "result_schema").toString("utf8"));
156
192
  if (!new Ajv2020({ strict: true, strictRequired: false, validateFormats: false }).compile(schema)(value))
157
193
  refuse("accepted_composition_required");
158
194
  const compose = value;
159
- if (compose.run_id !== input.runId || compose.stage !== "compose" || compose.outcome !== "accepted")
195
+ if (compose.run_id !== input.runId || compose.stage !== authoring || compose.outcome !== "accepted")
160
196
  refuse("accepted_composition_required");
161
- const probe = selected.bootstrap.authority.binding.target.tool_probes?.["mb-lint"];
162
- if (!probe || selected.bootstrap.authority.binding.target.tools["mb-lint"] !== selected.lint.facts.executable
197
+ const probe = selected.probe;
198
+ if (!probe || selected.executable !== selected.lint.facts.executable
163
199
  || probe.executable_sha256 !== selected.lint.facts.executable_sha256 || probe.version !== selected.lint.facts.version
164
200
  || hash(readBoundedReleaseFile(selected.lint.facts.executable, 64 * 1024 * 1024)) !== probe.executable_sha256)
165
201
  refuse("selected_linter_changed");
166
- const preservation = PreparedMemoryBaselinePreservation.prepare(context, input.execution);
202
+ const bundle = input.bundle ?? input.corrected?.bundle();
203
+ if (upgrade && (!(bundle instanceof RetainedExecutionBundle) || bundle.execution.sha256 !== input.execution.sha256 || bundle.descriptor.sha256 !== input.flow.sha256))
204
+ refuse("registered_upgrade_bundle_required");
205
+ if (input.composition && (!(input.composition instanceof PreparedAcceptedMemoryComposition) || input.composition.result().sha256 !== selected.compose.result.sha256))
206
+ refuse("foreign_accepted_composition");
207
+ const preservation = upgrade ? input.corrected ?? input.composition ?? PreparedAcceptedMemoryComposition.prepare(context, { scope: input, bundle: bundle }) : PreparedMemoryBaselinePreservation.prepare(context, input.execution);
167
208
  const workspace = selected.run.workspace_root;
168
209
  const config = lintConfig(workspace);
169
210
  const corrected = input.corrected?.value();
170
- if (config)
171
- validateMemoryLintConfig(config, corrected
172
- ? memoryVerificationActivePaths(corrected.unit_inventory, corrected.assignments)
173
- : memoryVerificationActivePaths(compose.units));
211
+ let guidance;
212
+ let canonicalEntries = [];
213
+ let canonicalFiles = new Map();
214
+ let templates;
215
+ if (upgrade) {
216
+ const storage = readUpgradeStorageReadiness(context, selected.scope);
217
+ if (!storage?.selection)
218
+ refuse("retained_upgrade_inventory_required");
219
+ const diff = readAcceptedStageData(context, { projectId: input.projectId, runId: input.runId, stage: "diff-analysis" });
220
+ guidance = memoryUpgradeLintGuidance(storage.selection.payload.current.inventory.inventory.entries, JSON.parse(diff.bytes.toString("utf8")).details.path_map);
221
+ canonicalEntries = storage.selection.payload.current.inventory.inventory.entries;
222
+ canonicalFiles = new Map(storage.selection.payload.layer.files.map(file => [file.path, Buffer.from(file.base64, "base64")]));
223
+ const current = new Map(canonicalEntries.filter(entry => /^mbb\/templates\/.+\.(?:md|markdown)$/.test(entry.path) && entry.current?.kind === "file" && entry.target && ["canonical", "local-customized"].includes(entry.ownership))
224
+ .map(entry => [entry.path, readBoundedReleaseFile(path.join(workspace, ".memory-bank", entry.path), 64 * 1024 * 1024)]));
225
+ templates = memoryCanonicalTemplatePaths(canonicalEntries, canonicalFiles, current);
226
+ }
227
+ const supplementalFiles = config ? memoryVerificationSupplementalLintFiles(config, corrected
228
+ ? memoryVerificationActivePaths(corrected.unit_inventory, corrected.assignments, guidance, templates)
229
+ : memoryVerificationActivePaths(compose.units, [], guidance, templates)) : [];
230
+ const canonicalExceptions = memoryCanonicalLintExceptions(canonicalEntries, canonicalFiles, supplementalFiles);
174
231
  let observed = null;
175
232
  let exists = false;
176
233
  try {
@@ -183,6 +240,8 @@ export class PreparedMemoryVerificationChecks {
183
240
  }
184
241
  const profileRefs = input.corrected ? input.corrected.value().run_inputs : compose.units.flatMap(unit => unit.artifacts);
185
242
  const expectedProfiles = new Set(profileRefs.filter(artifact => artifact.root === "workspace" && artifact.path === profilePath).map(artifact => artifact.sha256));
243
+ if (upgrade && exists && !expectedProfiles.size && selected.baselineProfile)
244
+ expectedProfiles.add(selected.baselineProfile);
186
245
  if (expectedProfiles.size !== (exists ? 1 : 0))
187
246
  refuse("profile_presence_differs_from_composition");
188
247
  if (exists) {
@@ -194,21 +253,27 @@ export class PreparedMemoryVerificationChecks {
194
253
  const { profile: policy, hash: profileHash } = readCodeCheckProfile(workspace);
195
254
  if (profileHash !== (observed?.hashes().get(`workspace\0${profilePath}`) ?? null))
196
255
  refuse("profile_changed_during_preparation");
197
- const checks = [{ id: "MEMORY/verify/lint-schema-links", canonical_ref: "MEMORY/verify/lint-schema-links",
198
- command: `${quote(selected.lint.facts.executable)} --root ${quote(workspace)} --format json > "$DD_FLOW_EVIDENCE_DIR/mb-lint.json"`,
199
- purpose: "Mandatory bootstrap-selected Memory Bank lint, frontmatter/schema and Markdown target checks", run_at: "readiness", availability: "available", required_artifacts: ["mb-lint.json"], inputs: ["."],
200
- // The pinned linter reads project files/config and invokes Git; provider
201
- // Session configuration is not one of its execution dependencies.
202
- environment_inputs: ["PATH", "PATHEXT", "HOME", "XDG_CONFIG_HOME", "NODE_*", "UV_*", "GIT_*", "LANG", "LC_*", "TZ", "DYLD_*", "LD_*", "SYSTEMROOT", "COMSPEC", "TMPDIR", "TMP", "TEMP"] },
256
+ const lintCheck = { id: "MEMORY/verify/lint-schema-links", canonical_ref: "MEMORY/verify/lint-schema-links",
257
+ command: `${quote(selected.lint.facts.executable)} --root ${quote(workspace)} --format json > "$DD_FLOW_EVIDENCE_DIR/mb-lint.json"`,
258
+ purpose: "Mandatory bootstrap-selected Memory Bank lint, frontmatter/schema and Markdown target checks", run_at: "readiness", availability: "available", required_artifacts: ["mb-lint.json"], inputs: ["."],
259
+ // The pinned linter reads project files/config and invokes Git; provider
260
+ // Session configuration is not one of its execution dependencies.
261
+ environment_inputs: ["PATH", "PATHEXT", "HOME", "XDG_CONFIG_HOME", "NODE_*", "UV_*", "GIT_*", "LANG", "LC_*", "TZ", "DYLD_*", "LD_*", "SYSTEMROOT", "COMSPEC", "TMPDIR", "TMP", "TEMP"] };
262
+ const checks = [lintCheck,
263
+ ...(supplementalFiles.length ? [{ ...lintCheck, id: "MEMORY/verify/lint-active-documents", canonical_ref: "MEMORY/verify/lint-active-documents",
264
+ command: memorySupplementalLintCommand(selected.lint.facts.executable, workspace, supplementalFiles, canonicalExceptions),
265
+ purpose: "Mandatory independent lint of active Markdown excluded by preserved project policy",
266
+ required_artifacts: ["mb-lint-active-config.json", "mb-lint-active.json"] }] : []),
203
267
  ...projectPolicyCheckDeclarationsFromProfile(policy, "readiness")];
204
- if (input.corrected && codeCheckProfileHash(workspace, checks) !== input.corrected.verificationProfileHash(context))
205
- refuse("correction_policy_requires_readmission");
268
+ if (input.corrected)
269
+ assertRetainedMemoryVerificationPolicy(input.corrected.verificationProfileHash(context), codeCheckProfileHash(workspace, checks));
206
270
  const prepared = new PreparedMemoryVerificationChecks(token, input, selected, observed, preservation, checks, config ? hash(config) : null);
207
271
  prepared.#checkEnvironment = memoryCheckEnvironment(context, input.projectId, input.runId);
208
272
  prepared.revalidate(context);
209
273
  return prepared;
210
274
  }
211
275
  declarations() { return structuredClone(this.#checks); }
276
+ profileHash() { return this.#profileSha256; }
212
277
  assertCorrectionOwner(corrected) {
213
278
  if (!isMemoryCorrectionInputOwner(corrected) || this.#input.corrected !== corrected)
214
279
  refuse("foreign_correction_check_owner");
@@ -137,15 +137,16 @@ function accepted(context, scope) {
137
137
  return refuse("invalid_receipt_json");
138
138
  }
139
139
  if (!receipt || typeof receipt !== "object" || Array.isArray(receipt) || hybridDigest({ ...receipt, checks: undefined }) !== hybridDigest({ schema_id: "dd-flow/memory-verification-acceptance@1", run_id: scope.runId, stage: "verify", project_id: scope.projectId,
140
- attempt: selected.attempt, input_sha256: selected.input_sha256, result_sha256: data.result.sha256 }) || data.data_schema_id !== "dd-flow/mb-init-verify-result@1"
140
+ attempt: selected.attempt, input_sha256: selected.input_sha256, result_sha256: data.result.sha256 }) || !["dd-flow/mb-init-verify-result@1", "dd-flow/mb-upgrade-stage-result@1"].includes(data.data_schema_id ?? "")
141
141
  || data.input_sha256 !== selected.input_sha256)
142
142
  refuse("accepted_receipt_changed");
143
143
  const value = JSON.parse(data.bytes.toString("utf8"));
144
- const compose = readAcceptedStageData(context, { ...scope, stage: "compose" }), composed = JSON.parse(compose.bytes.toString("utf8"));
145
- if (compose.data_schema_id !== "dd-flow/mb-init-compose-result@1"
146
- || composed.schema_id !== compose.data_schema_id || composed.stage !== "compose" || composed.run_id !== scope.runId
144
+ const authoring = data.data_schema_id === "dd-flow/mb-upgrade-stage-result@1" ? "upgrade" : "compose";
145
+ const compose = readAcceptedStageData(context, { ...scope, stage: authoring }), composed = JSON.parse(compose.bytes.toString("utf8"));
146
+ if (compose.data_schema_id !== (authoring === "upgrade" ? data.data_schema_id : "dd-flow/mb-init-compose-result@1")
147
+ || composed.schema_id !== compose.data_schema_id || composed.stage !== authoring || composed.run_id !== scope.runId
147
148
  || composed.outcome !== "accepted" || composed.input_sha256 !== compose.input_sha256
148
- || hybridDigest(value.predecessors) !== hybridDigest([{ stage: "compose", result: compose.result, input_sha256: compose.input_sha256 }]))
149
+ || hybridDigest(value.predecessors) !== hybridDigest([{ stage: authoring, result: compose.result, input_sha256: compose.input_sha256 }]))
149
150
  refuse("accepted_predecessor_changed");
150
151
  if (value.stage !== "verify" || value.run_id !== scope.runId || !["accepted", "needs_repair"].includes(value.outcome) || value.input_sha256 !== selected.input_sha256
151
152
  || !Array.isArray(receipt.checks) || receipt.checks.some(reference => !reference || typeof reference !== "object" || Array.isArray(reference)
@@ -24,14 +24,14 @@ function refuse(reason) {
24
24
  */
25
25
  export function runMemoryVerificationChecks(context, input) {
26
26
  const bundle = readFlowRunExecutionBundle(context, input);
27
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.descriptor.successor("compose", "accepted") !== "verify"
27
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) || bundle.descriptor.successor(bundle.descriptor.descriptor.id === "mb-upgrade" ? "upgrade" : "compose", "accepted") !== "verify"
28
28
  || bundle.descriptor.successor("verify", "accepted") !== "review")
29
29
  refuse("registered_memory_bundle_required");
30
30
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
31
31
  const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), index = JSON.parse(run.index_json);
32
32
  if (index.current_stage !== "verify" || index.stage_runs.find((stage) => stage.stage === "verify")?.status !== "running")
33
33
  refuse("active_verification_required");
34
- return PreparedMemoryVerificationChecks.prepare(context, { ...scope, execution: bundle.execution, flow: bundle.descriptor }).execute(context);
34
+ return PreparedMemoryVerificationChecks.prepare(context, { ...scope, execution: bundle.execution, flow: bundle.descriptor, bundle }).execute(context);
35
35
  }
36
36
  /** Productive entry implementation, not registered until the complete six-stage
37
37
  * memory group is ready. Checks and semantic assessment acceptance belong to
@@ -41,22 +41,23 @@ export function startMemoryVerification(context, input) {
41
41
  if (!(input.bytes instanceof Uint8Array) || input.bytes.length > 1024 * 1024)
42
42
  refuse("invalid_input_bytes");
43
43
  const bundle = readFlowRunExecutionBundle(context, input);
44
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.descriptor.successor("compose", "accepted") !== "verify"
44
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) || bundle.descriptor.successor(bundle.descriptor.descriptor.id === "mb-upgrade" ? "upgrade" : "compose", "accepted") !== "verify"
45
45
  || bundle.descriptor.successor("verify", "accepted") !== "review")
46
46
  refuse("registered_memory_bundle_required");
47
47
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId, stage: "verify" };
48
48
  const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), index = JSON.parse(run.index_json);
49
49
  if (index.stage_runs.find((stage) => stage.stage === "verify")?.status === "done")
50
50
  refuse("use_accepted_finish_replay");
51
- const preservation = PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
52
- const inherited = context.db.readSnapshot(() => ({ compose: readAcceptedStageData(context, { ...scope, stage: "compose" }), preflight: readAcceptedStageData(context, { ...scope, stage: "preflight" }) }));
51
+ const upgrade = bundle.descriptor.descriptor.id === "mb-upgrade", authoring = upgrade ? "upgrade" : "compose";
52
+ const preservation = upgrade ? PreparedAcceptedMemoryComposition.prepare(context, { scope, bundle }) : PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
53
+ const inherited = context.db.readSnapshot(() => ({ compose: readAcceptedStageData(context, { ...scope, stage: authoring }), preflight: readAcceptedStageData(context, { ...scope, stage: "preflight" }) }));
53
54
  const compose = JSON.parse(inherited.compose.bytes.toString("utf8")), preflight = JSON.parse(inherited.preflight.bytes.toString("utf8"));
54
- if (compose.schema_id !== "dd-flow/mb-init-compose-result@1" || compose.run_id !== input.runId || compose.outcome !== "accepted"
55
- || preflight.schema_id !== "dd-flow/mb-init-preflight-result@1" || preflight.run_id !== input.runId || preflight.outcome !== "accepted")
55
+ if (compose.schema_id !== (upgrade ? "dd-flow/mb-upgrade-stage-result@1" : "dd-flow/mb-init-compose-result@1") || compose.run_id !== input.runId || compose.outcome !== "accepted"
56
+ || preflight.schema_id !== (upgrade ? compose.schema_id : "dd-flow/mb-init-preflight-result@1") || preflight.run_id !== input.runId || preflight.outcome !== "accepted")
56
57
  refuse("accepted_composition_and_baseline_required");
57
58
  const fence = (writer) => {
58
59
  preservation.assertCustody(writer);
59
- if (readAcceptedStageData(writer, { ...scope, stage: "compose" }).authority_sha256 !== inherited.compose.authority_sha256
60
+ if (readAcceptedStageData(writer, { ...scope, stage: authoring }).authority_sha256 !== inherited.compose.authority_sha256
60
61
  || readAcceptedStageData(writer, { ...scope, stage: "preflight" }).authority_sha256 !== inherited.preflight.authority_sha256)
61
62
  refuse("inherited_custody_changed");
62
63
  };
@@ -75,7 +76,7 @@ export function finishMemoryVerification(context, input) {
75
76
  if (!(input.bytes instanceof Uint8Array) || !input.bytes.length || input.bytes.length > 1024 * 1024)
76
77
  refuse("invalid_result_bytes");
77
78
  const bundle = readFlowRunExecutionBundle(context, input);
78
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.descriptor.successor("compose", "accepted") !== "verify"
79
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) || bundle.descriptor.successor(bundle.descriptor.descriptor.id === "mb-upgrade" ? "upgrade" : "compose", "accepted") !== "verify"
79
80
  || bundle.descriptor.successor("verify", "accepted") !== "review")
80
81
  refuse("registered_memory_bundle_required");
81
82
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
@@ -99,11 +100,11 @@ export function finishMemoryVerification(context, input) {
99
100
  }
100
101
  const composition = PreparedAcceptedMemoryComposition.prepare(context, { scope, bundle }), compose = composition.result();
101
102
  const composedUnits = compose.value().units;
102
- const preservation = PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
103
- const policy = PreparedMemoryVerificationChecks.prepare(context, { ...scope, execution: bundle.execution, flow: bundle.descriptor });
103
+ const preservation = bundle.descriptor.descriptor.id === "mb-upgrade" ? composition : PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
104
+ const policy = PreparedMemoryVerificationChecks.prepare(context, { ...scope, execution: bundle.execution, flow: bundle.descriptor, bundle, composition });
104
105
  const checks = policy.evidence(context, "diagnostic");
105
106
  const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, stage: "verify", flow: bundle.descriptor, execution: bundle.execution, bundle,
106
- sources: composition.captureSources(context, input.bytes, checks), checks });
107
+ sources: composition.captureSources(context, input.bytes, checks), checks, historicalEvidence: composition.historicalEvidence() });
107
108
  let proposal;
108
109
  try {
109
110
  proposal = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.bytes));
@@ -114,7 +115,8 @@ export function finishMemoryVerification(context, input) {
114
115
  }
115
116
  const references = checks.sourceReferences().map(({ path, sha256 }) => ({ path, sha256 }));
116
117
  const result = PreparedMemoryStageResult.prepare(Buffer.from(JSON.stringify(projectMemoryVerificationChecks(projectMemoryVerificationArtifacts(proposal, composedUnits, composition.outputReferences(), createHash("sha256").update(input.bytes).digest("hex")), references, bundle.descriptor.stage("verify").directory, createHash("sha256").update(input.bytes).digest("hex")))), bundle.descriptor, binding.binding());
117
- const acceptance = PreparedMemoryVerificationAcceptance.prepare({ scope, result, compose, checks, composition, roots: bundle.execution.snapshot().scope });
118
+ const acceptance = PreparedMemoryVerificationAcceptance.prepare({ scope, result, compose, checks, composition, roots: bundle.execution.snapshot().scope,
119
+ proposalSha256: createHash("sha256").update(input.bytes).digest("hex") });
118
120
  const receipt = PreparedMemoryVerificationReceipt.prepare(context, { scope, result, checks, acceptance });
119
121
  const settlement = PreparedDescriptorStageSettlement.prepare(context, { ...input, stage: "verify", bytes: result.bytes() });
120
122
  composition.revalidate(context);
@@ -0,0 +1,12 @@
1
+ import { createHash } from "node:crypto";
2
+ import { AppError } from "../shared/errors.js";
3
+ /** Syntax only: the caller still owns bounds, assignment and evidence checks. */
4
+ export function parseMemoryWorkResultProposal(bytes, code) {
5
+ try {
6
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
7
+ }
8
+ catch {
9
+ throw new AppError(code, "Memory result proposal is not valid UTF-8 JSON. Correct only this proposal using its assigned packet; do not rerun settled work or change retained inputs", 2, { reason: "invalid_result_json", phase: "prepare", effect: "no_effect", recoverable: true,
10
+ result_sha256: createHash("sha256").update(bytes).digest("hex") });
11
+ }
12
+ }
@@ -10,7 +10,7 @@ import { restoreMemoryRepairPublicationFromStage, prepareMemorySecondRepairPubli
10
10
  * from worker JSON, mutable schemas, caller profile or a supplied request key.
11
11
  * Preparation is read-only and occurs before the settlement writer.
12
12
  */
13
- export function prepareRegisteredMemoryWorkResult(context, work, result) {
13
+ export function prepareRegisteredMemoryWorkResult(context, work, result, progress) {
14
14
  if (!["dd-flow/memory-composition-work-result@1", "dd-flow/memory-review-work-result@1", "dd-flow/memory-repair-work-result@1"].includes(work.result_schema ?? ""))
15
15
  return null;
16
16
  const bytes = Buffer.from(result, "utf8");
@@ -44,15 +44,16 @@ export function prepareRegisteredMemoryWorkResult(context, work, result) {
44
44
  return PreparedPublishedMemoryRepairWorkResult.prepare(context, publication);
45
45
  }
46
46
  if (work.result_schema === "dd-flow/memory-review-work-result@1") {
47
- return PreparedRegisteredMemoryReviewWorkResult.prepare(context, { workId: work.work_id, bytes });
47
+ return PreparedRegisteredMemoryReviewWorkResult.prepare(context, { workId: work.work_id, bytes, ...(progress ? { progress } : {}) });
48
48
  }
49
49
  const run = context.db.get("SELECT project_root FROM runs WHERE project_id=? AND id=?", [work.project_id, work.run_id]);
50
50
  const bundle = run && readFlowRunExecutionBundle(context, { projectRoot: run.project_root, runId: work.run_id });
51
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
51
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
52
52
  throw new AppError("memory_work_result_preparation_required", "Composition finish requires its retained memory flow", 1, { effect: "no_effect" });
53
+ const stage = bundle.descriptor.descriptor.id === "mb-init" ? "compose" : "upgrade";
53
54
  const custody = readWorkBatchCustody(context, work.work_id);
54
55
  const registration = selectMemoryCompositionRegistration(context, {
55
- project_id: work.project_id, run_id: work.run_id, stage: "compose", attempt: custody.scope.attempt,
56
+ project_id: work.project_id, run_id: work.run_id, stage, attempt: custody.scope.attempt,
56
57
  cycle: custody.scope.cycle, parent_work_id: custody.scope.parent_work_id
57
58
  });
58
59
  return PreparedRegisteredMemoryCompositionWorkResult.prepareFromStageCustody(context, bytes, bundle.engine(), {
@@ -1,6 +1,6 @@
1
1
  import { managedInvocationContext, managedLifecycleCommand } from "./lifecycle-invocations.js";
2
2
  import { stageLifecycleInstruction } from "../harness-runtime/lib/delegation-instructions.mjs";
3
- import { continueProviderCapacity } from "./provider-capacity.js";
3
+ import { continueProviderCapacity, ownedProviderBoundary } from "./provider-capacity.js";
4
4
  import { errorRecord } from "./run-controller-state.js";
5
5
  import crypto from "node:crypto";
6
6
  import fs from "node:fs";
@@ -185,7 +185,9 @@ async function dispatch(context, input) {
185
185
  if (!["created", "running", "paused", "completed"].includes(context.db.get("SELECT status FROM works WHERE work_id = ?", [input.request.executor_work_id])?.status ?? ""))
186
186
  throw new AppError("capacity_continuation_blocked", "MERGE Work has failed or lost its binding", 1);
187
187
  },
188
- decision: () => {
188
+ decision: (boundary) => {
189
+ if (boundary && !ownedProviderBoundary(context, { projectId: input.request.project_id, runId: input.request.run_id, stage: "merge", sessionId, generation, workId: input.request.executor_work_id, scope: "stage" }, boundary))
190
+ return "reconciliation_blocked";
189
191
  const status = context.db.get("SELECT status FROM merge_requests WHERE merge_request_id = ?", [input.request.merge_request_id])?.status;
190
192
  const workStatus = context.db.get("SELECT status FROM works WHERE work_id = ?", [input.request.executor_work_id])?.status;
191
193
  return status === "completed" ? "completed" : status === "action_required" || workStatus === "paused" ? "paused" : "continue";