@zq-silk/yui 0.13.9 → 0.14.0
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/ARCHITECTURE.md +69 -428
- package/README.md +108 -298
- package/dist/agent/managedRuntimeEnvironment.js +2 -2
- package/dist/cli/commandCatalog.js +39 -77
- package/dist/cli/interactionCandidates.js +4 -4
- package/dist/cli/interactionPolicy.js +7 -10
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/updateCommand.js +6 -27
- package/dist/cli/updateOrchestrator.js +63 -484
- package/dist/cli/updatePorts.js +15 -333
- package/dist/cli/upgradeCommand.js +8 -65
- package/dist/cli.js +57 -242
- package/dist/commands/configCommands.js +11 -62
- package/dist/commands/executionAuditCommands.js +23 -23
- package/dist/commands/globalRoleCommands.js +2 -7
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/projectCommands.js +5 -5
- package/dist/commands/releaseCommands.js +3 -10
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/sessionCommands.js +2 -2
- package/dist/commands/taskActor.js +31 -39
- package/dist/commands/taskChangeSetCommands.js +5 -12
- package/dist/commands/taskCommands.js +464 -1249
- package/dist/commands/taskContextCommand.js +35 -36
- package/dist/commands/taskExecutionCommands.js +33 -46
- package/dist/commands/taskInputCommands.js +20 -42
- package/dist/commands/taskNextActionCommand.js +9 -9
- package/dist/commands/taskOverviewCommand.js +56 -95
- package/dist/commands/taskRoleRuntimeStatus.js +77 -107
- package/dist/commands/taskUpstreamCommands.js +3 -3
- package/dist/commands/taskWorkspaceCommands.js +7 -79
- package/dist/commands/telemetryCommands.js +32 -124
- package/dist/commands/workflowCommands.js +3 -3
- package/dist/completion/fileCompletionManager.js +1 -1
- package/dist/config/configCatalog.js +4 -6
- package/dist/config/yuiConfig.js +6 -43
- package/dist/context/dispatchContext.js +14 -30
- package/dist/context/roleSessionContext.js +2 -2
- package/dist/context/sessionBootstrapManifest.js +2 -2
- package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
- package/dist/context/turnInputContract.js +204 -0
- package/dist/context/wakeNotification.js +2 -2
- package/dist/controller/agentRuntimeObserver.js +18 -18
- package/dist/controller/clientRuntime.js +13 -20
- package/dist/controller/controller.js +89 -116
- package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
- package/dist/controller/jobControl.js +17 -17
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +38 -59
- package/dist/controller/resourceInventoryRpc.js +3 -3
- package/dist/controller/resourceInventoryWorker.js +1 -1
- package/dist/controller/runtime.js +46 -53
- package/dist/controller/runtimeEventInbox.js +23 -31
- package/dist/controller/runtimeEventProcessor.js +15 -15
- package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
- package/dist/controller/runtimeLaunchCoordinator.js +3 -3
- package/dist/controller/runtimeObservationHook.js +11 -8
- package/dist/controller/sessionNotify.js +11 -11
- package/dist/controller/structuredProviderObservation.js +89 -16
- package/dist/coordination/workMailbox.js +309 -579
- package/dist/coordination/workMailboxQueue.js +5 -6
- package/dist/core/controllerClient.js +1 -91
- package/dist/core/controllerServer.js +3 -6
- package/dist/doctor/doctor.js +51 -314
- package/dist/execution/candidateConvergence.js +3 -3
- package/dist/execution/executionGroup.js +32 -33
- package/dist/execution/executionHealth.js +36 -38
- package/dist/execution/resourceBroker.js +12 -12
- package/dist/executor/agentExecutor.js +30 -265
- package/dist/executor/effectiveLaunch.js +9 -19
- package/dist/executor/executorRegistry.js +43 -17
- package/dist/executor/fileRoleLaunchPlanner.js +56 -56
- package/dist/executor/launchPlan.js +3 -3
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +20 -25
- package/dist/input/inputRequest.js +12 -12
- package/dist/integration/changeSet.js +9 -13
- package/dist/integration/changeSetManifest.js +1 -1
- package/dist/integration/gitIntegrationService.js +2 -2
- package/dist/integration/integrationQueueService.js +5 -21
- package/dist/integration/overlapDiagnostics.js +2 -2
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/job/jobRunner.js +1 -1
- package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
- package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
- package/dist/message/message.js +6 -6
- package/dist/observability/executionAudit.js +74 -86
- package/dist/observability/faultClassification.js +7 -24
- package/dist/observability/orchestrationMetrics.js +5 -5
- package/dist/observability/runtimeIdentity.js +34 -101
- package/dist/profile/agentProfile.js +1 -1
- package/dist/release/cliHomeReleaseFence.js +3 -3
- package/dist/release/releaseWorkflowEngine.js +6 -10
- package/dist/release/releaseWorkflowPorts.js +2 -2
- package/dist/release/workflowFileLock.js +1 -1
- package/dist/repository/checkoutSwap.js +1 -1
- package/dist/repository/gitWorkspace.js +0 -13
- package/dist/repository/project.js +1 -1
- package/dist/repository/projectMaintenanceLock.js +1 -2
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +21 -25
- package/dist/repository/taskWorkspaceIdentity.js +8 -21
- package/dist/repository/taskWorkspacePreparer.js +63 -620
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +1 -1
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/sqliteResourceRegistry.js +1 -1
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewFindingLedger.js +1 -1
- package/dist/review/reviewOutcomeClassifier.js +35 -50
- package/dist/review/reviewRound.js +14 -25
- package/dist/review/reviewerAvailability.js +4 -4
- package/dist/review/taskFinalReviewContractResolution.js +41 -0
- package/dist/role/role.js +6 -3
- package/dist/runtime/agentDriver.js +4 -0
- package/dist/runtime/agentHost.js +151 -36
- package/dist/runtime/builtinAgentDrivers.js +79 -2
- package/dist/runtime/codexAppServerRuntime.js +122 -0
- package/dist/runtime/continuationManager.js +3 -5
- package/dist/runtime/exactControlPlane.js +17 -42
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +4 -4
- package/dist/runtime/processExitObservation.js +1 -1
- package/dist/runtime/processExitOutbox.js +0 -32
- package/dist/runtime/promptEnvelope.js +9 -9
- package/dist/runtime/providerContinuation.js +2 -2
- package/dist/runtime/providerContinuationReconciliationService.js +2 -2
- package/dist/runtime/providerRuntimeIdentity.js +76 -24
- package/dist/runtime/recentTurnIds.js +38 -0
- package/dist/runtime/runtimeContinuationProjection.js +2 -2
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +58 -21
- package/dist/runtime/runtimeProjection.js +19 -27
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/structuredProviderHost.js +177 -12
- package/dist/runtime/tmuxAdapters.js +46 -11
- package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
- package/dist/scheduler/leaderWakeupProcessor.js +147 -445
- package/dist/scheduler/operatorEvent.js +4 -6
- package/dist/scheduler/resourceQueueProjection.js +71 -0
- package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
- package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
- package/dist/scheduler/taskExecutionProjection.js +99 -99
- package/dist/scheduler/taskObservabilityProjection.js +10 -10
- package/dist/scheduler/taskWake.js +4 -4
- package/dist/scheduler/wakeReason.js +6 -10
- package/dist/scheduler/wakeupQueue.js +0 -9
- package/dist/setup/setupCommand.js +2 -2
- package/dist/storage/currentTaskStore.js +46 -0
- package/dist/storage/persistenceWorker.js +1 -1
- package/dist/storage/sqliteSchema.js +81 -485
- package/dist/storage/sqliteStore.js +206 -365
- package/dist/storage/storageSchema.js +1 -15
- package/dist/storage/storageVersions.js +8 -9
- package/dist/storage/storeRpc.js +10 -34
- package/dist/storage/taskStore.js +63 -3415
- package/dist/storage/upgrade/recordVersions.js +55 -149
- package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
- package/dist/task/completionReadiness.js +5 -5
- package/dist/task/deliveryGuard.js +10 -10
- package/dist/task/nextAction.js +74 -77
- package/dist/task/task.js +2 -4
- package/dist/task/taskRecordReference.js +3 -3
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +53 -53
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +8 -14
- package/dist/turn/turn.js +356 -0
- package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
- package/dist/verification/gateArtifactStore.js +2 -2
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/components.js +29 -54
- package/dist/web/assets/client/i18n.js +17 -37
- package/dist/web/assets/client/view.js +37 -37
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +5 -5
- package/dist/web/assets/styles/widgets.js +1 -2
- package/dist/web/webSnapshot.js +65 -60
- package/dist/workItem/workItem.js +11 -11
- package/dist/workspace/workItemChangeSetManager.js +1 -1
- package/docs/task-local-identity.md +5 -5
- package/i18n/README.zh-CN.md +41 -54
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +85 -83
- package/skills/yui-operator/SKILL.md +16 -16
- package/skills/yui-reviewer/SKILL.md +10 -10
- package/skills/yui-runtime/SKILL.md +17 -18
- package/skills/yui-worker/SKILL.md +16 -18
- package/dist/context/runContextContract.js +0 -162
- package/dist/executor/turnCompletion.js +0 -126
- package/dist/review/taskFinalReviewContractEvent.js +0 -1
- package/dist/review/taskFinalReviewContractRebind.js +0 -367
- package/dist/run/agentRun.js +0 -356
- package/dist/run/rejectedYieldAttempt.js +0 -221
- package/dist/run/runControlRequest.js +0 -50
- package/dist/run/yieldReceipt.js +0 -65
- package/dist/runtime/turnCompletion.js +0 -3
- package/dist/scheduler/actionability.js +0 -323
- package/dist/scheduler/activeRoleRunDelivery.js +0 -868
- package/dist/scheduler/activeTaskProgress.js +0 -126
- package/dist/storage/compatibleTaskStore.js +0 -248
- package/dist/storage/migration/baseline.js +0 -78
- package/dist/storage/migration/classifier.js +0 -51
- package/dist/storage/migration/compatibleCodec.js +0 -53
- package/dist/storage/migration/engine.js +0 -147
- package/dist/storage/migration/index.js +0 -33
- package/dist/storage/migration/planner.js +0 -154
- package/dist/storage/migration/productionRegistry.js +0 -3931
- package/dist/storage/migration/registry.js +0 -169
- package/dist/storage/migration/report.js +0 -54
- package/dist/storage/migration/types.js +0 -31
- package/dist/storage/upgrade/homeClassification.js +0 -353
- package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
- package/dist/storage/upgrade/migrationReceipt.js +0 -67
- package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
- package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
- package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
- package/dist/storage/upgrade/recordVersionScan.js +0 -176
- package/dist/storage/upgrade/sqliteFileSet.js +0 -50
- package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
- package/dist/storage/upgrade/sqliteStateMigration.js +0 -918
- package/dist/storage/upgrade/switchProgress.js +0 -80
- package/dist/storage/upgrade/upgradeReceipt.js +0 -161
- package/dist/storage/upgradeCoordination.js +0 -187
- package/dist/storage/upgradeFence.js +0 -366
- package/dist/telemetry/telemetryCompaction.js +0 -252
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The transactional migration engine.
|
|
3
|
-
*
|
|
4
|
-
* The engine is parameterized over the abstract {@link MigrationTarget} and the
|
|
5
|
-
* `latest` supported {@link StorageVersionState}; it never touches a real Home
|
|
6
|
-
* and holds no domain list of derived-state fields. All domain knowledge lives
|
|
7
|
-
* behind the injected `rebuildDerivedState` / `validateCurrentState` boundary,
|
|
8
|
-
* and every step only *declares* its effects.
|
|
9
|
-
*
|
|
10
|
-
* Flow (execute mode):
|
|
11
|
-
* inspect -> plan (reject on missing step) -> detectLiveRuntime (fail-closed
|
|
12
|
-
* if active) -> read immutable source -> apply step transforms into a fresh
|
|
13
|
-
* output -> rebuildDerivedState(effects) -> validateCurrentState() ->
|
|
14
|
-
* atomicSwitchWithBackup -> structured MigrationReport.
|
|
15
|
-
*
|
|
16
|
-
* Dry-run mode runs the same pipeline through the validation gate, then discards
|
|
17
|
-
* the fresh output and never switches.
|
|
18
|
-
*
|
|
19
|
-
* Invariants: on any failure the source is never switched and stays byte-for-
|
|
20
|
-
* byte unchanged, and — because input is immutable and output is fresh — an
|
|
21
|
-
* interrupted run is safely retriable (delete partial output and re-run). Once
|
|
22
|
-
* the source already equals `latest`, the run is a no-op (`already-current`).
|
|
23
|
-
*/
|
|
24
|
-
import { planMigration } from "./planner.js";
|
|
25
|
-
import { collectEffects, toStepSummary } from "./report.js";
|
|
26
|
-
import { AmbiguousSwitchError } from "./types.js";
|
|
27
|
-
/** Run the transactional migration and return a structured report. Never throws. */
|
|
28
|
-
export function runMigration(options) {
|
|
29
|
-
const { registry, target, latest, mode } = options;
|
|
30
|
-
// 1) inspect — read-only.
|
|
31
|
-
const source = target.inspectVersions();
|
|
32
|
-
// 2) plan — a missing adjacent step or a future version fails closed here.
|
|
33
|
-
const plan = planMigration(registry, source, latest);
|
|
34
|
-
if (plan.kind === "blocked") {
|
|
35
|
-
return { outcome: "blocked", mode, source, target: latest, blocker: plan.blocker };
|
|
36
|
-
}
|
|
37
|
-
if (plan.kind === "no-op") {
|
|
38
|
-
return { outcome: "already-current", mode, source, target: latest };
|
|
39
|
-
}
|
|
40
|
-
const stepSummaries = plan.steps.map(toStepSummary);
|
|
41
|
-
const effects = collectEffects(plan.steps);
|
|
42
|
-
// 3) detectLiveRuntime — refuse to migrate a target a live runtime is holding.
|
|
43
|
-
const live = target.detectLiveRuntime();
|
|
44
|
-
if (live.active) {
|
|
45
|
-
return {
|
|
46
|
-
outcome: "active-runtime",
|
|
47
|
-
mode,
|
|
48
|
-
source,
|
|
49
|
-
target: latest,
|
|
50
|
-
steps: stepSummaries,
|
|
51
|
-
...(live.detail ? { detail: live.detail } : {})
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
// 4) apply steps to a fresh output; the source is only ever read.
|
|
55
|
-
let stage = "precondition";
|
|
56
|
-
const applied = [];
|
|
57
|
-
try {
|
|
58
|
-
let snapshot = target.readSource();
|
|
59
|
-
for (const planned of plan.steps) {
|
|
60
|
-
stage = "precondition";
|
|
61
|
-
planned.step.preconditions(snapshot);
|
|
62
|
-
stage = "transform";
|
|
63
|
-
const next = planned.step.transform(snapshot);
|
|
64
|
-
assertFreshOutput(next, snapshot, planned);
|
|
65
|
-
snapshot = next;
|
|
66
|
-
applied.push(toStepSummary(planned));
|
|
67
|
-
}
|
|
68
|
-
stage = "write-fresh-output";
|
|
69
|
-
target.writeFreshOutput(snapshot);
|
|
70
|
-
// 5) injected canonical derived-state rebuild over the fresh output.
|
|
71
|
-
stage = "rebuild";
|
|
72
|
-
const derived = target.rebuildDerivedState(effects);
|
|
73
|
-
// 6) injected canonical validation gate (the real post-migration loader).
|
|
74
|
-
stage = "validate";
|
|
75
|
-
const validation = target.validateCurrentState();
|
|
76
|
-
if (mode === "dry-run") {
|
|
77
|
-
// Validate only; never switch. Discard the staged output.
|
|
78
|
-
target.discardFreshOutput();
|
|
79
|
-
return {
|
|
80
|
-
outcome: "dry-run",
|
|
81
|
-
mode: "dry-run",
|
|
82
|
-
source,
|
|
83
|
-
target: latest,
|
|
84
|
-
steps: stepSummaries,
|
|
85
|
-
effects,
|
|
86
|
-
derived,
|
|
87
|
-
validation
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
// 7) atomic switch with timestamped backup — the only write to the source.
|
|
91
|
-
stage = "switch";
|
|
92
|
-
const switched = target.atomicSwitchWithBackup();
|
|
93
|
-
return {
|
|
94
|
-
outcome: "migrated",
|
|
95
|
-
mode: "execute",
|
|
96
|
-
source,
|
|
97
|
-
target: latest,
|
|
98
|
-
steps: stepSummaries,
|
|
99
|
-
effects,
|
|
100
|
-
derived,
|
|
101
|
-
validation,
|
|
102
|
-
switch: switched
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
// A partially-applied, ambiguous switch is NOT a clean "source unchanged"
|
|
107
|
-
// failure: the original was moved aside and could not be restored. Surface it
|
|
108
|
-
// as its own outcome so the orchestrator reports a truthful manual recovery
|
|
109
|
-
// instead of a false "unchanged" (P1-4).
|
|
110
|
-
if (error instanceof AmbiguousSwitchError) {
|
|
111
|
-
return {
|
|
112
|
-
outcome: "switch-ambiguous",
|
|
113
|
-
mode,
|
|
114
|
-
source,
|
|
115
|
-
target: latest,
|
|
116
|
-
steps: stepSummaries,
|
|
117
|
-
homePath: error.homePath,
|
|
118
|
-
backupPath: error.backupPath,
|
|
119
|
-
stagingPath: error.stagingPath,
|
|
120
|
-
error: error.message
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
outcome: "failed",
|
|
125
|
-
mode,
|
|
126
|
-
source,
|
|
127
|
-
target: latest,
|
|
128
|
-
stage,
|
|
129
|
-
stepsApplied: applied,
|
|
130
|
-
error: error instanceof Error ? error.message : String(error)
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Defend the pure `immutable-input -> fresh-output` contract: a transform must
|
|
136
|
-
* return a value distinct from its input (never mutate-and-return the source).
|
|
137
|
-
*/
|
|
138
|
-
function assertFreshOutput(next, previous, planned) {
|
|
139
|
-
if (next === previous &&
|
|
140
|
-
typeof next === "object" &&
|
|
141
|
-
next !== null) {
|
|
142
|
-
throw new Error(`Migration step ${planned.axis}` +
|
|
143
|
-
`${planned.recordKind ? `/${planned.recordKind}` : ""} ` +
|
|
144
|
-
`${planned.fromVersion}->${planned.toVersion} returned its input object; ` +
|
|
145
|
-
"transforms must produce a fresh output.");
|
|
146
|
-
}
|
|
147
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic, pure storage-migration core.
|
|
3
|
-
*
|
|
4
|
-
* A future-facing, fully unit-testable migration framework over three
|
|
5
|
-
* independent monotonic version axes (layout / aggregate / record, where the
|
|
6
|
-
* record axis is a `recordKind -> {version, path}` map). The transactional engine
|
|
7
|
-
* is parameterized over an abstract {@link MigrationTarget}, so it neither
|
|
8
|
-
* touches a real Home nor hardcodes any domain derived-state list. Real wiring
|
|
9
|
-
* (the production step graph, canonical rebuild/validate boundary, and target)
|
|
10
|
-
* is injected elsewhere.
|
|
11
|
-
*/
|
|
12
|
-
import { CURRENT_AGGREGATE_SCHEMA_VERSION, CURRENT_STORAGE_LAYOUT_VERSION } from "../storageVersions.js";
|
|
13
|
-
export * from "./types.js";
|
|
14
|
-
export { MigrationRegistry, MigrationRegistryError, createEmptyRegistry } from "./registry.js";
|
|
15
|
-
export { planMigration } from "./planner.js";
|
|
16
|
-
export { classifyStorage } from "./classifier.js";
|
|
17
|
-
export { runMigration } from "./engine.js";
|
|
18
|
-
export { collectEffects, describeReport, toStepSummary } from "./report.js";
|
|
19
|
-
export { BASELINE_STORAGE_LAYOUT_VERSION, BASELINE_AGGREGATE_SCHEMA_VERSION, BASELINE_RECORD_VERSIONS, BASELINE_STORAGE_VERSION_STATE, baselineStorageVersionState, assertBaselineConsistency } from "./baseline.js";
|
|
20
|
-
export { createProductionRegistry, createProductionStorageRegistry, assertRegistryCoversBaselineToCurrent } from "./productionRegistry.js";
|
|
21
|
-
export { loadCompatibleSnapshot, writeCurrentSnapshot, StorageCompatibilityError } from "./compatibleCodec.js";
|
|
22
|
-
/**
|
|
23
|
-
* The current baseline scalar versions, sourced from the single authoritative
|
|
24
|
-
* definitions in `storageSchema.ts` (never re-hardcoded here). Callers compose a
|
|
25
|
-
* full {@link StorageVersionState} by supplying the record-family map for the
|
|
26
|
-
* families they own — the generic core intentionally holds no record list.
|
|
27
|
-
*/
|
|
28
|
-
export function latestScalarVersions() {
|
|
29
|
-
return {
|
|
30
|
-
layout: CURRENT_STORAGE_LAYOUT_VERSION,
|
|
31
|
-
aggregate: CURRENT_AGGREGATE_SCHEMA_VERSION
|
|
32
|
-
};
|
|
33
|
-
}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The cross-axis migration path planner.
|
|
3
|
-
*
|
|
4
|
-
* Given the source and target (latest-supported) {@link StorageVersionState}s and
|
|
5
|
-
* a {@link MigrationRegistry}, it produces a deterministically-ordered plan or a
|
|
6
|
-
* precise fail-closed blocker. It performs no I/O and interprets no domain data.
|
|
7
|
-
*
|
|
8
|
-
* Deterministic order encodes the axis dependency: `layout -> aggregate ->
|
|
9
|
-
* record`. Record families are nested inside the aggregate, so their steps run
|
|
10
|
-
* after the aggregate reaches its target version; record kinds are visited in
|
|
11
|
-
* sorted order and each family's steps ascend by version. Any single missing
|
|
12
|
-
* adjacent step, or any axis whose source is newer than supported, fails closed.
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* Plan the migration from `source` to `target`.
|
|
16
|
-
*
|
|
17
|
-
* Returns `no-op` when every axis is already current, `runnable` with a fully
|
|
18
|
-
* ordered adjacent step chain, or `blocked` with the first fail-closed reason in
|
|
19
|
-
* deterministic axis order (`layout`, then `aggregate`, then record kinds sorted).
|
|
20
|
-
*/
|
|
21
|
-
export function planMigration(registry, source, target) {
|
|
22
|
-
const ordered = [];
|
|
23
|
-
// 1) layout, then 2) aggregate — scalars migrate before any nested record.
|
|
24
|
-
for (const axis of ["layout", "aggregate"]) {
|
|
25
|
-
const chain = planScalarAxis(registry, axis, source[axis], target[axis]);
|
|
26
|
-
if (chain.kind === "blocked")
|
|
27
|
-
return { kind: "blocked", blocker: chain.blocker };
|
|
28
|
-
ordered.push(...chain.steps);
|
|
29
|
-
}
|
|
30
|
-
// 3) record families — nested inside the aggregate; visit target kinds in
|
|
31
|
-
// sorted order so the plan is deterministic. A target-only family starts at
|
|
32
|
-
// the explicit pre-introduction version 0 and therefore requires a registered
|
|
33
|
-
// `introduction` step. It is not an aggregate transform or an implicit
|
|
34
|
-
// no-op: the record family must pass the same fail-closed delivery gate as
|
|
35
|
-
// every later version transition.
|
|
36
|
-
const targetKinds = Object.keys(target.record).sort();
|
|
37
|
-
for (const recordKind of targetKinds) {
|
|
38
|
-
const sourceEntry = source.record[recordKind];
|
|
39
|
-
const chain = planRecordFamily(registry, recordKind, sourceEntry?.version ?? 0, target.record[recordKind].version);
|
|
40
|
-
if (chain.kind === "blocked")
|
|
41
|
-
return { kind: "blocked", blocker: chain.blocker };
|
|
42
|
-
ordered.push(...chain.steps);
|
|
43
|
-
}
|
|
44
|
-
return ordered.length === 0
|
|
45
|
-
? { kind: "no-op" }
|
|
46
|
-
: {
|
|
47
|
-
kind: "runnable",
|
|
48
|
-
path: ordered.some(({ transition }) => transition === "offline-migration")
|
|
49
|
-
? "offline-migration"
|
|
50
|
-
: "compatible",
|
|
51
|
-
steps: ordered
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function planScalarAxis(registry, axis, from, to) {
|
|
55
|
-
return planChain(registry, axis, undefined, from, to);
|
|
56
|
-
}
|
|
57
|
-
function planRecordFamily(registry, recordKind, from, to) {
|
|
58
|
-
return planChain(registry, "record", recordKind, from, to);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Resolve the adjacent step chain that advances one axis from `from` to `to`.
|
|
62
|
-
* A source newer than supported is `future-version`; a gap with no registered
|
|
63
|
-
* adjacent step is `missing-step`. Both carry a precise reason and action.
|
|
64
|
-
*/
|
|
65
|
-
function planChain(registry, axis, recordKind, from, to) {
|
|
66
|
-
const label = axisLabel(axis, recordKind);
|
|
67
|
-
if (from > to) {
|
|
68
|
-
return {
|
|
69
|
-
kind: "blocked",
|
|
70
|
-
blocker: {
|
|
71
|
-
reason: "future-version",
|
|
72
|
-
axis,
|
|
73
|
-
...(recordKind ? { recordKind } : {}),
|
|
74
|
-
found: from,
|
|
75
|
-
supported: to,
|
|
76
|
-
message: `${label} version ${from} is newer than this release supports (${to}).`,
|
|
77
|
-
action: "Upgrade to a newer Yui release that understands this version."
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
const steps = [];
|
|
82
|
-
for (let version = from; version < to; version += 1) {
|
|
83
|
-
const declaration = registry.lookupDeclaration(axis, recordKind, version);
|
|
84
|
-
const registeredStep = registry.lookup(axis, recordKind, version);
|
|
85
|
-
if (declaration === undefined && registeredStep !== undefined) {
|
|
86
|
-
return {
|
|
87
|
-
kind: "blocked",
|
|
88
|
-
blocker: {
|
|
89
|
-
reason: "missing-declaration",
|
|
90
|
-
axis,
|
|
91
|
-
...(recordKind ? { recordKind } : {}),
|
|
92
|
-
from: version,
|
|
93
|
-
to: version + 1,
|
|
94
|
-
message: `No compatible/offline-migration declaration is registered for ` +
|
|
95
|
-
`${label} ${version}->${version + 1}.`,
|
|
96
|
-
action: "Declare the adjacent change explicitly; do not infer compatibility from its version."
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
if (declaration === undefined) {
|
|
101
|
-
return {
|
|
102
|
-
kind: "blocked",
|
|
103
|
-
blocker: {
|
|
104
|
-
reason: "missing-step",
|
|
105
|
-
axis,
|
|
106
|
-
...(recordKind ? { recordKind } : {}),
|
|
107
|
-
from: version,
|
|
108
|
-
to: version + 1,
|
|
109
|
-
message: `No migration step is registered for ${label} ${version}->${version + 1}.`,
|
|
110
|
-
action: "This version cannot be migrated by this release; a newer release must provide the step."
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
const step = declaration.kind === "compatible"
|
|
115
|
-
? {
|
|
116
|
-
axis,
|
|
117
|
-
...(recordKind ? { recordKind } : {}),
|
|
118
|
-
fromVersion: version,
|
|
119
|
-
toVersion: version + 1,
|
|
120
|
-
preconditions: declaration.validateSource,
|
|
121
|
-
transform: declaration.normalize,
|
|
122
|
-
declaredEffects: []
|
|
123
|
-
}
|
|
124
|
-
: registeredStep;
|
|
125
|
-
if (step === undefined) {
|
|
126
|
-
return {
|
|
127
|
-
kind: "blocked",
|
|
128
|
-
blocker: {
|
|
129
|
-
reason: "missing-step",
|
|
130
|
-
axis,
|
|
131
|
-
...(recordKind ? { recordKind } : {}),
|
|
132
|
-
from: version,
|
|
133
|
-
to: version + 1,
|
|
134
|
-
message: `No migration step is registered for ${label} ${version}->${version + 1}.`,
|
|
135
|
-
action: "This offline transition cannot run until this release provides its migration step."
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
steps.push({
|
|
140
|
-
axis,
|
|
141
|
-
...(recordKind ? { recordKind } : {}),
|
|
142
|
-
fromVersion: version,
|
|
143
|
-
toVersion: version + 1,
|
|
144
|
-
transition: declaration.kind,
|
|
145
|
-
step
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
return { kind: "ok", steps };
|
|
149
|
-
}
|
|
150
|
-
function axisLabel(axis, recordKind) {
|
|
151
|
-
if (axis === "record")
|
|
152
|
-
return `record family '${recordKind ?? "?"}'`;
|
|
153
|
-
return axis === "layout" ? "storage layout" : "aggregate schema";
|
|
154
|
-
}
|