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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +9 -0
  3. package/dist/build-info.json +6 -6
  4. package/dist/cli/argument-values.js +5 -5
  5. package/dist/cli/command-inputs.js +89 -20
  6. package/dist/cli/command-metadata.js +197 -0
  7. package/dist/cli/command-option-descriptions.js +191 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/error-output.js +52 -0
  11. package/dist/cli/executor-onboarding.js +76 -0
  12. package/dist/cli/flows.js +29 -0
  13. package/dist/cli/harnesses.js +84 -0
  14. package/dist/cli/help.js +240 -6
  15. package/dist/cli/input-preparation.js +54 -5
  16. package/dist/cli/memory-flow-admission.js +44 -0
  17. package/dist/cli/memory-init-invocation.js +78 -0
  18. package/dist/cli/memory-init.js +240 -0
  19. package/dist/cli/memory-storage-admission.js +53 -0
  20. package/dist/cli/models.js +39 -0
  21. package/dist/cli/native-hook-ingress.js +1 -1
  22. package/dist/cli/operator-profiles.js +61 -0
  23. package/dist/cli/output-options.js +35 -0
  24. package/dist/cli/response-file.js +71 -0
  25. package/dist/cli/run-cli.js +283 -160
  26. package/dist/cli/setup.js +149 -0
  27. package/dist/cli.js +54 -2
  28. package/dist/domain/stage-handler-identities.js +20 -0
  29. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  30. package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
  31. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +4 -2
  32. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +11 -5
  33. package/dist/harness-runtime/lib/dd-codex.mjs +22 -10
  34. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
  35. package/dist/harness-runtime/lib/dd-droid.mjs +2 -1
  36. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +4 -2
  37. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +6 -4
  38. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +9 -9
  39. package/dist/harness-runtime/lib/delegation-instructions.mjs +5 -3
  40. package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
  41. package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
  42. package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
  43. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  44. package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
  45. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  46. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  47. package/dist/harness-runtime/lib/opencode-plugin.mjs +2 -0
  48. package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
  49. package/dist/runtime/context.js +1 -1
  50. package/dist/schemas/discovery-result.schema.json +184 -0
  51. package/dist/schemas/execution-bundle.schema.json +205 -0
  52. package/dist/schemas/execution-settings.schema.json +162 -0
  53. package/dist/schemas/flow-descriptor.schema.json +54 -0
  54. package/dist/schemas/flow-run.schema.json +22 -0
  55. package/dist/schemas/harness-catalog.schema.json +80 -0
  56. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  57. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  58. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  59. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  60. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  61. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  62. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  63. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  64. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  65. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  66. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  67. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  68. package/dist/schemas/model-catalog.schema.json +153 -0
  69. package/dist/schemas/profile-settings.schema.json +122 -0
  70. package/dist/schemas/release-manifest.schema.json +291 -0
  71. package/dist/schemas/run-engine-binding.schema.json +1 -1
  72. package/dist/services/check-runner-evidence.js +51 -4
  73. package/dist/services/cli-operation-classifier.js +8 -47
  74. package/dist/services/cli-upgrade-allowlist.js +27 -0
  75. package/dist/services/code-checks.js +387 -34
  76. package/dist/services/controller-execution.js +88 -0
  77. package/dist/services/controller-fanout.js +71 -12
  78. package/dist/services/dashboard.js +8 -2
  79. package/dist/services/descriptor-coordinator-session.js +35 -0
  80. package/dist/services/descriptor-root-work.js +53 -0
  81. package/dist/services/descriptor-run-settlement.js +105 -0
  82. package/dist/services/descriptor-run-start.js +449 -0
  83. package/dist/services/descriptor-stage-coordinator.js +197 -0
  84. package/dist/services/descriptor-stage-settlement.js +222 -0
  85. package/dist/services/descriptor-stage-start.js +139 -0
  86. package/dist/services/discovery/agy-discovery.js +2 -0
  87. package/dist/services/discovery/codex-discovery.js +2 -0
  88. package/dist/services/discovery/droid-discovery.js +2 -0
  89. package/dist/services/discovery/grok-discovery.js +2 -0
  90. package/dist/services/discovery/opencode-discovery.js +2 -0
  91. package/dist/services/discovery/static.js +31 -0
  92. package/dist/services/discovery/zcode-discovery.js +2 -0
  93. package/dist/services/engines.js +39 -22
  94. package/dist/services/eval-snapshots.js +83 -25
  95. package/dist/services/execution-bundles.js +263 -0
  96. package/dist/services/execution-policy.js +20 -16
  97. package/dist/services/executor-onboarding.js +56 -0
  98. package/dist/services/external-work-launch.js +91 -11
  99. package/dist/services/flow-catalog.js +21 -0
  100. package/dist/services/flow-descriptors.js +82 -0
  101. package/dist/services/frozen-engine.js +242 -0
  102. package/dist/services/generic-execution.js +164 -0
  103. package/dist/services/harness-adapter.js +28 -2
  104. package/dist/services/harness-discovery.js +29 -0
  105. package/dist/services/harness-doctor.js +75 -0
  106. package/dist/services/harness-probe-effects.js +51 -0
  107. package/dist/services/harness-version-probe.js +100 -0
  108. package/dist/services/hooks.js +24 -6
  109. package/dist/services/hybrid-contracts.js +483 -0
  110. package/dist/services/ids.js +29 -1
  111. package/dist/services/installation-lock.js +95 -0
  112. package/dist/services/installed-flow-source.js +183 -0
  113. package/dist/services/lifecycle-invocations.js +257 -78
  114. package/dist/services/memory-accepted-composition.js +77 -0
  115. package/dist/services/memory-baseline-preservation.js +65 -0
  116. package/dist/services/memory-completed-correction-wave.js +320 -0
  117. package/dist/services/memory-compose-handler.js +258 -0
  118. package/dist/services/memory-composition-acceptance.js +199 -0
  119. package/dist/services/memory-composition-graph.js +134 -0
  120. package/dist/services/memory-composition-registration.js +146 -0
  121. package/dist/services/memory-composition-work-custody.js +151 -0
  122. package/dist/services/memory-composition-work-results.js +96 -0
  123. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  124. package/dist/services/memory-corrected-review-batch.js +30 -0
  125. package/dist/services/memory-corrected-review-findings.js +106 -0
  126. package/dist/services/memory-corrected-review-inputs.js +210 -0
  127. package/dist/services/memory-corrected-review-projection.js +78 -0
  128. package/dist/services/memory-corrected-review-receipt.js +170 -0
  129. package/dist/services/memory-corrected-review-registration.js +191 -0
  130. package/dist/services/memory-correction-check-receipt.js +219 -0
  131. package/dist/services/memory-correction-input-owner.js +6 -0
  132. package/dist/services/memory-discover-handler.js +104 -0
  133. package/dist/services/memory-finish-evidence.js +435 -0
  134. package/dist/services/memory-finish-handler.js +215 -0
  135. package/dist/services/memory-finish-integration.js +280 -0
  136. package/dist/services/memory-finish-readiness.js +122 -0
  137. package/dist/services/memory-git-integration.js +151 -0
  138. package/dist/services/memory-historical-corrected-review.js +206 -0
  139. package/dist/services/memory-historical-original-review.js +130 -0
  140. package/dist/services/memory-historical-repair-registration.js +99 -0
  141. package/dist/services/memory-historical-second-review.js +128 -0
  142. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  143. package/dist/services/memory-init-contexts.js +89 -0
  144. package/dist/services/memory-init-controller-start.js +84 -0
  145. package/dist/services/memory-init-engine-release.js +223 -0
  146. package/dist/services/memory-init-git-policy.js +136 -0
  147. package/dist/services/memory-init-lint-capability.js +185 -0
  148. package/dist/services/memory-init-native-capacity.js +241 -0
  149. package/dist/services/memory-init-preflight.js +312 -0
  150. package/dist/services/memory-init-project-bootstrap.js +599 -0
  151. package/dist/services/memory-init-request-candidate.js +157 -0
  152. package/dist/services/memory-init-request-input.js +66 -0
  153. package/dist/services/memory-init-resource-storage.js +125 -0
  154. package/dist/services/memory-init-run-allocation.js +81 -0
  155. package/dist/services/memory-init-run-bundle.js +98 -0
  156. package/dist/services/memory-init-start.js +175 -0
  157. package/dist/services/memory-init-startup-custody.js +80 -0
  158. package/dist/services/memory-init-startup-input.js +240 -0
  159. package/dist/services/memory-init-storage.js +81 -0
  160. package/dist/services/memory-init-stores.js +359 -0
  161. package/dist/services/memory-init-worktrunk-capability.js +172 -0
  162. package/dist/services/memory-layer-publication.js +611 -0
  163. package/dist/services/memory-layer.js +156 -0
  164. package/dist/services/memory-lint-config.js +85 -0
  165. package/dist/services/memory-native-review-copy.js +165 -0
  166. package/dist/services/memory-normal-flow-entry.js +75 -0
  167. package/dist/services/memory-ordinary-defaults.js +112 -0
  168. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  169. package/dist/services/memory-preflight-handler.js +259 -0
  170. package/dist/services/memory-repair-current-view.js +299 -0
  171. package/dist/services/memory-repair-document-delta.js +451 -0
  172. package/dist/services/memory-repair-history.js +491 -0
  173. package/dist/services/memory-repair-physical-binding.js +312 -0
  174. package/dist/services/memory-repair-publication-files.js +152 -0
  175. package/dist/services/memory-repair-publication-intent.js +27 -0
  176. package/dist/services/memory-repair-publication-plan.js +160 -0
  177. package/dist/services/memory-repair-publication-source.js +225 -0
  178. package/dist/services/memory-repair-publication.js +794 -0
  179. package/dist/services/memory-repair-registration.js +239 -0
  180. package/dist/services/memory-repair-work-baseline.js +413 -0
  181. package/dist/services/memory-repair-work-completion.js +97 -0
  182. package/dist/services/memory-repair-work-custody.js +73 -0
  183. package/dist/services/memory-repair-work-results.js +89 -0
  184. package/dist/services/memory-repair-workspace.js +252 -0
  185. package/dist/services/memory-repair-writer-copy.js +735 -0
  186. package/dist/services/memory-result-binding.js +173 -0
  187. package/dist/services/memory-retained-review-authority.js +129 -0
  188. package/dist/services/memory-retained-review-results.js +70 -0
  189. package/dist/services/memory-retained-second-baseline.js +102 -0
  190. package/dist/services/memory-retained-second-repairs.js +156 -0
  191. package/dist/services/memory-review-acceptance.js +214 -0
  192. package/dist/services/memory-review-correction-plan.js +171 -0
  193. package/dist/services/memory-review-handler.js +585 -0
  194. package/dist/services/memory-review-inputs.js +200 -0
  195. package/dist/services/memory-review-receipt.js +180 -0
  196. package/dist/services/memory-review-registration.js +108 -0
  197. package/dist/services/memory-review-work-custody.js +124 -0
  198. package/dist/services/memory-review-work-input.js +72 -0
  199. package/dist/services/memory-review-work-results.js +73 -0
  200. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  201. package/dist/services/memory-second-correction-plan.js +76 -0
  202. package/dist/services/memory-second-repair-baseline.js +91 -0
  203. package/dist/services/memory-second-repair-launch.js +614 -0
  204. package/dist/services/memory-second-repair-registration.js +88 -0
  205. package/dist/services/memory-second-repair-source.js +187 -0
  206. package/dist/services/memory-second-review-acceptance.js +115 -0
  207. package/dist/services/memory-source-observations.js +117 -0
  208. package/dist/services/memory-stage-dispatch.js +28 -0
  209. package/dist/services/memory-stage-results.js +199 -0
  210. package/dist/services/memory-verification-acceptance.js +135 -0
  211. package/dist/services/memory-verification-checks.js +252 -0
  212. package/dist/services/memory-verification-receipt.js +159 -0
  213. package/dist/services/memory-verify-handler.js +135 -0
  214. package/dist/services/memory-work-result-preparation.js +63 -0
  215. package/dist/services/model-catalog.js +109 -0
  216. package/dist/services/model-discovery.js +46 -0
  217. package/dist/services/operator-profiles.js +236 -0
  218. package/dist/services/projects.js +17 -2
  219. package/dist/services/recovery-snapshot-database.js +416 -1
  220. package/dist/services/release-archive-producer.js +52 -0
  221. package/dist/services/release-archive.js +143 -0
  222. package/dist/services/release-cache.js +142 -0
  223. package/dist/services/release-compatibility.js +18 -0
  224. package/dist/services/release-download.js +67 -0
  225. package/dist/services/release-envelope.js +104 -0
  226. package/dist/services/release-manifest.js +45 -0
  227. package/dist/services/release-payload.js +114 -0
  228. package/dist/services/release-producer.js +63 -0
  229. package/dist/services/release-provenance.js +160 -0
  230. package/dist/services/release-registry.js +66 -0
  231. package/dist/services/release-source.js +194 -0
  232. package/dist/services/repair-intents.js +1 -1
  233. package/dist/services/review-copy.js +10 -2
  234. package/dist/services/run-control.js +80 -9
  235. package/dist/services/run-controller-capture.js +10 -3
  236. package/dist/services/run-controller-process.js +21 -0
  237. package/dist/services/run-controller-recovery.js +3 -1
  238. package/dist/services/run-controller-state.js +1 -1
  239. package/dist/services/run-controller.js +101 -40
  240. package/dist/services/run-recovery-guard.js +2 -0
  241. package/dist/services/run-recovery.js +145 -5
  242. package/dist/services/run-start-custody.js +177 -0
  243. package/dist/services/runs.js +319 -25
  244. package/dist/services/setup.js +377 -0
  245. package/dist/services/stage-context.js +9 -1
  246. package/dist/services/stage-handlers.js +74 -0
  247. package/dist/services/stage-report-renderer.js +63 -0
  248. package/dist/services/stage-work-graph.js +17 -0
  249. package/dist/services/vnext-code.js +3 -3
  250. package/dist/services/vnext-execution-profile.js +2 -2
  251. package/dist/services/vnext-fanout.js +70 -9
  252. package/dist/services/vnext-merge.js +8 -3
  253. package/dist/services/vnext-plan-review.js +6 -4
  254. package/dist/services/work-registry.js +616 -71
  255. package/dist/services/workspace-files.js +1 -1
  256. package/dist/storage/database.js +84 -6
  257. package/dist/storage/writer-contract.js +11 -7
  258. package/package.json +13 -3
  259. package/tools/create-canon-release.mjs +33 -0
  260. package/tools/produce-hybrid-release.mjs +41 -0
