@zq-silk/yui 0.6.0 → 0.6.2
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.
- package/README.md +5 -5
- package/dist/agent/managedRuntimeEnvironment.js +2 -1
- package/dist/cli/commandCatalog.js +251 -13
- package/dist/cli/updateOrchestrator.js +8 -0
- package/dist/cli/updatePorts.js +76 -22
- package/dist/cli.js +264 -20
- package/dist/commands/configCommands.js +83 -9
- package/dist/commands/controllerCommands.js +103 -0
- package/dist/commands/deliveryGuardPreflight.js +30 -0
- package/dist/commands/durableJobCommands.js +231 -0
- package/dist/commands/executionAuditCommands.js +193 -0
- package/dist/commands/grantCommands.js +374 -0
- package/dist/commands/projectCommands.js +119 -81
- package/dist/commands/releaseCommands.js +444 -0
- package/dist/commands/resourcesCommands.js +274 -0
- package/dist/commands/sessionCommands.js +104 -0
- package/dist/commands/taskActor.js +117 -0
- package/dist/commands/taskChangeSetCommands.js +60 -0
- package/dist/commands/taskCommands.js +618 -202
- package/dist/commands/taskCompletionGate.js +78 -1
- package/dist/commands/taskContextCommand.js +33 -6
- package/dist/commands/taskInputCommands.js +1 -1
- package/dist/commands/taskIntegrationCommands.js +136 -33
- package/dist/commands/taskIntegrationQueueCommands.js +228 -0
- package/dist/commands/taskNextActionCommand.js +100 -0
- package/dist/commands/taskOverlapCommands.js +120 -0
- package/dist/commands/taskOverviewCommand.js +36 -8
- package/dist/commands/telemetryCommands.js +330 -0
- package/dist/commands/workflowCommands.js +415 -0
- package/dist/config/yuiConfig.js +62 -0
- package/dist/controller/clientRuntime.js +42 -1
- package/dist/controller/controller.js +402 -56
- package/dist/controller/controllerMain.js +25 -2
- package/dist/controller/domainIdentity.js +16 -8
- package/dist/controller/fileSchedulerStoreAdapter.js +423 -31
- package/dist/controller/handoverCandidate.js +168 -0
- package/dist/controller/jobClient.js +102 -0
- package/dist/controller/jobControl.js +613 -0
- package/dist/controller/jobSupervisor.js +498 -0
- package/dist/controller/providerHookRunFence.js +34 -5
- package/dist/controller/resourceCleanupLinux.js +18 -9
- package/dist/controller/resourceInventoryLinux.js +90 -39
- package/dist/controller/runtime.js +165 -15
- package/dist/controller/runtimeEventInbox.js +234 -57
- package/dist/controller/runtimeEventProcessor.js +297 -58
- package/dist/controller/sessionOwnerReconciliation.js +321 -0
- package/dist/core/controllerServer.js +416 -27
- package/dist/core/controllerTelemetry.js +167 -0
- package/dist/doctor/doctor.js +113 -16
- package/dist/domain/validation.js +9 -0
- package/dist/execution/executionGroup.js +40 -3
- package/dist/executor/agentExecutor.js +6 -3
- package/dist/executor/effectiveLaunch.js +52 -0
- package/dist/executor/executorRegistry.js +50 -0
- package/dist/executor/fileRoleLaunchPlanner.js +61 -6
- package/dist/grant/capabilityGrant.js +282 -0
- package/dist/integration/changeSet.js +16 -3
- package/dist/integration/changeSetManifest.js +46 -0
- package/dist/integration/gitIntegrationService.js +528 -147
- package/dist/integration/integrationAttempt.js +54 -5
- package/dist/integration/integrationQueueEntry.js +221 -0
- package/dist/integration/integrationQueueService.js +955 -0
- package/dist/integration/manifestTags.js +99 -0
- package/dist/integration/overlapDiagnostics.js +211 -0
- package/dist/job/durableJob.js +449 -0
- package/dist/job/jobRunner.js +350 -0
- package/dist/lifecycle/exactRunTerminalization.js +24 -2
- package/dist/lifecycle/providerErrorClass.js +126 -0
- package/dist/message/message.js +16 -3
- package/dist/observability/executionAudit.js +545 -0
- package/dist/observability/faultClassification.js +160 -0
- package/dist/observability/runtimeIdentity.js +367 -0
- package/dist/release/fakeReleasePorts.js +55 -0
- package/dist/release/releaseHandover.js +475 -0
- package/dist/release/releaseIdempotencyStore.js +165 -0
- package/dist/release/releaseWorkflow.js +459 -0
- package/dist/release/releaseWorkflowEngine.js +688 -0
- package/dist/release/releaseWorkflowPorts.js +1720 -0
- package/dist/release/runtimeRelease.js +495 -0
- package/dist/release/workflowFileLock.js +218 -0
- package/dist/repository/gitWorkspace.js +177 -1
- package/dist/repository/projectMaintenanceLock.js +315 -0
- package/dist/repository/taskWorkspaceCoordinator.js +87 -17
- package/dist/repository/taskWorkspacePreparer.js +1091 -517
- package/dist/resources/autoResourceGc.js +116 -0
- package/dist/resources/liveReferences.js +574 -0
- package/dist/resources/resourceDiscovery.js +477 -0
- package/dist/resources/resourceGc.js +645 -0
- package/dist/resources/resourceRegistrar.js +256 -0
- package/dist/resources/resourceRegistry.js +150 -0
- package/dist/resources/resourceRegistryStore.js +41 -0
- package/dist/resources/resourceTypes.js +42 -0
- package/dist/resources/sqliteResourceRegistry.js +111 -0
- package/dist/review/reviewConfig.js +10 -0
- package/dist/review/reviewFinding.js +240 -0
- package/dist/review/reviewFindingLedger.js +545 -0
- package/dist/review/reviewOutcomeClassifier.js +61 -0
- package/dist/review/reviewRound.js +56 -4
- package/dist/run/agentRun.js +80 -4
- package/dist/run/providerRetry.js +84 -0
- package/dist/run/providerRetryConfig.js +63 -0
- package/dist/run/yieldReceipt.js +65 -0
- package/dist/runtime/exactControlPlane.js +79 -2
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/sessionOwnerIdentity.js +269 -0
- package/dist/runtime/sessionOwnerRegistry.js +132 -0
- package/dist/runtime/sessionReconciliation.js +93 -0
- package/dist/runtime/sessionTerminationGuard.js +211 -0
- package/dist/runtime/taskRuntimeIsolation.js +13 -0
- package/dist/runtime/tmuxAdapters.js +34 -1
- package/dist/scheduler/actionability.js +155 -0
- package/dist/scheduler/activeRoleRunDelivery.js +14 -5
- package/dist/scheduler/activeTaskProgress.js +60 -0
- package/dist/scheduler/leaderWakeupProcessor.js +22 -11
- package/dist/scheduler/roleRunStall.js +135 -29
- package/dist/scheduler/taskExecutionProjection.js +11 -0
- package/dist/storage/compatibleTaskStore.js +112 -5
- package/dist/storage/migration/productionRegistry.js +736 -1
- package/dist/storage/sqliteSchema.js +264 -3
- package/dist/storage/sqliteStore.js +487 -13
- package/dist/storage/storeRpc.js +21 -0
- package/dist/storage/taskStore.js +974 -21
- package/dist/storage/upgrade/homeClassification.js +120 -2
- package/dist/storage/upgrade/migrationReceipt.js +67 -0
- package/dist/storage/upgrade/pseudoLayoutRepair.js +241 -0
- package/dist/storage/upgrade/recordVersions.js +10 -1
- package/dist/storage/upgrade/sqliteMigrationTarget.js +58 -6
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +290 -0
- package/dist/storage/upgrade/sqliteStateMigration.js +258 -2
- package/dist/storage/upgrade/upgradeOrchestrator.js +482 -16
- package/dist/task/deliveryGuard.js +226 -0
- package/dist/task/nextAction.js +738 -0
- package/dist/task/repairWave.js +137 -0
- package/dist/task/taskRecordReference.js +6 -1
- package/dist/telemetry/sqliteTelemetryStore.js +387 -0
- package/dist/telemetry/telemetryCompaction.js +251 -0
- package/dist/telemetry/telemetryConfig.js +64 -0
- package/dist/telemetry/telemetryRouter.js +32 -0
- package/dist/telemetry/telemetryStore.js +19 -0
- package/dist/telemetry/telemetryWiring.js +33 -0
- package/dist/tmux/tmuxManager.js +20 -1
- package/dist/tmux/tmuxSocketEndpoint.js +20 -0
- package/dist/verification/gateArtifact.js +216 -0
- package/dist/verification/gateArtifactStore.js +87 -0
- package/dist/verification/verificationGateService.js +414 -0
- package/dist/verification/verificationPlan.js +308 -0
- package/dist/workspace/gitChangeSetCapture.js +12 -2
- package/dist/workspace/workItemChangeSetManager.js +60 -3
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +8 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
const DEFAULT_MAX_RUNTIME_EVENTS_PER_DRAIN = 64;
|
|
2
|
+
/** Folds immutable Hook facts in one bounded transaction before acknowledging them. */
|
|
2
3
|
export class FileRuntimeEventProcessor {
|
|
3
4
|
inbox;
|
|
4
5
|
observer;
|
|
@@ -17,48 +18,128 @@ export class FileRuntimeEventProcessor {
|
|
|
17
18
|
events = this.inbox.list();
|
|
18
19
|
}
|
|
19
20
|
catch (error) {
|
|
20
|
-
return
|
|
21
|
+
return emptyDrainFailure(error);
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
const coalesced = coalesceRuntimeProgress(events);
|
|
24
|
+
const maximum = positiveInteger(this.options.maxEventsPerDrain, DEFAULT_MAX_RUNTIME_EVENTS_PER_DRAIN);
|
|
25
|
+
const selected = selectDrainBatch(coalesced, maximum);
|
|
26
|
+
let stateTransactions = 0;
|
|
27
|
+
if (selected.length > 0 && this.observer.withRuntimeEventTransaction !== undefined) {
|
|
23
28
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
29
|
+
stateTransactions += 1;
|
|
30
|
+
const folded = this.observer.withRuntimeEventTransaction(() => (selected.map((candidate) => this.foldOne(candidate, now))));
|
|
31
|
+
for (const result of folded) {
|
|
32
|
+
this.finalizeOne(result, acknowledgedEventIds, deferred, failed);
|
|
30
33
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// A failed aggregate transaction commits nothing. Retry each candidate
|
|
37
|
+
// independently so one bad event cannot strand unrelated facts.
|
|
38
|
+
for (const candidate of selected) {
|
|
39
|
+
try {
|
|
40
|
+
stateTransactions += 1;
|
|
41
|
+
const folded = this.observer.withRuntimeEventTransaction(() => (this.foldOne(candidate, now)));
|
|
42
|
+
this.finalizeOne(folded, acknowledgedEventIds, deferred, failed);
|
|
39
43
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const outcome = this.applyProviderTurnProgress(event, now);
|
|
43
|
-
if (outcome === "deferred") {
|
|
44
|
-
deferred.push(event);
|
|
45
|
-
continue;
|
|
44
|
+
catch (candidateError) {
|
|
45
|
+
failed.push({ eventId: candidate.event.id, error: candidateError });
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
for (const candidate of selected) {
|
|
52
|
+
try {
|
|
53
|
+
const folded = this.foldOne(candidate, now);
|
|
54
|
+
this.finalizeOne(folded, acknowledgedEventIds, deferred, failed);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
failed.push({ eventId: candidate.event.id, error });
|
|
54
58
|
}
|
|
55
|
-
this.acknowledge(event.id, acknowledgedEventIds);
|
|
56
59
|
}
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
}
|
|
61
|
+
const progressEventsSelected = selected.filter(({ event }) => (event.type === "native-turn-progress")).length;
|
|
62
|
+
const representedEventCount = selected.reduce((count, candidate) => (count + candidate.representedEventIds.length), 0);
|
|
63
|
+
const acknowledged = new Set(acknowledgedEventIds);
|
|
64
|
+
const remaining = events.filter(({ id }) => !acknowledged.has(id));
|
|
65
|
+
const remainingProgressEventCount = remaining.filter(({ type }) => (type === "native-turn-progress")).length;
|
|
66
|
+
return {
|
|
67
|
+
acknowledgedEventIds,
|
|
68
|
+
deferred,
|
|
69
|
+
failed,
|
|
70
|
+
remainingEventCount: Math.max(0, events.length - acknowledgedEventIds.length),
|
|
71
|
+
metrics: {
|
|
72
|
+
listedEventCount: events.length,
|
|
73
|
+
selectedEventCount: selected.length,
|
|
74
|
+
semanticEventsSelected: selected.length - progressEventsSelected,
|
|
75
|
+
progressEventsSelected,
|
|
76
|
+
progressEventsCoalesced: representedEventCount - selected.length,
|
|
77
|
+
stateTransactions,
|
|
78
|
+
remainingSemanticEventCount: remaining.length - remainingProgressEventCount,
|
|
79
|
+
remainingProgressEventCount
|
|
59
80
|
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
foldOne(candidate, now) {
|
|
84
|
+
const event = candidate.event;
|
|
85
|
+
let outcome = "applied";
|
|
86
|
+
if (event.type === "native-turn-completed") {
|
|
87
|
+
outcome = this.applyCodex(event, now);
|
|
88
|
+
}
|
|
89
|
+
else if (event.type === "claude-stop-failure") {
|
|
90
|
+
this.applyClaudeStopFailure(event, now);
|
|
91
|
+
}
|
|
92
|
+
else if (event.type === "native-session-lifecycle") {
|
|
93
|
+
outcome = this.applySessionLifecycle(event, now);
|
|
94
|
+
}
|
|
95
|
+
else if (event.type === "native-turn-progress") {
|
|
96
|
+
outcome = this.applyProviderTurnProgress(event, now);
|
|
97
|
+
}
|
|
98
|
+
else if (event.type === "durable-job-terminal") {
|
|
99
|
+
// f7/rr5: The supervisor already transitioned the job and
|
|
100
|
+
// enqueued the Leader wakeup. This event is the durable terminal
|
|
101
|
+
// channel: acknowledge it so the Controller's event pipeline
|
|
102
|
+
// converges without re-processing. No state change to apply.
|
|
103
|
+
this.applyDurableJobTerminal(event);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
outcome = this.applyPromptAccepted(event, now);
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
candidate,
|
|
110
|
+
outcome,
|
|
111
|
+
notifyTaskRuntime: outcome === "applied" && (event.type === "native-session-lifecycle"
|
|
112
|
+
|| event.type === "native-prompt-accepted"
|
|
113
|
+
|| (event.type === "native-turn-completed" && event.scope === "task"))
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
finalizeOne(folded, acknowledged, deferred, failed) {
|
|
117
|
+
const { candidate, outcome } = folded;
|
|
118
|
+
try {
|
|
119
|
+
if (outcome === "deferred") {
|
|
120
|
+
deferred.push(candidate.event);
|
|
121
|
+
this.acknowledge(candidate.representedEventIds.filter((id) => id !== candidate.event.id), acknowledged);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (folded.notifyTaskRuntime) {
|
|
125
|
+
const event = candidate.event;
|
|
126
|
+
if (event.scope === "task" && event.taskId !== undefined && event.type !== "durable-job-terminal") {
|
|
127
|
+
this.options.onTaskRuntimeApplied?.({
|
|
128
|
+
taskId: event.taskId,
|
|
129
|
+
roleName: event.roleName,
|
|
130
|
+
agentId: event.agentId,
|
|
131
|
+
adapterId: event.adapterId,
|
|
132
|
+
...(event.launchId === undefined ? {} : { launchId: event.launchId }),
|
|
133
|
+
nativeSessionId: event.nativeSessionId,
|
|
134
|
+
...(event.runId === undefined ? {} : { runId: event.runId })
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this.acknowledge(candidate.representedEventIds, acknowledged);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
failed.push({ eventId: candidate.event.id, error });
|
|
60
142
|
}
|
|
61
|
-
return { acknowledgedEventIds, deferred, failed };
|
|
62
143
|
}
|
|
63
144
|
applySessionLifecycle(event, now) {
|
|
64
145
|
const task = this.observer.getTask(event.taskId);
|
|
@@ -77,12 +158,6 @@ export class FileRuntimeEventProcessor {
|
|
|
77
158
|
...(event.runId === undefined ? {} : { runId: event.runId }),
|
|
78
159
|
...(event.sessionSource === undefined ? {} : { sessionSource: event.sessionSource })
|
|
79
160
|
}, now);
|
|
80
|
-
if (outcome === "applied") {
|
|
81
|
-
this.options.onTaskRuntimeApplied?.({
|
|
82
|
-
taskId: event.taskId,
|
|
83
|
-
roleName: event.roleName
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
161
|
return outcome === "deferred" ? "deferred" : outcome;
|
|
87
162
|
}
|
|
88
163
|
applyPromptAccepted(event, now) {
|
|
@@ -102,14 +177,19 @@ export class FileRuntimeEventProcessor {
|
|
|
102
177
|
runId: event.runId,
|
|
103
178
|
receiptId: event.receiptId
|
|
104
179
|
}, now);
|
|
105
|
-
if (outcome === "applied") {
|
|
106
|
-
this.options.onTaskRuntimeApplied?.({
|
|
107
|
-
taskId: event.taskId,
|
|
108
|
-
roleName: event.roleName
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
180
|
return outcome === "deferred" ? "deferred" : outcome;
|
|
112
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* f7/rr5: Acknowledge a durable-job-terminal event. The supervisor
|
|
184
|
+
* already committed the terminal transition and the Leader wakeup;
|
|
185
|
+
* this event only needs to be acknowledged so it leaves the inbox.
|
|
186
|
+
*/
|
|
187
|
+
applyDurableJobTerminal(event) {
|
|
188
|
+
// The event is a notification of a committed state change. No observer
|
|
189
|
+
// call is needed — the Leader wakeup was enqueued in the same
|
|
190
|
+
// transaction as the terminal transition.
|
|
191
|
+
void event;
|
|
192
|
+
}
|
|
113
193
|
applyProviderTurnProgress(event, now) {
|
|
114
194
|
const task = this.observer.getTask(event.taskId);
|
|
115
195
|
if (task === null || task.status !== "active")
|
|
@@ -164,10 +244,6 @@ export class FileRuntimeEventProcessor {
|
|
|
164
244
|
this.recordObsolete(event, "runtime-cleanup-or-stopped-session", now);
|
|
165
245
|
return "obsolete";
|
|
166
246
|
}
|
|
167
|
-
this.options.onTaskRuntimeApplied?.({
|
|
168
|
-
taskId: event.taskId,
|
|
169
|
-
roleName: event.roleName
|
|
170
|
-
});
|
|
171
247
|
return "applied";
|
|
172
248
|
}
|
|
173
249
|
const input = {
|
|
@@ -224,6 +300,10 @@ export class FileRuntimeEventProcessor {
|
|
|
224
300
|
recordObsolete(event, reason, now) {
|
|
225
301
|
if (event.scope !== "task" || event.taskId === undefined)
|
|
226
302
|
return;
|
|
303
|
+
// durable-job-terminal events have no provider identity; they are never
|
|
304
|
+
// recorded as obsolete.
|
|
305
|
+
if (!("roleName" in event) || !("nativeSessionId" in event))
|
|
306
|
+
return;
|
|
227
307
|
this.observer.observeObsoleteRuntimeEvent?.({
|
|
228
308
|
eventId: event.id,
|
|
229
309
|
eventType: event.type,
|
|
@@ -236,10 +316,129 @@ export class FileRuntimeEventProcessor {
|
|
|
236
316
|
reason
|
|
237
317
|
}, now);
|
|
238
318
|
}
|
|
239
|
-
acknowledge(
|
|
240
|
-
this.inbox.
|
|
241
|
-
|
|
319
|
+
acknowledge(ids, acknowledged) {
|
|
320
|
+
if (this.inbox.acknowledgeMany !== undefined) {
|
|
321
|
+
acknowledged.push(...this.inbox.acknowledgeMany(ids));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
for (const id of ids) {
|
|
325
|
+
if (this.inbox.acknowledge(id))
|
|
326
|
+
acknowledged.push(id);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
export function coalesceRuntimeProgress(events, instrumentation = {}) {
|
|
331
|
+
const result = [];
|
|
332
|
+
let segment = [];
|
|
333
|
+
const flush = () => {
|
|
334
|
+
if (segment.length === 0)
|
|
335
|
+
return;
|
|
336
|
+
const frontiers = new Map();
|
|
337
|
+
for (let index = 0; index < segment.length; index += 1) {
|
|
338
|
+
instrumentation.onProgressVisit?.();
|
|
339
|
+
const event = segment[index];
|
|
340
|
+
const key = progressStreamKey(event);
|
|
341
|
+
const frontier = frontiers.get(key);
|
|
342
|
+
if (frontier === undefined || event.receivedAt > frontier.latestReceivedAt) {
|
|
343
|
+
frontiers.set(key, {
|
|
344
|
+
latestReceivedAt: event.receivedAt,
|
|
345
|
+
...(event.sequence === undefined
|
|
346
|
+
? {}
|
|
347
|
+
: {
|
|
348
|
+
greatestSequence: event.sequence,
|
|
349
|
+
firstGreatestSequenceIndex: index
|
|
350
|
+
}),
|
|
351
|
+
firstLatestIndex: index
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
else if (event.receivedAt === frontier.latestReceivedAt
|
|
355
|
+
&& event.sequence !== undefined
|
|
356
|
+
&& (frontier.greatestSequence === undefined
|
|
357
|
+
|| event.sequence > frontier.greatestSequence)) {
|
|
358
|
+
frontiers.set(key, {
|
|
359
|
+
...frontier,
|
|
360
|
+
greatestSequence: event.sequence,
|
|
361
|
+
firstGreatestSequenceIndex: index
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const representedByIndex = new Map();
|
|
366
|
+
for (let index = 0; index < segment.length; index += 1) {
|
|
367
|
+
instrumentation.onProgressVisit?.();
|
|
368
|
+
const event = segment[index];
|
|
369
|
+
const frontier = frontiers.get(progressStreamKey(event));
|
|
370
|
+
const strictlyDominated = event.receivedAt < frontier.latestReceivedAt
|
|
371
|
+
|| (event.receivedAt === frontier.latestReceivedAt
|
|
372
|
+
&& event.sequence !== undefined
|
|
373
|
+
&& frontier.greatestSequence !== undefined
|
|
374
|
+
&& event.sequence < frontier.greatestSequence);
|
|
375
|
+
const representativeIndex = strictlyDominated
|
|
376
|
+
? frontier.firstGreatestSequenceIndex ?? frontier.firstLatestIndex
|
|
377
|
+
: index;
|
|
378
|
+
const represented = representedByIndex.get(representativeIndex) ?? [];
|
|
379
|
+
represented.push(event.id);
|
|
380
|
+
representedByIndex.set(representativeIndex, represented);
|
|
381
|
+
}
|
|
382
|
+
for (let index = 0; index < segment.length; index += 1) {
|
|
383
|
+
const representedEventIds = representedByIndex.get(index);
|
|
384
|
+
if (representedEventIds === undefined)
|
|
385
|
+
continue;
|
|
386
|
+
result.push({ event: segment[index], representedEventIds });
|
|
387
|
+
}
|
|
388
|
+
segment = [];
|
|
389
|
+
};
|
|
390
|
+
for (const event of events) {
|
|
391
|
+
if (event.type !== "native-turn-progress") {
|
|
392
|
+
flush();
|
|
393
|
+
result.push({ event, representedEventIds: [event.id] });
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
segment.push(event);
|
|
242
397
|
}
|
|
398
|
+
flush();
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
function selectDrainBatch(events, maximum) {
|
|
402
|
+
// A batch is always an arrival-order prefix. Admission and drain coalescing
|
|
403
|
+
// keep a progress flood bounded without allowing a later semantic fact to
|
|
404
|
+
// overtake an earlier progress fence from another Run.
|
|
405
|
+
return events.slice(0, maximum);
|
|
406
|
+
}
|
|
407
|
+
function progressStreamKey(event) {
|
|
408
|
+
return JSON.stringify([
|
|
409
|
+
event.taskId,
|
|
410
|
+
event.roleName,
|
|
411
|
+
event.agentId,
|
|
412
|
+
event.adapterId,
|
|
413
|
+
event.launchId,
|
|
414
|
+
event.nativeSessionId,
|
|
415
|
+
event.runId
|
|
416
|
+
]);
|
|
417
|
+
}
|
|
418
|
+
function emptyDrainFailure(error) {
|
|
419
|
+
return {
|
|
420
|
+
acknowledgedEventIds: [],
|
|
421
|
+
deferred: [],
|
|
422
|
+
failed: [{ error }],
|
|
423
|
+
remainingEventCount: 0,
|
|
424
|
+
metrics: {
|
|
425
|
+
listedEventCount: 0,
|
|
426
|
+
selectedEventCount: 0,
|
|
427
|
+
semanticEventsSelected: 0,
|
|
428
|
+
progressEventsSelected: 0,
|
|
429
|
+
progressEventsCoalesced: 0,
|
|
430
|
+
stateTransactions: 0,
|
|
431
|
+
remainingSemanticEventCount: 0,
|
|
432
|
+
remainingProgressEventCount: 0
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function positiveInteger(value, fallback) {
|
|
437
|
+
const resolved = value ?? fallback;
|
|
438
|
+
if (!Number.isSafeInteger(resolved) || resolved <= 0) {
|
|
439
|
+
throw new TypeError("Runtime event drain limit must be a positive integer.");
|
|
440
|
+
}
|
|
441
|
+
return resolved;
|
|
243
442
|
}
|
|
244
443
|
function isObsoleteRuntimeTurnObservation(value) {
|
|
245
444
|
return typeof value === "object"
|
|
@@ -290,7 +489,7 @@ export class AsyncRuntimeEventProcessor {
|
|
|
290
489
|
events = this.inbox.list();
|
|
291
490
|
}
|
|
292
491
|
catch (error) {
|
|
293
|
-
return
|
|
492
|
+
return emptyDrainFailure(error);
|
|
294
493
|
}
|
|
295
494
|
for (const event of events) {
|
|
296
495
|
try {
|
|
@@ -318,6 +517,12 @@ export class AsyncRuntimeEventProcessor {
|
|
|
318
517
|
continue;
|
|
319
518
|
}
|
|
320
519
|
}
|
|
520
|
+
else if (event.type === "durable-job-terminal") {
|
|
521
|
+
// f7/rr5: The supervisor already transitioned the job and
|
|
522
|
+
// enqueued the Leader wakeup. This event is the durable terminal
|
|
523
|
+
// channel: acknowledge it so the pipeline converges without
|
|
524
|
+
// re-processing. No state change to apply.
|
|
525
|
+
}
|
|
321
526
|
else {
|
|
322
527
|
const outcome = await this.applyPromptAccepted(event, now);
|
|
323
528
|
if (outcome === "deferred") {
|
|
@@ -331,7 +536,26 @@ export class AsyncRuntimeEventProcessor {
|
|
|
331
536
|
failed.push({ eventId: event.id, error });
|
|
332
537
|
}
|
|
333
538
|
}
|
|
334
|
-
|
|
539
|
+
const acknowledged = new Set(acknowledgedEventIds);
|
|
540
|
+
const remaining = events.filter(({ id }) => !acknowledged.has(id));
|
|
541
|
+
const progressEventsSelected = events.filter(({ type }) => (type === "native-turn-progress")).length;
|
|
542
|
+
const remainingProgressEventCount = remaining.filter(({ type }) => (type === "native-turn-progress")).length;
|
|
543
|
+
return {
|
|
544
|
+
acknowledgedEventIds,
|
|
545
|
+
deferred,
|
|
546
|
+
failed,
|
|
547
|
+
remainingEventCount: remaining.length,
|
|
548
|
+
metrics: {
|
|
549
|
+
listedEventCount: events.length,
|
|
550
|
+
selectedEventCount: events.length,
|
|
551
|
+
semanticEventsSelected: events.length - progressEventsSelected,
|
|
552
|
+
progressEventsSelected,
|
|
553
|
+
progressEventsCoalesced: 0,
|
|
554
|
+
stateTransactions: 0,
|
|
555
|
+
remainingSemanticEventCount: remaining.length - remainingProgressEventCount,
|
|
556
|
+
remainingProgressEventCount
|
|
557
|
+
}
|
|
558
|
+
};
|
|
335
559
|
}
|
|
336
560
|
async applySessionLifecycle(event, now) {
|
|
337
561
|
const task = await this.observer.getTask(event.taskId);
|
|
@@ -353,7 +577,12 @@ export class AsyncRuntimeEventProcessor {
|
|
|
353
577
|
if (outcome === "applied") {
|
|
354
578
|
this.options.onTaskRuntimeApplied?.({
|
|
355
579
|
taskId: event.taskId,
|
|
356
|
-
roleName: event.roleName
|
|
580
|
+
roleName: event.roleName,
|
|
581
|
+
agentId: event.agentId,
|
|
582
|
+
adapterId: event.adapterId,
|
|
583
|
+
launchId: event.launchId,
|
|
584
|
+
nativeSessionId: event.nativeSessionId,
|
|
585
|
+
...(event.runId === undefined ? {} : { runId: event.runId })
|
|
357
586
|
});
|
|
358
587
|
}
|
|
359
588
|
return outcome === "deferred" ? "deferred" : outcome;
|
|
@@ -378,7 +607,12 @@ export class AsyncRuntimeEventProcessor {
|
|
|
378
607
|
if (outcome === "applied") {
|
|
379
608
|
this.options.onTaskRuntimeApplied?.({
|
|
380
609
|
taskId: event.taskId,
|
|
381
|
-
roleName: event.roleName
|
|
610
|
+
roleName: event.roleName,
|
|
611
|
+
agentId: event.agentId,
|
|
612
|
+
adapterId: event.adapterId,
|
|
613
|
+
launchId: event.launchId,
|
|
614
|
+
nativeSessionId: event.nativeSessionId,
|
|
615
|
+
runId: event.runId
|
|
382
616
|
});
|
|
383
617
|
}
|
|
384
618
|
return outcome === "deferred" ? "deferred" : outcome;
|
|
@@ -439,7 +673,12 @@ export class AsyncRuntimeEventProcessor {
|
|
|
439
673
|
}
|
|
440
674
|
this.options.onTaskRuntimeApplied?.({
|
|
441
675
|
taskId: event.taskId,
|
|
442
|
-
roleName: event.roleName
|
|
676
|
+
roleName: event.roleName,
|
|
677
|
+
agentId: event.agentId,
|
|
678
|
+
adapterId: event.adapterId,
|
|
679
|
+
...(event.launchId === undefined ? {} : { launchId: event.launchId }),
|
|
680
|
+
nativeSessionId: event.nativeSessionId,
|
|
681
|
+
...(event.runId === undefined ? {} : { runId: event.runId })
|
|
443
682
|
});
|
|
444
683
|
return "applied";
|
|
445
684
|
}
|
|
@@ -495,7 +734,7 @@ export class AsyncRuntimeEventProcessor {
|
|
|
495
734
|
await this.observer.observeClaudeStopFailureEvent(input, now);
|
|
496
735
|
}
|
|
497
736
|
async recordObsolete(event, reason, now) {
|
|
498
|
-
if (event.scope !== "task" || event.taskId === undefined)
|
|
737
|
+
if (event.scope !== "task" || event.taskId === undefined || event.type === "durable-job-terminal")
|
|
499
738
|
return;
|
|
500
739
|
await this.observer.observeObsoleteRuntimeEvent?.({
|
|
501
740
|
eventId: event.id,
|