@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,367 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { join, resolve } from "node:path";
3
- import { requireIdentity, requireTimestamp } from "../domain/validation.js";
4
- import { readActiveReleasePointer, readHandoverFence, readHandoverReceipt, releaseDirectoryName, releasesDirectory, verifyReleaseIntegrity } from "../release/runtimeRelease.js";
5
- import { exactControlPlaneDigest, parseExactControlPlaneDescriptor } from "../runtime/exactControlPlane.js";
6
- import { createTaskFinalReviewContract, sameTaskFinalReviewContract, validateTaskFinalReviewContract } from "./taskFinalReviewContract.js";
7
- import { governingWorkItemCandidate } from "../workItem/workItem.js";
8
- import { TASK_FINAL_REVIEW_CONTRACT_REBOUND_EVENT } from "./taskFinalReviewContractEvent.js";
9
- export { TASK_FINAL_REVIEW_CONTRACT_REBOUND_EVENT } from "./taskFinalReviewContractEvent.js";
10
- /**
11
- * Resolves the effective Task-final Review contract from its immutable Task
12
- * records. Mutation and read-model callers share this adapter so a legal
13
- * release rebind cannot be interpreted differently by the two paths.
14
- */
15
- export function resolveRecordedTaskFinalReviewContract(taskId, workItems, reviewRounds, events) {
16
- const candidateObservations = workItems.flatMap((item) => {
17
- const candidate = governingWorkItemCandidate(item);
18
- return candidate?.taskFinalReviewContract === undefined
19
- ? []
20
- : [{
21
- contract: candidate.taskFinalReviewContract,
22
- createdAt: candidate.createdAt,
23
- source: `Candidate ${item.id}/${candidate.id}`
24
- }];
25
- });
26
- const historicalCandidateObservations = workItems.flatMap((item) => (item.candidates
27
- .filter((candidate) => candidate.taskFinalReviewContract !== undefined)
28
- .map((candidate) => ({
29
- contract: candidate.taskFinalReviewContract,
30
- createdAt: candidate.createdAt,
31
- source: `Historical Candidate ${item.id}/${candidate.id}`
32
- }))));
33
- const reviewObservations = reviewRounds.flatMap((round) => ((round.scope ?? "work-item") !== "task"
34
- || round.taskFinalReviewContract === undefined
35
- ? []
36
- : [{
37
- contract: round.taskFinalReviewContract,
38
- createdAt: round.createdAt,
39
- source: `ReviewRound ${round.id}`
40
- }]));
41
- return resolveTaskFinalReviewContract(taskId, [...candidateObservations, ...reviewObservations], events, historicalCandidateObservations);
42
- }
43
- export function createTaskFinalReviewContractRebind(input) {
44
- const taskId = requireIdentity(input.taskId, "Task final-review rebind Task id");
45
- const reviewerRoleName = requireIdentity(input.reviewerRoleName, "Task final-review rebind Reviewer Role");
46
- const fromContract = validateTaskFinalReviewContract(input.fromContract);
47
- if (fromContract.taskId !== taskId) {
48
- throw new Error("Task final-review rebind contract belongs to another Task.");
49
- }
50
- if (fromContract.reviewerRoleName !== reviewerRoleName) {
51
- throw new Error("Task final-review rebind changes the Reviewer identity.");
52
- }
53
- const toContract = createTaskFinalReviewContract({
54
- taskId,
55
- reviewerRoleName,
56
- controlPlaneDigest: requireDigest(input.toControlPlaneDigest, "Task final-review rebind target control-plane digest")
57
- });
58
- if (fromContract.controlPlaneDigest === toContract.controlPlaneDigest) {
59
- throw new Error("Task final-review rebind must change the control-plane digest.");
60
- }
61
- const fromRelease = validateReleaseIdentity(input.fromRelease, "source");
62
- const toRelease = validateReleaseIdentity(input.toRelease, "target");
63
- if (fromRelease.releaseId === toRelease.releaseId) {
64
- throw new Error("Task final-review rebind must cross an immutable release handover.");
65
- }
66
- return Object.freeze({
67
- schemaVersion: 1,
68
- taskId,
69
- reviewerRoleName,
70
- fromContract,
71
- toContract,
72
- fromRelease,
73
- toRelease,
74
- handoverId: requireIdentity(input.handoverId, "Task final-review rebind handover id"),
75
- authorizedBy: requireText(input.authorizedBy, "Task final-review rebind authorizer")
76
- });
77
- }
78
- export function taskFinalReviewContractRebindPayload(rebind) {
79
- const validated = createTaskFinalReviewContractRebind({
80
- ...rebind,
81
- toControlPlaneDigest: rebind.toContract.controlPlaneDigest
82
- });
83
- return {
84
- schemaVersion: "1",
85
- taskId: validated.taskId,
86
- reviewerRoleName: validated.reviewerRoleName,
87
- fromContractDigest: validated.fromContract.digest,
88
- toContractDigest: validated.toContract.digest,
89
- fromControlPlaneDigest: validated.fromContract.controlPlaneDigest,
90
- toControlPlaneDigest: validated.toContract.controlPlaneDigest,
91
- fromReleaseId: validated.fromRelease.releaseId,
92
- fromReleaseVersion: validated.fromRelease.version,
93
- fromReleaseBuildId: validated.fromRelease.buildId,
94
- fromReleasePackageDigest: validated.fromRelease.packageDigest,
95
- ...(validated.fromRelease.sourceCommit === undefined
96
- ? {}
97
- : { fromReleaseSourceCommit: validated.fromRelease.sourceCommit }),
98
- toReleaseId: validated.toRelease.releaseId,
99
- toReleaseVersion: validated.toRelease.version,
100
- toReleaseBuildId: validated.toRelease.buildId,
101
- toReleasePackageDigest: validated.toRelease.packageDigest,
102
- ...(validated.toRelease.sourceCommit === undefined
103
- ? {}
104
- : { toReleaseSourceCommit: validated.toRelease.sourceCommit }),
105
- handoverId: validated.handoverId,
106
- authorizedBy: validated.authorizedBy
107
- };
108
- }
109
- export function taskFinalReviewContractRebindFromEvent(event) {
110
- if (event.type !== TASK_FINAL_REVIEW_CONTRACT_REBOUND_EVENT) {
111
- throw new Error(`Task event is not a final-review contract rebind: ${event.id}.`);
112
- }
113
- const payload = event.payload;
114
- if (payload.schemaVersion !== "1") {
115
- throw new Error(`Task final-review rebind event schema is invalid: ${event.id}.`);
116
- }
117
- if (payload.taskId !== event.taskId) {
118
- throw new Error(`Task final-review rebind event belongs to another Task: ${event.id}.`);
119
- }
120
- const fromContract = createTaskFinalReviewContract({
121
- taskId: payload.taskId,
122
- reviewerRoleName: payload.reviewerRoleName,
123
- controlPlaneDigest: payload.fromControlPlaneDigest
124
- });
125
- if (fromContract.digest !== payload.fromContractDigest) {
126
- throw new Error(`Task final-review rebind source digest is invalid: ${event.id}.`);
127
- }
128
- const rebind = createTaskFinalReviewContractRebind({
129
- taskId: payload.taskId,
130
- reviewerRoleName: payload.reviewerRoleName,
131
- fromContract,
132
- toControlPlaneDigest: payload.toControlPlaneDigest,
133
- fromRelease: releaseIdentityFromPayload(payload, "from"),
134
- toRelease: releaseIdentityFromPayload(payload, "to"),
135
- handoverId: payload.handoverId,
136
- authorizedBy: payload.authorizedBy
137
- });
138
- if (rebind.toContract.digest !== payload.toContractDigest) {
139
- throw new Error(`Task final-review rebind target digest is invalid: ${event.id}.`);
140
- }
141
- return rebind;
142
- }
143
- /**
144
- * Historical Candidate and Review records remain immutable. Before the first
145
- * explicit rebind event, older Yui releases may have emitted successive
146
- * control-plane contracts without a rebind event. Preserve that legacy prefix
147
- * as a forward-only sequence, then require one strict append-only rebind chain.
148
- * Any Reviewer change, reversion, fork, or post-rebind drift fails closed.
149
- */
150
- export function resolveTaskFinalReviewContract(taskId, observations, events, historicalObservations = []) {
151
- const normalizedTaskId = requireIdentity(taskId, "Task final-review contract Task id");
152
- const orderedObservations = [...observations]
153
- .map((observation) => ({
154
- contract: validateTaskFinalReviewContract(observation.contract),
155
- createdAt: requireTimestamp(observation.createdAt, "Task final-review observation createdAt"),
156
- source: requireText(observation.source, "Task final-review observation source")
157
- }))
158
- .sort(compareCreatedAt);
159
- const orderedHistoricalObservations = [...historicalObservations]
160
- .map((observation) => ({
161
- contract: validateTaskFinalReviewContract(observation.contract),
162
- createdAt: requireTimestamp(observation.createdAt, "Task final-review historical observation createdAt"),
163
- source: requireText(observation.source, "Task final-review historical observation source")
164
- }))
165
- .sort(compareCreatedAt);
166
- const orderedEvents = events
167
- .filter(({ type }) => type === TASK_FINAL_REVIEW_CONTRACT_REBOUND_EVENT)
168
- .map((event) => ({
169
- event,
170
- createdAt: requireTimestamp(event.createdAt, "Task final-review rebind event createdAt"),
171
- rebind: taskFinalReviewContractRebindFromEvent(event)
172
- }))
173
- .sort((left, right) => compareCreatedAt(left, right)
174
- || left.event.id.localeCompare(right.event.id, undefined, { numeric: true }));
175
- if (orderedObservations.length === 0 && orderedEvents.length === 0)
176
- return undefined;
177
- for (const observation of [...orderedObservations, ...orderedHistoricalObservations]) {
178
- if (observation.contract.taskId !== normalizedTaskId) {
179
- throw new Error(`${observation.source} carries a final-review contract for another Task.`);
180
- }
181
- }
182
- const firstRebindAt = orderedEvents[0]?.createdAt;
183
- const primaryLegacyObservations = firstRebindAt === undefined
184
- ? orderedObservations
185
- : orderedObservations.filter(({ createdAt }) => createdAt < firstRebindAt);
186
- const historicalRebindSource = orderedEvents[0] === undefined
187
- ? undefined
188
- : orderedHistoricalObservations.find((observation) => (observation.createdAt < orderedEvents[0].createdAt
189
- && sameTaskFinalReviewContract(observation.contract, orderedEvents[0].rebind.fromContract)));
190
- const legacyObservations = primaryLegacyObservations.length > 0
191
- ? primaryLegacyObservations
192
- : historicalRebindSource === undefined ? [] : [historicalRebindSource];
193
- if (legacyObservations.length === 0) {
194
- throw new Error(`Task ${normalizedTaskId} has a final-review rebind without an established source contract.`);
195
- }
196
- const initial = legacyObservations[0].contract;
197
- const reviewerRoleName = initial.reviewerRoleName;
198
- let effective = initial;
199
- const legacyContractDigests = new Set([initial.digest]);
200
- for (const observation of legacyObservations) {
201
- if (observation.contract.reviewerRoleName !== reviewerRoleName) {
202
- throw new Error(`${observation.source} changes the Task final-review Reviewer identity.`);
203
- }
204
- if (sameTaskFinalReviewContract(observation.contract, effective))
205
- continue;
206
- if (legacyContractDigests.has(observation.contract.digest)) {
207
- throw new Error(`${observation.source} reverts a legacy Task final-review contract.`);
208
- }
209
- legacyContractDigests.add(observation.contract.digest);
210
- effective = observation.contract;
211
- }
212
- for (const entry of orderedEvents) {
213
- const { rebind } = entry;
214
- if (!sameTaskFinalReviewContract(effective, rebind.fromContract)) {
215
- throw new Error(`Task final-review rebind chain forks at ${entry.event.id}.`);
216
- }
217
- if (rebind.reviewerRoleName !== initial.reviewerRoleName) {
218
- throw new Error(`Task final-review rebind changes Reviewer identity at ${entry.event.id}.`);
219
- }
220
- effective = rebind.toContract;
221
- }
222
- for (const observation of orderedObservations) {
223
- if (firstRebindAt === undefined || observation.createdAt < firstRebindAt)
224
- continue;
225
- let expected = legacyObservations.at(-1).contract;
226
- for (const entry of orderedEvents) {
227
- if (entry.createdAt > observation.createdAt)
228
- break;
229
- expected = entry.rebind.toContract;
230
- }
231
- if (!sameTaskFinalReviewContract(observation.contract, expected)) {
232
- throw new Error(`${observation.source} does not match the effective Task final-review contract at creation.`);
233
- }
234
- }
235
- return Object.freeze({
236
- initial,
237
- effective,
238
- rebinds: Object.freeze(orderedEvents.map(({ rebind }) => rebind))
239
- });
240
- }
241
- /**
242
- * Builds the immutable release proof while the caller holds the release
243
- * handover lock. The current exact control descriptor is supplied only by the
244
- * CLI preflight; caller-provided target identities are checked against it.
245
- */
246
- export function prepareTaskFinalReviewContractRebindProof(input) {
247
- const home = resolve(input.home);
248
- const taskId = requireIdentity(input.taskId, "Task final-review rebind Task id");
249
- const fromControlPlaneDigest = requireDigest(input.fromControlPlaneDigest, "Task final-review rebind source control-plane digest");
250
- const toControlPlaneDigest = requireDigest(input.toControlPlaneDigest, "Task final-review rebind target control-plane digest");
251
- if (fromControlPlaneDigest === toControlPlaneDigest) {
252
- throw new Error("Task final-review rebind source and target control planes are identical.");
253
- }
254
- if (exactControlPlaneDigest(input.currentControlPlane) !== toControlPlaneDigest) {
255
- throw new Error("Task final-review rebind target is not the current exact control plane.");
256
- }
257
- if (resolve(input.currentControlPlane.yuiHome) !== home) {
258
- throw new Error("Task final-review rebind target control plane belongs to another Home.");
259
- }
260
- const fromReleaseId = requireText(input.fromReleaseId, "Source release id");
261
- const toReleaseId = requireText(input.toReleaseId, "Target release id");
262
- if (fromReleaseId === toReleaseId) {
263
- throw new Error("Task final-review rebind source and target releases are identical.");
264
- }
265
- if (readHandoverFence(home) !== null) {
266
- throw new Error("Task final-review rebind is blocked by an unfinished release handover.");
267
- }
268
- const active = readActiveReleasePointer(home);
269
- if (active === null
270
- || active.releaseId !== toReleaseId
271
- || active.buildId !== input.currentControlPlane.buildId
272
- || active.packageDigest !== input.currentControlPlane.activeReleaseDigest) {
273
- throw new Error("The active release does not match the requested target release and exact control plane.");
274
- }
275
- const sourcePath = join(home, "runtime", "control-plane", `${fromControlPlaneDigest}.json`);
276
- const sourceControl = parseExactControlPlaneDescriptor(readFileSync(sourcePath, "utf8"));
277
- if (exactControlPlaneDigest(sourceControl) !== fromControlPlaneDigest) {
278
- throw new Error("Task final-review rebind source control-plane descriptor digest is invalid.");
279
- }
280
- if (resolve(sourceControl.yuiHome) !== home) {
281
- throw new Error("Task final-review rebind source control plane belongs to another Home.");
282
- }
283
- const fromRelease = installedReleaseIdentity(home, fromReleaseId, sourceControl, "source");
284
- const toRelease = installedReleaseIdentity(home, toReleaseId, input.currentControlPlane, "target");
285
- const handover = readHandoverReceipt(home);
286
- if (handover === null
287
- || handover.outcome !== "completed"
288
- || handover.activatedReleaseId !== toReleaseId
289
- || typeof handover.handoverId !== "string"
290
- || handover.handoverId.length === 0) {
291
- throw new Error("Task final-review rebind requires the completed release handover that activated the target.");
292
- }
293
- return Object.freeze({
294
- schemaVersion: 1,
295
- taskId,
296
- fromControlPlaneDigest,
297
- toControlPlaneDigest,
298
- fromRelease,
299
- toRelease,
300
- handoverId: handover.handoverId
301
- });
302
- }
303
- function installedReleaseIdentity(home, releaseId, control, label) {
304
- if (control.buildId === undefined || control.activeReleaseDigest === undefined) {
305
- throw new Error(`Task final-review rebind ${label} control plane is not an immutable release.`);
306
- }
307
- let manifest;
308
- try {
309
- manifest = verifyReleaseIntegrity(join(releasesDirectory(home), releaseId));
310
- }
311
- catch (error) {
312
- throw new Error(`Task final-review rebind ${label} release is unknown or invalid: ${releaseId}.`, { cause: error });
313
- }
314
- if (releaseDirectoryName(manifest) !== releaseId
315
- || manifest.buildId !== control.buildId
316
- || manifest.packageDigest !== control.activeReleaseDigest) {
317
- throw new Error(`Task final-review rebind ${label} release does not match its control plane.`);
318
- }
319
- return validateReleaseIdentity({
320
- releaseId,
321
- version: manifest.version,
322
- buildId: manifest.buildId,
323
- packageDigest: manifest.packageDigest,
324
- ...(manifest.sourceCommit === undefined ? {} : { sourceCommit: manifest.sourceCommit })
325
- }, label);
326
- }
327
- function releaseIdentityFromPayload(payload, prefix) {
328
- const title = prefix === "from" ? "From" : "To";
329
- return validateReleaseIdentity({
330
- releaseId: payload[`${prefix}ReleaseId`],
331
- version: payload[`${prefix}ReleaseVersion`],
332
- buildId: payload[`${prefix}ReleaseBuildId`],
333
- packageDigest: payload[`${prefix}ReleasePackageDigest`],
334
- ...(payload[`${prefix}ReleaseSourceCommit`] === undefined
335
- ? {}
336
- : { sourceCommit: payload[`${prefix}ReleaseSourceCommit`] })
337
- }, title);
338
- }
339
- function validateReleaseIdentity(value, label) {
340
- return Object.freeze({
341
- releaseId: requireText(value.releaseId, `Task final-review rebind ${label} release id`),
342
- version: requireText(value.version, `Task final-review rebind ${label} release version`),
343
- buildId: requireText(value.buildId, `Task final-review rebind ${label} release build id`),
344
- packageDigest: requireDigest(value.packageDigest, `Task final-review rebind ${label} release package digest`),
345
- ...(value.sourceCommit === undefined
346
- ? {}
347
- : { sourceCommit: requireText(value.sourceCommit, `Task final-review rebind ${label} source commit`) })
348
- });
349
- }
350
- function compareCreatedAt(left, right) {
351
- return left.createdAt.localeCompare(right.createdAt);
352
- }
353
- function requireDigest(value, label) {
354
- if (typeof value !== "string" || !/^[a-f0-9]{64}$/u.test(value)) {
355
- throw new Error(`${label} is invalid.`);
356
- }
357
- return value;
358
- }
359
- function requireText(value, label) {
360
- if (typeof value !== "string" || value.includes("\0")) {
361
- throw new Error(`${label} is invalid.`);
362
- }
363
- const normalized = value.trim();
364
- if (normalized.length === 0)
365
- throw new Error(`${label} is required.`);
366
- return normalized;
367
- }