@zq-silk/yui 0.15.7 → 0.15.8

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 (281) hide show
  1. package/ARCHITECTURE.md +192 -399
  2. package/README.md +127 -1149
  3. package/dist/agent/adapterCatalog.js +15 -2
  4. package/dist/agent/agent.js +23 -3
  5. package/dist/agent/argumentPolicy.js +7 -1
  6. package/dist/agent/connectionPlan.js +62 -0
  7. package/dist/agent/executionComponents.js +158 -0
  8. package/dist/agent/launchEnvironment.js +31 -3
  9. package/dist/agent/managedRuntimeEnvironment.js +3 -5
  10. package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
  11. package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
  12. package/dist/brief/taskBrief.js +12 -0
  13. package/dist/cli/agentConfigurationPicker.js +13 -0
  14. package/dist/cli/commandCatalog.js +157 -70
  15. package/dist/cli/interactionCandidates.js +5 -5
  16. package/dist/cli/interactionPolicy.js +38 -8
  17. package/dist/cli/invocationRouter.js +1 -1
  18. package/dist/cli/managedDiagnostics.js +28 -0
  19. package/dist/cli/operatorWizard.js +1 -7
  20. package/dist/cli/roleOptionOrder.js +27 -0
  21. package/dist/cli/roleWizard.js +50 -14
  22. package/dist/cli/updateOrchestrator.js +1 -1
  23. package/dist/cli/updatePorts.js +3 -4
  24. package/dist/cli.js +178 -95
  25. package/dist/commands/agentCommands.js +72 -14
  26. package/dist/commands/capabilityCommands.js +9 -6
  27. package/dist/commands/configCommands.js +20 -20
  28. package/dist/commands/deliveryGuardPreflight.js +2 -2
  29. package/dist/commands/executionAuditCommands.js +24 -24
  30. package/dist/commands/globalRoleCommands.js +1 -1
  31. package/dist/commands/grantCommands.js +4 -4
  32. package/dist/commands/operatorCommands.js +1 -7
  33. package/dist/commands/projectCommands.js +4 -4
  34. package/dist/commands/resourcesCommands.js +2 -2
  35. package/dist/commands/roleConfiguration.js +25 -5
  36. package/dist/commands/roleRuntimeGuard.js +4 -5
  37. package/dist/commands/sessionCommands.js +3 -7
  38. package/dist/commands/taskActivationCommands.js +259 -0
  39. package/dist/commands/taskActor.js +28 -49
  40. package/dist/commands/taskCommands.js +1188 -710
  41. package/dist/commands/taskContextCommand.js +39 -583
  42. package/dist/commands/taskExecutionCommands.js +32 -32
  43. package/dist/commands/taskInputCommands.js +40 -104
  44. package/dist/commands/taskIntegrationCommands.js +3 -2
  45. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  46. package/dist/commands/taskNextActionCommand.js +8 -8
  47. package/dist/commands/taskOverviewCommand.js +33 -45
  48. package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
  49. package/dist/commands/taskRoleRuntimeStatus.js +133 -102
  50. package/dist/commands/telemetryCommands.js +36 -38
  51. package/dist/config/configCatalog.js +4 -4
  52. package/dist/config/yuiConfig.js +8 -8
  53. package/dist/context/contextSnapshot.js +10 -10
  54. package/dist/context/dispatchContext.js +11 -11
  55. package/dist/context/roleSessionContext.js +6 -3
  56. package/dist/context/{turnContextPack.js → runContextPack.js} +146 -81
  57. package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
  58. package/dist/context/sessionBootstrapManifest.js +21 -2
  59. package/dist/context/sourceRunContext.js +30 -0
  60. package/dist/context/taskContext.js +458 -0
  61. package/dist/context/wakeNotification.js +27 -27
  62. package/dist/controller/agentRuntimeObserver.js +21 -24
  63. package/dist/controller/capabilityBridge.js +17 -6
  64. package/dist/controller/clientRuntime.js +65 -92
  65. package/dist/controller/controller.js +114 -188
  66. package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
  67. package/dist/controller/jobControl.js +54 -85
  68. package/dist/controller/resourceInventory.js +8 -27
  69. package/dist/controller/resourceInventoryLinux.js +12 -13
  70. package/dist/controller/runtime.js +529 -479
  71. package/dist/controller/runtimeEventInbox.js +55 -25
  72. package/dist/controller/runtimeEventProcessor.js +22 -31
  73. package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
  74. package/dist/controller/runtimeLaunchCoordinator.js +80 -426
  75. package/dist/controller/runtimeObservationHook.js +14 -18
  76. package/dist/controller/sessionNotify.js +16 -24
  77. package/dist/controller/sessionOwnerReconciliation.js +168 -50
  78. package/dist/controller/structuredProviderObservation.js +138 -99
  79. package/dist/coordination/workMailbox.js +3 -3
  80. package/dist/coordination/workMailboxQueue.js +36 -33
  81. package/dist/core/boundedRpc.js +8 -1
  82. package/dist/core/controllerClient.js +20 -1
  83. package/dist/core/controllerServer.js +4 -4
  84. package/dist/doctor/doctor.js +13 -2
  85. package/dist/domain/agentResultTransport.js +9 -9
  86. package/dist/execution/codexThreadNaming.js +2 -8
  87. package/dist/execution/executionHealth.js +51 -63
  88. package/dist/execution/reviewMainRun.js +137 -0
  89. package/dist/execution/workItemExecution.js +28 -29
  90. package/dist/execution/workItemExecutionProjection.js +99 -107
  91. package/dist/execution/workItemMainRun.js +141 -0
  92. package/dist/executor/agentAdapter.js +227 -20
  93. package/dist/executor/agentConfigurationCatalog.js +126 -4
  94. package/dist/executor/agentConfigurationProbe.js +162 -4
  95. package/dist/executor/agentExecutor.js +79 -78
  96. package/dist/executor/effectiveLaunch.js +105 -18
  97. package/dist/executor/executorRegistry.js +29 -44
  98. package/dist/executor/fileRoleLaunchPlanner.js +229 -154
  99. package/dist/executor/workspacePreflightClassification.js +16 -16
  100. package/dist/grant/capabilityGrant.js +6 -3
  101. package/dist/input/inputRequest.js +12 -10
  102. package/dist/integration/gitIntegrationService.js +4 -11
  103. package/dist/integration/integrationQueueService.js +4 -4
  104. package/dist/interaction/operatorPresentation.js +1 -1
  105. package/dist/kernel/builtinCapabilities.js +247 -12
  106. package/dist/kernel/capabilityRegistry.js +64 -18
  107. package/dist/kernel/instanceHost.js +12 -1
  108. package/dist/kernel/kernelPorts.js +2 -2
  109. package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
  110. package/dist/lifecycle/exactRunTerminalization.js +449 -0
  111. package/dist/message/message.js +62 -6
  112. package/dist/message/messageContinuation.js +204 -0
  113. package/dist/observability/executionAudit.js +70 -72
  114. package/dist/observability/faultClassification.js +2 -2
  115. package/dist/observability/orchestrationMetrics.js +8 -8
  116. package/dist/operator/operatorSessionHistory.js +1 -7
  117. package/dist/output/agentConfigurationPresentation.js +8 -3
  118. package/dist/output/agentRunConfigurationPresentation.js +128 -0
  119. package/dist/output/rolePresentation.js +54 -3
  120. package/dist/plugins/pluginChild.js +104 -0
  121. package/dist/plugins/pluginIntent.js +26 -0
  122. package/dist/plugins/pluginInterpreter.js +43 -0
  123. package/dist/plugins/pluginPackage.js +101 -0
  124. package/dist/plugins/pluginProcess.js +112 -0
  125. package/dist/plugins/pluginService.js +380 -0
  126. package/dist/profile/agentProfile.js +1 -1
  127. package/dist/repository/gitWorkspace.js +26 -4
  128. package/dist/repository/project.js +19 -4
  129. package/dist/repository/taskBaseFreshness.js +13 -13
  130. package/dist/repository/taskWorkspaceCoordinator.js +20 -27
  131. package/dist/repository/taskWorkspacePreparer.js +344 -83
  132. package/dist/resources/autoResourceGc.js +3 -3
  133. package/dist/resources/liveReferences.js +3 -3
  134. package/dist/resources/projectResource.js +123 -0
  135. package/dist/resources/projectResourceService.js +421 -0
  136. package/dist/resources/resourceDiscovery.js +6 -6
  137. package/dist/resources/resourceGc.js +1 -1
  138. package/dist/resources/resourceRegistrar.js +1 -1
  139. package/dist/resources/resourceTypes.js +1 -1
  140. package/dist/review/deltaRecheck.js +3 -3
  141. package/dist/review/reviewAcceptance.js +16 -16
  142. package/dist/review/reviewDecision.js +7 -7
  143. package/dist/review/reviewRound.js +21 -20
  144. package/dist/review/reviewerAvailability.js +2 -2
  145. package/dist/role/role.js +51 -7
  146. package/dist/role/taskRoleUpdate.js +30 -0
  147. package/dist/runtime/acpProtocol.js +425 -0
  148. package/dist/runtime/acpSession.js +731 -0
  149. package/dist/runtime/acpSessionConfiguration.js +260 -0
  150. package/dist/runtime/agentDriver.js +30 -11
  151. package/dist/runtime/agentEndpoint.js +278 -0
  152. package/dist/runtime/agentEndpointIdentity.js +86 -0
  153. package/dist/runtime/agentEndpointOwnership.js +239 -0
  154. package/dist/runtime/agentError.js +2 -10
  155. package/dist/runtime/agentHost.js +565 -314
  156. package/dist/runtime/agentRunConfiguration.js +258 -0
  157. package/dist/runtime/builtinAgentDrivers.js +134 -18
  158. package/dist/runtime/builtinAgentErrorMappers.js +55 -3
  159. package/dist/runtime/builtinTranscriptUsage.js +1 -1
  160. package/dist/runtime/claude-process-owner +0 -0
  161. package/dist/runtime/codexAppServerRuntime.js +38 -30
  162. package/dist/runtime/codexInteractiveHost.js +41 -6
  163. package/dist/runtime/continuationManager.js +2 -6
  164. package/dist/runtime/executionEnvironment.js +30 -0
  165. package/dist/runtime/firstProgressAdvisory.js +11 -11
  166. package/dist/runtime/index.js +4 -3
  167. package/dist/runtime/jsonLineChannel.js +109 -0
  168. package/dist/runtime/launchBroker.js +91 -16
  169. package/dist/runtime/launchDiagnostics.js +2 -2
  170. package/dist/runtime/lifecycleReservation.js +10 -18
  171. package/dist/runtime/managedCaller.js +61 -17
  172. package/dist/runtime/nativeSessionControl.js +102 -0
  173. package/dist/runtime/ports.js +6 -21
  174. package/dist/runtime/processExitObservation.js +8 -7
  175. package/dist/runtime/promptEnvelope.js +17 -6
  176. package/dist/runtime/providerContinuation.js +3 -9
  177. package/dist/runtime/providerContinuationReconciliationService.js +4 -13
  178. package/dist/runtime/providerControl.js +2 -7
  179. package/dist/runtime/providerRuntimeIdentity.js +110 -222
  180. package/dist/runtime/providerRuntimeReconciler.js +5 -9
  181. package/dist/runtime/runtimeBinding.js +0 -1
  182. package/dist/runtime/runtimeContinuationProjection.js +4 -7
  183. package/dist/runtime/runtimeDeadlines.js +9 -0
  184. package/dist/runtime/runtimeHealthPolicy.js +1 -1
  185. package/dist/runtime/runtimeObservation.js +29 -65
  186. package/dist/runtime/runtimeProjection.js +43 -51
  187. package/dist/runtime/runtimeSessionCandidate.js +1 -3
  188. package/dist/runtime/sessionLaunchRequest.js +3 -7
  189. package/dist/runtime/sessionOwnerIdentity.js +7 -54
  190. package/dist/runtime/sessionOwnerRegistry.js +22 -17
  191. package/dist/runtime/sessionReconciliation.js +4 -8
  192. package/dist/runtime/sessionTerminationGuard.js +70 -259
  193. package/dist/runtime/sessionTokenMetrics.js +5 -16
  194. package/dist/runtime/structuredProviderHost.js +237 -117
  195. package/dist/runtime/taskRuntimeIsolation.js +39 -122
  196. package/dist/runtime/tmuxAdapters.js +39 -86
  197. package/dist/scheduler/activeRoleRunDelivery.js +354 -0
  198. package/dist/scheduler/leaderWakeupProcessor.js +75 -266
  199. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  200. package/dist/scheduler/ports.js +80 -9
  201. package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
  202. package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
  203. package/dist/scheduler/taskExecutionProjection.js +120 -124
  204. package/dist/scheduler/taskObservabilityProjection.js +29 -29
  205. package/dist/scheduler/taskWake.js +11 -4
  206. package/dist/scheduler/wakeReason.js +9 -1
  207. package/dist/setup/setupCommand.js +1 -0
  208. package/dist/storage/migrations/agentRunContract.js +159 -0
  209. package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
  210. package/dist/storage/sqliteSchema.js +431 -5
  211. package/dist/storage/sqliteStore.js +375 -220
  212. package/dist/storage/storageVersions.js +1 -1
  213. package/dist/storage/storeRpc.js +10 -5
  214. package/dist/storage/taskStore.js +13 -11
  215. package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
  216. package/dist/surface/surfaceContributions.js +102 -0
  217. package/dist/task/completionReadiness.js +32 -6
  218. package/dist/task/deliveryGuard.js +16 -16
  219. package/dist/task/draftPlan.js +72 -12
  220. package/dist/task/nextAction.js +144 -128
  221. package/dist/task/remoteDelivery.js +6 -6
  222. package/dist/task/task.js +184 -18
  223. package/dist/task/taskActivation.js +301 -0
  224. package/dist/task/taskActivationService.js +392 -0
  225. package/dist/task/taskRecordReference.js +5 -4
  226. package/dist/task/taskRecordRetirement.js +1 -1
  227. package/dist/telemetry/sqliteTelemetryStore.js +55 -68
  228. package/dist/telemetry/telemetryConfig.js +14 -14
  229. package/dist/telemetry/telemetryWiring.js +2 -2
  230. package/dist/web/assets/assetManifest.js +2 -0
  231. package/dist/web/assets/client/app.js +120 -20
  232. package/dist/web/assets/client/components.js +87 -54
  233. package/dist/web/assets/client/i18n.js +83 -41
  234. package/dist/web/assets/client/markdown.js +1 -1
  235. package/dist/web/assets/client/taskSurface.js +353 -0
  236. package/dist/web/assets/client/view.js +49 -44
  237. package/dist/web/assets/shell.js +1 -1
  238. package/dist/web/assets/styles/cards.js +22 -4
  239. package/dist/web/controllerWeb.js +60 -0
  240. package/dist/web/webMutation.js +28 -0
  241. package/dist/web/webServer.js +118 -8
  242. package/dist/web/webSnapshot.js +81 -74
  243. package/dist/web/webTaskSurface.js +64 -0
  244. package/dist/workItem/dependencyGate.js +1 -1
  245. package/dist/workItem/workItem.js +80 -48
  246. package/dist/workspace/workItemChangeSetManager.js +16 -9
  247. package/docs/agent-result-consumption.md +94 -0
  248. package/docs/agent-runtime-drivers.md +91 -0
  249. package/docs/architecture/README.md +38 -0
  250. package/docs/architecture/capabilities-and-resources.md +79 -0
  251. package/docs/managed-turn-and-session-runtime.md +222 -0
  252. package/docs/observability/README.md +81 -0
  253. package/docs/plugin-sdk.md +290 -0
  254. package/docs/provider-runtime.md +163 -0
  255. package/docs/release-workflow.md +303 -0
  256. package/docs/roles-and-configuration.md +113 -0
  257. package/docs/sqlite-control-plane-design.md +76 -0
  258. package/docs/task-dag-semantics.md +57 -0
  259. package/docs/task-delivery.md +103 -0
  260. package/docs/task-local-identity.md +6 -6
  261. package/docs/testing/verification-levels.md +86 -0
  262. package/i18n/README.zh-CN.md +98 -739
  263. package/package.json +2 -2
  264. package/skills/yui-leader/SKILL.md +130 -103
  265. package/skills/yui-leader/references/integration.md +39 -0
  266. package/skills/yui-leader/references/replicated-execution.md +42 -0
  267. package/skills/yui-leader/references/task-plugins.md +33 -0
  268. package/skills/yui-operator/SKILL.md +30 -59
  269. package/skills/yui-reviewer/SKILL.md +35 -36
  270. package/skills/yui-runtime/SKILL.md +88 -24
  271. package/skills/yui-runtime/references/publication.md +22 -0
  272. package/skills/yui-runtime/references/recovery.md +64 -0
  273. package/skills/yui-worker/SKILL.md +37 -39
  274. package/dist/cli/roleOptionCatalog.js +0 -68
  275. package/dist/context/sourceTurnContext.js +0 -30
  276. package/dist/execution/reviewMainTurn.js +0 -161
  277. package/dist/execution/workItemMainTurn.js +0 -164
  278. package/dist/lifecycle/exactTurnTerminalization.js +0 -407
  279. package/dist/runtime/preallocatedNativeSession.js +0 -13
  280. package/dist/runtime/runtimeStopReceipt.js +0 -42
  281. package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
@@ -0,0 +1,204 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+ import { createRun, withRunContextSnapshot } from "../agentRun/agentRun.js";
3
+ import { createRunInput } from "../context/runInputContract.js";
4
+ import { contextContentDigest, contextSnapshotRef, createContextSnapshot } from "../context/contextSnapshot.js";
5
+ import { roleSessionMayContinue } from "../executor/effectiveLaunch.js";
6
+ import { enqueueRoleRunDispatch } from "../coordination/workMailboxQueue.js";
7
+ import { createTaskEvent } from "../event/taskEvent.js";
8
+ import { validateExactRunReviewRound } from "../lifecycle/exactRunTerminalization.js";
9
+ import { sourceRunContextValue } from "../context/sourceRunContext.js";
10
+ import { requireManagedTaskCaller } from "../runtime/managedCaller.js";
11
+ export function resolveMessageRecipient(store, taskId, roleName, scope) {
12
+ if (scope.reviewRoundId !== undefined) {
13
+ const round = store.getReviewRound(taskId, scope.reviewRoundId);
14
+ if (round === null)
15
+ throw new Error("ReviewRound is unavailable in this Task.");
16
+ if (scope.workItemId !== undefined && scope.workItemId !== round.workItemId)
17
+ throw new Error("ReviewRound WorkItem scope mismatch.");
18
+ scope = { reviewRoundId: scope.reviewRoundId, ...(round.workItemId === undefined ? {} : { workItemId: round.workItemId }) };
19
+ }
20
+ if (scope.workItemId === undefined && scope.reviewRoundId === undefined) {
21
+ throw new Error("Recipient requires --work-item or --review-round; Message does not establish an Assignment.");
22
+ }
23
+ const previous = store.listRuns(taskId).filter((run) => run.roleName === roleName && run.workItemId === scope.workItemId
24
+ && run.reviewRoundId === scope.reviewRoundId).at(-1);
25
+ if (previous === undefined)
26
+ throw new Error("No existing Dispatch owns this Role and work scope.");
27
+ return { roleName, ownerRunId: previous.id, ...scope };
28
+ }
29
+ /** Bounded diagnosis, not automatic ownership repair. */
30
+ export function messageContinuationBlocker(store, message) {
31
+ const target = message.recipient;
32
+ if (target?.ownerRunId === undefined)
33
+ return "recipient-assignment-missing";
34
+ const task = store.getTask(message.taskId);
35
+ if (task?.status !== "active")
36
+ return `task-${task?.status ?? "missing"}`;
37
+ if (task.executionGate.state !== "enabled")
38
+ return "execution-disabled";
39
+ const owner = store.getRun(message.taskId, target.ownerRunId);
40
+ if (owner === null || owner.roleName !== target.roleName || owner.workItemId !== target.workItemId
41
+ || owner.reviewRoundId !== target.reviewRoundId)
42
+ return "owner-assignment-mismatch";
43
+ if (owner.result?.failureReason === "delivery-unknown")
44
+ return "owner-acceptance-unknown";
45
+ if (owner.executionGroupId !== undefined || owner.sourceExecutionGroupId !== undefined) {
46
+ return "replicated-assignment-requires-explicit-dispatch";
47
+ }
48
+ if (target.workItemId !== undefined) {
49
+ const work = store.getWorkItem(message.taskId, target.workItemId);
50
+ if (work?.status !== "open")
51
+ return `work-item-${work?.status ?? "missing"}`;
52
+ if (target.reviewRoundId === undefined && work.assignee !== target.roleName)
53
+ return "owner-changed";
54
+ if (target.reviewRoundId === undefined && !isDeepStrictEqual([...work.writeProjectIds].sort(), [...owner.effective.writeProjectIds].sort()))
55
+ return "assignment-scope-changed";
56
+ if (target.reviewRoundId === undefined && owner.workspace !== undefined) {
57
+ const workspace = target.roleName === "leader"
58
+ ? store.getTaskWorkspace(message.taskId) : store.getWorkItemWorkspace(message.taskId, target.workItemId);
59
+ const identity = (entries) => entries.map((entry) => ({
60
+ projectId: entry.projectId, path: entry.path, access: entry.access, branch: entry.branch
61
+ }));
62
+ if (workspace?.root !== owner.workspace.root
63
+ || !isDeepStrictEqual(identity(workspace.entries), identity(owner.workspace.entries))) {
64
+ return "assignment-workspace-changed";
65
+ }
66
+ }
67
+ const ownershipAt = message.handovers?.at(-1)?.at ?? message.createdAt;
68
+ if (target.reviewRoundId === undefined && store.listEvents(message.taskId).some((event) => event.type === "work.edited" && event.payload.workItemId === target.workItemId
69
+ && event.payload.fields?.split(",").includes("assignee")
70
+ && event.createdAt > ownershipAt && event.payload.previous !== event.payload.current))
71
+ return "owner-changed";
72
+ }
73
+ const latest = store.listRuns(message.taskId).filter((run) => run.workItemId === owner.workItemId && run.reviewRoundId === owner.reviewRoundId
74
+ && run.roleName === owner.roleName).at(-1);
75
+ if (latest !== undefined && latest.id !== owner.id
76
+ && latest.inputs[0]?.input.source.channel !== "message-continuation")
77
+ return "assignment-changed";
78
+ if (target.reviewRoundId !== undefined) {
79
+ const round = store.getReviewRound(message.taskId, target.reviewRoundId);
80
+ if (round === null)
81
+ return "review-round-missing";
82
+ if ((round.scope ?? "work-item") === "task") {
83
+ if (round.taskCandidate?.projects.some((project) => task.projectBindings.find((binding) => binding.projectId === project.projectId)?.currentCommit !== project.commit)) {
84
+ return "review-candidate-stale";
85
+ }
86
+ }
87
+ else {
88
+ const item = store.getWorkItem(message.taskId, round.workItemId);
89
+ if (item?.candidates.at(-1)?.id !== round.candidateId)
90
+ return "review-candidate-stale";
91
+ }
92
+ const validation = validateExactRunReviewRound(store, latest ?? owner, { allowTerminal: true });
93
+ if (validation.disposition !== "applied")
94
+ return validation.reason ?? "review-candidate-stale";
95
+ }
96
+ return undefined;
97
+ }
98
+ /** Called in the Controller's ordinary reconciliation transaction. Messages
99
+ * remain the pending authority; Mailbox is only the existing scheduling hint.
100
+ * Reserving inputs and creating the next Run is one atomic effect. */
101
+ export function prepareMessageContinuations(store, taskId, now, roleName) {
102
+ const pending = store.listMessages(taskId).filter((message) => message.recipient?.roleName === roleName && message.recipient.ownerRunId !== undefined
103
+ && message.continuation?.runId === undefined);
104
+ for (const message of pending) {
105
+ const recipient = message.recipient;
106
+ const blocker = messageContinuationBlocker(store, message);
107
+ if (blocker !== undefined) {
108
+ markNotDelivered(store, message, blocker);
109
+ continue;
110
+ }
111
+ if (store.getActiveRun(taskId, recipient.roleName) !== null)
112
+ continue;
113
+ const owner = store.getRun(taskId, recipient.ownerRunId);
114
+ const sessions = store.getTaskRoleSessionSet(taskId, recipient.roleName);
115
+ const session = sessions?.sessions[owner.effective.agentId];
116
+ const provider = sessions?.providerBinding;
117
+ if (provider?.authority.owner === "human" || provider?.authority.owner === "unknown"
118
+ || (provider?.run !== null && provider?.run !== undefined
119
+ && ["submitting", "accepted", "delivery-unknown"].includes(provider.run.status)))
120
+ continue;
121
+ if (session?.status !== "active" || sessions?.activeAgentId !== owner.effective.agentId
122
+ || store.getRole(taskId, recipient.roleName)?.activeAgentId !== owner.effective.agentId
123
+ || !roleSessionMayContinue(session.effective, owner.effective)) {
124
+ markNotDelivered(store, message, "compatible-session-unavailable");
125
+ continue;
126
+ }
127
+ // Reuse the same current-Session authority gate as Task-local actions.
128
+ // Matching Agent/effective flags alone do not undo explicit revocation.
129
+ requireManagedTaskCaller(store, {
130
+ YUI_SESSION_SCOPE: "task", YUI_TASK_ID: taskId, YUI_ROLE: recipient.roleName,
131
+ YUI_NATIVE_SESSION_ID: session.nativeSessionId, YUI_WORKSPACE: owner.effective.workspace.root
132
+ });
133
+ const originalNativeSessionId = store.listEvents(taskId).filter((event) => event.type === "run.session-prepared"
134
+ && event.payload.runId === owner.id && event.payload.roleName === owner.roleName)
135
+ .at(-1)?.payload.nativeSessionId ?? owner.result?.provider?.conversationId;
136
+ if (originalNativeSessionId === undefined || originalNativeSessionId !== session.nativeSessionId) {
137
+ markNotDelivered(store, message, originalNativeSessionId === undefined
138
+ ? "owner-session-unobserved" : "owner-session-changed");
139
+ continue;
140
+ }
141
+ const batch = pending.filter((entry) => isDeepStrictEqual(entry.recipient, recipient)
142
+ && messageContinuationBlocker(store, entry) === undefined).slice(0, 16);
143
+ const previous = store.listRuns(taskId).filter((run) => run.roleName === owner.roleName
144
+ && run.workItemId === owner.workItemId && run.reviewRoundId === owner.reviewRoundId).at(-1);
145
+ const baselineRef = previous.inputs[0]?.input.contextSnapshotRef;
146
+ const baseline = baselineRef === undefined ? null : store.getContextSnapshot(taskId, baselineRef.id);
147
+ if (baseline === null || baseline.digest !== baselineRef.digest) {
148
+ markNotDelivered(store, message, "assignment-context-unavailable");
149
+ continue;
150
+ }
151
+ const runId = store.nextRunId(taskId);
152
+ const round = owner.reviewRoundId === undefined ? null : store.getReviewRound(taskId, owner.reviewRoundId);
153
+ const continuingRound = round === null ? null : (() => {
154
+ const { endedAt: _endedAt, failure: _failure, ...current } = round;
155
+ return { ...current, status: "running", reviewerRunId: runId };
156
+ })();
157
+ const priorMessages = baseline.resources.filter((entry) => entry.ref.store === "task-message").slice(-16);
158
+ const source = sourceRunContextValue(previous);
159
+ const resources = [...baseline.resources.filter((entry) => entry.ref.store !== "task-message" && entry.ref.store !== "source-run"
160
+ && !(continuingRound !== null && entry.ref.store === "review-round" && entry.ref.refId === continuingRound.id)),
161
+ ...(continuingRound === null ? [] : [{ ref: { layer: "L3", store: "review-round",
162
+ refId: continuingRound.id, revision: now.toISOString(), digest: contextContentDigest(continuingRound),
163
+ summary: `ReviewRound ${continuingRound.id}` }, value: continuingRound }]),
164
+ ...priorMessages,
165
+ { ref: { layer: "L4", store: "source-run", refId: previous.id,
166
+ revision: previous.updatedAt, digest: contextContentDigest(source), summary: `Previous result ${previous.id}` }, value: source },
167
+ ...batch.map((entry) => ({
168
+ ref: { layer: "L4", store: "task-message", refId: entry.id,
169
+ revision: entry.createdAt, digest: contextContentDigest(entry), summary: `Message ${entry.id}` },
170
+ value: entry
171
+ }))];
172
+ const latestSnapshot = store.listContextSnapshots(taskId).filter((entry) => entry.scope === baseline.scope && entry.scopeRef === baseline.scopeRef).at(-1);
173
+ const snapshot = createContextSnapshot({
174
+ ...baseline, id: store.nextContextSnapshotId(taskId),
175
+ sequence: (latestSnapshot?.sequence ?? baseline.sequence) + 1,
176
+ parentRef: contextSnapshotRef(baseline), frozenAt: now, frozenBy: "controller",
177
+ resources, refs: resources.map(({ ref }) => ref)
178
+ });
179
+ store.saveContextSnapshot(snapshot);
180
+ const run = withRunContextSnapshot(createRun(runId, taskId, recipient.roleName, "resume", createRunInput({ source: { type: "yui", channel: "message-continuation" },
181
+ directive: `Continue the same Assignment in its existing workspace. Read Messages ${batch.map((m) => m.id).join(", ")} from this exact Context. Message receipt is not implementation or acceptance.`,
182
+ deltaRefIds: batch.map((entry) => entry.id) }), now, copyAssignment(owner)), contextSnapshotRef(snapshot), batch.map((entry) => entry.id));
183
+ store.saveRun(run);
184
+ store.saveActiveRun(run);
185
+ if (continuingRound !== null)
186
+ store.saveReviewRound(taskId, continuingRound);
187
+ for (const entry of batch)
188
+ store.updateMessage(taskId, { ...entry, continuation: { runId } });
189
+ enqueueRoleRunDispatch(store, { taskId, roleName: run.roleName, runId,
190
+ reason: "message-continuation", occurredAt: now });
191
+ store.saveEvent(taskId, createTaskEvent(store.nextEventId(taskId), taskId, "message.continuation", { runId, roleName: run.roleName, messageIds: batch.map((entry) => entry.id).join(",") }, now));
192
+ }
193
+ }
194
+ function copyAssignment(run) {
195
+ return { purpose: run.purpose, effective: run.effective,
196
+ ...(run.workItemId === undefined ? {} : { workItemId: run.workItemId }),
197
+ ...(run.reviewRoundId === undefined ? {} : { reviewRoundId: run.reviewRoundId }),
198
+ ...(run.workspace === undefined ? {} : { workspace: run.workspace }) };
199
+ }
200
+ function markNotDelivered(store, message, reason) {
201
+ if (message.continuation?.notDeliveredReason === reason)
202
+ return;
203
+ store.updateMessage(message.taskId, { ...message, continuation: { notDeliveredReason: reason } });
204
+ }
@@ -2,7 +2,7 @@
2
2
  * Read-only execution audit aggregator (Issue 11 §3).
3
3
  *
4
4
  * The audit answers "what happened in this Home" from durable records alone:
5
- * Turns/failures/durations, wake reasons, Runtime generations, Review execution
5
+ * AgentRuns/failures/durations, wake reasons, Runtime count, Review execution
6
6
  * vs semantic failures, Integration failure classes and gate reuse, telemetry
7
7
  * volume, and the longest/stale executions. It never writes Task state, never
8
8
  * wakes a Leader, and never takes the storage write lock — it only calls the
@@ -15,7 +15,7 @@ import { join } from "node:path";
15
15
  import { openCurrentTaskStore } from "../storage/currentTaskStore.js";
16
16
  import { resolveTaskStoreBackendForHome } from "../storage/sqliteStore.js";
17
17
  import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.js";
18
- import { classifyTurnFailure, classifyIntegrationAttempt, classifyReviewRound, countFaultClasses } from "./faultClassification.js";
18
+ import { classifyRunFailure, classifyIntegrationAttempt, classifyReviewRound, countFaultClasses } from "./faultClassification.js";
19
19
  import { RUNTIME_LAUNCH_KINDS, RUNTIME_LAUNCH_PHASES } from "../runtime/launchDiagnostics.js";
20
20
  import { UNSUPPORTED } from "./runtimeIdentity.js";
