@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.
Files changed (229) hide show
  1. package/ARCHITECTURE.md +69 -428
  2. package/README.md +108 -298
  3. package/dist/agent/managedRuntimeEnvironment.js +2 -2
  4. package/dist/cli/commandCatalog.js +39 -77
  5. package/dist/cli/interactionCandidates.js +4 -4
  6. package/dist/cli/interactionPolicy.js +7 -10
  7. package/dist/cli/invocationRouter.js +1 -1
  8. package/dist/cli/updateCommand.js +6 -27
  9. package/dist/cli/updateOrchestrator.js +63 -484
  10. package/dist/cli/updatePorts.js +15 -333
  11. package/dist/cli/upgradeCommand.js +8 -65
  12. package/dist/cli.js +57 -242
  13. package/dist/commands/configCommands.js +11 -62
  14. package/dist/commands/executionAuditCommands.js +23 -23
  15. package/dist/commands/globalRoleCommands.js +2 -7
  16. package/dist/commands/jobCommands.js +1 -4
  17. package/dist/commands/projectCommands.js +5 -5
  18. package/dist/commands/releaseCommands.js +3 -10
  19. package/dist/commands/resourcesCommands.js +2 -2
  20. package/dist/commands/sessionCommands.js +2 -2
  21. package/dist/commands/taskActor.js +31 -39
  22. package/dist/commands/taskChangeSetCommands.js +5 -12
  23. package/dist/commands/taskCommands.js +464 -1249
  24. package/dist/commands/taskContextCommand.js +35 -36
  25. package/dist/commands/taskExecutionCommands.js +33 -46
  26. package/dist/commands/taskInputCommands.js +20 -42
  27. package/dist/commands/taskNextActionCommand.js +9 -9
  28. package/dist/commands/taskOverviewCommand.js +56 -95
  29. package/dist/commands/taskRoleRuntimeStatus.js +77 -107
  30. package/dist/commands/taskUpstreamCommands.js +3 -3
  31. package/dist/commands/taskWorkspaceCommands.js +7 -79
  32. package/dist/commands/telemetryCommands.js +32 -124
  33. package/dist/commands/workflowCommands.js +3 -3
  34. package/dist/completion/fileCompletionManager.js +1 -1
  35. package/dist/config/configCatalog.js +4 -6
  36. package/dist/config/yuiConfig.js +6 -43
  37. package/dist/context/dispatchContext.js +14 -30
  38. package/dist/context/roleSessionContext.js +2 -2
  39. package/dist/context/sessionBootstrapManifest.js +2 -2
  40. package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
  41. package/dist/context/turnInputContract.js +204 -0
  42. package/dist/context/wakeNotification.js +2 -2
  43. package/dist/controller/agentRuntimeObserver.js +18 -18
  44. package/dist/controller/clientRuntime.js +13 -20
  45. package/dist/controller/controller.js +89 -116
  46. package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
  47. package/dist/controller/jobControl.js +17 -17
  48. package/dist/controller/resourceInventory.js +6 -6
  49. package/dist/controller/resourceInventoryLinux.js +38 -59
  50. package/dist/controller/resourceInventoryRpc.js +3 -3
  51. package/dist/controller/resourceInventoryWorker.js +1 -1
  52. package/dist/controller/runtime.js +46 -53
  53. package/dist/controller/runtimeEventInbox.js +23 -31
  54. package/dist/controller/runtimeEventProcessor.js +15 -15
  55. package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
  56. package/dist/controller/runtimeLaunchCoordinator.js +3 -3
  57. package/dist/controller/runtimeObservationHook.js +11 -8
  58. package/dist/controller/sessionNotify.js +11 -11
  59. package/dist/controller/structuredProviderObservation.js +89 -16
  60. package/dist/coordination/workMailbox.js +309 -579
  61. package/dist/coordination/workMailboxQueue.js +5 -6
  62. package/dist/core/controllerClient.js +1 -91
  63. package/dist/core/controllerServer.js +3 -6
  64. package/dist/doctor/doctor.js +51 -314
  65. package/dist/execution/candidateConvergence.js +3 -3
  66. package/dist/execution/executionGroup.js +32 -33
  67. package/dist/execution/executionHealth.js +36 -38
  68. package/dist/execution/resourceBroker.js +12 -12
  69. package/dist/executor/agentExecutor.js +30 -265
  70. package/dist/executor/effectiveLaunch.js +9 -19
  71. package/dist/executor/executorRegistry.js +43 -17
  72. package/dist/executor/fileRoleLaunchPlanner.js +56 -56
  73. package/dist/executor/launchPlan.js +3 -3
  74. package/dist/executor/workspacePreflightClassification.js +16 -16
  75. package/dist/grant/capabilityGrant.js +20 -25
  76. package/dist/input/inputRequest.js +12 -12
  77. package/dist/integration/changeSet.js +9 -13
  78. package/dist/integration/changeSetManifest.js +1 -1
  79. package/dist/integration/gitIntegrationService.js +2 -2
  80. package/dist/integration/integrationQueueService.js +5 -21
  81. package/dist/integration/overlapDiagnostics.js +2 -2
  82. package/dist/interaction/operatorPresentation.js +1 -1
  83. package/dist/job/jobRunner.js +1 -1
  84. package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
  85. package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
  86. package/dist/message/message.js +6 -6
  87. package/dist/observability/executionAudit.js +74 -86
  88. package/dist/observability/faultClassification.js +7 -24
  89. package/dist/observability/orchestrationMetrics.js +5 -5
  90. package/dist/observability/runtimeIdentity.js +34 -101
  91. package/dist/profile/agentProfile.js +1 -1
  92. package/dist/release/cliHomeReleaseFence.js +3 -3
  93. package/dist/release/releaseWorkflowEngine.js +6 -10
  94. package/dist/release/releaseWorkflowPorts.js +2 -2
  95. package/dist/release/workflowFileLock.js +1 -1
  96. package/dist/repository/checkoutSwap.js +1 -1
  97. package/dist/repository/gitWorkspace.js +0 -13
  98. package/dist/repository/project.js +1 -1
  99. package/dist/repository/projectMaintenanceLock.js +1 -2
  100. package/dist/repository/taskBaseFreshness.js +13 -13
  101. package/dist/repository/taskWorkspaceCoordinator.js +21 -25
  102. package/dist/repository/taskWorkspaceIdentity.js +8 -21
  103. package/dist/repository/taskWorkspacePreparer.js +63 -620
  104. package/dist/resources/autoResourceGc.js +3 -3
  105. package/dist/resources/liveReferences.js +1 -1
  106. package/dist/resources/resourceGc.js +1 -1
  107. package/dist/resources/sqliteResourceRegistry.js +1 -1
  108. package/dist/review/reviewDecision.js +7 -7
  109. package/dist/review/reviewFindingLedger.js +1 -1
  110. package/dist/review/reviewOutcomeClassifier.js +35 -50
  111. package/dist/review/reviewRound.js +14 -25
  112. package/dist/review/reviewerAvailability.js +4 -4
  113. package/dist/review/taskFinalReviewContractResolution.js +41 -0
  114. package/dist/role/role.js +6 -3
  115. package/dist/runtime/agentDriver.js +4 -0
  116. package/dist/runtime/agentHost.js +151 -36
  117. package/dist/runtime/builtinAgentDrivers.js +79 -2
  118. package/dist/runtime/codexAppServerRuntime.js +122 -0
  119. package/dist/runtime/continuationManager.js +3 -5
  120. package/dist/runtime/exactControlPlane.js +17 -42
  121. package/dist/runtime/firstProgressAdvisory.js +1 -1
  122. package/dist/runtime/index.js +2 -2
  123. package/dist/runtime/launchDiagnostics.js +2 -2
  124. package/dist/runtime/lifecycleReservation.js +4 -4
  125. package/dist/runtime/processExitObservation.js +1 -1
  126. package/dist/runtime/processExitOutbox.js +0 -32
  127. package/dist/runtime/promptEnvelope.js +9 -9
  128. package/dist/runtime/providerContinuation.js +2 -2
  129. package/dist/runtime/providerContinuationReconciliationService.js +2 -2
  130. package/dist/runtime/providerRuntimeIdentity.js +76 -24
  131. package/dist/runtime/recentTurnIds.js +38 -0
  132. package/dist/runtime/runtimeContinuationProjection.js +2 -2
  133. package/dist/runtime/runtimeHealthPolicy.js +1 -1
  134. package/dist/runtime/runtimeObservation.js +58 -21
  135. package/dist/runtime/runtimeProjection.js +19 -27
  136. package/dist/runtime/sessionLaunchRequest.js +2 -2
  137. package/dist/runtime/structuredProviderHost.js +177 -12
  138. package/dist/runtime/tmuxAdapters.js +46 -11
  139. package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
  140. package/dist/scheduler/leaderWakeupProcessor.js +147 -445
  141. package/dist/scheduler/operatorEvent.js +4 -6
  142. package/dist/scheduler/resourceQueueProjection.js +71 -0
  143. package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
  144. package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
  145. package/dist/scheduler/taskExecutionProjection.js +99 -99
  146. package/dist/scheduler/taskObservabilityProjection.js +10 -10
  147. package/dist/scheduler/taskWake.js +4 -4
  148. package/dist/scheduler/wakeReason.js +6 -10
  149. package/dist/scheduler/wakeupQueue.js +0 -9
  150. package/dist/setup/setupCommand.js +2 -2
  151. package/dist/storage/currentTaskStore.js +46 -0
  152. package/dist/storage/persistenceWorker.js +1 -1
  153. package/dist/storage/sqliteSchema.js +81 -485
  154. package/dist/storage/sqliteStore.js +206 -365
  155. package/dist/storage/storageSchema.js +1 -15
  156. package/dist/storage/storageVersions.js +8 -9
  157. package/dist/storage/storeRpc.js +10 -34
  158. package/dist/storage/taskStore.js +63 -3415
  159. package/dist/storage/upgrade/recordVersions.js +55 -149
  160. package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
  161. package/dist/task/completionReadiness.js +5 -5
  162. package/dist/task/deliveryGuard.js +10 -10
  163. package/dist/task/nextAction.js +74 -77
  164. package/dist/task/task.js +2 -4
  165. package/dist/task/taskRecordReference.js +3 -3
  166. package/dist/task/taskRecordRetirement.js +1 -1
  167. package/dist/telemetry/sqliteTelemetryStore.js +53 -53
  168. package/dist/telemetry/telemetryConfig.js +14 -14
  169. package/dist/telemetry/telemetryWiring.js +8 -14
  170. package/dist/turn/turn.js +356 -0
  171. package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
  172. package/dist/verification/gateArtifactStore.js +2 -2
  173. package/dist/web/assets/client/app.js +1 -1
  174. package/dist/web/assets/client/components.js +29 -54
  175. package/dist/web/assets/client/i18n.js +17 -37
  176. package/dist/web/assets/client/view.js +37 -37
  177. package/dist/web/assets/shell.js +1 -1
  178. package/dist/web/assets/styles/cards.js +5 -5
  179. package/dist/web/assets/styles/widgets.js +1 -2
  180. package/dist/web/webSnapshot.js +65 -60
  181. package/dist/workItem/workItem.js +11 -11
  182. package/dist/workspace/workItemChangeSetManager.js +1 -1
  183. package/docs/task-local-identity.md +5 -5
  184. package/i18n/README.zh-CN.md +41 -54
  185. package/package.json +1 -1
  186. package/skills/yui-leader/SKILL.md +85 -83
  187. package/skills/yui-operator/SKILL.md +16 -16
  188. package/skills/yui-reviewer/SKILL.md +10 -10
  189. package/skills/yui-runtime/SKILL.md +17 -18
  190. package/skills/yui-worker/SKILL.md +16 -18
  191. package/dist/context/runContextContract.js +0 -162
  192. package/dist/executor/turnCompletion.js +0 -126
  193. package/dist/review/taskFinalReviewContractEvent.js +0 -1
  194. package/dist/review/taskFinalReviewContractRebind.js +0 -367
  195. package/dist/run/agentRun.js +0 -356
  196. package/dist/run/rejectedYieldAttempt.js +0 -221
  197. package/dist/run/runControlRequest.js +0 -50
  198. package/dist/run/yieldReceipt.js +0 -65
  199. package/dist/runtime/turnCompletion.js +0 -3
  200. package/dist/scheduler/actionability.js +0 -323
  201. package/dist/scheduler/activeRoleRunDelivery.js +0 -868
  202. package/dist/scheduler/activeTaskProgress.js +0 -126
  203. package/dist/storage/compatibleTaskStore.js +0 -248
  204. package/dist/storage/migration/baseline.js +0 -78
  205. package/dist/storage/migration/classifier.js +0 -51
  206. package/dist/storage/migration/compatibleCodec.js +0 -53
  207. package/dist/storage/migration/engine.js +0 -147
  208. package/dist/storage/migration/index.js +0 -33
  209. package/dist/storage/migration/planner.js +0 -154
  210. package/dist/storage/migration/productionRegistry.js +0 -3931
  211. package/dist/storage/migration/registry.js +0 -169
  212. package/dist/storage/migration/report.js +0 -54
  213. package/dist/storage/migration/types.js +0 -31
  214. package/dist/storage/upgrade/homeClassification.js +0 -353
  215. package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
  216. package/dist/storage/upgrade/migrationReceipt.js +0 -67
  217. package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
  218. package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
  219. package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
  220. package/dist/storage/upgrade/recordVersionScan.js +0 -176
  221. package/dist/storage/upgrade/sqliteFileSet.js +0 -50
  222. package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
  223. package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
  224. package/dist/storage/upgrade/sqliteStateMigration.js +0 -918
  225. package/dist/storage/upgrade/switchProgress.js +0 -80
  226. package/dist/storage/upgrade/upgradeReceipt.js +0 -161
  227. package/dist/storage/upgradeCoordination.js +0 -187
  228. package/dist/storage/upgradeFence.js +0 -366
  229. 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
- }