@deksden-com/dd-flow-cli 0.9.0-beta.143 → 0.9.0-beta.145

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 (197) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +13 -8
  3. package/dist/build-info.json +7 -7
  4. package/dist/cli/command-inputs.js +9 -3
  5. package/dist/cli/command-metadata.js +33 -14
  6. package/dist/cli/help.js +32 -1
  7. package/dist/cli/hook-ingress.js +27 -3
  8. package/dist/cli/memory-flow-admission.js +7 -3
  9. package/dist/cli/memory-init-invocation.js +10 -3
  10. package/dist/cli/memory-init.js +74 -68
  11. package/dist/cli/memory-storage-admission.js +3 -2
  12. package/dist/cli/memory-storage-qualification.js +105 -0
  13. package/dist/cli/memory-storage-transition.js +123 -0
  14. package/dist/cli/memory-upgrade.js +189 -0
  15. package/dist/cli/native-hook-ingress.js +14 -4
  16. package/dist/cli/native-hook-preparation.js +55 -0
  17. package/dist/cli/response-file.js +2 -1
  18. package/dist/cli/run-cli.js +70 -32
  19. package/dist/cli/setup.js +2 -1
  20. package/dist/cli.js +12 -0
  21. package/dist/domain/stage-handler-identities.js +8 -0
  22. package/dist/harness-runtime/bin/dd-agy.mjs +3 -3
  23. package/dist/harness-runtime/bin/dd-grok.mjs +3 -3
  24. package/dist/harness-runtime/bin/dd-zcode.mjs +5 -5
  25. package/dist/harness-runtime/lib/agy-error-boundary.mjs +58 -0
  26. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +62 -20
  27. package/dist/harness-runtime/lib/dd-agy.mjs +17 -3
  28. package/dist/harness-runtime/lib/dd-droid.mjs +1 -1
  29. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +70 -13
  30. package/dist/harness-runtime/lib/dd-grok.mjs +6 -3
  31. package/dist/harness-runtime/lib/dd-zcode.mjs +44 -14
  32. package/dist/harness-runtime/lib/delegation-instructions.mjs +1 -1
  33. package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
  34. package/dist/harness-runtime/lib/entity-references.mjs +9 -0
  35. package/dist/harness-runtime/lib/managed-daemon.mjs +13 -6
  36. package/dist/harness-runtime/lib/native-hook-command.mjs +4 -4
  37. package/dist/harness-runtime/lib/opencode-plugin.mjs +3 -3
  38. package/dist/harness-runtime/lib/operation-errors.mjs +1 -1
  39. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +4 -2
  40. package/dist/harness-runtime/lib/provider-overload-policy.mjs +19 -6
  41. package/dist/harness-runtime/lib/runner-events.mjs +3 -1
  42. package/dist/harness-runtime/lib/setup-progress.mjs +8 -6
  43. package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
  44. package/dist/schemas/memory-repair-work-result.schema.json +9 -2
  45. package/dist/schemas/release-impact.schema.json +3 -3
  46. package/dist/schemas/stage-start-response.schema.json +4 -0
  47. package/dist/services/accepted-intent.js +13 -1
  48. package/dist/services/canon.js +43 -7
  49. package/dist/services/cli-operation-classifier.js +1 -1
  50. package/dist/services/cli-upgrade-allowlist.js +1 -1
  51. package/dist/services/code-checks.js +11 -4
  52. package/dist/services/compatibility-preflight.js +5 -2
  53. package/dist/services/controller-fanout.js +21 -4
  54. package/dist/services/controller-memory-task.js +45 -0
  55. package/dist/services/controller-memory-worker.js +48 -0
  56. package/dist/services/dashboard.js +2 -2
  57. package/dist/services/descriptor-run-start.js +26 -19
  58. package/dist/services/descriptor-stage-coordinator.js +30 -10
  59. package/dist/services/descriptor-stage-start.js +40 -4
  60. package/dist/services/engines.js +64 -14
  61. package/dist/services/eval-snapshots.js +104 -93
  62. package/dist/services/external-work-launch.js +5 -3
  63. package/dist/services/flow-catalog.js +8 -4
  64. package/dist/services/frozen-engine.js +113 -11
  65. package/dist/services/hook-memory-routing.js +188 -0
  66. package/dist/services/hook-recovery-guard.js +14 -0
  67. package/dist/services/hook-session-observation.js +24 -0
  68. package/dist/services/hooks.js +27 -8
  69. package/dist/services/hybrid-contracts.js +2 -13
  70. package/dist/services/hybrid-digest.js +14 -0
  71. package/dist/services/installed-flow-source.js +25 -4
  72. package/dist/services/lifecycle-invocations.js +33 -5
  73. package/dist/services/memory-accepted-composition.js +5 -4
  74. package/dist/services/memory-completed-correction-wave.js +23 -15
  75. package/dist/services/memory-compose-handler.js +163 -21
  76. package/dist/services/memory-composition-acceptance.js +186 -10
  77. package/dist/services/memory-composition-graph.js +42 -11
  78. package/dist/services/memory-composition-registration.js +23 -8
  79. package/dist/services/memory-composition-work-custody.js +14 -9
  80. package/dist/services/memory-composition-work-results.js +15 -3
  81. package/dist/services/memory-corrected-review-batch.js +10 -3
  82. package/dist/services/memory-corrected-review-findings.js +4 -2
  83. package/dist/services/memory-corrected-review-inputs.js +10 -5
  84. package/dist/services/memory-corrected-review-receipt.js +17 -9
  85. package/dist/services/memory-corrected-review-registration.js +3 -2
  86. package/dist/services/memory-correction-check-receipt.js +20 -4
  87. package/dist/services/memory-custody-snapshot.js +36 -0
  88. package/dist/services/memory-finish-evidence.js +44 -22
  89. package/dist/services/memory-finish-handler.js +37 -23
  90. package/dist/services/memory-finish-integration.js +218 -48
  91. package/dist/services/memory-finish-readiness.js +66 -19
  92. package/dist/services/memory-git-integration.js +87 -18
  93. package/dist/services/memory-historical-corrected-review.js +21 -15
  94. package/dist/services/memory-historical-original-review.js +22 -9
  95. package/dist/services/memory-historical-repair-registration.js +14 -8
  96. package/dist/services/memory-historical-second-review.js +30 -11
  97. package/dist/services/memory-init-contexts.js +28 -2
  98. package/dist/services/memory-init-controller-start.js +19 -8
  99. package/dist/services/memory-init-git-policy.js +50 -21
  100. package/dist/services/memory-init-lint-capability.js +21 -3
  101. package/dist/services/memory-init-native-capacity.js +13 -0
  102. package/dist/services/memory-init-preflight.js +11 -1
  103. package/dist/services/memory-init-request-candidate.js +73 -17
  104. package/dist/services/memory-init-request-input.js +23 -7
  105. package/dist/services/memory-init-run-bundle.js +49 -12
  106. package/dist/services/memory-init-storage.js +17 -7
  107. package/dist/services/memory-layer.js +68 -4
  108. package/dist/services/memory-lint-config.js +111 -2
  109. package/dist/services/memory-native-review-copy.js +5 -67
  110. package/dist/services/memory-normal-flow-entry.js +12 -0
  111. package/dist/services/memory-ordinary-defaults.js +22 -5
  112. package/dist/services/memory-preflight-handler.js +15 -0
  113. package/dist/services/memory-repair-current-view.js +1 -1
  114. package/dist/services/memory-repair-document-delta.js +70 -33
  115. package/dist/services/memory-repair-history.js +12 -7
  116. package/dist/services/memory-repair-physical-binding.js +1 -119
  117. package/dist/services/memory-repair-publication-plan.js +5 -3
  118. package/dist/services/memory-repair-publication-source.js +1 -1
  119. package/dist/services/memory-repair-publication.js +3 -2
  120. package/dist/services/memory-repair-registration.js +2 -1
  121. package/dist/services/memory-repair-work-baseline.js +4 -2
  122. package/dist/services/memory-repair-work-completion.js +32 -12
  123. package/dist/services/memory-repair-work-results.js +21 -2
  124. package/dist/services/memory-repair-workspace.js +11 -2
  125. package/dist/services/memory-repair-writer-copy.js +2 -1
  126. package/dist/services/memory-result-binding.js +78 -12
  127. package/dist/services/memory-retained-review-authority.js +17 -8
  128. package/dist/services/memory-retained-second-baseline.js +1 -1
  129. package/dist/services/memory-retained-second-repairs.js +12 -6
  130. package/dist/services/memory-review-correction-plan.js +47 -12
  131. package/dist/services/memory-review-handler.js +17 -17
  132. package/dist/services/memory-review-inputs.js +55 -9
  133. package/dist/services/memory-review-limits.js +10 -0
  134. package/dist/services/memory-review-receipt.js +2 -2
  135. package/dist/services/memory-review-registration.js +13 -4
  136. package/dist/services/memory-review-work-custody.js +3 -1
  137. package/dist/services/memory-review-work-input.js +26 -7
  138. package/dist/services/memory-review-work-results.js +26 -4
  139. package/dist/services/memory-second-corrected-review-inputs.js +5 -3
  140. package/dist/services/memory-second-correction-plan.js +2 -1
  141. package/dist/services/memory-second-repair-launch.js +4 -4
  142. package/dist/services/memory-second-repair-source.js +1 -1
  143. package/dist/services/memory-stage-dispatch.js +38 -1
  144. package/dist/services/memory-stage-results.js +113 -22
  145. package/dist/services/memory-upgrade-analysis-handler.js +243 -0
  146. package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
  147. package/dist/services/memory-upgrade-evidence.js +100 -0
  148. package/dist/services/memory-upgrade-inventory.js +442 -0
  149. package/dist/services/memory-upgrade-publication-custody.js +73 -0
  150. package/dist/services/memory-upgrade-publication.js +413 -0
  151. package/dist/services/memory-upgrade-selection.js +430 -0
  152. package/dist/services/memory-upgrade-start.js +60 -0
  153. package/dist/services/memory-upgrade-storage-readiness.js +340 -0
  154. package/dist/services/memory-verification-acceptance.js +38 -17
  155. package/dist/services/memory-verification-checks.js +77 -23
  156. package/dist/services/memory-verification-receipt.js +6 -5
  157. package/dist/services/memory-verify-handler.js +15 -13
  158. package/dist/services/memory-work-result-json.js +12 -0
  159. package/dist/services/memory-work-result-preparation.js +5 -4
  160. package/dist/services/merge-server.js +4 -2
  161. package/dist/services/migrations.js +127 -98
  162. package/dist/services/physical-startup.js +45 -0
  163. package/dist/services/project-registry.js +97 -0
  164. package/dist/services/project-summary.js +1 -1
  165. package/dist/services/projects.js +3 -93
  166. package/dist/services/prompt-delivery.js +71 -0
  167. package/dist/services/provider-capacity.js +74 -9
  168. package/dist/services/recovery-snapshot-database.js +32 -4
  169. package/dist/services/repair-intents.js +1 -12
  170. package/dist/services/repair-receipt.js +13 -0
  171. package/dist/services/run-control-worker.js +35 -18
  172. package/dist/services/run-controller-process.js +2 -6
  173. package/dist/services/run-controller-recovery.js +6 -1
  174. package/dist/services/run-controller.js +131 -80
  175. package/dist/services/run-recovery-guard.js +30 -0
  176. package/dist/services/run-recovery.js +11 -44
  177. package/dist/services/run-start-custody.js +17 -5
  178. package/dist/services/runtime-scope-worker.js +46 -19
  179. package/dist/services/sessions.js +3 -24
  180. package/dist/services/setup.js +63 -13
  181. package/dist/services/stage-handlers.js +9 -7
  182. package/dist/services/stage-pause.js +108 -44
  183. package/dist/services/version-status.js +1 -1
  184. package/dist/services/vnext-fanout.js +21 -9
  185. package/dist/services/vnext-plan-review.js +3 -5
  186. package/dist/services/work-registry.js +80 -33
  187. package/dist/services/workspace-files.js +1 -1
  188. package/dist/shared/entity-references.js +1 -8
  189. package/dist/storage/data-preservation.js +65 -0
  190. package/dist/storage/database.js +53 -19
  191. package/dist/storage/import-guard.js +84 -27
  192. package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
  193. package/dist/storage/paired-writer-migration.js +424 -0
  194. package/dist/storage/writer-contract.js +11 -4
  195. package/dist/storage/writer-migration.js +313 -52
  196. package/dist/storage/writer-restore.js +217 -0
  197. package/package.json +8 -4
