@zq-silk/yui 0.13.9 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +69 -428
- package/README.md +108 -298
- package/dist/agent/managedRuntimeEnvironment.js +2 -2
- package/dist/cli/commandCatalog.js +39 -77
- package/dist/cli/interactionCandidates.js +4 -4
- package/dist/cli/interactionPolicy.js +7 -10
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/updateCommand.js +6 -27
- package/dist/cli/updateOrchestrator.js +63 -484
- package/dist/cli/updatePorts.js +15 -333
- package/dist/cli/upgradeCommand.js +8 -65
- package/dist/cli.js +57 -242
- package/dist/commands/configCommands.js +11 -62
- package/dist/commands/executionAuditCommands.js +23 -23
- package/dist/commands/globalRoleCommands.js +2 -7
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/projectCommands.js +5 -5
- package/dist/commands/releaseCommands.js +3 -10
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/sessionCommands.js +2 -2
- package/dist/commands/taskActor.js +31 -39
- package/dist/commands/taskChangeSetCommands.js +5 -12
- package/dist/commands/taskCommands.js +464 -1249
- package/dist/commands/taskContextCommand.js +35 -36
- package/dist/commands/taskExecutionCommands.js +33 -46
- package/dist/commands/taskInputCommands.js +20 -42
- package/dist/commands/taskNextActionCommand.js +9 -9
- package/dist/commands/taskOverviewCommand.js +56 -95
- package/dist/commands/taskRoleRuntimeStatus.js +77 -107
- package/dist/commands/taskUpstreamCommands.js +3 -3
- package/dist/commands/taskWorkspaceCommands.js +7 -79
- package/dist/commands/telemetryCommands.js +32 -124
- package/dist/commands/workflowCommands.js +3 -3
- package/dist/completion/fileCompletionManager.js +1 -1
- package/dist/config/configCatalog.js +4 -6
- package/dist/config/yuiConfig.js +6 -43
- package/dist/context/dispatchContext.js +14 -30
- package/dist/context/roleSessionContext.js +2 -2
- package/dist/context/sessionBootstrapManifest.js +2 -2
- package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
- package/dist/context/turnInputContract.js +204 -0
- package/dist/context/wakeNotification.js +2 -2
- package/dist/controller/agentRuntimeObserver.js +18 -18
- package/dist/controller/clientRuntime.js +13 -20
- package/dist/controller/controller.js +89 -116
- package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
- package/dist/controller/jobControl.js +17 -17
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +38 -59
- package/dist/controller/resourceInventoryRpc.js +3 -3
- package/dist/controller/resourceInventoryWorker.js +1 -1
- package/dist/controller/runtime.js +46 -53
- package/dist/controller/runtimeEventInbox.js +23 -31
- package/dist/controller/runtimeEventProcessor.js +15 -15
- package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
- package/dist/controller/runtimeLaunchCoordinator.js +3 -3
- package/dist/controller/runtimeObservationHook.js +11 -8
- package/dist/controller/sessionNotify.js +11 -11
- package/dist/controller/structuredProviderObservation.js +89 -16
- package/dist/coordination/workMailbox.js +309 -579
- package/dist/coordination/workMailboxQueue.js +5 -6
- package/dist/core/controllerClient.js +1 -91
- package/dist/core/controllerServer.js +3 -6
- package/dist/doctor/doctor.js +51 -314
- package/dist/execution/candidateConvergence.js +3 -3
- package/dist/execution/executionGroup.js +32 -33
- package/dist/execution/executionHealth.js +36 -38
- package/dist/execution/resourceBroker.js +12 -12
- package/dist/executor/agentExecutor.js +30 -265
- package/dist/executor/effectiveLaunch.js +9 -19
- package/dist/executor/executorRegistry.js +43 -17
- package/dist/executor/fileRoleLaunchPlanner.js +56 -56
- package/dist/executor/launchPlan.js +3 -3
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +20 -25
- package/dist/input/inputRequest.js +12 -12
- package/dist/integration/changeSet.js +9 -13
- package/dist/integration/changeSetManifest.js +1 -1
- package/dist/integration/gitIntegrationService.js +2 -2
- package/dist/integration/integrationQueueService.js +5 -21
- package/dist/integration/overlapDiagnostics.js +2 -2
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/job/jobRunner.js +1 -1
- package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
- package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
- package/dist/message/message.js +6 -6
- package/dist/observability/executionAudit.js +74 -86
- package/dist/observability/faultClassification.js +7 -24
- package/dist/observability/orchestrationMetrics.js +5 -5
- package/dist/observability/runtimeIdentity.js +34 -101
- package/dist/profile/agentProfile.js +1 -1
- package/dist/release/cliHomeReleaseFence.js +3 -3
- package/dist/release/releaseWorkflowEngine.js +6 -10
- package/dist/release/releaseWorkflowPorts.js +2 -2
- package/dist/release/workflowFileLock.js +1 -1
- package/dist/repository/checkoutSwap.js +1 -1
- package/dist/repository/gitWorkspace.js +0 -13
- package/dist/repository/project.js +1 -1
- package/dist/repository/projectMaintenanceLock.js +1 -2
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +21 -25
- package/dist/repository/taskWorkspaceIdentity.js +8 -21
- package/dist/repository/taskWorkspacePreparer.js +63 -620
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +1 -1
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/sqliteResourceRegistry.js +1 -1
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewFindingLedger.js +1 -1
- package/dist/review/reviewOutcomeClassifier.js +35 -50
- package/dist/review/reviewRound.js +14 -25
- package/dist/review/reviewerAvailability.js +4 -4
- package/dist/review/taskFinalReviewContractResolution.js +41 -0
- package/dist/role/role.js +6 -3
- package/dist/runtime/agentDriver.js +4 -0
- package/dist/runtime/agentHost.js +151 -36
- package/dist/runtime/builtinAgentDrivers.js +79 -2
- package/dist/runtime/codexAppServerRuntime.js +122 -0
- package/dist/runtime/continuationManager.js +3 -5
- package/dist/runtime/exactControlPlane.js +17 -42
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +4 -4
- package/dist/runtime/processExitObservation.js +1 -1
- package/dist/runtime/processExitOutbox.js +0 -32
- package/dist/runtime/promptEnvelope.js +9 -9
- package/dist/runtime/providerContinuation.js +2 -2
- package/dist/runtime/providerContinuationReconciliationService.js +2 -2
- package/dist/runtime/providerRuntimeIdentity.js +76 -24
- package/dist/runtime/recentTurnIds.js +38 -0
- package/dist/runtime/runtimeContinuationProjection.js +2 -2
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +58 -21
- package/dist/runtime/runtimeProjection.js +19 -27
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/structuredProviderHost.js +177 -12
- package/dist/runtime/tmuxAdapters.js +46 -11
- package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
- package/dist/scheduler/leaderWakeupProcessor.js +147 -445
- package/dist/scheduler/operatorEvent.js +4 -6
- package/dist/scheduler/resourceQueueProjection.js +71 -0
- package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
- package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
- package/dist/scheduler/taskExecutionProjection.js +99 -99
- package/dist/scheduler/taskObservabilityProjection.js +10 -10
- package/dist/scheduler/taskWake.js +4 -4
- package/dist/scheduler/wakeReason.js +6 -10
- package/dist/scheduler/wakeupQueue.js +0 -9
- package/dist/setup/setupCommand.js +2 -2
- package/dist/storage/currentTaskStore.js +46 -0
- package/dist/storage/persistenceWorker.js +1 -1
- package/dist/storage/sqliteSchema.js +81 -485
- package/dist/storage/sqliteStore.js +206 -365
- package/dist/storage/storageSchema.js +1 -15
- package/dist/storage/storageVersions.js +8 -9
- package/dist/storage/storeRpc.js +10 -34
- package/dist/storage/taskStore.js +63 -3415
- package/dist/storage/upgrade/recordVersions.js +55 -149
- package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
- package/dist/task/completionReadiness.js +5 -5
- package/dist/task/deliveryGuard.js +10 -10
- package/dist/task/nextAction.js +74 -77
- package/dist/task/task.js +2 -4
- package/dist/task/taskRecordReference.js +3 -3
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +53 -53
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +8 -14
- package/dist/turn/turn.js +356 -0
- package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
- package/dist/verification/gateArtifactStore.js +2 -2
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/components.js +29 -54
- package/dist/web/assets/client/i18n.js +17 -37
- package/dist/web/assets/client/view.js +37 -37
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +5 -5
- package/dist/web/assets/styles/widgets.js +1 -2
- package/dist/web/webSnapshot.js +65 -60
- package/dist/workItem/workItem.js +11 -11
- package/dist/workspace/workItemChangeSetManager.js +1 -1
- package/docs/task-local-identity.md +5 -5
- package/i18n/README.zh-CN.md +41 -54
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +85 -83
- package/skills/yui-operator/SKILL.md +16 -16
- package/skills/yui-reviewer/SKILL.md +10 -10
- package/skills/yui-runtime/SKILL.md +17 -18
- package/skills/yui-worker/SKILL.md +16 -18
- package/dist/context/runContextContract.js +0 -162
- package/dist/executor/turnCompletion.js +0 -126
- package/dist/review/taskFinalReviewContractEvent.js +0 -1
- package/dist/review/taskFinalReviewContractRebind.js +0 -367
- package/dist/run/agentRun.js +0 -356
- package/dist/run/rejectedYieldAttempt.js +0 -221
- package/dist/run/runControlRequest.js +0 -50
- package/dist/run/yieldReceipt.js +0 -65
- package/dist/runtime/turnCompletion.js +0 -3
- package/dist/scheduler/actionability.js +0 -323
- package/dist/scheduler/activeRoleRunDelivery.js +0 -868
- package/dist/scheduler/activeTaskProgress.js +0 -126
- package/dist/storage/compatibleTaskStore.js +0 -248
- package/dist/storage/migration/baseline.js +0 -78
- package/dist/storage/migration/classifier.js +0 -51
- package/dist/storage/migration/compatibleCodec.js +0 -53
- package/dist/storage/migration/engine.js +0 -147
- package/dist/storage/migration/index.js +0 -33
- package/dist/storage/migration/planner.js +0 -154
- package/dist/storage/migration/productionRegistry.js +0 -3931
- package/dist/storage/migration/registry.js +0 -169
- package/dist/storage/migration/report.js +0 -54
- package/dist/storage/migration/types.js +0 -31
- package/dist/storage/upgrade/homeClassification.js +0 -353
- package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
- package/dist/storage/upgrade/migrationReceipt.js +0 -67
- package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
- package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
- package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
- package/dist/storage/upgrade/recordVersionScan.js +0 -176
- package/dist/storage/upgrade/sqliteFileSet.js +0 -50
- package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
- package/dist/storage/upgrade/sqliteStateMigration.js +0 -918
- package/dist/storage/upgrade/switchProgress.js +0 -80
- package/dist/storage/upgrade/upgradeReceipt.js +0 -161
- package/dist/storage/upgradeCoordination.js +0 -187
- package/dist/storage/upgradeFence.js +0 -366
- package/dist/telemetry/telemetryCompaction.js +0 -252
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
import { isDeepStrictEqual } from "node:util";
|
|
2
2
|
import { completeProcessing } from "../coordination/workMailbox.js";
|
|
3
|
-
import { settleExactWorkExecution } from "../coordination/workMailboxQueue.js";
|
|
4
|
-
import { terminalizeTaskRoleRunSession } from "../executor/agentExecutor.js";
|
|
5
3
|
import { finishReviewRound, updateReviewExecutionGroup } from "../review/reviewRound.js";
|
|
6
4
|
import { reconcileReviewFindingsAfterReview } from "../review/reviewFindingLedger.js";
|
|
7
|
-
import {
|
|
8
|
-
import { createYieldReceipt } from "../run/yieldReceipt.js";
|
|
5
|
+
import { completeTurn, failTurn } from "../turn/turn.js";
|
|
9
6
|
import { recordExecutionLaneResult, resolveExecutionGroup } from "../execution/executionGroup.js";
|
|
10
7
|
import { isRuntimeLaunchReservation, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
8
|
+
import { managedProviderTurnId } from "../runtime/providerRuntimeIdentity.js";
|
|
9
|
+
import { latestTurnDurableProgressAt } from "../scheduler/roleTurnStall.js";
|
|
13
10
|
import { markTaskWakeConsumed } from "../scheduler/taskWake.js";
|
|
14
11
|
import { workItemExecutionGroupById, updateWorkItemExecutionGroup } from "../workItem/workItem.js";
|
|
15
12
|
/**
|
|
16
13
|
* Validate every immutable identity and frozen Project head needed before a
|
|
17
|
-
* review
|
|
14
|
+
* review Turn can settle any mailbox or Round state. This is deliberately
|
|
18
15
|
* read-only: callers use it as the compare-and-swap fence immediately before
|
|
19
16
|
* their aggregate mutation.
|
|
20
17
|
*/
|
|
21
|
-
export function
|
|
22
|
-
if (
|
|
18
|
+
export function validateExactTurnReviewRound(store, turn, options = {}) {
|
|
19
|
+
if (turn.purpose !== "review")
|
|
23
20
|
return { disposition: "applied", round: null };
|
|
24
|
-
if (
|
|
21
|
+
if (turn.reviewRoundId === undefined) {
|
|
25
22
|
return { disposition: "obsolete", round: null, reason: "review-round-missing" };
|
|
26
23
|
}
|
|
27
|
-
const round = store.getReviewRound(
|
|
24
|
+
const round = store.getReviewRound(turn.taskId, turn.reviewRoundId);
|
|
28
25
|
if (round === null) {
|
|
29
26
|
return { disposition: "obsolete", round: null, reason: "review-round-missing" };
|
|
30
27
|
}
|
|
@@ -32,60 +29,60 @@ export function validateExactRunReviewRound(store, run, options = {}) {
|
|
|
32
29
|
&& round.status !== "pending" && round.status !== "running") {
|
|
33
30
|
return { disposition: "obsolete", round, reason: "review-round-terminal" };
|
|
34
31
|
}
|
|
35
|
-
const lane = round.executionGroup?.lanes.find(({ id }) => id ===
|
|
36
|
-
const
|
|
37
|
-
const exactReviewerRole = round.reviewerRoleName ===
|
|
38
|
-
if (!
|
|
32
|
+
const lane = round.executionGroup?.lanes.find(({ id }) => id === turn.executionLaneId);
|
|
33
|
+
const exactReviewerTurn = round.reviewerTurnId === turn.id || lane?.turnId === turn.id;
|
|
34
|
+
const exactReviewerRole = round.reviewerRoleName === turn.roleName || lane?.roleName === turn.roleName;
|
|
35
|
+
if (!exactReviewerTurn
|
|
39
36
|
|| !exactReviewerRole
|
|
40
|
-
|| round.workItemId !==
|
|
41
|
-
|| round.reviewBaseCommit !==
|
|
37
|
+
|| round.workItemId !== turn.workItemId
|
|
38
|
+
|| round.reviewBaseCommit !== turn.effective.reviewBaseCommit) {
|
|
42
39
|
return { disposition: "obsolete", round, reason: "review-round-mismatch" };
|
|
43
40
|
}
|
|
44
41
|
const laneWorkspaceRoot = lane?.workspace?.root;
|
|
45
|
-
if (
|
|
46
|
-
|| (laneWorkspaceRoot === undefined && !isDeepStrictEqual(
|
|
47
|
-
|| (laneWorkspaceRoot !== undefined &&
|
|
42
|
+
if (turn.workspace === undefined || round.workspace === undefined
|
|
43
|
+
|| (laneWorkspaceRoot === undefined && !isDeepStrictEqual(turn.workspace, round.workspace))
|
|
44
|
+
|| (laneWorkspaceRoot !== undefined && turn.workspace.root !== laneWorkspaceRoot)) {
|
|
48
45
|
return { disposition: "obsolete", round, reason: "review-workspace-mismatch" };
|
|
49
46
|
}
|
|
50
|
-
const storedWorkspace =
|
|
51
|
-
? store.getManagedWorkspace(
|
|
52
|
-
: store.getReviewRoundWorkspace(
|
|
47
|
+
const storedWorkspace = turn.workspace.owner.type === "execution-lane"
|
|
48
|
+
? store.getManagedWorkspace(turn.workspace.owner)
|
|
49
|
+
: store.getReviewRoundWorkspace(turn.taskId, round.id);
|
|
53
50
|
if (storedWorkspace === null
|
|
54
|
-
|| (
|
|
51
|
+
|| (turn.workspace.owner.type !== "execution-lane"
|
|
55
52
|
&& !isDeepStrictEqual(storedWorkspace, round.workspace))
|
|
56
|
-
|| !isDeepStrictEqual(storedWorkspace,
|
|
53
|
+
|| !isDeepStrictEqual(storedWorkspace, turn.workspace)) {
|
|
57
54
|
return { disposition: "obsolete", round, reason: "review-workspace-drift" };
|
|
58
55
|
}
|
|
59
|
-
if (
|
|
56
|
+
if (turn.workspace.owner.type !== "execution-lane") {
|
|
60
57
|
if (storedWorkspace.owner.type !== "review-round"
|
|
61
|
-
|| storedWorkspace.owner.taskId !==
|
|
58
|
+
|| storedWorkspace.owner.taskId !== turn.taskId
|
|
62
59
|
|| storedWorkspace.owner.reviewRoundId !== round.id) {
|
|
63
60
|
return { disposition: "obsolete", round, reason: "review-workspace-owner-mismatch" };
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
|
-
if (
|
|
67
|
-
&& (
|
|
68
|
-
||
|
|
69
|
-
||
|
|
70
|
-
||
|
|
63
|
+
if (turn.workspace.owner.type === "execution-lane"
|
|
64
|
+
&& (turn.workspace.owner.purpose !== "review"
|
|
65
|
+
|| turn.workspace.owner.executionGroupId !== turn.executionGroupId
|
|
66
|
+
|| turn.workspace.owner.executionLaneId !== turn.executionLaneId
|
|
67
|
+
|| turn.workspace.owner.reviewRoundId !== round.id)) {
|
|
71
68
|
return { disposition: "obsolete", round, reason: "review-lane-workspace-owner-mismatch" };
|
|
72
69
|
}
|
|
73
|
-
if (
|
|
70
|
+
if (turn.workspace.owner.type === "execution-lane") {
|
|
74
71
|
if (lane === undefined
|
|
75
|
-
|| lane.
|
|
76
|
-
|| lane.roleName !==
|
|
77
|
-
|| lane.workspace?.root !==
|
|
78
|
-
|| lane.workspace.writableProjectIds.length !==
|
|
79
|
-
||
|
|
72
|
+
|| lane.turnId !== turn.id
|
|
73
|
+
|| lane.roleName !== turn.roleName
|
|
74
|
+
|| lane.workspace?.root !== turn.workspace.root
|
|
75
|
+
|| lane.workspace.writableProjectIds.length !== turn.workspace.entries.length
|
|
76
|
+
|| turn.workspace.entries.some((entry) => (entry.access !== "write"
|
|
80
77
|
|| !lane.workspace.writableProjectIds.includes(entry.projectId)))) {
|
|
81
78
|
return { disposition: "obsolete", round, reason: "review-lane-workspace-lineage-mismatch" };
|
|
82
79
|
}
|
|
83
80
|
}
|
|
84
|
-
const task = store.getTask(
|
|
81
|
+
const task = store.getTask(turn.taskId);
|
|
85
82
|
const taskScope = (round.scope ?? "work-item") === "task";
|
|
86
83
|
const item = taskScope || round.workItemId === undefined
|
|
87
84
|
? null
|
|
88
|
-
: store.getWorkItem(
|
|
85
|
+
: store.getWorkItem(turn.taskId, round.workItemId);
|
|
89
86
|
if (!taskScope && item === null) {
|
|
90
87
|
return { disposition: "obsolete", round, reason: "review-work-item-missing" };
|
|
91
88
|
}
|
|
@@ -129,22 +126,22 @@ export function validateExactRunReviewRound(store, run, options = {}) {
|
|
|
129
126
|
return { disposition: "applied", round };
|
|
130
127
|
}
|
|
131
128
|
/**
|
|
132
|
-
* Atomically terminalizes the exact ReviewRound bound to a review
|
|
129
|
+
* Atomically terminalizes the exact ReviewRound bound to a review Turn.
|
|
133
130
|
* The round must still be pending/running and its reviewer identity must match
|
|
134
|
-
* the
|
|
135
|
-
* by the exact
|
|
136
|
-
* path: a failed review
|
|
131
|
+
* the Turn exactly. This is the sole review-round convergence primitive shared
|
|
132
|
+
* by the exact Turn terminalization path and the pre-delivery launch-failure
|
|
133
|
+
* path: a failed review Turn must never leave its Round stranded.
|
|
137
134
|
*/
|
|
138
|
-
export function
|
|
139
|
-
const validation =
|
|
135
|
+
export function terminalizeExactTurnReviewRound(store, input, now) {
|
|
136
|
+
const validation = validateExactTurnReviewRound(store, input.turn);
|
|
140
137
|
if (validation.disposition !== "applied" || validation.round === null) {
|
|
141
138
|
return validation;
|
|
142
139
|
}
|
|
143
140
|
const reviewRound = validation.round;
|
|
144
|
-
let groupedRound = input.
|
|
145
|
-
&& input.
|
|
141
|
+
let groupedRound = input.turn.executionGroupId !== undefined
|
|
142
|
+
&& input.turn.executionLaneId !== undefined
|
|
146
143
|
&& reviewRound.executionGroup !== undefined
|
|
147
|
-
? updateReviewExecutionGroup(reviewRound, recordExecutionLaneResult(reviewRound.executionGroup, input.
|
|
144
|
+
? updateReviewExecutionGroup(reviewRound, recordExecutionLaneResult(reviewRound.executionGroup, input.turn.executionLaneId, {
|
|
148
145
|
summary: input.outcome.summary,
|
|
149
146
|
...(input.reviewResult?.report === undefined ? {} : { report: input.reviewResult.report }),
|
|
150
147
|
...(input.reviewResult?.checks === undefined
|
|
@@ -168,14 +165,13 @@ export function terminalizeExactRunReviewRound(store, input, now) {
|
|
|
168
165
|
...(input.reviewResult?.gitSnapshot === undefined
|
|
169
166
|
? {}
|
|
170
167
|
: { gitSnapshot: input.reviewResult.gitSnapshot })
|
|
171
|
-
}, input.outcome.status
|
|
168
|
+
}, input.outcome.status, now))
|
|
172
169
|
: reviewRound;
|
|
173
170
|
if (input.settleFailedExecutionGroup === true
|
|
174
171
|
&& input.outcome.status === "failed"
|
|
175
172
|
&& groupedRound.executionGroup !== undefined
|
|
176
173
|
&& groupedRound.executionGroup.resolution === undefined
|
|
177
|
-
&& groupedRound.executionGroup.lanes.every((lane) => (lane.status === "
|
|
178
|
-
|| lane.status === "completed"
|
|
174
|
+
&& groupedRound.executionGroup.lanes.every((lane) => (lane.status === "completed"
|
|
179
175
|
|| lane.status === "failed"
|
|
180
176
|
|| lane.status === "skipped"))) {
|
|
181
177
|
groupedRound = updateReviewExecutionGroup(groupedRound, resolveExecutionGroup(groupedRound.executionGroup, {
|
|
@@ -195,7 +191,7 @@ export function terminalizeExactRunReviewRound(store, input, now) {
|
|
|
195
191
|
store.saveReviewRound(input.taskId, groupedRound);
|
|
196
192
|
return { disposition: "applied", round: groupedRound };
|
|
197
193
|
}
|
|
198
|
-
const terminal = finishReviewRound(groupedRound, input.outcome.status
|
|
194
|
+
const terminal = finishReviewRound(groupedRound, input.outcome.status, input.outcome.summary, now, input.reviewResult);
|
|
199
195
|
store.saveReviewRound(input.taskId, terminal);
|
|
200
196
|
// Issue 06: a completed (semantic) Round feeds the finding ledger; a failed
|
|
201
197
|
// execution attempt is skipped by the classifier and never creates findings.
|
|
@@ -205,17 +201,17 @@ export function terminalizeExactRunReviewRound(store, input, now) {
|
|
|
205
201
|
return { disposition: "applied", round: terminal };
|
|
206
202
|
}
|
|
207
203
|
/**
|
|
208
|
-
* Retire one stranded active
|
|
204
|
+
* Retire one stranded active Turn only after its exact Provider Turn is
|
|
209
205
|
* terminal and every durable execution fence is quiet. The caller owns the
|
|
210
|
-
* surrounding aggregate transaction so the
|
|
206
|
+
* surrounding aggregate transaction so the Turn, ReviewRound/Lane, mailbox,
|
|
211
207
|
* Session, and append-only retirement record commit together.
|
|
212
208
|
*/
|
|
213
|
-
export function
|
|
214
|
-
const current = store.
|
|
209
|
+
export function retireExactActiveTurn(store, input, now) {
|
|
210
|
+
const current = store.getTurn(input.taskId, input.turnId);
|
|
215
211
|
const stateChanged = (reason) => ({
|
|
216
212
|
disposition: "state-changed",
|
|
217
|
-
|
|
218
|
-
...(current === null ? {} : { progressAt:
|
|
213
|
+
turn: current,
|
|
214
|
+
...(current === null ? {} : { progressAt: latestTurnDurableProgressAt(store, input.taskId, input.roleName, input.turnId)?.progressAt }),
|
|
219
215
|
reason
|
|
220
216
|
});
|
|
221
217
|
const task = store.getTask(input.taskId);
|
|
@@ -224,22 +220,22 @@ export function retireExactActiveAgentRun(store, input, now) {
|
|
|
224
220
|
if (task.status !== "active")
|
|
225
221
|
return stateChanged("task-terminal");
|
|
226
222
|
if (current === null)
|
|
227
|
-
return stateChanged("
|
|
223
|
+
return stateChanged("turn-missing");
|
|
228
224
|
if (current.status !== "active")
|
|
229
|
-
return stateChanged("
|
|
225
|
+
return stateChanged("turn-terminal");
|
|
230
226
|
if (current.taskId !== input.taskId || current.roleName !== input.roleName) {
|
|
231
|
-
return stateChanged("
|
|
227
|
+
return stateChanged("turn-owner-mismatch");
|
|
232
228
|
}
|
|
233
229
|
if (current.effective.agentId !== input.agentId
|
|
234
230
|
|| current.effective.adapterId !== input.adapterId) {
|
|
235
|
-
return stateChanged("
|
|
231
|
+
return stateChanged("turn-launch-identity-mismatch");
|
|
236
232
|
}
|
|
237
233
|
const active = current.executionGroupId !== undefined && current.executionLaneId !== undefined
|
|
238
|
-
? store.
|
|
239
|
-
: store.
|
|
234
|
+
? store.getActiveExecutionLaneTurn(input.taskId, current.executionGroupId, current.executionLaneId)
|
|
235
|
+
: store.getActiveTurn(input.taskId, input.roleName);
|
|
240
236
|
if (active?.id !== current.id)
|
|
241
|
-
return stateChanged("active-
|
|
242
|
-
const progress =
|
|
237
|
+
return stateChanged("active-turn-mismatch");
|
|
238
|
+
const progress = latestTurnDurableProgressAt(store, input.taskId, input.roleName, input.turnId);
|
|
243
239
|
if (progress === null)
|
|
244
240
|
return stateChanged("progress-unavailable");
|
|
245
241
|
if (progress.progressAt !== input.expectedProgressAt) {
|
|
@@ -250,21 +246,16 @@ export function retireExactActiveAgentRun(store, input, now) {
|
|
|
250
246
|
taskId: input.taskId,
|
|
251
247
|
roleName: input.roleName,
|
|
252
248
|
agentId: input.agentId,
|
|
253
|
-
|
|
254
|
-
receiptId: agentRunDeliveryReceiptId(current),
|
|
249
|
+
turnId: input.turnId,
|
|
255
250
|
...(input.nativeSessionId === undefined ? {} : { nativeSessionId: input.nativeSessionId }),
|
|
256
251
|
...(input.launchId === undefined ? {} : { launchId: input.launchId }),
|
|
257
252
|
settleFailedExecutionGroup: true,
|
|
258
|
-
outcome: { status: "failed", summary: input.reason }
|
|
253
|
+
outcome: { status: "failed", summary: input.reason, failureReason: "missing-result" }
|
|
259
254
|
};
|
|
260
|
-
if (!matchesSessionFence(sessions, terminalInput)
|
|
261
|
-
|| !matchesLaunchFence(store, sessions, terminalInput)) {
|
|
262
|
-
return stateChanged("session-or-launch-fence-mismatch");
|
|
263
|
-
}
|
|
264
255
|
const session = sessions?.sessions[input.agentId];
|
|
265
256
|
const providerBinding = sessions?.providerBinding;
|
|
266
257
|
const providerTurn = providerBinding?.turn;
|
|
267
|
-
const providerSettled = providerTurn
|
|
258
|
+
const providerSettled = managedProviderTurnId(providerTurn) === current.id
|
|
268
259
|
&& (providerTurn?.status === "completed"
|
|
269
260
|
|| providerTurn?.status === "failed"
|
|
270
261
|
|| providerTurn?.status === "cancelled"
|
|
@@ -272,107 +263,59 @@ export function retireExactActiveAgentRun(store, input, now) {
|
|
|
272
263
|
if (session?.status === "active" && !providerSettled) {
|
|
273
264
|
return {
|
|
274
265
|
disposition: "blocked",
|
|
275
|
-
|
|
266
|
+
turn: current,
|
|
276
267
|
progressAt: progress.progressAt,
|
|
277
268
|
reason: "runtime-not-terminal"
|
|
278
269
|
};
|
|
279
270
|
}
|
|
280
|
-
const terminal =
|
|
281
|
-
if (terminal.disposition !== "applied" || terminal.
|
|
271
|
+
const terminal = terminalizeExactTaskTurn(store, terminalInput, now);
|
|
272
|
+
if (terminal.disposition !== "applied" || terminal.turn === null) {
|
|
282
273
|
return stateChanged(terminal.reason ?? "terminalization-fence-mismatch");
|
|
283
274
|
}
|
|
284
275
|
return {
|
|
285
276
|
disposition: "applied",
|
|
286
|
-
|
|
277
|
+
turn: terminal.turn,
|
|
287
278
|
progressAt: progress.progressAt
|
|
288
279
|
};
|
|
289
280
|
}
|
|
290
281
|
/**
|
|
291
282
|
* Applies one exact application-level terminal fact inside the caller's
|
|
292
|
-
*
|
|
283
|
+
* TaskStore transaction. All caller-owned outcome records can therefore
|
|
293
284
|
* be saved in the same aggregate commit.
|
|
294
285
|
*/
|
|
295
|
-
export function
|
|
296
|
-
const
|
|
297
|
-
if (
|
|
298
|
-
return obsolete(null, "
|
|
299
|
-
if (
|
|
300
|
-
return obsolete(
|
|
301
|
-
if (
|
|
302
|
-
return obsolete(
|
|
303
|
-
}
|
|
304
|
-
if (
|
|
305
|
-
return obsolete(
|
|
286
|
+
export function terminalizeExactTaskTurn(store, input, now) {
|
|
287
|
+
const turn = store.getTurn(input.taskId, input.turnId);
|
|
288
|
+
if (turn === null)
|
|
289
|
+
return obsolete(null, "turn-missing");
|
|
290
|
+
if (turn.status !== "active")
|
|
291
|
+
return obsolete(turn, "turn-terminal");
|
|
292
|
+
if (turn.taskId !== input.taskId || turn.roleName !== input.roleName) {
|
|
293
|
+
return obsolete(turn, "turn-owner-mismatch");
|
|
294
|
+
}
|
|
295
|
+
if (turn.effective.agentId !== input.agentId) {
|
|
296
|
+
return obsolete(turn, "turn-agent-mismatch");
|
|
306
297
|
}
|
|
307
298
|
const role = store.getRole(input.taskId, input.roleName);
|
|
308
299
|
if (role === null)
|
|
309
|
-
return obsolete(
|
|
310
|
-
const active =
|
|
311
|
-
? store.
|
|
312
|
-
: store.
|
|
313
|
-
if (active?.id !==
|
|
314
|
-
return obsolete(
|
|
300
|
+
return obsolete(turn, "role-missing");
|
|
301
|
+
const active = turn.executionGroupId !== undefined && turn.executionLaneId !== undefined
|
|
302
|
+
? store.getActiveExecutionLaneTurn(input.taskId, turn.executionGroupId, turn.executionLaneId)
|
|
303
|
+
: store.getActiveTurn(input.taskId, input.roleName);
|
|
304
|
+
if (active?.id !== turn.id)
|
|
305
|
+
return obsolete(turn, "active-turn-mismatch");
|
|
315
306
|
const sessions = store.getTaskRoleSessionSet(input.taskId, input.roleName);
|
|
316
|
-
if (!matchesSessionFence(sessions, input)) {
|
|
317
|
-
return obsolete(run, "session-fence-mismatch");
|
|
318
|
-
}
|
|
319
|
-
if (!matchesLaunchFence(store, sessions, input)) {
|
|
320
|
-
return obsolete(run, "launch-fence-mismatch");
|
|
321
|
-
}
|
|
322
|
-
if (input.settleFailedExecutionGroup !== true
|
|
323
|
-
&& runOwnsBlockingProviderContinuation(store.listEvents(input.taskId), {
|
|
324
|
-
taskId: run.taskId,
|
|
325
|
-
roleName: run.roleName,
|
|
326
|
-
runId: run.id,
|
|
327
|
-
agentId: run.effective.agentId
|
|
328
|
-
})) {
|
|
329
|
-
return obsolete(run, "provider-continuation-writer-owned");
|
|
330
|
-
}
|
|
331
307
|
// Validate the exact ReviewRound, Candidate, stored workspace, and frozen
|
|
332
308
|
// Project heads before any mailbox or Round write.
|
|
333
|
-
const reviewValidation =
|
|
309
|
+
const reviewValidation = validateExactTurnReviewRound(store, turn);
|
|
334
310
|
if (reviewValidation.disposition !== "applied") {
|
|
335
|
-
return obsolete(
|
|
336
|
-
}
|
|
337
|
-
const roleTarget = {
|
|
338
|
-
kind: "role",
|
|
339
|
-
taskId: input.taskId,
|
|
340
|
-
roleName: input.roleName
|
|
341
|
-
};
|
|
342
|
-
if (input.mailboxDisposition === "discard") {
|
|
343
|
-
store.removeWorkMailbox(roleTarget);
|
|
344
|
-
}
|
|
345
|
-
else {
|
|
346
|
-
// For review Runs the mailbox must carry an exact pending or processing
|
|
347
|
-
// entry for this Run: an absent or unrelated mailbox means the review
|
|
348
|
-
// dispatch was never recorded and the terminalization must fail closed.
|
|
349
|
-
// Execution/Leader Runs keep the historical absent-is-clean behavior so
|
|
350
|
-
// direct Leader completion and normal execution are unaffected.
|
|
351
|
-
const isReview = run.purpose === "review";
|
|
352
|
-
const mailbox = store.getWorkMailbox(roleTarget);
|
|
353
|
-
const processing = mailbox?.processing;
|
|
354
|
-
if (mailbox !== null && processing !== null && processing !== undefined) {
|
|
355
|
-
if (processing.executionRef === undefined
|
|
356
|
-
|| processing.executionRef.type !== "run"
|
|
357
|
-
|| processing.executionRef.taskId !== run.taskId
|
|
358
|
-
|| processing.executionRef.id !== run.id) {
|
|
359
|
-
return obsolete(run, "mailbox-busy");
|
|
360
|
-
}
|
|
361
|
-
store.saveWorkMailbox(completeProcessing(mailbox, processing.batchId));
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
const mailboxSettlement = settleExactWorkExecution(store, roleTarget, { type: "run", taskId: run.taskId, id: run.id });
|
|
365
|
-
if (mailboxSettlement === "absent" && isReview && run.deliveredAt === undefined) {
|
|
366
|
-
return obsolete(run, "review-mailbox-missing");
|
|
367
|
-
}
|
|
368
|
-
}
|
|
311
|
+
return obsolete(turn, reviewValidation.reason ?? "review-round-mismatch");
|
|
369
312
|
}
|
|
370
|
-
// All
|
|
371
|
-
// Only now may the exact ReviewRound be terminalized alongside the
|
|
372
|
-
// stale fence never leaves a Round written while the
|
|
373
|
-
const reviewRoundTerminalization =
|
|
313
|
+
// All Turn, active-pointer, Session, launch, and mailbox fences have passed.
|
|
314
|
+
// Only now may the exact ReviewRound be terminalized alongside the Turn so a
|
|
315
|
+
// stale fence never leaves a Round written while the Turn stays active.
|
|
316
|
+
const reviewRoundTerminalization = terminalizeExactTurnReviewRound(store, {
|
|
374
317
|
taskId: input.taskId,
|
|
375
|
-
|
|
318
|
+
turn,
|
|
376
319
|
outcome: input.outcome,
|
|
377
320
|
reviewResult: input.reviewResult,
|
|
378
321
|
...(input.settleFailedExecutionGroup === undefined
|
|
@@ -380,38 +323,21 @@ export function terminalizeExactTaskRun(store, input, now) {
|
|
|
380
323
|
: { settleFailedExecutionGroup: input.settleFailedExecutionGroup })
|
|
381
324
|
}, now);
|
|
382
325
|
if (reviewRoundTerminalization.disposition !== "applied") {
|
|
383
|
-
return obsolete(
|
|
384
|
-
}
|
|
385
|
-
const terminal = input.outcome.status === "
|
|
386
|
-
?
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
...(input.reviewResult.report === undefined ? {} : { report: input.reviewResult.report }),
|
|
394
|
-
...(input.reviewResult.checks === undefined ? {} : { checks: input.reviewResult.checks }),
|
|
395
|
-
...(input.reviewResult.findings === undefined ? {} : { findings: input.reviewResult.findings }),
|
|
396
|
-
...(input.reviewResult.evidence === undefined ? {} : { evidence: input.reviewResult.evidence }),
|
|
397
|
-
...(input.reviewResult.evidenceCommit === undefined ? {} : { evidenceCommit: input.reviewResult.evidenceCommit }),
|
|
398
|
-
...(input.reviewResult.gitSnapshot === undefined ? {} : { gitSnapshot: input.reviewResult.gitSnapshot }),
|
|
399
|
-
...(input.reviewResult.deltaDisposition === undefined ? {} : { deltaDisposition: input.reviewResult.deltaDisposition }),
|
|
400
|
-
...(input.reviewResult.deltaReasoning === undefined ? {} : { deltaReasoning: input.reviewResult.deltaReasoning })
|
|
401
|
-
}
|
|
402
|
-
})
|
|
403
|
-
}, now))
|
|
404
|
-
: failAgentRun(run, input.outcome.summary, now);
|
|
405
|
-
if (run.executionGroupId !== undefined
|
|
406
|
-
&& run.executionLaneId !== undefined
|
|
407
|
-
&& run.purpose === "execution"
|
|
408
|
-
&& run.workItemId !== undefined) {
|
|
409
|
-
const item = store.getWorkItem(input.taskId, run.workItemId);
|
|
326
|
+
return obsolete(turn, reviewRoundTerminalization.reason ?? "review-round-mismatch");
|
|
327
|
+
}
|
|
328
|
+
const terminal = input.outcome.status === "completed"
|
|
329
|
+
? completeTurn(turn, input.outcome.summary, now, input.outcome.provider)
|
|
330
|
+
: failTurn(turn, input.outcome.failureReason ?? "runtime-failed", input.outcome.summary, now, input.outcome.provider);
|
|
331
|
+
if (turn.executionGroupId !== undefined
|
|
332
|
+
&& turn.executionLaneId !== undefined
|
|
333
|
+
&& turn.purpose === "execution"
|
|
334
|
+
&& turn.workItemId !== undefined) {
|
|
335
|
+
const item = store.getWorkItem(input.taskId, turn.workItemId);
|
|
410
336
|
const group = item === null
|
|
411
337
|
? undefined
|
|
412
|
-
: workItemExecutionGroupById(item,
|
|
338
|
+
: workItemExecutionGroupById(item, turn.executionGroupId);
|
|
413
339
|
if (item !== null && group !== undefined) {
|
|
414
|
-
let grouped = recordExecutionLaneResult(group,
|
|
340
|
+
let grouped = recordExecutionLaneResult(group, turn.executionLaneId, {
|
|
415
341
|
summary: input.outcome.summary,
|
|
416
342
|
...(input.reviewResult?.report === undefined ? {} : { report: input.reviewResult.report }),
|
|
417
343
|
...(input.reviewResult?.checks === undefined ? {} : { checks: input.reviewResult.checks }),
|
|
@@ -419,12 +345,11 @@ export function terminalizeExactTaskRun(store, input, now) {
|
|
|
419
345
|
...(input.reviewResult?.evidence === undefined ? {} : { evidence: input.reviewResult.evidence }),
|
|
420
346
|
...(input.reviewResult?.evidenceCommit === undefined ? {} : { evidenceCommit: input.reviewResult.evidenceCommit }),
|
|
421
347
|
...(input.reviewResult?.gitSnapshot === undefined ? {} : { gitSnapshot: input.reviewResult.gitSnapshot })
|
|
422
|
-
}, input.outcome.status
|
|
348
|
+
}, input.outcome.status, now);
|
|
423
349
|
if (input.settleFailedExecutionGroup === true
|
|
424
350
|
&& input.outcome.status === "failed"
|
|
425
351
|
&& grouped.resolution === undefined
|
|
426
|
-
&& grouped.lanes.every((lane) => (lane.status === "
|
|
427
|
-
|| lane.status === "completed"
|
|
352
|
+
&& grouped.lanes.every((lane) => (lane.status === "completed"
|
|
428
353
|
|| lane.status === "failed"
|
|
429
354
|
|| lane.status === "skipped"))) {
|
|
430
355
|
grouped = resolveExecutionGroup(grouped, {
|
|
@@ -435,63 +360,22 @@ export function terminalizeExactTaskRun(store, input, now) {
|
|
|
435
360
|
store.saveWorkItem(input.taskId, updateWorkItemExecutionGroup(item, grouped, now));
|
|
436
361
|
}
|
|
437
362
|
}
|
|
438
|
-
store.
|
|
363
|
+
store.saveTurn(terminal);
|
|
439
364
|
if (terminal.roleName === "leader") {
|
|
440
365
|
const wake = store.listTaskWakes(input.taskId)
|
|
441
|
-
.find((candidate) => candidate.
|
|
366
|
+
.find((candidate) => candidate.turnId === terminal.id && candidate.status === "dispatched");
|
|
442
367
|
if (wake !== undefined) {
|
|
443
368
|
store.saveTaskWake(input.taskId, markTaskWakeConsumed(wake, now));
|
|
444
369
|
}
|
|
445
370
|
}
|
|
446
371
|
if (terminal.executionGroupId !== undefined && terminal.executionLaneId !== undefined) {
|
|
447
|
-
store.
|
|
372
|
+
store.clearActiveExecutionLaneTurn(input.taskId, terminal.executionGroupId, terminal.executionLaneId);
|
|
448
373
|
}
|
|
449
374
|
else {
|
|
450
|
-
store.
|
|
451
|
-
}
|
|
452
|
-
if (sessions !== null) {
|
|
453
|
-
store.saveTaskRoleSessionSet(terminalizeTaskRoleRunSession(sessions, {
|
|
454
|
-
agentId: input.agentId,
|
|
455
|
-
runId: input.runId,
|
|
456
|
-
receiptId: input.receiptId
|
|
457
|
-
}, now));
|
|
375
|
+
store.clearActiveTurn(input.taskId, input.roleName);
|
|
458
376
|
}
|
|
459
377
|
settleLaunchReservation(store, sessions, input);
|
|
460
|
-
return { disposition: "applied",
|
|
461
|
-
}
|
|
462
|
-
function matchesSessionFence(sessions, input) {
|
|
463
|
-
if (sessions === null)
|
|
464
|
-
return input.nativeSessionId === undefined;
|
|
465
|
-
if (sessions.activeAgentId !== input.agentId)
|
|
466
|
-
return false;
|
|
467
|
-
const session = sessions.sessions[input.agentId];
|
|
468
|
-
if (input.nativeSessionId !== undefined) {
|
|
469
|
-
if (session?.nativeSessionId !== input.nativeSessionId)
|
|
470
|
-
return false;
|
|
471
|
-
}
|
|
472
|
-
const inFlight = sessions.inFlight;
|
|
473
|
-
return inFlight === null || (inFlight.agentId === input.agentId
|
|
474
|
-
&& inFlight.runId === input.runId
|
|
475
|
-
&& inFlight.receiptId === input.receiptId);
|
|
476
|
-
}
|
|
477
|
-
function matchesLaunchFence(store, sessions, input) {
|
|
478
|
-
// A resumed Run shares the native Provider Session whose process environment
|
|
479
|
-
// was created for an earlier Run. Once that exact native Session has passed
|
|
480
|
-
// matchesSessionFence, its immutable per-launch environment is not a second
|
|
481
|
-
// Run identity. Opaque hosts still require the launch fence below.
|
|
482
|
-
if (input.nativeSessionId !== undefined)
|
|
483
|
-
return true;
|
|
484
|
-
if (input.launchId === undefined)
|
|
485
|
-
return true;
|
|
486
|
-
const session = sessions?.sessions[input.agentId];
|
|
487
|
-
if (session?.launchId === input.launchId)
|
|
488
|
-
return true;
|
|
489
|
-
const mailbox = store.getWorkMailbox(runtimeLifecycleTarget({
|
|
490
|
-
scope: "task",
|
|
491
|
-
taskId: input.taskId,
|
|
492
|
-
roleName: input.roleName
|
|
493
|
-
}));
|
|
494
|
-
return isRuntimeLaunchReservation(mailbox?.processing, input.launchId);
|
|
378
|
+
return { disposition: "applied", turn: terminal };
|
|
495
379
|
}
|
|
496
380
|
function settleLaunchReservation(store, sessions, input) {
|
|
497
381
|
const target = runtimeLifecycleTarget({
|
|
@@ -515,6 +399,6 @@ function settleLaunchReservation(store, sessions, input) {
|
|
|
515
399
|
store.saveWorkMailbox(settled);
|
|
516
400
|
}
|
|
517
401
|
}
|
|
518
|
-
function obsolete(
|
|
519
|
-
return { disposition: "obsolete",
|
|
402
|
+
function obsolete(turn, reason) {
|
|
403
|
+
return { disposition: "obsolete", turn, reason };
|
|
520
404
|
}
|
package/dist/message/message.js
CHANGED
|
@@ -12,9 +12,9 @@ export function createTaskMessage(id, taskId, body, kind, author, now, context =
|
|
|
12
12
|
...(context.wakePolicy === undefined
|
|
13
13
|
? {}
|
|
14
14
|
: { wakePolicy: context.wakePolicy }),
|
|
15
|
-
...(context.
|
|
15
|
+
...(context.turnId === undefined
|
|
16
16
|
? {}
|
|
17
|
-
: {
|
|
17
|
+
: { turnId: requireSafeIdentity(context.turnId, "Message Turn id") }),
|
|
18
18
|
...(context.workItemId === undefined
|
|
19
19
|
? {}
|
|
20
20
|
: { workItemId: requireSafeIdentity(context.workItemId, "Message Work item id") }),
|
|
@@ -43,16 +43,16 @@ export function validateTaskMessage(message) {
|
|
|
43
43
|
&& message.kind !== "operator") {
|
|
44
44
|
throw new Error("Message wakePolicy is only valid for user/operator messages.");
|
|
45
45
|
}
|
|
46
|
-
if (message.
|
|
47
|
-
requireSafeIdentity(message.
|
|
46
|
+
if (message.turnId !== undefined)
|
|
47
|
+
requireSafeIdentity(message.turnId, "Message Turn id");
|
|
48
48
|
if (message.workItemId !== undefined) {
|
|
49
49
|
validateTaskRecordReference({
|
|
50
50
|
taskId: message.taskId,
|
|
51
51
|
localId: message.workItemId
|
|
52
52
|
}, "workItem");
|
|
53
53
|
}
|
|
54
|
-
if (message.
|
|
55
|
-
validateTaskRecordReference({ taskId: message.taskId, localId: message.
|
|
54
|
+
if (message.turnId !== undefined) {
|
|
55
|
+
validateTaskRecordReference({ taskId: message.taskId, localId: message.turnId }, "turn");
|
|
56
56
|
}
|
|
57
57
|
if (typeof message.createdAt !== "string" || Number.isNaN(Date.parse(message.createdAt))) {
|
|
58
58
|
throw new Error("Message createdAt is invalid.");
|