@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
@@ -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
- * Runs/failures/durations, wake reasons, Session generations, Review execution
5
+ * Turns/failures/durations, wake reasons, Session generations, 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
@@ -12,16 +12,16 @@
12
12
  */
13
13
  import { readdirSync, statSync } from "node:fs";
14
14
  import { join } from "node:path";
15
- import { openCompatibleFileTaskStore } from "../storage/compatibleTaskStore.js";
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 { classifyAgentRunFailure, classifyIntegrationAttempt, classifyReviewRound, classifyWakeReasons, countFaultClasses } from "./faultClassification.js";
18
+ import { classifyTurnFailure, 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";
22
22
  export function createProductionExecutionAuditPorts() {
23
23
  return {
24
- openStore: (home) => openCompatibleFileTaskStore(home),
24
+ openStore: (home) => openCurrentTaskStore(home),
25
25
  directorySize: (path) => directorySizeBytes(path)
26
26
  };
27
27
  }
@@ -86,10 +86,10 @@ function roleBucket(roleName) {
86
86
  }
87
87
  return "other";
88
88
  }
89
- function durationMs(run) {
90
- if (run.endedAt === undefined)
89
+ function durationMs(turn) {
90
+ if (turn.result === undefined)
91
91
  return 0;
92
- return Math.max(0, Date.parse(run.endedAt) - Date.parse(run.createdAt));
92
+ return Math.max(0, Date.parse(turn.result.completedAt) - Date.parse(turn.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 Run it carried. Runs and Sessions are separate axes: a Session
120
- * that stops after its Run yielded is a post-completion stop, not a Run
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
121
121
  * failure. Correlation is by Role + Agent + Adapter (the durable identity a
122
- * Run and its Session share) and the Session's terminal update timestamp.
122
+ * Turn and its Session share) and the Session's terminal update timestamp.
123
123
  */
124
- function classifyTerminalSessionRunRelation(runs, roleName, session, counts) {
124
+ function classifyTerminalSessionTurnRelation(turns, roleName, session, counts) {
125
125
  const terminalAt = Date.parse(session.updatedAt);
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))
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))
131
131
  .sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt));
132
- const lastRun = carried[0];
133
- if (lastRun === undefined) {
134
- counts.noRun += 1;
132
+ const lastTurn = carried[0];
133
+ if (lastTurn === undefined) {
134
+ counts.noTurn += 1;
135
135
  return;
136
136
  }
137
- if (lastRun.status === "yielded"
138
- && lastRun.endedAt !== undefined
139
- && Date.parse(lastRun.endedAt) <= terminalAt) {
140
- counts.postRunYielded += 1;
137
+ if (lastTurn.status === "completed"
138
+ && lastTurn.result !== undefined
139
+ && Date.parse(lastTurn.result.completedAt) <= terminalAt) {
140
+ counts.postTurnCompleted += 1;
141
141
  return;
142
142
  }
143
- if (lastRun.status === "failed") {
144
- counts.runFailed += 1;
143
+ if (lastTurn.status === "failed") {
144
+ counts.turnFailed += 1;
145
145
  return;
146
146
  }
147
- counts.activeRun += 1;
147
+ counts.activeTurn += 1;
148
148
  }
149
149
  function ok(data) {
150
150
  return { status: "ok", data };
@@ -156,7 +156,7 @@ function failed(error) {
156
156
  };
157
157
  }
158
158
  /**
159
- * Run the read-only audit. The store is opened once and only read methods are
159
+ * Execute the read-only audit. The store is opened once and only read methods are
160
160
  * called; no transaction, no Event, no Message, no wake is produced.
161
161
  */
162
162
  export function runExecutionAudit(home, options = {}, ports = createProductionExecutionAuditPorts()) {
@@ -178,7 +178,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
178
178
  homeIdentity: UNSUPPORTED,
179
179
  scope,
180
180
  tasks: section,
181
- runs: section,
181
+ turns: section,
182
182
  wakes: section,
183
183
  sessions: section,
184
184
  reviews: section,
@@ -224,11 +224,11 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
224
224
  return failed(error);
225
225
  }
226
226
  })();
