@deksden-com/dd-flow-cli 0.9.0-beta.136 → 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.
- package/CHANGELOG.md +12 -0
- package/README.md +9 -0
- package/dist/build-info.json +6 -6
- package/dist/cli/argument-values.js +5 -5
- package/dist/cli/command-inputs.js +89 -20
- package/dist/cli/command-metadata.js +56 -3
- package/dist/cli/command-option-descriptions.js +5 -0
- package/dist/cli/executor-onboarding.js +8 -3
- package/dist/cli/flows.js +29 -0
- package/dist/cli/help.js +240 -6
- package/dist/cli/input-preparation.js +54 -5
- package/dist/cli/memory-flow-admission.js +44 -0
- package/dist/cli/memory-init-invocation.js +78 -0
- package/dist/cli/memory-init.js +240 -0
- package/dist/cli/memory-storage-admission.js +53 -0
- package/dist/cli/native-hook-ingress.js +1 -1
- package/dist/cli/response-file.js +2 -0
- package/dist/cli/run-cli.js +283 -160
- package/dist/cli/setup.js +9 -7
- package/dist/cli.js +54 -2
- package/dist/domain/stage-handler-identities.js +20 -0
- package/dist/harness-runtime/DD-ZCODE.md +13 -0
- package/dist/harness-runtime/bin/dd-opencode.mjs +3 -3
- package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +4 -2
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +11 -5
- package/dist/harness-runtime/lib/dd-codex.mjs +22 -10
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
- package/dist/harness-runtime/lib/dd-droid.mjs +2 -1
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +4 -2
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +20 -5
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +45 -10
- package/dist/harness-runtime/lib/dd-zcode.mjs +7 -3
- package/dist/harness-runtime/lib/delegation-instructions.mjs +5 -3
- package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
- package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
- package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
- package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
- package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
- package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
- package/dist/harness-runtime/lib/opencode-plugin.mjs +5 -1
- package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
- package/dist/runtime/context.js +1 -1
- package/dist/schemas/discovery-result.schema.json +184 -0
- package/dist/schemas/execution-bundle.schema.json +205 -0
- package/dist/schemas/execution-settings.schema.json +162 -0
- package/dist/schemas/flow-descriptor.schema.json +54 -0
- package/dist/schemas/flow-run.schema.json +22 -0
- package/dist/schemas/harness-catalog.schema.json +80 -0
- package/dist/schemas/mb-init-compose-result.schema.json +457 -0
- package/dist/schemas/mb-init-discover-result.schema.json +500 -0
- package/dist/schemas/mb-init-finish-result.schema.json +422 -0
- package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
- package/dist/schemas/mb-init-review-result.schema.json +396 -0
- package/dist/schemas/mb-init-verify-result.schema.json +391 -0
- package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
- package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
- package/dist/schemas/memory-composition-work-result.schema.json +38 -0
- package/dist/schemas/memory-repair-work-result.schema.json +49 -0
- package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
- package/dist/schemas/memory-review-work-result.schema.json +43 -0
- package/dist/schemas/model-catalog.schema.json +153 -0
- package/dist/schemas/profile-settings.schema.json +122 -0
- package/dist/schemas/release-manifest.schema.json +291 -0
- package/dist/schemas/run-engine-binding.schema.json +1 -1
- package/dist/services/check-runner-evidence.js +51 -4
- package/dist/services/cli-operation-classifier.js +8 -47
- package/dist/services/code-checks.js +387 -34
- package/dist/services/controller-child-observer.js +99 -0
- package/dist/services/controller-execution.js +88 -0
- package/dist/services/controller-fanout.js +79 -13
- package/dist/services/dashboard.js +8 -2
- package/dist/services/descriptor-coordinator-session.js +35 -0
- package/dist/services/descriptor-root-work.js +53 -0
- package/dist/services/descriptor-run-settlement.js +105 -0
- package/dist/services/descriptor-run-start.js +449 -0
- package/dist/services/descriptor-stage-coordinator.js +197 -0
- package/dist/services/descriptor-stage-settlement.js +222 -0
- package/dist/services/descriptor-stage-start.js +139 -0
- package/dist/services/engines.js +39 -22
- package/dist/services/eval-snapshots.js +83 -25
- package/dist/services/execution-bundles.js +263 -0
- package/dist/services/execution-policy.js +20 -16
- package/dist/services/external-work-launch.js +91 -11
- package/dist/services/flow-catalog.js +21 -0
- package/dist/services/flow-descriptors.js +82 -0
- package/dist/services/frozen-engine.js +242 -0
- package/dist/services/generic-execution.js +164 -0
- package/dist/services/harness-adapter.js +28 -2
- package/dist/services/hooks.js +24 -6
- package/dist/services/hybrid-contracts.js +31 -3
- package/dist/services/ids.js +29 -1
- package/dist/services/installation-lock.js +7 -4
- package/dist/services/installed-flow-source.js +183 -0
- package/dist/services/lifecycle-invocations.js +257 -78
- package/dist/services/memory-accepted-composition.js +77 -0
- package/dist/services/memory-baseline-preservation.js +65 -0
- package/dist/services/memory-completed-correction-wave.js +320 -0
- package/dist/services/memory-compose-handler.js +258 -0
- package/dist/services/memory-composition-acceptance.js +199 -0
- package/dist/services/memory-composition-graph.js +134 -0
- package/dist/services/memory-composition-registration.js +146 -0
- package/dist/services/memory-composition-work-custody.js +151 -0
- package/dist/services/memory-composition-work-results.js +96 -0
- package/dist/services/memory-corrected-review-acceptance.js +129 -0
- package/dist/services/memory-corrected-review-batch.js +30 -0
- package/dist/services/memory-corrected-review-findings.js +106 -0
- package/dist/services/memory-corrected-review-inputs.js +210 -0
- package/dist/services/memory-corrected-review-projection.js +78 -0
- package/dist/services/memory-corrected-review-receipt.js +170 -0
- package/dist/services/memory-corrected-review-registration.js +191 -0
- package/dist/services/memory-correction-check-receipt.js +219 -0
- package/dist/services/memory-correction-input-owner.js +6 -0
- package/dist/services/memory-discover-handler.js +104 -0
- package/dist/services/memory-finish-evidence.js +435 -0
- package/dist/services/memory-finish-handler.js +215 -0
- package/dist/services/memory-finish-integration.js +280 -0
- package/dist/services/memory-finish-readiness.js +122 -0
- package/dist/services/memory-git-integration.js +151 -0
- package/dist/services/memory-historical-corrected-review.js +206 -0
- package/dist/services/memory-historical-original-review.js +130 -0
- package/dist/services/memory-historical-repair-registration.js +99 -0
- package/dist/services/memory-historical-second-review.js +128 -0
- package/dist/services/memory-init-bootstrap-readiness.js +210 -0
- package/dist/services/memory-init-contexts.js +89 -0
- package/dist/services/memory-init-controller-start.js +84 -0
- package/dist/services/memory-init-engine-release.js +223 -0
- package/dist/services/memory-init-git-policy.js +136 -0
- package/dist/services/memory-init-lint-capability.js +185 -0
- package/dist/services/memory-init-native-capacity.js +241 -0
- package/dist/services/memory-init-preflight.js +312 -0
- package/dist/services/memory-init-project-bootstrap.js +599 -0
- package/dist/services/memory-init-request-candidate.js +157 -0
- package/dist/services/memory-init-request-input.js +66 -0
- package/dist/services/memory-init-resource-storage.js +125 -0
- package/dist/services/memory-init-run-allocation.js +81 -0
- package/dist/services/memory-init-run-bundle.js +98 -0
- package/dist/services/memory-init-start.js +175 -0
- package/dist/services/memory-init-startup-custody.js +80 -0
- package/dist/services/memory-init-startup-input.js +240 -0
- package/dist/services/memory-init-storage.js +81 -0
- package/dist/services/memory-init-stores.js +359 -0
- package/dist/services/memory-init-worktrunk-capability.js +172 -0
- package/dist/services/memory-layer-publication.js +611 -0
- package/dist/services/memory-layer.js +156 -0
- package/dist/services/memory-lint-config.js +85 -0
- package/dist/services/memory-native-review-copy.js +165 -0
- package/dist/services/memory-normal-flow-entry.js +75 -0
- package/dist/services/memory-ordinary-defaults.js +112 -0
- package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
- package/dist/services/memory-preflight-handler.js +259 -0
- package/dist/services/memory-repair-current-view.js +299 -0
- package/dist/services/memory-repair-document-delta.js +451 -0
- package/dist/services/memory-repair-history.js +491 -0
- package/dist/services/memory-repair-physical-binding.js +312 -0
- package/dist/services/memory-repair-publication-files.js +152 -0
- package/dist/services/memory-repair-publication-intent.js +27 -0
- package/dist/services/memory-repair-publication-plan.js +160 -0
- package/dist/services/memory-repair-publication-source.js +225 -0
- package/dist/services/memory-repair-publication.js +794 -0
- package/dist/services/memory-repair-registration.js +239 -0
- package/dist/services/memory-repair-work-baseline.js +413 -0
- package/dist/services/memory-repair-work-completion.js +97 -0
- package/dist/services/memory-repair-work-custody.js +73 -0
- package/dist/services/memory-repair-work-results.js +89 -0
- package/dist/services/memory-repair-workspace.js +252 -0
- package/dist/services/memory-repair-writer-copy.js +735 -0
- package/dist/services/memory-result-binding.js +173 -0
- package/dist/services/memory-retained-review-authority.js +129 -0
- package/dist/services/memory-retained-review-results.js +70 -0
- package/dist/services/memory-retained-second-baseline.js +102 -0
- package/dist/services/memory-retained-second-repairs.js +156 -0
- package/dist/services/memory-review-acceptance.js +214 -0
- package/dist/services/memory-review-correction-plan.js +171 -0
- package/dist/services/memory-review-handler.js +585 -0
- package/dist/services/memory-review-inputs.js +200 -0
- package/dist/services/memory-review-receipt.js +180 -0
- package/dist/services/memory-review-registration.js +108 -0
- package/dist/services/memory-review-work-custody.js +124 -0
- package/dist/services/memory-review-work-input.js +72 -0
- package/dist/services/memory-review-work-results.js +73 -0
- package/dist/services/memory-second-corrected-review-inputs.js +165 -0
- package/dist/services/memory-second-correction-plan.js +76 -0
- package/dist/services/memory-second-repair-baseline.js +91 -0
- package/dist/services/memory-second-repair-launch.js +614 -0
- package/dist/services/memory-second-repair-registration.js +88 -0
- package/dist/services/memory-second-repair-source.js +187 -0
- package/dist/services/memory-second-review-acceptance.js +115 -0
- package/dist/services/memory-source-observations.js +117 -0
- package/dist/services/memory-stage-dispatch.js +28 -0
- package/dist/services/memory-stage-results.js +199 -0
- package/dist/services/memory-verification-acceptance.js +135 -0
- package/dist/services/memory-verification-checks.js +252 -0
- package/dist/services/memory-verification-receipt.js +159 -0
- package/dist/services/memory-verify-handler.js +135 -0
- package/dist/services/memory-work-result-preparation.js +63 -0
- package/dist/services/projects.js +17 -2
- package/dist/services/recovery-snapshot-database.js +416 -1
- package/dist/services/repair-intents.js +1 -1
- package/dist/services/review-copy.js +10 -2
- package/dist/services/run-control.js +80 -9
- package/dist/services/run-controller-capture.js +10 -3
- package/dist/services/run-controller-process.js +21 -0
- package/dist/services/run-controller-recovery.js +3 -1
- package/dist/services/run-controller-state.js +1 -1
- package/dist/services/run-controller.js +184 -48
- package/dist/services/run-recovery-guard.js +2 -0
- package/dist/services/run-recovery.js +145 -5
- package/dist/services/run-start-custody.js +177 -0
- package/dist/services/runs.js +319 -25
- package/dist/services/stage-context.js +9 -1
- package/dist/services/stage-handlers.js +74 -0
- package/dist/services/stage-lifecycle.js +2 -1
- package/dist/services/stage-report-renderer.js +76 -0
- package/dist/services/stage-work-graph.js +17 -0
- package/dist/services/vnext-code.js +3 -3
- package/dist/services/vnext-execution-profile.js +2 -2
- package/dist/services/vnext-fanout.js +136 -10
- package/dist/services/vnext-merge.js +8 -3
- package/dist/services/vnext-plan-review.js +6 -4
- package/dist/services/vnext-protocolize.js +60 -2
- package/dist/services/work-registry.js +616 -71
- package/dist/services/workspace-files.js +1 -1
- package/dist/storage/database.js +84 -6
- package/dist/storage/writer-contract.js +11 -7
- package/package.json +13 -3
- package/tools/create-canon-release.mjs +33 -0
- package/tools/produce-hybrid-release.mjs +41 -0
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import semver from "semver";
|
|
5
|
+
import { AppError } from "../shared/errors.js";
|
|
6
|
+
import { hybridDigest } from "./hybrid-contracts.js";
|
|
7
|
+
import { FrozenGenericExecution } from "./generic-execution.js";
|
|
8
|
+
import { PreparedMemoryInitTarget } from "./memory-init-preflight.js";
|
|
9
|
+
import { PreparedMemoryInitRuntimeStorage } from "./memory-init-storage.js";
|
|
10
|
+
import { PreparedMemoryLayer } from "./memory-layer.js";
|
|
11
|
+
import { publishMemoryInitDraftIdentity, readRetainedMemoryLayer, restorePublishedMemoryLayer } from "./memory-layer-publication.js";
|
|
12
|
+
import { PreparedProjectRegistration, registerPreparedProject } from "./projects.js";
|
|
13
|
+
import { resolveHarnessCommand } from "./harness-config.js";
|
|
14
|
+
import { readBoundedReleaseFile } from "./release-source.js";
|
|
15
|
+
import { appendAudit } from "./audit.js";
|
|
16
|
+
import { PreparedMemoryInitLintCapability, isMemoryInitLintCapabilityFacts } from "./memory-init-lint-capability.js";
|
|
17
|
+
import { PreparedMemoryInitWorktrunkCapability, isMemoryInitWorktrunkCapabilityFacts } from "./memory-init-worktrunk-capability.js";
|
|
18
|
+
import { PreparedMemoryInitResourceStorage, isMemoryInitResourceStorageFacts } from "./memory-init-resource-storage.js";
|
|
19
|
+
import { AdmittedFrozenEngine } from "./frozen-engine.js";
|
|
20
|
+
import { resourceHome } from "./managed-processes.js";
|
|
21
|
+
import { readSetupStatus } from "./setup.js";
|
|
22
|
+
import { readMemoryInitGitPolicy } from "./memory-init-git-policy.js";
|
|
23
|
+
const intentEvent = "memory.init_project_bootstrap_intent", receiptEvent = "memory.init_project_bootstrap";
|
|
24
|
+
const digest = (value) => createHash("sha256").update(value).digest("hex");
|
|
25
|
+
function refuse(reason, effect = "no_effect") {
|
|
26
|
+
throw new AppError("memory_init_project_bootstrap_invalid", "Project bootstrap cannot proceed without its exact request custody", 1, { reason, effect, next_action: "reconcile_exact_request" });
|
|
27
|
+
}
|
|
28
|
+
function row(context, scope, event) {
|
|
29
|
+
if (!scope || !/^[A-Za-z0-9][A-Za-z0-9_.-]{0,95}$/.test(scope.requestId)
|
|
30
|
+
|| !path.isAbsolute(scope.projectRoot) || !path.isAbsolute(scope.workspaceRoot)
|
|
31
|
+
|| Object.keys(scope).some(key => !["requestId", "projectRoot", "workspaceRoot"].includes(key)))
|
|
32
|
+
refuse("invalid_request_scope");
|
|
33
|
+
const rows = context.db.all("SELECT id, project_id, payload_json FROM audit_events WHERE event_type = ? AND json_extract(payload_json, '$.scope.requestId') = ? AND json_extract(payload_json, '$.scope.projectRoot') = ? AND json_extract(payload_json, '$.scope.workspaceRoot') = ? LIMIT 2", [event, scope.requestId, scope.projectRoot, scope.workspaceRoot]);
|
|
34
|
+
if (rows.length > 1)
|
|
35
|
+
refuse("ambiguous_request_custody");
|
|
36
|
+
const selected = rows[0];
|
|
37
|
+
if (!selected)
|
|
38
|
+
return null;
|
|
39
|
+
try {
|
|
40
|
+
if (Buffer.byteLength(selected.payload_json) > 1024 * 1024)
|
|
41
|
+
refuse("unbounded_request_custody");
|
|
42
|
+
return { ...selected, value: JSON.parse(selected.payload_json) };
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error instanceof AppError)
|
|
46
|
+
throw error;
|
|
47
|
+
return refuse("invalid_request_custody");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** SQL-only prepublication release selection. Current setup defaults are not a
|
|
51
|
+
* restart source, and old draft receipts do not fabricate this missing proof.
|
|
52
|
+
*/
|
|
53
|
+
export function readMemoryInitReleaseSelection(context, scope) {
|
|
54
|
+
const retained = row(context, scope, "memory.init_release_selection");
|
|
55
|
+
if (!retained)
|
|
56
|
+
return null;
|
|
57
|
+
const value = retained.value;
|
|
58
|
+
if (value.schema_id !== "dd-flow/memory-init-release-selection@1" || hybridDigest(value.scope) !== hybridDigest(scope)
|
|
59
|
+
|| Object.keys(value).sort().join() !== "bootstrap_identity,execution_sha256,installation_manifest_base64,installation_manifest_sha256,pack_sha256,schema_id,scope"
|
|
60
|
+
|| [value.bootstrap_identity, value.execution_sha256, value.pack_sha256, value.installation_manifest_sha256].some(sha => typeof sha !== "string" || !/^[a-f0-9]{64}$/.test(sha))
|
|
61
|
+
|| typeof value.installation_manifest_base64 !== "string" || value.installation_manifest_base64.length > 1024 * 1024)
|
|
62
|
+
refuse("release_selection_custody_changed");
|
|
63
|
+
const bytes = Buffer.from(value.installation_manifest_base64, "base64");
|
|
64
|
+
if (!bytes.length || bytes.toString("base64") !== value.installation_manifest_base64
|
|
65
|
+
|| digest(bytes) !== value.installation_manifest_sha256)
|
|
66
|
+
refuse("release_selection_custody_changed");
|
|
67
|
+
return structuredClone(value);
|
|
68
|
+
}
|
|
69
|
+
function readIntent(context, scope) {
|
|
70
|
+
const selected = row(context, scope, intentEvent);
|
|
71
|
+
if (!selected)
|
|
72
|
+
return null;
|
|
73
|
+
const value = selected.value;
|
|
74
|
+
if (!["dd-flow/memory-init-project-bootstrap-intent@1", "dd-flow/memory-init-project-bootstrap-intent@2", "dd-flow/memory-init-project-bootstrap-intent@3", "dd-flow/memory-init-project-bootstrap-intent@4"].includes(value.schema_id) || hybridDigest(value.scope) !== hybridDigest(scope)
|
|
75
|
+
|| !/^[a-f0-9]{64}$/.test(value.identity) || !["prepared", "registered"].includes(value.status)
|
|
76
|
+
|| Object.keys(value).some(key => !["schema_id", "scope", "identity", "expected_project", "status", "receipt_sha256", "lint_capability", "worktrunk_capability", "resource_storage"].includes(key))
|
|
77
|
+
|| (value.schema_id !== "dd-flow/memory-init-project-bootstrap-intent@1" ? !isMemoryInitLintCapabilityFacts(value.lint_capability) : value.lint_capability !== undefined)
|
|
78
|
+
|| (["dd-flow/memory-init-project-bootstrap-intent@3", "dd-flow/memory-init-project-bootstrap-intent@4"].includes(value.schema_id) ? !isMemoryInitWorktrunkCapabilityFacts(value.worktrunk_capability) : value.worktrunk_capability !== undefined)
|
|
79
|
+
|| (value.schema_id === "dd-flow/memory-init-project-bootstrap-intent@4" ? !isMemoryInitResourceStorageFacts(value.resource_storage) : value.resource_storage !== undefined)
|
|
80
|
+
|| value.expected_project !== null && (!value.expected_project || typeof value.expected_project.id !== "string"
|
|
81
|
+
|| value.expected_project.root !== scope.projectRoot || value.expected_project.status !== "active"
|
|
82
|
+
|| Object.keys(value.expected_project).some(key => !["id", "root", "status"].includes(key)))
|
|
83
|
+
|| (value.status === "prepared" ? value.receipt_sha256 !== null : typeof value.receipt_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(value.receipt_sha256)))
|
|
84
|
+
refuse("invalid_request_intent");
|
|
85
|
+
return { ...selected, intent: value };
|
|
86
|
+
}
|
|
87
|
+
/** One consistent SQL snapshot of historical custody, not current files/readiness. */
|
|
88
|
+
export function readMemoryInitProjectBootstrap(context, scope) {
|
|
89
|
+
return context.db.readSnapshot(() => readProjectBootstrapSnapshot(context, scope));
|
|
90
|
+
}
|
|
91
|
+
function readProjectBootstrapSnapshot(context, scope) {
|
|
92
|
+
const intent = readIntent(context, scope), selected = row(context, scope, receiptEvent);
|
|
93
|
+
if (!intent) {
|
|
94
|
+
if (selected)
|
|
95
|
+
refuse("bootstrap_intent_missing");
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
if (intent.intent.status === "prepared") {
|
|
99
|
+
if (selected)
|
|
100
|
+
refuse("uncommitted_bootstrap_receipt");
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (!selected)
|
|
104
|
+
refuse("bootstrap_receipt_missing");
|
|
105
|
+
const payload = selected.value, receipt = payload.receipt;
|
|
106
|
+
if (!receipt || !["dd-flow/memory-init-project-bootstrap@1", "dd-flow/memory-init-project-bootstrap@2", "dd-flow/memory-init-project-bootstrap@3", "dd-flow/memory-init-project-bootstrap@4"].includes(receipt.schema_id) || hybridDigest(receipt.scope) !== hybridDigest(scope)
|
|
107
|
+
|| Object.keys(payload).some(key => !["scope", "identity", "sha256", "receipt"].includes(key))
|
|
108
|
+
|| Object.keys(receipt).some(key => !["schema_id", "scope", "identity", "project_id", "target_sha256", "layer_sha256", "execution_sha256", "storage_sha256", "layer_publication_sha256", "draft_identity_sha256", "lint_capability_sha256", "worktrunk_capability_sha256", "resource_storage_sha256", "semantic_status", "created_at"].includes(key))
|
|
109
|
+
|| intent.intent.schema_id !== receipt.schema_id.replace("project-bootstrap@", "project-bootstrap-intent@")
|
|
110
|
+
|| (receipt.schema_id !== "dd-flow/memory-init-project-bootstrap@1" ? receipt.lint_capability_sha256 !== hybridDigest(intent.intent.lint_capability) : receipt.lint_capability_sha256 !== undefined)
|
|
111
|
+
|| (["dd-flow/memory-init-project-bootstrap@3", "dd-flow/memory-init-project-bootstrap@4"].includes(receipt.schema_id) ? receipt.worktrunk_capability_sha256 !== hybridDigest(intent.intent.worktrunk_capability) : receipt.worktrunk_capability_sha256 !== undefined)
|
|
112
|
+
|| (receipt.schema_id === "dd-flow/memory-init-project-bootstrap@4" ? receipt.resource_storage_sha256 !== hybridDigest(intent.intent.resource_storage) : receipt.resource_storage_sha256 !== undefined)
|
|
113
|
+
|| typeof receipt.project_id !== "string" || !receipt.project_id
|
|
114
|
+
|| receipt.identity !== intent.intent.identity || payload.identity !== receipt.identity || payload.sha256 !== hybridDigest(receipt)
|
|
115
|
+
|| payload.sha256 !== intent.intent.receipt_sha256 || selected.project_id !== receipt.project_id
|
|
116
|
+
|| receipt.semantic_status !== "draft_not_accepted" || typeof receipt.created_at !== "string" || !Number.isFinite(Date.parse(receipt.created_at))
|
|
117
|
+
|| [receipt.target_sha256, receipt.layer_sha256, receipt.execution_sha256, receipt.storage_sha256,
|
|
118
|
+
receipt.layer_publication_sha256, receipt.draft_identity_sha256].some(value => typeof value !== "string" || !/^[a-f0-9]{64}$/.test(value)))
|
|
119
|
+
refuse("bootstrap_receipt_changed");
|
|
120
|
+
if (!context.db.get("SELECT 1 FROM projects WHERE id = ? AND root = ?", [receipt.project_id, scope.projectRoot]))
|
|
121
|
+
refuse("registered_project_identity_changed");
|
|
122
|
+
return { receipt: structuredClone(receipt), sha256: payload.sha256 };
|
|
123
|
+
}
|
|
124
|
+
/** Independent SQL proof lookup; historical v1 never gains new qualification. */
|
|
125
|
+
export function readMemoryInitProjectBootstrapLintCapability(context, scope) {
|
|
126
|
+
const registered = readMemoryInitProjectBootstrap(context, scope);
|
|
127
|
+
if (!registered || registered.receipt.schema_id === "dd-flow/memory-init-project-bootstrap@1")
|
|
128
|
+
return null;
|
|
129
|
+
const facts = readIntent(context, scope)?.intent.lint_capability;
|
|
130
|
+
if (!isMemoryInitLintCapabilityFacts(facts) || hybridDigest(facts) !== registered.receipt.lint_capability_sha256)
|
|
131
|
+
refuse("lint_capability_custody_changed");
|
|
132
|
+
return { facts: structuredClone(facts), sha256: registered.receipt.lint_capability_sha256 };
|
|
133
|
+
}
|
|
134
|
+
/** Independently retained functional proof; historical @1/@2 never gain it. */
|
|
135
|
+
export function readMemoryInitProjectBootstrapWorktrunkCapability(context, scope) {
|
|
136
|
+
const registered = readMemoryInitProjectBootstrap(context, scope);
|
|
137
|
+
if (!registered || !["dd-flow/memory-init-project-bootstrap@3", "dd-flow/memory-init-project-bootstrap@4"].includes(registered.receipt.schema_id))
|
|
138
|
+
return null;
|
|
139
|
+
const facts = readIntent(context, scope)?.intent.worktrunk_capability;
|
|
140
|
+
if (!isMemoryInitWorktrunkCapabilityFacts(facts) || hybridDigest(facts) !== registered.receipt.worktrunk_capability_sha256)
|
|
141
|
+
refuse("worktrunk_capability_custody_changed");
|
|
142
|
+
return { facts: structuredClone(facts), sha256: registered.receipt.worktrunk_capability_sha256 };
|
|
143
|
+
}
|
|
144
|
+
/** Independent retained storage proof; historical @1/@2/@3 never gain it. */
|
|
145
|
+
export function readMemoryInitProjectBootstrapResourceStorage(context, scope) {
|
|
146
|
+
const registered = readMemoryInitProjectBootstrap(context, scope);
|
|
147
|
+
if (!registered || registered.receipt.schema_id !== "dd-flow/memory-init-project-bootstrap@4")
|
|
148
|
+
return null;
|
|
149
|
+
const facts = readIntent(context, scope)?.intent.resource_storage;
|
|
150
|
+
if (!isMemoryInitResourceStorageFacts(facts) || hybridDigest(facts) !== registered.receipt.resource_storage_sha256)
|
|
151
|
+
refuse("resource_storage_custody_changed");
|
|
152
|
+
return { facts: structuredClone(facts), sha256: registered.receipt.resource_storage_sha256 };
|
|
153
|
+
}
|
|
154
|
+
/** Historical registration alone cannot attest engine-bound draft bootstrap. */
|
|
155
|
+
export function readMemoryInitProjectBootstrapEngineAdmission(context, scope) {
|
|
156
|
+
return context.db.readSnapshot(() => {
|
|
157
|
+
const accepted = row(context, scope, "memory.init_engine_bootstrap");
|
|
158
|
+
if (!accepted) {
|
|
159
|
+
if (row(context, scope, "memory.init_engine_admission")?.value.status === "accepted")
|
|
160
|
+
refuse("engine_bootstrap_custody_missing");
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const registered = readMemoryInitProjectBootstrap(context, scope), admission = row(context, scope, "memory.init_engine_admission");
|
|
164
|
+
if (!registered || !admission)
|
|
165
|
+
refuse("engine_bootstrap_custody_missing");
|
|
166
|
+
const value = admission.value, proof = value.proof;
|
|
167
|
+
const policyBound = value.schema_id === "dd-flow/memory-init-engine-admission@2";
|
|
168
|
+
const policy = policyBound ? readMemoryInitGitPolicy(context, scope) : null;
|
|
169
|
+
const policyBinding = policyBound ? { git_policy_sha256: value.git_policy_sha256 } : {};
|
|
170
|
+
if (policyBound && (!policy || policy.target_sha256 !== registered.receipt.target_sha256
|
|
171
|
+
|| hybridDigest(policy) !== value.git_policy_sha256))
|
|
172
|
+
refuse("git_policy_custody_changed");
|
|
173
|
+
if (Object.keys(value).sort().join() !== (policyBound
|
|
174
|
+
? "acceptance_sha256,bootstrap_identity,execution_sha256,git_policy_sha256,identity,proof,schema_id,scope,status"
|
|
175
|
+
: "acceptance_sha256,bootstrap_identity,execution_sha256,identity,proof,schema_id,scope,status")
|
|
176
|
+
|| value.status !== "accepted" || value.acceptance_sha256 !== hybridDigest(accepted.value)
|
|
177
|
+
|| !["dd-flow/memory-init-engine-admission@1", "dd-flow/memory-init-engine-admission@2"].includes(value.schema_id) || hybridDigest(value.scope) !== hybridDigest(scope)
|
|
178
|
+
|| value.bootstrap_identity !== registered.receipt.identity || value.execution_sha256 !== registered.receipt.execution_sha256
|
|
179
|
+
|| !proof || Object.keys(proof).sort().join() !== "engine_manifest_sha256,engine_sha256,facts,sha256"
|
|
180
|
+
|| !proof.facts || typeof proof.facts !== "object" || Array.isArray(proof.facts)
|
|
181
|
+
|| [proof.engine_manifest_sha256, proof.engine_sha256, proof.sha256].some(hash => typeof hash !== "string" || !/^[a-f0-9]{64}$/.test(hash))
|
|
182
|
+
|| hybridDigest(proof.facts) !== proof.sha256
|
|
183
|
+
|| value.identity !== hybridDigest({ scope, bootstrap_identity: value.bootstrap_identity, execution_sha256: value.execution_sha256, proof, ...policyBinding }))
|
|
184
|
+
refuse("engine_admission_custody_changed");
|
|
185
|
+
const expected = { schema_id: "dd-flow/memory-init-engine-bootstrap@1", scope,
|
|
186
|
+
admission_identity: value.identity, bootstrap_sha256: registered.sha256, project_id: registered.receipt.project_id };
|
|
187
|
+
if (accepted.project_id !== registered.receipt.project_id || hybridDigest(accepted.value) !== hybridDigest(expected))
|
|
188
|
+
refuse("engine_bootstrap_custody_changed");
|
|
189
|
+
return { identity: value.identity, proof: structuredClone(proof), bootstrap_sha256: registered.sha256,
|
|
190
|
+
...(policyBound ? { git_policy_sha256: value.git_policy_sha256 } : {}) };
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function project(context, root) {
|
|
194
|
+
return context.db.get("SELECT id, root, status FROM projects WHERE root = ?", [root]) ?? null;
|
|
195
|
+
}
|
|
196
|
+
/** Static selected command/permission admission, usable before runtime stores.
|
|
197
|
+
* No diagnostic, provider process or credential read is performed. Bootstrap
|
|
198
|
+
* still captures and revalidates these same command identities independently. */
|
|
199
|
+
export function prepareMemoryInitHarnessCommands(context, execution) {
|
|
200
|
+
return execution.snapshot().profiles.map(({ id, profile }) => {
|
|
201
|
+
if (profile.permission !== "allow")
|
|
202
|
+
refuse("profile_permission_denied");
|
|
203
|
+
const inspect = (kind) => {
|
|
204
|
+
try {
|
|
205
|
+
const configured = resolveHarnessCommand(context.ddFlowHome, profile.harness, kind), resolved = fs.realpathSync(configured);
|
|
206
|
+
fs.accessSync(resolved, fs.constants.X_OK);
|
|
207
|
+
return { configured, resolved, sha256: digest(readBoundedReleaseFile(resolved, 256 * 1024 * 1024)) };
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return refuse(`harness_command_unavailable:${profile.harness}:${kind}`);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
return { profile_id: id, harness: profile.harness, adapter: inspect("adapter"), runtime: inspect("runtime") };
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/** Productive project/draft registration, not a complete memory-bootstrap-receipt.
|
|
217
|
+
* Static command availability, frozen permission/routes, declared mb-lint minimum
|
|
218
|
+
* and executing run-store admission are checked before project effects. Selected
|
|
219
|
+
* mb-lint also passes isolated JSON/YAML/required-field/link behavior probes.
|
|
220
|
+
* Worktrunk passes an isolated actual Git-worktree creation probe before project
|
|
221
|
+
* effects. The executing CLI also admits the selected existing shared registry
|
|
222
|
+
* without initialization/migration. Frozen-engine/provider readiness and
|
|
223
|
+
* productive workspace custody still precede public dispatch.
|
|
224
|
+
*/
|
|
225
|
+
export class PreparedMemoryInitProjectBootstrap {
|
|
226
|
+
identity;
|
|
227
|
+
#scope;
|
|
228
|
+
#target;
|
|
229
|
+
#layer;
|
|
230
|
+
#execution;
|
|
231
|
+
#storage;
|
|
232
|
+
#project;
|
|
233
|
+
#commands;
|
|
234
|
+
#lint;
|
|
235
|
+
#worktrunk;
|
|
236
|
+
#resource;
|
|
237
|
+
#installationManifestBase64;
|
|
238
|
+
constructor(context, target, layer, execution, storage) {
|
|
239
|
+
const facts = target.facts();
|
|
240
|
+
this.#scope = { requestId: facts.request_id, projectRoot: facts.project_root, workspaceRoot: facts.workspace_root };
|
|
241
|
+
this.#target = target;
|
|
242
|
+
this.#layer = layer;
|
|
243
|
+
this.#execution = execution;
|
|
244
|
+
this.#storage = storage;
|
|
245
|
+
const retainedSelection = readMemoryInitReleaseSelection(context, this.#scope);
|
|
246
|
+
if (retainedSelection) {
|
|
247
|
+
if (retainedSelection.installation_manifest_sha256 !== layer.installationSha256)
|
|
248
|
+
refuse("bootstrap_installation_changed");
|
|
249
|
+
this.#installationManifestBase64 = retainedSelection.installation_manifest_base64;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
// Historical draft registration remains resumable without a current setup
|
|
253
|
+
// selection. Only productive readiness requires retained release proof.
|
|
254
|
+
const selection = readSetupStatus(context.ddFlowHome);
|
|
255
|
+
this.#installationManifestBase64 = selection.installation_readiness === "installed"
|
|
256
|
+
&& selection.installation?.manifest_sha256 === layer.installationSha256 ? selection.installation.manifest_bytes_base64 : null;
|
|
257
|
+
}
|
|
258
|
+
this.#project = PreparedProjectRegistration.prepare({ root: facts.project_root });
|
|
259
|
+
this.#resource = PreparedMemoryInitResourceStorage.prepare(context);
|
|
260
|
+
this.#commands = prepareMemoryInitHarnessCommands(context, execution);
|
|
261
|
+
this.#lint = PreparedMemoryInitLintCapability.prepare(target, context.env);
|
|
262
|
+
this.#worktrunk = PreparedMemoryInitWorktrunkCapability.prepare(target, context.env);
|
|
263
|
+
this.identity = hybridDigest({ scope: this.#scope, target: target.sha256, layer: layer.sha256,
|
|
264
|
+
execution: execution.sha256, storage: storage.sha256, resource: this.#resource.sha256, commands: this.#commands, lint: this.#lint.sha256, worktrunk: this.#worktrunk.sha256 });
|
|
265
|
+
Object.freeze(this);
|
|
266
|
+
}
|
|
267
|
+
/** Copied prepared release material; only the request owner may retain it.
|
|
268
|
+
* This is not engine, storage, provider or RUN readiness. */
|
|
269
|
+
releaseSelection() {
|
|
270
|
+
if (!this.#installationManifestBase64)
|
|
271
|
+
refuse("selected_release_manifest_unavailable");
|
|
272
|
+
return structuredClone({ schema_id: "dd-flow/memory-init-release-selection@1", scope: this.#scope,
|
|
273
|
+
bootstrap_identity: this.identity, execution_sha256: this.#execution.sha256, pack_sha256: this.#layer.packSha256,
|
|
274
|
+
installation_manifest_sha256: this.#layer.installationSha256, installation_manifest_base64: this.#installationManifestBase64 });
|
|
275
|
+
}
|
|
276
|
+
retainReadinessSelection(context) {
|
|
277
|
+
const value = this.releaseSelection();
|
|
278
|
+
context.db.writeTransaction(() => {
|
|
279
|
+
this.#storage.assertCompatibility(context);
|
|
280
|
+
const retained = readMemoryInitReleaseSelection(context, this.#scope);
|
|
281
|
+
if (retained) {
|
|
282
|
+
if (hybridDigest(retained) !== hybridDigest(value))
|
|
283
|
+
refuse("release_selection_custody_changed");
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (readMemoryInitProjectBootstrap(context, this.#scope))
|
|
287
|
+
refuse("historical_bootstrap_has_no_release_selection");
|
|
288
|
+
appendAudit(context, { eventType: "memory.init_release_selection", payload: value });
|
|
289
|
+
}, "memoryInit.retainReleaseSelection");
|
|
290
|
+
}
|
|
291
|
+
static prepare(context, input) {
|
|
292
|
+
if (!(input.target instanceof PreparedMemoryInitTarget) || !(input.layer instanceof PreparedMemoryLayer)
|
|
293
|
+
|| !(input.execution instanceof FrozenGenericExecution))
|
|
294
|
+
refuse("unprepared_bootstrap_input");
|
|
295
|
+
const facts = input.target.facts(), scope = input.execution.snapshot().scope;
|
|
296
|
+
if (input.execution.settings.flow_id !== "mb-init" || scope.requestId !== facts.request_id
|
|
297
|
+
|| scope.projectRoot !== facts.project_root || scope.workspace !== facts.workspace_root)
|
|
298
|
+
refuse("foreign_execution_scope");
|
|
299
|
+
const current = project(context, facts.project_root);
|
|
300
|
+
if (current && current.status !== "active")
|
|
301
|
+
refuse("project_not_active");
|
|
302
|
+
let minimum;
|
|
303
|
+
try {
|
|
304
|
+
const compatibility = JSON.parse(input.layer.files().get("dd-flow/compatibility.json").toString("utf8"));
|
|
305
|
+
if (typeof compatibility.mb_lint?.min_version !== "string")
|
|
306
|
+
refuse("mb_lint_minimum_not_admitted");
|
|
307
|
+
minimum = compatibility.mb_lint.min_version;
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
return refuse("mb_lint_minimum_not_admitted");
|
|
311
|
+
}
|
|
312
|
+
if (!facts.tool_probes || !semver.valid(minimum) || !semver.valid(facts.tool_probes["mb-lint"].version)
|
|
313
|
+
|| semver.lt(facts.tool_probes["mb-lint"].version, minimum))
|
|
314
|
+
refuse("mb_lint_minimum_not_admitted");
|
|
315
|
+
const prepared = new PreparedMemoryInitProjectBootstrap(context, input.target, input.layer, input.execution, PreparedMemoryInitRuntimeStorage.prepare(context));
|
|
316
|
+
const intent = readIntent(context, prepared.#scope);
|
|
317
|
+
if (intent && intent.intent.identity !== prepared.identity)
|
|
318
|
+
refuse("request_identity_changed");
|
|
319
|
+
if (intent && hybridDigest(intent.intent.lint_capability) !== prepared.#lint.sha256)
|
|
320
|
+
refuse("lint_capability_custody_changed");
|
|
321
|
+
if (intent && hybridDigest(intent.intent.worktrunk_capability) !== prepared.#worktrunk.sha256)
|
|
322
|
+
refuse("worktrunk_capability_custody_changed");
|
|
323
|
+
if (intent && hybridDigest(intent.intent.resource_storage) !== prepared.#resource.sha256)
|
|
324
|
+
refuse("resource_storage_custody_changed");
|
|
325
|
+
if (row(context, prepared.#scope, receiptEvent))
|
|
326
|
+
readMemoryInitProjectBootstrap(context, prepared.#scope);
|
|
327
|
+
if (!intent && fs.existsSync(path.join(facts.workspace_root, ".memory-bank")))
|
|
328
|
+
refuse("bootstrap_intent_missing");
|
|
329
|
+
prepared.revalidatePhysical(context, false);
|
|
330
|
+
return prepared;
|
|
331
|
+
}
|
|
332
|
+
/** Reconstruct an accepted bootstrap from request-local custody only. No
|
|
333
|
+
* cached caller target, current global installation or publication fallback
|
|
334
|
+
* can supply lost evidence. Tool/storage/command admission is repeated before
|
|
335
|
+
* returning; readiness still requires the independently selected engine.
|
|
336
|
+
*/
|
|
337
|
+
static restore(context, execution) {
|
|
338
|
+
if (!(execution instanceof FrozenGenericExecution) || execution.settings.flow_id !== "mb-init")
|
|
339
|
+
refuse("unprepared_bootstrap_execution");
|
|
340
|
+
const frozen = execution.snapshot(), scope = { requestId: frozen.scope.requestId,
|
|
341
|
+
projectRoot: frozen.scope.projectRoot, workspaceRoot: frozen.scope.workspace };
|
|
342
|
+
const retained = context.db.readSnapshot(() => {
|
|
343
|
+
const registered = readMemoryInitProjectBootstrap(context, scope), selection = readMemoryInitReleaseSelection(context, scope);
|
|
344
|
+
if (!registered || registered.receipt.schema_id !== "dd-flow/memory-init-project-bootstrap@4" || !selection
|
|
345
|
+
|| registered.receipt.execution_sha256 !== execution.sha256 || selection.execution_sha256 !== execution.sha256
|
|
346
|
+
|| selection.bootstrap_identity !== registered.receipt.identity)
|
|
347
|
+
refuse("accepted_bootstrap_required");
|
|
348
|
+
return { registered, selection };
|
|
349
|
+
});
|
|
350
|
+
const restored = restorePublishedMemoryLayer(context.ddFlowHome, { ...scope,
|
|
351
|
+
targetSha256: retained.registered.receipt.target_sha256, layerSha256: retained.registered.receipt.layer_sha256,
|
|
352
|
+
installationSha256: retained.selection.installation_manifest_sha256 }, retained.registered.receipt.layer_publication_sha256, context.env, retained.registered.receipt.draft_identity_sha256);
|
|
353
|
+
if (restored.layer.packSha256 !== retained.selection.pack_sha256)
|
|
354
|
+
refuse("retained_pack_changed");
|
|
355
|
+
return PreparedMemoryInitProjectBootstrap.prepare(context, { target: restored.target, layer: restored.layer, execution });
|
|
356
|
+
}
|
|
357
|
+
revalidatePhysical(context, qualifyTools = true) {
|
|
358
|
+
const facts = this.#target.facts();
|
|
359
|
+
if (fs.existsSync(path.join(facts.workspace_root, ".memory-bank"))) {
|
|
360
|
+
const retained = readRetainedMemoryLayer(context.ddFlowHome, { projectRoot: facts.project_root,
|
|
361
|
+
workspaceRoot: facts.workspace_root, requestId: facts.request_id, targetSha256: this.#target.sha256,
|
|
362
|
+
layerSha256: this.#layer.sha256, installationSha256: this.#layer.installationSha256 });
|
|
363
|
+
if (retained.sha256 !== this.#layer.sha256)
|
|
364
|
+
refuse("retained_layer_changed");
|
|
365
|
+
PreparedMemoryInitTarget.revalidateOwnedPublication(facts, this.#target.sha256, context.env);
|
|
366
|
+
}
|
|
367
|
+
else
|
|
368
|
+
this.#target.revalidate();
|
|
369
|
+
if (hybridDigest(prepareMemoryInitHarnessCommands(context, this.#execution)) !== hybridDigest(this.#commands))
|
|
370
|
+
refuse("harness_commands_changed");
|
|
371
|
+
this.#resource.revalidate(context);
|
|
372
|
+
if (qualifyTools) {
|
|
373
|
+
this.#lint.revalidate(this.#target, context.env);
|
|
374
|
+
this.#worktrunk.revalidate(this.#target, context.env);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/** Independently observed input for the productive bootstrap receipt. This
|
|
378
|
+
* does not launch a provider or promote account/model access from unknown.
|
|
379
|
+
* Callers cannot replace the target, execution, release or accepted proof.
|
|
380
|
+
*/
|
|
381
|
+
prepareReadiness(context, engine) {
|
|
382
|
+
if (!(engine instanceof AdmittedFrozenEngine))
|
|
383
|
+
refuse("selected_engine_not_admitted");
|
|
384
|
+
this.revalidatePhysical(context, false);
|
|
385
|
+
this.#storage.assertCompatibility(context);
|
|
386
|
+
const registered = readMemoryInitProjectBootstrap(context, this.#scope);
|
|
387
|
+
const accepted = readMemoryInitProjectBootstrapEngineAdmission(context, this.#scope);
|
|
388
|
+
const release = readMemoryInitReleaseSelection(context, this.#scope);
|
|
389
|
+
if (!registered || registered.receipt.identity !== this.identity || !accepted
|
|
390
|
+
|| accepted.bootstrap_sha256 !== registered.sha256 || !release
|
|
391
|
+
|| release.bootstrap_identity !== this.identity || release.execution_sha256 !== this.#execution.sha256
|
|
392
|
+
|| release.pack_sha256 !== this.#layer.packSha256 || release.installation_manifest_sha256 !== this.#layer.installationSha256
|
|
393
|
+
|| release.installation_manifest_base64 !== this.#installationManifestBase64)
|
|
394
|
+
refuse("accepted_engine_bootstrap_required");
|
|
395
|
+
const proof = engine.admitMemoryInitStorage(context.ddFlowHome, resourceHome(context));
|
|
396
|
+
if (hybridDigest(proof) !== hybridDigest(accepted.proof))
|
|
397
|
+
refuse("engine_storage_changed_after_bootstrap");
|
|
398
|
+
const manifest = engine.manifest(), installation = JSON.parse(Buffer.from(release.installation_manifest_base64, "base64").toString("utf8"));
|
|
399
|
+
if (installation.engine.package !== manifest.package_name
|
|
400
|
+
|| installation.engine.version !== manifest.package_version)
|
|
401
|
+
refuse("readiness_installation_changed");
|
|
402
|
+
// Read exactly the admitted installed inventory, not a repository scan. A
|
|
403
|
+
// completed journal alone cannot qualify deleted/replaced installed files.
|
|
404
|
+
const memoryRoot = path.join(this.#scope.workspaceRoot, ".memory-bank"), rootOwner = fs.lstatSync(memoryRoot);
|
|
405
|
+
const marker = path.join(memoryRoot, ".dd-flow-layer-owner.json");
|
|
406
|
+
const publicationBytes = readBoundedReleaseFile(marker, 1024 * 1024);
|
|
407
|
+
const publication = JSON.parse(publicationBytes.toString("utf8"));
|
|
408
|
+
if (!rootOwner.isDirectory() || fs.lstatSync(marker).nlink !== 1
|
|
409
|
+
|| digest(publicationBytes) !== registered.receipt.layer_publication_sha256
|
|
410
|
+
|| publication.root_device !== rootOwner.dev || publication.root_inode !== rootOwner.ino)
|
|
411
|
+
refuse("readiness_layer_owner_changed");
|
|
412
|
+
for (const [logical, bytes] of this.#layer.files()) {
|
|
413
|
+
const file = path.join(this.#scope.workspaceRoot, ".memory-bank", logical);
|
|
414
|
+
let parent = path.join(this.#scope.workspaceRoot, ".memory-bank");
|
|
415
|
+
if (!fs.lstatSync(parent).isDirectory())
|
|
416
|
+
refuse("readiness_layer_changed");
|
|
417
|
+
for (const segment of logical.split("/").slice(0, -1)) {
|
|
418
|
+
parent = path.join(parent, segment);
|
|
419
|
+
if (!fs.lstatSync(parent).isDirectory())
|
|
420
|
+
refuse("readiness_layer_changed");
|
|
421
|
+
}
|
|
422
|
+
if (fs.lstatSync(file).nlink !== 1 || !readBoundedReleaseFile(file, 1024 * 1024).equals(bytes))
|
|
423
|
+
refuse("readiness_layer_changed");
|
|
424
|
+
}
|
|
425
|
+
return { scope: { ...this.#scope }, target: this.#target.facts(), execution_sha256: this.#execution.sha256,
|
|
426
|
+
pack_sha256: this.#layer.packSha256, installation_manifest_sha256: this.#layer.installationSha256,
|
|
427
|
+
installation_manifest_base64: release.installation_manifest_base64,
|
|
428
|
+
engine_manifest_base64: engine.manifestBytes().toString("base64"),
|
|
429
|
+
...(accepted.git_policy_sha256 ? { git_policy_sha256: accepted.git_policy_sha256 } : {}), registered, accepted };
|
|
430
|
+
}
|
|
431
|
+
/** Productive engine-bound path. Historical draft receipts do not acquire this
|
|
432
|
+
* qualification: the independent gate must exist before project publication.
|
|
433
|
+
* This still does not assert provider or final normal-flow readiness.
|
|
434
|
+
*/
|
|
435
|
+
applyWithEngine(context, engine, onCheckpoint) {
|
|
436
|
+
if (!(engine instanceof AdmittedFrozenEngine))
|
|
437
|
+
refuse("selected_engine_not_admitted");
|
|
438
|
+
const event = "memory.init_engine_admission";
|
|
439
|
+
// Old admission remains historical; a new request must freeze explicit
|
|
440
|
+
// policy before its first storage/bootstrap effect, never infer it here.
|
|
441
|
+
const legacy = row(context, this.#scope, event)?.value.schema_id === "dd-flow/memory-init-engine-admission@1";
|
|
442
|
+
const policy = legacy ? null : readMemoryInitGitPolicy(context, this.#scope);
|
|
443
|
+
if (!legacy && (!policy || policy.target_sha256 !== this.#target.sha256))
|
|
444
|
+
refuse("explicit_git_policy_required");
|
|
445
|
+
const policyBinding = policy ? { git_policy_sha256: hybridDigest(policy) } : {};
|
|
446
|
+
const proof = engine.admitMemoryInitStorage(context.ddFlowHome, resourceHome(context));
|
|
447
|
+
const identity = hybridDigest({ scope: this.#scope, bootstrap_identity: this.identity, execution_sha256: this.#execution.sha256, proof, ...policyBinding });
|
|
448
|
+
const expected = { schema_id: legacy ? "dd-flow/memory-init-engine-admission@1" : "dd-flow/memory-init-engine-admission@2", scope: this.#scope,
|
|
449
|
+
bootstrap_identity: this.identity, execution_sha256: this.#execution.sha256, identity, proof, ...policyBinding, status: "prepared", acceptance_sha256: null };
|
|
450
|
+
const assertReceipt = () => {
|
|
451
|
+
if (policy && hybridDigest(readMemoryInitGitPolicy(context, this.#scope)) !== policyBinding.git_policy_sha256)
|
|
452
|
+
refuse("git_policy_custody_changed");
|
|
453
|
+
const prior = row(context, this.#scope, event);
|
|
454
|
+
if (!prior || !["prepared", "accepted"].includes(prior.value.status)
|
|
455
|
+
|| (prior.value.status === "prepared" ? prior.value.acceptance_sha256 !== null : typeof prior.value.acceptance_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(prior.value.acceptance_sha256))
|
|
456
|
+
|| hybridDigest({ ...prior.value, status: "prepared", acceptance_sha256: null }) !== hybridDigest(expected))
|
|
457
|
+
refuse("engine_admission_custody_changed");
|
|
458
|
+
return prior;
|
|
459
|
+
};
|
|
460
|
+
const revalidate = () => {
|
|
461
|
+
if (hybridDigest(engine.admitMemoryInitStorage(context.ddFlowHome, resourceHome(context))) !== hybridDigest(proof))
|
|
462
|
+
refuse("engine_storage_changed_after_preparation");
|
|
463
|
+
assertReceipt();
|
|
464
|
+
};
|
|
465
|
+
const alreadyPublished = fs.existsSync(path.join(this.#scope.workspaceRoot, ".memory-bank"));
|
|
466
|
+
context.db.writeTransaction(() => {
|
|
467
|
+
this.#storage.assertCompatibility(context);
|
|
468
|
+
const prior = row(context, this.#scope, event);
|
|
469
|
+
if (prior) {
|
|
470
|
+
assertReceipt();
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (readMemoryInitProjectBootstrap(context, this.#scope))
|
|
474
|
+
refuse("historical_bootstrap_has_no_engine_admission");
|
|
475
|
+
// Existing draft intent is allowed only before any publication; do not
|
|
476
|
+
// retroactively qualify already installed bytes from the legacy path.
|
|
477
|
+
if (alreadyPublished)
|
|
478
|
+
refuse("engine_admission_after_publication");
|
|
479
|
+
appendAudit(context, { eventType: event, payload: expected });
|
|
480
|
+
}, "memoryInit.engineAdmission");
|
|
481
|
+
try {
|
|
482
|
+
this.retainReadinessSelection(context);
|
|
483
|
+
revalidate();
|
|
484
|
+
const registered = this.apply(context, phase => {
|
|
485
|
+
onCheckpoint?.(phase);
|
|
486
|
+
revalidate();
|
|
487
|
+
});
|
|
488
|
+
revalidate();
|
|
489
|
+
const acceptance = { schema_id: "dd-flow/memory-init-engine-bootstrap@1", scope: this.#scope,
|
|
490
|
+
admission_identity: identity, bootstrap_sha256: registered.sha256, project_id: registered.receipt.project_id };
|
|
491
|
+
context.db.writeTransaction(() => {
|
|
492
|
+
const admission = assertReceipt();
|
|
493
|
+
if (readMemoryInitProjectBootstrap(context, this.#scope)?.sha256 !== registered.sha256)
|
|
494
|
+
refuse("bootstrap_custody_changed");
|
|
495
|
+
const prior = row(context, this.#scope, "memory.init_engine_bootstrap");
|
|
496
|
+
if (prior) {
|
|
497
|
+
if (admission.value.status !== "accepted" || admission.value.acceptance_sha256 !== hybridDigest(acceptance) || hybridDigest(prior.value) !== hybridDigest(acceptance))
|
|
498
|
+
refuse("engine_bootstrap_custody_changed");
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (admission.value.status === "accepted")
|
|
502
|
+
refuse("engine_bootstrap_custody_missing");
|
|
503
|
+
appendAudit(context, { projectId: registered.receipt.project_id, eventType: "memory.init_engine_bootstrap", payload: acceptance });
|
|
504
|
+
const updated = context.db.run("UPDATE audit_events SET payload_json=? WHERE id=? AND payload_json=?", [JSON.stringify({ ...admission.value, status: "accepted", acceptance_sha256: hybridDigest(acceptance) }), admission.id, admission.payload_json]);
|
|
505
|
+
if (updated.changes !== 1)
|
|
506
|
+
refuse("engine_admission_custody_changed");
|
|
507
|
+
}, "memoryInit.acceptEngineBootstrap");
|
|
508
|
+
return { ...registered, engine_admission_identity: identity };
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
throw new AppError("memory_init_engine_bootstrap_failed", "Engine-bound bootstrap retained an incomplete request outcome", 1, { reason: error instanceof AppError ? error.details.reason ?? error.code : "engine_bootstrap_operation_failed",
|
|
512
|
+
effect: "partial", next_action: "reconcile_exact_request" });
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
apply(context, onCheckpoint) {
|
|
516
|
+
const completed = readMemoryInitProjectBootstrap(context, this.#scope);
|
|
517
|
+
if (completed) {
|
|
518
|
+
if (completed.receipt.identity !== this.identity || project(context, this.#scope.projectRoot)?.status !== "active")
|
|
519
|
+
refuse("request_identity_changed");
|
|
520
|
+
return { ...completed, changed: false };
|
|
521
|
+
}
|
|
522
|
+
this.revalidatePhysical(context);
|
|
523
|
+
const fresh = !fs.existsSync(path.join(this.#scope.workspaceRoot, ".memory-bank"));
|
|
524
|
+
let retained = false;
|
|
525
|
+
try {
|
|
526
|
+
const intent = context.db.writeTransaction(() => {
|
|
527
|
+
this.#storage.assertCompatibility(context);
|
|
528
|
+
const prior = readIntent(context, this.#scope);
|
|
529
|
+
if (prior) {
|
|
530
|
+
if (prior.intent.identity !== this.identity)
|
|
531
|
+
refuse("request_identity_changed");
|
|
532
|
+
if (hybridDigest(prior.intent.lint_capability) !== this.#lint.sha256)
|
|
533
|
+
refuse("lint_capability_custody_changed");
|
|
534
|
+
if (hybridDigest(prior.intent.worktrunk_capability) !== this.#worktrunk.sha256)
|
|
535
|
+
refuse("worktrunk_capability_custody_changed");
|
|
536
|
+
if (hybridDigest(prior.intent.resource_storage) !== this.#resource.sha256)
|
|
537
|
+
refuse("resource_storage_custody_changed");
|
|
538
|
+
return prior.intent;
|
|
539
|
+
}
|
|
540
|
+
if (!fresh)
|
|
541
|
+
refuse("bootstrap_intent_missing");
|
|
542
|
+
const expected = project(context, this.#scope.projectRoot);
|
|
543
|
+
if (expected && expected.status !== "active")
|
|
544
|
+
refuse("project_not_active");
|
|
545
|
+
const value = { schema_id: "dd-flow/memory-init-project-bootstrap-intent@4", scope: this.#scope,
|
|
546
|
+
identity: this.identity, expected_project: expected, status: "prepared", receipt_sha256: null, lint_capability: this.#lint.facts(), worktrunk_capability: this.#worktrunk.facts(), resource_storage: this.#resource.facts() };
|
|
547
|
+
appendAudit(context, { eventType: intentEvent, payload: value });
|
|
548
|
+
return value;
|
|
549
|
+
}, "memoryInit.projectBootstrapIntent");
|
|
550
|
+
retained = true;
|
|
551
|
+
onCheckpoint?.("intent_retained");
|
|
552
|
+
this.revalidatePhysical(context);
|
|
553
|
+
const drafts = publishMemoryInitDraftIdentity(context.ddFlowHome, this.#target, this.#layer, context.env);
|
|
554
|
+
onCheckpoint?.("drafts_published");
|
|
555
|
+
this.revalidatePhysical(context);
|
|
556
|
+
const result = context.db.writeTransaction(() => {
|
|
557
|
+
this.#storage.assertCompatibility(context);
|
|
558
|
+
const replay = readMemoryInitProjectBootstrap(context, this.#scope);
|
|
559
|
+
if (replay) {
|
|
560
|
+
if (replay.receipt.identity !== this.identity)
|
|
561
|
+
refuse("request_identity_changed");
|
|
562
|
+
return { ...replay, changed: false };
|
|
563
|
+
}
|
|
564
|
+
const current = readIntent(context, this.#scope);
|
|
565
|
+
if (!current || hybridDigest(current.intent) !== hybridDigest(intent))
|
|
566
|
+
refuse("request_intent_changed");
|
|
567
|
+
const existing = project(context, this.#scope.projectRoot);
|
|
568
|
+
if (hybridDigest(existing) !== hybridDigest(intent.expected_project))
|
|
569
|
+
refuse("project_identity_changed");
|
|
570
|
+
if (!existing)
|
|
571
|
+
registerPreparedProject(context, this.#project);
|
|
572
|
+
const registered = project(context, this.#scope.projectRoot);
|
|
573
|
+
if (!registered || registered.status !== "active")
|
|
574
|
+
refuse("project_registration_failed");
|
|
575
|
+
const receipt = { schema_id: "dd-flow/memory-init-project-bootstrap@4",
|
|
576
|
+
scope: this.#scope, identity: this.identity, project_id: registered.id, target_sha256: this.#target.sha256,
|
|
577
|
+
layer_sha256: this.#layer.sha256, execution_sha256: this.#execution.sha256, storage_sha256: this.#storage.sha256,
|
|
578
|
+
layer_publication_sha256: drafts.receipt.layer_publication_sha256, draft_identity_sha256: drafts.sha256,
|
|
579
|
+
lint_capability_sha256: this.#lint.sha256,
|
|
580
|
+
worktrunk_capability_sha256: this.#worktrunk.sha256,
|
|
581
|
+
resource_storage_sha256: this.#resource.sha256,
|
|
582
|
+
semantic_status: "draft_not_accepted", created_at: context.now() };
|
|
583
|
+
const sha256 = hybridDigest(receipt);
|
|
584
|
+
appendAudit(context, { projectId: registered.id, eventType: receiptEvent, payload: { scope: this.#scope, identity: this.identity, sha256, receipt } });
|
|
585
|
+
context.db.run("UPDATE audit_events SET payload_json = ? WHERE id = ? AND payload_json = ?", [JSON.stringify({ ...intent, status: "registered", receipt_sha256: sha256 }), current.id, current.payload_json]);
|
|
586
|
+
const accepted = readMemoryInitProjectBootstrap(context, this.#scope);
|
|
587
|
+
if (!accepted)
|
|
588
|
+
refuse("bootstrap_receipt_not_committed");
|
|
589
|
+
return { ...accepted, changed: true };
|
|
590
|
+
}, "memoryInit.registerProjectBootstrap");
|
|
591
|
+
onCheckpoint?.("registered");
|
|
592
|
+
return result;
|
|
593
|
+
}
|
|
594
|
+
catch (error) {
|
|
595
|
+
throw new AppError("memory_init_project_bootstrap_failed", "Project bootstrap retained an incomplete request outcome", 1, { reason: error instanceof AppError ? error.details?.reason ?? error.code : "bootstrap_operation_failed",
|
|
596
|
+
effect: retained ? "partial" : "no_effect", next_action: "reconcile_exact_request" });
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|