@@ -0,0 +1,136 @@
1
+ import path from "node:path";
2
+ import { spawnSync } from "node:child_process";
3
+ import { AppError } from "../shared/errors.js";
4
+ import { hybridDigest } from "./hybrid-contracts.js";
5
+ import { appendAudit } from "./audit.js";
6
+ import { PreparedMemoryInitTarget } from "./memory-init-preflight.js";
7
+ const event = "memory.init_git_policy", token = Symbol("memory-init-git-policy");
8
+ function refuse(reason) {
9
+ throw new AppError("memory_init_git_policy_invalid", "Init lacks explicit retained Git policy", 2, { reason, effect: "no_effect" });
10
+ }
11
+ function validScope(scope) {
12
+ if (!scope || typeof scope.requestId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_.-]{0,95}$/.test(scope.requestId)
13
+ || typeof scope.projectRoot !== "string" || !path.isAbsolute(scope.projectRoot)
14
+ || typeof scope.workspaceRoot !== "string" || !path.isAbsolute(scope.workspaceRoot)
15
+ || Object.keys(scope).sort().join() !== "projectRoot,requestId,workspaceRoot")
16
+ refuse("invalid_request_scope");
17
+ }
18
+ /** SQL preservation, not fresh policy inference, Git execution or permission. */
19
+ export function readMemoryInitGitPolicy(context, scope) {
20
+ validScope(scope);
21
+ const rows = context.db.all(`SELECT payload_json FROM audit_events WHERE event_type=?
22
+ AND json_extract(payload_json,'$.scope.requestId')=? AND json_extract(payload_json,'$.scope.projectRoot')=?
23
+ AND json_extract(payload_json,'$.scope.workspaceRoot')=? LIMIT 2`, [event, scope.requestId, scope.projectRoot, scope.workspaceRoot]);
24
+ if (!rows.length)
25
+ return null;
26
+ if (rows.length !== 1 || Buffer.byteLength(rows[0].payload_json) > 32 * 1024)
27
+ refuse("ambiguous_or_unbounded_policy");
28
+ let value;
29
+ try {
30
+ value = JSON.parse(rows[0].payload_json);
31
+ }
32
+ catch {
33
+ return refuse("invalid_policy_receipt");
34
+ }
35
+ if (!value || value.schema_id !== "dd-flow/memory-init-git-policy@1" || hybridDigest(value.scope) !== hybridDigest(scope)
36
+ || Object.keys(value).sort().join() !== "initial_head,integration_branch,push_authorized,repository,route,schema_id,scope,source,target_sha256,workspace_branch"
37
+ || value.source !== "explicit_request" || value.push_authorized !== false
38
+ || !["integration_branch_direct", "feature_worktree"].includes(value.route)
39
+ || typeof value.target_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(value.target_sha256)
40
+ || typeof value.repository !== "string" || !path.isAbsolute(value.repository)
41
+ || typeof value.workspace_branch !== "string" || !value.workspace_branch
42
+ || typeof value.integration_branch !== "string" || !value.integration_branch
43
+ || (value.initial_head !== null && (typeof value.initial_head !== "string" || !/^[a-f0-9]{40,64}$/.test(value.initial_head))))
44
+ refuse("policy_receipt_changed");
45
+ return structuredClone(value);
46
+ }
47
+ /** Explicit request choice frozen against genuine no-effect target preflight.
48
+ * Retaining this receipt must precede bootstrap publication. It grants no
49
+ * dispatch authority by itself or compatibility with a historical bootstrap.
50
+ * Memory finish integrates only after independently accepted current review;
51
+ * this receipt never authorizes push. */
52
+ export class PreparedMemoryInitGitPolicy {
53
+ #target;
54
+ #receipt;
55
+ constructor(key, target, receipt) {
56
+ if (key !== token)
57
+ refuse("policy_token_required");
58
+ this.#target = target;
59
+ this.#receipt = structuredClone(receipt);
60
+ Object.freeze(this);
61
+ }
62
+ static prepare(context, input) {
63
+ if (!(input.target instanceof PreparedMemoryInitTarget))
64
+ refuse("prepared_target_required");
65
+ if (context.db.isOwnedWriteTransaction?.())
66
+ refuse("preparation_outside_writer_required");
67
+ const prepared = this.prepareFresh(context.env, input);
68
+ const receipt = prepared.value(), retained = readMemoryInitGitPolicy(context, receipt.scope);
69
+ if (retained && hybridDigest(retained) !== hybridDigest(receipt))
70
+ refuse("policy_request_conflict");
71
+ return prepared;
72
+ }
73
+ /** Fresh explicit policy before opening runtime stores. This checks Git and
74
+ * scope, but grants no SQL custody, integration or provider authority. */
75
+ static prepareFresh(environment, input) {
76
+ if (!(input.target instanceof PreparedMemoryInitTarget))
77
+ refuse("prepared_target_required");
78
+ const selection = input.selection;
79
+ if (!selection || Object.keys(selection).sort().join() !== "integrationBranch,route"
80
+ || !["integration_branch_direct", "feature_worktree"].includes(selection.route)
81
+ || typeof selection.integrationBranch !== "string" || !selection.integrationBranch || selection.integrationBranch.startsWith("-") || selection.integrationBranch.length > 1024
82
+ || [...selection.integrationBranch].some(character => character.charCodeAt(0) <= 32 || character.charCodeAt(0) === 127))
83
+ refuse("explicit_policy_required");
84
+ input.target.revalidate();
85
+ const facts = input.target.facts(), scope = { requestId: facts.request_id, projectRoot: facts.project_root, workspaceRoot: facts.workspace_root };
86
+ if (!facts.tool_probes)
87
+ refuse("fresh_target_required");
88
+ const env = Object.fromEntries(Object.entries(environment).filter(([key]) => !key.startsWith("GIT_")));
89
+ const result = spawnSync(facts.tools.git, ["check-ref-format", `refs/heads/${selection.integrationBranch}`], { env: { ...env, GIT_OPTIONAL_LOCKS: "0" }, encoding: "utf8", timeout: 5000, maxBuffer: 64 * 1024, shell: false, windowsHide: true });
90
+ if (result.error || result.signal || result.status !== 0)
91
+ refuse("invalid_integration_branch");
92
+ if (selection.route === "integration_branch_direct"
93
+ ? scope.projectRoot !== scope.workspaceRoot || facts.branch !== selection.integrationBranch
94
+ : scope.projectRoot === scope.workspaceRoot || facts.branch === selection.integrationBranch)
95
+ refuse("route_workspace_mismatch");
96
+ if (selection.route === "feature_worktree") {
97
+ const branch = spawnSync(facts.tools.git, ["-C", scope.projectRoot, "rev-parse", "--verify", `refs/heads/${selection.integrationBranch}^{commit}`], { env: { ...env, GIT_OPTIONAL_LOCKS: "0" }, encoding: "utf8", timeout: 5000, maxBuffer: 64 * 1024, shell: false, windowsHide: true });
98
+ if (branch.error || branch.signal || branch.status !== 0 || !/^[a-f0-9]{40,64}$/.test(branch.stdout.trim()))
99
+ refuse("integration_branch_unavailable");
100
+ }
101
+ const receipt = { schema_id: "dd-flow/memory-init-git-policy@1", scope, target_sha256: input.target.sha256,
102
+ repository: facts.repository, workspace_branch: facts.branch, initial_head: facts.head, source: "explicit_request",
103
+ route: selection.route, integration_branch: selection.integrationBranch, push_authorized: false };
104
+ return new PreparedMemoryInitGitPolicy(token, input.target, receipt);
105
+ }
106
+ value() { return structuredClone(this.#receipt); }
107
+ retain(context) {
108
+ if (context.db.isOwnedWriteTransaction?.())
109
+ refuse("preparation_outside_writer_required");
110
+ this.#target.revalidate();
111
+ return context.db.writeTransaction(() => this.retainPreparedSql(context), "memoryInit.retainGitPolicy");
112
+ }
113
+ /** Metadata-only publication for an already prepared aggregate owner. */
114
+ retainPreparedSql(context) {
115
+ if (!context.db.isOwnedWriteTransaction?.())
116
+ refuse("owned_policy_writer_required");
117
+ const receipt = readMemoryInitGitPolicy(context, this.#receipt.scope);
118
+ if (receipt) {
119
+ if (hybridDigest(receipt) !== hybridDigest(this.#receipt))
120
+ refuse("policy_request_conflict");
121
+ return receipt;
122
+ }
123
+ const scope = this.#receipt.scope;
124
+ if (context.db.get(`SELECT 1 FROM audit_events WHERE event_type IN ('memory.init_project_bootstrap_intent','memory.init_project_bootstrap')
125
+ AND json_extract(payload_json,'$.scope.requestId')=? AND json_extract(payload_json,'$.scope.projectRoot')=?
126
+ AND json_extract(payload_json,'$.scope.workspaceRoot')=? LIMIT 1`, [scope.requestId, scope.projectRoot, scope.workspaceRoot]))
127
+ refuse("policy_must_precede_bootstrap");
128
+ appendAudit(context, { eventType: event, payload: this.#receipt });
129
+ this.assertCustody(context);
130
+ return this.value();
131
+ }
132
+ assertCustody(context) {
133
+ if (hybridDigest(readMemoryInitGitPolicy(context, this.#receipt.scope)) !== hybridDigest(this.#receipt))
134
+ refuse("policy_receipt_changed");
135
+ }
136
+ }
@@ -0,0 +1,185 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { createHash } from "node:crypto";
6
+ import { AppError } from "../shared/errors.js";
7
+ import { hybridDigest } from "./hybrid-contracts.js";
8
+ import { PreparedMemoryInitTarget } from "./memory-init-preflight.js";
9
+ import { readBoundedReleaseFile } from "./release-source.js";
10
+ function refuse(reason) {
11
+ throw new AppError("memory_init_lint_capability_failed", "Selected mb-lint cannot validate Memory Bank documents", 1, { reason, effect: "no_effect", next_action: "repair_prerequisite_then_retry" });
12
+ }
13
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
14
+ const logical = ".memory-bank/index.md";
15
+ const validDocument = `---
16
+ file: '.memory-bank/index.md'
17
+ description: 'Isolated deterministic capability probe.'
18
+ purpose: 'Validate the selected linter without reading project documents.'
19
+ version: '0.1.0'
20
+ date: '2026-01-01'
21
+ status: 'DRAFT'
22
+ c4_level: 'documentation'
23
+ parent: null
24
+ tags: [capability-probe]
25
+ ---
26
+
27
+ # Isolated capability probe
28
+ `;
29
+ /** Shape validation for historical SQL custody, never executable qualification. */
30
+ export function isMemoryInitLintCapabilityFacts(value) {
31
+ if (!value || typeof value !== "object" || Array.isArray(value))
32
+ return false;
33
+ const facts = value, hashes = ["executable_sha256", "valid_document_sha256", "invalid_document_sha256",
34
+ "positive_report_sha256", "negative_report_sha256", "required_fields_report_sha256", "missing_link_report_sha256"];
35
+ return facts.schema_id === "dd-flow/memory-init-lint-capability@1" && typeof facts.executable === "string" && path.isAbsolute(facts.executable)
36
+ && typeof facts.version === "string" && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(facts.version)
37
+ && Object.keys(facts).length === hashes.length + 3
38
+ && hashes.every(key => typeof facts[key] === "string" && /^[a-f0-9]{64}$/.test(facts[key]));
39
+ }
40
+ /** Tests deterministic JSON lint behavior, not semantic grounding or provider readiness.
41
+ * CLI writes only its own temporary files containing fixed probe data.
42
+ */
43
+ export class PreparedMemoryInitLintCapability {
44
+ sha256;
45
+ #facts;
46
+ constructor(facts) {
47
+ this.#facts = facts;
48
+ this.sha256 = hybridDigest(facts);
49
+ Object.freeze(this);
50
+ }
51
+ static prepare(target, env) {
52
+ if (!(target instanceof PreparedMemoryInitTarget))
53
+ refuse("unprepared_target");
54
+ const selected = target.facts(), executable = selected.tools["mb-lint"], probe = selected.tool_probes?.["mb-lint"];
55
+ if (!probe)
56
+ refuse("missing_selected_tool_probe");
57
+ const checksum = () => {
58
+ try {
59
+ return hash(readBoundedReleaseFile(executable, 64 * 1024 * 1024));
60
+ }
61
+ catch {
62
+ return refuse("selected_executable_unavailable");
63
+ }
64
+ };
65
+ if (checksum() !== probe.executable_sha256)
66
+ refuse("selected_executable_changed");
67
+ let scratch, rootOwner, primary, prepared;
68
+ try {
69
+ scratch = fs.mkdtempSync(path.join(os.tmpdir(), "dd-flow-init-lint-"));
70
+ rootOwner = fs.lstatSync(scratch);
71
+ const bank = path.join(scratch, ".memory-bank");
72
+ fs.mkdirSync(bank);
73
+ const bankOwner = fs.lstatSync(bank);
74
+ const file = path.join(scratch, logical);
75
+ fs.writeFileSync(file, validDocument, { flag: "wx", mode: 0o600 });
76
+ const fileOwner = fs.lstatSync(file);
77
+ let expectedDocument = validDocument;
78
+ const same = (actual, selected) => actual.dev === selected.dev && actual.ino === selected.ino;
79
+ const ownDirectories = () => {
80
+ const root = fs.lstatSync(scratch), directory = fs.lstatSync(bank);
81
+ if (!root.isDirectory() || !directory.isDirectory() || !same(root, rootOwner) || !same(directory, bankOwner))
82
+ refuse("probe_directory_owner_changed");
83
+ };
84
+ const writeProbe = (document) => {
85
+ ownDirectories();
86
+ const fd = fs.openSync(file, fs.constants.O_WRONLY | (fs.constants.O_NOFOLLOW ?? 0));
87
+ try {
88
+ const actual = fs.fstatSync(fd);
89
+ if (!actual.isFile() || actual.nlink !== 1 || !same(actual, fileOwner))
90
+ refuse("probe_file_owner_changed");
91
+ fs.ftruncateSync(fd, 0);
92
+ fs.writeFileSync(fd, document);
93
+ expectedDocument = document;
94
+ }
95
+ finally {
96
+ fs.closeSync(fd);
97
+ }
98
+ };
99
+ const probeEnv = Object.fromEntries(Object.entries(env).filter(([key]) => !key.startsWith("GIT_")));
100
+ const run = (status, rule) => {
101
+ ownDirectories();
102
+ const result = spawnSync(executable, ["--root", scratch, "--files", logical, "--format", "json"], { cwd: scratch, env: { ...probeEnv, GIT_OPTIONAL_LOCKS: "0" }, shell: false, windowsHide: true, timeout: 5000, maxBuffer: 256 * 1024 });
103
+ if (result.error || result.signal || result.status !== status)
104
+ refuse("lint_probe_execution_failed");
105
+ ownDirectories();
106
+ const actual = fs.lstatSync(file);
107
+ if (!actual.isFile() || actual.nlink !== 1 || !same(actual, fileOwner)
108
+ || hash(readBoundedReleaseFile(file, 64 * 1024)) !== hash(Buffer.from(expectedDocument)))
109
+ refuse("probe_input_changed");
110
+ let report;
111
+ try {
112
+ report = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(result.stdout));
113
+ }
114
+ catch {
115
+ return refuse("lint_probe_invalid_json");
116
+ }
117
+ if (!report || report.tool !== "mb-lint" || report.version !== probe.version || report.root !== "."
118
+ || report.memoryBank !== ".memory-bank" || !Array.isArray(report.findings)
119
+ || !report.summary || typeof report.summary !== "object")
120
+ refuse("lint_probe_invalid_report");
121
+ const summary = report.summary;
122
+ if (Object.keys(summary).length !== 4 || ["errors", "warnings", "info", "suggestions"].some(key => !Number.isSafeInteger(summary[key]) || Number(summary[key]) < 0)
123
+ || summary.errors !== report.findings.filter(value => value?.severity === "error").length)
124
+ refuse("lint_probe_invalid_summary");
125
+ if (status === 0 && (Object.values(summary).some(value => value !== 0) || report.findings.length !== 0))
126
+ refuse("valid_document_rejected");
127
+ if (status === 1 && (!(Number(summary.errors) > 0) || !report.findings.some(value => value && typeof value === "object"
128
+ && value.ruleId === rule && value.severity === "error" && value.file === logical)))
129
+ refuse(`lint_rule_not_detected:${rule}`);
130
+ return hybridDigest(report);
131
+ };
132
+ const positive = run(0), invalid = "---\nfile: [\n---\n\n# Invalid YAML probe\n";
133
+ writeProbe(invalid);
134
+ const negative = run(1, "frontmatter/parseable");
135
+ writeProbe("---\nfile: '.memory-bank/index.md'\n---\n\n# Missing frontmatter fields\n");
136
+ const fields = run(1, "frontmatter/required-fields");
137
+ writeProbe(`${validDocument}\n[Missing target](missing-probe-target.md)\n`);
138
+ const links = run(1, "links/markdown-target-exists");
139
+ if (checksum() !== probe.executable_sha256)
140
+ refuse("selected_executable_changed");
141
+ prepared = new PreparedMemoryInitLintCapability({ schema_id: "dd-flow/memory-init-lint-capability@1",
142
+ executable, executable_sha256: probe.executable_sha256, version: probe.version,
143
+ valid_document_sha256: hash(Buffer.from(validDocument)), invalid_document_sha256: hash(Buffer.from(invalid)),
144
+ positive_report_sha256: positive, negative_report_sha256: negative,
145
+ required_fields_report_sha256: fields, missing_link_report_sha256: links });
146
+ }
147
+ catch (error) {
148
+ primary = error instanceof AppError ? error : new AppError("memory_init_lint_capability_failed", "Lint probe observation failed", 1, { reason: "lint_probe_observation_failed", effect: "no_effect", next_action: "repair_prerequisite_then_retry" });
149
+ }
150
+ if (scratch)
151
+ try {
152
+ const actual = fs.lstatSync(scratch);
153
+ if (!rootOwner || !actual.isDirectory() || actual.dev !== rootOwner.dev || actual.ino !== rootOwner.ino)
154
+ refuse("probe_root_owner_changed");
155
+ fs.rmSync(scratch, { recursive: true });
156
+ }
157
+ catch {
158
+ throw new AppError("memory_init_lint_probe_cleanup_failed", "Isolated lint probe requires cleanup", 1, { reason: primary instanceof AppError ? primary.details.reason : primary ? "probe_failed" : "cleanup_failed",
159
+ effect: "partial", owned_probe_path: scratch, next_action: "reconcile_owned_probe" });
160
+ }
161
+ if (primary)
162
+ throw primary;
163
+ return prepared;
164
+ }
165
+ facts() { return { ...this.#facts }; }
166
+ revalidate(target, _env) {
167
+ if (!(target instanceof PreparedMemoryInitTarget))
168
+ refuse("unprepared_target");
169
+ const selected = target.facts(), probe = selected.tool_probes?.["mb-lint"];
170
+ if (!probe || selected.tools["mb-lint"] !== this.#facts.executable
171
+ || probe.version !== this.#facts.version || probe.executable_sha256 !== this.#facts.executable_sha256)
172
+ refuse("lint_capability_changed");
173
+ // This instance already passed the functional probes. Publication checks
174
+ // preserve its selected executable, not repeat qualification after effects.
175
+ let checksum;
176
+ try {
177
+ checksum = hash(readBoundedReleaseFile(this.#facts.executable, 64 * 1024 * 1024));
178
+ }
179
+ catch {
180
+ return refuse("selected_executable_unavailable");
181
+ }
182
+ if (checksum !== this.#facts.executable_sha256)
183
+ refuse("selected_executable_changed");
184
+ }
185
+ }
@@ -0,0 +1,241 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import { createHash } from "node:crypto";
5
+ import { AppError, errorRecord } from "../shared/errors.js";
6
+ import { hybridDigest } from "./hybrid-contracts.js";
7
+ import { resolveHarnessCommand, harnessRuntimeArguments } from "./harness-config.js";
8
+ import { runHarnessAdapter, adapterSessionId } from "./harness-adapter.js";
9
+ import { renderCapacityInstructions } from "../harness-runtime/lib/delegation-instructions.mjs";
10
+ import { normalizeNativeChildren } from "../harness-runtime/lib/native-children.mjs";
11
+ import { readBoundedReleaseFile } from "./release-source.js";
12
+ import { acquireInstallationLock } from "./installation-lock.js";
13
+ import { inspectDaemonOperation } from "../harness-runtime/lib/daemon-operations.mjs";
14
+ import { nativeCommandFingerprint } from "../harness-runtime/lib/native-request-proof.mjs";
15
+ const sha = (bytes) => createHash("sha256").update(bytes).digest("hex");
16
+ function refuse(reason, effect = "no_effect") {
17
+ throw new AppError("memory_init_native_capacity_required", "Native startup requires its exact qualified probe", 1, { reason, effect, next_action: "reconcile_exact_native_probe" });
18
+ }
19
+ function read(file) {
20
+ try {
21
+ const stat = fs.lstatSync(file);
22
+ if (!stat.isFile() || stat.nlink !== 1)
23
+ refuse("linked_probe_receipt", "unknown");
24
+ return JSON.parse(readBoundedReleaseFile(file, 1024 * 1024).toString("utf8"));
25
+ }
26
+ catch (error) {
27
+ if (error.code === "ENOENT")
28
+ return null;
29
+ throw error;
30
+ }
31
+ }
32
+ function retain(file, value) {
33
+ fs.writeFileSync(file, JSON.stringify(value), { flag: "wx", mode: 0o600 });
34
+ }
35
+ function publicReply(result) {
36
+ const reply = { ok: true, ...result };
37
+ // The daemon retains this transport-only shutdown marker, but its public
38
+ // response deliberately omits it (dd-codex-daemon response projection).
39
+ delete reply._shutdown;
40
+ return reply;
41
+ }
42
+ /** Technical child probe: no RUN, project registration, lifecycle hooks or
43
+ * operator profile writes. An unresolved intent never authorizes redispatch. */
44
+ export async function produceMemoryInitNativeCapacity(input) {
45
+ if (!input.allowLiveProbe || !Number.isInteger(input.maximum) || input.maximum < 1 || input.maximum > 15
46
+ || !/^[a-f0-9]{64}$/.test(input.requestSha256)
47
+ || input.nativeConfigHome !== undefined && !path.isAbsolute(input.nativeConfigHome))
48
+ refuse("explicit_probe_authorization_required");
49
+ const nativeConfigHome = input.nativeConfigHome ?? input.env.CODEX_HOME ?? path.join(input.env.HOME ?? os.homedir(), ".codex");
50
+ const executable = resolveHarnessCommand(input.home, input.profile.harness, "adapter");
51
+ const runtime = resolveHarnessCommand(input.home, input.profile.harness, "runtime");
52
+ const identity = { schema_id: "dd-flow/memory-native-probe-input@1", scope: input.scope,
53
+ profile: input.profile, maximum: input.maximum, native_config_home: nativeConfigHome,
54
+ request_sha256: input.requestSha256, adapter: { path: executable, sha256: sha(readBoundedReleaseFile(executable, 16 * 1024 * 1024)) },
55
+ runtime: { path: runtime, sha256: sha(readBoundedReleaseFile(runtime, 256 * 1024 * 1024)) } };
56
+ const root = path.join(input.home, "memory-init-native-probes", hybridDigest(input.scope));
57
+ fs.mkdirSync(root, { recursive: true, mode: 0o700 });
58
+ if (fs.realpathSync(root) !== root)
59
+ refuse("linked_probe_root", "unknown");
60
+ const lease = acquireInstallationLock(path.join(root, "probe.lock"), hybridDigest(identity));
61
+ try {
62
+ const prior = read(path.join(root, "input.json"));
63
+ if (prior && hybridDigest(prior) !== hybridDigest(identity))
64
+ refuse("probe_selection_changed", "unknown");
65
+ if (!prior)
66
+ retain(path.join(root, "input.json"), identity);
67
+ const result = read(path.join(root, "capacity.json"));
68
+ const publish = async (proof) => {
69
+ const cleanup = proof.cleanup;
70
+ const start = read(path.join(root, "daemon-start.json"));
71
+ const rootSessionId = adapterSessionId(read(path.join(root, "session-create.json")));
72
+ const inspected = read(path.join(root, "session-inspect.json"));
73
+ const children = rootSessionId && inspected ? normalizeNativeChildren(inspected, rootSessionId) : [];
74
+ for (const phase of ["daemon-start", "session-create", "session-prompt", "daemon-stop"]) {
75
+ const operationId = `memory-native:${hybridDigest(identity)}:${phase}`;
76
+ const observed = await inspectDaemonOperation(path.join(root, "daemon"), operationId).catch(() => null);
77
+ const fingerprint = read(path.join(root, `${phase}.request-proof.json`));
78
+ const intent = read(path.join(root, `${phase}.intent.json`));
79
+ const expected = read(path.join(root, `${phase}.json`));
80
+ if (!observed || !fingerprint || fingerprint.command_sha256 !== intent?.command_sha256
81
+ || observed.invocation_sha256 !== fingerprint.command_sha256 || observed.params_sha256 !== fingerprint.params_sha256
82
+ || observed.operation_id !== operationId || observed.state !== "completed"
83
+ || phase !== "daemon-start" && observed.daemon_id !== start?.daemon_id
84
+ || hybridDigest(publicReply(observed.result)) !== hybridDigest(expected))
85
+ refuse("probe_provider_custody_changed", "unknown");
86
+ }
87
+ if (hybridDigest(proof.input) !== hybridDigest(identity) || proof.failure || !rootSessionId
88
+ || proof.root_session_id !== rootSessionId || hybridDigest(proof.inspected) !== hybridDigest(inspected)
89
+ || hybridDigest(proof.children) !== hybridDigest(children) || proof.capacity !== children.length
90
+ || children.length < input.maximum || children.length > input.maximum || new Set(children.map(child => child.session_id)).size !== children.length
91
+ || children.some(child => child.session_id === rootSessionId || child.parent_session_id !== rootSessionId || child.provenance === "parent_mismatch")
92
+ || cleanup?.stopped !== true || cleanup.settled !== true || cleanup.shutdown_contract !== "dd-flow/daemon-shutdown@1"
93
+ || typeof start?.daemon_id !== "string" || cleanup.daemon_id !== start.daemon_id
94
+ || hybridDigest(cleanup) !== hybridDigest(read(path.join(root, "daemon-stop.json"))))
95
+ refuse("probe_not_qualified", "partial");
96
+ const bytes = Buffer.from(JSON.stringify(proof)), checksum = sha(bytes);
97
+ const reference = { path: "execution/native-capacity.json", sha256: checksum };
98
+ const receipts = new Map([[checksum, { kind: "native-capacity", requestId: input.scope.requestId,
99
+ projectRoot: input.scope.projectRoot, workspace: input.scope.workspaceRoot,
100
+ harness: input.profile.harness, profileRevision: hybridDigest(input.profile), capacity: Number(proof.capacity) }]]);
101
+ return { reference, receipts, receiptBytes: new Map([[checksum, bytes]]) };
102
+ };
103
+ if (result)
104
+ return await publish(result);
105
+ // An independent bounded technical workspace cannot modify the target.
106
+ const workspace = path.join(root, "project"), stateDir = path.join(root, "daemon");
107
+ fs.mkdirSync(workspace, { recursive: true, mode: 0o700 });
108
+ const common = ["--state-dir", stateDir, "--cwd", workspace, "--journal", path.join(root, "events.jsonl"),
109
+ "--no-flow", ...harnessRuntimeArguments(input.home, input.profile.harness)];
110
+ const env = { ...input.env, ...(input.nativeConfigHome !== undefined ? { CODEX_HOME: input.nativeConfigHome } : {}),
111
+ DD_FLOW_CONFIG_HOME: input.home, DD_FLOW_RESOURCE_HOME: path.join(root, "resources") };
112
+ delete env.DD_FLOW_HOME;
113
+ delete env.DD_FLOW_BIN;
114
+ delete env.DD_FLOW_ENGINE_HOME;
115
+ const call = async (phase, args, timeoutMs = 120_000) => {
116
+ lease.assertOwnership();
117
+ const operationId = `memory-native:${hybridDigest(identity)}:${phase}`;
118
+ const command = nativeCommandFingerprint({ executable, args: [...args, ...common], cwd: workspace, env, operationId });
119
+ const received = read(path.join(root, `${phase}.json`));
120
+ const intent = read(path.join(root, `${phase}.intent.json`));
121
+ if (intent && (intent.operation_id !== operationId || hybridDigest(intent.args) !== hybridDigest(args)
122
+ || intent.command_sha256 !== command))
123
+ refuse("phase_request_changed", "unknown");
124
+ const durable = phase !== "session-inspect";
125
+ if (received || intent) {
126
+ if (!durable && received && intent)
127
+ return received;
128
+ // The shared adapter builder retained this before RPC/provider dispatch,
129
+ // independently of both the eventual reply and the local ACK receipt.
130
+ const witness = read(path.join(root, `${phase}.request-proof.json`));
131
+ if (!witness)
132
+ refuse(`unresolved_${phase}`, "unknown");
133
+ const observed = await inspectDaemonOperation(stateDir, operationId).catch(() => null);
134
+ const start = read(path.join(root, "daemon-start.json"));
135
+ if (observed?.operation_id !== operationId || observed.operation !== args.slice(0, 2).join(".")
136
+ || witness.command_sha256 !== command || observed.invocation_sha256 !== command
137
+ || observed.params_sha256 !== witness.params_sha256 || !/^[a-f0-9]{64}$/.test(String(observed.params_sha256))
138
+ || phase !== "daemon-start" && observed.daemon_id !== start?.daemon_id
139
+ || observed.state !== "completed" || !observed.result || typeof observed.result !== "object"
140
+ || observed.settlement && !["not_required", "settled"].includes(String(observed.settlement.state)))
141
+ refuse(`unresolved_${phase}`, "unknown");
142
+ const recovered = publicReply(observed.result);
143
+ if (received) {
144
+ if (hybridDigest(received) !== hybridDigest(recovered))
145
+ refuse("phase_receipt_changed", "unknown");
146
+ return received;
147
+ }
148
+ retain(path.join(root, `${phase}.json`), recovered);
149
+ return recovered;
150
+ }
151
+ retain(path.join(root, `${phase}.intent.json`), { operation_id: operationId, args, command_sha256: command });
152
+ let reply;
153
+ try {
154
+ const parent = fs.lstatSync(root);
155
+ reply = await runHarnessAdapter({ executable, args: [...args, ...common], env: { ...env,
156
+ DD_FLOW_NATIVE_REQUEST_PROOF_FILE: path.join(root, `${phase}.request-proof.json`), DD_FLOW_NATIVE_COMMAND_SHA256: command,
157
+ DD_FLOW_NATIVE_REQUEST_OPERATION: args.slice(0, 2).join("."), DD_FLOW_NATIVE_REQUEST_PROOF_OWNER: JSON.stringify({ dev: parent.dev, ino: parent.ino }) }, operationId,
158
+ harness: input.profile.harness, cwd: workspace, timeoutMs, signal: AbortSignal.timeout(timeoutMs) });
159
+ }
160
+ catch (error) {
161
+ if (!durable)
162
+ throw error;
163
+ // Lost first ACK is observation loss, not permission to launch again.
164
+ const witness = read(path.join(root, `${phase}.request-proof.json`));
165
+ const observed = await inspectDaemonOperation(stateDir, operationId).catch(() => null);
166
+ const start = read(path.join(root, "daemon-start.json"));
167
+ if (!witness || witness.operation_id !== operationId || witness.operation !== args.slice(0, 2).join(".")
168
+ || observed?.operation_id !== operationId || observed.operation !== witness.operation
169
+ || witness.command_sha256 !== command || observed.invocation_sha256 !== command
170
+ || observed.params_sha256 !== witness.params_sha256 || observed.state !== "completed"
171
+ || phase !== "daemon-start" && observed.daemon_id !== start?.daemon_id
172
+ || observed.settlement && observed.settlement.state !== "not_required"
173
+ && observed.settlement.state !== "settled"
174
+ || !observed.result || typeof observed.result !== "object")
175
+ throw error;
176
+ reply = publicReply(observed.result);
177
+ }
178
+ if (durable) {
179
+ const observed = await inspectDaemonOperation(stateDir, operationId);
180
+ const witness = read(path.join(root, `${phase}.request-proof.json`));
181
+ if (observed.operation_id !== operationId || observed.state !== "completed" || !witness
182
+ || witness.command_sha256 !== command || observed.invocation_sha256 !== command
183
+ || observed.params_sha256 !== witness.params_sha256)
184
+ refuse(`unresolved_${phase}`, "unknown");
185
+ }
186
+ retain(path.join(root, `${phase}.json`), reply);
187
+ return reply;
188
+ };
189
+ let inspected, rootSessionId = null;
190
+ let failure, cleanup;
191
+ try {
192
+ await call("daemon-start", ["daemon", "start"]);
193
+ const created = await call("session-create", ["session", "create", "--model", input.profile.model, "--reasoning", input.profile.reasoning]);
194
+ rootSessionId = adapterSessionId(created);
195
+ if (!rootSessionId)
196
+ refuse("root_session_identity_missing", "unknown");
197
+ await call("session-prompt", ["session", "prompt", "--session-id", rootSessionId, "--model", input.profile.model,
198
+ "--reasoning", input.profile.reasoning, "--prompt", renderCapacityInstructions({ harness: input.profile.harness, maximum: input.maximum })], 180_000);
199
+ inspected = await call("session-inspect", ["session", "inspect", "--session-id", rootSessionId]);
200
+ }
201
+ catch (error) {
202
+ failure = errorRecord(error);
203
+ // Retain a physical tree observation before owned shutdown, even when the
204
+ // prompt ACK is unknown. A later exact terminal receipt can then reconcile
205
+ // without needing to restart the stopped daemon or resend productive work.
206
+ if (rootSessionId && !read(path.join(root, "session-inspect.intent.json"))) {
207
+ try {
208
+ inspected = await call("session-inspect", ["session", "inspect", "--session-id", rootSessionId]);
209
+ }
210
+ catch { /* The unresolved observation remains pending, never fabricated. */ }
211
+ }
212
+ }
213
+ finally {
214
+ try {
215
+ const start = read(path.join(root, "daemon-start.json")), daemon = read(path.join(stateDir, "daemon.json"));
216
+ if (!start || typeof start.daemon_id !== "string" || daemon?.daemon_id !== start.daemon_id)
217
+ refuse("cleanup_daemon_incarnation_unknown", "unknown");
218
+ cleanup = await call("daemon-stop", ["daemon", "stop", "--cancel-tree"]);
219
+ }
220
+ catch (error) {
221
+ failure ??= errorRecord(error);
222
+ }
223
+ }
224
+ const children = rootSessionId && inspected ? normalizeNativeChildren(inspected, rootSessionId) : [];
225
+ const qualified = !failure && cleanup?.stopped === true && cleanup.settled === true
226
+ && cleanup.shutdown_contract === "dd-flow/daemon-shutdown@1" && typeof cleanup.daemon_id === "string"
227
+ && children.length === input.maximum && children.length <= 15
228
+ && children.every(child => child.parent_session_id === rootSessionId && child.session_id !== rootSessionId && child.provenance !== "parent_mismatch");
229
+ const proof = { schema_id: "dd-flow/memory-native-capacity@1", input: identity, root_session_id: rootSessionId,
230
+ inspected, cleanup, children, capacity: children.length, qualified, ...(failure ? { failure } : {}) };
231
+ if (failure) {
232
+ fs.appendFileSync(path.join(root, "observations.jsonl"), `${JSON.stringify(proof)}\n`, { mode: 0o600 });
233
+ refuse("probe_operation_unresolved", "unknown");
234
+ }
235
+ retain(path.join(root, "capacity.json"), proof);
236
+ return await publish(proof);
237
+ }
238
+ finally {
239
+ lease.release();
240
+ }
241
+ }