@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
|
@@ -4,13 +4,6 @@ import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.j
|
|
|
4
4
|
import { projectRuntimeTaskEvents } from "../runtime/runtimeProjection.js";
|
|
5
5
|
import { DEFAULT_RUNTIME_HEALTH_POLICY } from "../runtime/runtimeHealthPolicy.js";
|
|
6
6
|
import { runOwnsBlockingProviderContinuation } from "../runtime/runtimeContinuationProjection.js";
|
|
7
|
-
import { summarizeExecutionGroup } from "./executionGroup.js";
|
|
8
|
-
import { executionStageSpendClosed, observedExecutionResourceUsage, projectExecutionStageResources } from "./resourceBroker.js";
|
|
9
|
-
/**
|
|
10
|
-
* Fold existing Turn, runtime, Session, process-exit, and stall facts into the
|
|
11
|
-
* four Lane health states. This is a read model only: it never advances a
|
|
12
|
-
* Lane, terminalizes a Turn, or guesses that silence means death.
|
|
13
|
-
*/
|
|
14
7
|
export function projectExecutionGroupHealth(input) {
|
|
15
8
|
const policy = input.policy ?? DEFAULT_RUNTIME_HEALTH_POLICY;
|
|
16
9
|
const lanes = input.group.lanes.map((lane) => projectExecutionLaneHealth(lane, input, policy));
|
|
@@ -21,79 +14,69 @@ export function projectExecutionGroupHealth(input) {
|
|
|
21
14
|
silentLaneCount: countHealth(lanes, "silent"),
|
|
22
15
|
suspectedStalledLaneCount: countHealth(lanes, "suspected-stalled"),
|
|
23
16
|
confirmedDeadLaneCount: countHealth(lanes, "confirmed-dead"),
|
|
24
|
-
reusableLaneIds: lanes.filter(({ resultReusable }) => resultReusable)
|
|
25
|
-
|
|
26
|
-
retryableLaneIds: lanes.filter(({ recovery }) => recovery === "retry-new-turn")
|
|
27
|
-
.map(({ laneId }) => laneId)
|
|
17
|
+
reusableLaneIds: lanes.filter(({ resultReusable }) => resultReusable).map(({ laneId }) => laneId),
|
|
18
|
+
retryableLaneIds: lanes.filter(({ recovery }) => recovery === "retry-new-turn").map(({ laneId }) => laneId)
|
|
28
19
|
});
|
|
29
20
|
}
|
|
30
|
-
/** Structural Group summary plus the health/recovery projection used by CLI/Web reads. */
|
|
31
21
|
export function summarizeExecutionGroupHealth(input) {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
22
|
+
const health = projectExecutionGroupHealth(input);
|
|
23
|
+
const healthByLane = new Map(health.lanes.map((lane) => [lane.laneId, lane]));
|
|
24
|
+
const laneSummaries = input.group.lanes.map((lane) => {
|
|
25
|
+
const projected = healthByLane.get(lane.id);
|
|
26
|
+
const turn = exactLaneTurn(input, lane);
|
|
27
|
+
return Object.freeze({
|
|
28
|
+
roleName: lane.roleName,
|
|
29
|
+
ordinal: lane.ordinal,
|
|
30
|
+
...(lane.currentTurnId === undefined ? {} : { turnId: lane.currentTurnId }),
|
|
31
|
+
...(lane.successfulTurnId === undefined
|
|
32
|
+
? {}
|
|
33
|
+
: { successfulTurnId: lane.successfulTurnId }),
|
|
34
|
+
status: projectedStatus(lane, turn),
|
|
35
|
+
...(lane.effective === undefined ? {} : { effective: lane.effective }),
|
|
36
|
+
...projected
|
|
46
37
|
});
|
|
47
|
-
|
|
38
|
+
});
|
|
48
39
|
return Object.freeze({
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})),
|
|
40
|
+
groupId: input.group.id,
|
|
41
|
+
purpose: "reviewRoundId" in input.group.assignment ? "review" : "execution",
|
|
42
|
+
kind: "replicated",
|
|
43
|
+
laneCount: input.group.lanes.length,
|
|
44
|
+
activeLaneCount: laneSummaries.filter(({ status }) => status === "running").length,
|
|
45
|
+
terminalLaneCount: input.group.lanes.filter(({ disposition }) => disposition !== "open").length,
|
|
46
|
+
succeededLaneCount: input.group.lanes.filter(({ disposition }) => disposition === "succeeded").length,
|
|
47
|
+
failedLaneCount: input.group.lanes.filter(({ disposition }) => disposition === "failed").length,
|
|
48
|
+
laneSummaries,
|
|
54
49
|
health: Object.freeze({
|
|
55
|
-
activeLaneCount:
|
|
56
|
-
silentLaneCount:
|
|
57
|
-
suspectedStalledLaneCount:
|
|
58
|
-
confirmedDeadLaneCount:
|
|
59
|
-
reusableLaneIds:
|
|
60
|
-
retryableLaneIds:
|
|
61
|
-
})
|
|
62
|
-
...(resources === undefined ? {} : { resources })
|
|
50
|
+
activeLaneCount: health.activeLaneCount,
|
|
51
|
+
silentLaneCount: health.silentLaneCount,
|
|
52
|
+
suspectedStalledLaneCount: health.suspectedStalledLaneCount,
|
|
53
|
+
confirmedDeadLaneCount: health.confirmedDeadLaneCount,
|
|
54
|
+
reusableLaneIds: health.reusableLaneIds,
|
|
55
|
+
retryableLaneIds: health.retryableLaneIds
|
|
56
|
+
})
|
|
63
57
|
});
|
|
64
58
|
}
|
|
65
|
-
/** Unresolved Lane recovery in deterministic operational priority order. */
|
|
66
59
|
export function actionableExecutionLaneRecoveries(groups) {
|
|
67
|
-
return groups
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (lane.recovery === "retry-new-turn"
|
|
71
|
-
&& group.resources !== undefined
|
|
72
|
-
&& executionStageSpendClosed(group.resources))
|
|
73
|
-
return [];
|
|
74
|
-
if (lane.recovery !== "retry-new-turn")
|
|
75
|
-
return [];
|
|
76
|
-
return [{
|
|
60
|
+
return groups.flatMap((group) => group.laneSummaries.flatMap((lane) => lane.recovery !== "retry-new-turn"
|
|
61
|
+
? []
|
|
62
|
+
: [{
|
|
77
63
|
groupId: group.groupId,
|
|
78
64
|
laneId: lane.laneId,
|
|
79
65
|
...(lane.turnId === undefined ? {} : { turnId: lane.turnId }),
|
|
80
66
|
...(lane.runtimeHealth === undefined ? {} : { runtimeHealth: lane.runtimeHealth }),
|
|
81
|
-
recovery:
|
|
82
|
-
}];
|
|
83
|
-
}));
|
|
67
|
+
recovery: "retry-new-turn"
|
|
68
|
+
}]));
|
|
84
69
|
}
|
|
85
70
|
function projectExecutionLaneHealth(lane, input, policy) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (lane.status !== "completed"
|
|
91
|
-
&& lane.turnId !== undefined
|
|
71
|
+
const turn = exactLaneTurn(input, lane);
|
|
72
|
+
const continuationAgentId = turn?.effective.agentId ?? lane.effective?.agentId;
|
|
73
|
+
if (lane.disposition === "open"
|
|
74
|
+
&& lane.currentTurnId !== undefined
|
|
92
75
|
&& continuationAgentId !== undefined
|
|
93
76
|
&& runOwnsBlockingProviderContinuation(input.events, {
|
|
94
77
|
taskId: input.group.taskId,
|
|
95
78
|
roleName: lane.roleName,
|
|
96
|
-
turnId: lane.
|
|
79
|
+
turnId: lane.currentTurnId,
|
|
97
80
|
agentId: continuationAgentId
|
|
98
81
|
})) {
|
|
99
82
|
return projection(lane, {
|
|
@@ -104,71 +87,63 @@ function projectExecutionLaneHealth(lane, input, policy) {
|
|
|
104
87
|
evidence: ["runtime-continuation-writer-owned"]
|
|
105
88
|
});
|
|
106
89
|
}
|
|
107
|
-
if (lane.
|
|
90
|
+
if (lane.disposition === "succeeded") {
|
|
108
91
|
return projection(lane, {
|
|
109
92
|
recovery: "reuse-result",
|
|
110
93
|
resultReusable: true,
|
|
111
|
-
reason: "the
|
|
112
|
-
evidence: ["execution-lane-
|
|
94
|
+
reason: "the successful Producer result is durable and immutable",
|
|
95
|
+
evidence: ["execution-lane-success"]
|
|
113
96
|
});
|
|
114
97
|
}
|
|
115
|
-
if (lane.
|
|
98
|
+
if (lane.disposition === "failed") {
|
|
116
99
|
return projection(lane, {
|
|
117
100
|
runtimeHealth: "confirmed-dead",
|
|
118
|
-
recovery: "retry-new-turn",
|
|
119
|
-
resultReusable: false,
|
|
120
|
-
reason: "the exact Lane attempt is durably failed; a retry must create a new Turn",
|
|
121
|
-
evidence: ["execution-lane-terminal-failure"]
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
if (lane.status === "skipped") {
|
|
125
|
-
return projection(lane, {
|
|
126
101
|
recovery: "none",
|
|
127
102
|
resultReusable: false,
|
|
128
|
-
reason: "the Lane was
|
|
129
|
-
evidence: ["execution-lane-
|
|
103
|
+
reason: "the logical Producer Lane was explicitly settled as failed",
|
|
104
|
+
evidence: ["execution-lane-settled-failure"]
|
|
130
105
|
});
|
|
131
106
|
}
|
|
132
|
-
if (lane.
|
|
107
|
+
if (lane.currentTurnId === undefined) {
|
|
133
108
|
return projection(lane, {
|
|
134
109
|
recovery: "none",
|
|
135
110
|
resultReusable: false,
|
|
136
|
-
reason: "the Lane has not
|
|
111
|
+
reason: "the Producer Lane has not been dispatched",
|
|
137
112
|
evidence: []
|
|
138
113
|
});
|
|
139
114
|
}
|
|
140
|
-
if (
|
|
115
|
+
if (turn === undefined) {
|
|
141
116
|
return projection(lane, {
|
|
142
117
|
runtimeHealth: "suspected-stalled",
|
|
143
118
|
recovery: "inspect",
|
|
144
119
|
resultReusable: false,
|
|
145
|
-
reason: "the
|
|
120
|
+
reason: "the open Lane has no exact current Turn",
|
|
146
121
|
evidence: ["execution-lineage-missing"]
|
|
147
122
|
});
|
|
148
123
|
}
|
|
149
|
-
if (
|
|
124
|
+
if (turn.status === "failed") {
|
|
150
125
|
return projection(lane, {
|
|
151
126
|
runtimeHealth: "confirmed-dead",
|
|
152
127
|
recovery: "retry-new-turn",
|
|
153
128
|
resultReusable: false,
|
|
154
|
-
reason: "the exact Turn is durably failed",
|
|
129
|
+
reason: "the exact current Turn is durably failed",
|
|
155
130
|
evidence: ["turn-terminal-failure"]
|
|
156
131
|
});
|
|
157
132
|
}
|
|
158
|
-
if (
|
|
133
|
+
if (turn.status === "completed") {
|
|
159
134
|
return projection(lane, {
|
|
160
135
|
runtimeHealth: "suspected-stalled",
|
|
161
136
|
recovery: "inspect",
|
|
162
137
|
resultReusable: false,
|
|
163
|
-
reason: "the
|
|
138
|
+
reason: "the current Turn completed without settling its logical Lane",
|
|
164
139
|
evidence: ["execution-lineage-inconsistent"]
|
|
165
140
|
});
|
|
166
141
|
}
|
|
167
|
-
const session = input.sessions.find((candidate) => (candidate.roleName ===
|
|
168
|
-
&& candidate.agentId ===
|
|
169
|
-
&& candidate.adapterId ===
|
|
170
|
-
const observations = exactTurnObservations(input.events,
|
|
171
|
-
const runtime = runtimeProjection(observations, input.events,
|
|
142
|
+
const session = input.sessions.find((candidate) => (candidate.roleName === turn.roleName
|
|
143
|
+
&& candidate.agentId === turn.effective.agentId
|
|
144
|
+
&& candidate.adapterId === turn.effective.adapterId));
|
|
145
|
+
const observations = exactTurnObservations(input.events, turn, session);
|
|
146
|
+
const runtime = runtimeProjection(observations, input.events, turn);
|
|
172
147
|
const unsettledContinuation = runtime !== null
|
|
173
148
|
&& Object.values(runtime.continuations).some((continuation) => (continuation.execution === "active"
|
|
174
149
|
|| continuation.execution === "unknown"
|
|
@@ -203,9 +178,8 @@ function projectExecutionLaneHealth(lane, input, policy) {
|
|
|
203
178
|
evidence: runtimeTerminalEvidence
|
|
204
179
|
});
|
|
205
180
|
}
|
|
206
|
-
const exit = latestExactProcessExit(input.events,
|
|
207
|
-
|
|
208
|
-
if (sessionDead
|
|
181
|
+
const exit = latestExactProcessExit(input.events, turn, session);
|
|
182
|
+
if (session?.status === "ended"
|
|
209
183
|
&& exit !== null
|
|
210
184
|
&& isAbnormalExit(exit.classification)
|
|
211
185
|
&& !unsettledChildWork) {
|
|
@@ -217,20 +191,20 @@ function projectExecutionLaneHealth(lane, input, policy) {
|
|
|
217
191
|
evidence: ["native-session-terminal", `process-exit:${exit.classification}`]
|
|
218
192
|
});
|
|
219
193
|
}
|
|
220
|
-
if (isRoleTurnStalled(input.events,
|
|
194
|
+
if (isRoleTurnStalled(input.events, turn.id)) {
|
|
221
195
|
return projection(lane, {
|
|
222
196
|
runtimeHealth: "suspected-stalled",
|
|
223
197
|
recovery: "inspect",
|
|
224
198
|
resultReusable: false,
|
|
225
|
-
reason: `the durable progress clock has not advanced since ${latestStallProgressAt(input.events,
|
|
199
|
+
reason: `the durable progress clock has not advanced since ${latestStallProgressAt(input.events, turn.id) ?? turn.updatedAt}; no death proof exists`,
|
|
226
200
|
evidence: ["turn-stalled"]
|
|
227
201
|
});
|
|
228
202
|
}
|
|
229
203
|
const activeOperation = runtime !== null
|
|
230
204
|
&& (Object.keys(runtime.operations).length > 0 || unsettledContinuation);
|
|
231
205
|
const lastActivityAt = runtime?.lastRuntimeActivityAt
|
|
232
|
-
??
|
|
233
|
-
??
|
|
206
|
+
?? turn.updatedAt
|
|
207
|
+
?? turn.createdAt;
|
|
234
208
|
const recentActivity = input.now.getTime() - Date.parse(lastActivityAt) < policy.quietAfterMs;
|
|
235
209
|
if (activeOperation || recentActivity) {
|
|
236
210
|
return projection(lane, {
|
|
@@ -244,7 +218,9 @@ function projectExecutionLaneHealth(lane, input, policy) {
|
|
|
244
218
|
: "the exact Turn has recent structured runtime activity",
|
|
245
219
|
evidence: unsettledContinuation
|
|
246
220
|
? ["runtime-continuation-unsettled"]
|
|
247
|
-
: activeOperation
|
|
221
|
+
: activeOperation
|
|
222
|
+
? ["runtime-operation-active"]
|
|
223
|
+
: ["runtime-activity-recent"]
|
|
248
224
|
});
|
|
249
225
|
}
|
|
250
226
|
return projection(lane, {
|
|
@@ -255,43 +231,42 @@ function projectExecutionLaneHealth(lane, input, policy) {
|
|
|
255
231
|
evidence: ["turn-active"]
|
|
256
232
|
});
|
|
257
233
|
}
|
|
258
|
-
function
|
|
259
|
-
return
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
&& run.executionLaneId === lane.id;
|
|
234
|
+
function exactLaneTurn(input, lane) {
|
|
235
|
+
return lane.currentTurnId === undefined
|
|
236
|
+
? undefined
|
|
237
|
+
: input.turns.find((turn) => (turn.taskId === input.group.taskId
|
|
238
|
+
&& turn.id === lane.currentTurnId
|
|
239
|
+
&& turn.executionGroupId === input.group.id
|
|
240
|
+
&& turn.executionLaneId === lane.id
|
|
241
|
+
&& turn.roleName === lane.roleName));
|
|
267
242
|
}
|
|
268
|
-
function exactTurnObservations(events,
|
|
243
|
+
function exactTurnObservations(events, turn, session) {
|
|
269
244
|
return events.map(runtimeObservationFromTaskEvent)
|
|
270
245
|
.filter((observation) => (observation !== null
|
|
271
|
-
&& observation.fence.taskId ===
|
|
272
|
-
&& observation.fence.turnId ===
|
|
273
|
-
&& observation.fence.roleName ===
|
|
274
|
-
&& observation.fence.agentId ===
|
|
275
|
-
&& (session?.
|
|
246
|
+
&& observation.fence.taskId === turn.taskId
|
|
247
|
+
&& observation.fence.turnId === turn.id
|
|
248
|
+
&& observation.fence.roleName === turn.roleName
|
|
249
|
+
&& observation.fence.agentId === turn.effective.agentId
|
|
250
|
+
&& (session?.runtimeGenerationId === undefined || observation.fence.runtimeGenerationId === session.runtimeGenerationId)
|
|
276
251
|
&& (session?.nativeSessionId === undefined
|
|
277
252
|
|| observation.fence.nativeSessionId === session.nativeSessionId)));
|
|
278
253
|
}
|
|
279
|
-
function runtimeProjection(observations, events,
|
|
254
|
+
function runtimeProjection(observations, events, turn) {
|
|
280
255
|
const first = observations[0];
|
|
281
256
|
return first === undefined
|
|
282
257
|
? null
|
|
283
|
-
: projectRuntimeTaskEvents(first.fence,
|
|
258
|
+
: projectRuntimeTaskEvents(first.fence, turn.createdAt, events);
|
|
284
259
|
}
|
|
285
|
-
function latestExactProcessExit(events,
|
|
260
|
+
function latestExactProcessExit(events, turn, session) {
|
|
286
261
|
const matching = events.flatMap((event) => {
|
|
287
262
|
if (event.type !== "runtime.process-exit-observed")
|
|
288
263
|
return [];
|
|
289
264
|
try {
|
|
290
265
|
const observation = validateRuntimeProcessExitObservation(JSON.parse(event.payload.observation ?? ""));
|
|
291
|
-
if (observation.taskId !==
|
|
292
|
-
|| observation.turnId !==
|
|
293
|
-
|| observation.roleName !==
|
|
294
|
-
|| (session?.
|
|
266
|
+
if (observation.taskId !== turn.taskId
|
|
267
|
+
|| observation.turnId !== turn.id
|
|
268
|
+
|| observation.roleName !== turn.roleName
|
|
269
|
+
|| (session?.runtimeGenerationId !== undefined && observation.runtimeGenerationId !== session.runtimeGenerationId)
|
|
295
270
|
|| (session?.nativeSessionId !== undefined
|
|
296
271
|
&& observation.nativeSessionId !== session.nativeSessionId))
|
|
297
272
|
return [];
|
|
@@ -309,6 +284,24 @@ function latestExactProcessExit(events, run, session) {
|
|
|
309
284
|
function isAbnormalExit(classification) {
|
|
310
285
|
return classification === "host-abnormal" || classification === "provider-turn-failed";
|
|
311
286
|
}
|
|
287
|
+
function projectedStatus(lane, turn) {
|
|
288
|
+
if (lane.disposition === "succeeded")
|
|
289
|
+
return "succeeded";
|
|
290
|
+
if (lane.disposition === "failed")
|
|
291
|
+
return "failed";
|
|
292
|
+
if (lane.currentTurnId === undefined)
|
|
293
|
+
return "pending";
|
|
294
|
+
if (turn === undefined)
|
|
295
|
+
return "unknown";
|
|
296
|
+
if (turn.status === "active")
|
|
297
|
+
return "running";
|
|
298
|
+
if (turn.status === "failed")
|
|
299
|
+
return "needs-attention";
|
|
300
|
+
return "unknown";
|
|
301
|
+
}
|
|
302
|
+
function projection(lane, fields) {
|
|
303
|
+
return Object.freeze({ laneId: lane.id, ...fields });
|
|
304
|
+
}
|
|
312
305
|
function countHealth(lanes, health) {
|
|
313
306
|
return lanes.filter(({ runtimeHealth }) => runtimeHealth === health).length;
|
|
314
307
|
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { enqueueRoleTurnDispatch } from "../coordination/workMailboxQueue.js";
|
|
2
|
+
import { createTurnInput } from "../context/turnInputContract.js";
|
|
3
|
+
import { contextSnapshotDeltaRefIds, freezeTurnContextSnapshot } from "../context/turnContextPack.js";
|
|
4
|
+
import { contextSnapshotRef } from "../context/contextSnapshot.js";
|
|
5
|
+
import { roleAgentSessionResumeMode } from "../executor/agentExecutor.js";
|
|
6
|
+
import { resolveEffectiveLaunch } from "../executor/effectiveLaunch.js";
|
|
7
|
+
import { createTaskEvent } from "../event/taskEvent.js";
|
|
8
|
+
import { finishReviewRound, startReviewRound } from "../review/reviewRound.js";
|
|
9
|
+
import { createTurn } from "../turn/turn.js";
|
|
10
|
+
import { executionGroupSettled, MINIMUM_SYNTHESIS_RESULTS } from "./workItemExecution.js";
|
|
11
|
+
export function successfulReviewSynthesisProducers(store, round, group) {
|
|
12
|
+
if (!executionGroupSettled(group)) {
|
|
13
|
+
throw new Error(`Review ExecutionGroup is not settled: ${round.id}/${group.id}.`);
|
|
14
|
+
}
|
|
15
|
+
return [...group.lanes]
|
|
16
|
+
.sort((left, right) => left.ordinal - right.ordinal || left.id.localeCompare(right.id))
|
|
17
|
+
.flatMap((lane) => {
|
|
18
|
+
if (lane.disposition !== "succeeded")
|
|
19
|
+
return [];
|
|
20
|
+
const turn = lane.successfulTurnId === undefined
|
|
21
|
+
? null
|
|
22
|
+
: store.getTurn(round.taskId, lane.successfulTurnId);
|
|
23
|
+
if (turn === null
|
|
24
|
+
|| turn.status !== "completed"
|
|
25
|
+
|| turn.purpose !== "review"
|
|
26
|
+
|| turn.reviewRoundId !== round.id
|
|
27
|
+
|| turn.executionGroupId !== group.id
|
|
28
|
+
|| turn.executionLaneId !== lane.id
|
|
29
|
+
|| turn.result === undefined) {
|
|
30
|
+
throw new Error(`Successful Review ExecutionLane has no exact Producer result: `
|
|
31
|
+
+ `${group.id}/${lane.id}.`);
|
|
32
|
+
}
|
|
33
|
+
return [{
|
|
34
|
+
laneId: lane.id,
|
|
35
|
+
roleName: lane.roleName,
|
|
36
|
+
turnId: turn.id
|
|
37
|
+
}];
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Projects a settled replicated Review into exactly one initial main Reviewer
|
|
42
|
+
* synthesis Turn. Explicit Turn retry may create later main attempts with the
|
|
43
|
+
* same source Group; successful producer Lanes remain immutable.
|
|
44
|
+
*/
|
|
45
|
+
export function reconcileReviewMainTurns(store, taskId, now) {
|
|
46
|
+
const task = store.getTask(taskId);
|
|
47
|
+
if (task === null || task.status !== "active") {
|
|
48
|
+
return { createdTurns: [], failedReviewRoundIds: [] };
|
|
49
|
+
}
|
|
50
|
+
const createdTurns = [];
|
|
51
|
+
const failedReviewRoundIds = [];
|
|
52
|
+
const rounds = [...store.listReviewRounds(taskId)]
|
|
53
|
+
.sort((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id));
|
|
54
|
+
for (const round of rounds) {
|
|
55
|
+
const group = round.executionGroup;
|
|
56
|
+
if (round.status !== "running"
|
|
57
|
+
|| group === undefined
|
|
58
|
+
|| round.reviewerTurnId !== undefined
|
|
59
|
+
|| !executionGroupSettled(group))
|
|
60
|
+
continue;
|
|
61
|
+
const producers = successfulReviewSynthesisProducers(store, round, group);
|
|
62
|
+
if (producers.length < MINIMUM_SYNTHESIS_RESULTS) {
|
|
63
|
+
const summary = `Review ExecutionGroup ${group.id} settled with ${producers.length} `
|
|
64
|
+
+ `successful Producer result${producers.length === 1 ? "" : "s"}; at least `
|
|
65
|
+
+ `${MINIMUM_SYNTHESIS_RESULTS} are required.`;
|
|
66
|
+
store.saveReviewRound(taskId, finishReviewRound(round, "failed", now, { kind: "quorum", message: summary }));
|
|
67
|
+
store.saveEvent(taskId, createTaskEvent(store.nextEventId(taskId), taskId, "review.execution-group-failed", {
|
|
68
|
+
reviewRoundId: round.id,
|
|
69
|
+
executionGroupId: group.id,
|
|
70
|
+
successfulProducerCount: String(producers.length),
|
|
71
|
+
requiredProducerCount: String(MINIMUM_SYNTHESIS_RESULTS)
|
|
72
|
+
}, now));
|
|
73
|
+
failedReviewRoundIds.push(round.id);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const existing = store.listTurns(taskId).filter((turn) => (turn.purpose === "review"
|
|
77
|
+
&& turn.reviewRoundId === round.id
|
|
78
|
+
&& turn.sourceExecutionGroupId === group.id));
|
|
79
|
+
if (existing.some(({ status }) => status !== "failed"))
|
|
80
|
+
continue;
|
|
81
|
+
const role = store.getRole(taskId, round.reviewerRoleName);
|
|
82
|
+
if (role === null) {
|
|
83
|
+
throw new Error(`Review main Role is missing: ${taskId}/${round.reviewerRoleName}.`);
|
|
84
|
+
}
|
|
85
|
+
if (store.getActiveTurn(taskId, role.name) !== null)
|
|
86
|
+
continue;
|
|
87
|
+
const workspace = store.getReviewRoundWorkspace(taskId, round.id);
|
|
88
|
+
if (workspace === null) {
|
|
89
|
+
throw new Error(`Review main workspace is missing: ${taskId}/${round.id}.`);
|
|
90
|
+
}
|
|
91
|
+
const effective = resolveEffectiveLaunch({
|
|
92
|
+
role,
|
|
93
|
+
purpose: "review",
|
|
94
|
+
workspace,
|
|
95
|
+
reviewRoundId: round.id,
|
|
96
|
+
reviewBaseCommit: round.reviewBaseCommit
|
|
97
|
+
});
|
|
98
|
+
const snapshot = freezeTurnContextSnapshot(store, {
|
|
99
|
+
taskId,
|
|
100
|
+
roleName: role.name,
|
|
101
|
+
purpose: "review",
|
|
102
|
+
...(round.workItemId === undefined ? {} : { workItemId: round.workItemId }),
|
|
103
|
+
reviewRoundId: round.id,
|
|
104
|
+
sourceExecutionGroupId: group.id
|
|
105
|
+
}, now, "controller", group.assignment.contextSnapshotRef);
|
|
106
|
+
const turn = createTurn(store.nextTurnId(taskId), taskId, role.name, roleAgentSessionResumeMode(store.getTaskRoleSessionSet(taskId, role.name), effective.agentId, effective), createTurnInput({
|
|
107
|
+
source: {
|
|
108
|
+
type: "yui",
|
|
109
|
+
channel: round.workItemId === undefined ? "task-dispatch" : "workitem-dispatch"
|
|
110
|
+
},
|
|
111
|
+
directive: synthesisDirective(group, producers),
|
|
112
|
+
contextSnapshotRef: contextSnapshotRef(snapshot),
|
|
113
|
+
deltaRefIds: contextSnapshotDeltaRefIds(store, snapshot)
|
|
114
|
+
}), now, {
|
|
115
|
+
...(round.workItemId === undefined ? {} : { workItemId: round.workItemId }),
|
|
116
|
+
purpose: "review",
|
|
117
|
+
reviewRoundId: round.id,
|
|
118
|
+
sourceExecutionGroupId: group.id,
|
|
119
|
+
workspace,
|
|
120
|
+
effective
|
|
121
|
+
});
|
|
122
|
+
store.saveTurn(turn);
|
|
123
|
+
store.saveReviewRound(taskId, startReviewRound(round, turn.id));
|
|
124
|
+
store.saveActiveTurn(turn);
|
|
125
|
+
enqueueRoleTurnDispatch(store, {
|
|
126
|
+
taskId,
|
|
127
|
+
roleName: role.name,
|
|
128
|
+
turnId: turn.id,
|
|
129
|
+
reason: "review-synthesis-ready",
|
|
130
|
+
occurredAt: now
|
|
131
|
+
});
|
|
132
|
+
store.saveEvent(taskId, createTaskEvent(store.nextEventId(taskId), taskId, "turn.review-dispatched", {
|
|
133
|
+
turnId: turn.id,
|
|
134
|
+
role: turn.roleName,
|
|
135
|
+
purpose: turn.purpose,
|
|
136
|
+
mode: turn.mode,
|
|
137
|
+
agent: `${turn.effective.agentId}/${turn.effective.adapterId}`,
|
|
138
|
+
effectiveRevision: String(turn.effective.sourceDesiredRevision),
|
|
139
|
+
profileAccess: turn.effective.profileAccess,
|
|
140
|
+
effectivePermission: turn.effective.permission.strategy,
|
|
141
|
+
writeProjectIds: turn.effective.writeProjectIds.join(",") || "none",
|
|
142
|
+
reviewRoundId: round.id,
|
|
143
|
+
sourceExecutionGroupId: group.id
|
|
144
|
+
}, now));
|
|
145
|
+
createdTurns.push(turn);
|
|
146
|
+
}
|
|
147
|
+
return { createdTurns, failedReviewRoundIds };
|
|
148
|
+
}
|
|
149
|
+
function synthesisDirective(group, producers) {
|
|
150
|
+
return [
|
|
151
|
+
"Act as the main Reviewer over every frozen successful Producer result in stable Lane order.",
|
|
152
|
+
"Expand each exact source Turn from the frozen Context Snapshot and consume its original result text plus Core-authored system evidence.",
|
|
153
|
+
"Resolve disagreements through review judgment against the frozen candidate. Do not rerun, retry, append, select, or abandon Lanes.",
|
|
154
|
+
"Return one complete original review result for the Leader; Yui Core does not parse or validate its semantic structure.",
|
|
155
|
+
JSON.stringify({
|
|
156
|
+
schemaVersion: 1,
|
|
157
|
+
sourceExecutionGroupId: group.id,
|
|
158
|
+
producers
|
|
159
|
+
}, null, 2)
|
|
160
|
+
].join("\n\n");
|
|
161
|
+
}
|