@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,159 @@
|
|
|
1
|
+
import { AppError } from "../shared/errors.js";
|
|
2
|
+
import { hybridDigest } from "./hybrid-contracts.js";
|
|
3
|
+
import { appendAudit } from "./audit.js";
|
|
4
|
+
import { PreparedCheckEvidence, PreparedRetainedCheckEvidence } from "./code-checks.js";
|
|
5
|
+
import { PreparedMemoryStageResult } from "./memory-stage-results.js";
|
|
6
|
+
import { PreparedMemoryVerificationAcceptance } from "./memory-verification-acceptance.js";
|
|
7
|
+
import { readAcceptedStageData } from "./stage-report-renderer.js";
|
|
8
|
+
const event = "memory.verification_acceptance";
|
|
9
|
+
function refuse(reason) {
|
|
10
|
+
throw new AppError("memory_verification_receipt_invalid", "Verification lacks committed historical check custody", 2, { reason, effect: "no_effect" });
|
|
11
|
+
}
|
|
12
|
+
function stage(context, scope) {
|
|
13
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id=? AND id=?", [scope.projectId, scope.runId]);
|
|
14
|
+
if (!run)
|
|
15
|
+
refuse("run_missing");
|
|
16
|
+
const index = JSON.parse(run.index_json), selected = index.stage_runs.find((value) => value.stage === "verify");
|
|
17
|
+
if (!selected || typeof selected.attempt !== "string" || !/^try-[0-9]{3,}$/.test(selected.attempt)
|
|
18
|
+
|| typeof selected.input_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(selected.input_sha256))
|
|
19
|
+
refuse("verify_identity_missing");
|
|
20
|
+
return { current: index.current_stage, attempt: selected.attempt, input_sha256: selected.input_sha256, status: selected.status };
|
|
21
|
+
}
|
|
22
|
+
function receiptRows(context, scope) {
|
|
23
|
+
return context.db.all("SELECT payload_json FROM audit_events WHERE project_id=? AND event_type=? AND json_extract(payload_json,'$.run_id')=? LIMIT 2", [scope.projectId, event, scope.runId]);
|
|
24
|
+
}
|
|
25
|
+
/** Independent receipt written in the same transaction as fresh acceptance.
|
|
26
|
+
* A later replay does not re-evaluate today's policy or repaired workspace.
|
|
27
|
+
* It proves only that these exact bytes/checks were accepted historically.
|
|
28
|
+
*/
|
|
29
|
+
export class PreparedMemoryVerificationReceipt {
|
|
30
|
+
#scope;
|
|
31
|
+
#receipt;
|
|
32
|
+
#checks;
|
|
33
|
+
#acceptance;
|
|
34
|
+
#result;
|
|
35
|
+
constructor(scope, receipt, checks, acceptance, result) {
|
|
36
|
+
this.#scope = { ...scope };
|
|
37
|
+
this.#receipt = structuredClone(receipt);
|
|
38
|
+
this.#checks = checks;
|
|
39
|
+
this.#acceptance = acceptance;
|
|
40
|
+
this.#result = result;
|
|
41
|
+
Object.freeze(this);
|
|
42
|
+
}
|
|
43
|
+
static prepare(context, input) {
|
|
44
|
+
if (!(input.result instanceof PreparedMemoryStageResult) || !(input.checks instanceof PreparedCheckEvidence)
|
|
45
|
+
|| !(input.acceptance instanceof PreparedMemoryVerificationAcceptance))
|
|
46
|
+
refuse("prepared_acceptance_required");
|
|
47
|
+
input.checks.assertOwner({ ...input.scope, scope: "aggregate" });
|
|
48
|
+
input.acceptance.assertCustody(context, input.result, input.checks);
|
|
49
|
+
const selected = context.db.readSnapshot(() => stage(context, input.scope)), value = input.result.value();
|
|
50
|
+
if (selected.current !== "verify" || selected.status !== "running" || value.stage !== "verify" || (value.outcome !== "accepted" && value.outcome !== "needs_repair")
|
|
51
|
+
|| value.run_id !== input.scope.runId || value.input_sha256 !== selected.input_sha256)
|
|
52
|
+
refuse("active_result_required");
|
|
53
|
+
if (receiptRows(context, input.scope).length)
|
|
54
|
+
refuse("fresh_receipt_already_exists");
|
|
55
|
+
const receipt = { schema_id: "dd-flow/memory-verification-acceptance@1", run_id: input.scope.runId, stage: "verify", project_id: input.scope.projectId,
|
|
56
|
+
attempt: selected.attempt, input_sha256: selected.input_sha256, result_sha256: input.result.sha256, checks: input.checks.retainedReferences(context) };
|
|
57
|
+
if (!receipt.checks.length || receipt.checks.length > 4096 || Buffer.byteLength(JSON.stringify(receipt)) > 2 * 1024 * 1024)
|
|
58
|
+
refuse("receipt_exceeds_bound");
|
|
59
|
+
return new PreparedMemoryVerificationReceipt(input.scope, receipt, input.checks, input.acceptance, input.result);
|
|
60
|
+
}
|
|
61
|
+
record(context) {
|
|
62
|
+
this.#checks.assertCustody(context);
|
|
63
|
+
this.#acceptance.assertCustody(context, this.#result);
|
|
64
|
+
const selected = stage(context, this.#scope);
|
|
65
|
+
if (selected.current !== "verify" || selected.status !== "running" || selected.attempt !== this.#receipt.attempt
|
|
66
|
+
|| selected.input_sha256 !== this.#receipt.input_sha256 || receiptRows(context, this.#scope).length)
|
|
67
|
+
refuse("fresh_custody_changed");
|
|
68
|
+
if (hybridDigest(this.#checks.retainedReferences(context)) !== hybridDigest(this.#receipt.checks))
|
|
69
|
+
refuse("selected_checks_changed");
|
|
70
|
+
appendAudit(context, { projectId: this.#scope.projectId, eventType: event, payload: this.#receipt });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export class PreparedAcceptedMemoryVerification {
|
|
74
|
+
#scope;
|
|
75
|
+
#authority;
|
|
76
|
+
#receiptSha256;
|
|
77
|
+
#checks;
|
|
78
|
+
constructor(scope, authority, receiptSha256, checks) {
|
|
79
|
+
this.#scope = { ...scope };
|
|
80
|
+
this.#authority = authority;
|
|
81
|
+
this.#receiptSha256 = receiptSha256;
|
|
82
|
+
this.#checks = checks;
|
|
83
|
+
Object.freeze(this);
|
|
84
|
+
}
|
|
85
|
+
static prepare(context, input) {
|
|
86
|
+
if (!(input.bytes instanceof Uint8Array) || !input.bytes.length || input.bytes.length > 1024 * 1024)
|
|
87
|
+
refuse("invalid_replay_bytes");
|
|
88
|
+
const selected = context.db.readSnapshot(() => accepted(context, input));
|
|
89
|
+
if (!selected.data.bytes.equals(input.bytes))
|
|
90
|
+
refuse("accepted_result_changed");
|
|
91
|
+
const checks = PreparedRetainedCheckEvidence.prepare(context, { projectId: input.projectId, runId: input.runId, references: selected.receipt.checks,
|
|
92
|
+
...(JSON.parse(selected.data.bytes.toString("utf8")).outcome === "needs_repair" ? { mode: "diagnostic" } : {}) });
|
|
93
|
+
const prepared = new PreparedAcceptedMemoryVerification(input, selected.authority, selected.sha256, checks);
|
|
94
|
+
prepared.assertCustody(context);
|
|
95
|
+
return prepared;
|
|
96
|
+
}
|
|
97
|
+
assertCustody(context) {
|
|
98
|
+
const selected = context.db.readSnapshot(() => accepted(context, this.#scope));
|
|
99
|
+
if (selected.sha256 !== this.#receiptSha256 || selected.authority !== this.#authority)
|
|
100
|
+
refuse("accepted_custody_changed");
|
|
101
|
+
this.#checks.assertCustody(context);
|
|
102
|
+
}
|
|
103
|
+
revalidate(context) { this.#checks.revalidate(context); this.assertCustody(context); }
|
|
104
|
+
qualityPassed(context) { this.assertCustody(context); return JSON.parse(accepted(context, this.#scope).data.bytes.toString("utf8")).outcome === "accepted"; }
|
|
105
|
+
diagnosticFindings(context) {
|
|
106
|
+
this.assertCustody(context);
|
|
107
|
+
const findings = JSON.parse(accepted(context, this.#scope).data.bytes.toString("utf8")).findings;
|
|
108
|
+
return findings.map(finding => ({ ...structuredClone(finding), evidence: finding.evidence.map(source => ({ ...source, root: source.root === "run" ? "run" : "workspace", path: source.root === "canon" ? `.memory-bank/${source.path}` : source.path })) }));
|
|
109
|
+
}
|
|
110
|
+
finalChecks(context) { if (!this.qualityPassed(context))
|
|
111
|
+
refuse("verification_quality_not_passed"); return structuredClone(accepted(context, this.#scope).receipt.checks); }
|
|
112
|
+
/** SQL-only policy identity from the independently accepted check rows,
|
|
113
|
+
* not today's mutable project profile or coordinator result JSON. */
|
|
114
|
+
profileHash(context) {
|
|
115
|
+
this.assertCustody(context);
|
|
116
|
+
const selected = accepted(context, this.#scope);
|
|
117
|
+
const hashes = selected.receipt.checks.map(reference => {
|
|
118
|
+
const row = context.db.get("SELECT profile_hash FROM check_receipts WHERE project_id=? AND run_id=? AND id=?", [this.#scope.projectId, this.#scope.runId, reference.id]);
|
|
119
|
+
if (!row || (row.profile_hash !== null && (typeof row.profile_hash !== "string" || !/^[a-f0-9]{64}$/.test(row.profile_hash))))
|
|
120
|
+
refuse("accepted_policy_hash_missing");
|
|
121
|
+
return row.profile_hash;
|
|
122
|
+
});
|
|
123
|
+
if (!hashes.length || hashes.some(value => value !== hashes[0]))
|
|
124
|
+
refuse("accepted_policy_hash_inconsistent");
|
|
125
|
+
return hashes[0];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function accepted(context, scope) {
|
|
129
|
+
const selected = stage(context, scope), data = readAcceptedStageData(context, { ...scope, stage: "verify" }), rows = receiptRows(context, scope);
|
|
130
|
+
if (selected.status !== "done" || rows.length !== 1 || Buffer.byteLength(rows[0].payload_json) > 2 * 1024 * 1024)
|
|
131
|
+
refuse("accepted_receipt_missing");
|
|
132
|
+
let receipt;
|
|
133
|
+
try {
|
|
134
|
+
receipt = JSON.parse(rows[0].payload_json);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return refuse("invalid_receipt_json");
|
|
138
|
+
}
|
|
139
|
+
if (!receipt || typeof receipt !== "object" || Array.isArray(receipt) || hybridDigest({ ...receipt, checks: undefined }) !== hybridDigest({ schema_id: "dd-flow/memory-verification-acceptance@1", run_id: scope.runId, stage: "verify", project_id: scope.projectId,
|
|
140
|
+
attempt: selected.attempt, input_sha256: selected.input_sha256, result_sha256: data.result.sha256 }) || data.data_schema_id !== "dd-flow/mb-init-verify-result@1"
|
|
141
|
+
|| data.input_sha256 !== selected.input_sha256)
|
|
142
|
+
refuse("accepted_receipt_changed");
|
|
143
|
+
const value = JSON.parse(data.bytes.toString("utf8"));
|
|
144
|
+
const compose = readAcceptedStageData(context, { ...scope, stage: "compose" }), composed = JSON.parse(compose.bytes.toString("utf8"));
|
|
145
|
+
if (compose.data_schema_id !== "dd-flow/mb-init-compose-result@1"
|
|
146
|
+
|| composed.schema_id !== compose.data_schema_id || composed.stage !== "compose" || composed.run_id !== scope.runId
|
|
147
|
+
|| composed.outcome !== "accepted" || composed.input_sha256 !== compose.input_sha256
|
|
148
|
+
|| hybridDigest(value.predecessors) !== hybridDigest([{ stage: "compose", result: compose.result, input_sha256: compose.input_sha256 }]))
|
|
149
|
+
refuse("accepted_predecessor_changed");
|
|
150
|
+
if (value.stage !== "verify" || value.run_id !== scope.runId || !["accepted", "needs_repair"].includes(value.outcome) || value.input_sha256 !== selected.input_sha256
|
|
151
|
+
|| !Array.isArray(receipt.checks) || receipt.checks.some(reference => !reference || typeof reference !== "object" || Array.isArray(reference)
|
|
152
|
+
|| Object.keys(reference).some(key => !["id", "path", "sha256", "sql_sha256"].includes(key))
|
|
153
|
+
|| typeof reference.id !== "string" || !reference.id || typeof reference.path !== "string"
|
|
154
|
+
|| typeof reference.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(reference.sha256)
|
|
155
|
+
|| typeof reference.sql_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(reference.sql_sha256)) || !Array.isArray(value.details?.checks)
|
|
156
|
+
|| receipt.checks.some(({ path, sha256 }) => !value.details.checks.some((reference) => reference.path === path && reference.sha256 === sha256)))
|
|
157
|
+
refuse("accepted_check_references_changed");
|
|
158
|
+
return { data, receipt, sha256: hybridDigest(receipt), authority: hybridDigest({ verify: data.authority_sha256, compose: compose.authority_sha256 }) };
|
|
159
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { hybridDigest } from "./hybrid-contracts.js";
|
|
3
|
+
import { AppError } from "../shared/errors.js";
|
|
4
|
+
import { readFlowRunExecutionBundle, assertPreparedRunBundleSqlAuthority } from "./runs.js";
|
|
5
|
+
import { requireProjectByRoot } from "./projects.js";
|
|
6
|
+
import { resolveProjectRoot } from "../storage/paths.js";
|
|
7
|
+
import { PreparedMemoryBaselinePreservation } from "./memory-baseline-preservation.js";
|
|
8
|
+
import { readAcceptedStageData } from "./stage-report-renderer.js";
|
|
9
|
+
import { PreparedDescriptorStageStart } from "./descriptor-stage-start.js";
|
|
10
|
+
import { PreparedDescriptorStageCoordinator } from "./descriptor-stage-coordinator.js";
|
|
11
|
+
import { PreparedMemoryVerificationChecks } from "./memory-verification-checks.js";
|
|
12
|
+
import { PreparedMemoryResultBinding } from "./memory-result-binding.js";
|
|
13
|
+
import { PreparedMemoryStageResult } from "./memory-stage-results.js";
|
|
14
|
+
import { PreparedAcceptedMemoryComposition } from "./memory-accepted-composition.js";
|
|
15
|
+
import { PreparedMemoryVerificationAcceptance, projectMemoryVerificationChecks, projectMemoryVerificationArtifacts } from "./memory-verification-acceptance.js";
|
|
16
|
+
import { PreparedDescriptorStageSettlement } from "./descriptor-stage-settlement.js";
|
|
17
|
+
import { PreparedMemoryVerificationReceipt, PreparedAcceptedMemoryVerification } from "./memory-verification-receipt.js";
|
|
18
|
+
function refuse(reason) {
|
|
19
|
+
throw new AppError("memory_verify_handler_invalid", "Memory verification lacks registered scope or accepted composition", 2, { reason, effect: "no_effect" });
|
|
20
|
+
}
|
|
21
|
+
/** CLI-owned finite checks for the active verifier. Callers supply no command,
|
|
22
|
+
* profile hash, receipt path or alternate executable. Public routing remains
|
|
23
|
+
* pending complete memory handler registration.
|
|
24
|
+
*/
|
|
25
|
+
export function runMemoryVerificationChecks(context, input) {
|
|
26
|
+
const bundle = readFlowRunExecutionBundle(context, input);
|
|
27
|
+
if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.descriptor.successor("compose", "accepted") !== "verify"
|
|
28
|
+
|| bundle.descriptor.successor("verify", "accepted") !== "review")
|
|
29
|
+
refuse("registered_memory_bundle_required");
|
|
30
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
|
|
31
|
+
const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), index = JSON.parse(run.index_json);
|
|
32
|
+
if (index.current_stage !== "verify" || index.stage_runs.find((stage) => stage.stage === "verify")?.status !== "running")
|
|
33
|
+
refuse("active_verification_required");
|
|
34
|
+
return PreparedMemoryVerificationChecks.prepare(context, { ...scope, execution: bundle.execution, flow: bundle.descriptor }).execute(context);
|
|
35
|
+
}
|
|
36
|
+
/** Productive entry implementation, not registered until the complete six-stage
|
|
37
|
+
* memory group is ready. Checks and semantic assessment acceptance belong to
|
|
38
|
+
* its finish path, not this allocation of a verifier coordinator.
|
|
39
|
+
*/
|
|
40
|
+
export function startMemoryVerification(context, input) {
|
|
41
|
+
if (!(input.bytes instanceof Uint8Array) || input.bytes.length > 1024 * 1024)
|
|
42
|
+
refuse("invalid_input_bytes");
|
|
43
|
+
const bundle = readFlowRunExecutionBundle(context, input);
|
|
44
|
+
if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.descriptor.successor("compose", "accepted") !== "verify"
|
|
45
|
+
|| bundle.descriptor.successor("verify", "accepted") !== "review")
|
|
46
|
+
refuse("registered_memory_bundle_required");
|
|
47
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId, stage: "verify" };
|
|
48
|
+
const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), index = JSON.parse(run.index_json);
|
|
49
|
+
if (index.stage_runs.find((stage) => stage.stage === "verify")?.status === "done")
|
|
50
|
+
refuse("use_accepted_finish_replay");
|
|
51
|
+
const preservation = PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
|
|
52
|
+
const inherited = context.db.readSnapshot(() => ({ compose: readAcceptedStageData(context, { ...scope, stage: "compose" }), preflight: readAcceptedStageData(context, { ...scope, stage: "preflight" }) }));
|
|
53
|
+
const compose = JSON.parse(inherited.compose.bytes.toString("utf8")), preflight = JSON.parse(inherited.preflight.bytes.toString("utf8"));
|
|
54
|
+
if (compose.schema_id !== "dd-flow/mb-init-compose-result@1" || compose.run_id !== input.runId || compose.outcome !== "accepted"
|
|
55
|
+
|| preflight.schema_id !== "dd-flow/mb-init-preflight-result@1" || preflight.run_id !== input.runId || preflight.outcome !== "accepted")
|
|
56
|
+
refuse("accepted_composition_and_baseline_required");
|
|
57
|
+
const fence = (writer) => {
|
|
58
|
+
preservation.assertCustody(writer);
|
|
59
|
+
if (readAcceptedStageData(writer, { ...scope, stage: "compose" }).authority_sha256 !== inherited.compose.authority_sha256
|
|
60
|
+
|| readAcceptedStageData(writer, { ...scope, stage: "preflight" }).authority_sha256 !== inherited.preflight.authority_sha256)
|
|
61
|
+
refuse("inherited_custody_changed");
|
|
62
|
+
};
|
|
63
|
+
const start = PreparedDescriptorStageStart.prepare(context, { ...input, stage: "verify" });
|
|
64
|
+
preservation.revalidate(context);
|
|
65
|
+
const stage = start.apply(context, fence), coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage: "verify" });
|
|
66
|
+
preservation.revalidate(context);
|
|
67
|
+
return { ...stage, ...coordinator.apply(context, fence) };
|
|
68
|
+
}
|
|
69
|
+
/** Verification settlement. Restore composition from committed SQL and
|
|
70
|
+
* its original registration, never from verifier-proposed predecessor bytes.
|
|
71
|
+
* Replay consumes independent historical acceptance/check custody instead of
|
|
72
|
+
* current workspace policy. No partial registry is enabled by this path.
|
|
73
|
+
*/
|
|
74
|
+
export function finishMemoryVerification(context, input) {
|
|
75
|
+
if (!(input.bytes instanceof Uint8Array) || !input.bytes.length || input.bytes.length > 1024 * 1024)
|
|
76
|
+
refuse("invalid_result_bytes");
|
|
77
|
+
const bundle = readFlowRunExecutionBundle(context, input);
|
|
78
|
+
if (!bundle || bundle.descriptor.descriptor.id !== "mb-init" || bundle.descriptor.successor("compose", "accepted") !== "verify"
|
|
79
|
+
|| bundle.descriptor.successor("verify", "accepted") !== "review")
|
|
80
|
+
refuse("registered_memory_bundle_required");
|
|
81
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId };
|
|
82
|
+
const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), index = JSON.parse(run.index_json);
|
|
83
|
+
if (index.stage_runs.find((stage) => stage.stage === "verify")?.status === "done") {
|
|
84
|
+
const data = readAcceptedStageData(context, { ...scope, stage: "verify" });
|
|
85
|
+
const accepted = PreparedAcceptedMemoryVerification.prepare(context, { ...scope, bytes: data.bytes });
|
|
86
|
+
const value = JSON.parse(data.bytes.toString("utf8"));
|
|
87
|
+
let proposal;
|
|
88
|
+
try {
|
|
89
|
+
proposal = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.bytes));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
refuse("invalid_result_bytes");
|
|
93
|
+
}
|
|
94
|
+
if (hybridDigest(projectMemoryVerificationChecks(projectMemoryVerificationArtifacts(proposal, value.units, value.units.flatMap((unit) => unit.artifacts)), value.details.checks, bundle.descriptor.stage("verify").directory, createHash("sha256").update(input.bytes).digest("hex"))) !== hybridDigest(value))
|
|
95
|
+
refuse("accepted_result_changed");
|
|
96
|
+
const settlement = PreparedDescriptorStageSettlement.prepare(context, { ...input, stage: "verify", bytes: data.bytes });
|
|
97
|
+
accepted.revalidate(context);
|
|
98
|
+
return settlement.apply(context, writer => accepted.assertCustody(writer));
|
|
99
|
+
}
|
|
100
|
+
const composition = PreparedAcceptedMemoryComposition.prepare(context, { scope, bundle }), compose = composition.result();
|
|
101
|
+
const composedUnits = compose.value().units;
|
|
102
|
+
const preservation = PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
|
|
103
|
+
const policy = PreparedMemoryVerificationChecks.prepare(context, { ...scope, execution: bundle.execution, flow: bundle.descriptor });
|
|
104
|
+
const checks = policy.evidence(context, "diagnostic");
|
|
105
|
+
const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, stage: "verify", flow: bundle.descriptor, execution: bundle.execution, bundle,
|
|
106
|
+
sources: composition.captureSources(context, input.bytes, checks), checks });
|
|
107
|
+
let proposal;
|
|
108
|
+
try {
|
|
109
|
+
proposal = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.bytes));
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
PreparedMemoryStageResult.prepare(input.bytes, bundle.descriptor, binding.binding());
|
|
113
|
+
refuse("invalid_result_bytes");
|
|
114
|
+
}
|
|
115
|
+
const references = checks.sourceReferences().map(({ path, sha256 }) => ({ path, sha256 }));
|
|
116
|
+
const result = PreparedMemoryStageResult.prepare(Buffer.from(JSON.stringify(projectMemoryVerificationChecks(projectMemoryVerificationArtifacts(proposal, composedUnits, composition.outputReferences(), createHash("sha256").update(input.bytes).digest("hex")), references, bundle.descriptor.stage("verify").directory, createHash("sha256").update(input.bytes).digest("hex")))), bundle.descriptor, binding.binding());
|
|
117
|
+
const acceptance = PreparedMemoryVerificationAcceptance.prepare({ scope, result, compose, checks, composition, roots: bundle.execution.snapshot().scope });
|
|
118
|
+
const receipt = PreparedMemoryVerificationReceipt.prepare(context, { scope, result, checks, acceptance });
|
|
119
|
+
const settlement = PreparedDescriptorStageSettlement.prepare(context, { ...input, stage: "verify", bytes: result.bytes() });
|
|
120
|
+
composition.revalidate(context);
|
|
121
|
+
binding.revalidate(context);
|
|
122
|
+
// Binding owns the check artifact references and has just revalidated the
|
|
123
|
+
// same checks; acceptance adds SQL custody, not another physical pass.
|
|
124
|
+
preservation.revalidate(context);
|
|
125
|
+
policy.revalidate(context);
|
|
126
|
+
acceptance.assertCustody(context, result);
|
|
127
|
+
return settlement.apply(context, writer => {
|
|
128
|
+
composition.assertCustody(writer);
|
|
129
|
+
binding.assertCustody(writer);
|
|
130
|
+
preservation.assertCustody(writer);
|
|
131
|
+
policy.assertCustody(writer);
|
|
132
|
+
acceptance.assertCustody(writer, result);
|
|
133
|
+
receipt.record(writer);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { AppError } from "../shared/errors.js";
|
|
2
|
+
import { readFlowRunExecutionBundle } from "./runs.js";
|
|
3
|
+
import { readWorkBatchCustody } from "./work-registry.js";
|
|
4
|
+
import { selectMemoryCompositionRegistration } from "./memory-composition-registration.js";
|
|
5
|
+
import { PreparedRegisteredMemoryCompositionWorkResult } from "./memory-composition-work-custody.js";
|
|
6
|
+
import { PreparedRegisteredMemoryReviewWorkResult } from "./memory-review-work-custody.js";
|
|
7
|
+
import { PreparedPublishedMemoryRepairWorkResult } from "./memory-repair-work-custody.js";
|
|
8
|
+
import { restoreMemoryRepairPublicationFromStage, prepareMemorySecondRepairPublicationFromStage } from "./memory-review-handler.js";
|
|
9
|
+
/** Public Work finish selects authority from SQL and the retained bundle, not
|
|
10
|
+
* from worker JSON, mutable schemas, caller profile or a supplied request key.
|
|
11
|
+
* Preparation is read-only and occurs before the settlement writer.
|
|
12
|
+
*/
|
|
13
|
+
export function prepareRegisteredMemoryWorkResult(context, work, result) {
|
|
14
|
+
if (!["dd-flow/memory-composition-work-result@1", "dd-flow/memory-review-work-result@1", "dd-flow/memory-repair-work-result@1"].includes(work.result_schema ?? ""))
|
|
15
|
+
return null;
|
|
16
|
+
const bytes = Buffer.from(result, "utf8");
|
|
17
|
+
if (work.result_schema === "dd-flow/memory-repair-work-result@1") {
|
|
18
|
+
if (!bytes.length || bytes.length > 1024 * 1024)
|
|
19
|
+
throw new AppError("memory_work_result_preparation_required", "Repair finish requires bounded published result bytes", 1, { effect: "no_effect" });
|
|
20
|
+
const run = context.db.get("SELECT project_root FROM runs WHERE project_id=? AND id=?", [work.project_id, work.run_id]);
|
|
21
|
+
const link = context.db.get("SELECT id,start_receipt_json FROM work_sessions WHERE work_id=? AND status='running'", [work.work_id]);
|
|
22
|
+
let wave, workspaceRoot;
|
|
23
|
+
try {
|
|
24
|
+
const payload = JSON.parse(work.payload_json ?? "null");
|
|
25
|
+
if (payload?.kind !== "memory-repair" || payload.read_only !== false)
|
|
26
|
+
throw new Error("Invalid repair payload");
|
|
27
|
+
wave = payload.memory_repair?.wave;
|
|
28
|
+
if (!link?.start_receipt_json || Buffer.byteLength(link.start_receipt_json) > 32 * 1024 * 1024)
|
|
29
|
+
throw new Error("Missing bounded start receipt");
|
|
30
|
+
const receipt = JSON.parse(link.start_receipt_json);
|
|
31
|
+
if (typeof receipt.context !== "string" || Buffer.byteLength(receipt.context) > 16 * 1024 * 1024)
|
|
32
|
+
throw new Error("Missing bounded context");
|
|
33
|
+
workspaceRoot = JSON.parse(receipt.context).workspace_root;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new AppError("memory_work_result_preparation_required", "Repair finish requires retained physical start scope", 1, { effect: "no_effect" });
|
|
37
|
+
}
|
|
38
|
+
if (!run || !link || wave !== 1 && wave !== 2 || typeof workspaceRoot !== "string" || !workspaceRoot)
|
|
39
|
+
throw new AppError("memory_work_result_preparation_required", "Repair finish requires its exact wave and WorkSession", 1, { effect: "no_effect" });
|
|
40
|
+
const input = { projectRoot: run.project_root, runId: work.run_id, workId: work.work_id, workSessionId: link.id, workspaceRoot };
|
|
41
|
+
const publication = wave === 1 ? restoreMemoryRepairPublicationFromStage(context, input) : prepareMemorySecondRepairPublicationFromStage(context, input);
|
|
42
|
+
if (!publication.bytes().equals(bytes))
|
|
43
|
+
throw new AppError("memory_work_result_preparation_required", "Submitted repair bytes differ from the retained publication", 1, { effect: "no_effect" });
|
|
44
|
+
return PreparedPublishedMemoryRepairWorkResult.prepare(context, publication);
|
|
45
|
+
}
|
|
46
|
+
if (work.result_schema === "dd-flow/memory-review-work-result@1") {
|
|
47
|
+
return PreparedRegisteredMemoryReviewWorkResult.prepare(context, { workId: work.work_id, bytes });
|
|
48
|
+
}
|
|
49
|
+
const run = context.db.get("SELECT project_root FROM runs WHERE project_id=? AND id=?", [work.project_id, work.run_id]);
|
|
50
|
+
const bundle = run && readFlowRunExecutionBundle(context, { projectRoot: run.project_root, runId: work.run_id });
|
|
51
|
+
if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
|
|
52
|
+
throw new AppError("memory_work_result_preparation_required", "Composition finish requires its retained memory flow", 1, { effect: "no_effect" });
|
|
53
|
+
const custody = readWorkBatchCustody(context, work.work_id);
|
|
54
|
+
const registration = selectMemoryCompositionRegistration(context, {
|
|
55
|
+
project_id: work.project_id, run_id: work.run_id, stage: "compose", attempt: custody.scope.attempt,
|
|
56
|
+
cycle: custody.scope.cycle, parent_work_id: custody.scope.parent_work_id
|
|
57
|
+
});
|
|
58
|
+
return PreparedRegisteredMemoryCompositionWorkResult.prepareFromStageCustody(context, bytes, bundle.engine(), {
|
|
59
|
+
projectId: work.project_id, runId: work.run_id, workId: work.work_id,
|
|
60
|
+
coordinatorWorkId: registration.scope.parent_work_id, requestKey: registration.scope.request_key,
|
|
61
|
+
flow: bundle.descriptor, execution: bundle.execution, bundle
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -11,9 +11,24 @@ import { loadProjectFlowContract } from "../domain/flow-contract.js";
|
|
|
11
11
|
import { buildStaticFlowGuidance } from "./flow-guidance.js";
|
|
12
12
|
import { normalizeProtocolLifecycle } from "./protocol-lifecycle.js";
|
|
13
13
|
import { buildProjectSummary, projectRegistrySummary, readPublishedProjectSummary } from "./project-summary.js";
|
|
14
|
+
/** Resolve filesystem identity before entering a composite SQL writer. */
|
|
15
|
+
export class PreparedProjectRegistration {
|
|
16
|
+
#root;
|
|
17
|
+
constructor(root) { this.#root = root; Object.freeze(this); }
|
|
18
|
+
static prepare(input) {
|
|
19
|
+
return new PreparedProjectRegistration(resolveProjectRoot(input.root));
|
|
20
|
+
}
|
|
21
|
+
root() { return this.#root; }
|
|
22
|
+
}
|
|
14
23
|
export function registerProject(context, input) {
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
return registerPreparedProject(context, PreparedProjectRegistration.prepare(input));
|
|
25
|
+
}
|
|
26
|
+
/** Metadata-only registration; the composite caller owns its SQL transaction. */
|
|
27
|
+
export function registerPreparedProject(context, prepared) {
|
|
28
|
+
if (!(prepared instanceof PreparedProjectRegistration))
|
|
29
|
+
throw new AppError("validation", "Project registration must be prepared", 2);
|
|
30
|
+
const root = prepared.root();
|
|
31
|
+
const existing = context.db.get("SELECT * FROM projects WHERE root = ?", [root]);
|
|
17
32
|
const now = context.now();
|
|
18
33
|
const project = existing ?? newProjectRecord(context, root, now);
|
|
19
34
|
if (existing) {
|