@@ -1,6 +1,7 @@
1
1
  import { AppError } from "../shared/errors.js";
2
2
  import { hybridDigest } from "./hybrid-contracts.js";
3
3
  import { PreparedCompletedMemoryCorrectionWave } from "./memory-completed-correction-wave.js";
4
+ import { isCompletedMemoryRepairClaim } from "./memory-repair-work-results.js";
4
5
  import { ObservedMemorySources } from "./memory-source-observations.js";
5
6
  import { memorySourceKey } from "./memory-stage-results.js";
6
7
  import { assertPreparedRunBundleSqlAuthority } from "./runs.js";
@@ -9,6 +10,7 @@ import { RetainedExecutionBundle } from "./execution-bundles.js";
9
10
  import { PreparedRetainedMemoryReviewAuthority } from "./memory-retained-review-authority.js";
10
11
  import { PreparedRetainedMemoryReviewResults } from "./memory-retained-review-results.js";
11
12
  import { PreparedRegisteredMemoryCorrections } from "./memory-repair-registration.js";
13
+ import { memoryReviewViewWithinLimit } from "./memory-review-limits.js";
12
14
  const token = Symbol("corrected-memory-review-inputs");
13
15
  function refuse(reason) {
14
16
  throw new AppError("memory_corrected_review_input_invalid", "Re-review inputs lack settled corrections and current source custody", 2, { reason, effect: "no_effect" });
@@ -46,9 +48,8 @@ export function correctedMemoryReviewAssignments(input) {
46
48
  const finalProof = new Map();
47
49
  for (const repair of input.repairs) {
48
50
  reference(repair.reference.path, repair.reference.sha256, "run");
49
- if (repair.result.outcome !== "accepted" || !Array.isArray(repair.unit_ids) || !repair.unit_ids.length
50
- || repair.unit_ids.some((id) => !input.units.some(unit => unit.id === id && unit.applicability === "applicable"))
51
- || !Array.isArray(repair.result.changes) || !repair.result.changes.length)
51
+ if (!isCompletedMemoryRepairClaim(repair.result) || !Array.isArray(repair.unit_ids) || !repair.unit_ids.length
52
+ || repair.unit_ids.some((id) => !input.units.some(unit => unit.id === id && unit.applicability === "applicable")))
52
53
  refuse("invalid_repair_projection");
53
54
  for (const change of repair.result.changes) {
54
55
  reference(change.path, change.after_sha256 ?? change.before_sha256);
@@ -97,6 +98,9 @@ export function correctedMemoryReviewAssignments(input) {
97
98
  unit.artifacts.push({ ...current });
98
99
  }
99
100
  const inputs = new Map();
101
+ for (const ref of input.initialAssignments?.find(item => item.unit.id === original.id)?.inputs ?? [])
102
+ if (ref.root === "run" && /^upgrade-baseline-[a-f0-9]{64}\.bin$/.test(ref.path))
103
+ inputs.set(memorySourceKey(ref.root, ref.path), { ...ref });
100
104
  for (const ref of [...unit.evidence, ...unit.artifacts, ...input.repairs.map(repair => reference(repair.reference.path, repair.reference.sha256, "run"))]) {
101
105
  const physical = reference(ref.root === "canon" ? `.memory-bank/${ref.path}` : ref.path, ref.sha256, ref.root === "run" ? "run" : "workspace");
102
106
  const key = memorySourceKey(physical.root, physical.path), prior = inputs.get(key);
@@ -151,7 +155,7 @@ export class PreparedCorrectedMemoryReviewInputs {
151
155
  return prepared;
152
156
  }
153
157
  static prepareFromBundle(context, input) {
154
- if (!(input.bundle instanceof RetainedExecutionBundle) || input.bundle.descriptor.descriptor.id !== "mb-init")
158
+ if (!(input.bundle instanceof RetainedExecutionBundle) || !["mb-init", "mb-upgrade"].includes(input.bundle.descriptor.descriptor.id))
155
159
  refuse("registered_memory_bundle_required");
156
160
  const original = PreparedRetainedMemoryReviewAuthority.prepare(context, input.scope, input.bundle);
157
161
  const review = PreparedRetainedMemoryReviewResults.prepare(context, original);
@@ -203,8 +207,9 @@ function prepareView(wave) {
203
207
  completed_correction_sha256: wave.sha256, original_review_sha256: review.sha256,
204
208
  source_policy: "review-inputs@1", source_sha256: source, base: original.base, run_inputs: runInputs,
205
209
  unit_inventory: structuredClone(original.unit_inventory), affected_unit_ids: wave.affectedUnitIds(), assignments,
210
+ ...(original.upgrade_baseline ? { upgrade_baseline: structuredClone(original.upgrade_baseline), preservation_invariants: structuredClone(original.preservation_invariants ?? []) } : {}),
206
211
  instruction: structuredClone(original.instruction), repairs: repairs.map(repair => ({ work_id: repair.work_id, authority_sha256: repair.authority_sha256, result: repair.reference })) };
207
- if (Buffer.byteLength(JSON.stringify(view)) > 1024 * 1024)
212
+ if (!memoryReviewViewWithinLimit(view))
208
213
  refuse("unbounded_corrected_view");
209
214
  return view;
210
215
  }
@@ -1,3 +1,4 @@
1
+ import { assertMemorySqlCustody } from "./memory-custody-snapshot.js";
1
2
  import { AppError } from "../shared/errors.js";
2
3
  import { appendAudit } from "./audit.js";
3
4
  import { hybridDigest } from "./hybrid-contracts.js";
@@ -81,7 +82,7 @@ export class PreparedMemoryCorrectedReviewReceipt {
81
82
  refuse("receipt_readback_failed");
82
83
  }
83
84
  }
84
- function acceptedReceipt(context, scope) {
85
+ function acceptedReceipt(context, scope, flowId) {
85
86
  const data = readAcceptedStageData(context, { ...scope, stage: "review" }), rows = records(context, scope);
86
87
  if (rows.length !== 1 || Buffer.byteLength(rows[0].payload_json) > 2 * 1024 * 1024)
87
88
  refuse("accepted_receipt_missing");
@@ -99,7 +100,7 @@ function acceptedReceipt(context, scope) {
99
100
  || !/^[a-f0-9]{64}$/.test(retained.first_review_proof_sha256)))
100
101
  || typeof retained.corrected_input_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(retained.corrected_input_sha256)
101
102
  || typeof retained.check_receipt_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(retained.check_receipt_sha256)
102
- || data.data_schema_id !== "dd-flow/mb-init-review-result@1" || retained.result_sha256 !== data.result.sha256
103
+ || data.data_schema_id !== (flowId === "mb-upgrade" ? "dd-flow/mb-upgrade-stage-result@1" : "dd-flow/mb-init-review-result@1") || retained.result_sha256 !== data.result.sha256
103
104
  || retained.input_sha256 !== data.input_sha256)
104
105
  refuse("accepted_receipt_changed");
105
106
  return { data, retained, authority: hybridDigest({ data: data.authority_sha256, receipt: retained }) };
@@ -109,24 +110,27 @@ function acceptedReceipt(context, scope) {
109
110
  * commit: generic settlement restores it; reviewers/checks/repairs may not be
110
111
  * substituted or re-admitted from today's project policy or documents. */
111
112
  export class PreparedAcceptedMemoryCorrectedReview {
113
+ #custodyKey = {};
112
114
  #scope;
113
115
  #authority;
114
116
  #history;
115
- constructor(key, scope, authority, history) {
117
+ #flowId;
118
+ constructor(key, scope, authority, history, flowId) {
116
119
  if (key !== token)
117
120
  refuse("receipt_token_required");
118
121
  this.#scope = { ...scope };
119
122
  this.#authority = authority;
120
123
  this.#history = history;
124
+ this.#flowId = flowId;
121
125
  Object.freeze(this);
122
126
  }
123
127
  static prepare(context, input) {
124
- if (!(input.bundle instanceof RetainedExecutionBundle) || input.bundle.descriptor.descriptor.id !== "mb-init"
128
+ if (!(input.bundle instanceof RetainedExecutionBundle) || !["mb-init", "mb-upgrade"].includes(input.bundle.descriptor.descriptor.id)
125
129
  || !(input.bytes instanceof Uint8Array) || !input.bytes.length || input.bytes.length > 1024 * 1024)
126
130
  refuse("registered_memory_result_required");
127
131
  if (context.db.isOwnedWriteTransaction?.())
128
132
  refuse("preparation_outside_writer_required");
129
- const accepted = context.db.readSnapshot(() => acceptedReceipt(context, input.scope));
133
+ const accepted = context.db.readSnapshot(() => acceptedReceipt(context, input.scope, input.bundle.descriptor.descriptor.id));
130
134
  if (!accepted.data.bytes.equals(Buffer.from(input.bytes)))
131
135
  refuse("accepted_result_bytes_changed");
132
136
  const hashes = { correctedInputSha256: accepted.retained.corrected_input_sha256, checkReceiptSha256: accepted.retained.check_receipt_sha256 };
@@ -151,20 +155,24 @@ export class PreparedAcceptedMemoryCorrectedReview {
151
155
  const schema = JSON.parse(input.bundle.descriptor.stageBlob("review", "result_schema").toString("utf8"));
152
156
  if (!new Ajv2020({ strict: true, strictRequired: false, validateFormats: false }).compile(schema)(value))
153
157
  refuse("accepted_result_schema_changed");
154
- const prepared = new PreparedAcceptedMemoryCorrectedReview(token, input.scope, accepted.authority, history);
158
+ const prepared = new PreparedAcceptedMemoryCorrectedReview(token, input.scope, accepted.authority, history, input.bundle.descriptor.descriptor.id);
155
159
  prepared.revalidate(context);
156
160
  return prepared;
157
161
  }
158
162
  assertCustody(context) {
159
- this.#history.assertCustody(context);
160
- if (acceptedReceipt(context, this.#scope).authority !== this.#authority)
161
- refuse("accepted_review_custody_changed");
163
+ const history = this.#history;
164
+ assertMemorySqlCustody(context, this.#custodyKey, () => {
165
+ history.assertCustody(context);
166
+ if (acceptedReceipt(context, this.#scope, this.#flowId).authority !== this.#authority)
167
+ refuse("accepted_review_custody_changed");
168
+ });
162
169
  }
163
170
  /** Final wave inputs selected by the independently accepted receipt. */
164
171
  reviewedSources(context) {
165
172
  this.assertCustody(context);
166
173
  return this.#history.retainedInputView().run_inputs;
167
174
  }
175
+ settledDocumentBaseline(context) { this.assertCustody(context); return this.#history.settledDocumentBaseline(); }
168
176
  finalChecks(context) { this.assertCustody(context); return this.#history.finalChecks(context); }
169
177
  revalidate(context) { this.#history.revalidate(context); this.assertCustody(context); }
170
178
  }
@@ -6,6 +6,7 @@ import { isMemoryCorrectionInputOwner } from "./memory-correction-input-owner.js
6
6
  import { PreparedMemoryCorrectionCheckReceipt } from "./memory-correction-check-receipt.js";
7
7
  import { memoryCorrectedReviewBatch } from "./memory-corrected-review-batch.js";
8
8
  import { addWorkBatch, prepareWorkBatch, readWorkBatchCustody } from "./work-registry.js";
9
+ import { memoryReviewRegistrationByteLimit } from "./memory-review-limits.js";
9
10
  const token = Symbol("registered-corrected-memory-review");
10
11
  const event = "memory.corrected_review_registration";
11
12
  function refuse(reason) {
@@ -40,7 +41,7 @@ function readRetainedRegistration(context, scope, inputSha256, checkReceiptSha25
40
41
  const rows = context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type=? AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.scope.attempt')=? AND json_extract(payload_json,'$.scope.parent_work_id')=? AND json_extract(payload_json,'$.wave')=? LIMIT 2", [scope.project_id, event, scope.run_id, scope.attempt, scope.parent_work_id, wave]);
41
42
  if (!rows.length)
42
43
  return null;
43
- if (rows.length !== 1 || Buffer.byteLength(rows[0].payload_json) > 2 * 1024 * 1024)
44
+ if (rows.length !== 1 || Buffer.byteLength(rows[0].payload_json) > memoryReviewRegistrationByteLimit)
44
45
  refuse("ambiguous_or_unbounded_registration");
45
46
  let receipt;
46
47
  try {
@@ -171,7 +172,7 @@ export function registerCorrectedMemoryReview(context, inputs, checks) {
171
172
  refuse("review_registration_missing");
172
173
  const receipt = { schema_id: "dd-flow/memory-corrected-review-registration@1", run_id: scope.run_id, scope: view.scope, wave: view.wave,
173
174
  input_sha256: inputs.sha256, view, check_receipt_sha256: checks.sha256, batch_sha256: hybridDigest(batch.works), work_ids: ids };
174
- if (Buffer.byteLength(JSON.stringify(receipt)) > 2 * 1024 * 1024)
175
+ if (Buffer.byteLength(JSON.stringify(receipt)) > memoryReviewRegistrationByteLimit)
175
176
  refuse("unbounded_registration");
176
177
  appendAudit(context, { projectId: scope.project_id, eventType: event, payload: receipt });
177
178
  }
@@ -65,7 +65,7 @@ export class PreparedMemoryCorrectionCheckReceipt {
65
65
  evidence.assertOwner({ projectId: view.scope.project_id, runId: view.scope.run_id, scope: "aggregate" });
66
66
  const receipt = { schema_id: "dd-flow/memory-correction-checks@1", project_id: view.scope.project_id, run_id: view.scope.run_id,
67
67
  wave: view.wave, review_input_sha256: view.scope.input_sha256, corrected_input_sha256: corrected.sha256,
68
- completed_correction_sha256: view.completed_correction_sha256, profile_sha256: corrected.verificationProfileHash(context),
68
+ completed_correction_sha256: view.completed_correction_sha256, profile_sha256: policy.profileHash(),
69
69
  declarations_sha256: hybridDigest(policy.declarations()), checks: evidence.retainedReferences(context) };
70
70
  if (!receipt.checks.length || receipt.checks.length > 4096 || Buffer.byteLength(JSON.stringify(receipt)) > 2 * 1024 * 1024)
71
71
  refuse("unbounded_check_receipt");
@@ -81,7 +81,8 @@ export class PreparedMemoryCorrectionCheckReceipt {
81
81
  refuse("prepared_check_owners_required");
82
82
  if (context.db.isOwnedWriteTransaction?.())
83
83
  refuse("preparation_outside_writer_required");
84
- if (!context.db.readSnapshot(() => stored(context, corrected))) {
84
+ const existing = context.db.readSnapshot(() => stored(context, corrected));
85
+ if (!existing) {
85
86
  const view = corrected.value(), projectRoot = corrected.bundle().execution.snapshot().scope.projectRoot;
86
87
  const args = ["--run", view.scope.run_id, "--project-root", projectRoot, "--wave", String(view.wave), "--json"];
87
88
  throw new AppError("memory_correction_checks_invalid", "Correction checks have not been registered for the settled corrected view", 2, { reason: "registered_check_receipt_required", phase: "prepare", effect: "no_effect", recoverable: true,
@@ -90,7 +91,22 @@ export class PreparedMemoryCorrectionCheckReceipt {
90
91
  const bundle = corrected.bundle(), scope = corrected.value().scope;
91
92
  const policy = PreparedMemoryVerificationChecks.prepare(context, { projectId: scope.project_id, runId: scope.run_id,
92
93
  execution: bundle.execution, flow: bundle.descriptor, corrected });
93
- return PreparedMemoryCorrectionCheckReceipt.prepare(context, corrected, policy);
94
+ // Registered execution belongs to its original environment, not the
95
+ // controller/reviewer's current shell. Keep exact current document and
96
+ // policy custody, then restore the sealed execution instead of selecting
97
+ // fresh evidence using the observer's environment.
98
+ const view = corrected.value(), receipt = historicalReceipt(context, { projectId: scope.project_id, runId: scope.run_id,
99
+ wave: view.wave, receiptSha256: hybridDigest(existing), correctedInputSha256: corrected.sha256 });
100
+ const expected = { schema_id: "dd-flow/memory-correction-checks@1", project_id: scope.project_id, run_id: scope.run_id,
101
+ wave: view.wave, review_input_sha256: scope.input_sha256, corrected_input_sha256: corrected.sha256,
102
+ completed_correction_sha256: view.completed_correction_sha256, profile_sha256: policy.profileHash(),
103
+ declarations_sha256: hybridDigest(policy.declarations()), checks: receipt.checks };
104
+ if (hybridDigest(receipt) !== hybridDigest(expected))
105
+ refuse("registered_check_receipt_changed");
106
+ const evidence = PreparedRetainedCheckEvidence.prepare(context, { projectId: scope.project_id, runId: scope.run_id, references: receipt.checks });
107
+ const prepared = new PreparedMemoryCorrectionCheckReceipt(token, corrected, policy, evidence, receipt, true);
108
+ prepared.revalidate(context);
109
+ return prepared;
94
110
  }
95
111
  value() {
96
112
  return structuredClone(this.#receipt);
@@ -111,7 +127,7 @@ export class PreparedMemoryCorrectionCheckReceipt {
111
127
  const existing = stored(context, this.#corrected);
112
128
  if ((this.#registered && !existing) || (existing && hybridDigest(existing) !== this.sha256))
113
129
  refuse("registered_check_receipt_changed");
114
- if (hybridDigest(this.#evidence.retainedReferences(context)) !== hybridDigest(this.#receipt.checks))
130
+ if ("retainedReferences" in this.#evidence && hybridDigest(this.#evidence.retainedReferences(context)) !== hybridDigest(this.#receipt.checks))
115
131
  refuse("selected_check_evidence_changed");
116
132
  }
117
133
  revalidate(context) {
@@ -0,0 +1,36 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ const snapshots = new WeakMap();
3
+ function synchronous(read) {
4
+ const value = read();
5
+ if (value && typeof value.then === "function") {
6
+ void Promise.resolve(value).catch(() => { });
7
+ throw new AppError("read_snapshot_async", "Memory custody traversal must be synchronous", 1);
8
+ }
9
+ return value;
10
+ }
11
+ export function withMemoryCustodySnapshot(context, read) {
12
+ if (snapshots.has(context))
13
+ return synchronous(read);
14
+ return context.db.readSnapshot(() => {
15
+ snapshots.set(context, new Set());
16
+ try {
17
+ return synchronous(read);
18
+ }
19
+ finally {
20
+ snapshots.delete(context);
21
+ }
22
+ });
23
+ }
24
+ /** Only SQL custody may share a completed proof within this synchronous
25
+ * snapshot. Physical revalidation stays outside this memo, and the next
26
+ * traversal always rereads SQL. Failed checks never become reusable proof.
27
+ * Prepared owners supply private keys, never their externally visible object. */
28
+ export function assertMemorySqlCustody(context, owner, validate) {
29
+ withMemoryCustodySnapshot(context, () => {
30
+ const checked = snapshots.get(context);
31
+ if (checked.has(owner))
32
+ return;
33
+ synchronous(validate);
34
+ checked.add(owner);
35
+ });
36
+ }
@@ -13,14 +13,23 @@ import { ObservedMemorySources } from "./memory-source-observations.js";
13
13
  import { memorySourceKey, PreparedMemoryStageResult } from "./memory-stage-results.js";
14
14
  import { PreparedDescriptorStageSettlement } from "./descriptor-stage-settlement.js";
15
15
  import { assertPreparedRunBundleSqlAuthority } from "./runs.js";
16
- import { readMemoryInitBootstrapReadiness } from "./memory-init-bootstrap-readiness.js";
17
- import { readMemoryInitGitPolicy } from "./memory-init-git-policy.js";
18
16
  import { reviewedMemoryGitFiles } from "./memory-git-integration.js";
17
+ import { readMemoryFinishGitSelection, readMemoryUpgradeFinishInventory } from "./memory-finish-integration.js";
19
18
  const token = Symbol("memory-finish-evidence"), event = "memory.finish_evidence";
20
19
  const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
21
20
  function refuse(reason) {
22
21
  throw new AppError("memory_finish_evidence_invalid", "Finish evidence lacks independently prepared acceptance custody", 2, { reason, effect: "no_effect" });
23
22
  }
23
+ export function parseMemoryFinishProposal(bytes) {
24
+ if (!(bytes instanceof Uint8Array) || !bytes.length || bytes.length > 1024 * 1024)
25
+ refuse("invalid_result_bytes");
26
+ try {
27
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
28
+ }
29
+ catch {
30
+ throw new AppError("memory_finish_evidence_invalid", "Finish proposal must be valid UTF-8 JSON. Correct only the proposal syntax, then use retry_command; do not rerun integration or settled checks", 2, { reason: "invalid_result_json", phase: "prepare", effect: "no_effect", recoverable: true, result_sha256: hash(bytes) });
31
+ }
32
+ }
24
33
  /** Terminal inventory and receipts belong to the accepted review/evidence
25
34
  * owners. Optional echoes cannot introduce new references or semantic claims. */
26
35
  export function projectMemoryFinishResult(value, owner, resultSha256) {
@@ -77,11 +86,24 @@ function acceptance(context, scope) {
77
86
  refuse("ambiguous_finish_acceptance");
78
87
  return rows[0] ? JSON.parse(rows[0].payload_json) : null;
79
88
  }
89
+ /** Terminal parsing inherits the accepted scope and named old-data criteria;
90
+ * no fresh version inference or mutable project sources are consulted. */
91
+ function upgradeBinding(context, scope, bundle) {
92
+ if (bundle.descriptor.descriptor.id !== "mb-upgrade")
93
+ refuse("upgrade_preservation_binding_changed");
94
+ const preflight = readAcceptedStageData(context, { ...scope, stage: "preflight" });
95
+ const diff = readAcceptedStageData(context, { ...scope, stage: "diff-analysis" });
96
+ const preservationInvariants = JSON.parse(preflight.bytes.toString("utf8")).details.preservation_invariants;
97
+ const minimumMode = JSON.parse(diff.bytes.toString("utf8")).details.mode;
98
+ if (!["patch", "targeted_minor", "full_migration"].includes(minimumMode) || !Array.isArray(preservationInvariants))
99
+ refuse("upgrade_preservation_binding_changed");
100
+ return { minimumMode, preservationInvariants };
101
+ }
80
102
  /** SQL-only historical byte/projection custody. Callers must independently
81
103
  * prepare the genuine accepted review owner outside their writer. This does
82
104
  * not re-observe today's integration checkout or grant RUN closure. */
83
105
  export function readAcceptedMemoryFinishEvidence(context, input) {
84
- if (!(input.bundle instanceof RetainedExecutionBundle) || input.bundle.descriptor.descriptor.id !== "mb-init"
106
+ if (!(input.bundle instanceof RetainedExecutionBundle) || !["mb-init", "mb-upgrade"].includes(input.bundle.descriptor.descriptor.id)
85
107
  || !PreparedMemoryFinishReview.isPrepared(input.review))
86
108
  refuse("registered_memory_review_required");
87
109
  const scope = { ...input.scope, stage: "finish" };
@@ -96,7 +118,7 @@ export function readAcceptedMemoryFinishEvidence(context, input) {
96
118
  || evidence.attempt !== stage.attempt || evidence.input_sha256 !== stage.input_sha256
97
119
  || evidence.bundle_sha256 !== input.bundle.sha256 || evidence.review_sha256 !== reviewData.result.sha256
98
120
  || !input.review.bytes().equals(reviewData.bytes)
99
- || data.data_schema_id !== "dd-flow/mb-init-finish-result@1" || data.input_sha256 !== stage.input_sha256
121
+ || data.data_schema_id !== (input.bundle.descriptor.descriptor.id === "mb-upgrade" ? "dd-flow/mb-upgrade-stage-result@1" : "dd-flow/mb-init-finish-result@1") || data.input_sha256 !== stage.input_sha256
100
122
  || hybridDigest(evidence.checks) !== hybridDigest(input.review.finalChecks(context)))
101
123
  refuse("accepted_finish_evidence_changed");
102
124
  const expectedAcceptance = { schema_id: "dd-flow/memory-finish-acceptance@1", project_id: scope.projectId, run_id: scope.runId,
@@ -134,16 +156,18 @@ export function readAcceptedMemoryFinishEvidence(context, input) {
134
156
  refuse("historical_evidence_projection_changed");
135
157
  const frozen = input.bundle.execution.snapshot().scope;
136
158
  const request = { requestId: frozen.requestId, projectRoot: frozen.projectRoot, workspaceRoot: frozen.workspace };
137
- const bootstrap = readMemoryInitBootstrapReadiness(context, request), policy = readMemoryInitGitPolicy(context, request);
138
- if (!bootstrap || !policy || bootstrap.projectId !== scope.projectId
139
- || bootstrap.authority.binding.execution_sha256 !== input.bundle.execution.sha256
140
- || bootstrap.authority.binding.git_policy_sha256 !== hybridDigest(policy)
141
- || policy.target_sha256 !== hybridDigest(bootstrap.authority.binding.target)
142
- || readiness.value.bootstrap_authority_sha256 !== hybridDigest(bootstrap.authority)
143
- || readiness.value.pack_sha256 !== bootstrap.authority.binding.pack_sha256)
159
+ const selected = readMemoryFinishGitSelection(context, scope, input.bundle), policy = selected.policy;
160
+ const packSha256 = selected.kind === "init" ? selected.readiness.authority.binding.pack_sha256 : selected.readiness.authority.receipt.upgrade_target.pack_sha256;
161
+ if (readiness.value.bootstrap_authority_sha256 !== hybridDigest(selected.readiness.authority)
162
+ || readiness.value.pack_sha256 !== packSha256)
144
163
  refuse("historical_terminal_bootstrap_policy_changed");
145
164
  const integrated = integration.value;
146
- const reviewedFiles = reviewedMemoryGitFiles(input.review.reviewedSources(context));
165
+ const upgrade = selected.kind === "upgrade" ? readMemoryUpgradeFinishInventory(context, scope, input.bundle, input.review) : null;
166
+ const reviewedFiles = upgrade?.references ?? reviewedMemoryGitFiles(input.review.reviewedSources(context));
167
+ if (upgrade && (integrated.upgrade_inventory_sha256 !== hybridDigest(upgrade)
168
+ || integrated.removed_files_sha256 !== (upgrade.removals.length ? hybridDigest(upgrade.removals) : undefined)
169
+ || hybridDigest([readiness.value.migration_record]) !== hybridDigest([upgrade.migrationRecord])))
170
+ refuse("historical_upgrade_inventory_changed");
147
171
  if (integrated.schema_id !== "dd-flow/memory-git-integration-observation@1"
148
172
  || integrated.project_root !== request.projectRoot || integrated.workspace_root !== request.workspaceRoot
149
173
  || integrated.repository !== policy.repository || integrated.workspace_branch !== policy.workspace_branch
@@ -167,11 +191,13 @@ export function readAcceptedMemoryFinishEvidence(context, input) {
167
191
  runId: scope.runId, stage: "finish", inputSha256: stage.input_sha256,
168
192
  predecessors: [{ stage: "review", result: reviewData.result, input_sha256: reviewData.input_sha256 }],
169
193
  unitIds: reviewed.units.map((unit) => unit.id), sources,
194
+ ...(upgrade ? { upgrade: upgradeBinding(context, scope, input.bundle) } : {}),
170
195
  historicalEvidence: new Set(reviewed.units.flatMap((unit) => unit.evidence.map(ref => `${memorySourceKey(ref.root, ref.path)}\0${ref.sha256}`)))
171
196
  });
172
197
  const value = result.value(), references = { coverage: evidence.coverage,
173
198
  checks: evidence.checks.map(({ path, sha256 }) => ({ path, sha256 })),
174
- integration: evidence.integration, normal_flow_readiness: evidence.normal_flow_readiness };
199
+ integration: evidence.integration, normal_flow_readiness: evidence.normal_flow_readiness,
200
+ ...(upgrade ? { migration_record: upgrade.migrationRecord } : {}) };
175
201
  if (value.outcome !== "accepted" || hybridDigest(value.units) !== hybridDigest(reviewed.units)
176
202
  || hybridDigest(value.findings) !== hybridDigest(reviewed.findings) || hybridDigest(value.details) !== hybridDigest(references))
177
203
  refuse("historical_finish_result_projection_changed");
@@ -209,7 +235,7 @@ export class PreparedMemoryFinishEvidence {
209
235
  Object.freeze(this);
210
236
  }
211
237
  static prepare(context, input) {
212
- if (!(input.bundle instanceof RetainedExecutionBundle) || input.bundle.descriptor.descriptor.id !== "mb-init")
238
+ if (!(input.bundle instanceof RetainedExecutionBundle) || !["mb-init", "mb-upgrade"].includes(input.bundle.descriptor.descriptor.id))
213
239
  refuse("registered_memory_bundle_required");
214
240
  if (context.db.isOwnedWriteTransaction?.())
215
241
  refuse("preparation_outside_writer_required");
@@ -258,7 +284,8 @@ export class PreparedMemoryFinishEvidence {
258
284
  references() {
259
285
  const value = this.#receipt;
260
286
  return { coverage: { ...value.coverage }, checks: value.checks.map(({ path, sha256 }) => ({ path, sha256 })),
261
- integration: { ...value.integration }, normal_flow_readiness: { ...value.normal_flow_readiness } };
287
+ integration: { ...value.integration }, normal_flow_readiness: { ...value.normal_flow_readiness },
288
+ ...(this.#bundle.descriptor.descriptor.id === "mb-upgrade" ? { migration_record: this.#readiness.value().migration_record } : {}) };
262
289
  }
263
290
  /** Fresh terminal result preparation, never a historical replay reader.
264
291
  * The proposal cannot replace accepted review coverage or CLI evidence. */
@@ -274,18 +301,13 @@ export class PreparedMemoryFinishEvidence {
274
301
  if (typeof review.input_sha256 !== "string")
275
302
  refuse("accepted_review_input_missing");
276
303
  const reviewed = JSON.parse(this.#review.bytes().toString("utf8"));
277
- let proposal;
278
- try {
279
- proposal = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
280
- }
281
- catch {
282
- refuse("invalid_result_bytes");
283
- }
304
+ const proposal = parseMemoryFinishProposal(bytes);
284
305
  const canonical = projectMemoryFinishResult(proposal, { units: reviewed.units, findings: reviewed.findings, details: this.references() }, hash(bytes));
285
306
  const result = PreparedMemoryStageResult.prepare(Buffer.from(JSON.stringify(canonical)), bundle.descriptor, {
286
307
  runId: this.#scope.runId, stage: "finish", inputSha256: this.#input.inputSha256,
287
308
  predecessors: [{ stage: "review", result: review.result, input_sha256: review.input_sha256 }],
288
309
  unitIds: reviewed.units.map((unit) => unit.id), sources: sources.hashes(),
310
+ ...(bundle.descriptor.descriptor.id === "mb-upgrade" ? { upgrade: upgradeBinding(context, this.#scope, bundle) } : {}),
289
311
  historicalEvidence: new Set(reviewed.units.flatMap((unit) => unit.evidence.map(ref => `${memorySourceKey(ref.root, ref.path)}\0${ref.sha256}`)))
290
312
  });
291
313
  const value = result.value();
@@ -1,3 +1,4 @@
1
+ import { assertMemorySqlCustody, withMemoryCustodySnapshot } from "./memory-custody-snapshot.js";
1
2
  import { AppError } from "../shared/errors.js";
2
3
  import { RetainedExecutionBundle } from "./execution-bundles.js";
3
4
  import { readAcceptedStageData } from "./stage-report-renderer.js";
@@ -32,6 +33,7 @@ function selected(context, scope) {
32
33
  /** Closed review predecessor proof only. It does not establish integration,
33
34
  * normal-flow readiness, terminal Stage acceptance or RUN completion. */
34
35
  export class PreparedMemoryFinishReview {
36
+ #custodyKey = {};
35
37
  static isPrepared(value) {
36
38
  return typeof value === "object" && value !== null && #review in value;
37
39
  }
@@ -51,40 +53,52 @@ export class PreparedMemoryFinishReview {
51
53
  Object.freeze(this);
52
54
  }
53
55
  static prepare(context, input) {
54
- if (!(input.bundle instanceof RetainedExecutionBundle) || input.bundle.descriptor.descriptor.id !== "mb-init"
56
+ if (!(input.bundle instanceof RetainedExecutionBundle) || !["mb-init", "mb-upgrade"].includes(input.bundle.descriptor.descriptor.id)
55
57
  || input.bundle.descriptor.successor("review", "accepted") !== "finish")
56
58
  refuse("registered_memory_bundle_required");
57
59
  if (context.db.isOwnedWriteTransaction?.())
58
60
  refuse("preparation_outside_writer_required");
59
- assertPreparedRunBundleSqlAuthority(context, input.scope, input.bundle);
60
- const data = context.db.readSnapshot(() => selected(context, input.scope));
61
- const review = data.corrected
62
- ? PreparedAcceptedMemoryCorrectedReview.prepare(context, { ...input, bytes: data.data.bytes })
63
- : PreparedAcceptedMemoryInitialReview.prepare(context, { ...input, bytes: data.data.bytes });
64
- const prepared = new PreparedMemoryFinishReview(token, input.scope, review, data);
65
- prepared.revalidate(context);
66
- return prepared;
61
+ return withMemoryCustodySnapshot(context, () => {
62
+ assertPreparedRunBundleSqlAuthority(context, input.scope, input.bundle);
63
+ const data = context.db.readSnapshot(() => selected(context, input.scope));
64
+ const review = data.corrected
65
+ ? PreparedAcceptedMemoryCorrectedReview.prepare(context, { ...input, bytes: data.data.bytes })
66
+ : PreparedAcceptedMemoryInitialReview.prepare(context, { ...input, bytes: data.data.bytes });
67
+ const prepared = new PreparedMemoryFinishReview(token, input.scope, review, data);
68
+ prepared.revalidate(context);
69
+ return prepared;
70
+ });
67
71
  }
68
72
  bytes() { return Buffer.from(this.#bytes); }
69
73
  reviewedSources(context) { this.assertCustody(context); return this.#review.reviewedSources(context); }
74
+ reviewedDocumentInventory(context) {
75
+ this.assertCustody(context);
76
+ return this.#review instanceof PreparedAcceptedMemoryCorrectedReview ? this.#review.settledDocumentBaseline(context).entries() : null;
77
+ }
70
78
  finalChecks(context) { this.assertCustody(context); return this.#review.finalChecks(context); }
71
79
  assertCustody(context) {
72
- this.#review.assertCustody(context);
73
- const data = selected(context, this.#scope);
74
- if (data.corrected !== this.#corrected || data.data.authority_sha256 !== this.#authority
75
- || !data.data.bytes.equals(this.#bytes))
76
- refuse("accepted_review_changed");
80
+ const review = this.#review;
81
+ assertMemorySqlCustody(context, this.#custodyKey, () => {
82
+ review.assertCustody(context);
83
+ const data = selected(context, this.#scope);
84
+ if (data.corrected !== this.#corrected || data.data.authority_sha256 !== this.#authority
85
+ || !data.data.bytes.equals(this.#bytes))
86
+ refuse("accepted_review_changed");
87
+ });
88
+ }
89
+ revalidate(context) {
90
+ const review = this.#review;
91
+ withMemoryCustodySnapshot(context, () => { review.revalidate(context); this.assertCustody(context); });
77
92
  }
78
- revalidate(context) { this.#review.revalidate(context); this.assertCustody(context); }
79
93
  }
80
- /** Productive terminal entry awaiting the complete six-stage registry. Opens
81
- * only after historical review proof; no provider dispatch or Git mutation.
94
+ /** Shared terminal entry for registered Memory flows. Opens only after
95
+ * historical review proof; no provider dispatch or Git mutation.
82
96
  * Terminal settlement must separately prove integration and readiness. */
83
97
  export function startMemoryFinish(context, input) {
84
98
  if (!(input.bytes instanceof Uint8Array) || input.bytes.length > 1024 * 1024)
85
99
  refuse("invalid_input_bytes");
86
100
  const bundle = readFlowRunExecutionBundle(context, input);
87
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || !bundle.descriptor.descriptor.terminal_stages.includes("finish")
101
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) || !bundle.descriptor.descriptor.terminal_stages.includes("finish")
88
102
  || bundle.descriptor.successor("review", "accepted") !== "finish")
89
103
  refuse("registered_memory_bundle_required");
90
104
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
@@ -107,7 +121,7 @@ export function replayAcceptedMemoryFinish(context, input) {
107
121
  if (context.db.isOwnedWriteTransaction?.())
108
122
  refuse("preparation_outside_writer_required");
109
123
  const bundle = readFlowRunExecutionBundle(context, input);
110
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
124
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
111
125
  refuse("registered_memory_bundle_required");
112
126
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
113
127
  const review = PreparedMemoryFinishReview.prepare(context, { scope, bundle });
@@ -149,7 +163,7 @@ export function settleAcceptedMemoryRun(context, input) {
149
163
  if (context.db.isOwnedWriteTransaction?.())
150
164
  refuse("preparation_outside_writer_required");
151
165
  const bundle = readFlowRunExecutionBundle(context, input);
152
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init"
166
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id)
153
167
  || !bundle.descriptor.descriptor.terminal_stages.includes("finish"))
154
168
  refuse("registered_memory_bundle_required");
155
169
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
@@ -175,14 +189,14 @@ export function settleAcceptedMemoryRun(context, input) {
175
189
  * Publication has its own exact receipt and does not accept the Stage. */
176
190
  export function registerMemoryFinishEvidenceFromStage(context, input) {
177
191
  const bundle = readFlowRunExecutionBundle(context, input);
178
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
192
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
179
193
  refuse("registered_memory_bundle_required");
180
194
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
181
195
  return PreparedMemoryFinishEvidence.prepare(context, { scope: { projectId: project.id, runId: input.runId }, bundle }).register(context);
182
196
  }
183
197
  export function integrateMemoryFinishFromStage(context, input) {
184
198
  const bundle = readFlowRunExecutionBundle(context, input);
185
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
199
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
186
200
  refuse("registered_memory_bundle_required");
187
201
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
188
202
  return integrateMemoryFinish(context, { scope: { projectId: project.id, runId: input.runId }, bundle });
@@ -196,7 +210,7 @@ export function finishMemoryFinish(context, input) {
196
210
  if (context.db.isOwnedWriteTransaction?.())
197
211
  refuse("preparation_outside_writer_required");
198
212
  const bundle = readFlowRunExecutionBundle(context, input);
199
- if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
213
+ if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
200
214
  refuse("registered_memory_bundle_required");
201
215
  const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
202
216
  const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle);