@deksden-com/dd-flow-cli 0.9.0-beta.143 → 0.9.0-beta.145
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +13 -8
- package/dist/build-info.json +7 -7
- package/dist/cli/command-inputs.js +9 -3
- package/dist/cli/command-metadata.js +33 -14
- package/dist/cli/help.js +32 -1
- package/dist/cli/hook-ingress.js +27 -3
- package/dist/cli/memory-flow-admission.js +7 -3
- package/dist/cli/memory-init-invocation.js +10 -3
- package/dist/cli/memory-init.js +74 -68
- package/dist/cli/memory-storage-admission.js +3 -2
- package/dist/cli/memory-storage-qualification.js +105 -0
- package/dist/cli/memory-storage-transition.js +123 -0
- package/dist/cli/memory-upgrade.js +189 -0
- package/dist/cli/native-hook-ingress.js +14 -4
- package/dist/cli/native-hook-preparation.js +55 -0
- package/dist/cli/response-file.js +2 -1
- package/dist/cli/run-cli.js +70 -32
- package/dist/cli/setup.js +2 -1
- package/dist/cli.js +12 -0
- package/dist/domain/stage-handler-identities.js +8 -0
- package/dist/harness-runtime/bin/dd-agy.mjs +3 -3
- package/dist/harness-runtime/bin/dd-grok.mjs +3 -3
- package/dist/harness-runtime/bin/dd-zcode.mjs +5 -5
- package/dist/harness-runtime/lib/agy-error-boundary.mjs +58 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +62 -20
- package/dist/harness-runtime/lib/dd-agy.mjs +17 -3
- package/dist/harness-runtime/lib/dd-droid.mjs +1 -1
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +70 -13
- package/dist/harness-runtime/lib/dd-grok.mjs +6 -3
- package/dist/harness-runtime/lib/dd-zcode.mjs +44 -14
- package/dist/harness-runtime/lib/delegation-instructions.mjs +1 -1
- package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
- package/dist/harness-runtime/lib/entity-references.mjs +9 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +13 -6
- package/dist/harness-runtime/lib/native-hook-command.mjs +4 -4
- package/dist/harness-runtime/lib/opencode-plugin.mjs +3 -3
- package/dist/harness-runtime/lib/operation-errors.mjs +1 -1
- package/dist/harness-runtime/lib/provider-overload-policy.d.mts +4 -2
- package/dist/harness-runtime/lib/provider-overload-policy.mjs +19 -6
- package/dist/harness-runtime/lib/runner-events.mjs +3 -1
- package/dist/harness-runtime/lib/setup-progress.mjs +8 -6
- package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
- package/dist/schemas/memory-repair-work-result.schema.json +9 -2
- package/dist/schemas/release-impact.schema.json +3 -3
- package/dist/schemas/stage-start-response.schema.json +4 -0
- package/dist/services/accepted-intent.js +13 -1
- package/dist/services/canon.js +43 -7
- package/dist/services/cli-operation-classifier.js +1 -1
- package/dist/services/cli-upgrade-allowlist.js +1 -1
- package/dist/services/code-checks.js +11 -4
- package/dist/services/compatibility-preflight.js +5 -2
- package/dist/services/controller-fanout.js +21 -4
- package/dist/services/controller-memory-task.js +45 -0
- package/dist/services/controller-memory-worker.js +48 -0
- package/dist/services/dashboard.js +2 -2
- package/dist/services/descriptor-run-start.js +26 -19
- package/dist/services/descriptor-stage-coordinator.js +30 -10
- package/dist/services/descriptor-stage-start.js +40 -4
- package/dist/services/engines.js +64 -14
- package/dist/services/eval-snapshots.js +104 -93
- package/dist/services/external-work-launch.js +5 -3
- package/dist/services/flow-catalog.js +8 -4
- package/dist/services/frozen-engine.js +113 -11
- package/dist/services/hook-memory-routing.js +188 -0
- package/dist/services/hook-recovery-guard.js +14 -0
- package/dist/services/hook-session-observation.js +24 -0
- package/dist/services/hooks.js +27 -8
- package/dist/services/hybrid-contracts.js +2 -13
- package/dist/services/hybrid-digest.js +14 -0
- package/dist/services/installed-flow-source.js +25 -4
- package/dist/services/lifecycle-invocations.js +33 -5
- package/dist/services/memory-accepted-composition.js +5 -4
- package/dist/services/memory-completed-correction-wave.js +23 -15
- package/dist/services/memory-compose-handler.js +163 -21
- package/dist/services/memory-composition-acceptance.js +186 -10
- package/dist/services/memory-composition-graph.js +42 -11
- package/dist/services/memory-composition-registration.js +23 -8
- package/dist/services/memory-composition-work-custody.js +14 -9
- package/dist/services/memory-composition-work-results.js +15 -3
- package/dist/services/memory-corrected-review-batch.js +10 -3
- package/dist/services/memory-corrected-review-findings.js +4 -2
- package/dist/services/memory-corrected-review-inputs.js +10 -5
- package/dist/services/memory-corrected-review-receipt.js +17 -9
- package/dist/services/memory-corrected-review-registration.js +3 -2
- package/dist/services/memory-correction-check-receipt.js +20 -4
- package/dist/services/memory-custody-snapshot.js +36 -0
- package/dist/services/memory-finish-evidence.js +44 -22
- package/dist/services/memory-finish-handler.js +37 -23
- package/dist/services/memory-finish-integration.js +218 -48
- package/dist/services/memory-finish-readiness.js +66 -19
- package/dist/services/memory-git-integration.js +87 -18
- package/dist/services/memory-historical-corrected-review.js +21 -15
- package/dist/services/memory-historical-original-review.js +22 -9
- package/dist/services/memory-historical-repair-registration.js +14 -8
- package/dist/services/memory-historical-second-review.js +30 -11
- package/dist/services/memory-init-contexts.js +28 -2
- package/dist/services/memory-init-controller-start.js +19 -8
- package/dist/services/memory-init-git-policy.js +50 -21
- package/dist/services/memory-init-lint-capability.js +21 -3
- package/dist/services/memory-init-native-capacity.js +13 -0
- package/dist/services/memory-init-preflight.js +11 -1
- package/dist/services/memory-init-request-candidate.js +73 -17
- package/dist/services/memory-init-request-input.js +23 -7
- package/dist/services/memory-init-run-bundle.js +49 -12
- package/dist/services/memory-init-storage.js +17 -7
- package/dist/services/memory-layer.js +68 -4
- package/dist/services/memory-lint-config.js +111 -2
- package/dist/services/memory-native-review-copy.js +5 -67
- package/dist/services/memory-normal-flow-entry.js +12 -0
- package/dist/services/memory-ordinary-defaults.js +22 -5
- package/dist/services/memory-preflight-handler.js +15 -0
- package/dist/services/memory-repair-current-view.js +1 -1
- package/dist/services/memory-repair-document-delta.js +70 -33
- package/dist/services/memory-repair-history.js +12 -7
- package/dist/services/memory-repair-physical-binding.js +1 -119
- package/dist/services/memory-repair-publication-plan.js +5 -3
- package/dist/services/memory-repair-publication-source.js +1 -1
- package/dist/services/memory-repair-publication.js +3 -2
- package/dist/services/memory-repair-registration.js +2 -1
- package/dist/services/memory-repair-work-baseline.js +4 -2
- package/dist/services/memory-repair-work-completion.js +32 -12
- package/dist/services/memory-repair-work-results.js +21 -2
- package/dist/services/memory-repair-workspace.js +11 -2
- package/dist/services/memory-repair-writer-copy.js +2 -1
- package/dist/services/memory-result-binding.js +78 -12
- package/dist/services/memory-retained-review-authority.js +17 -8
- package/dist/services/memory-retained-second-baseline.js +1 -1
- package/dist/services/memory-retained-second-repairs.js +12 -6
- package/dist/services/memory-review-correction-plan.js +47 -12
- package/dist/services/memory-review-handler.js +17 -17
- package/dist/services/memory-review-inputs.js +55 -9
- package/dist/services/memory-review-limits.js +10 -0
- package/dist/services/memory-review-receipt.js +2 -2
- package/dist/services/memory-review-registration.js +13 -4
- package/dist/services/memory-review-work-custody.js +3 -1
- package/dist/services/memory-review-work-input.js +26 -7
- package/dist/services/memory-review-work-results.js +26 -4
- package/dist/services/memory-second-corrected-review-inputs.js +5 -3
- package/dist/services/memory-second-correction-plan.js +2 -1
- package/dist/services/memory-second-repair-launch.js +4 -4
- package/dist/services/memory-second-repair-source.js +1 -1
- package/dist/services/memory-stage-dispatch.js +38 -1
- package/dist/services/memory-stage-results.js +113 -22
- package/dist/services/memory-upgrade-analysis-handler.js +243 -0
- package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
- package/dist/services/memory-upgrade-evidence.js +100 -0
- package/dist/services/memory-upgrade-inventory.js +442 -0
- package/dist/services/memory-upgrade-publication-custody.js +73 -0
- package/dist/services/memory-upgrade-publication.js +413 -0
- package/dist/services/memory-upgrade-selection.js +430 -0
- package/dist/services/memory-upgrade-start.js +60 -0
- package/dist/services/memory-upgrade-storage-readiness.js +340 -0
- package/dist/services/memory-verification-acceptance.js +38 -17
- package/dist/services/memory-verification-checks.js +77 -23
- package/dist/services/memory-verification-receipt.js +6 -5
- package/dist/services/memory-verify-handler.js +15 -13
- package/dist/services/memory-work-result-json.js +12 -0
- package/dist/services/memory-work-result-preparation.js +5 -4
- package/dist/services/merge-server.js +4 -2
- package/dist/services/migrations.js +127 -98
- package/dist/services/physical-startup.js +45 -0
- package/dist/services/project-registry.js +97 -0
- package/dist/services/project-summary.js +1 -1
- package/dist/services/projects.js +3 -93
- package/dist/services/prompt-delivery.js +71 -0
- package/dist/services/provider-capacity.js +74 -9
- package/dist/services/recovery-snapshot-database.js +32 -4
- package/dist/services/repair-intents.js +1 -12
- package/dist/services/repair-receipt.js +13 -0
- package/dist/services/run-control-worker.js +35 -18
- package/dist/services/run-controller-process.js +2 -6
- package/dist/services/run-controller-recovery.js +6 -1
- package/dist/services/run-controller.js +131 -80
- package/dist/services/run-recovery-guard.js +30 -0
- package/dist/services/run-recovery.js +11 -44
- package/dist/services/run-start-custody.js +17 -5
- package/dist/services/runtime-scope-worker.js +46 -19
- package/dist/services/sessions.js +3 -24
- package/dist/services/setup.js +63 -13
- package/dist/services/stage-handlers.js +9 -7
- package/dist/services/stage-pause.js +108 -44
- package/dist/services/version-status.js +1 -1
- package/dist/services/vnext-fanout.js +21 -9
- package/dist/services/vnext-plan-review.js +3 -5
- package/dist/services/work-registry.js +80 -33
- package/dist/services/workspace-files.js +1 -1
- package/dist/shared/entity-references.js +1 -8
- package/dist/storage/data-preservation.js +65 -0
- package/dist/storage/database.js +53 -19
- package/dist/storage/import-guard.js +84 -27
- package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
- package/dist/storage/paired-writer-migration.js +424 -0
- package/dist/storage/writer-contract.js +11 -4
- package/dist/storage/writer-migration.js +313 -52
- package/dist/storage/writer-restore.js +217 -0
- package/package.json +8 -4
|
@@ -50,7 +50,7 @@ export class PreparedInstalledFlowSource {
|
|
|
50
50
|
}
|
|
51
51
|
static fromInstalledRelease(home, expectedInstallationSha256, flowId) {
|
|
52
52
|
try {
|
|
53
|
-
if (!path.isAbsolute(home) || !/^[a-f0-9]{64}$/.test(expectedInstallationSha256) ||
|
|
53
|
+
if (!path.isAbsolute(home) || !/^[a-f0-9]{64}$/.test(expectedInstallationSha256) || !["mb-init", "mb-upgrade"].includes(flowId))
|
|
54
54
|
refuse("invalid_selection");
|
|
55
55
|
const selected = readSetupStatus(home);
|
|
56
56
|
if (!selected.installation || selected.installation_readiness !== "installed")
|
|
@@ -120,6 +120,18 @@ export class PreparedInstalledFlowSource {
|
|
|
120
120
|
* or admit its engine/storage; those remain the bootstrap owner's duties.
|
|
121
121
|
*/
|
|
122
122
|
static restoreRetained(input, expectedSha256) {
|
|
123
|
+
const result = this.restoreRetainedData(input, expectedSha256);
|
|
124
|
+
try {
|
|
125
|
+
result.resolveRegisteredFlow();
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return refuse("invalid_retained_source");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Data recovery before storage/engine admission. This cannot register a
|
|
133
|
+
* handler; productive restoration still uses restoreRetained above. */
|
|
134
|
+
static restoreRetainedData(input, expectedSha256) {
|
|
123
135
|
try {
|
|
124
136
|
if (!input || typeof input !== "object" || Array.isArray(input) || typeof expectedSha256 !== "string"
|
|
125
137
|
|| !/^[a-f0-9]{64}$/.test(expectedSha256))
|
|
@@ -132,7 +144,7 @@ export class PreparedInstalledFlowSource {
|
|
|
132
144
|
|| typeof value.canon.archive_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(value.canon.archive_sha256)
|
|
133
145
|
|| typeof value.canon.version !== "string" || !/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/.test(value.canon.version)
|
|
134
146
|
|| !value.descriptor || Object.keys(value.descriptor).sort().join() !== "path,sha256"
|
|
135
|
-
||
|
|
147
|
+
|| !["mb-init/flow-descriptor.json", "mb-upgrade/flow-descriptor.json"].includes(value.descriptor.path) || typeof value.descriptor.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(value.descriptor.sha256)
|
|
136
148
|
|| !Array.isArray(value.blobs) || value.blobs.length < 1 || value.blobs.length > 129)
|
|
137
149
|
refuse("invalid_retained_source");
|
|
138
150
|
const blobs = new Map(), folded = new Set();
|
|
@@ -154,10 +166,19 @@ export class PreparedInstalledFlowSource {
|
|
|
154
166
|
const descriptor = blobs.get(value.descriptor.path);
|
|
155
167
|
if (!descriptor || hash(descriptor) !== value.descriptor.sha256)
|
|
156
168
|
refuse("retained_source_changed");
|
|
157
|
-
const
|
|
169
|
+
const flowId = value.descriptor.path.startsWith("mb-upgrade/") ? "mb-upgrade" : "mb-init";
|
|
170
|
+
const declared = JSON.parse(descriptor.toString("utf8"));
|
|
171
|
+
if (validateHybridShape("flow-descriptor", declared).length || declared.id !== flowId || declared.origin !== "canon")
|
|
172
|
+
refuse("invalid_retained_source");
|
|
173
|
+
for (const stage of declared.stages)
|
|
174
|
+
for (const kind of ["instruction", "result_schema"]) {
|
|
175
|
+
const reference = stage[kind], content = blobs.get(reference.path);
|
|
176
|
+
if (!content || hash(content) !== reference.sha256)
|
|
177
|
+
refuse("retained_source_changed");
|
|
178
|
+
}
|
|
179
|
+
const result = new PreparedInstalledFlowSource(null, value.installation_sha256, flowId, { ...value.descriptor }, { ...value.canon }, blobs);
|
|
158
180
|
if (result.sha256 !== expectedSha256)
|
|
159
181
|
refuse("retained_source_changed");
|
|
160
|
-
result.resolveRegisteredFlow();
|
|
161
182
|
return result;
|
|
162
183
|
}
|
|
163
184
|
catch (error) {
|
|
@@ -8,16 +8,15 @@ import { AppError, errorRecord } from "../shared/errors.js";
|
|
|
8
8
|
import { shortEntityReference } from "../shared/entity-references.js";
|
|
9
9
|
import { resolveWorkReference } from "../storage/work-references.js";
|
|
10
10
|
import { commandOption, commandPosition, continuationCommand, lifecycleCommandFromPayload, parseLifecycleCommand, shellSuffixOffset } from "./lifecycle-command.js";
|
|
11
|
-
import { requireProjectByRoot } from "./
|
|
12
|
-
import { assertRunMutationAllowed, assertStageSettlementAllowed, assertWorkSettlementAllowed, recoveryGuard, recoveryPacketReceipt } from "./run-recovery.js";
|
|
11
|
+
import { requireProjectByRoot } from "./project-registry.js";
|
|
12
|
+
import { assertRunMutationAllowed, assertStageSettlementAllowed, assertWorkSettlementAllowed, recoveryGuard, recoveryPacketReceipt } from "./run-recovery-guard.js";
|
|
13
13
|
import { readNativeDaemonState, requireManagedDaemonBinding } from "./managed-daemon-binding.js";
|
|
14
14
|
import { managedProcessStatus, processIsAlive, processStartedAt } from "./managed-processes.js";
|
|
15
15
|
import { appendEvent } from "./run-controller-state.js";
|
|
16
|
-
import { recoverCommittedWorkStart } from "./work-registry.js";
|
|
17
16
|
import { observeCommandHook } from "./hooks.js";
|
|
18
17
|
import { runtimeHarness } from "./execution-policy.js";
|
|
19
18
|
import { normalizedPathAlias, resolveContextualPaths } from "./command-context.js";
|
|
20
|
-
import { isRegisteredRepair } from "./repair-
|
|
19
|
+
import { isRegisteredRepair } from "./repair-receipt.js";
|
|
21
20
|
import { stageAttempt } from "./stage-work-graph.js";
|
|
22
21
|
import { contextualPathOptionsForLifecycle } from "../cli/command-inputs.js";
|
|
23
22
|
import { canonicalPath } from "../storage/paths.js";
|
|
@@ -1930,9 +1929,38 @@ export async function awaitLifecycleInvocation(context, input) {
|
|
|
1930
1929
|
return { outcome: JSON.parse(row.outcome_json), replay: true };
|
|
1931
1930
|
if (row.status === "executing") {
|
|
1932
1931
|
const scope = JSON.parse(row.scope_json);
|
|
1932
|
+
const parsed = invocation(row.command);
|
|
1933
|
+
if (parsed.operation === "stage_resume" && scope.runId) {
|
|
1934
|
+
input.assertCurrent(scope);
|
|
1935
|
+
const { recoverCommittedStageResume } = await import("./stage-pause.js");
|
|
1936
|
+
const result = recoverCommittedStageResume(context, { id: row.id, projectRoot: scope.projectRoot, runId: scope.runId, generation: scope.generation, stage: commandOption(parsed, "stage") ?? "", workId: commandOption(parsed, "work") ?? "" });
|
|
1937
|
+
if (result) {
|
|
1938
|
+
const { preparePromptDelivery } = await import("./prompt-delivery.js");
|
|
1939
|
+
const delivered = preparePromptDelivery(result);
|
|
1940
|
+
const previousScope = context.env.DD_FLOW_INVOCATION_SCOPE;
|
|
1941
|
+
context.env.DD_FLOW_INVOCATION_SCOPE = row.scope_json;
|
|
1942
|
+
try {
|
|
1943
|
+
bindLifecyclePublishedPacket(context, String(result.worker_prompt_markdown));
|
|
1944
|
+
}
|
|
1945
|
+
finally {
|
|
1946
|
+
if (previousScope === undefined)
|
|
1947
|
+
delete context.env.DD_FLOW_INVOCATION_SCOPE;
|
|
1948
|
+
else
|
|
1949
|
+
context.env.DD_FLOW_INVOCATION_SCOPE = previousScope;
|
|
1950
|
+
}
|
|
1951
|
+
const project = requireProjectByRoot(context, scope.projectRoot);
|
|
1952
|
+
const event = row.event_key ? context.db.get("SELECT id FROM hook_events WHERE project_id = ? AND event_key = ?", [project.id, row.event_key]) : null;
|
|
1953
|
+
if (event)
|
|
1954
|
+
observeLifecycleCommand(context, row.command, { project_id: project.id, id: event.id })({ result: delivered });
|
|
1955
|
+
const outcome = { result: delivered, effect: "committed" };
|
|
1956
|
+
settleLifecycleInvocation(context, row.id, outcome);
|
|
1957
|
+
return { outcome, replay: true };
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1933
1960
|
if (invocation(row.command).operation === "work_start" && row.event_key) {
|
|
1934
1961
|
input.assertCurrent(scope);
|
|
1935
|
-
const
|
|
1962
|
+
const { recoverCommittedWorkStart } = await import("./work-registry.js");
|
|
1963
|
+
const result = recoverCommittedWorkStart(context, row.id, row.event_key, scope.generation, undefined, input.progress);
|
|
1936
1964
|
if (result) {
|
|
1937
1965
|
const outcome = { result, effect: "committed" };
|
|
1938
1966
|
settleLifecycleInvocation(context, row.id, outcome);
|
|
@@ -35,15 +35,16 @@ export class PreparedAcceptedMemoryComposition {
|
|
|
35
35
|
}
|
|
36
36
|
static prepare(context, input) {
|
|
37
37
|
const { scope, bundle } = input;
|
|
38
|
-
if (!(bundle instanceof RetainedExecutionBundle) || bundle.descriptor.descriptor.id
|
|
38
|
+
if (!(bundle instanceof RetainedExecutionBundle) || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
|
|
39
39
|
refuse("registered_memory_bundle_required");
|
|
40
|
+
const stage = bundle.descriptor.descriptor.id === "mb-init" ? "compose" : "upgrade";
|
|
40
41
|
const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), root = readDescriptorRootWork(context, scope, bundle);
|
|
41
|
-
const registration = selectMemoryCompositionRegistration(context, { ...stageGraphScope(context, scope.projectId, scope.runId,
|
|
42
|
+
const registration = selectMemoryCompositionRegistration(context, { ...stageGraphScope(context, scope.projectId, scope.runId, stage), stage, parent_work_id: root.workId });
|
|
42
43
|
const blueprint = PreparedMemoryResultBinding.prepareRegisteredComposition(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle, acceptedReplay: true,
|
|
43
44
|
registrationScope: registration.scope });
|
|
44
45
|
const outputs = PreparedMemoryCompositionAcceptance.prepare(context, { scope: registration.scope, flow: bundle.descriptor, engine: bundle.engine(), binding: blueprint.binding() });
|
|
45
|
-
const composed = readAcceptedStageData(context, { ...scope, stage
|
|
46
|
-
const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, stage
|
|
46
|
+
const composed = readAcceptedStageData(context, { ...scope, stage }), runRoot = run.run_root ?? run.run_dir;
|
|
47
|
+
const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, stage, flow: bundle.descriptor, execution: bundle.execution, bundle, acceptedReplay: true,
|
|
47
48
|
sources: captureMemoryCompositionSources(context, bundle, runRoot, composed.bytes, outputs), historicalEvidence: outputs.historicalEvidence() });
|
|
48
49
|
if (!binding.acceptedBytes()?.equals(composed.bytes))
|
|
49
50
|
refuse("accepted_composition_changed");
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { assertMemorySqlCustody } from "./memory-custody-snapshot.js";
|
|
1
2
|
import { AppError } from "../shared/errors.js";
|
|
2
3
|
import { hybridDigest } from "./hybrid-contracts.js";
|
|
3
4
|
import { PreparedRegisteredMemoryCorrections } from "./memory-repair-registration.js";
|
|
4
5
|
import { PreparedRetainedSecondMemoryRepairs } from "./memory-retained-second-repairs.js";
|
|
5
6
|
import { PreparedSettledMemoryRepair } from "./memory-repair-history.js";
|
|
6
7
|
import { PreparedMemoryRepairWorkspace } from "./memory-repair-workspace.js";
|
|
8
|
+
import { isCompletedMemoryRepairClaim } from "./memory-repair-work-results.js";
|
|
7
9
|
import { reviewSourcePaths } from "./review-copy.js";
|
|
8
10
|
import { readAcceptedStageData } from "./stage-report-renderer.js";
|
|
9
11
|
const token = Symbol("completed-memory-correction-wave");
|
|
@@ -41,8 +43,7 @@ export function memoryCorrectionAffectedUnits(units, repairs, composition = [])
|
|
|
41
43
|
const affected = new Set(), changed = new Set();
|
|
42
44
|
for (const repair of repairs) {
|
|
43
45
|
if (!repair || !Array.isArray(repair.unit_ids) || !repair.unit_ids.length || new Set(repair.unit_ids).size !== repair.unit_ids.length
|
|
44
|
-
|| repair.unit_ids.some((id) => !applicable.has(id)) || repair.result
|
|
45
|
-
|| !Array.isArray(repair.result.changes) || !repair.result.changes.length)
|
|
46
|
+
|| repair.unit_ids.some((id) => !applicable.has(id)) || !isCompletedMemoryRepairClaim(repair.result))
|
|
46
47
|
refuse("invalid_settled_repair_projection");
|
|
47
48
|
for (const id of repair.unit_ids)
|
|
48
49
|
affected.add(id);
|
|
@@ -138,6 +139,7 @@ const nonMemory = (entry) => entry.path !== ".memory-bank" && !entry.path.starts
|
|
|
138
139
|
* review. Reconstruction starts at independently retained first-wave state;
|
|
139
140
|
* neither current files nor a second writer's claimed before-view are anchors. */
|
|
140
141
|
export class PreparedHistoricalSecondMemoryCorrectionWave {
|
|
142
|
+
#custodyKey = {};
|
|
141
143
|
static isPrepared(value) {
|
|
142
144
|
return typeof value === "object" && value !== null && #registration in value;
|
|
143
145
|
}
|
|
@@ -167,11 +169,11 @@ export class PreparedHistoricalSecondMemoryCorrectionWave {
|
|
|
167
169
|
for (const history of histories) {
|
|
168
170
|
if (!prefixes.has(hybridDigest(history.before().entries())))
|
|
169
171
|
refuse("unexplained_historical_input_view");
|
|
170
|
-
baseline = baseline.composeSettledDelta(history.before(), history.after());
|
|
172
|
+
baseline = baseline.composeSettledDelta(history.before(), history.after(), history.result().outcome);
|
|
171
173
|
prefixes.add(hybridDigest(baseline.entries()));
|
|
172
174
|
}
|
|
173
175
|
const batch = registration.batch(), receipt = registration.receipt(), first = registration.initialInputView();
|
|
174
|
-
const compose = readAcceptedStageData(context, { ...input.scope, stage: "compose" });
|
|
176
|
+
const compose = readAcceptedStageData(context, { ...input.scope, stage: input.bundle.descriptor.descriptor.id === "mb-upgrade" ? "upgrade" : "compose" });
|
|
175
177
|
const affected = memoryCorrectionAffectedUnits(memoryCorrectionCurrentUnits(first.unit_inventory, first.assignments), histories.map(history => ({ result: history.result(),
|
|
176
178
|
unit_ids: batch.works.find(item => receipt.work_ids[item.key] === history.workId).payload.memory_repair.unit_ids })), JSON.parse(compose.bytes.toString("utf8")).details.works);
|
|
177
179
|
const prepared = new PreparedHistoricalSecondMemoryCorrectionWave(historicalToken, registration, selected, histories, baseline, affected);
|
|
@@ -189,10 +191,13 @@ export class PreparedHistoricalSecondMemoryCorrectionWave {
|
|
|
189
191
|
unit_ids: batch.works.find(item => receipt.work_ids[item.key] === history.workId).payload.memory_repair.unit_ids }));
|
|
190
192
|
}
|
|
191
193
|
assertCustody(context) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
const registration = this.#registration;
|
|
195
|
+
assertMemorySqlCustody(context, this.#custodyKey, () => {
|
|
196
|
+
if (hybridDigest(selection(context, registration)) !== hybridDigest(this.#selected))
|
|
197
|
+
refuse("historical_second_graph_changed");
|
|
198
|
+
for (const history of this.#histories)
|
|
199
|
+
history.assertCustody(context);
|
|
200
|
+
});
|
|
196
201
|
}
|
|
197
202
|
revalidate(context) {
|
|
198
203
|
this.#registration.revalidate(context);
|
|
@@ -207,6 +212,7 @@ export class PreparedHistoricalSecondMemoryCorrectionWave {
|
|
|
207
212
|
* from today's filesystem. This owner neither allocates reviewers nor marks
|
|
208
213
|
* repair findings resolved; independent re-review must consume it separately. */
|
|
209
214
|
export class PreparedCompletedMemoryCorrectionWave {
|
|
215
|
+
#custodyKey = {};
|
|
210
216
|
static isPrepared(value) {
|
|
211
217
|
return typeof value === "object" && value !== null && #selected in value;
|
|
212
218
|
}
|
|
@@ -252,7 +258,7 @@ export class PreparedCompletedMemoryCorrectionWave {
|
|
|
252
258
|
for (const history of histories) {
|
|
253
259
|
if (!known.has(hybridDigest(history.before().entries())))
|
|
254
260
|
refuse("unexplained_historical_input_view");
|
|
255
|
-
baseline = baseline.composeSettledDelta(history.before(), history.after());
|
|
261
|
+
baseline = baseline.composeSettledDelta(history.before(), history.after(), history.result().outcome);
|
|
256
262
|
known.add(hybridDigest(baseline.entries()));
|
|
257
263
|
}
|
|
258
264
|
const view = PreparedRetainedSecondMemoryRepairs.isPrepared(registration) ? registration.initialInputView()
|
|
@@ -272,7 +278,7 @@ export class PreparedCompletedMemoryCorrectionWave {
|
|
|
272
278
|
if (histories.some(history => hybridDigest(history.workspaceManifest().entries().filter(nonMemory)) !== sourceSha256))
|
|
273
279
|
refuse("non_memory_source_changed");
|
|
274
280
|
const batch = registration.batch(), receipt = registration.receipt();
|
|
275
|
-
const compose = readAcceptedStageData(context, { projectId: receipt.scope.project_id, runId: receipt.run_id, stage: "compose" });
|
|
281
|
+
const compose = readAcceptedStageData(context, { projectId: receipt.scope.project_id, runId: receipt.run_id, stage: bundle.descriptor.descriptor.id === "mb-upgrade" ? "upgrade" : "compose" });
|
|
276
282
|
const dependencies = JSON.parse(compose.bytes.toString("utf8")).details.works;
|
|
277
283
|
const currentUnits = PreparedRetainedSecondMemoryRepairs.isPrepared(registration)
|
|
278
284
|
? memoryCorrectionCurrentUnits(registration.initialInputView().unit_inventory, registration.initialInputView().assignments)
|
|
@@ -292,11 +298,13 @@ export class PreparedCompletedMemoryCorrectionWave {
|
|
|
292
298
|
repairResults() { return this.#histories.map(history => ({ work_id: history.workId, result: history.result(), reference: history.reference(), authority_sha256: history.sha256 })); }
|
|
293
299
|
/** Only SQL custody is inspected inside the future review-allocation writer. */
|
|
294
300
|
assertCustody(context) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
history
|
|
301
|
+
assertMemorySqlCustody(context, this.#custodyKey, () => {
|
|
302
|
+
const selected = this.#selected;
|
|
303
|
+
if (hybridDigest(selection(context, this.#registration)) !== hybridDigest(selected))
|
|
304
|
+
refuse("completed_wave_custody_changed");
|
|
305
|
+
for (const history of this.#histories)
|
|
306
|
+
history.assertCustody(context);
|
|
307
|
+
});
|
|
300
308
|
}
|
|
301
309
|
/** Fresh allocation fence, before adding successor reviewers. General
|
|
302
310
|
* custody deliberately stays valid when those admitted children exist. */
|
|
@@ -20,6 +20,14 @@ import { PreparedMemoryCompositionAcceptance } from "./memory-composition-accept
|
|
|
20
20
|
import { readAcceptedStageData } from "./stage-report-renderer.js";
|
|
21
21
|
import { ObservedMemorySources } from "./memory-source-observations.js";
|
|
22
22
|
import { PreparedCheckEvidence } from "./code-checks.js";
|
|
23
|
+
import { captureMemoryUpgradeSources } from "./memory-upgrade-analysis-handler.js";
|
|
24
|
+
import { PreparedMemoryUpgradeBootstrapReadiness, readMemoryUpgradeBootstrapReadiness } from "./memory-upgrade-bootstrap-readiness.js";
|
|
25
|
+
import { readUpgradeStorageReadiness } from "./memory-upgrade-storage-readiness.js";
|
|
26
|
+
import { PreparedMemoryUpgradePublication } from "./memory-upgrade-publication.js";
|
|
27
|
+
import { PreparedMemoryLayer } from "./memory-layer.js";
|
|
28
|
+
import { appendAudit } from "./audit.js";
|
|
29
|
+
import { assertImportAdmission } from "../storage/import-guard.js";
|
|
30
|
+
import { readMemoryUpgradePublication, upgradePublicationKey, upgradePublicationReceipt, upgradePublicationIntentEvent, upgradePublicationCompleteEvent } from "./memory-upgrade-publication-custody.js";
|
|
23
31
|
function refuse(reason) {
|
|
24
32
|
throw new AppError("memory_compose_handler_invalid", "Memory composition lacks retained scope, plan or output custody", 2, { reason, effect: "no_effect" });
|
|
25
33
|
}
|
|
@@ -27,12 +35,30 @@ function selected(context, input) {
|
|
|
27
35
|
if (!(input.bytes instanceof Uint8Array) || input.bytes.length > 1024 * 1024)
|
|
28
36
|
refuse("invalid_input_bytes");
|
|
29
37
|
const bundle = readFlowRunExecutionBundle(context, input);
|
|
30
|
-
if (!bundle ||
|
|
31
|
-
|| bundle.descriptor.successor("compose", "accepted") !== "verify")
|
|
38
|
+
if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
|
|
32
39
|
refuse("registered_memory_bundle_required");
|
|
33
|
-
const
|
|
40
|
+
const stage = bundle.descriptor.descriptor.id === "mb-init" ? "compose" : "upgrade";
|
|
41
|
+
if (bundle.descriptor.successor(stage === "compose" ? "discover" : "diff-analysis", "accepted") !== stage
|
|
42
|
+
|| bundle.descriptor.successor(stage, "accepted") !== "verify")
|
|
43
|
+
refuse("registered_memory_bundle_required");
|
|
44
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot)), scope = { projectId: project.id, runId: input.runId, stage };
|
|
34
45
|
const run = assertPreparedRunBundleSqlAuthority(context, scope, bundle), index = JSON.parse(run.index_json);
|
|
35
|
-
return { bundle, scope, run, accepted: index.stage_runs.find((
|
|
46
|
+
return { bundle, scope, run, accepted: index.stage_runs.find((item) => item.stage === stage)?.status === "done" };
|
|
47
|
+
}
|
|
48
|
+
function compositionBaseline(context, bundle) {
|
|
49
|
+
if (bundle.descriptor.descriptor.id === "mb-init")
|
|
50
|
+
return PreparedMemoryBaselinePreservation.prepare(context, bundle.execution);
|
|
51
|
+
const selected = bundle.execution.snapshot().scope;
|
|
52
|
+
const scope = { requestId: selected.requestId, projectRoot: selected.projectRoot, workspaceRoot: selected.workspace };
|
|
53
|
+
const ready = readMemoryUpgradeBootstrapReadiness(context, scope);
|
|
54
|
+
if (!ready?.hasPreservationBaseline || ready.authority.binding.execution_sha256 !== bundle.execution.sha256)
|
|
55
|
+
refuse("accepted_upgrade_bootstrap_required");
|
|
56
|
+
const authority = hybridDigest(ready.authority);
|
|
57
|
+
return {
|
|
58
|
+
assertCustody(writer) { const current = readMemoryUpgradeBootstrapReadiness(writer, scope); if (!current || hybridDigest(current.authority) !== authority)
|
|
59
|
+
refuse("upgrade_bootstrap_changed"); },
|
|
60
|
+
revalidate(reader) { PreparedMemoryUpgradeBootstrapReadiness.assertForRetainedRun(reader, bundle); this.assertCustody(reader); }
|
|
61
|
+
};
|
|
36
62
|
}
|
|
37
63
|
/** SQL-only physical binding proof; allocation/prompt custody is checked
|
|
38
64
|
* separately. No new Session, hook claim or provider invocation is created.
|
|
@@ -70,14 +96,14 @@ export function registerMemoryCompositionFromStage(context, input) {
|
|
|
70
96
|
const { bundle, scope, accepted } = selected(context, input);
|
|
71
97
|
if (accepted)
|
|
72
98
|
refuse("use_accepted_finish_replay");
|
|
73
|
-
const coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage:
|
|
99
|
+
const coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage: scope.stage });
|
|
74
100
|
const allocated = context.db.readSnapshot(() => {
|
|
75
101
|
coordinator.assertAllocatedCustody(context);
|
|
76
102
|
const root = readDescriptorRootWork(context, scope, bundle);
|
|
77
103
|
return { workId: root.workId, physical: coordinatorSession(context, scope, bundle, root.workId) };
|
|
78
104
|
});
|
|
79
105
|
const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle,
|
|
80
|
-
sources: captureMemoryPreflightSources(context, bundle, input.bytes) });
|
|
106
|
+
sources: scope.stage === "compose" ? captureMemoryPreflightSources(context, bundle, input.bytes) : captureMemoryUpgradeSources(context, bundle, scope.stage, input.bytes) });
|
|
81
107
|
let composition;
|
|
82
108
|
try {
|
|
83
109
|
composition = PreparedMemoryStageResult.prepare(input.bytes, bundle.descriptor, binding.binding());
|
|
@@ -94,7 +120,7 @@ export function registerMemoryCompositionFromStage(context, input) {
|
|
|
94
120
|
const ordinaryDefaults = readDescriptorStageInput(context, scope, bundle).input.ordinary_defaults;
|
|
95
121
|
if (ordinaryDefaults) {
|
|
96
122
|
assertMemoryOrdinaryConfigurationCoverage(composition.value(), ordinaryDefaults);
|
|
97
|
-
if (ordinaryDefaults.missing.length && !context.db.get("SELECT 1 FROM audit_events WHERE project_id=? AND event_type='flow_run.stage_resumed' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.stage')='compose' LIMIT 1", [scope.projectId, scope.runId])) {
|
|
123
|
+
if (scope.stage === "compose" && ordinaryDefaults.missing.length && !context.db.get("SELECT 1 FROM audit_events WHERE project_id=? AND event_type='flow_run.stage_resumed' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.stage')='compose' LIMIT 1", [scope.projectId, scope.runId])) {
|
|
98
124
|
throw new AppError("memory_stage_result_invalid", "Resolve the missing ordinary configuration choice through the existing compose pause/answer path before registering Work", 2, { phase: "prepare", effect: "no_effect", recoverable: true, reason: "ordinary_configuration_choice_required", missing: ordinaryDefaults.missing });
|
|
99
125
|
}
|
|
100
126
|
}
|
|
@@ -114,25 +140,136 @@ export function startMemoryComposition(context, input) {
|
|
|
114
140
|
const { bundle, scope, accepted } = selected(context, input);
|
|
115
141
|
if (accepted)
|
|
116
142
|
refuse("use_accepted_finish_replay");
|
|
117
|
-
const preservation =
|
|
118
|
-
const inherited = context.db.readSnapshot(() => ({ discovery: readAcceptedStageData(context, { ...scope, stage:
|
|
143
|
+
const preservation = compositionBaseline(context, bundle), discoveryStage = scope.stage === "compose" ? "discover" : "diff-analysis";
|
|
144
|
+
const inherited = context.db.readSnapshot(() => ({ discovery: readAcceptedStageData(context, { ...scope, stage: discoveryStage }), preflight: readAcceptedStageData(context, { ...scope, stage: "preflight" }) }));
|
|
119
145
|
const preflight = JSON.parse(inherited.preflight.bytes.toString("utf8")), discovery = JSON.parse(inherited.discovery.bytes.toString("utf8"));
|
|
120
|
-
if (preflight.schema_id !== "dd-flow/mb-init-preflight-result@1" || preflight.run_id !== input.runId || preflight.outcome !== "accepted"
|
|
121
|
-
|| discovery.schema_id !== "dd-flow/mb-init-discover-result@1"
|
|
146
|
+
if (preflight.schema_id !== (scope.stage === "compose" ? "dd-flow/mb-init-preflight-result@1" : "dd-flow/mb-upgrade-stage-result@1") || preflight.run_id !== input.runId || preflight.outcome !== "accepted"
|
|
147
|
+
|| discovery.schema_id !== (scope.stage === "compose" ? "dd-flow/mb-init-discover-result@1" : "dd-flow/mb-upgrade-stage-result@1")
|
|
148
|
+
|| preflight.stage !== "preflight" || discovery.stage !== discoveryStage
|
|
122
149
|
|| discovery.run_id !== input.runId || discovery.outcome !== "accepted")
|
|
123
150
|
refuse("accepted_discovery_and_baseline_required");
|
|
124
151
|
const fence = (writer) => {
|
|
125
152
|
preservation.assertCustody(writer);
|
|
126
|
-
if (readAcceptedStageData(writer, { ...scope, stage:
|
|
153
|
+
if (readAcceptedStageData(writer, { ...scope, stage: discoveryStage }).authority_sha256 !== inherited.discovery.authority_sha256
|
|
127
154
|
|| readAcceptedStageData(writer, { ...scope, stage: "preflight" }).authority_sha256 !== inherited.preflight.authority_sha256)
|
|
128
155
|
refuse("inherited_custody_changed");
|
|
129
156
|
};
|
|
130
|
-
const start = PreparedDescriptorStageStart.prepare(context, { ...input, stage:
|
|
157
|
+
const start = PreparedDescriptorStageStart.prepare(context, { ...input, stage: scope.stage });
|
|
131
158
|
preservation.revalidate(context);
|
|
132
|
-
const stage = start.apply(context, fence), coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage:
|
|
159
|
+
const stage = start.apply(context, fence), coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage: scope.stage });
|
|
133
160
|
preservation.revalidate(context);
|
|
134
161
|
return { ...stage, ...coordinator.apply(context, fence) };
|
|
135
162
|
}
|
|
163
|
+
/** Mechanical upgrade continuation, not final Stage acceptance. Reuses the
|
|
164
|
+
* registered blueprint and settled Work; the plan is retained in SQL before
|
|
165
|
+
* the first filesystem effect. No provider or second controller is launched.
|
|
166
|
+
* Kept outside the registry until the complete upgrade lifecycle is admitted.
|
|
167
|
+
*/
|
|
168
|
+
export function publishMemoryUpgradeFromStage(context, input) {
|
|
169
|
+
const { bundle, scope, accepted } = selected(context, { ...input, bytes: Buffer.alloc(0) });
|
|
170
|
+
if (scope.stage !== "upgrade" || accepted)
|
|
171
|
+
refuse("active_upgrade_publication_required");
|
|
172
|
+
const coordinator = PreparedDescriptorStageCoordinator.prepare(context, { ...input, stage: "upgrade" });
|
|
173
|
+
const allocated = context.db.readSnapshot(() => {
|
|
174
|
+
coordinator.assertAllocatedCustody(context);
|
|
175
|
+
const root = readDescriptorRootWork(context, scope, bundle);
|
|
176
|
+
return { workId: root.workId, physical: coordinatorSession(context, scope, bundle, root.workId) };
|
|
177
|
+
});
|
|
178
|
+
const registration = selectMemoryCompositionRegistration(context, { ...stageGraphScope(context, scope.projectId, scope.runId, "upgrade"), stage: "upgrade", parent_work_id: allocated.workId });
|
|
179
|
+
const binding = PreparedMemoryResultBinding.prepareRegisteredComposition(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle, registrationScope: registration.scope });
|
|
180
|
+
const outputs = PreparedMemoryCompositionAcceptance.prepareForUpgradePublication(context, { scope: registration.scope, flow: bundle.descriptor, engine: bundle.engine(), binding: binding.binding() });
|
|
181
|
+
const frozen = bundle.execution.snapshot().scope, bootstrapScope = { requestId: frozen.requestId, projectRoot: frozen.projectRoot, workspaceRoot: frozen.workspace };
|
|
182
|
+
const ready = readMemoryUpgradeBootstrapReadiness(context, bootstrapScope), storage = readUpgradeStorageReadiness(context, bootstrapScope);
|
|
183
|
+
if (!ready || !storage?.selection || ready.authority.binding.storage_sha256 !== storage.sha256)
|
|
184
|
+
refuse("accepted_upgrade_bootstrap_required");
|
|
185
|
+
const identity = { scope: registration.scope, selection_sha256: storage.selection.sha256, execution_sha256: bundle.execution.sha256,
|
|
186
|
+
registration_sha256: hybridDigest(registration), bootstrap_sha256: hybridDigest(ready.authority),
|
|
187
|
+
work_custody_sha256: outputs.custodySha256() };
|
|
188
|
+
const fence = (writer) => {
|
|
189
|
+
assertPreparedRunBundleSqlAuthority(writer, scope, bundle);
|
|
190
|
+
coordinator.assertAllocatedCustody(writer);
|
|
191
|
+
binding.assertCustody(writer);
|
|
192
|
+
outputs.assertCustody(writer);
|
|
193
|
+
if (readDescriptorRootWork(writer, scope, bundle).workId !== allocated.workId
|
|
194
|
+
|| coordinatorSession(writer, scope, bundle, allocated.workId) !== allocated.physical)
|
|
195
|
+
refuse("upgrade_publication_coordinator_changed");
|
|
196
|
+
const current = readMemoryUpgradeBootstrapReadiness(writer, bootstrapScope), retained = readUpgradeStorageReadiness(writer, bootstrapScope);
|
|
197
|
+
if (!current || hybridDigest(current.authority) !== identity.bootstrap_sha256 || retained?.selection?.sha256 !== identity.selection_sha256)
|
|
198
|
+
refuse("upgrade_publication_dependencies_changed");
|
|
199
|
+
};
|
|
200
|
+
const read = (reader) => readMemoryUpgradePublication(reader, identity);
|
|
201
|
+
let plan = read(context)?.plan;
|
|
202
|
+
if (!plan) {
|
|
203
|
+
binding.revalidate(context);
|
|
204
|
+
outputs.revalidate(context);
|
|
205
|
+
const selected = storage.selection.payload, layer = selected.layer;
|
|
206
|
+
if (!selected.current.old_tree || !selected.current.version_source)
|
|
207
|
+
refuse("upgrade_publication_baseline_required");
|
|
208
|
+
const target = PreparedMemoryLayer.restoreRetained(new Map(layer.files.map(file => [file.path, Buffer.from(file.base64, "base64")])), layer.sha256, layer.installation_sha256);
|
|
209
|
+
const diff = readAcceptedStageData(context, { ...scope, stage: "diff-analysis" }), details = JSON.parse(diff.bytes.toString("utf8")).details;
|
|
210
|
+
plan = PreparedMemoryUpgradePublication.prepare({ selectionSha256: storage.selection.sha256, inventory: selected.current.inventory,
|
|
211
|
+
oldTree: selected.current.old_tree, layer: target, changes: details.path_map, versionSource: selected.current.version_source });
|
|
212
|
+
const before = new Map(plan.beforeFiles().map(file => [file.path, file]));
|
|
213
|
+
const settled = new Map(outputs.settledArtifacts().filter(item => item.artifact.root === "workspace").map(item => [item.artifact.path, item.artifact.sha256]));
|
|
214
|
+
for (const entry of selected.current.inventory.inventory.entries)
|
|
215
|
+
if (entry.current && !before.has(entry.path))
|
|
216
|
+
refuse("unsettled_semantic_removal");
|
|
217
|
+
for (const [name, file] of before) {
|
|
218
|
+
const original = selected.current.inventory.inventory.entries.find(entry => entry.path === name)?.current;
|
|
219
|
+
if (original && file.kind === original.kind && file.mode === original.mode && file.sha256 === original.sha256)
|
|
220
|
+
continue;
|
|
221
|
+
if (file.kind !== "file" || original && file.mode !== original.mode || settled.get(`.memory-bank/${name}`) !== file.sha256)
|
|
222
|
+
refuse("unsettled_semantic_change");
|
|
223
|
+
}
|
|
224
|
+
const prepared = plan;
|
|
225
|
+
plan = context.db.writeTransaction(() => {
|
|
226
|
+
fence(context);
|
|
227
|
+
const prior = read(context)?.plan;
|
|
228
|
+
if (prior) {
|
|
229
|
+
if (prior.sha256 !== prepared.sha256)
|
|
230
|
+
refuse("upgrade_publication_plan_changed");
|
|
231
|
+
return prior;
|
|
232
|
+
}
|
|
233
|
+
const now = context.now();
|
|
234
|
+
context.db.run("INSERT INTO runtime_config (key,value_json,created_at,updated_at) VALUES (?,?,?,?)", [upgradePublicationKey(identity), JSON.stringify({ binding: identity, plan_json: prepared.bytes().toString("utf8"), plan_sha256: prepared.sha256 }), now, now]);
|
|
235
|
+
appendAudit(context, { projectId: scope.projectId, eventType: upgradePublicationIntentEvent, payload: upgradePublicationReceipt(identity, prepared) });
|
|
236
|
+
const retained = read(context);
|
|
237
|
+
if (!retained)
|
|
238
|
+
refuse("upgrade_publication_intent_readback_failed");
|
|
239
|
+
return retained.plan;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
const publication = plan;
|
|
243
|
+
try {
|
|
244
|
+
while (true) {
|
|
245
|
+
assertImportAdmission(context.ddFlowHome);
|
|
246
|
+
context.db.readSnapshot(() => { fence(context); if (read(context)?.plan.sha256 !== publication.sha256)
|
|
247
|
+
refuse("upgrade_publication_intent_changed"); });
|
|
248
|
+
if (publication.applyNextAction().status === "applied")
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
context.db.writeTransaction(() => {
|
|
252
|
+
fence(context);
|
|
253
|
+
if (read(context)?.plan.sha256 !== publication.sha256)
|
|
254
|
+
refuse("upgrade_publication_intent_changed");
|
|
255
|
+
if (!read(context)?.completed)
|
|
256
|
+
appendAudit(context, { projectId: scope.projectId, eventType: upgradePublicationCompleteEvent, payload: upgradePublicationReceipt(identity, publication, true) });
|
|
257
|
+
if (!read(context)?.completed)
|
|
258
|
+
refuse("upgrade_publication_completion_readback_failed");
|
|
259
|
+
});
|
|
260
|
+
const state = publication.classify();
|
|
261
|
+
if (state.completed !== state.total)
|
|
262
|
+
refuse("upgrade_publication_not_complete");
|
|
263
|
+
const record = publication.outputs().find(output => output.path === `archive/mb-upgrade/${identity.selection_sha256}/migration.json`);
|
|
264
|
+
if (!record)
|
|
265
|
+
refuse("upgrade_migration_record_missing");
|
|
266
|
+
return { status: "applied", publication_sha256: publication.sha256, migration_record: { path: `.memory-bank/${record.path}`, sha256: record.sha256 },
|
|
267
|
+
artifacts: publication.outputs().map(output => ({ root: "workspace", path: `.memory-bank/${output.path}`, sha256: output.sha256 })) };
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
throw new AppError("memory_upgrade_publication_pending", "Preserve the accepted SQL plan and reconcile this upgrade continuation", 1, { effect: "publication_pending", publication_sha256: publication.sha256, cause: error instanceof Error ? error.message : String(error) });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
136
273
|
/** Agent references are selectors, not permissions. Supplement independent
|
|
137
274
|
* baseline evidence only with current outputs admitted by completed Work.
|
|
138
275
|
*/
|
|
@@ -207,7 +344,10 @@ export function captureMemoryCompositionSources(context, bundle, runRoot, bytes,
|
|
|
207
344
|
}
|
|
208
345
|
// Keep evidence/artifact roles for the shared collector; settled child output
|
|
209
346
|
// references already have their independent output owner above.
|
|
210
|
-
const observedBaseline =
|
|
347
|
+
const observedBaseline = bundle.descriptor.descriptor.id === "mb-upgrade"
|
|
348
|
+
? captureMemoryUpgradeSources(context, bundle, value.stage, Buffer.from(JSON.stringify(value)))
|
|
349
|
+
: captureMemoryPreflightSources(context, bundle, Buffer.from(JSON.stringify(value)));
|
|
350
|
+
const locations = new Map();
|
|
211
351
|
for (const key of observedBaseline.hashes().keys()) {
|
|
212
352
|
const [root, logical] = key.split("\0");
|
|
213
353
|
locations.set(key, { root: root, path: logical });
|
|
@@ -230,27 +370,29 @@ export function captureMemoryCompositionSources(context, bundle, runRoot, bytes,
|
|
|
230
370
|
* Semantic quality remains the following VERIFY and independent REVIEW gates.
|
|
231
371
|
*/
|
|
232
372
|
export function finishMemoryComposition(context, input) {
|
|
233
|
-
const { bundle, scope, run, accepted } = selected(context, input)
|
|
373
|
+
const { bundle, scope, run, accepted } = selected(context, input);
|
|
374
|
+
const root = readDescriptorRootWork(context, scope, bundle);
|
|
234
375
|
if (!input.bytes.length)
|
|
235
376
|
refuse("invalid_result_bytes");
|
|
236
|
-
const registration = selectMemoryCompositionRegistration(context, { ...stageGraphScope(context, scope.projectId, scope.runId, scope.stage), stage:
|
|
377
|
+
const registration = selectMemoryCompositionRegistration(context, { ...stageGraphScope(context, scope.projectId, scope.runId, scope.stage), stage: scope.stage, parent_work_id: root.workId });
|
|
237
378
|
const registrationScope = registration.scope;
|
|
238
379
|
const blueprintBinding = PreparedMemoryResultBinding.prepareRegisteredComposition(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle,
|
|
239
380
|
registrationScope, acceptedReplay: accepted });
|
|
240
381
|
const outputs = PreparedMemoryCompositionAcceptance.prepare(context, { scope: registrationScope, flow: bundle.descriptor, engine: bundle.engine(), binding: blueprintBinding.binding() });
|
|
241
|
-
const
|
|
382
|
+
const bytes = outputs.projectResult(input.bytes);
|
|
383
|
+
const sources = captureMemoryCompositionSources(context, bundle, run.run_root ?? run.run_dir, bytes, outputs);
|
|
242
384
|
const binding = PreparedMemoryResultBinding.prepare(context, { ...scope, flow: bundle.descriptor, execution: bundle.execution, bundle, sources, acceptedReplay: accepted, historicalEvidence: outputs.historicalEvidence() });
|
|
243
385
|
const replay = binding.acceptedBytes();
|
|
244
|
-
if (replay && !replay.equals(
|
|
386
|
+
if (replay && !replay.equals(bytes))
|
|
245
387
|
refuse("accepted_result_changed");
|
|
246
|
-
const result = PreparedMemoryStageResult.prepare(
|
|
388
|
+
const result = PreparedMemoryStageResult.prepare(bytes, bundle.descriptor, binding.binding());
|
|
247
389
|
outputs.assertResult(result);
|
|
248
390
|
const ordinaryDefaults = readDescriptorStageInput(context, scope, bundle, true, accepted).input.ordinary_defaults;
|
|
249
391
|
if (ordinaryDefaults && !replay) {
|
|
250
392
|
const selected = bundle.execution.snapshot().scope;
|
|
251
393
|
assertMemoryOrdinaryConfigurationOutputs(context, selected.workspace, ordinaryDefaults, result.value().units.flatMap(unit => unit.artifacts), { requestId: selected.requestId, projectRoot: selected.projectRoot, workspaceRoot: selected.workspace });
|
|
252
394
|
}
|
|
253
|
-
const settlement = PreparedDescriptorStageSettlement.prepare(context, { ...input, stage:
|
|
395
|
+
const settlement = PreparedDescriptorStageSettlement.prepare(context, { ...input, stage: scope.stage, bytes: result.bytes() });
|
|
254
396
|
blueprintBinding.revalidate(context);
|
|
255
397
|
binding.revalidate(context);
|
|
256
398
|
outputs.revalidate(context);
|