@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
|
@@ -2,10 +2,10 @@ import { requireIdentity, requireText, requireTimestamp } from "../domain/valida
|
|
|
2
2
|
import { validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
3
3
|
import { validateTaskFinalReviewContract } from "./taskFinalReviewContract.js";
|
|
4
4
|
import { validateManagedWorkspace } from "../worktree/managedWorkspace.js";
|
|
5
|
-
import { assertExecutionGroupTransition,
|
|
5
|
+
import { assertExecutionGroupTransition, retryFailedExecutionLanes, validateExecutionGroup, validateReviewExecutionAssignment } from "../execution/workItemExecution.js";
|
|
6
6
|
export function createReviewRound(id, taskId, workItemId, candidateId, reviewerRoleName, requestedBy, reviewBaseCommit, now, executionGroup) {
|
|
7
7
|
return validateReviewRound({
|
|
8
|
-
schemaVersion:
|
|
8
|
+
schemaVersion: 8,
|
|
9
9
|
id: requireIdentity(id, "ReviewRound id"),
|
|
10
10
|
taskId: requireIdentity(taskId, "Task id"),
|
|
11
11
|
workItemId: requireIdentity(workItemId, "Work Item id"),
|
|
@@ -21,7 +21,7 @@ export function createReviewRound(id, taskId, workItemId, candidateId, reviewerR
|
|
|
21
21
|
export function createTaskReviewRound(id, taskId, reviewerRoleName, requestedBy, taskCandidate, now, taskFinalReviewContract, executionGroup) {
|
|
22
22
|
const candidate = validateTaskReviewCandidate(taskCandidate);
|
|
23
23
|
return validateReviewRound({
|
|
24
|
-
schemaVersion:
|
|
24
|
+
schemaVersion: 8,
|
|
25
25
|
id: requireIdentity(id, "ReviewRound id"),
|
|
26
26
|
taskId: requireIdentity(taskId, "Task id"),
|
|
27
27
|
reviewerRoleName: requireIdentity(reviewerRoleName, "Reviewer Role"),
|
|
@@ -47,7 +47,7 @@ export function createTaskReviewRound(id, taskId, reviewerRoleName, requestedBy,
|
|
|
47
47
|
export function createTaskDeltaReviewRound(id, taskId, reviewerRoleName, requestedBy, taskCandidate, deltaRecheck, now, taskFinalReviewContract, executionGroup) {
|
|
48
48
|
const candidate = validateTaskReviewCandidate(taskCandidate);
|
|
49
49
|
return validateReviewRound({
|
|
50
|
-
schemaVersion:
|
|
50
|
+
schemaVersion: 8,
|
|
51
51
|
id: requireIdentity(id, "ReviewRound id"),
|
|
52
52
|
taskId: requireIdentity(taskId, "Task id"),
|
|
53
53
|
reviewerRoleName: requireIdentity(reviewerRoleName, "Reviewer Role"),
|
|
@@ -80,7 +80,10 @@ export function attachReviewRoundWorkspace(round, workspace) {
|
|
|
80
80
|
}
|
|
81
81
|
export function startReviewRound(round, reviewerTurnId) {
|
|
82
82
|
validateReviewRound(round);
|
|
83
|
-
if (round.status !== "pending"
|
|
83
|
+
if (round.status !== "pending"
|
|
84
|
+
&& !(round.status === "running"
|
|
85
|
+
&& round.executionGroup !== undefined
|
|
86
|
+
&& round.reviewerTurnId === undefined)) {
|
|
84
87
|
throw new Error(`ReviewRound cannot start from ${round.status}: ${round.id}.`);
|
|
85
88
|
}
|
|
86
89
|
if (round.workspace === undefined) {
|
|
@@ -92,74 +95,67 @@ export function startReviewRound(round, reviewerTurnId) {
|
|
|
92
95
|
status: "running"
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
|
-
export function
|
|
98
|
+
export function startReplicatedReviewRound(round) {
|
|
99
|
+
validateReviewRound(round);
|
|
100
|
+
if (round.status !== "pending" || round.executionGroup === undefined) {
|
|
101
|
+
throw new Error(`ReviewRound cannot start replicated execution: ${round.id}.`);
|
|
102
|
+
}
|
|
103
|
+
if (round.workspace === undefined) {
|
|
104
|
+
throw new Error(`ReviewRound workspace is not ready: ${round.id}.`);
|
|
105
|
+
}
|
|
106
|
+
return validateReviewRound({ ...round, status: "running" });
|
|
107
|
+
}
|
|
108
|
+
export function finishReviewRound(round, status, now, failure) {
|
|
96
109
|
validateReviewRound(round);
|
|
97
110
|
if (round.status !== "pending" && round.status !== "running") {
|
|
98
111
|
throw new Error(`ReviewRound is already terminal: ${round.id}.`);
|
|
99
112
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
status,
|
|
103
|
-
summary: requireText(summary, "Review summary"),
|
|
104
|
-
report: requireText(result.report ?? summary, "Review report"),
|
|
105
|
-
checks: validateChecks(result.checks ?? []),
|
|
106
|
-
...(result.evidenceCommit === undefined
|
|
107
|
-
? {}
|
|
108
|
-
: { evidenceCommit: requireCommit(result.evidenceCommit, "Review evidence commit") }),
|
|
109
|
-
endedAt: now.toISOString()
|
|
110
|
-
});
|
|
111
|
-
if (round.deltaRecheck === undefined) {
|
|
112
|
-
if (result.deltaDisposition !== undefined || result.deltaReasoning !== undefined) {
|
|
113
|
-
throw new Error(`Only a delta-recheck ReviewRound can carry a delta disposition: ${round.id}.`);
|
|
114
|
-
}
|
|
115
|
-
return terminal;
|
|
113
|
+
if (status === "completed" && failure !== undefined) {
|
|
114
|
+
throw new Error("A completed ReviewRound cannot carry failure metadata.");
|
|
116
115
|
}
|
|
117
|
-
if (status
|
|
118
|
-
|
|
119
|
-
// the candidate stays unaccepted.
|
|
120
|
-
return terminal;
|
|
116
|
+
if (status === "failed" && failure === undefined) {
|
|
117
|
+
throw new Error("A failed ReviewRound requires Core-owned failure metadata.");
|
|
121
118
|
}
|
|
122
|
-
// Fail closed: a completed delta Round without an explicit, valid
|
|
123
|
-
// disposition remains non-accepting for Leader routing. Uncertainty never accepts.
|
|
124
|
-
const disposition = result.deltaDisposition ?? "requires-full-review";
|
|
125
|
-
const reasoning = result.deltaReasoning ?? result.report ?? summary;
|
|
126
119
|
return validateReviewRound({
|
|
127
|
-
...
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
reasoning: requireText(reasoning, "Delta recheck reasoning")
|
|
132
|
-
})
|
|
120
|
+
...round,
|
|
121
|
+
status,
|
|
122
|
+
...(failure === undefined ? {} : { failure: validateReviewRoundFailure(failure) }),
|
|
123
|
+
endedAt: now.toISOString()
|
|
133
124
|
});
|
|
134
125
|
}
|
|
135
126
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
127
|
+
* Retry a failed review execution attempt under the same semantic Round
|
|
128
|
+
* identity. Turn history remains the attempt trail; the Round itself returns
|
|
129
|
+
* to pending so infrastructure retries do not manufacture a new semantic
|
|
130
|
+
* ReviewRound or duplicate findings.
|
|
140
131
|
*/
|
|
141
|
-
export function
|
|
132
|
+
export function retryReviewRound(round, requestedBy, now) {
|
|
142
133
|
validateReviewRound(round);
|
|
143
|
-
if ((round.scope ?? "work-item") !== "task") {
|
|
144
|
-
throw new Error(`Only a Task-final ReviewRound can be retried in place: ${round.id}.`);
|
|
145
|
-
}
|
|
146
134
|
if (round.status !== "failed") {
|
|
147
135
|
throw new Error(`ReviewRound ${round.id} is not retryable from ${round.status}.`);
|
|
148
136
|
}
|
|
149
|
-
const
|
|
150
|
-
? undefined
|
|
151
|
-
: retryReviewExecutionGroup(round, executionLaneId);
|
|
137
|
+
const taskScope = (round.scope ?? "work-item") === "task";
|
|
152
138
|
return validateReviewRound({
|
|
153
139
|
schemaVersion: round.schemaVersion,
|
|
154
140
|
id: round.id,
|
|
155
141
|
taskId: round.taskId,
|
|
142
|
+
...(round.scope === undefined ? {} : { scope: round.scope }),
|
|
143
|
+
...(taskScope
|
|
144
|
+
? {}
|
|
145
|
+
: {
|
|
146
|
+
workItemId: round.workItemId,
|
|
147
|
+
candidateId: round.candidateId
|
|
148
|
+
}),
|
|
156
149
|
reviewerRoleName: round.reviewerRoleName,
|
|
157
150
|
reviewBaseCommit: round.reviewBaseCommit,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
151
|
+
...(taskScope
|
|
152
|
+
? {
|
|
153
|
+
taskCandidate: round.taskCandidate,
|
|
154
|
+
...(round.taskFinalReviewContract === undefined
|
|
155
|
+
? {}
|
|
156
|
+
: { taskFinalReviewContract: round.taskFinalReviewContract })
|
|
157
|
+
}
|
|
158
|
+
: {}),
|
|
163
159
|
...(round.deltaRecheck === undefined
|
|
164
160
|
? {}
|
|
165
161
|
// A retried delta Round is still the same semantic recheck: the
|
|
@@ -176,129 +172,37 @@ export function retryTaskReviewRound(round, requestedBy, executionLaneId) {
|
|
|
176
172
|
deletedLines: round.deltaRecheck.deletedLines
|
|
177
173
|
})
|
|
178
174
|
}),
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
|
|
175
|
+
// A replicated retry preserves settled successful Producers and reopens
|
|
176
|
+
// only failed Lanes. If every Producer succeeded, only the main Reviewer
|
|
177
|
+
// Turn is retried.
|
|
178
|
+
...(round.executionGroup === undefined
|
|
179
|
+
? {}
|
|
180
|
+
: { executionGroup: retryFailedExecutionLanes(round.executionGroup, now) }),
|
|
182
181
|
requestedBy: validateReviewRequestSource(requestedBy),
|
|
183
182
|
status: "pending",
|
|
184
183
|
...(round.workspace === undefined ? {} : { workspace: round.workspace }),
|
|
185
184
|
createdAt: round.createdAt
|
|
186
185
|
});
|
|
187
186
|
}
|
|
188
|
-
/**
|
|
189
|
-
export function
|
|
187
|
+
/** Task-final compatibility wrapper for callers that require that scope. */
|
|
188
|
+
export function retryTaskReviewRound(round, requestedBy, now) {
|
|
189
|
+
if ((round.scope ?? "work-item") !== "task") {
|
|
190
|
+
throw new Error(`Only a Task-final ReviewRound can be retried in place: ${round.id}.`);
|
|
191
|
+
}
|
|
192
|
+
return retryReviewRound(round, requestedBy, now);
|
|
193
|
+
}
|
|
194
|
+
/** A failed producer attempt leaves its logical Lane open for another Turn. */
|
|
195
|
+
export function retryRunningReviewExecutionLane(round, executionLaneId, turnId) {
|
|
190
196
|
validateReviewRound(round);
|
|
191
197
|
if (round.status !== "running" || round.executionGroup === undefined) {
|
|
192
198
|
throw new Error(`ReviewRound ${round.id} has no running ExecutionGroup.`);
|
|
193
199
|
}
|
|
194
200
|
const lane = round.executionGroup.lanes.find(({ id }) => id === executionLaneId);
|
|
195
|
-
if (lane === undefined || lane.
|
|
201
|
+
if (lane === undefined || lane.disposition !== "open" || lane.currentTurnId !== turnId) {
|
|
196
202
|
throw new Error(`Review retry does not target the current failed Lane attempt: `
|
|
197
203
|
+ `${round.executionGroup.id}/${executionLaneId}/${turnId}.`);
|
|
198
204
|
}
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
function retryReviewExecutionGroup(round, executionLaneId, retryAt) {
|
|
202
|
-
const previous = round.executionGroup;
|
|
203
|
-
if (executionLaneId !== undefined) {
|
|
204
|
-
const exactLane = previous.lanes.find(({ id }) => id === executionLaneId);
|
|
205
|
-
if (exactLane === undefined || exactLane.status !== "failed") {
|
|
206
|
-
throw new Error(`Review retry Lane is not failed: ${previous.id}/${executionLaneId}.`);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
const now = retryAt ?? new Date(Date.parse(round.endedAt ?? round.createdAt));
|
|
210
|
-
const lanes = previous.lanes.map((lane) => (lane.status === "failed"
|
|
211
|
-
&& (executionLaneId === undefined || lane.id === executionLaneId)
|
|
212
|
-
? resetReviewExecutionLane(previous, lane.id, now)
|
|
213
|
-
: lane));
|
|
214
|
-
return validateExecutionGroup({
|
|
215
|
-
...previous,
|
|
216
|
-
lanes,
|
|
217
|
-
updatedAt: now.toISOString()
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
/** Accepts the Reviewer's complete report and extracts only optional known evidence. */
|
|
221
|
-
export function parseReviewResultReport(value) {
|
|
222
|
-
const report = requireText(value, "Review report");
|
|
223
|
-
let parsed;
|
|
224
|
-
try {
|
|
225
|
-
parsed = JSON.parse(report);
|
|
226
|
-
}
|
|
227
|
-
catch {
|
|
228
|
-
return { summary: report, report, checks: [] };
|
|
229
|
-
}
|
|
230
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
231
|
-
return { summary: report, report, checks: [] };
|
|
232
|
-
}
|
|
233
|
-
const record = parsed;
|
|
234
|
-
const summary = typeof record.summary === "string" && record.summary.trim().length > 0
|
|
235
|
-
? requireText(record.summary, "Review summary")
|
|
236
|
-
: report;
|
|
237
|
-
const checks = extractChecks(record.checks);
|
|
238
|
-
const findings = extractFindings(record.findings);
|
|
239
|
-
const evidence = extractEvidence(record.evidence);
|
|
240
|
-
const deltaDisposition = extractDeltaDisposition(record.deltaDisposition);
|
|
241
|
-
return {
|
|
242
|
-
summary,
|
|
243
|
-
report,
|
|
244
|
-
checks,
|
|
245
|
-
...(findings.length === 0 ? {} : { findings }),
|
|
246
|
-
...(evidence.length === 0 ? {} : { evidence }),
|
|
247
|
-
...(deltaDisposition === undefined ? {} : { deltaDisposition }),
|
|
248
|
-
...(typeof record.deltaReasoning !== "string"
|
|
249
|
-
|| record.deltaReasoning.trim().length === 0
|
|
250
|
-
? {}
|
|
251
|
-
: { deltaReasoning: requireText(record.deltaReasoning, "Delta recheck reasoning") }),
|
|
252
|
-
...(typeof record.evidenceCommit !== "string"
|
|
253
|
-
? {}
|
|
254
|
-
: {
|
|
255
|
-
evidenceCommit: requireCommit(record.evidenceCommit, "Review evidence commit")
|
|
256
|
-
})
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
function extractDeltaDisposition(value) {
|
|
260
|
-
if (value !== "equivalent-and-accepted"
|
|
261
|
-
&& value !== "finding"
|
|
262
|
-
&& value !== "requires-full-review") {
|
|
263
|
-
return undefined;
|
|
264
|
-
}
|
|
265
|
-
return value;
|
|
266
|
-
}
|
|
267
|
-
function extractFindings(value) {
|
|
268
|
-
if (!Array.isArray(value))
|
|
269
|
-
return [];
|
|
270
|
-
return value.flatMap((entry) => {
|
|
271
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
272
|
-
return [];
|
|
273
|
-
}
|
|
274
|
-
const finding = entry;
|
|
275
|
-
if (typeof finding.id !== "string"
|
|
276
|
-
|| (finding.severity !== "low" && finding.severity !== "medium"
|
|
277
|
-
&& finding.severity !== "high" && finding.severity !== "critical"
|
|
278
|
-
&& finding.severity !== "p1" && finding.severity !== "p2")
|
|
279
|
-
|| (finding.status !== "open" && finding.status !== "resolved")
|
|
280
|
-
|| typeof finding.summary !== "string") {
|
|
281
|
-
return [];
|
|
282
|
-
}
|
|
283
|
-
return [{
|
|
284
|
-
id: requireIdentity(finding.id, "Review finding id"),
|
|
285
|
-
// Reviewers may use the product-level P1/P2 vocabulary. Execution
|
|
286
|
-
// groups keep one canonical severity scale so resolution gates remain
|
|
287
|
-
// stable across Worker and Reviewer reports.
|
|
288
|
-
severity: finding.severity === "p1"
|
|
289
|
-
? "critical"
|
|
290
|
-
: finding.severity === "p2"
|
|
291
|
-
? "high"
|
|
292
|
-
: finding.severity,
|
|
293
|
-
status: finding.status,
|
|
294
|
-
summary: requireText(finding.summary, "Review finding summary")
|
|
295
|
-
}];
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
function extractEvidence(value) {
|
|
299
|
-
if (!Array.isArray(value))
|
|
300
|
-
return [];
|
|
301
|
-
return value.flatMap((entry) => (typeof entry === "string" && entry.trim().length > 0 ? [entry.trim()] : []));
|
|
205
|
+
return round;
|
|
302
206
|
}
|
|
303
207
|
export function recordReviewWorkspaceDisposition(round, disposition, now) {
|
|
304
208
|
validateReviewRound(round);
|
|
@@ -348,9 +252,8 @@ export function updateReviewExecutionGroup(round, executionGroup) {
|
|
|
348
252
|
}
|
|
349
253
|
return validateReviewRound({ ...round, executionGroup });
|
|
350
254
|
}
|
|
351
|
-
if (round.executionGroup.id !== executionGroup.id
|
|
352
|
-
|
|
353
|
-
throw new Error(`ReviewRound ExecutionGroup target is immutable: ${round.id}.`);
|
|
255
|
+
if (round.executionGroup.id !== executionGroup.id) {
|
|
256
|
+
throw new Error(`ReviewRound ExecutionGroup identity is immutable: ${round.id}.`);
|
|
354
257
|
}
|
|
355
258
|
if (JSON.stringify(round.executionGroup) === JSON.stringify(executionGroup))
|
|
356
259
|
return round;
|
|
@@ -358,8 +261,30 @@ export function updateReviewExecutionGroup(round, executionGroup) {
|
|
|
358
261
|
return validateReviewRound({ ...round, executionGroup });
|
|
359
262
|
}
|
|
360
263
|
export function validateReviewRound(round) {
|
|
361
|
-
|
|
362
|
-
|
|
264
|
+
rejectUnknownFields(round, [
|
|
265
|
+
"schemaVersion",
|
|
266
|
+
"id",
|
|
267
|
+
"taskId",
|
|
268
|
+
"workItemId",
|
|
269
|
+
"candidateId",
|
|
270
|
+
"reviewerRoleName",
|
|
271
|
+
"reviewerTurnId",
|
|
272
|
+
"reviewBaseCommit",
|
|
273
|
+
"scope",
|
|
274
|
+
"taskCandidate",
|
|
275
|
+
"taskFinalReviewContract",
|
|
276
|
+
"deltaRecheck",
|
|
277
|
+
"executionGroup",
|
|
278
|
+
"workspace",
|
|
279
|
+
"requestedBy",
|
|
280
|
+
"status",
|
|
281
|
+
"failure",
|
|
282
|
+
"workspaceDisposition",
|
|
283
|
+
"createdAt",
|
|
284
|
+
"endedAt"
|
|
285
|
+
], "ReviewRound");
|
|
286
|
+
if (round.schemaVersion !== 8)
|
|
287
|
+
throw new Error("ReviewRound must use schemaVersion 8.");
|
|
363
288
|
validateTaskRecordReference({ taskId: round.taskId, localId: round.id }, "reviewRound");
|
|
364
289
|
requireIdentity(round.reviewerRoleName, "Reviewer Role");
|
|
365
290
|
requireCommit(round.reviewBaseCommit, "Review base commit");
|
|
@@ -424,29 +349,30 @@ export function validateReviewRound(round) {
|
|
|
424
349
|
requireTimestamp(round.createdAt, "ReviewRound createdAt");
|
|
425
350
|
const terminal = round.status === "completed" || round.status === "failed";
|
|
426
351
|
if (terminal) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if (round.
|
|
431
|
-
|
|
432
|
-
// when the reviewer ran checks on the frozen candidate tree; differs
|
|
433
|
-
// when the reviewer committed diagnostics on top of it. A dirty
|
|
434
|
-
// review with uncommitted changes records no evidenceCommit, since no
|
|
435
|
-
// single commit captures the checked tree.
|
|
436
|
-
requireCommit(round.evidenceCommit, "Review evidence commit");
|
|
352
|
+
if (round.status === "completed" && round.reviewerTurnId === undefined) {
|
|
353
|
+
throw new Error("A completed ReviewRound requires its exact main Reviewer Turn.");
|
|
354
|
+
}
|
|
355
|
+
if (round.status === "completed" && round.failure !== undefined) {
|
|
356
|
+
throw new Error("A completed ReviewRound cannot carry failure metadata.");
|
|
437
357
|
}
|
|
358
|
+
if (round.status === "failed" && round.failure === undefined) {
|
|
359
|
+
throw new Error("A failed ReviewRound requires failure metadata.");
|
|
360
|
+
}
|
|
361
|
+
if (round.failure !== undefined)
|
|
362
|
+
validateReviewRoundFailure(round.failure);
|
|
438
363
|
requireTimestamp(round.endedAt ?? "", "ReviewRound endedAt");
|
|
439
364
|
}
|
|
440
|
-
else if (round.
|
|
441
|
-
|| round.report !== undefined
|
|
442
|
-
|| round.checks !== undefined
|
|
443
|
-
|| round.evidenceCommit !== undefined
|
|
365
|
+
else if (round.failure !== undefined
|
|
444
366
|
|| round.endedAt !== undefined) {
|
|
445
367
|
throw new Error("An active ReviewRound cannot have terminal metadata.");
|
|
446
368
|
}
|
|
369
|
+
if (round.status === "running" && round.workspace === undefined) {
|
|
370
|
+
throw new Error("A running ReviewRound requires its main Reviewer workspace.");
|
|
371
|
+
}
|
|
447
372
|
if (round.status === "running"
|
|
448
|
-
&&
|
|
449
|
-
|
|
373
|
+
&& round.reviewerTurnId === undefined
|
|
374
|
+
&& round.executionGroup === undefined) {
|
|
375
|
+
throw new Error("A running ReviewRound requires a direct Reviewer Turn or replicated Group.");
|
|
450
376
|
}
|
|
451
377
|
if (round.workspaceDisposition !== undefined) {
|
|
452
378
|
if (!terminal || round.workspace === undefined) {
|
|
@@ -459,23 +385,19 @@ export function validateReviewRound(round) {
|
|
|
459
385
|
}
|
|
460
386
|
requireTimestamp(round.workspaceDisposition.recordedAt, "Review workspace disposition time");
|
|
461
387
|
}
|
|
462
|
-
if (round.deltaRecheck?.disposition !== undefined) {
|
|
463
|
-
if (!terminal) {
|
|
464
|
-
throw new Error("An active delta-recheck ReviewRound cannot have a disposition.");
|
|
465
|
-
}
|
|
466
|
-
if (round.deltaRecheck.reasoning === undefined
|
|
467
|
-
|| round.deltaRecheck.reasoning.trim().length === 0) {
|
|
468
|
-
throw new Error("A terminal delta-recheck ReviewRound requires reasoning.");
|
|
469
|
-
}
|
|
470
|
-
if (round.deltaRecheck.escalatedToReviewRoundId !== undefined
|
|
471
|
-
&& round.deltaRecheck.disposition !== "requires-full-review") {
|
|
472
|
-
throw new Error("Only a requires-full-review delta-recheck can record an escalation.");
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
388
|
return round;
|
|
476
389
|
}
|
|
477
390
|
/** Validates a delta-recheck record's immutable identity and terminal fields. */
|
|
478
391
|
export function validateDeltaRecheckRecord(record) {
|
|
392
|
+
rejectUnknownFields(record, [
|
|
393
|
+
"schemaVersion",
|
|
394
|
+
"previousReviewRoundId",
|
|
395
|
+
"previousBaseCommit",
|
|
396
|
+
"diffDigest",
|
|
397
|
+
"changedFiles",
|
|
398
|
+
"addedLines",
|
|
399
|
+
"deletedLines"
|
|
400
|
+
], "Delta recheck record");
|
|
479
401
|
if (record.schemaVersion !== 1) {
|
|
480
402
|
throw new Error("Delta recheck record must use schemaVersion 1.");
|
|
481
403
|
}
|
|
@@ -492,59 +414,43 @@ export function validateDeltaRecheckRecord(record) {
|
|
|
492
414
|
|| !Number.isInteger(record.deletedLines) || record.deletedLines < 0) {
|
|
493
415
|
throw new Error("Delta recheck line counts are invalid.");
|
|
494
416
|
}
|
|
495
|
-
if (record.disposition !== undefined
|
|
496
|
-
&& record.disposition !== "equivalent-and-accepted"
|
|
497
|
-
&& record.disposition !== "finding"
|
|
498
|
-
&& record.disposition !== "requires-full-review") {
|
|
499
|
-
throw new Error(`Delta recheck disposition is invalid: ${String(record.disposition)}.`);
|
|
500
|
-
}
|
|
501
|
-
if (record.reasoning !== undefined) {
|
|
502
|
-
requireText(record.reasoning, "Delta recheck reasoning");
|
|
503
|
-
}
|
|
504
|
-
if (record.escalatedToReviewRoundId !== undefined) {
|
|
505
|
-
requireIdentity(record.escalatedToReviewRoundId, "Delta recheck escalation ReviewRound id");
|
|
506
|
-
}
|
|
507
417
|
return record;
|
|
508
418
|
}
|
|
509
419
|
/** True when this Round is an Issue 07 delta-recheck. */
|
|
510
420
|
export function isDeltaRecheckRound(round) {
|
|
511
421
|
return round.deltaRecheck !== undefined;
|
|
512
422
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
export function deltaRecheckBlocksAcceptance(round) {
|
|
526
|
-
return round.deltaRecheck !== undefined
|
|
527
|
-
&& round.status === "completed"
|
|
528
|
-
&& round.deltaRecheck.disposition !== undefined
|
|
529
|
-
&& round.deltaRecheck.disposition !== "equivalent-and-accepted";
|
|
423
|
+
function validateReviewRoundFailure(failure) {
|
|
424
|
+
rejectUnknownFields(failure, [
|
|
425
|
+
"kind",
|
|
426
|
+
"message"
|
|
427
|
+
], "ReviewRound failure");
|
|
428
|
+
if (failure.kind !== "dispatch"
|
|
429
|
+
&& failure.kind !== "execution"
|
|
430
|
+
&& failure.kind !== "quorum") {
|
|
431
|
+
throw new Error("ReviewRound failure kind is invalid.");
|
|
432
|
+
}
|
|
433
|
+
requireText(failure.message, "ReviewRound failure message");
|
|
434
|
+
return failure;
|
|
530
435
|
}
|
|
531
436
|
function validateReviewExecutionGroup(group, round) {
|
|
532
437
|
validateExecutionGroup(group);
|
|
533
|
-
|
|
438
|
+
const assignment = validateReviewExecutionAssignment(group.assignment);
|
|
439
|
+
if (group.taskId !== round.taskId
|
|
440
|
+
|| assignment.taskId !== round.taskId
|
|
441
|
+
|| assignment.reviewRoundId !== round.id
|
|
442
|
+
|| assignment.reviewBaseCommit !== round.reviewBaseCommit
|
|
443
|
+
|| assignment.scope !== (round.scope ?? "work-item")) {
|
|
534
444
|
throw new Error(`ReviewRound ExecutionGroup provenance is invalid: ${round.id}.`);
|
|
535
445
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (group.target.kind !== expectedKind
|
|
540
|
-
|| group.target.taskId !== round.taskId) {
|
|
541
|
-
throw new Error(`ReviewRound ExecutionGroup target is invalid: ${round.id}.`);
|
|
542
|
-
}
|
|
543
|
-
if (expectedKind === "work-item"
|
|
544
|
-
&& (group.target.workItemId !== round.workItemId
|
|
545
|
-
|| group.target.candidateId !== round.candidateId)) {
|
|
446
|
+
if ((round.scope ?? "work-item") === "work-item"
|
|
447
|
+
&& (assignment.workItemId !== round.workItemId
|
|
448
|
+
|| assignment.candidateId !== round.candidateId)) {
|
|
546
449
|
throw new Error(`ReviewRound ExecutionGroup WorkItem target is invalid: ${round.id}.`);
|
|
547
450
|
}
|
|
451
|
+
if (group.lanes.some(({ roleName }) => roleName === round.reviewerRoleName)) {
|
|
452
|
+
throw new Error(`The main Reviewer cannot also be a Producer Lane: ${round.id}.`);
|
|
453
|
+
}
|
|
548
454
|
return group;
|
|
549
455
|
}
|
|
550
456
|
export function validateTaskReviewCandidate(candidate) {
|
|
@@ -563,26 +469,6 @@ export function validateTaskReviewCandidate(candidate) {
|
|
|
563
469
|
}
|
|
564
470
|
return { schemaVersion: 1, projects };
|
|
565
471
|
}
|
|
566
|
-
function extractChecks(value) {
|
|
567
|
-
if (!Array.isArray(value))
|
|
568
|
-
return [];
|
|
569
|
-
const extracted = value.flatMap((entry) => {
|
|
570
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
571
|
-
return [];
|
|
572
|
-
const check = entry;
|
|
573
|
-
if (typeof check.name !== "string"
|
|
574
|
-
|| (check.outcome !== "passed"
|
|
575
|
-
&& check.outcome !== "failed"
|
|
576
|
-
&& check.outcome !== "skipped"))
|
|
577
|
-
return [];
|
|
578
|
-
return [{
|
|
579
|
-
name: check.name,
|
|
580
|
-
outcome: check.outcome,
|
|
581
|
-
...(typeof check.details === "string" ? { details: check.details } : {})
|
|
582
|
-
}];
|
|
583
|
-
});
|
|
584
|
-
return validateChecks(extracted);
|
|
585
|
-
}
|
|
586
472
|
function validateReviewWorkspace(round, workspace) {
|
|
587
473
|
validateManagedWorkspace(workspace);
|
|
588
474
|
if (workspace.owner.taskId !== round.taskId) {
|
|
@@ -600,24 +486,6 @@ function validateReviewWorkspace(round, workspace) {
|
|
|
600
486
|
throw new Error(`ReviewRound workspace does not contain its review base: ${round.id}.`);
|
|
601
487
|
}
|
|
602
488
|
}
|
|
603
|
-
function validateChecks(checks) {
|
|
604
|
-
if (!Array.isArray(checks))
|
|
605
|
-
throw new Error("Review checks are invalid.");
|
|
606
|
-
return checks.map((check) => {
|
|
607
|
-
const name = requireText(check.name, "Review check name");
|
|
608
|
-
if (check.outcome !== "passed" && check.outcome !== "failed"
|
|
609
|
-
&& check.outcome !== "skipped") {
|
|
610
|
-
throw new Error(`Review check outcome is invalid: ${String(check.outcome)}.`);
|
|
611
|
-
}
|
|
612
|
-
return {
|
|
613
|
-
name,
|
|
614
|
-
outcome: check.outcome,
|
|
615
|
-
...(check.details === undefined
|
|
616
|
-
? {}
|
|
617
|
-
: { details: requireText(check.details, "Review check details") })
|
|
618
|
-
};
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
489
|
function requireCommit(value, label) {
|
|
622
490
|
const commit = requireText(value, label).toLowerCase();
|
|
623
491
|
if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/u.test(commit)) {
|
|
@@ -634,3 +502,9 @@ function validateReviewRequestSource(source) {
|
|
|
634
502
|
}
|
|
635
503
|
return source;
|
|
636
504
|
}
|
|
505
|
+
function rejectUnknownFields(value, fields, label) {
|
|
506
|
+
const allowed = new Set(fields);
|
|
507
|
+
const unknown = Object.keys(value).find((field) => !allowed.has(field));
|
|
508
|
+
if (unknown !== undefined)
|
|
509
|
+
throw new Error(`${label} has unknown field: ${unknown}.`);
|
|
510
|
+
}
|
|
@@ -2,9 +2,8 @@ import { nextPendingBatch, mailboxHasWork } from "../coordination/workMailbox.js
|
|
|
2
2
|
import { runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
3
3
|
/** One authoritative read-only projection for a Task Reviewer Role slot. */
|
|
4
4
|
export function projectReviewerAvailability(store, taskId, reviewerRoleName) {
|
|
5
|
-
const active = store.getActiveTurn(taskId, reviewerRoleName)
|
|
6
|
-
|
|
7
|
-
if (active !== null && active !== undefined) {
|
|
5
|
+
const active = store.getActiveTurn(taskId, reviewerRoleName);
|
|
6
|
+
if (active !== null) {
|
|
8
7
|
return {
|
|
9
8
|
kind: "busy",
|
|
10
9
|
reviewerRoleName,
|
|
@@ -18,8 +17,15 @@ export function projectReviewerAvailability(store, taskId, reviewerRoleName) {
|
|
|
18
17
|
retryAfterSeconds: 5
|
|
19
18
|
};
|
|
20
19
|
}
|
|
21
|
-
const
|
|
22
|
-
|
|
20
|
+
const runtimeMailbox = store.getWorkMailbox(runtimeLifecycleTarget({
|
|
21
|
+
scope: "task",
|
|
22
|
+
taskId,
|
|
23
|
+
roleName: reviewerRoleName
|
|
24
|
+
}));
|
|
25
|
+
if (runtimeMailbox !== null && mailboxHasWork(runtimeMailbox)) {
|
|
26
|
+
return runtimeLifecycleBusy(reviewerRoleName, runtimeMailbox);
|
|
27
|
+
}
|
|
28
|
+
const activeRound = store.listReviewRounds(taskId).find((round) => ((round.status === "pending" || round.status === "running")
|
|
23
29
|
&& (round.reviewerRoleName === reviewerRoleName
|
|
24
30
|
|| round.executionGroup?.lanes.some(({ roleName }) => roleName === reviewerRoleName) === true)));
|
|
25
31
|
if (activeRound !== undefined) {
|
|
@@ -33,35 +39,19 @@ export function projectReviewerAvailability(store, taskId, reviewerRoleName) {
|
|
|
33
39
|
retryAfterSeconds: 5
|
|
34
40
|
};
|
|
35
41
|
}
|
|
36
|
-
const reviewerMailbox = store.getWorkMailbox({
|
|
37
|
-
kind: "role",
|
|
38
|
-
taskId,
|
|
39
|
-
roleName: reviewerRoleName
|
|
40
|
-
});
|
|
41
|
-
if (reviewerMailbox !== null && mailboxHasWork(reviewerMailbox)) {
|
|
42
|
-
return mailboxBusy(reviewerRoleName, "mailbox", reviewerMailbox);
|
|
43
|
-
}
|
|
44
|
-
const runtimeMailbox = store.getWorkMailbox(runtimeLifecycleTarget({
|
|
45
|
-
scope: "task",
|
|
46
|
-
taskId,
|
|
47
|
-
roleName: reviewerRoleName
|
|
48
|
-
}));
|
|
49
|
-
if (runtimeMailbox !== null && mailboxHasWork(runtimeMailbox)) {
|
|
50
|
-
return mailboxBusy(reviewerRoleName, "runtime-lifecycle", runtimeMailbox);
|
|
51
|
-
}
|
|
52
42
|
return {
|
|
53
43
|
kind: "available",
|
|
54
44
|
reviewerRoleName,
|
|
55
45
|
retryable: true
|
|
56
46
|
};
|
|
57
47
|
}
|
|
58
|
-
function
|
|
48
|
+
function runtimeLifecycleBusy(reviewerRoleName, mailbox) {
|
|
59
49
|
const pending = nextPendingBatch(mailbox);
|
|
60
50
|
const startedAt = mailbox.processing?.startedAt ?? pending?.firstQueuedAt;
|
|
61
51
|
return {
|
|
62
52
|
kind: "busy",
|
|
63
53
|
reviewerRoleName,
|
|
64
|
-
phase,
|
|
54
|
+
phase: "runtime-lifecycle",
|
|
65
55
|
...(startedAt === undefined ? {} : { startedAt }),
|
|
66
56
|
retryable: true,
|
|
67
57
|
retryAfterSeconds: 5
|
package/dist/role/role.js
CHANGED
|
@@ -98,6 +98,9 @@ export function switchActiveRoleAgent(role, sessions, targetAgentId, runtime, no
|
|
|
98
98
|
: {
|
|
99
99
|
...sessions,
|
|
100
100
|
activeAgentId: normalizedTarget,
|
|
101
|
+
...(sessions.owner.scope === "task" && fromAgentId !== normalizedTarget
|
|
102
|
+
? { providerBinding: null }
|
|
103
|
+
: {}),
|
|
101
104
|
updatedAt: timestamp
|
|
102
105
|
};
|
|
103
106
|
return {
|
|
@@ -40,7 +40,7 @@ function observation(input, mapped) {
|
|
|
40
40
|
const eventId = hookEventId(input, mapped, requestOccurrenceId);
|
|
41
41
|
const fence = { ...input.fence, ...mapped.fence };
|
|
42
42
|
return createRuntimeObservation({
|
|
43
|
-
schemaVersion:
|
|
43
|
+
schemaVersion: 4,
|
|
44
44
|
eventId,
|
|
45
45
|
semanticKey: requestOccurrenceId === undefined
|
|
46
46
|
? runtimeObservationSemanticKey({
|