@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
@@ -0,0 +1,340 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { AppError } from "../shared/errors.js";
5
+ import { assertUpgradeRunStorageReady } from "./migrations.js";
6
+ import { hybridDigest } from "./hybrid-contracts.js";
7
+ import { appendAudit } from "./audit.js";
8
+ import { restoreMemoryUpgradeSelection, restoreMemoryUpgradeSelectionData, decodeMemoryUpgradeSelection } from "./memory-upgrade-selection.js";
9
+ import { prepareMemoryUpgradeInventory, matchesRetainedMemoryUpgradeInventory } from "./memory-upgrade-inventory.js";
10
+ import { observeDescriptorWorkspace } from "./descriptor-run-start.js";
11
+ import { PreparedMemoryInitRuntimeStorage } from "./memory-init-storage.js";
12
+ import { PreparedMemoryInitResourceStorage } from "./memory-init-resource-storage.js";
13
+ import { resourceHome } from "./managed-processes.js";
14
+ import semver from "semver";
15
+ import { PreparedMemoryLayer } from "./memory-layer.js";
16
+ import { readBoundedReleaseFile } from "./release-source.js";
17
+ import { observeMemoryGitPolicySelection } from "./memory-init-git-policy.js";
18
+ import { readRunStartRequest, hasRunStartTable } from "./run-start-custody.js";
19
+ import { runContextRelocations, projectPacketLocators } from "./stage-context.js";
20
+ // One historical decode per connection. SQL bytes, logical scope and audit
21
+ // custody are still observed on every read; callers receive private copies.
22
+ const retainedDecodes = new WeakMap();
23
+ function refuse(reason) {
24
+ throw new AppError("upgrade_storage_request_invalid", "Upgrade storage readiness must retain its original request", 1, { reason, effect: "no_effect", next_action: "reconcile_exact_request" });
25
+ }
26
+ function project(context, scope) {
27
+ if (!scope || Object.keys(scope).sort().join() !== "projectRoot,requestId,workspaceRoot"
28
+ || typeof scope.requestId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_.-]{0,95}$/.test(scope.requestId))
29
+ refuse("invalid_scope");
30
+ if ([scope.projectRoot, scope.workspaceRoot].some(root => typeof root !== "string" || !path.isAbsolute(root) || path.resolve(root) !== root))
31
+ refuse("invalid_scope");
32
+ const selected = context.db.get("SELECT id FROM projects WHERE root = ? AND status = 'active'", [scope.projectRoot]);
33
+ if (selected)
34
+ return selected.id;
35
+ const candidates = hasRunStartTable(context) ? context.db.all("SELECT p.id,p.root,s.run_id FROM projects p JOIN run_start_requests s ON s.project_id=p.id WHERE p.status='active' AND s.request_id=? AND json_extract(s.payload_json,'$.project_root')=? AND json_extract(s.payload_json,'$.workspace_root')=?", [scope.requestId, scope.projectRoot, scope.workspaceRoot]) : [];
36
+ const matches = candidates.filter(row => {
37
+ const request = readRunStartRequest(context, row.id, scope.requestId);
38
+ return request?.published && request.payload.initial_index.flow_kind === 'mb-upgrade'
39
+ && projectPacketLocators(scope.projectRoot, runContextRelocations(context, row.id, row.run_id)) === row.root;
40
+ });
41
+ if (matches.length !== 1)
42
+ refuse("project_not_active");
43
+ return matches[0].id;
44
+ }
45
+ /** Physical imports use the source request's immutable logical scope. This is
46
+ * a historical read projection, never new storage/RUN admission. */
47
+ export function resolveUpgradeHistoricalScope(context, scope) {
48
+ const projectId = project(context, scope);
49
+ const row = hasRunStartTable(context) ? context.db.get("SELECT run_id FROM run_start_requests WHERE project_id=? AND request_id=?", [projectId, scope.requestId]) : undefined;
50
+ const relocations = row ? runContextRelocations(context, projectId, row.run_id) : [];
51
+ if (relocations.length) {
52
+ const request = readRunStartRequest(context, projectId, scope.requestId);
53
+ if (request?.published && request.payload.initial_index.flow_kind === 'mb-upgrade') {
54
+ const original = { requestId: scope.requestId, projectRoot: request.payload.project_root, workspaceRoot: request.payload.workspace_root };
55
+ if (projectPacketLocators(original.projectRoot, relocations) === scope.projectRoot && projectPacketLocators(original.workspaceRoot, relocations) === scope.workspaceRoot)
56
+ return { projectId, scope: original };
57
+ }
58
+ }
59
+ return { projectId, scope };
60
+ }
61
+ function scopeDirectories(scope) {
62
+ for (const root of [scope.projectRoot, scope.workspaceRoot]) {
63
+ try {
64
+ if (typeof root !== "string" || fs.realpathSync(root) !== root || !fs.statSync(root).isDirectory())
65
+ refuse("noncanonical_scope");
66
+ }
67
+ catch (error) {
68
+ if (error instanceof AppError)
69
+ throw error;
70
+ refuse("scope_unavailable");
71
+ }
72
+ }
73
+ }
74
+ const key = (projectId, requestId) => `mb-upgrade.storage.${projectId}.${requestId}`;
75
+ /** The selected engine issues these facts; SQL custody preserves them after
76
+ * the pre-context files are retired. Never rebuild historical evidence. */
77
+ export function upgradeStorageMigration(value, selectionSha256) {
78
+ const migration = value, sha = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
79
+ if (!migration || !migration.request || !path.isAbsolute(migration.request.path) || !sha(migration.request.sha256)
80
+ || !migration.proof?.reference || migration.proof.reference.path !== migration.request.path + ".result.json"
81
+ || !sha(migration.proof.reference.sha256) || !Array.isArray(migration.proof.evidence) || migration.proof.evidence.length !== 5)
82
+ refuse("invalid_migration_proof");
83
+ const kinds = ["writer-drain", "storage-backup", "storage-plan", "storage-apply", "storage-verification"];
84
+ migration.proof.evidence.forEach((entry, index) => {
85
+ if (!entry || typeof entry.base64 !== "string" || entry.base64.length > 1024 * 1024)
86
+ refuse("invalid_migration_evidence");
87
+ const raw = Buffer.from(entry.base64, "base64");
88
+ if (entry.kind !== kinds[index] || entry.path !== `receipts/${entry.kind}.json` || raw.toString("base64") !== entry.base64
89
+ || createHash("sha256").update(raw).digest("hex") !== entry.sha256)
90
+ refuse("invalid_migration_evidence");
91
+ let evidence;
92
+ try {
93
+ evidence = JSON.parse(raw.toString("utf8"));
94
+ }
95
+ catch {
96
+ return refuse("invalid_migration_evidence");
97
+ }
98
+ if (evidence.schema_id !== "dd-flow/paired-storage-evidence@1" || evidence.kind !== entry.kind
99
+ || evidence.request_sha256 !== migration.request.sha256 || evidence.selection_sha256 !== selectionSha256)
100
+ refuse("foreign_migration_evidence");
101
+ });
102
+ return migration;
103
+ }
104
+ /** Shared read-only project fence before either storage bootstrap or cutover. */
105
+ export function assertMemoryUpgradeProjectCurrent(selected, scope, env) {
106
+ const p = selected.payload;
107
+ if (p.git && createHash("sha256").update(readBoundedReleaseFile(p.git.executable, 64 * 1024 * 1024)).digest("hex") !== p.git.probe.executable_sha256)
108
+ refuse("selected_git_changed");
109
+ if (p.git && hybridDigest(observeMemoryGitPolicySelection(env, { scope, gitExecutable: p.git.executable,
110
+ selection: { route: p.git.policy.route, integrationBranch: p.git.policy.integration_branch } })) !== hybridDigest(p.git.policy))
111
+ refuse("git_policy_changed");
112
+ if (hybridDigest(observeDescriptorWorkspace({ env }, scope.projectRoot, scope.workspaceRoot, p.git?.executable)) !== hybridDigest(p.workspace)
113
+ || !matchesRetainedMemoryUpgradeInventory(prepareMemoryUpgradeInventory(scope.workspaceRoot, selected.layer, selected.baselineLayer ?? undefined), p.current.inventory))
114
+ refuse("current_context_changed");
115
+ }
116
+ /** Current physical admission in the bound engine, separate from historical
117
+ * migration receipts. Shared by initial bootstrap and relocated RUN stages. */
118
+ export function assertUpgradeExecutionStorage(context, engine) {
119
+ if (context.db.isOwnedWriteTransaction?.())
120
+ refuse("preparation_outside_writer_required");
121
+ const proof = engine.admitMemoryUpgradeStorage(context.ddFlowHome, resourceHome(context));
122
+ const stores = [PreparedMemoryInitRuntimeStorage.prepareUpgrade(context).facts(), PreparedMemoryInitResourceStorage.prepare(context).facts()];
123
+ const runProof = proof.facts.run, resourceProof = proof.facts.resource;
124
+ if (stores.some(local => {
125
+ const remote = local.store_kind === "run" ? runProof : resourceProof;
126
+ return local.store_path !== remote.store_path || local.schema_sha256 !== remote.schema_sha256
127
+ || local.executing_writer_version !== remote.executing_writer_version;
128
+ }))
129
+ refuse("executing_store_context_changed");
130
+ return proof;
131
+ }
132
+ /** New bootstrap path: source/target policy comes only from retained input.
133
+ * Physical stores are observed now, not inferred from a project's MB version. */
134
+ function frozenProof(context, scope, retained, retainedMigration) {
135
+ const original = retained ? null : restoreMemoryUpgradeSelection(context.ddFlowHome, scope);
136
+ const selected = original ?? restoreMemoryUpgradeSelectionData(Buffer.from(retained.payload_json, "utf8"), retained.sha256, retained.request_input, scope), p = selected.payload;
137
+ const requestInput = retained?.request_input ?? original.original.input;
138
+ if (p.impact.chain.status !== "ok")
139
+ refuse("incomplete_retained_impact_chain");
140
+ if (!retained && selected.baselineLayer) {
141
+ const baseline = PreparedMemoryLayer.fromCommittedCanon(context.ddFlowHome, JSON.parse(Buffer.from(p.current.manifest_base64, "base64").toString("utf8")), selected.baselineLayer.installationSha256);
142
+ if (!baseline || baseline.sha256 !== selected.baselineLayer.sha256 || baseline.installationSha256 !== selected.baselineLayer.installationSha256)
143
+ refuse("canonical_baseline_changed");
144
+ }
145
+ assertMemoryUpgradeProjectCurrent(selected, scope, context.env);
146
+ const compatibility = JSON.parse(selected.layer.files().get("dd-flow/compatibility.json").toString("utf8"));
147
+ const contract = JSON.parse(selected.layer.files().get("dd-flow/flow-contract.json").toString("utf8"));
148
+ const manifest = selected.engine.manifest();
149
+ if (compatibility.memory_bank_version !== selected.release.canon.version || compatibility.dd_flow_cli.flow_contract !== contract.id
150
+ || compatibility.dd_flow_cli.package_name !== manifest.package_name || compatibility.engine.package_name !== manifest.package_name
151
+ || !semver.valid(compatibility.dd_flow_cli.min_version) || semver.lt(manifest.package_version, compatibility.dd_flow_cli.min_version)
152
+ || !semver.satisfies(manifest.package_version, compatibility.engine.version_range, { includePrerelease: true }))
153
+ refuse("retained_engine_incompatible");
154
+ const proof = assertUpgradeExecutionStorage(context, selected.engine);
155
+ let migration;
156
+ const file = original ? path.join(path.dirname(original.original.candidate.retain().file), "storage-migration.json")
157
+ : retainedMigration ? upgradeStorageMigration(retainedMigration, selected.sha256).request.path : undefined;
158
+ if (file && fs.existsSync(file)) {
159
+ const request = { path: file, sha256: createHash("sha256").update(readBoundedReleaseFile(file, 16 * 1024 * 1024)).digest("hex") };
160
+ const response = selected.engine.transitionMemoryUpgradeStorage({ home: context.ddFlowHome, resourceHome: resourceHome(context), scope,
161
+ selectionSha256: selected.sha256, action: "status", expectedSha256: request.sha256 });
162
+ const result = response.result;
163
+ if (result?.status !== "applied" || !result.proof)
164
+ refuse("migration_evidence_incomplete");
165
+ migration = upgradeStorageMigration({ request, proof: result.proof }, selected.sha256);
166
+ if (retainedMigration && hybridDigest(migration) !== hybridDigest(retainedMigration))
167
+ refuse("migration_evidence_changed");
168
+ }
169
+ else if (retainedMigration)
170
+ refuse("migration_request_unavailable");
171
+ return { selectionSha256: selected.sha256, selection: { sha256: selected.sha256,
172
+ payload_json: selected.bytes.toString("utf8"), request_input: requestInput }, proof: {
173
+ schema_id: migration ? "dd-flow/mb-upgrade-storage-readiness@2" : "dd-flow/mb-upgrade-storage-readiness@1",
174
+ route: migration ? "migration" : "verified-no-op", ...(migration ? { migration } : {}), selection_sha256: selected.sha256,
175
+ source_version: p.current.canon_version, target_version: selected.release.canon.version,
176
+ chain: p.impact.chain.steps, current_provenance: p.current.inventory.inventory.current_manifest,
177
+ target: { canon: selected.source.canonProvenance(), installation_sha256: p.release.manifest_sha256,
178
+ layer_sha256: selected.layer.sha256, pack_sha256: selected.layer.packSha256 }, selected_engine_storage: proof,
179
+ stores: [proof.facts.run, proof.facts.resource].map(store => ({ store_kind: store.store_kind, store_path: store.store_path,
180
+ store_dev: store.store_dev, store_ino: store.store_ino, schema_sha256: store.schema_sha256, executing_writer_version: store.executing_writer_version }))
181
+ } };
182
+ }
183
+ /** Historical evidence, not present-day physical admission. Project sync may
184
+ * change current files without rewriting the original upgrade's storage proof.
185
+ * Workspace/repository eligibility belongs to the upgrade target preflight.
186
+ */
187
+ export function readUpgradeStorageReadiness(context, scope) {
188
+ return context.db.readSnapshot(() => retainedStorage(context, scope));
189
+ }
190
+ function retainedStorage(context, scope) {
191
+ let logical;
192
+ try {
193
+ logical = resolveUpgradeHistoricalScope(context, scope);
194
+ }
195
+ catch (error) {
196
+ // A first upgrade may observe an existing MB in a new runtime Home. This
197
+ // is absence of history, not registration or permission to revive it.
198
+ if (error instanceof AppError && error.details.reason === 'project_not_active'
199
+ && !context.db.get('SELECT 1 FROM projects WHERE root=?', [scope.projectRoot])
200
+ && !(hasRunStartTable(context) && context.db.get("SELECT 1 FROM run_start_requests WHERE request_id=? AND json_extract(payload_json,'$.project_root')=?", [scope.requestId, scope.projectRoot])))
201
+ return null;
202
+ throw error;
203
+ }
204
+ const projectId = logical.projectId;
205
+ scope = logical.scope;
206
+ const row = context.db.get("SELECT value_json FROM runtime_config WHERE key = ?", [key(projectId, scope.requestId)]);
207
+ if (!row) {
208
+ if (context.db.get("SELECT 1 FROM audit_events WHERE project_id=? AND event_type='memory.upgrade_storage_ready' AND json_extract(payload_json,'$.request_id')=? AND json_extract(payload_json,'$.selection_sha256') IS NOT NULL LIMIT 1", [projectId, scope.requestId]))
209
+ refuse("storage_readiness_custody_missing");
210
+ return null;
211
+ }
212
+ if (Buffer.byteLength(row.value_json) > 68 * 1024 * 1024)
213
+ refuse("unbounded_retained_receipt");
214
+ const cached = retainedDecodes.get(context.db);
215
+ if (cached?.raw === row.value_json && cached.value.receipt.project_id === projectId
216
+ && hybridDigest(cached.value.receipt.scope) === hybridDigest(scope)) {
217
+ assertRetainedReadinessAudit(context, projectId, scope, cached.value);
218
+ return structuredClone(cached.value);
219
+ }
220
+ let receipt;
221
+ try {
222
+ receipt = JSON.parse(row.value_json);
223
+ }
224
+ catch {
225
+ return refuse("invalid_retained_receipt");
226
+ }
227
+ const frozen = receipt?.schema_id === "dd-flow/mb-upgrade-storage-request@2" || receipt?.schema_id === "dd-flow/mb-upgrade-storage-request@3";
228
+ const migrated = receipt?.schema_id === "dd-flow/mb-upgrade-storage-request@3";
229
+ if (!receipt || Object.keys(receipt).sort().join() !== (frozen ? "project_id,proof,schema_id,scope,selection" : "project_id,proof,schema_id,scope")
230
+ || !["dd-flow/mb-upgrade-storage-request@1", "dd-flow/mb-upgrade-storage-request@2", "dd-flow/mb-upgrade-storage-request@3"].includes(receipt.schema_id) || receipt.project_id !== projectId
231
+ || hybridDigest(receipt.scope) !== hybridDigest(scope) || !receipt.proof
232
+ || receipt.proof.schema_id !== (migrated ? "dd-flow/mb-upgrade-storage-readiness@2" : "dd-flow/mb-upgrade-storage-readiness@1")
233
+ || receipt.proof.route !== (migrated ? "migration" : "verified-no-op"))
234
+ refuse("changed_request");
235
+ if (receipt.proof.selection_sha256 !== undefined && (typeof receipt.proof.selection_sha256 !== "string"
236
+ || !/^[a-f0-9]{64}$/.test(receipt.proof.selection_sha256)))
237
+ refuse("changed_request");
238
+ const sha256 = hybridDigest(receipt);
239
+ if (!frozen)
240
+ return { receipt, sha256 };
241
+ const retained = receipt.selection;
242
+ if (!retained || Object.keys(retained).sort().join() !== "payload_json,request_input,sha256" || typeof retained.payload_json !== "string"
243
+ || retained.sha256 !== receipt.proof.selection_sha256)
244
+ refuse("invalid_retained_selection");
245
+ const selection = decodeMemoryUpgradeSelection(Buffer.from(retained.payload_json, "utf8"), retained.sha256, retained.request_input, scope);
246
+ if (migrated)
247
+ upgradeStorageMigration(receipt.proof.migration, retained.sha256);
248
+ const value = { receipt, sha256, selection };
249
+ assertRetainedReadinessAudit(context, projectId, scope, value);
250
+ retainedDecodes.set(context.db, { raw: row.value_json, value });
251
+ return structuredClone(value);
252
+ }
253
+ function assertRetainedReadinessAudit(context, projectId, scope, value) {
254
+ const { receipt, sha256 } = value, retained = receipt.selection;
255
+ if (!retained)
256
+ refuse("invalid_retained_selection");
257
+ const audits = context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type='memory.upgrade_storage_ready' AND json_extract(payload_json,'$.request_id')=? LIMIT 2", [projectId, scope.requestId]);
258
+ if (audits.length !== 1 || audits.some(event => Buffer.byteLength(event.payload_json) > 16 * 1024)
259
+ || hybridDigest(JSON.parse(audits[0].payload_json)) !== hybridDigest({ request_id: scope.requestId, project_root: scope.projectRoot,
260
+ workspace_root: scope.workspaceRoot, receipt_sha256: sha256, route: receipt.proof.route, selection_sha256: retained.sha256 }))
261
+ refuse("storage_readiness_custody_missing");
262
+ }
263
+ /** Retains physical admission plus selected-engine phase evidence when storage
264
+ * changed. Legacy apply markers are insufficient for migration bootstrap.
265
+ * This is a storage dependency, not complete bootstrap or provider readiness.
266
+ */
267
+ export class PreparedUpgradeStorageReadiness {
268
+ #receipt;
269
+ #engine;
270
+ #selectionSha256;
271
+ constructor(receipt, engine, selectionSha256) {
272
+ if (Buffer.byteLength(JSON.stringify(receipt)) > 68 * 1024 * 1024)
273
+ refuse("unbounded_retained_receipt");
274
+ this.#receipt = structuredClone(receipt);
275
+ this.#engine = engine;
276
+ this.#selectionSha256 = selectionSha256;
277
+ Object.freeze(this);
278
+ }
279
+ static prepareFromSelection(context, scope) {
280
+ if (context.db.isOwnedWriteTransaction?.())
281
+ refuse("preparation_outside_writer_required");
282
+ const projectId = project(context, scope);
283
+ scopeDirectories(scope);
284
+ const prior = readUpgradeStorageReadiness(context, scope);
285
+ const selected = frozenProof(context, scope, prior?.receipt.selection, prior?.receipt.proof.migration);
286
+ const receipt = { schema_id: selected.proof.route === "migration" ? "dd-flow/mb-upgrade-storage-request@3" : "dd-flow/mb-upgrade-storage-request@2", scope: { ...scope }, project_id: projectId,
287
+ proof: selected.proof, selection: selected.selection };
288
+ if (prior && prior.sha256 !== hybridDigest(receipt))
289
+ refuse("changed_request");
290
+ return new PreparedUpgradeStorageReadiness(receipt, undefined, selected.selectionSha256);
291
+ }
292
+ static prepare(context, scope, engine) {
293
+ const projectId = project(context, scope);
294
+ scopeDirectories(scope);
295
+ const proof = assertUpgradeRunStorageReady(context, scope.projectRoot, engine);
296
+ if (proof.route !== "verified-no-op")
297
+ refuse("storage_migration_requires_physical_proof");
298
+ const receipt = { schema_id: "dd-flow/mb-upgrade-storage-request@1", scope: { ...scope }, project_id: projectId, proof };
299
+ const prior = readUpgradeStorageReadiness(context, scope);
300
+ if (prior && prior.sha256 !== hybridDigest(receipt))
301
+ refuse("changed_request");
302
+ return new PreparedUpgradeStorageReadiness(receipt, engine);
303
+ }
304
+ apply(context) {
305
+ const scope = this.#receipt.scope;
306
+ if (this.#selectionSha256 !== undefined) {
307
+ const prior = readUpgradeStorageReadiness(context, scope);
308
+ if (prior) {
309
+ if (prior.sha256 !== hybridDigest(this.#receipt))
310
+ refuse("changed_request");
311
+ // Historical acknowledgement only, never fresh RUN/storage admission.
312
+ return { ...prior, changed: false };
313
+ }
314
+ }
315
+ const proof = this.#selectionSha256 === undefined ? assertUpgradeRunStorageReady(context, scope.projectRoot, this.#engine)
316
+ : frozenProof(context, scope).proof;
317
+ if (project(context, scope) !== this.#receipt.project_id
318
+ || hybridDigest(proof) !== hybridDigest(this.#receipt.proof))
319
+ refuse("changed_after_preparation");
320
+ return context.db.writeTransaction(() => {
321
+ const prior = readUpgradeStorageReadiness(context, scope);
322
+ if (prior) {
323
+ if (prior.sha256 !== hybridDigest(this.#receipt))
324
+ refuse("changed_request");
325
+ return { ...prior, changed: false };
326
+ }
327
+ const now = context.now();
328
+ context.db.run("INSERT INTO runtime_config (key,value_json,created_at,updated_at) VALUES (?,?,?,?)", [key(this.#receipt.project_id, scope.requestId), JSON.stringify(this.#receipt), now, now]);
329
+ appendAudit(context, { projectId: this.#receipt.project_id, eventType: "memory.upgrade_storage_ready", payload: {
330
+ request_id: scope.requestId, project_root: scope.projectRoot, workspace_root: scope.workspaceRoot,
331
+ receipt_sha256: hybridDigest(this.#receipt), route: this.#receipt.proof.route,
332
+ ...(this.#selectionSha256 ? { selection_sha256: this.#selectionSha256 } : {})
333
+ } });
334
+ const accepted = readUpgradeStorageReadiness(context, scope);
335
+ if (!accepted || accepted.sha256 !== hybridDigest(this.#receipt))
336
+ refuse("storage_readiness_readback_failed");
337
+ return { ...accepted, changed: true };
338
+ }, "memoryUpgrade.storageReadiness");
339
+ }
340
+ }
@@ -81,14 +81,16 @@ export class PreparedMemoryVerificationAcceptance {
81
81
  || input.composition.result().sha256 !== input.compose.sha256))
82
82
  refuse("prepared_authority_required");
83
83
  const outputs = input.composition?.outputReferences() ?? [];
84
+ const upgrade = compose.stage === "upgrade", authoring = upgrade ? "upgrade" : "compose";
84
85
  input.checks.assertOwner({ ...input.scope, scope: "aggregate" });
85
86
  const diagnostic = result.outcome === "needs_repair";
86
- if (compose.stage !== "compose" || compose.outcome !== "accepted" || result.stage !== "verify" || !["accepted", "needs_repair"].includes(result.outcome)
87
- || result.run_id !== compose.run_id || result.run_id !== input.scope.runId || result.predecessors.length !== 1 || result.predecessors[0].stage !== "compose"
87
+ if (!["compose", "upgrade"].includes(compose.stage) || compose.outcome !== "accepted" || result.stage !== "verify" || !["accepted", "needs_repair"].includes(result.outcome)
88
+ || result.run_id !== compose.run_id || result.run_id !== input.scope.runId || result.predecessors.length !== 1 || result.predecessors[0].stage !== authoring
88
89
  || result.predecessors[0].input_sha256 !== compose.input_sha256 || result.predecessors[0].result.sha256 !== input.compose.sha256
89
- || compose.findings.some(finding => finding.severity !== "minor" && finding.status !== "resolved")
90
- || (!diagnostic && (!input.checks.qualityPassed() || result.findings.some(finding => finding.severity !== "minor" && finding.status !== "resolved"))))
90
+ || compose.findings.some(finding => finding.severity !== "minor" && finding.status !== "resolved"))
91
91
  refuse("unaccepted_or_foreign_predecessor");
92
+ if (!diagnostic && (!input.checks.qualityPassed() || result.findings.some(finding => finding.severity !== "minor" && finding.status !== "resolved")))
93
+ throw new AppError("memory_verification_acceptance_invalid", "Accepted verification requires passed selected checks and no unresolved material findings. For a real gap use needs_repair with an open material finding; a pending later REVIEW is a separate gate, not a current defect. Do not mark unresolved findings resolved or rerun settled checks merely to pass", 2, { reason: "verification_not_accepted", phase: "prepare", effect: "no_effect", recoverable: true, result_sha256: input.proposalSha256 ?? input.result.sha256 });
92
94
  const expected = input.checks.resultReferences().map(reference => hybridDigest(reference)), actual = result.details.checks.map(reference => hybridDigest(reference));
93
95
  const allowedChecks = new Set(input.checks.sourceReferences().map(({ path, sha256 }) => hybridDigest({ path, sha256 })));
94
96
  if (expected.some(reference => !actual.includes(reference))
@@ -97,26 +99,45 @@ export class PreparedMemoryVerificationAcceptance {
97
99
  const units = new Map(compose.units.map(unit => [unit.id, unit]));
98
100
  if (result.units.length !== units.size || new Set(result.units.map(unit => unit.id)).size !== units.size)
99
101
  refuse("changed_unit_coverage");
100
- const assessments = new Map(result.details.semantic_assessments.map(assessment => [assessment.unit_id, assessment]));
101
- if (assessments.size !== result.details.semantic_assessments.length || [...assessments.keys()].some(id => !units.has(id))
102
+ const selectedAssessments = upgrade ? result.details.preservation_assessments?.map(item => ({ ...item, verdict: item.outcome === "preserved" ? "accepted" : item.outcome })) : result.details.semantic_assessments;
103
+ if (!selectedAssessments)
104
+ refuse("missing_unit_assessments");
105
+ const assessments = new Map();
106
+ for (const assessment of selectedAssessments)
107
+ assessments.set(assessment.unit_id, [...assessments.get(assessment.unit_id) ?? [], assessment]);
108
+ if (!upgrade && assessments.size !== selectedAssessments.length || [...assessments.keys()].some(id => !units.has(id))
102
109
  || compose.units.some(unit => unit.applicability !== "not-applicable" && !assessments.has(unit.id)))
103
110
  refuse("incomplete_or_duplicate_assessments");
111
+ if (upgrade && hybridDigest(input.result.preservationInvariants()) !== hybridDigest(input.compose.preservationInvariants()))
112
+ refuse("changed_preservation_invariants");
104
113
  const key = (source) => memorySourceKey(input.roots && input.roots.projectRoot === input.roots.workspace && source.root === "project" ? "workspace" : source.root, source.path);
105
114
  for (const unit of result.units) {
106
- const original = units.get(unit.id), assessment = assessments.get(unit.id);
107
- if (!original || unit.aspect !== original.aspect || unit.applicability !== original.applicability || unit.applicability === "unknown"
115
+ const original = units.get(unit.id), selected = assessments.get(unit.id) ?? [];
116
+ // IDs bind assessments to accepted units; aspect is descriptive prose.
117
+ // REVIEW derives its assignments from composition, not this wording.
118
+ if (!original || unit.applicability !== original.applicability || unit.applicability === "unknown"
108
119
  || (unit.applicability === "not-applicable" ? unit.outcome !== "not-applicable" : !["accepted", ...(diagnostic ? ["needs_repair"] : [])].includes(unit.outcome))
109
- || (assessment && (!["accepted", ...(diagnostic ? ["needs_repair"] : [])].includes(assessment.verdict) || !assessment.summary.trim())))
120
+ || selected.some(assessment => !["accepted", ...(diagnostic ? ["needs_repair"] : [])].includes(assessment.verdict) || !assessment.summary.trim()))
110
121
  refuse("unit_not_accepted_or_changed");
111
122
  assertMemoryVerificationArtifactReferences(original.artifacts, unit.artifacts, outputs);
112
- if (!assessment)
113
- continue;
114
- // PreparedMemoryStageResult already binds every evidence reference to
115
- // admitted bytes. Cross-unit and earlier-stage evidence is useful context,
116
- // but cannot replace examination of this unit's own composed output.
117
- if (unit.applicability !== "not-applicable" && !assessment.evidence.some(source => original.artifacts.some(artifact => key(artifact) === key(source) && artifact.sha256 === source.sha256))) {
118
- throw new AppError("memory_verification_acceptance_invalid", "Assess the composed documents themselves and cite a direct output reference for EACH applicable unit; the listed references identify this unit's outputs. Work result receipts do not replace direct output examination", 2, { reason: "assessment_does_not_examine_composed_output", phase: "prepare", effect: "no_effect", recoverable: true,
119
- unit_id: unit.id, output_references: structuredClone(original.artifacts), result_sha256: input.result.sha256 });
123
+ for (const assessment of selected) {
124
+ // PreparedMemoryStageResult already binds every evidence reference to
125
+ // admitted bytes. Cross-unit and earlier-stage evidence is useful context,
126
+ // but cannot replace examination of this unit's own composed output.
127
+ if (unit.applicability !== "not-applicable" && !assessment.evidence.some(source => original.artifacts.some(artifact => key(artifact) === key(source) && artifact.sha256 === source.sha256))) {
128
+ throw new AppError("memory_verification_acceptance_invalid", "Assess the composed documents themselves and cite a direct output reference for EACH applicable unit; the listed references identify this unit's outputs. Work result receipts do not replace direct output examination", 2, { reason: "assessment_does_not_examine_composed_output", phase: "prepare", effect: "no_effect", recoverable: true,
129
+ unit_id: unit.id, output_references: structuredClone(original.artifacts), result_sha256: input.result.sha256 });
130
+ }
131
+ if (upgrade) {
132
+ const id = assessment.invariant_id;
133
+ const invariant = input.result.preservationInvariants().find(item => item.id === id);
134
+ const old = invariant?.evidence;
135
+ // A current output alone cannot substantiate old-to-new preservation.
136
+ // Identical old bytes may be examined through the retained RUN copy.
137
+ if (!old?.some(before => assessment.evidence.some(source => source.sha256 === before.sha256 && (key(source) === key(before) || source.root === "run"))))
138
+ throw new AppError("memory_verification_acceptance_invalid", "Compare the retained old evidence as well as the current unit output; correct the assessment without rerunning settled checks", 2, { reason: "preservation_assessment_does_not_examine_old_evidence", phase: "prepare", effect: "no_effect", recoverable: true,
139
+ unit_id: unit.id, invariant_id: id, old_references: structuredClone(old ?? []), result_sha256: input.result.sha256 });
140
+ }
120
141
  }
121
142
  }
122
143
  if (diagnostic && !result.findings.some(finding => finding.severity !== "minor" && finding.status === "open")) {