21
21
  import { projectTaskOrchestration } from "./orchestrationMetrics.js";
@@ -86,10 +86,10 @@ function roleBucket(roleName) {
86
86
  }
87
87
  return "other";
88
88
  }
89
- function durationMs(turn) {
90
- if (turn.result === undefined)
89
+ function durationMs(run) {
90
+ if (run.result === undefined)
91
91
  return 0;
92
- return Math.max(0, Date.parse(turn.result.completedAt) - Date.parse(turn.createdAt));
92
+ return Math.max(0, Date.parse(run.result.completedAt) - Date.parse(run.createdAt));
93
93
  }
94
94
  function emptyLaunchFailureCounts() {
95
95
  const counts = {
@@ -116,35 +116,35 @@ function addLaunchFailureCounts(counts, summary) {
116
116
  }
117
117
  /**
118
118
  * Issue 09: classify a terminal Session (stopped/broken) by its relationship
119
- * to the last Turn it carried. Turns and Sessions are separate axes: a Session
120
- * that stops after its Turn completed is a post-completion stop, not a Turn
119
+ * to the last AgentRun it carried. AgentRuns and Sessions are separate axes: a Session
120
+ * that stops after its AgentRun completed is a post-completion stop, not a AgentRun
121
121
  * failure. Correlation is by Role + Agent + Adapter (the durable identity a
122
- * Turn and its Session share) and the Session's terminal update timestamp.
122
+ * AgentRun and its Session share) and the Session's terminal update timestamp.
123
123
  */
124
- function classifyTerminalSessionTurnRelation(turns, roleName, session, counts) {
124
+ function classifyTerminalSessionRunRelation(runs, roleName, session, counts) {
125
125
  const terminalAt = Date.parse(session.updatedAt);
126
- const carried = turns
127
- .filter((turn) => (turn.roleName === roleName
128
- && turn.effective.agentId === session.agentId
129
- && turn.effective.adapterId === session.adapterId
130
- && Date.parse(turn.createdAt) <= terminalAt))
126
+ const carried = runs
127
+ .filter((run) => (run.roleName === roleName
128
+ && run.effective.agentId === session.agentId
129
+ && run.effective.adapterId === session.adapterId
130
+ && Date.parse(run.createdAt) <= terminalAt))
131
131
  .sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt));
132
- const lastTurn = carried[0];
133
- if (lastTurn === undefined) {
134
- counts.noTurn += 1;
132
+ const lastRun = carried[0];
133
+ if (lastRun === undefined) {
134
+ counts.noRun += 1;
135
135
  return;
136
136
  }
137
- if (lastTurn.status === "completed"
138
- && lastTurn.result !== undefined
139
- && Date.parse(lastTurn.result.completedAt) <= terminalAt) {
140
- counts.postTurnCompleted += 1;
137
+ if (lastRun.status === "completed"
138
+ && lastRun.result !== undefined
139
+ && Date.parse(lastRun.result.completedAt) <= terminalAt) {
140
+ counts.postRunCompleted += 1;
141
141
  return;
142
142
  }
143
- if (lastTurn.status === "failed") {
144
- counts.turnFailed += 1;
143
+ if (lastRun.status === "failed") {
144
+ counts.runFailed += 1;
145
145
  return;
146
146
  }
147
- counts.activeTurn += 1;
147
+ counts.activeRun += 1;
148
148
  }
149
149
  function ok(data) {
150
150
  return { status: "ok", data };
@@ -182,7 +182,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
182
182
  homeIdentity: UNSUPPORTED,
183
183
  scope,
184
184
  tasks: section,
185
- turns: section,
185
+ runs: section,
186
186
  wakes: section,
187
187
  sessions: section,
188
188
  reviews: section,
@@ -228,7 +228,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
228
228
  return failed(error);
229
229
  }
230
230
  })();
231
- const turns = (() => {
231
+ const runs = (() => {
232
232
  try {
233
233
  let total = 0;
234
234
  let active = 0;
@@ -241,30 +241,30 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
241
241
  const failures = [];
242
242
  const launchFailures = emptyLaunchFailureCounts();
243
243
  for (const taskId of taskIds) {
244
- for (const turn of store.listTurns(taskId)) {
245
- if (!inWindow(turn.createdAt, options))
244
+ for (const run of store.listRuns(taskId)) {
245
+ if (!inWindow(run.createdAt, options))
246
246
  continue;
247
247
  total += 1;
248
- byRole[roleBucket(turn.roleName)] += 1;
249
- if (turn.purpose === "review")
248
+ byRole[roleBucket(run.roleName)] += 1;
249
+ if (run.purpose === "review")
250
250
  byPurpose.review += 1;
251
251
  else
252
252
  byPurpose.execution += 1;
253
- const duration = durationMs(turn);
254
- if (turn.status === "active") {
253
+ const duration = durationMs(run);
254
+ if (run.status === "active") {
255
255
  active += 1;
256
- cumulativeDurationMs += Math.max(0, Date.now() - Date.parse(turn.createdAt));
256
+ cumulativeDurationMs += Math.max(0, Date.now() - Date.parse(run.createdAt));
257
257
  }
258
- else if (turn.status === "completed") {
258
+ else if (run.status === "completed") {
259
259
  completed += 1;
260
260
  cumulativeDurationMs += duration;
261
261
  }
262
- else if (turn.status === "failed") {
262
+ else if (run.status === "failed") {
263
263
  failedCount += 1;
264
264
  failedDurationMs += duration;
265
265
  cumulativeDurationMs += duration;
266
- addLaunchFailureCounts(launchFailures, turn.result?.diagnostic);
267
- failures.push(classifyTurnFailure(turn));
266
+ addLaunchFailureCounts(launchFailures, run.result?.diagnostic);
267
+ failures.push(classifyRunFailure(run));
268
268
  }
269
269
  }
270
270
  }
@@ -288,18 +288,18 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
288
288
  })();
289
289
  const wakes = (() => {
290
290
  try {
291
- let leaderTurns = 0;
291
+ let leaderRuns = 0;
292
292
  let withWakeReasons = 0;
293
293
  let suppressedWakes = 0;
294
294
  const byReason = new Map();
295
295
  for (const taskId of taskIds) {
296
- for (const turn of store.listTurns(taskId)) {
297
- if (turn.roleName !== "leader")
296
+ for (const run of store.listRuns(taskId)) {
297
+ if (run.roleName !== "leader")
298
298
  continue;
299
- if (!inWindow(turn.createdAt, options))
299
+ if (!inWindow(run.createdAt, options))
300
300
  continue;
301
- leaderTurns += 1;
302
- const match = WAKE_REASON_PATTERN.exec(turn.inputs[0].input.directive ?? "");
301
+ leaderRuns += 1;
302
+ const match = WAKE_REASON_PATTERN.exec(run.inputs[0].input.directive ?? "");
303
303
  if (match === null)
304
304
  continue;
305
305
  withWakeReasons += 1;
@@ -317,12 +317,12 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
317
317
  }
318
318
  }
319
319
  return ok({
320
- leaderTurns,
320
+ leaderRuns,
321
321
  withWakeReasons,
322
322
  byReason: Object.fromEntries([...byReason.entries()].sort((left, right) => right[1] - left[1])),
323
323
  // Scheduler single-flight suppression: wakes that were coalesced
324
324
  // because the Role runtime lifecycle lane was busy. These are
325
- // scheduler outcomes, never failed Turns.
325
+ // scheduler outcomes, never failed AgentRuns.
326
326
  suppressedWakes: { status: "ok", data: suppressedWakes }
327
327
  });
328
328
  }
@@ -332,7 +332,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
332
332
  })();
333
333
  const sessions = (() => {
334
334
  try {
335
- let generations = 0;
335
+ let count = 0;
336
336
  let broken = 0;
337
337
  let stopped = 0;
338
338
  let other = 0;
@@ -340,18 +340,18 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
340
340
  let conversationSwitches = 0;
341
341
  let lifecycleEvents = 0;
342
342
  let stopFailures = 0;
343
- const terminalByTurnRelation = {
344
- postTurnCompleted: 0,
345
- turnFailed: 0,
346
- activeTurn: 0,
347
- noTurn: 0
343
+ const terminalByRunRelation = {
344
+ postRunCompleted: 0,
345
+ runFailed: 0,
346
+ activeRun: 0,
347
+ noRun: 0
348
348
  };
349
349
  for (const taskId of taskIds) {
350
- const turns = store.listTurns(taskId);
350
+ const runs = store.listRuns(taskId);
351
351
  for (const set of store.listRoleSessionSets(taskId)) {
352
352
  const history = Array.isArray(set.history) ? set.history : [];
353
353
  for (const session of [...history, ...Object.values(set.sessions)]) {
354
- generations += 1;
354
+ count += 1;
355
355
  if (session.status === "ended" && session.endReason === "failed")
356
356
  broken += 1;
357
357
  else if (session.status === "ended")
@@ -359,7 +359,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
359
359
  else
360
360
  other += 1;
361
361
  if (session.status === "ended") {
362
- classifyTerminalSessionTurnRelation(turns, set.owner.roleName, session, terminalByTurnRelation);
362
+ classifyTerminalSessionRunRelation(runs, set.owner.roleName, session, terminalByRunRelation);
363
363
  }
364
364
  }
365
365
  }
@@ -379,7 +379,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
379
379
  }
380
380
  }
381
381
  return ok({
382
- generations,
382
+ count,
383
383
  broken,
384
384
  stopped,
385
385
  other,
@@ -387,7 +387,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
387
387
  conversationSwitches,
388
388
  lifecycleEvents,
389
389
  stopFailures,
390
- terminalByTurnRelation
390
+ terminalByRunRelation
391
391
  });
392
392
  }
393
393
  catch (error) {
@@ -577,7 +577,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
577
577
  entries.push({
578
578
  taskId,
579
579
  eventId: event.id,
580
- turnId: event.payload.turnId ?? "",
580
+ runId: event.payload.runId ?? "",
581
581
  roleName: event.payload.roleName ?? "",
582
582
  source: event.payload.source ?? "unknown",
583
583
  phase: event.payload.phase ?? "unknown",
@@ -591,8 +591,6 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
591
591
  registrationDisposition: event.payload.registrationDisposition,
592
592
  errorName: event.payload.errorName,
593
593
  causeName: event.payload.causeName,
594
- expectedRuntimeGenerationId: event.payload.expectedRuntimeGenerationId,
595
- observedRuntimeGenerationId: event.payload.observedRuntimeGenerationId,
596
594
  attemptId: event.payload.attemptId
597
595
  }),
598
596
  createdAt: event.createdAt
@@ -619,7 +617,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
619
617
  if (!inWindow(item.createdAt, options))
620
618
  continue;
621
619
  total += 1;
622
- if (item.status === "completed")
620
+ if (item.status === "accepted")
623
621
  completed += 1;
624
622
  else if (item.status === "retired")
625
623
  retired += 1;
@@ -639,7 +637,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
639
637
  return [];
640
638
  return [projectTaskOrchestration({
641
639
  task,
642
- turns: withinWindow(store.listTurns(taskId), options),
640
+ runs: withinWindow(store.listRuns(taskId), options),
643
641
  roleSessionSets: sessionSetsWithinWindow(store.listRoleSessionSets(taskId), options),
644
642
  workItems: withinWindow(store.listWorkItems(taskId), options),
645
643
  changeSets: withinWindow(store.listChangeSets(taskId), options),
@@ -704,7 +702,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
704
702
  let processExitObservations = 0;
705
703
  let compactionEvents = 0;
706
704
  for (const taskId of taskIds) {
707
- for (const run of store.listTurns(taskId)) {
705
+ for (const run of store.listRuns(taskId)) {
708
706
  if (!inWindow(run.createdAt, options))
709
707
  continue;
710
708
  const version = String(run.effective.contextProtocolVersion);
@@ -756,21 +754,21 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
756
754
  try {
757
755
  const entries = [];
758
756
  for (const taskId of taskIds) {
759
- for (const turn of store.listTurns(taskId)) {
760
- if (!inWindow(turn.createdAt, options))
757
+ for (const run of store.listRuns(taskId)) {
758
+ if (!inWindow(run.createdAt, options))
761
759
  continue;
762
- const duration = turn.status === "active"
763
- ? Math.max(0, Date.now() - Date.parse(turn.createdAt))
764
- : durationMs(turn);
760
+ const duration = run.status === "active"
761
+ ? Math.max(0, Date.now() - Date.parse(run.createdAt))
762
+ : durationMs(run);
765
763
  if (duration <= 0)
766
764
  continue;
767
765
  entries.push({
768
766
  taskId,
769
- turnId: turn.id,
770
- roleName: turn.roleName,
771
- status: turn.status,
767
+ runId: run.id,
768
+ roleName: run.roleName,
769
+ status: run.status,
772
770
  durationMs: duration,
773
- startedAt: turn.createdAt
771
+ startedAt: run.createdAt
774
772
  });
775
773
  }
776
774
  }
@@ -788,7 +786,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
788
786
  homeIdentity,
789
787
  scope,
790
788
  tasks,
791
- turns,
789
+ runs,
792
790
  wakes,
793
791
  sessions,
794
792
  reviews,
@@ -20,8 +20,8 @@ function excerpt(text, max = 160) {
20
20
  const normalized = text.replace(/\s+/g, " ").trim();
21
21
  return normalized.length <= max ? normalized : `${normalized.slice(0, max)}…`;
22
22
  }
23
- /** Classify a failed Turn without inspecting Agent-authored output. */
24
- export function classifyTurnFailure(run) {
23
+ /** Classify a failed AgentRun without inspecting Agent-authored output. */
24
+ export function classifyRunFailure(run) {
25
25
  if (run.status !== "failed")
26
26
  return NO_FAULT;
27
27
  const failureReason = run.result?.failureReason;
@@ -1,5 +1,5 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
- import { isCompletedReviewExecutionFromTurns } from "../review/reviewAcceptance.js";
2
+ import { isCompletedReviewExecutionFromRuns } from "../review/reviewAcceptance.js";
3
3
  import { projectFirstProgressAdvisory } from "../runtime/firstProgressAdvisory.js";
4
4
  /** One Task's orchestration cost and advisory projection, with no writes. */
5
5
  export function projectTaskOrchestration(facts) {
@@ -48,10 +48,10 @@ export function projectTaskOrchestration(facts) {
48
48
  timeToFirstProjectCommitMs: firstCommitAt === undefined
49
49
  ? null
50
50
  : Math.max(0, Date.parse(firstCommitAt) - Date.parse(facts.task.createdAt)),
51
- turns: {
52
- total: facts.turns.length,
53
- byStatus: counts(facts.turns.map(({ status }) => status)),
54
- byRole: counts(facts.turns.map(({ roleName }) => roleName))
51
+ runs: {
52
+ total: facts.runs.length,
53
+ byStatus: counts(facts.runs.map(({ status }) => status)),
54
+ byRole: counts(facts.runs.map(({ roleName }) => roleName))
55
55
  },
56
56
  workItems: facts.workItems.length,
57
57
  reviews: {
@@ -65,7 +65,7 @@ export function projectTaskOrchestration(facts) {
65
65
  repeatedIdentities,
66
66
  evidenceReuses: facts.integrations.filter((attempt) => ((attempt.checks ?? []).some(({ details }) => details?.startsWith("Reused successful check evidence from ")))).length
67
67
  },
68
- providerGenerationsBeforeFirstProgress: firstProgress.generationsBeforeFirstProgress,
68
+ providerSessionsBeforeFirstProgress: firstProgress.sessionsBeforeFirstProgress,
69
69
  publicationToCompletionMs: publicationAt === undefined || facts.task.completedAt === undefined
70
70
  ? null
71
71
  : Math.max(0, Date.parse(facts.task.completedAt) - Date.parse(publicationAt)),
@@ -91,7 +91,7 @@ function projectAdvisories(facts, fullRounds, repeatedIdentities, firstProgressA
91
91
  .map(({ id }) => `durable-job:${id}`)
92
92
  });
93
93
  }
94
- const completedFull = fullRounds.filter((round) => (isCompletedReviewExecutionFromTurns(round, facts.turns)))
94
+ const completedFull = fullRounds.filter((round) => (isCompletedReviewExecutionFromRuns(round, facts.runs)))
95
95
  .sort((left, right) => left.createdAt.localeCompare(right.createdAt));
96
96
  const recent = completedFull.slice(-3);
97
97
  const sameCandidate = recent.length === 3
@@ -108,7 +108,7 @@ function projectAdvisories(facts, fullRounds, repeatedIdentities, firstProgressA
108
108
  if (firstProgressAttention) {
109
109
  result.push({
110
110
  code: "provider-first-progress-advisory",
111
- reason: "Two fresh Leader generations produced no first durable progress; consider Operator attention before another generation.",
111
+ reason: "Two fresh Leader Sessions produced no first durable progress; consider Operator attention before another Session.",
112
112
  refs: [facts.task.id]
113
113
  });
114
114
  }
@@ -1,3 +1,4 @@
1
+ import { agentAdapterLabel as adapterLabel } from "../agent/adapterCatalog.js";
1
2
  import { normalizeRoleAgentSessionText, roleAgentSessionRef, validateRoleSessionSet } from "../executor/agentExecutor.js";
2
3
  /** Separates the one selected writer authority from retained conversations. */
3
4
  export function projectOperatorStatus(sessions, activeAgentId, activeAdapterId) {
@@ -141,13 +142,6 @@ function optionalDisplayText(value) {
141
142
  const normalized = normalizeRoleAgentSessionText(value);
142
143
  return normalized.length === 0 ? undefined : normalized;
143
144
  }
144
- function adapterLabel(adapterId) {
145
- return adapterId === "codex"
146
- ? "Codex"
147
- : adapterId === "claude"
148
- ? "Claude"
149
- : adapterId;
150
- }
151
145
  function requireText(value, label) {
152
146
  if (typeof value !== "string" || value.includes("\0") || value.trim().length === 0) {
153
147
  throw new Error(`${label} is required.`);
@@ -1,4 +1,5 @@
1
1
  import { renderAgentConfigurationResolutionNotice } from "../cli/agentConfigurationPicker.js";
2
+ import { agentHandshakeLine } from "./agentRunConfigurationPresentation.js";
2
3
  import { defaultTableWidth, renderTable } from "./table.js";
3
4
  export function renderAgentConfigurationCatalog(resolved) {
4
5
  const { catalog } = resolved;
@@ -11,13 +12,17 @@ export function renderAgentConfigurationCatalog(resolved) {
11
12
  model.serviceTiers?.map((tier) => tier.value).join(", ") || "none reported"
12
13
  ]);
13
14
  const fieldRows = catalog.fields
14
- .filter((field) => field.key !== "model" && field.key !== "effort")
15
+ .filter((field) => modelRows.length === 0 || (field.key !== "model" && field.key !== "effort"))
15
16
  .map((field) => [
16
17
  field.key,
17
18
  field.choices.map((choice) => choice.value).join(", ") || "none reported",
19
+ // An available field can still carry a reason, and for ACP it always does:
20
+ // the values are enumerated per Session, so the probe deliberately lists
21
+ // none. Dropping that sentence left "none reported" looking like a failed
22
+ // query rather than a deliberate boundary, so it is shown either way.
18
23
  field.available === false
19
24
  ? `unavailable${field.reason === undefined ? "" : `: ${field.reason}`}`
20
- : "available",
25
+ : field.reason === undefined ? "available" : `available: ${field.reason}`,
21
26
  field.allowCustom ? "yes" : "no"
22
27
  ]);
23
28
  const sections = [
@@ -39,5 +44,5 @@ export function renderAgentConfigurationCatalog(resolved) {
39
44
  { header: "Custom", minWidth: 6, maxWidth: 8 }
40
45
  ], fieldRows, defaultTableWidth())])
41
46
  ];
42
- return `${sections.join("\n\n")}\n${renderAgentConfigurationResolutionNotice(resolved)}`;
47
+ return `${sections.join("\n\n")}\n${agentHandshakeLine(catalog.handshake)}\n${renderAgentConfigurationResolutionNotice(resolved)}`;
43
48
  }