@zq-silk/yui 0.14.0 → 0.14.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/ARCHITECTURE.md +64 -35
- package/README.md +258 -125
- package/dist/agent/argumentPolicy.js +2 -1
- package/dist/agent/managedRuntimeEnvironment.js +5 -8
- package/dist/cli/commandCatalog.js +74 -109
- package/dist/cli/helpRenderer.js +1 -2
- package/dist/cli/interactionCandidates.js +10 -0
- package/dist/cli/interactionPolicy.js +76 -37
- package/dist/cli/roleWizard.js +5 -6
- package/dist/cli/updateOrchestrator.js +10 -8
- package/dist/cli/updatePorts.js +17 -13
- package/dist/cli/upgradeCommand.js +2 -5
- package/dist/cli.js +268 -231
- package/dist/commands/agentCommands.js +13 -0
- package/dist/commands/configCommands.js +7 -19
- package/dist/commands/configOverview.js +3 -2
- package/dist/commands/durableJobCommands.js +1 -1
- package/dist/commands/executionAuditCommands.js +4 -9
- package/dist/commands/globalRoleCommands.js +17 -0
- package/dist/commands/profileCommands.js +200 -30
- package/dist/commands/sessionCommands.js +1 -1
- package/dist/commands/taskActor.js +29 -127
- package/dist/commands/taskChangeSetCommands.js +1 -3
- package/dist/commands/taskCommands.js +1771 -2107
- package/dist/commands/taskCompletionGate.js +27 -103
- package/dist/commands/taskContextCommand.js +47 -80
- package/dist/commands/taskExecutionCommands.js +9 -27
- package/dist/commands/taskInputCommands.js +10 -10
- package/dist/commands/taskIntegrationCommands.js +69 -61
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -29
- package/dist/commands/taskOverviewCommand.js +25 -3
- package/dist/commands/taskPublicationCommands.js +151 -85
- package/dist/commands/taskPublicationVerifyCommand.js +181 -0
- package/dist/commands/taskRemoteDeliveryCommand.js +134 -0
- package/dist/commands/taskRoleRuntimeStatus.js +5 -6
- package/dist/commands/taskUpstreamCommands.js +79 -95
- package/dist/config/configCatalog.js +1 -1
- package/dist/context/contextSnapshot.js +17 -2
- package/dist/context/sessionBootstrapManifest.js +18 -1
- package/dist/context/sourceTurnContext.js +30 -0
- package/dist/context/turnContextPack.js +107 -48
- package/dist/context/turnInputContract.js +11 -4
- package/dist/context/wakeNotification.js +84 -22
- package/dist/controller/agentRuntimeObserver.js +9 -12
- package/dist/controller/clientRuntime.js +13 -13
- package/dist/controller/controller.js +11 -11
- package/dist/controller/fileSchedulerStoreAdapter.js +262 -219
- package/dist/controller/jobControl.js +11 -10
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +2 -2
- package/dist/controller/runtime.js +18 -61
- package/dist/controller/runtimeEventInbox.js +57 -34
- package/dist/controller/runtimeEventProcessor.js +36 -96
- package/dist/controller/runtimeHookTurnFence.js +33 -57
- package/dist/controller/runtimeLaunchCoordinator.js +44 -40
- package/dist/controller/runtimeObservationHook.js +18 -12
- package/dist/controller/sessionNotify.js +43 -28
- package/dist/controller/sessionOwnerReconciliation.js +21 -21
- package/dist/controller/structuredProviderObservation.js +13 -16
- package/dist/coordination/workMailboxQueue.js +132 -0
- package/dist/core/controllerServer.js +1 -0
- package/dist/domain/agentResultTransport.js +60 -0
- package/dist/execution/executionHealth.js +111 -118
- package/dist/execution/reviewMainTurn.js +161 -0
- package/dist/execution/workItemExecution.js +454 -0
- package/dist/execution/workItemExecutionProjection.js +309 -0
- package/dist/execution/workItemMainTurn.js +164 -0
- package/dist/executor/agentExecutor.js +19 -19
- package/dist/executor/executorRegistry.js +7 -28
- package/dist/executor/fileRoleLaunchPlanner.js +51 -83
- package/dist/external/githubPublicationVerifier.js +114 -0
- package/dist/external/gitlabPublicationVerifier.js +158 -0
- package/dist/external/pinnedCommandRunner.js +73 -0
- package/dist/integration/changeSetManifest.js +0 -3
- package/dist/integration/deliveryObligation.js +43 -6
- package/dist/integration/gitIntegrationService.js +284 -101
- package/dist/integration/integrationAttempt.js +64 -14
- package/dist/integration/integrationQueueEntry.js +5 -35
- package/dist/integration/integrationQueueService.js +65 -194
- package/dist/lifecycle/canonicalLifecycleEvent.js +16 -15
- package/dist/lifecycle/exactTurnTerminalization.js +100 -97
- package/dist/message/message.js +16 -0
- package/dist/observability/executionAudit.js +4 -25
- package/dist/observability/faultClassification.js +58 -70
- package/dist/observability/orchestrationMetrics.js +8 -50
- package/dist/profile/agentProfile.js +60 -15
- package/dist/profile/agentProfileRuntime.js +100 -0
- package/dist/release/releaseWorkflowPorts.js +5 -68
- package/dist/repository/executionLaneGitSnapshot.js +80 -0
- package/dist/repository/gitWorkspace.js +9 -67
- package/dist/repository/taskBaseFreshness.js +3 -1
- package/dist/repository/taskWorkspaceCoordinator.js +32 -4
- package/dist/repository/taskWorkspacePreparer.js +252 -411
- package/dist/resources/liveReferences.js +6 -55
- package/dist/resources/resourceDiscovery.js +1 -30
- package/dist/resources/resourceRegistrar.js +0 -23
- package/dist/review/deltaRecheck.js +8 -65
- package/dist/review/reviewAcceptance.js +22 -19
- package/dist/review/reviewConfig.js +0 -10
- package/dist/review/reviewDecision.js +2 -2
- package/dist/review/reviewRound.js +147 -273
- package/dist/review/reviewerAvailability.js +13 -23
- package/dist/role/role.js +3 -0
- package/dist/runtime/agentDriverObservation.js +1 -1
- package/dist/runtime/agentHost.js +51 -51
- package/dist/runtime/builtinAgentDrivers.js +9 -2
- package/dist/runtime/codexAppServerRuntime.js +23 -5
- package/dist/runtime/exactControlPlane.js +2 -267
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/launchBroker.js +11 -11
- package/dist/runtime/lifecycleReservation.js +2 -2
- package/dist/runtime/managedCaller.js +111 -0
- package/dist/runtime/ports.js +16 -3
- package/dist/runtime/preallocatedNativeSession.js +2 -2
- package/dist/runtime/processExitObservation.js +3 -2
- package/dist/runtime/providerContinuationReconciliationService.js +1 -1
- package/dist/runtime/runtimeBinding.js +1 -1
- package/dist/runtime/runtimeObservation.js +33 -16
- package/dist/runtime/runtimeSessionCandidate.js +2 -2
- package/dist/runtime/runtimeStopReceipt.js +11 -11
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/sessionOwnerIdentity.js +9 -9
- package/dist/runtime/sessionOwnerRegistry.js +13 -13
- package/dist/runtime/sessionReconciliation.js +4 -4
- package/dist/runtime/sessionTerminationGuard.js +9 -9
- package/dist/runtime/sessionTokenMetrics.js +5 -7
- package/dist/runtime/structuredProviderHost.js +5 -5
- package/dist/runtime/taskRuntimeIsolation.js +24 -24
- package/dist/runtime/tmuxAdapters.js +32 -30
- package/dist/scheduler/activeRoleTurnDelivery.js +37 -15
- package/dist/scheduler/leaderWakeupProcessor.js +78 -55
- package/dist/scheduler/roleTurnLiveness.js +6 -6
- package/dist/scheduler/roleTurnStall.js +8 -9
- package/dist/scheduler/taskExecutionProjection.js +19 -41
- package/dist/scheduler/taskObservabilityProjection.js +75 -122
- package/dist/storage/sqliteSchema.js +1 -21
- package/dist/storage/sqliteStore.js +62 -47
- package/dist/storage/storageSchema.js +1 -8
- package/dist/storage/storageVersions.js +7 -4
- package/dist/storage/taskStore.js +8 -8
- package/dist/storage/upgrade/upgradeOrchestrator.js +112 -83
- package/dist/task/completionReadiness.js +17 -98
- package/dist/task/deliveryGuard.js +9 -11
- package/dist/task/draftPlan.js +142 -0
- package/dist/task/nextAction.js +179 -477
- package/dist/task/publicationVerification.js +1 -0
- package/dist/task/remoteDelivery.js +233 -0
- package/dist/task/task.js +108 -4
- package/dist/task/taskRecordReference.js +0 -1
- package/dist/turn/turn.js +109 -16
- package/dist/verification/verificationGateService.js +0 -26
- package/dist/web/assets/client/components.js +99 -121
- package/dist/web/assets/client/i18n.js +136 -58
- package/dist/web/assets/client/view.js +44 -0
- package/dist/web/assets/styles/cards.js +3 -15
- package/dist/web/assets/styles/widgets.js +4 -0
- package/dist/web/webSnapshot.js +29 -14
- package/dist/workItem/dependencyGate.js +34 -0
- package/dist/workItem/workItem.js +99 -266
- package/dist/workspace/workItemChangeSetManager.js +15 -59
- package/docs/task-local-identity.md +1 -1
- package/i18n/README.zh-CN.md +165 -59
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +272 -782
- package/skills/yui-operator/SKILL.md +190 -365
- package/skills/yui-reviewer/SKILL.md +40 -33
- package/skills/yui-runtime/SKILL.md +27 -6
- package/skills/yui-worker/SKILL.md +19 -6
- package/dist/execution/candidateConvergence.js +0 -623
- package/dist/execution/executionGroup.js +0 -854
- package/dist/execution/resourceBroker.js +0 -426
- package/dist/executor/launchPlan.js +0 -16
- package/dist/review/reviewFinding.js +0 -240
- package/dist/review/reviewFindingLedger.js +0 -550
- package/dist/review/reviewOutcomeClassifier.js +0 -255
- package/dist/scheduler/resourceQueueProjection.js +0 -71
- package/dist/task/repairWave.js +0 -150
|
@@ -29,7 +29,7 @@ export async function reconcileExitedRoleTurns(store, delivery, now, selection,
|
|
|
29
29
|
adapterId: run.effective.adapterId,
|
|
30
30
|
turnId: run.id,
|
|
31
31
|
progressAt: run.createdAt,
|
|
32
|
-
...(session?.
|
|
32
|
+
...(session?.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId }),
|
|
33
33
|
...(session?.nativeSessionId === undefined
|
|
34
34
|
? {}
|
|
35
35
|
: { nativeSessionId: session.nativeSessionId })
|
|
@@ -64,7 +64,7 @@ export async function reconcileExitedRoleTurns(store, delivery, now, selection,
|
|
|
64
64
|
...(session?.nativeSessionId === undefined
|
|
65
65
|
? {}
|
|
66
66
|
: { nativeSessionId: session.nativeSessionId }),
|
|
67
|
-
...(session?.
|
|
67
|
+
...(session?.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId })
|
|
68
68
|
}]
|
|
69
69
|
: []))
|
|
70
70
|
: [], targetedInventory);
|
|
@@ -94,7 +94,7 @@ export async function reconcileExitedRoleTurns(store, delivery, now, selection,
|
|
|
94
94
|
taskId: task.id,
|
|
95
95
|
roleName: role.name,
|
|
96
96
|
turnId: run.id,
|
|
97
|
-
...(session?.
|
|
97
|
+
...(session?.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId }),
|
|
98
98
|
...(session?.nativeSessionId === undefined
|
|
99
99
|
? {}
|
|
100
100
|
: { nativeSessionId: session.nativeSessionId }),
|
|
@@ -123,16 +123,16 @@ export async function reconcileExitedRoleTurns(store, delivery, now, selection,
|
|
|
123
123
|
mode: "resume",
|
|
124
124
|
turnId: run.id,
|
|
125
125
|
nativeSessionId: session.nativeSessionId,
|
|
126
|
-
...(session.
|
|
126
|
+
...(session.runtimeGenerationId === undefined
|
|
127
127
|
? {}
|
|
128
|
-
: { hostActivationId: session.
|
|
128
|
+
: { hostActivationId: session.runtimeGenerationId })
|
|
129
129
|
});
|
|
130
130
|
store.saveRoleTurnPrepared({
|
|
131
131
|
task,
|
|
132
132
|
role,
|
|
133
133
|
turn: run,
|
|
134
134
|
session: recovered.session ?? session,
|
|
135
|
-
...(recovered.
|
|
135
|
+
...(recovered.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: recovered.runtimeGenerationId }),
|
|
136
136
|
now
|
|
137
137
|
});
|
|
138
138
|
liveStatuses?.set(`${task.id}\0${role.name}`, "present");
|
|
@@ -58,7 +58,7 @@ export function projectRoleTurnHealth(input) {
|
|
|
58
58
|
: session.status === "ended"
|
|
59
59
|
? session.endReason === "failed" ? "broken" : "stopped"
|
|
60
60
|
: !hasResourceIdentityText(session.nativeSessionId)
|
|
61
|
-
&& !hasResourceIdentityText(session.
|
|
61
|
+
&& !hasResourceIdentityText(session.runtimeGenerationId)
|
|
62
62
|
? "unknown"
|
|
63
63
|
: "matching";
|
|
64
64
|
const resourceActivity = hostLiveness === "present"
|
|
@@ -212,9 +212,8 @@ export function latestTurnDurableProgressAt(store, taskId, roleName, turnId, pre
|
|
|
212
212
|
const changeSets = store.listChangeSets?.(taskId)
|
|
213
213
|
.filter(({ workItemId }) => workItemId === run.workItemId)
|
|
214
214
|
?? [];
|
|
215
|
-
const changeSetIds = new Set(changeSets.map(({ id }) => id));
|
|
216
215
|
const integrations = store.listIntegrationAttempts?.(taskId)
|
|
217
|
-
.filter(({
|
|
216
|
+
.filter(({ source }) => (source.kind === "work-item" && source.workItemId === run.workItemId))
|
|
218
217
|
?? [];
|
|
219
218
|
const inputProgress = store.listInputRequests?.(taskId)
|
|
220
219
|
.filter((request) => (request.requester.turnId === run.id
|
|
@@ -509,7 +508,7 @@ export async function reconcileStalledRoleTurns(store, delivery, now, selection,
|
|
|
509
508
|
progressAt: run.createdAt,
|
|
510
509
|
agentId: session?.agentId ?? run.effective.agentId,
|
|
511
510
|
adapterId: session?.adapterId ?? run.effective.adapterId,
|
|
512
|
-
...(session?.
|
|
511
|
+
...(session?.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId }),
|
|
513
512
|
...(session?.nativeSessionId === undefined
|
|
514
513
|
? {}
|
|
515
514
|
: { nativeSessionId: session.nativeSessionId })
|
|
@@ -520,7 +519,7 @@ export async function reconcileStalledRoleTurns(store, delivery, now, selection,
|
|
|
520
519
|
progressAt: currentRoleTurnProgressAt(store, task.id, role.name, run).progressAt,
|
|
521
520
|
agentId: session?.agentId ?? run.effective.agentId,
|
|
522
521
|
adapterId: session?.adapterId ?? run.effective.adapterId,
|
|
523
|
-
...(session?.
|
|
522
|
+
...(session?.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId }),
|
|
524
523
|
...(session?.nativeSessionId === undefined
|
|
525
524
|
? {}
|
|
526
525
|
: { nativeSessionId: session.nativeSessionId })
|
|
@@ -624,9 +623,9 @@ export async function reconcileStalledRoleTurns(store, delivery, now, selection,
|
|
|
624
623
|
...(candidate.session.nativeSessionId === undefined
|
|
625
624
|
? {}
|
|
626
625
|
: { nativeSessionId: candidate.session.nativeSessionId }),
|
|
627
|
-
...(candidate.session.
|
|
626
|
+
...(candidate.session.runtimeGenerationId === undefined
|
|
628
627
|
? {}
|
|
629
|
-
: {
|
|
628
|
+
: { runtimeGenerationId: candidate.session.runtimeGenerationId })
|
|
630
629
|
};
|
|
631
630
|
const resourceSnapshot = resourceForRun(resourceEvidence, candidate.task.id, candidate.role.name, candidate.run.id);
|
|
632
631
|
const resourceIsCurrent = live === "present"
|
|
@@ -946,10 +945,10 @@ function resourceEvidenceMatchesCurrentRun(resource, expected, progressAt) {
|
|
|
946
945
|
|| identity.agentId !== expected.agentId
|
|
947
946
|
|| identity.adapterId !== expected.adapterId
|
|
948
947
|
|| identity.nativeSessionId !== expected.nativeSessionId
|
|
949
|
-
|| identity.
|
|
948
|
+
|| identity.runtimeGenerationId !== expected.runtimeGenerationId)
|
|
950
949
|
return false;
|
|
951
950
|
return hasResourceIdentityText(identity.nativeSessionId)
|
|
952
|
-
|| hasResourceIdentityText(identity.
|
|
951
|
+
|| hasResourceIdentityText(identity.runtimeGenerationId);
|
|
953
952
|
}
|
|
954
953
|
function hasResourceIdentityText(value) {
|
|
955
954
|
return typeof value === "string" && value.trim().length > 0;
|
|
@@ -35,7 +35,7 @@ export function buildTaskExecutionProjection(store, taskId, taskOverride, now =
|
|
|
35
35
|
turns,
|
|
36
36
|
executionGroups: store.listWorkItems === undefined && store.listReviewRounds === undefined
|
|
37
37
|
? []
|
|
38
|
-
: collectExecutionGroups(store.listWorkItems?.(taskId) ?? [], store.listReviewRounds?.(taskId) ?? []),
|
|
38
|
+
: collectExecutionGroups(store.listWorkItems?.(taskId) ?? [], store.listReviewRounds?.(taskId) ?? [], turns),
|
|
39
39
|
workItems: store.listWorkItems?.(taskId) ?? [],
|
|
40
40
|
...(store.listContextSnapshots === undefined
|
|
41
41
|
? {}
|
|
@@ -67,11 +67,12 @@ export function buildTaskExecutionProjection(store, taskId, taskOverride, now =
|
|
|
67
67
|
* unchanged revision.
|
|
68
68
|
*/
|
|
69
69
|
export function projectTaskExecutionFromFacts(facts) {
|
|
70
|
+
const turns = operationalTaskRecords(facts.turns, facts.events ?? [], "turn");
|
|
70
71
|
const executionGroups = facts.executionGroups
|
|
71
|
-
?? collectExecutionGroups(facts.workItems ?? [], facts.reviewRounds ?? []);
|
|
72
|
+
?? collectExecutionGroups(facts.workItems ?? [], facts.reviewRounds ?? [], turns);
|
|
72
73
|
return projectTaskExecution({
|
|
73
74
|
...facts,
|
|
74
|
-
turns
|
|
75
|
+
turns,
|
|
75
76
|
executionGroups
|
|
76
77
|
});
|
|
77
78
|
}
|
|
@@ -79,21 +80,18 @@ export function projectTaskExecution(facts) {
|
|
|
79
80
|
const { task, roles, turns, workItems = [], inputRequests = [], reviewRounds = [], integrations = [], events = [], pendingWakeup = null, leaderMailbox = null, leaderFailure = null, roleSessions = [], executionGroups = [] } = facts;
|
|
80
81
|
const now = facts.now ?? new Date();
|
|
81
82
|
const groupSummaries = executionGroups.map((group) => {
|
|
82
|
-
const stageGroups = workItems.find((item) => (item.executionGroups.some(({ id }) => id === group.id)))?.executionGroups;
|
|
83
83
|
return summarizeExecutionGroupHealth({
|
|
84
84
|
group,
|
|
85
|
-
...(stageGroups === undefined ? {} : { stageGroups }),
|
|
86
85
|
turns,
|
|
87
86
|
sessions: roleSessions,
|
|
88
87
|
events,
|
|
89
88
|
now,
|
|
90
|
-
|
|
89
|
+
...(facts.runtimeHealthPolicy === undefined
|
|
90
|
+
? {}
|
|
91
|
+
: { policy: facts.runtimeHealthPolicy })
|
|
91
92
|
});
|
|
92
93
|
});
|
|
93
|
-
const observabilityGroups = uniqueExecutionGroups(
|
|
94
|
-
...executionGroups,
|
|
95
|
-
...workItems.flatMap((item) => item.executionGroups)
|
|
96
|
-
]);
|
|
94
|
+
const observabilityGroups = uniqueExecutionGroups(executionGroups);
|
|
97
95
|
const sessionTokens = roleSessions.map((session) => {
|
|
98
96
|
const identity = resolveSessionTokenIdentity({ taskId: task.id, ...session });
|
|
99
97
|
return Object.freeze({
|
|
@@ -105,7 +103,6 @@ export function projectTaskExecution(facts) {
|
|
|
105
103
|
const observability = buildTaskObservabilityProjection({
|
|
106
104
|
workItems,
|
|
107
105
|
executionGroups: observabilityGroups,
|
|
108
|
-
groupSummaries,
|
|
109
106
|
turns,
|
|
110
107
|
events,
|
|
111
108
|
contextSnapshots: facts.contextSnapshots,
|
|
@@ -474,37 +471,18 @@ function uniqueExecutionGroups(groups) {
|
|
|
474
471
|
return true;
|
|
475
472
|
});
|
|
476
473
|
}
|
|
477
|
-
function collectExecutionGroups(workItems, reviewRounds) {
|
|
478
|
-
const workItemsById = new Map(workItems.map((item) => [item.id, item]));
|
|
479
|
-
const orderedRounds = [...reviewRounds].sort((left, right) => (left.id.localeCompare(right.id, undefined, { numeric: true })));
|
|
480
|
-
const latestTaskRound = orderedRounds
|
|
481
|
-
.filter((round) => (round.scope ?? "work-item") === "task")
|
|
482
|
-
.at(-1);
|
|
483
|
-
const latestWorkItemRounds = new Map();
|
|
484
|
-
for (const round of orderedRounds) {
|
|
485
|
-
if ((round.scope ?? "work-item") === "task"
|
|
486
|
-
|| round.workItemId === undefined
|
|
487
|
-
|| round.candidateId === undefined)
|
|
488
|
-
continue;
|
|
489
|
-
const item = workItemsById.get(round.workItemId);
|
|
490
|
-
if (item === undefined
|
|
491
|
-
|| item.status === "retired"
|
|
492
|
-
|| item.candidates.at(-1)?.id !== round.candidateId)
|
|
493
|
-
continue;
|
|
494
|
-
latestWorkItemRounds.set(`${round.workItemId}\0${round.candidateId}`, round);
|
|
495
|
-
}
|
|
496
|
-
const operationalReviewRoundIds = new Set([
|
|
497
|
-
...(latestTaskRound === undefined ? [] : [latestTaskRound.id]),
|
|
498
|
-
...[...latestWorkItemRounds.values()].map(({ id }) => id)
|
|
499
|
-
]);
|
|
474
|
+
function collectExecutionGroups(workItems, reviewRounds, _turns) {
|
|
500
475
|
const groups = [
|
|
501
|
-
...workItems.
|
|
502
|
-
const group =
|
|
476
|
+
...workItems.flatMap((item) => {
|
|
477
|
+
const group = item.status === "retired"
|
|
478
|
+
? undefined
|
|
479
|
+
: currentWorkItemExecutionGroup(item);
|
|
503
480
|
return group === undefined ? [] : [group];
|
|
504
481
|
}),
|
|
505
|
-
...reviewRounds.flatMap((round) => (
|
|
506
|
-
|
|
507
|
-
|
|
482
|
+
...reviewRounds.flatMap((round) => ((round.status === "pending" || round.status === "running")
|
|
483
|
+
&& round.executionGroup !== undefined
|
|
484
|
+
? [round.executionGroup]
|
|
485
|
+
: []))
|
|
508
486
|
];
|
|
509
487
|
const seen = new Set();
|
|
510
488
|
return groups.filter((group) => {
|
|
@@ -623,7 +601,7 @@ function collectBlockers(workItems, reviewRounds, integrations, openInputs, task
|
|
|
623
601
|
}
|
|
624
602
|
if (item.status === "pending" && (item.dependsOn ?? []).some((id) => {
|
|
625
603
|
const status = byId.get(id)?.status;
|
|
626
|
-
return status !== "completed"
|
|
604
|
+
return status !== "completed";
|
|
627
605
|
})) {
|
|
628
606
|
blockers.push({
|
|
629
607
|
kind: "work",
|
|
@@ -638,7 +616,7 @@ function collectBlockers(workItems, reviewRounds, integrations, openInputs, task
|
|
|
638
616
|
kind: "review",
|
|
639
617
|
id: round.id,
|
|
640
618
|
owner: "leader",
|
|
641
|
-
summary: round.
|
|
619
|
+
summary: round.failure?.message ?? `ReviewRound ${round.id} failed.`
|
|
642
620
|
});
|
|
643
621
|
}
|
|
644
622
|
for (const attempt of integrations.filter(({ status }) => status === "blocked" || status === "failed")) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { isDeepStrictEqual } from "node:util";
|
|
2
|
-
import { observedExecutionResourceUsage } from "../execution/resourceBroker.js";
|
|
3
1
|
/**
|
|
4
2
|
* Build the read-only DAG, execution, cost, and context view consumed by CLI
|
|
5
3
|
* and Web. It deliberately derives every value from existing Task records and
|
|
@@ -7,48 +5,20 @@ import { observedExecutionResourceUsage } from "../execution/resourceBroker.js";
|
|
|
7
5
|
*/
|
|
8
6
|
export function buildTaskObservabilityProjection(input) {
|
|
9
7
|
const now = input.now ?? new Date();
|
|
10
|
-
const summariesById = new Map((input.groupSummaries ?? []).map((summary) => [summary.groupId, summary]));
|
|
11
8
|
const dag = projectDag(input.workItems);
|
|
12
9
|
const workItems = input.workItems.map((item) => {
|
|
13
10
|
const groups = item.executionGroups;
|
|
14
|
-
const
|
|
15
|
-
const summary = summariesById.get(group.id);
|
|
16
|
-
return summary === undefined ? [] : [summary];
|
|
17
|
-
});
|
|
18
|
-
const stages = groups.map((group) => {
|
|
19
|
-
const summary = summariesById.get(group.id);
|
|
20
|
-
return Object.freeze({
|
|
21
|
-
groupId: group.id,
|
|
22
|
-
...(group.stage === undefined ? {} : {
|
|
23
|
-
mode: group.stage.mode,
|
|
24
|
-
stage: group.stage.stage,
|
|
25
|
-
round: group.stage.round,
|
|
26
|
-
stageAttempt: group.stage.stageAttempt
|
|
27
|
-
}),
|
|
28
|
-
laneCount: group.lanes.length,
|
|
29
|
-
activeLaneCount: group.lanes.filter(({ status }) => status === "pending" || status === "running").length,
|
|
30
|
-
terminalLaneCount: group.lanes.filter(({ status }) => isTerminalLane(status)).length,
|
|
31
|
-
...(group.resolution === undefined ? {} : { resolution: group.resolution.decision }),
|
|
32
|
-
...(summary?.resources === undefined ? {} : { resources: summary.resources })
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
const itemCost = projectCost(groups, input.turns, input.events, now);
|
|
11
|
+
const itemCost = projectWorkItemCost(groups, input.turns, now);
|
|
36
12
|
const itemContext = projectContext(groups, input.turns, input.contextSnapshots);
|
|
37
|
-
const
|
|
38
|
-
const openFindingCount = groups.reduce((count, group) => count + group.lanes.reduce((laneCount, lane) => laneCount + (lane.result?.findings ?? [])
|
|
39
|
-
.filter(({ status }) => status === "open").length, 0), 0);
|
|
13
|
+
const producerObservability = projectWorkItemProducerObservability(item, input.turns);
|
|
40
14
|
return Object.freeze({
|
|
41
15
|
workItemId: item.id,
|
|
42
16
|
title: item.title,
|
|
43
17
|
status: item.status,
|
|
44
|
-
...(item.currentExecutionGroupId === undefined ? {} : { currentGroupId: item.currentExecutionGroupId }),
|
|
45
18
|
groupIds: groups.map(({ id }) => id),
|
|
46
|
-
executionGroups,
|
|
47
|
-
stages,
|
|
48
19
|
cost: itemCost,
|
|
49
20
|
context: itemContext,
|
|
50
|
-
|
|
51
|
-
openFindingCount
|
|
21
|
+
resultCount: producerObservability?.resultCount ?? null
|
|
52
22
|
});
|
|
53
23
|
});
|
|
54
24
|
const cost = projectCost(input.executionGroups, input.turns, input.events, now);
|
|
@@ -61,6 +31,26 @@ export function buildTaskObservabilityProjection(input) {
|
|
|
61
31
|
sessionTokens: Object.freeze([...(input.sessionTokens ?? [])])
|
|
62
32
|
});
|
|
63
33
|
}
|
|
34
|
+
function projectWorkItemProducerObservability(item, turns) {
|
|
35
|
+
const successfulLanes = item.executionGroups.flatMap((group) => group.lanes.flatMap((lane) => (lane.disposition === "succeeded" ? [{ group, lane }] : [])));
|
|
36
|
+
let resultCount = 0;
|
|
37
|
+
for (const { group, lane } of successfulLanes) {
|
|
38
|
+
const turn = lane.successfulTurnId === undefined
|
|
39
|
+
? undefined
|
|
40
|
+
: turns.find(({ id }) => id === lane.successfulTurnId);
|
|
41
|
+
if (turn === undefined
|
|
42
|
+
|| turn.result === undefined
|
|
43
|
+
|| turn.status !== "completed"
|
|
44
|
+
|| turn.taskId !== item.taskId
|
|
45
|
+
|| turn.workItemId !== item.id
|
|
46
|
+
|| turn.executionGroupId !== group.id
|
|
47
|
+
|| turn.executionLaneId !== lane.id
|
|
48
|
+
|| turn.roleName !== lane.roleName)
|
|
49
|
+
return null;
|
|
50
|
+
resultCount += 1;
|
|
51
|
+
}
|
|
52
|
+
return { resultCount };
|
|
53
|
+
}
|
|
64
54
|
function projectDag(workItems) {
|
|
65
55
|
const byId = new Map(workItems.map((item) => [item.id, item]));
|
|
66
56
|
const dependents = new Map();
|
|
@@ -114,6 +104,10 @@ function rootCauses(id, byId) {
|
|
|
114
104
|
result.push(currentId);
|
|
115
105
|
return;
|
|
116
106
|
}
|
|
107
|
+
if (item.status === "retired") {
|
|
108
|
+
result.push(item.id);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
117
111
|
const unresolved = item.dependsOn.filter((dependency) => !dependencySatisfied(dependency, byId));
|
|
118
112
|
if (unresolved.length === 0) {
|
|
119
113
|
if (item.status === "failed" || item.status === "awaiting_acceptance")
|
|
@@ -121,7 +115,7 @@ function rootCauses(id, byId) {
|
|
|
121
115
|
return;
|
|
122
116
|
}
|
|
123
117
|
for (const dependency of unresolved) {
|
|
124
|
-
const target =
|
|
118
|
+
const target = byId.get(dependency);
|
|
125
119
|
if (target?.status === "failed" || target?.status === "awaiting_acceptance")
|
|
126
120
|
result.push(target.id);
|
|
127
121
|
else
|
|
@@ -132,8 +126,7 @@ function rootCauses(id, byId) {
|
|
|
132
126
|
return [...new Set(result)];
|
|
133
127
|
}
|
|
134
128
|
function dependencySatisfied(id, byId) {
|
|
135
|
-
|
|
136
|
-
return target !== undefined && (target.status === "completed" || (target.status === "retired" && target.disposition?.replacementWorkItemId === undefined));
|
|
129
|
+
return byId.get(id)?.status === "completed";
|
|
137
130
|
}
|
|
138
131
|
function dependencyEdgeStatus(id, byId) {
|
|
139
132
|
const target = byId.get(id);
|
|
@@ -141,53 +134,52 @@ function dependencyEdgeStatus(id, byId) {
|
|
|
141
134
|
return "dead";
|
|
142
135
|
if (dependencySatisfied(id, byId))
|
|
143
136
|
return "satisfied";
|
|
144
|
-
|
|
145
|
-
if (resolved === undefined)
|
|
137
|
+
if (target.status === "retired")
|
|
146
138
|
return "dead";
|
|
147
|
-
if (
|
|
139
|
+
if (target.status === "failed" || target.status === "awaiting_acceptance")
|
|
148
140
|
return "failed-open";
|
|
149
141
|
return "active";
|
|
150
142
|
}
|
|
151
|
-
function
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
143
|
+
function projectCost(groups, turns, _events, now) {
|
|
144
|
+
const uniqueGroups = [...new Map(groups.map((group) => [group.id, group])).values()];
|
|
145
|
+
const groupIds = new Set(uniqueGroups.map(({ id }) => id));
|
|
146
|
+
const attempts = turns.filter(({ executionGroupId }) => (executionGroupId !== undefined && groupIds.has(executionGroupId)));
|
|
147
|
+
const laneCount = uniqueGroups.reduce((total, group) => total + group.lanes.length, 0);
|
|
148
|
+
return Object.freeze({
|
|
149
|
+
tokens: 0,
|
|
150
|
+
toolCalls: 0,
|
|
151
|
+
wallClockSeconds: uniqueGroups.reduce((total, group) => total + groupDurationSeconds(group, now), 0),
|
|
152
|
+
tokensObservable: false,
|
|
153
|
+
toolCallsObservable: false,
|
|
154
|
+
laneCount,
|
|
155
|
+
groupCount: uniqueGroups.length,
|
|
156
|
+
retryCount: Math.max(0, attempts.length - laneCount),
|
|
157
|
+
marginalValuePercent: null,
|
|
158
|
+
marginalValueStatus: "unavailable"
|
|
159
|
+
});
|
|
161
160
|
}
|
|
162
|
-
function
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
toolCalls += usage.toolCalls;
|
|
176
|
-
tokensObservable = tokensObservable && (usage.tokensObservable ?? true);
|
|
177
|
-
toolCallsObservable = toolCallsObservable && (usage.toolCallsObservable ?? true);
|
|
178
|
-
wallClockSeconds += stageDurationSeconds(lineage, now);
|
|
179
|
-
laneCount += group.lanes.length;
|
|
180
|
-
retryCount += Math.max(0, lineage.length - 1);
|
|
181
|
-
}
|
|
161
|
+
function projectWorkItemCost(groups, turns, now) {
|
|
162
|
+
const groupIds = new Set(groups.map(({ id }) => id));
|
|
163
|
+
const attempts = turns.filter(({ executionGroupId }) => (executionGroupId !== undefined && groupIds.has(executionGroupId)));
|
|
164
|
+
const wallClockSeconds = groups.reduce((total, group) => {
|
|
165
|
+
const started = Date.parse(group.createdAt);
|
|
166
|
+
const ended = group.lanes.some(({ disposition }) => disposition === "open")
|
|
167
|
+
? now.getTime()
|
|
168
|
+
: Date.parse(group.updatedAt);
|
|
169
|
+
return total + (Number.isFinite(started) && Number.isFinite(ended)
|
|
170
|
+
? Math.max(0, Math.floor((ended - started) / 1_000))
|
|
171
|
+
: 0);
|
|
172
|
+
}, 0);
|
|
173
|
+
const laneCount = groups.reduce((total, group) => total + group.lanes.length, 0);
|
|
182
174
|
return Object.freeze({
|
|
183
|
-
tokens,
|
|
184
|
-
toolCalls,
|
|
175
|
+
tokens: 0,
|
|
176
|
+
toolCalls: 0,
|
|
185
177
|
wallClockSeconds,
|
|
186
|
-
tokensObservable,
|
|
187
|
-
toolCallsObservable,
|
|
178
|
+
tokensObservable: false,
|
|
179
|
+
toolCallsObservable: false,
|
|
188
180
|
laneCount,
|
|
189
|
-
groupCount:
|
|
190
|
-
retryCount,
|
|
181
|
+
groupCount: groups.length,
|
|
182
|
+
retryCount: Math.max(0, attempts.length - laneCount),
|
|
191
183
|
marginalValuePercent: null,
|
|
192
184
|
marginalValueStatus: "unavailable"
|
|
193
185
|
});
|
|
@@ -195,7 +187,7 @@ function projectCost(groups, turns, events, now) {
|
|
|
195
187
|
function projectContext(groups, turns, snapshots) {
|
|
196
188
|
const refs = new Map();
|
|
197
189
|
for (const group of groups) {
|
|
198
|
-
const ref = group.
|
|
190
|
+
const ref = group.assignment.contextSnapshotRef;
|
|
199
191
|
if (ref !== undefined)
|
|
200
192
|
refs.set(ref.id, ref);
|
|
201
193
|
}
|
|
@@ -231,51 +223,12 @@ function projectContext(groups, turns, snapshots) {
|
|
|
231
223
|
compressionStatus: "unavailable"
|
|
232
224
|
});
|
|
233
225
|
}
|
|
234
|
-
function
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
const key = group.stage === undefined ? `group:${group.id}` : stageKey(group);
|
|
238
|
-
const existing = latest.get(key);
|
|
239
|
-
if (existing === undefined || compareStageGroup(existing, group) < 0)
|
|
240
|
-
latest.set(key, group);
|
|
241
|
-
}
|
|
242
|
-
return [...latest.values()].sort((left, right) => left.createdAt.localeCompare(right.createdAt));
|
|
243
|
-
}
|
|
244
|
-
function sameStage(left, right) {
|
|
245
|
-
if (left.stage === undefined || right.stage === undefined)
|
|
246
|
-
return left.id === right.id;
|
|
247
|
-
return left.taskId === right.taskId
|
|
248
|
-
&& executionTargetKey(left) === executionTargetKey(right)
|
|
249
|
-
&& left.stage.mode === right.stage.mode
|
|
250
|
-
&& left.stage.stage === right.stage.stage
|
|
251
|
-
&& left.stage.round === right.stage.round
|
|
252
|
-
&& isDeepStrictEqual(left.stage.budget, right.stage.budget)
|
|
253
|
-
&& isDeepStrictEqual(left.stage.resources, right.stage.resources);
|
|
254
|
-
}
|
|
255
|
-
function stageKey(group) {
|
|
256
|
-
const stage = group.stage;
|
|
257
|
-
return `${executionTargetKey(group)}\0${stage.mode}\0${stage.stage}\0${stage.round}`;
|
|
258
|
-
}
|
|
259
|
-
function executionTargetKey(group) {
|
|
260
|
-
const target = group.target;
|
|
261
|
-
return `${target.kind}\0${target.workItemId ?? ""}\0${target.candidateId ?? ""}`;
|
|
262
|
-
}
|
|
263
|
-
function compareStageGroup(left, right) {
|
|
264
|
-
return (left.stage?.stageAttempt ?? 1) - (right.stage?.stageAttempt ?? 1)
|
|
265
|
-
|| left.updatedAt.localeCompare(right.updatedAt)
|
|
266
|
-
|| left.id.localeCompare(right.id);
|
|
267
|
-
}
|
|
268
|
-
function stageDurationSeconds(groups, now) {
|
|
269
|
-
const started = groups.map(({ createdAt }) => Date.parse(createdAt)).filter(Number.isFinite);
|
|
270
|
-
const ended = groups.map((group) => Date.parse(group.updatedAt)).filter(Number.isFinite);
|
|
271
|
-
if (started.length === 0)
|
|
272
|
-
return 0;
|
|
273
|
-
const hasOpenWork = groups.some((group) => group.lanes.some(({ status }) => (status === "pending" || status === "running")));
|
|
274
|
-
const end = hasOpenWork || ended.length === 0
|
|
226
|
+
function groupDurationSeconds(group, now) {
|
|
227
|
+
const started = Date.parse(group.createdAt);
|
|
228
|
+
const ended = group.lanes.some(({ disposition }) => disposition === "open")
|
|
275
229
|
? now.getTime()
|
|
276
|
-
:
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return status === "completed" || status === "failed" || status === "skipped";
|
|
230
|
+
: Date.parse(group.updatedAt);
|
|
231
|
+
return Number.isFinite(started) && Number.isFinite(ended)
|
|
232
|
+
? Math.max(0, Math.floor((ended - started) / 1_000))
|
|
233
|
+
: 0;
|
|
281
234
|
}
|
|
@@ -460,28 +460,10 @@ BEGIN
|
|
|
460
460
|
AND turn_id = NEW.turn_id AND generation = NEW.generation;
|
|
461
461
|
END;
|
|
462
462
|
`;
|
|
463
|
-
/**
|
|
464
|
-
* Cross-Round semantic review
|
|
465
|
-
* findings with stable keys and Leader dispositions. Failed execution attempts
|
|
466
|
-
* never create rows; only completed Rounds feed the ledger.
|
|
467
|
-
*/
|
|
468
|
-
const BASELINE_REVIEW_FINDING_SQL = `
|
|
469
|
-
CREATE TABLE IF NOT EXISTS review_findings (
|
|
470
|
-
task_id TEXT NOT NULL,
|
|
471
|
-
finding_id TEXT NOT NULL,
|
|
472
|
-
stable_key TEXT NOT NULL,
|
|
473
|
-
severity TEXT NOT NULL,
|
|
474
|
-
payload TEXT NOT NULL,
|
|
475
|
-
updated_at TEXT NOT NULL,
|
|
476
|
-
PRIMARY KEY (task_id, finding_id)
|
|
477
|
-
);
|
|
478
|
-
CREATE INDEX IF NOT EXISTS idx_review_findings_task ON review_findings(task_id);
|
|
479
|
-
CREATE INDEX IF NOT EXISTS idx_review_findings_stable_key ON review_findings(task_id, stable_key);
|
|
480
|
-
`;
|
|
481
463
|
/**
|
|
482
464
|
* Session owner physical identity records.
|
|
483
465
|
*
|
|
484
|
-
* One row per runtime generation, keyed by
|
|
466
|
+
* One row per runtime generation, keyed by runtime generation id. The payload column
|
|
485
467
|
* stores the full versioned JSON record; typed columns support the
|
|
486
468
|
* reconciliation queries (task/role lookup, PID liveness).
|
|
487
469
|
*/
|
|
@@ -671,7 +653,6 @@ const MIGRATION_1_SQL = [
|
|
|
671
653
|
BASELINE_JOB_AND_RELEASE_SQL,
|
|
672
654
|
BASELINE_JOB_CALLER_SQL,
|
|
673
655
|
BASELINE_TELEMETRY_AGGREGATE_SQL,
|
|
674
|
-
BASELINE_REVIEW_FINDING_SQL,
|
|
675
656
|
BASELINE_SESSION_OWNER_SQL,
|
|
676
657
|
BASELINE_RESOURCE_REGISTRY_SQL,
|
|
677
658
|
BASELINE_GATE_ARTIFACT_SQL,
|
|
@@ -886,7 +867,6 @@ export const SQLITE_SCHEMA_TABLES = [
|
|
|
886
867
|
"turns",
|
|
887
868
|
"active_turns",
|
|
888
869
|
"review_rounds",
|
|
889
|
-
"review_findings",
|
|
890
870
|
"change_sets",
|
|
891
871
|
"integration_attempts",
|
|
892
872
|
"messages",
|