@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
@@ -97,7 +97,7 @@ export class FileRoleLaunchPlanner {
97
97
  || role === null) {
98
98
  throw new Error(`Task runtime is not current: ${input.taskId}/${input.roleName}.`);
99
99
  }
100
- const run = this.store.getActiveAgentRun(input.taskId, input.roleName);
100
+ const run = this.store.getActiveTurn(input.taskId, input.roleName);
101
101
  const sessions = this.store.getTaskRoleSessionSet(input.taskId, input.roleName);
102
102
  const session = sessions?.sessions[role.activeAgentId];
103
103
  if (session === undefined || session.launchId === undefined) {
@@ -111,11 +111,11 @@ export class FileRoleLaunchPlanner {
111
111
  agentId: session.agentId,
112
112
  adapterId: session.adapterId,
113
113
  workspace: effective.workspace.root,
114
- ...(run === null ? {} : { runId: run.id }),
114
+ ...(run === null ? {} : { turnId: run.id }),
115
115
  launchId: session.launchId,
116
116
  nativeSessionId: session.nativeSessionId
117
117
  });
118
- if (descriptor.runId !== input.runId
118
+ if (descriptor.turnId !== input.turnId
119
119
  || descriptor.launchId !== input.launchId
120
120
  || descriptor.nativeSessionId !== input.nativeSessionId
121
121
  || descriptor.agentId !== input.agentId
@@ -140,22 +140,22 @@ export class FileRoleLaunchPlanner {
140
140
  const role = this.store.getRole(input.taskId, input.roleName);
141
141
  if (role === null)
142
142
  throw new Error(`Role not found: ${input.taskId}/${input.roleName}.`);
143
- const activeRun = this.store.getActiveAgentRun(task.id, role.name);
144
- if (input.runId !== undefined && activeRun?.id !== input.runId) {
145
- throw new Error(`Role Run is no longer current: ${input.runId}.`);
143
+ const activeTurn = this.store.getActiveTurn(task.id, role.name);
144
+ if (input.turnId !== undefined && activeTurn?.id !== input.turnId) {
145
+ throw new Error(`Role Turn is no longer current: ${input.turnId}.`);
146
146
  }
147
- const runWorkspace = activeRun?.workspace;
147
+ const runWorkspace = activeTurn?.workspace;
148
148
  const main = this.store.getTaskWorkspace(task.id);
149
149
  // Quick Win (EXE-04/EXE-08): classify workspace preflight failures so
150
150
  // split-brain state is never reported as a transient Provider failure.
151
- const preflight = classifyWorkspacePreflight(this.store, task, input.roleName, activeRun === null ? null : { id: activeRun.id, workspace: activeRun.workspace }, this.#inspectWorkspacePhysicalState);
151
+ const preflight = classifyWorkspacePreflight(this.store, task, input.roleName, activeTurn === null ? null : { id: activeTurn.id, workspace: activeTurn.workspace }, this.#inspectWorkspacePhysicalState);
152
152
  if (preflight !== null) {
153
153
  throw new Error(formatWorkspacePreflightError(preflight));
154
154
  }
155
155
  const assignedWorkItem = this.store.listWorkItems(task.id).find((item) => item.assignee === role.name
156
156
  && !["completed", "failed", "retired"].includes(item.status));
157
- // A Run snapshot is authoritative for the live launch. In particular,
158
- // a reviewer Run must launch from its ReviewRound-owned workspace rather
157
+ // A Turn snapshot is authoritative for the live launch. In particular,
158
+ // a Reviewer Turn must launch from its ReviewRound-owned workspace rather
159
159
  // than falling back to the WorkItem Develop workspace. Without an
160
160
  // active snapshot, resolve the normal Role/WorkItem assignment.
161
161
  const workspace = runWorkspace !== undefined
@@ -183,8 +183,8 @@ export class FileRoleLaunchPlanner {
183
183
  && isolatedWorkItem !== null
184
184
  && (isolatedWorkItem.assignee === undefined || isolatedWorkItem.assignee === role.name)
185
185
  && !["completed", "failed", "retired"].includes(isolatedWorkItem.status)
186
- && (activeRun === null
187
- || activeRun.workItemId === workspace.owner.workItemId)
186
+ && (activeTurn === null
187
+ || activeTurn.workItemId === workspace.owner.workItemId)
188
188
  && sameWorkspaceProjects(workspace, task.projectBindings.map(({ projectId }) => projectId))
189
189
  && sameWritableProjects(workspace, isolatedWorkItem.writeProjectIds);
190
190
  const runScoped = runWorkspace !== undefined
@@ -192,29 +192,29 @@ export class FileRoleLaunchPlanner {
192
192
  && sameWorkspaceProjects(runWorkspace, task.projectBindings.map(({ projectId }) => projectId))
193
193
  && (runWorkspace.owner.type === "task"
194
194
  || (runWorkspace.owner.type === "work-item"
195
- && runWorkspace.owner.workItemId === activeRun?.workItemId)
195
+ && runWorkspace.owner.workItemId === activeTurn?.workItemId)
196
196
  || (runWorkspace.owner.type === "review-round"
197
- && activeRun?.purpose === "review"
198
- && runWorkspace.owner.reviewRoundId === activeRun.reviewRoundId)
197
+ && activeTurn?.purpose === "review"
198
+ && runWorkspace.owner.reviewRoundId === activeTurn.reviewRoundId)
199
199
  || (runWorkspace.owner.type === "execution-lane"
200
- && runWorkspace.owner.executionGroupId === activeRun?.executionGroupId
201
- && runWorkspace.owner.executionLaneId === activeRun?.executionLaneId
202
- && ((runWorkspace.owner.purpose === "review" && activeRun?.purpose === "review")
203
- || (runWorkspace.owner.purpose === "execution" && activeRun?.purpose === "execution"))));
200
+ && runWorkspace.owner.executionGroupId === activeTurn?.executionGroupId
201
+ && runWorkspace.owner.executionLaneId === activeTurn?.executionLaneId
202
+ && ((runWorkspace.owner.purpose === "review" && activeTurn?.purpose === "review")
203
+ || (runWorkspace.owner.purpose === "execution" && activeTurn?.purpose === "execution"))));
204
204
  if (!runScoped && !sharedMain && !isolated) {
205
205
  throw new Error(`Role workspace is not ready: ${input.taskId}/${input.roleName}.`);
206
206
  }
207
207
  }
208
208
  const sessionSet = this.store.getTaskRoleSessionSet(task.id, role.name);
209
- const resolvedEffective = activeRun?.effective
209
+ const resolvedEffective = activeTurn?.effective
210
210
  ?? activeLiveRoleAgentSession(sessionSet)?.effective
211
211
  ?? resolveTaskRoleEffectiveLaunch(this.store, role);
212
212
  if (input.effective !== undefined
213
213
  && !isDeepStrictEqual(resolvedEffective, input.effective)) {
214
- throw new Error(`Role launch effective Run snapshot changed: ${input.taskId}/${input.roleName}.`);
214
+ throw new Error(`Role launch effective Turn snapshot changed: ${input.taskId}/${input.roleName}.`);
215
215
  }
216
- if (activeRun !== null && input.effective === undefined) {
217
- throw new Error(`Role launch is missing the effective Run snapshot: ${input.taskId}/${input.roleName}.`);
216
+ if (activeTurn !== null && input.effective === undefined) {
217
+ throw new Error(`Role launch is missing the effective Turn snapshot: ${input.taskId}/${input.roleName}.`);
218
218
  }
219
219
  const effective = input.effective ?? resolvedEffective;
220
220
  const existing = sessionSet?.sessions[effective.agentId];
@@ -230,7 +230,7 @@ export class FileRoleLaunchPlanner {
230
230
  throw new Error(`Task Role still has a live Session: ${task.id}/${role.name}.`);
231
231
  }
232
232
  return this.#compile(role, input, { scope: "task", taskId: task.id }, resolveTaskRoleSessionTitle(input.mode === "resume" ? existing?.title : undefined, task, role.name), input.mode === "resume" && compatibleExisting ? existing.nativeSessionId : undefined, runWorkspace, effective, {
233
- purpose: activeRun?.purpose ?? "execution"
233
+ purpose: activeTurn?.purpose ?? "execution"
234
234
  });
235
235
  }
236
236
  planGlobalRole(input) {
@@ -280,7 +280,7 @@ export class FileRoleLaunchPlanner {
280
280
  const adapter = resolveAgentAdapter(binding.adapterId);
281
281
  const effectiveWorkspace = effective.workspace.root;
282
282
  const agentWorkspace = nativeAgentWorkspace(effective.workspace);
283
- if (adapter.id === "codex" && (owner.scope !== "task" || input.runId === undefined)) {
283
+ if (adapter.id === "codex" && (owner.scope !== "task" || input.turnId === undefined)) {
284
284
  const codexConfig = inspectCodexLaunchConfig({
285
285
  environment: launchEnvironment,
286
286
  workspace: agentWorkspace,
@@ -325,21 +325,21 @@ export class FileRoleLaunchPlanner {
325
325
  sessionManifestDigest: bootstrap.manifest.digest,
326
326
  sessionCliPath: bootstrap.sessionCliPath
327
327
  };
328
- const managedRun = owner.scope === "task" && input.runId !== undefined
329
- ? this.store.getAgentRun(owner.taskId, input.runId)
328
+ const managedRun = owner.scope === "task" && input.turnId !== undefined
329
+ ? this.store.getTurn(owner.taskId, input.turnId)
330
330
  : null;
331
331
  const driver = builtinAgentDriverRegistry().require(builtinDriverIdForAdapter(configured.adapterId));
332
- if (owner.scope === "task" && input.runId !== undefined) {
332
+ if (owner.scope === "task" && input.turnId !== undefined) {
333
333
  const admission = managedRuntimeAdmission(driver.capabilities);
334
334
  if (!admission.admitted) {
335
- throw new Error(`Agent Driver ${driver.id} cannot host managed Runs; missing capabilities: `
335
+ throw new Error(`Agent Driver ${driver.id} cannot host managed Turns; missing capabilities: `
336
336
  + admission.missing.join(", "));
337
337
  }
338
338
  }
339
339
  const roleConfig = binding.config.adapterId === "claude"
340
340
  && owner.scope === "task"
341
- && input.runId !== undefined
342
- ? managedClaudeControlPlaneConfig(binding.config, owner.taskId, managedRun?.workItemId, input.runId)
341
+ && input.turnId !== undefined
342
+ ? managedClaudeControlPlaneConfig(binding.config, owner.taskId, managedRun?.workItemId, input.turnId)
343
343
  : binding.config;
344
344
  const effectiveConfig = withNativeProjectDirectories(roleConfig, nativeAdditionalDirectories(effective.workspace, agentWorkspace));
345
345
  const compileInput = {
@@ -356,18 +356,18 @@ export class FileRoleLaunchPlanner {
356
356
  }
357
357
  // A previous attempt may have persisted a preallocated/discovered ID
358
358
  // before its receipt was committed. Reuse that fixed session rather than
359
- // allocating a second native session for the same durable AgentRun.
359
+ // allocating a second native session for the same durable Turn.
360
360
  const resumeNativeSessionId = input.mode === "resume"
361
361
  ? requireText(input.nativeSessionId, "Native session id")
362
362
  : knownNativeSessionId;
363
363
  const launchMode = resumeNativeSessionId === undefined
364
364
  ? "new"
365
365
  : "resume";
366
- const managedControl = owner.scope === "task" && input.runId !== undefined;
366
+ const managedControl = owner.scope === "task" && input.turnId !== undefined;
367
367
  const managedProviderEnvironment = managedControl
368
368
  && configured.adapterId === "codex"
369
369
  ? {
370
- // Managed Codex Runs are non-interactive. Use the Codex execution
370
+ // Managed Codex Turns are non-interactive. Use the Codex execution
371
371
  // identity for provider requests while clientInfo still identifies Yui.
372
372
  CODEX_INTERNAL_ORIGINATOR_OVERRIDE: "codex_exec"
373
373
  }
@@ -409,17 +409,17 @@ export class FileRoleLaunchPlanner {
409
409
  }
410
410
  if (binding.adapterId === "codex") {
411
411
  // Global/interactive Codex sessions still use notify for presentation.
412
- // Managed Runs receive lifecycle facts through their ordinary App Server
412
+ // Managed Turns receive lifecycle facts through their ordinary App Server
413
413
  // subscription, avoiding a second Hook channel for the same Turn.
414
- if (owner.scope !== "task" || input.runId === undefined) {
414
+ if (owner.scope !== "task" || input.turnId === undefined) {
415
415
  args = addCodexSessionNotify(args, launchMode, this.#cliPath);
416
416
  }
417
- // Managed Codex Runs use disposable proxy clients against the shared
417
+ // Managed Codex Turns use disposable proxy clients against the shared
418
418
  // native App Server. Their Session Manifest points at the Yui Skills;
419
419
  // no Yui Hook config is installed.
420
- if (owner.scope === "task" && input.runId !== undefined) {
420
+ if (owner.scope === "task" && input.turnId !== undefined) {
421
421
  if (managedRun === null || managedRun.status !== "active") {
422
- throw new Error(`Managed Codex Run is no longer active: ${input.runId}.`);
422
+ throw new Error(`Managed Codex Turn is no longer active: ${input.turnId}.`);
423
423
  }
424
424
  }
425
425
  session = launchMode === "resume"
@@ -439,9 +439,9 @@ export class FileRoleLaunchPlanner {
439
439
  }
440
440
  const managedClaudeRun = binding.adapterId === "claude"
441
441
  && owner.scope === "task"
442
- && input.runId !== undefined;
442
+ && input.turnId !== undefined;
443
443
  if (managedClaudeRun && (managedRun === null || managedRun.status !== "active")) {
444
- throw new Error(`Managed Claude Run is no longer active: ${input.runId}.`);
444
+ throw new Error(`Managed Claude Turn is no longer active: ${input.turnId}.`);
445
445
  }
446
446
  const runtimeDescriptor = owner.scope === "task"
447
447
  ? createExactTaskRuntimeDescriptor({
@@ -451,7 +451,7 @@ export class FileRoleLaunchPlanner {
451
451
  agentId: configured.id,
452
452
  adapterId: configured.adapterId,
453
453
  workspace: effectiveWorkspace,
454
- ...(input.runId === undefined ? {} : { runId: input.runId }),
454
+ ...(input.turnId === undefined ? {} : { turnId: input.turnId }),
455
455
  ...(input.launchId === undefined ? {} : { launchId: input.launchId }),
456
456
  ...(session === null
457
457
  ? {}
@@ -474,15 +474,15 @@ export class FileRoleLaunchPlanner {
474
474
  }
475
475
  // Session lifecycle and Turn submission are separate atomic operations.
476
476
  // Planning only starts or restores the exact native Session; delivery
477
- // submits the Run input after that Session fact is durable.
477
+ // submits the Turn input after that Session fact is durable.
478
478
  if (managedControl && (managedRun === null || managedRun.status !== "active")) {
479
- throw new Error(`Managed Run is no longer active: ${input.runId}.`);
479
+ throw new Error(`Managed Turn is no longer active: ${input.turnId}.`);
480
480
  }
481
481
  const providerAuthority = managedControl
482
482
  ? this.#providerAuthorityForLaunch(owner.taskId, role.name, input.launchId, input.mode)
483
483
  : undefined;
484
484
  const providerOwnedTurn = managedControl && input.mode === "resume"
485
- ? this.#providerOwnedTurnForLaunch(owner.taskId, role.name, input.runId)
485
+ ? this.#providerOwnedTurnForLaunch(owner.taskId, role.name, input.turnId)
486
486
  : undefined;
487
487
  const providerNativeSessionId = binding.adapterId === "claude"
488
488
  ? preallocatedNativeSessionId
@@ -557,7 +557,7 @@ export class FileRoleLaunchPlanner {
557
557
  ...(input.launchId === undefined
558
558
  ? {}
559
559
  : { YUI_LAUNCH_ID: input.launchId }),
560
- ...(input.runId === undefined ? {} : { YUI_RUN_ID: input.runId }),
560
+ ...(input.turnId === undefined ? {} : { YUI_TURN_ID: input.turnId }),
561
561
  ...(session === null
562
562
  ? {}
563
563
  : { YUI_NATIVE_SESSION_ID: session.nativeSessionId })
@@ -617,17 +617,18 @@ export class FileRoleLaunchPlanner {
617
617
  }
618
618
  throw new Error(`Provider writer authority is unknown: ${taskId}/${roleName}.`);
619
619
  }
620
- #providerOwnedTurnForLaunch(taskId, roleName, runId) {
620
+ #providerOwnedTurnForLaunch(taskId, roleName, turnId) {
621
621
  const binding = this.store.getTaskRoleSessionSet(taskId, roleName)?.providerBinding;
622
- if (binding === null || binding === undefined || binding.turn?.runId !== runId)
622
+ if (binding === null || binding === undefined
623
+ || binding.turn?.turnId !== turnId)
623
624
  return undefined;
624
625
  const turn = binding.turn;
625
- if (turn === null || !["accepted", "running"].includes(turn.status))
626
+ if (turn === null || turn.status !== "accepted")
626
627
  return undefined;
627
- if (turn.turnId === undefined) {
628
+ if (turn.nativeTurnId === undefined) {
628
629
  throw new Error(`Active Provider Turn has no native identity: ${taskId}/${roleName}.`);
629
630
  }
630
- return { attemptId: turn.attemptId, turnId: turn.turnId };
631
+ return { attemptId: turn.attemptId, turnId: turn.nativeTurnId };
631
632
  }
632
633
  #applyWorkspaceScope(taskId, role, launch, workspaceOverride) {
633
634
  const workspace = workspaceOverride
@@ -748,17 +749,16 @@ function ensureClaudeLifecyclePlugin(home, cliPath) {
748
749
  }, null, 2)}\n`);
749
750
  return root;
750
751
  }
751
- function managedClaudeControlPlaneConfig(config, taskId, workItemId, runId) {
752
+ function managedClaudeControlPlaneConfig(config, taskId, workItemId, turnId) {
752
753
  if (config.permission.strategy !== "configured")
753
754
  return config;
754
755
  const managed = [
755
- `Bash(yui task run context ${taskId}/${runId}:*)`,
756
+ `Bash(yui task turn context ${taskId}/${turnId}:*)`,
756
757
  `Bash(yui --json task context ${taskId})`,
757
758
  `Bash(yui --json task work list ${taskId})`,
758
759
  ...(workItemId === undefined
759
760
  ? []
760
- : [`Bash(yui --json task work show ${workItemId})`]),
761
- `Bash(yui task run yield ${runId} --summary-file -:*)`
761
+ : [`Bash(yui --json task work show ${workItemId})`])
762
762
  ];
763
763
  const existing = (config.permission.allowedTools ?? [])
764
764
  .filter((rule) => !isManagedYuiBashRule(rule));
@@ -833,7 +833,7 @@ function addCodexSessionNotify(args, mode, cliPath) {
833
833
  /**
834
834
  * Codex 0.145 discovers lifecycle hooks from its effective config. Keep Yui's
835
835
  * two handlers invocation-local: this avoids mutating CODEX_HOME or the Task
836
- * workspace, while the exact launch environment supplies the durable Run fence.
836
+ * workspace, while the exact launch environment supplies the durable Turn fence.
837
837
  */
838
838
  function codexLifecycleHooksConfig(cliPath) {
839
839
  const command = [
@@ -1,13 +1,13 @@
1
- export function withYuiRunEnvironment(launch, yuiHome, role, run, nativeSessionId, nativeSessionRoot) {
1
+ export function withYuiTurnEnvironment(launch, yuiHome, role, turn, nativeSessionId, nativeSessionRoot) {
2
2
  return {
3
3
  ...launch,
4
4
  env: {
5
5
  ...launch.env,
6
6
  YUI_HOME: yuiHome,
7
- YUI_TASK_ID: run.taskId,
7
+ YUI_TASK_ID: turn.taskId,
8
8
  YUI_ROLE: role.name,
9
9
  YUI_AGENT_ID: role.activeAgentId ?? role.agent ?? "",
10
- YUI_RUN_ID: run.id,
10
+ YUI_TURN_ID: turn.id,
11
11
  YUI_WORKSPACE: role.workspace,
12
12
  ...(nativeSessionRoot === undefined ? {} : { YUI_NATIVE_SESSION_ROOT: nativeSessionRoot }),
13
13
  ...(nativeSessionId === undefined ? {} : { YUI_NATIVE_SESSION_ID: nativeSessionId })
@@ -20,7 +20,7 @@ function ownerLabel(owner) {
20
20
  * This is a read-only check: it never mutates Git state, creates Sessions, or
21
21
  * writes recovery records.
22
22
  */
23
- export function classifyWorkspacePreflight(store, task, roleName, activeRun, inspectPhysical) {
23
+ export function classifyWorkspacePreflight(store, task, roleName, activeTurn, inspectPhysical) {
24
24
  const main = store.getTaskWorkspace(task.id);
25
25
  const bindings = task.projectBindings.map(({ projectId, directory }) => ({ projectId, directory }));
26
26
  // 1. Owner validation: the Task main workspace must be a durable,
@@ -41,26 +41,26 @@ export function classifyWorkspacePreflight(store, task, roleName, activeRun, ins
41
41
  actual
42
42
  };
43
43
  }
44
- // 2. Run snapshot validation: when the active Run carries a workspace
44
+ // 2. Turn snapshot validation: when the active Turn carries a workspace
45
45
  // snapshot its launch-stable identity must match the durable
46
46
  // ManagedWorkspace. Audit timestamps may change without changing the
47
- // owner, root, or Project entries authorized for the Run.
48
- if (activeRun?.workspace !== undefined) {
49
- const durableRunWorkspace = store.getManagedWorkspace(activeRun.workspace.owner);
47
+ // owner, root, or Project entries authorized for the Turn.
48
+ if (activeTurn?.workspace !== undefined) {
49
+ const durableRunWorkspace = store.getManagedWorkspace(activeTurn.workspace.owner);
50
50
  if (durableRunWorkspace === null
51
- || !sameManagedWorkspaceIdentity(durableRunWorkspace, activeRun.workspace)) {
51
+ || !sameManagedWorkspaceIdentity(durableRunWorkspace, activeTurn.workspace)) {
52
52
  const diff = [];
53
53
  if (durableRunWorkspace === null) {
54
- diff.push(`durable ManagedWorkspace for owner ${JSON.stringify(activeRun.workspace.owner)} is missing`);
54
+ diff.push(`durable ManagedWorkspace for owner ${JSON.stringify(activeTurn.workspace.owner)} is missing`);
55
55
  }
56
56
  else {
57
- if (durableRunWorkspace.root !== activeRun.workspace.root) {
58
- diff.push(`root: durable=${durableRunWorkspace.root} run=${activeRun.workspace.root}`);
57
+ if (durableRunWorkspace.root !== activeTurn.workspace.root) {
58
+ diff.push(`root: durable=${durableRunWorkspace.root} run=${activeTurn.workspace.root}`);
59
59
  }
60
- if (durableRunWorkspace.entries.length !== activeRun.workspace.entries.length) {
61
- diff.push(`entries: durable=${durableRunWorkspace.entries.length} run=${activeRun.workspace.entries.length}`);
60
+ if (durableRunWorkspace.entries.length !== activeTurn.workspace.entries.length) {
61
+ diff.push(`entries: durable=${durableRunWorkspace.entries.length} run=${activeTurn.workspace.entries.length}`);
62
62
  }
63
- for (const [index, entry] of activeRun.workspace.entries.entries()) {
63
+ for (const [index, entry] of activeTurn.workspace.entries.entries()) {
64
64
  const durableEntry = durableRunWorkspace.entries[index];
65
65
  if (durableEntry === undefined) {
66
66
  diff.push(`entry[${index}] ${entry.projectId}: missing from durable`);
@@ -76,10 +76,10 @@ export function classifyWorkspacePreflight(store, task, roleName, activeRun, ins
76
76
  }
77
77
  return {
78
78
  kind: "workspace-stale",
79
- reason: `Role Run workspace is not the durable owner: ${task.id}/${roleName}.`,
79
+ reason: `Role Turn workspace is not the durable owner: ${task.id}/${roleName}.`,
80
80
  taskId: task.id,
81
81
  roleName,
82
- runId: activeRun.id,
82
+ turnId: activeTurn.id,
83
83
  diff
84
84
  };
85
85
  }
@@ -89,7 +89,7 @@ export function classifyWorkspacePreflight(store, task, roleName, activeRun, ins
89
89
  // from that immutable boundary. A reset/repoint outside the lineage is
90
90
  // physical drift and must fail before Provider launch.
91
91
  if (inspectPhysical !== undefined) {
92
- const effective = activeRun?.workspace ?? main;
92
+ const effective = activeTurn?.workspace ?? main;
93
93
  for (const entry of effective.entries) {
94
94
  const physical = inspectPhysical(entry);
95
95
  if (!physical.recordedBaseIsAncestor) {
@@ -121,7 +121,7 @@ export function formatWorkspacePreflightError(classification) {
121
121
  + "` to inspect the binding, ManagedWorkspace, and physical HEAD.");
122
122
  break;
123
123
  case "workspace-stale":
124
- lines.push(` Run ${classification.runId} snapshot differs from the durable ManagedWorkspace:`);
124
+ lines.push(` Turn ${classification.turnId} snapshot differs from the durable ManagedWorkspace:`);
125
125
  for (const entry of classification.diff) {
126
126
  lines.push(` - ${entry}`);
127
127
  }
@@ -1,6 +1,6 @@
1
1
  import { requireIdentity, requireText, requireTimestamp, requirePositiveInteger } from "../domain/validation.js";
2
2
  import { validateTaskRecordReference } from "../task/taskRecordReference.js";
3
- export const CAPABILITY_GRANT_SCHEMA_VERSION = 1;
3
+ export const CAPABILITY_GRANT_SCHEMA_VERSION = 2;
4
4
  const IRREVERSIBILITY_RANK = {
5
5
  none: 0,
6
6
  reversible: 1,
@@ -19,6 +19,7 @@ export function createCapabilityGrant(id, taskId, input, now) {
19
19
  ...(input.expiresAt === undefined ? {} : { expiresAt: requireTimestamp(input.expiresAt, "Capability grant expiresAt") }),
20
20
  ...(input.maxUses === undefined ? {} : { maxUses: requirePositiveInteger(input.maxUses, "Capability grant maxUses") }),
21
21
  usesUsed: 0,
22
+ useReservations: Object.freeze([]),
22
23
  irreversibilityCeiling: normalizeCeiling(input.irreversibilityCeiling),
23
24
  createdAt: timestamp,
24
25
  updatedAt: timestamp
@@ -61,16 +62,14 @@ export function checkGrant(grant, request, now, options) {
61
62
  }
62
63
  return { allowed: true };
63
64
  }
64
- /** The reservation keys recorded on a grant, or an empty list for legacy grants. */
65
+ /** The reservation keys recorded on a grant. */
65
66
  export function grantUseReservations(grant) {
66
- return grant.useReservations ?? [];
67
+ return grant.useReservations;
67
68
  }
68
69
  /**
69
70
  * Record one use against the grant, failing closed once the limit is reached.
70
- * When `reservationKey` is supplied it is appended to the grant's durable
71
- * reservations so a later resume can recognize this exact attempt and avoid a
72
- * double charge. A use recorded without a key (legacy callers) leaves the
73
- * reservation list untouched.
71
+ * The reservation key is appended to the grant's durable reservations so a
72
+ * later resume recognizes this exact attempt and avoids a double charge.
74
73
  */
75
74
  export function recordGrantUse(grant, now, reservationKey) {
76
75
  validateCapabilityGrant(grant);
@@ -80,9 +79,7 @@ export function recordGrantUse(grant, now, reservationKey) {
80
79
  return validateCapabilityGrant({
81
80
  ...grant,
82
81
  usesUsed: grant.usesUsed + 1,
83
- ...(reservationKey === undefined
84
- ? {}
85
- : { useReservations: Object.freeze([...grantUseReservations(grant), reservationKey]) }),
82
+ useReservations: Object.freeze([...grantUseReservations(grant), reservationKey]),
86
83
  updatedAt: now.toISOString()
87
84
  });
88
85
  }
@@ -105,7 +102,7 @@ export function revokeGrant(grant, revokedBy, now) {
105
102
  }
106
103
  export function validateCapabilityGrant(grant) {
107
104
  if (grant.schemaVersion !== CAPABILITY_GRANT_SCHEMA_VERSION) {
108
- throw new Error("Capability grant must use schemaVersion 1.");
105
+ throw new Error("Capability grant must use schemaVersion 2.");
109
106
  }
110
107
  validateTaskRecordReference({ taskId: grant.taskId, localId: grant.id }, "capabilityGrant");
111
108
  requireIdentity(grant.taskId, "Task id");
@@ -125,22 +122,20 @@ export function validateCapabilityGrant(grant) {
125
122
  if (grant.maxUses !== undefined && grant.usesUsed > grant.maxUses) {
126
123
  throw new Error("Capability grant usesUsed cannot exceed maxUses.");
127
124
  }
128
- if (grant.useReservations !== undefined) {
129
- if (!Array.isArray(grant.useReservations)) {
130
- throw new Error("Capability grant useReservations must be an array.");
131
- }
132
- for (const key of grant.useReservations) {
133
- if (typeof key !== "string" || key.length === 0) {
134
- throw new Error("Capability grant useReservations must be non-empty strings.");
135
- }
136
- }
137
- if (new Set(grant.useReservations).size !== grant.useReservations.length) {
138
- throw new Error("Capability grant useReservations must be unique.");
139
- }
140
- if (grant.useReservations.length > grant.usesUsed) {
141
- throw new Error("Capability grant useReservations cannot outnumber usesUsed.");
125
+ if (!Array.isArray(grant.useReservations)) {
126
+ throw new Error("Capability grant useReservations must be an array.");
127
+ }
128
+ for (const key of grant.useReservations) {
129
+ if (typeof key !== "string" || key.length === 0) {
130
+ throw new Error("Capability grant useReservations must be non-empty strings.");
142
131
  }
143
132
  }
133
+ if (new Set(grant.useReservations).size !== grant.useReservations.length) {
134
+ throw new Error("Capability grant useReservations must be unique.");
135
+ }
136
+ if (grant.useReservations.length > grant.usesUsed) {
137
+ throw new Error("Capability grant useReservations cannot outnumber usesUsed.");
138
+ }
144
139
  normalizeCeiling(grant.irreversibilityCeiling);
145
140
  if ((grant.revokedAt === undefined) !== (grant.revokedBy === undefined)) {
146
141
  throw new Error("Capability grant revocation requires both revokedAt and revokedBy.");
@@ -14,7 +14,7 @@ export function createInputRequest(id, taskId, requester, input, now) {
14
14
  const timestamp = requireDate(now, "Input request creation time");
15
15
  const choices = normalizeChoices(input.choices);
16
16
  return validateInputRequest({
17
- schemaVersion: 2,
17
+ schemaVersion: 3,
18
18
  id: requireIdentity(id, "Input request id"),
19
19
  taskId: requireIdentity(taskId, "Input request Task id"),
20
20
  requester: normalizeRequester(requester),
@@ -72,12 +72,12 @@ export function validateInputRequest(value) {
72
72
  "schemaVersion", "id", "taskId", "requester", "question", "choices",
73
73
  "blockedRefs", "policy", "status", "createdAt", "updatedAt", ...terminalField
74
74
  ], "Input request");
75
- if (request.schemaVersion !== 2)
76
- throw new Error("Input request must use schemaVersion 2.");
75
+ if (request.schemaVersion !== 3)
76
+ throw new Error("Input request must use schemaVersion 3.");
77
77
  const choices = validateChoices(request.choices);
78
78
  const createdAt = requireTimestamp(request.createdAt, "Input request createdAt");
79
79
  const base = {
80
- schemaVersion: 2,
80
+ schemaVersion: 3,
81
81
  id: requireIdentity(request.id, "Input request id"),
82
82
  taskId: requireIdentity(request.taskId, "Input request Task id"),
83
83
  requester: normalizeRequester(request.requester),
@@ -91,10 +91,10 @@ export function validateInputRequest(value) {
91
91
  validateTaskRecordReference({ taskId: base.taskId, localId: base.id }, "inputRequest");
92
92
  validateTaskRecordReference({
93
93
  taskId: base.requester.taskId,
94
- localId: base.requester.runId
95
- }, "agentRun");
94
+ localId: base.requester.turnId
95
+ }, "turn");
96
96
  for (const reference of base.blockedRefs) {
97
- validateTaskRecordReference({ taskId: reference.taskId, localId: reference.id }, reference.type === "run" ? "agentRun" : "workItem");
97
+ validateTaskRecordReference({ taskId: reference.taskId, localId: reference.id }, reference.type === "turn" ? "turn" : "workItem");
98
98
  }
99
99
  if (base.requester.taskId !== base.taskId
100
100
  || base.blockedRefs.some(({ taskId }) => taskId !== base.taskId)) {
@@ -175,8 +175,8 @@ function normalizeBlockedRefs(value) {
175
175
  const references = value.map((reference) => {
176
176
  const item = record(reference, "Input blocked reference");
177
177
  exact(item, ["type", "taskId", "id"], "Input blocked reference");
178
- if (item.type !== "work-item" && item.type !== "run") {
179
- throw new Error("Input blocked reference type must be work-item or run.");
178
+ if (item.type !== "work-item" && item.type !== "turn") {
179
+ throw new Error("Input blocked reference type must be work-item or turn.");
180
180
  }
181
181
  return {
182
182
  type: item.type,
@@ -224,15 +224,15 @@ function validateBlockedRefs(value) {
224
224
  function normalizeRequester(value) {
225
225
  const requester = record(value, "Input requester");
226
226
  exact(requester, requester.nativeSessionId === undefined
227
- ? ["taskId", "roleName", "agentId", "runId"]
228
- : ["taskId", "roleName", "agentId", "runId", "nativeSessionId"], "Input requester");
227
+ ? ["taskId", "roleName", "agentId", "turnId"]
228
+ : ["taskId", "roleName", "agentId", "turnId", "nativeSessionId"], "Input requester");
229
229
  if (requester.roleName !== "leader")
230
230
  throw new Error("Input requester must be the Task Leader.");
231
231
  return {
232
232
  taskId: requireIdentity(requester.taskId, "Input requester Task id"),
233
233
  roleName: "leader",
234
234
  agentId: requireIdentity(requester.agentId, "Input requester Agent id"),
235
- runId: requireIdentity(requester.runId, "Input requester Run id"),
235
+ turnId: requireIdentity(requester.turnId, "Input requester Turn id"),
236
236
  ...(requester.nativeSessionId === undefined
237
237
  ? {}
238
238
  : { nativeSessionId: requireIdentity(requester.nativeSessionId, "Input requester native session id") })
@@ -3,18 +3,16 @@ import { validateTaskRecordReference } from "../task/taskRecordReference.js";
3
3
  import { validateChangeSetManifest } from "./changeSetManifest.js";
4
4
  export function createWorkItemChangeSet(input, now) {
5
5
  return validateChangeSet({
6
- schemaVersion: 3,
6
+ schemaVersion: 4,
7
7
  ...input,
8
8
  changedPaths: [...input.changedPaths],
9
- ...(input.manifest === undefined
10
- ? {}
11
- : { manifest: validateChangeSetManifest(input.manifest) }),
9
+ manifest: validateChangeSetManifest(input.manifest),
12
10
  createdAt: now.toISOString()
13
11
  });
14
12
  }
15
13
  export function validateChangeSet(changeSet) {
16
- if (changeSet.schemaVersion !== 3)
17
- throw new Error("ChangeSet must use schemaVersion 3.");
14
+ if (changeSet.schemaVersion !== 4)
15
+ throw new Error("ChangeSet must use schemaVersion 4.");
18
16
  validateTaskRecordReference({ taskId: changeSet.taskId, localId: changeSet.id }, "changeSet");
19
17
  validateTaskRecordReference({
20
18
  taskId: changeSet.taskId,
@@ -28,13 +26,11 @@ export function validateChangeSet(changeSet) {
28
26
  }
29
27
  requireText(changeSet.branch, "ChangeSet branch");
30
28
  normalizedUniqueText(changeSet.changedPaths, "ChangeSet path");
31
- if (changeSet.manifest !== undefined) {
32
- const manifest = validateChangeSetManifest(changeSet.manifest);
33
- const changed = new Set(changeSet.changedPaths);
34
- for (const deleted of manifest.deletedPaths) {
35
- if (!changed.has(deleted)) {
36
- throw new Error(`ChangeSet manifest deleted path is not a changed path: ${deleted}.`);
37
- }
29
+ const manifest = validateChangeSetManifest(changeSet.manifest);
30
+ const changed = new Set(changeSet.changedPaths);
31
+ for (const deleted of manifest.deletedPaths) {
32
+ if (!changed.has(deleted)) {
33
+ throw new Error(`ChangeSet manifest deleted path is not a changed path: ${deleted}.`);
38
34
  }
39
35
  }
40
36
  requireTimestamp(changeSet.createdAt, "ChangeSet createdAt");
@@ -33,7 +33,7 @@ export function validateChangeSetManifest(manifest) {
33
33
  }
34
34
  const tags = normalizedUniqueText(manifest.tags, "ChangeSet manifest tag");
35
35
  const deletedPaths = normalizedUniqueText(manifest.deletedPaths, "ChangeSet manifest deleted path");
36
- const evidenceRefs = normalizedUniqueText(manifest.evidenceRefs ?? [], "ChangeSet manifest evidence reference");
36
+ const evidenceRefs = normalizedUniqueText(manifest.evidenceRefs, "ChangeSet manifest evidence reference");
37
37
  return {
38
38
  schemaVersion: CHANGE_SET_MANIFEST_SCHEMA_VERSION,
39
39
  tags,
@@ -933,7 +933,7 @@ function integrationRuntimeLaunchId(home, integrationId) {
933
933
  }
934
934
  /**
935
935
  * Reuse is enabled only for an immutable installed release. Development
936
- * checkouts have no content-addressed release identity, so they rerun.
936
+ * checkouts have no content-addressed release identity, so they return.
937
937
  */
938
938
  function integrationRuntimeReleaseIdentity(home) {
939
939
  try {
@@ -1050,7 +1050,7 @@ async function resolveRef(repositoryPath, ref) {
1050
1050
  /**
1051
1051
  * Static preflight before the (potentially expensive) checks: the target ref
1052
1052
  * must still equal the expected head and a checked-out target worktree must be
1053
- * clean. A failure here means the check commands must not run. The post-check
1053
+ * clean. A failure here means the check commands must not turn. The post-check
1054
1054
  * {@link advanceTargetRef} re-verifies both before the CAS, so a target that
1055
1055
  * moves during the gate is still fenced.
1056
1056
  */