227
- const runs = (() => {
227
+ const turns = (() => {
228
228
  try {
229
229
  let total = 0;
230
230
  let active = 0;
231
- let yielded = 0;
231
+ let completed = 0;
232
232
  let failedCount = 0;
233
233
  let cumulativeDurationMs = 0;
234
234
  let failedDurationMs = 0;
@@ -237,37 +237,37 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
237
237
  const failures = [];
238
238
  const launchFailures = emptyLaunchFailureCounts();
239
239
  for (const taskId of taskIds) {
240
- for (const run of store.listAgentRuns(taskId)) {
241
- if (!inWindow(run.createdAt, options))
240
+ for (const turn of store.listTurns(taskId)) {
241
+ if (!inWindow(turn.createdAt, options))
242
242
  continue;
243
243
  total += 1;
244
- byRole[roleBucket(run.roleName)] += 1;
245
- if (run.purpose === "review")
244
+ byRole[roleBucket(turn.roleName)] += 1;
245
+ if (turn.purpose === "review")
246
246
  byPurpose.review += 1;
247
247
  else
248
248
  byPurpose.execution += 1;
249
- const duration = durationMs(run);
250
- if (run.status === "active") {
249
+ const duration = durationMs(turn);
250
+ if (turn.status === "active") {
251
251
  active += 1;
252
- cumulativeDurationMs += Math.max(0, Date.now() - Date.parse(run.createdAt));
252
+ cumulativeDurationMs += Math.max(0, Date.now() - Date.parse(turn.createdAt));
253
253
  }
254
- else if (run.status === "yielded") {
255
- yielded += 1;
254
+ else if (turn.status === "completed") {
255
+ completed += 1;
256
256
  cumulativeDurationMs += duration;
257
257
  }
258
- else if (run.status === "failed") {
258
+ else if (turn.status === "failed") {
259
259
  failedCount += 1;
260
260
  failedDurationMs += duration;
261
261
  cumulativeDurationMs += duration;
262
- addLaunchFailureCounts(launchFailures, run.summary);
263
- failures.push(classifyAgentRunFailure(run));
262
+ addLaunchFailureCounts(launchFailures, turn.result?.output);
263
+ failures.push(classifyTurnFailure(turn));
264
264
  }
265
265
  }
266
266
  }
267
267
  return ok({
268
268
  total,
269
269
  active,
270
- yielded,
270
+ completed,
271
271
  failed: failedCount,
272
272
  failureRate: total === 0 ? 0 : failedCount / total,
273
273
  cumulativeDurationMs,
@@ -284,20 +284,18 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
284
284
  })();
285
285
  const wakes = (() => {
286
286
  try {
287
- let leaderRuns = 0;
287
+ let leaderTurns = 0;
288
288
  let withWakeReasons = 0;
289
- let orphanWakes = 0;
290
- let orphanYieldOnly = 0;
291
289
  let suppressedWakes = 0;
292
290
  const byReason = new Map();
293
291
  for (const taskId of taskIds) {
294
- for (const run of store.listAgentRuns(taskId)) {
295
- if (run.roleName !== "leader")
292
+ for (const turn of store.listTurns(taskId)) {
293
+ if (turn.roleName !== "leader")
296
294
  continue;
297
- if (!inWindow(run.createdAt, options))
295
+ if (!inWindow(turn.createdAt, options))
298
296
  continue;
299
- leaderRuns += 1;
300
- const match = WAKE_REASON_PATTERN.exec(run.assignment.directive ?? "");
297
+ leaderTurns += 1;
298
+ const match = WAKE_REASON_PATTERN.exec(turn.inputs[0].input.directive ?? "");
301
299
  if (match === null)
302
300
  continue;
303
301
  withWakeReasons += 1;
@@ -305,12 +303,6 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
305
303
  for (const reason of reasons) {
306
304
  byReason.set(reason, (byReason.get(reason) ?? 0) + 1);
307
305
  }
308
- if (classifyWakeReasons(reasons).faultClass
309
- === "scheduler-duplicate-suppressed-wake") {
310
- orphanWakes += 1;
311
- if (run.status === "yielded")
312
- orphanYieldOnly += 1;
313
- }
314
306
  }
315
307
  for (const event of store.listEvents(taskId)) {
316
308
  if (event.type !== "wake.suppressed")
@@ -321,14 +313,12 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
321
313
  }
322
314
  }
323
315
  return ok({
324
- leaderRuns,
316
+ leaderTurns,
325
317
  withWakeReasons,
326
- orphanWakes,
327
- orphanYieldOnly,
328
318
  byReason: Object.fromEntries([...byReason.entries()].sort((left, right) => right[1] - left[1])),
329
319
  // Scheduler single-flight suppression: wakes that were coalesced
330
320
  // because the Role runtime lifecycle lane was busy. These are
331
- // scheduler outcomes, never failed Runs.
321
+ // scheduler outcomes, never failed Turns.
332
322
  suppressedWakes: { status: "ok", data: suppressedWakes }
333
323
  });
334
324
  }
@@ -346,14 +336,14 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
346
336
  let conversationSwitches = 0;
347
337
  let lifecycleEvents = 0;
348
338
  let stopFailures = 0;
349
- const terminalByRunRelation = {
350
- postRunYielded: 0,
351
- runFailed: 0,
352
- activeRun: 0,
353
- noRun: 0
339
+ const terminalByTurnRelation = {
340
+ postTurnCompleted: 0,
341
+ turnFailed: 0,
342
+ activeTurn: 0,
343
+ noTurn: 0
354
344
  };
355
345
  for (const taskId of taskIds) {
356
- const runs = store.listAgentRuns(taskId);
346
+ const turns = store.listTurns(taskId);
357
347
  for (const set of store.listRoleSessionSets(taskId)) {
358
348
  const history = Array.isArray(set.history) ? set.history : [];
359
349
  for (const session of [...history, ...Object.values(set.sessions)]) {
@@ -365,7 +355,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
365
355
  else
366
356
  other += 1;
367
357
  if (session.status === "ended") {
368
- classifyTerminalSessionRunRelation(runs, set.owner.roleName, session, terminalByRunRelation);
358
+ classifyTerminalSessionTurnRelation(turns, set.owner.roleName, session, terminalByTurnRelation);
369
359
  }
370
360
  }
371
361
  }
@@ -393,7 +383,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
393
383
  conversationSwitches,
394
384
  lifecycleEvents,
395
385
  stopFailures,
396
- terminalByRunRelation
386
+ terminalByTurnRelation
397
387
  });
398
388
  }
399
389
  catch (error) {
@@ -602,7 +592,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
602
592
  entries.push({
603
593
  taskId,
604
594
  eventId: event.id,
605
- runId: event.payload.runId ?? "",
595
+ turnId: event.payload.turnId ?? "",
606
596
  roleName: event.payload.roleName ?? "",
607
597
  source: event.payload.source ?? "unknown",
608
598
  phase: event.payload.phase ?? "unknown",
@@ -656,7 +646,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
656
646
  return [];
657
647
  return [projectTaskOrchestration({
658
648
  task,
659
- runs: withinWindow(store.listAgentRuns(taskId), options),
649
+ turns: withinWindow(store.listTurns(taskId), options),
660
650
  roleSessionSets: sessionSetsWithinWindow(store.listRoleSessionSets(taskId), options),
661
651
  workItems: withinWindow(store.listWorkItems(taskId), options),
662
652
  changeSets: withinWindow(store.listChangeSets(taskId), options),
@@ -723,14 +713,12 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
723
713
  let processExitObservations = 0;
724
714
  let compactionEvents = 0;
725
715
  for (const taskId of taskIds) {
726
- for (const run of store.listAgentRuns(taskId)) {
716
+ for (const run of store.listTurns(taskId)) {
727
717
  if (!inWindow(run.createdAt, options))
728
718
  continue;
729
- const version = String(run.effective.contextProtocolVersion ?? "legacy");
719
+ const version = String(run.effective.contextProtocolVersion);
730
720
  protocolVersions.set(version, (protocolVersions.get(version) ?? 0) + 1);
731
- if (run.effective.sessionManifestCompatibilityDigest !== undefined) {
732
- manifestDigests.add(run.effective.sessionManifestCompatibilityDigest);
733
- }
721
+ manifestDigests.add(run.effective.sessionManifestCompatibilityDigest);
734
722
  }
735
723
  for (const event of store.listEvents(taskId)) {
736
724
  if (!inWindow(event.createdAt, options))
@@ -777,21 +765,21 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
777
765
  try {
778
766
  const entries = [];
779
767
  for (const taskId of taskIds) {
780
- for (const run of store.listAgentRuns(taskId)) {
781
- if (!inWindow(run.createdAt, options))
768
+ for (const turn of store.listTurns(taskId)) {
769
+ if (!inWindow(turn.createdAt, options))
782
770
  continue;
783
- const duration = run.status === "active"
784
- ? Math.max(0, Date.now() - Date.parse(run.createdAt))
785
- : durationMs(run);
771
+ const duration = turn.status === "active"
772
+ ? Math.max(0, Date.now() - Date.parse(turn.createdAt))
773
+ : durationMs(turn);
786
774
  if (duration <= 0)
787
775
  continue;
788
776
  entries.push({
789
777
  taskId,
790
- runId: run.id,
791
- roleName: run.roleName,
792
- status: run.status,
778
+ turnId: turn.id,
779
+ roleName: turn.roleName,
780
+ status: turn.status,
793
781
  durationMs: duration,
794
- startedAt: run.createdAt
782
+ startedAt: turn.createdAt
795
783
  });
796
784
  }
797
785
  }
@@ -809,7 +797,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
809
797
  homeIdentity,
810
798
  scope,
811
799
  tasks,
812
- runs,
800
+ turns,
813
801
  wakes,
814
802
  sessions,
815
803
  reviews,
@@ -3,9 +3,8 @@ export const FAULT_CLASSES = [
3
3
  "provider-transient",
4
4
  "policy-denied",
5
5
  "session-dead",
6
- "delivery-yield-uncertain",
6
+ "delivery-uncertain",
7
7
  "storage-backend-lock",
8
- "scheduler-duplicate-suppressed-wake",
9
8
  "review-infra",
10
9
  "review-semantic-negative",
11
10
  "integration-environment",
@@ -23,7 +22,7 @@ const PROVIDER_TRANSIENT_PATTERN = /\b5\d{2}\b|gateway time|connection lost|serv
23
22
  const POLICY_DENIED_PATTERN = /policy|permission denied|forbidden|not authorized|\b403\b/iu;
24
23
  const SESSION_DEAD_PATTERN = /tmux session exited|session cannot be replaced|could not start|pane[^\n]*(dead|exited)|session[^\n]*(dead|exited|broken)|native session|launch reservation/iu;
25
24
  const STORAGE_LOCK_PATTERN = /storage lock|database is locked|SQLITE_BUSY|lock timeout|COMMAND_TIMED_OUT|storage conflict|timed out waiting/iu;
26
- const DELIVERY_UNCERTAIN_PATTERN = /delivery[^\n]*(uncertain|unknown)|yield[^\n]*(uncertain|unknown)|uncertain[^\n]*(yield|delivery)|push[^\n]*uncertain/iu;
25
+ const DELIVERY_UNCERTAIN_PATTERN = /delivery[^\n]*(uncertain|unknown)|uncertain[^\n]*delivery|push[^\n]*uncertain/iu;
27
26
  const STALE_BASE_PATTERN = /stale (role|agent|base|target|state)|expected head|base[^\n]*(changed|moved)|conflict|CAS/iu;
28
27
  const INTEGRATION_ENVIRONMENT_PATTERN = /tsc: not found|command not found|ENOENT|runner disappeared|runner vanished|dirty target|wrong argument|not a git repository|npm error|node: not found/iu;
29
28
  function excerpt(text, max = 160) {
@@ -31,11 +30,11 @@ function excerpt(text, max = 160) {
31
30
  return normalized.length <= max ? normalized : `${normalized.slice(0, max)}…`;
32
31
  }
33
32
  /**
34
- * Classify a failed AgentRun. A structured hint (from a future capability
33
+ * Classify a failed Turn. A structured hint (from a future capability
35
34
  * provider) always wins; otherwise the summary is matched as historical
36
- * import text. Active/yielded runs return {@link NO_FAULT}.
35
+ * import text. Non-failed Turns return {@link NO_FAULT}.
37
36
  */
38
- export function classifyAgentRunFailure(run, structured) {
37
+ export function classifyTurnFailure(run, structured) {
39
38
  if (run.status !== "failed")
40
39
  return NO_FAULT;
41
40
  if (structured !== undefined) {
@@ -45,7 +44,7 @@ export function classifyAgentRunFailure(run, structured) {
45
44
  evidence: structured.evidence
46
45
  };
47
46
  }
48
- const summary = run.summary ?? "";
47
+ const summary = run.result?.output ?? "";
49
48
  if (summary.length === 0) {
50
49
  return { faultClass: "other", basis: "text-historical", evidence: "" };
51
50
  }
@@ -60,7 +59,7 @@ export function classifyAgentRunFailure(run, structured) {
60
59
  return { faultClass: "storage-backend-lock", basis: "text-historical", evidence: text };
61
60
  }
62
61
  if (DELIVERY_UNCERTAIN_PATTERN.test(summary)) {
63
- return { faultClass: "delivery-yield-uncertain", basis: "text-historical", evidence: text };
62
+ return { faultClass: "delivery-uncertain", basis: "text-historical", evidence: text };
64
63
  }
65
64
  if (STALE_BASE_PATTERN.test(summary)) {
66
65
  return { faultClass: "stale-base-target-cas", basis: "text-historical", evidence: text };
@@ -134,22 +133,6 @@ export function classifyIntegrationAttempt(attempt) {
134
133
  evidence: "failed without checks or conflict"
135
134
  };
136
135
  }
137
- /**
138
- * Wake reason classification. An orphan wake (the scheduler re-woke a Leader
139
- * with no new fact) is the duplicate/suppressed-wake class. Quiescence
140
- * suppression counters are owned by the scheduler Issue; when absent the
141
- * audit reports `unsupported` instead of guessing.
142
- */
143
- export function classifyWakeReasons(reasons) {
144
- if (reasons.some((reason) => reason === "task-orphaned")) {
145
- return {
146
- faultClass: "scheduler-duplicate-suppressed-wake",
147
- basis: "structured",
148
- evidence: reasons.join(",")
149
- };
150
- }
151
- return NO_FAULT;
152
- }
153
136
  export function emptyFaultClassCounts() {
154
137
  return Object.freeze(Object.fromEntries(FAULT_CLASSES.map((name) => [name, 0])));
155
138
  }
@@ -4,7 +4,7 @@ import { projectFirstProgressAdvisory } from "../runtime/firstProgressAdvisory.j
4
4
  /** One Task's orchestration cost and advisory projection, with no writes. */
5
5
  export function projectTaskOrchestration(facts) {
6
6
  const evidence = {
7
- listAgentRuns: () => facts.runs,
7
+ listTurns: () => facts.turns,
8
8
  listReviewFindings: () => facts.reviewFindings,
9
9
  listEvents: () => facts.events
10
10
  };
@@ -57,10 +57,10 @@ export function projectTaskOrchestration(facts) {
57
57
  timeToFirstProjectCommitMs: firstCommitAt === undefined
58
58
  ? null
59
59
  : Math.max(0, Date.parse(firstCommitAt) - Date.parse(facts.task.createdAt)),
60
- runs: {
61
- total: facts.runs.length,
62
- byStatus: counts(facts.runs.map(({ status }) => status)),
63
- byRole: counts(facts.runs.map(({ roleName }) => roleName))
60
+ turns: {
61
+ total: facts.turns.length,
62
+ byStatus: counts(facts.turns.map(({ status }) => status)),
63
+ byRole: counts(facts.turns.map(({ roleName }) => roleName))
64
64
  },
65
65
  workItems: facts.workItems.length,
66
66
  reviews: {
@@ -14,7 +14,6 @@ import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "n
14
14
  import { join } from "node:path";
15
15
  import Database from "better-sqlite3";
16
16
  import { CURRENT_AGGREGATE_SCHEMA_VERSION, CURRENT_STORAGE_LAYOUT_VERSION } from "../storage/storageVersions.js";
17
- import { resolveTaskStoreBackendForHome } from "../storage/sqliteStore.js";
18
17
  import { resolveStoreWorkerEnabledForHome } from "../storage/storeRpc.js";
19
18
  export const UNSUPPORTED = "unsupported";
20
19
  /**
@@ -178,10 +177,8 @@ export function createProductionStorageIdentityPorts(env = process.env) {
178
177
  };
179
178
  }
180
179
  /**
181
- * Collect durable-vs-physical storage evidence for one Home. The manifest
182
- * declares a logical layout; the directory carries physical evidence
183
- * (state.json vs yui.db + WAL). Contradictions between the two are the
184
- * pseudo-layout-7 class of failure and fail closed.
180
+ * Collect read-only evidence for the exact current SQLite contract. Old files
181
+ * are never treated as an alternate authority or a repair source.
185
182
  */
186
183
  export function collectStorageIdentity(home, ports = createProductionStorageIdentityPorts()) {
187
184
  const manifestPath = join(home, "schema.json");
@@ -201,10 +198,10 @@ export function collectStorageIdentity(home, ports = createProductionStorageIden
201
198
  && Number.isFinite(manifest.aggregateSchemaVersion)) {
202
199
  aggregateSchemaVersion = manifest.aggregateSchemaVersion;
203
200
  }
204
- if (typeof logicalLayout === "number"
205
- && (logicalLayout > CURRENT_STORAGE_LAYOUT_VERSION
206
- || (typeof aggregateSchemaVersion === "number"
207
- && aggregateSchemaVersion > CURRENT_AGGREGATE_SCHEMA_VERSION))) {
201
+ if (typeof logicalLayout !== "number"
202
+ || typeof aggregateSchemaVersion !== "number"
203
+ || logicalLayout !== CURRENT_STORAGE_LAYOUT_VERSION
204
+ || aggregateSchemaVersion !== CURRENT_AGGREGATE_SCHEMA_VERSION) {
208
205
  manifestStatus = "unsupported";
209
206
  }
210
207
  }
@@ -222,120 +219,57 @@ export function collectStorageIdentity(home, ports = createProductionStorageIden
222
219
  const dbBytes = ports.fileSize(dbPath);
223
220
  const walPresent = ports.exists(`${dbPath}-wal`);
224
221
  const shmPresent = ports.exists(`${dbPath}-shm`);
225
- const configuredBackend = resolveTaskStoreBackendForHome(home, ports.env);
222
+ const configuredBackend = "sqlite";
226
223
  const workerEnabled = resolveStoreWorkerEnabledForHome(home, ports.env);
227
224
  const dbHealth = dbPresent ? ports.probeDatabaseHealth(dbPath) : null;
228
- const hasMigrationReceipt = ports.exists(join(home, "migration-receipt.json"));
229
225
  const findings = [];
230
- // A readable state.json is a JSON object (the file store's record container).
231
- // Pseudo-layout-7 is only repairable when state.json is a valid fallback.
232
- const stateText = statePresent ? ports.readText(statePath) : null;
233
- let stateReadable = false;
234
- if (stateText !== null) {
235
- try {
236
- const parsed = JSON.parse(stateText);
237
- stateReadable = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed);
238
- }
239
- catch {
240
- stateReadable = false;
241
- }
242
- }
243
- const layout7 = manifestStatus === "current"
244
- && typeof logicalLayout === "number"
245
- && logicalLayout >= CURRENT_STORAGE_LAYOUT_VERSION;
246
- if (layout7 && !dbPresent) {
247
- if (stateReadable) {
248
- // Pseudo-layout-7: manifest claims SQLite WAL but yui.db was never
249
- // materialized. state.json is the readable fallback; `yui upgrade`
250
- // rebuilds yui.db from it. This is the recognized NEEDS_STORAGE_REPAIR
251
- // state, not a hard contradiction — the file store is legitimately
252
- // serving until repair runs.
253
- findings.push({
254
- code: "pseudo-layout-7",
255
- severity: "needs-repair",
256
- message: `Manifest declares layout ${logicalLayout} (SQLite WAL) but `
257
- + `${dbPath} does not exist; state.json is the only authoritative `
258
- + "copy (pseudo-layout-7).",
259
- remediation: "Run `yui upgrade` to rebuild yui.db from state.json."
260
- });
261
- }
262
- else {
263
- findings.push({
264
- code: "no-authoritative-backend",
265
- severity: "contradiction",
266
- message: `Manifest declares layout ${logicalLayout} but neither `
267
- + "yui.db nor a readable state.json exists; there is no "
268
- + "authoritative backend.",
269
- remediation: "Restore one copy from a backup; do not guess which is newer."
270
- });
271
- }
272
- }
273
- if (dbPresent && dbHealth !== null && dbHealth !== "ok") {
226
+ if (manifestStatus === "current" && !dbPresent) {
274
227
  findings.push({
275
- code: "database-unhealthy",
228
+ code: "current-database-missing",
276
229
  severity: "contradiction",
277
- message: `yui.db exists but failed integrity check (${dbHealth}).`,
278
- remediation: "Restore yui.db from backup, or run `yui upgrade` to rebuild "
279
- + "it from state.json."
230
+ message: `The current storage contract requires ${dbPath}, but it is missing.`,
231
+ remediation: "Preserve this Home for diagnosis and initialize a new Home."
280
232
  });
281
233
  }
282
- if (dbPresent && statePresent && !hasMigrationReceipt && layout7) {
234
+ if (manifestStatus === "unsupported") {
283
235
  findings.push({
284
- code: "dual-copy-conflict",
236
+ code: "unsupported-storage-contract",
285
237
  severity: "contradiction",
286
- message: "Both state.json and yui.db exist without a migration receipt; "
287
- + "the authoritative copy is ambiguous.",
288
- remediation: "Restore one copy from a backup; do not guess which is newer."
238
+ message: "The Home does not match this release's exact storage contract.",
239
+ remediation: "Open it read-only with its original Yui version, then let the Operator recreate unfinished work in a new Home."
289
240
  });
290
241
  }
291
- if (configuredBackend === "sqlite" && !dbPresent) {
242
+ if (manifestStatus === "invalid") {
292
243
  findings.push({
293
- code: "backend-sqlite-without-database",
244
+ code: "invalid-storage-manifest",
294
245
  severity: "contradiction",
295
- message: "YUI_STORE_BACKEND=sqlite is set but no yui.db exists; the "
296
- + "SQLite store cannot open this Home.",
297
- remediation: "Run `yui upgrade` to create yui.db, or unset "
298
- + "YUI_STORE_BACKEND to keep using the file store explicitly."
246
+ message: "schema.json is invalid.",
247
+ remediation: "Preserve this Home for diagnosis and initialize a new Home."
299
248
  });
300
249
  }
301
- if (configuredBackend === "file"
302
- && dbPresent
303
- && manifestStatus === "current") {
250
+ if (dbPresent && dbHealth !== null && dbHealth !== "ok") {
304
251
  findings.push({
305
- code: "database-present-but-file-backend",
306
- severity: "warning",
307
- message: "yui.db exists but the file backend is selected; this process "
308
- + "is serving state.json, not the database.",
309
- remediation: "Unset YUI_STORE_BACKEND to let the Home manifest select "
310
- + "SQLite, or remove the stale yui.db."
252
+ code: "database-unhealthy",
253
+ severity: "contradiction",
254
+ message: `yui.db exists but failed integrity check (${dbHealth}).`,
255
+ remediation: "Preserve this Home for diagnosis and initialize a new Home."
311
256
  });
312
257
  }
313
- const rawWorkerFlag = ports.env.YUI_STORE_WORKER;
314
- if (rawWorkerFlag !== undefined
315
- && !workerEnabled
316
- && configuredBackend !== "sqlite") {
258
+ if (statePresent) {
317
259
  findings.push({
318
- code: "worker-flag-without-sqlite",
260
+ code: "ignored-historical-store",
319
261
  severity: "warning",
320
- message: `YUI_STORE_WORKER=${rawWorkerFlag} is set but the worker `
321
- + "requires YUI_STORE_BACKEND=sqlite; the worker is off.",
322
- remediation: "Set YUI_STORE_BACKEND=sqlite to activate the worker, or "
323
- + "unset YUI_STORE_WORKER."
262
+ message: "state.json is present but is not read or written by the current store.",
263
+ remediation: "Keep it only as read-only historical evidence or archive it outside the active Home."
324
264
  });
325
265
  }
326
- // Only fire for pre-layout-7 Homes where the file store is the legitimate
327
- // backend. A layout-7 Home without state.json is already covered by
328
- // no-authoritative-backend above (the file store is just a fallback there).
329
- if (configuredBackend === "file"
330
- && !statePresent
331
- && manifestStatus === "current"
332
- && !(typeof logicalLayout === "number" && logicalLayout >= CURRENT_STORAGE_LAYOUT_VERSION)) {
266
+ const rawWorkerFlag = ports.env.YUI_STORE_WORKER;
267
+ if (rawWorkerFlag !== undefined && !["0", "1", "false", "true"].includes(rawWorkerFlag.toLowerCase())) {
333
268
  findings.push({
334
- code: "file-store-missing-state",
335
- severity: "contradiction",
336
- message: "The file backend is selected but state.json is missing.",
337
- remediation: "Restore state.json from backup, or run the storage "
338
- + "migration to create yui.db."
269
+ code: "invalid-worker-flag",
270
+ severity: "warning",
271
+ message: `YUI_STORE_WORKER=${rawWorkerFlag} is invalid.`,
272
+ remediation: "Use 1/true, 0/false, or unset YUI_STORE_WORKER."
339
273
  });
340
274
  }
341
275
  return {
@@ -356,7 +290,6 @@ export function collectStorageIdentity(home, ports = createProductionStorageIden
356
290
  shm: shmPresent,
357
291
  health: dbHealth ?? UNSUPPORTED
358
292
  },
359
- hasMigrationReceipt,
360
293
  findings
361
294
  };
362
295
  }