@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
|
@@ -3,7 +3,7 @@ import { isReviewFindingBlocking } from "../review/reviewFinding.js";
|
|
|
3
3
|
import { deltaRecheckBlocksAcceptance } from "../review/reviewRound.js";
|
|
4
4
|
import { isSemanticReviewRound } from "../review/reviewOutcomeClassifier.js";
|
|
5
5
|
import { reviewFindingLedgerWriteFailedFromEvents } from "../review/reviewFindingLedger.js";
|
|
6
|
-
import { resolveRecordedTaskFinalReviewContract } from "../review/
|
|
6
|
+
import { resolveRecordedTaskFinalReviewContract } from "../review/taskFinalReviewContractResolution.js";
|
|
7
7
|
import { sameTaskFinalReviewContract } from "../review/taskFinalReviewContract.js";
|
|
8
8
|
const ACTIVE_JOB_STATUSES = new Set([
|
|
9
9
|
"queued",
|
|
@@ -16,13 +16,13 @@ const UNRESOLVED_INTEGRATION_STATUSES = new Set([
|
|
|
16
16
|
"validating"
|
|
17
17
|
]);
|
|
18
18
|
const TERMINAL_REVIEW_STATUSES = new Set(["completed", "failed"]);
|
|
19
|
-
const TERMINAL_LANE_STATUSES = new Set(["completed", "failed", "
|
|
19
|
+
const TERMINAL_LANE_STATUSES = new Set(["completed", "failed", "skipped"]);
|
|
20
20
|
export function projectCompletionReadiness(facts, options = {}) {
|
|
21
21
|
const blockers = [];
|
|
22
22
|
const advisories = [];
|
|
23
23
|
const { task } = facts;
|
|
24
24
|
const findingsGate = options.findingsGate ?? true;
|
|
25
|
-
const taskFinalReviewContract = resolveRecordedTaskFinalReviewContract(task.id, facts.workItems, facts.reviewRounds
|
|
25
|
+
const taskFinalReviewContract = resolveRecordedTaskFinalReviewContract(task.id, facts.workItems, facts.reviewRounds)?.effective;
|
|
26
26
|
const taskFinalReviewRequired = taskFinalReviewContract !== undefined;
|
|
27
27
|
// A pending/running Task-final Review must be resumed or blocked first.
|
|
28
28
|
for (const round of facts.reviewRounds) {
|
|
@@ -36,7 +36,7 @@ export function projectCompletionReadiness(facts, options = {}) {
|
|
|
36
36
|
reason: `Task-final ReviewRound ${round.id} is ${round.status}.`,
|
|
37
37
|
fix: round.status === "pending"
|
|
38
38
|
? `yui task review retry ${task.id}/${round.id}`
|
|
39
|
-
: `wait for Reviewer
|
|
39
|
+
: `wait for Reviewer Turn on ${round.id} to finish`
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
// Issue 07: only the latest completed Task-final Review can define whether
|
|
@@ -47,7 +47,7 @@ export function projectCompletionReadiness(facts, options = {}) {
|
|
|
47
47
|
.filter((round) => ((round.scope ?? "work-item") === "task"
|
|
48
48
|
&& (taskFinalReviewContract === undefined || sameTaskFinalReviewContract(round.taskFinalReviewContract, taskFinalReviewContract))
|
|
49
49
|
&& isSemanticReviewRound(round, {
|
|
50
|
-
|
|
50
|
+
listTurns: () => facts.turns,
|
|
51
51
|
listReviewFindings: () => facts.reviewFindings,
|
|
52
52
|
listEvents: () => facts.events
|
|
53
53
|
})))
|
|
@@ -173,32 +173,32 @@ function overlap(left, right) {
|
|
|
173
173
|
return left.split("\n").some((line) => line.length > 0 && rightLines.has(line));
|
|
174
174
|
}
|
|
175
175
|
/**
|
|
176
|
-
* Default number of consecutive
|
|
176
|
+
* Default number of consecutive completed Leader turns that must produce no
|
|
177
177
|
* durable delivery change before the budget is exhausted.
|
|
178
178
|
*/
|
|
179
179
|
export const DEFAULT_SEMANTIC_BUDGET_TURNS = 3;
|
|
180
180
|
/**
|
|
181
181
|
* Evaluate the semantic-progress budget from existing records only. The
|
|
182
|
-
* budget is exhausted when the last `turns` Leader
|
|
182
|
+
* budget is exhausted when the last `turns` Leader Turns all completed and no
|
|
183
183
|
* WorkItem/ChangeSet/Integration/Review record changed at or after the first
|
|
184
|
-
* of those
|
|
184
|
+
* of those Turns. Active execution (any Turn) never exhausts the budget: a
|
|
185
185
|
* slow but progressing Worker or Leader is never interrupted.
|
|
186
186
|
*/
|
|
187
187
|
export function evaluateSemanticBudget(facts, turns = DEFAULT_SEMANTIC_BUDGET_TURNS) {
|
|
188
|
-
if (facts.
|
|
188
|
+
if (facts.activeTurns.length > 0) {
|
|
189
189
|
return {
|
|
190
190
|
exhausted: false,
|
|
191
|
-
reason: "Active execution is in flight; the budget never interrupts a progressing
|
|
192
|
-
evidence: facts.
|
|
191
|
+
reason: "Active execution is in flight; the budget never interrupts a progressing Turn.",
|
|
192
|
+
evidence: facts.activeTurns.map((run) => run.id)
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
|
-
const recentLeaderRuns = facts.
|
|
196
|
-
.filter((run) => run.status === "
|
|
195
|
+
const recentLeaderRuns = facts.leaderTurns
|
|
196
|
+
.filter((run) => run.status === "completed")
|
|
197
197
|
.slice(-turns);
|
|
198
198
|
if (recentLeaderRuns.length < turns) {
|
|
199
199
|
return {
|
|
200
200
|
exhausted: false,
|
|
201
|
-
reason: `Fewer than ${turns} consecutive
|
|
201
|
+
reason: `Fewer than ${turns} consecutive completed Leader turns.`,
|
|
202
202
|
evidence: recentLeaderRuns.map((run) => run.id)
|
|
203
203
|
};
|
|
204
204
|
}
|
|
@@ -213,7 +213,7 @@ export function evaluateSemanticBudget(facts, turns = DEFAULT_SEMANTIC_BUDGET_TU
|
|
|
213
213
|
}
|
|
214
214
|
return {
|
|
215
215
|
exhausted: true,
|
|
216
|
-
reason: `${turns} consecutive Leader turns produced no durable delivery change; record a diagnosis
|
|
216
|
+
reason: `${turns} consecutive Leader turns produced no durable delivery change; record a diagnosis and wait for new facts instead of creating more records.`,
|
|
217
217
|
evidence: recentLeaderRuns.map((run) => run.id)
|
|
218
218
|
};
|
|
219
219
|
}
|
package/dist/task/nextAction.js
CHANGED
|
@@ -7,7 +7,7 @@ import { actionableExecutionLaneRecoveries } from "../execution/executionHealth.
|
|
|
7
7
|
import { candidateConvergenceDisagreement, candidateConvergenceEvidenceSufficient, candidateConvergenceStageResultsValid } from "../execution/candidateConvergence.js";
|
|
8
8
|
import { executionStageSpendClosed, routeExecutionStage } from "../execution/resourceBroker.js";
|
|
9
9
|
import { sameTaskFinalReviewContract } from "../review/taskFinalReviewContract.js";
|
|
10
|
-
import { resolveRecordedTaskFinalReviewContract } from "../review/
|
|
10
|
+
import { resolveRecordedTaskFinalReviewContract } from "../review/taskFinalReviewContractResolution.js";
|
|
11
11
|
import { currentWorkItemCandidate, currentWorkItemExecutionGroup, governingWorkItemCandidate } from "../workItem/workItem.js";
|
|
12
12
|
const OPEN_WORK_ITEM_STATUSES = new Set(["pending", "running", "awaiting_acceptance"]);
|
|
13
13
|
export function projectNextAction(facts) {
|
|
@@ -57,18 +57,18 @@ export function projectNextAction(facts) {
|
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
const laneRecovery = actionableExecutionLaneRecoveries(facts.executionGroups ?? [])
|
|
60
|
-
.find(
|
|
60
|
+
.find(hasExactTurn);
|
|
61
61
|
if (laneRecovery !== undefined) {
|
|
62
62
|
return buildExecutionLaneRecoveryAction(facts, laneRecovery);
|
|
63
63
|
}
|
|
64
|
-
const activeLeader = facts.
|
|
64
|
+
const activeLeader = facts.activeTurns.find((run) => run.roleName === "leader");
|
|
65
65
|
if (activeLeader !== undefined) {
|
|
66
66
|
return buildAction(facts, {
|
|
67
67
|
kind: "wait-for-owned-execution",
|
|
68
|
-
reason: `Leader
|
|
69
|
-
refs: [ref("
|
|
68
|
+
reason: `Leader Turn ${activeLeader.id} is active; the protocol position is being executed.`,
|
|
69
|
+
refs: [ref("turn", activeLeader.id)],
|
|
70
70
|
preconditions: [
|
|
71
|
-
{ fact: "Leader
|
|
71
|
+
{ fact: "Leader Turn is active", satisfied: true, ref: ref("turn", activeLeader.id) }
|
|
72
72
|
]
|
|
73
73
|
});
|
|
74
74
|
}
|
|
@@ -107,18 +107,18 @@ export function projectNextAction(facts) {
|
|
|
107
107
|
if (reviewGroupAwaitingResolution(activeReview)) {
|
|
108
108
|
return buildResolveReviewGroupAction(facts, activeReview);
|
|
109
109
|
}
|
|
110
|
-
if (activeReview.
|
|
110
|
+
if (activeReview.reviewerTurnId === undefined) {
|
|
111
111
|
return buildAction(facts, {
|
|
112
112
|
kind: "repair-protocol-inconsistency",
|
|
113
|
-
reason: `ReviewRound ${activeReview.id} is running but has no Reviewer
|
|
113
|
+
reason: `ReviewRound ${activeReview.id} is running but has no Reviewer Turn.`,
|
|
114
114
|
refs: [reviewRef],
|
|
115
115
|
conflicts: [reviewRef],
|
|
116
116
|
preconditions: [
|
|
117
|
-
{ fact: "Running ReviewRound has an exact Reviewer
|
|
117
|
+
{ fact: "Running ReviewRound has an exact Reviewer Turn", satisfied: false, ref: reviewRef }
|
|
118
118
|
]
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
|
-
const reviewRun = activeReviewRoundRun(activeReview, facts.
|
|
121
|
+
const reviewRun = activeReviewRoundRun(activeReview, facts.activeTurns);
|
|
122
122
|
if (reviewRun === undefined) {
|
|
123
123
|
if (reviewGroupHasResourceQueue(activeReview)) {
|
|
124
124
|
return buildAction(facts, {
|
|
@@ -132,36 +132,36 @@ export function projectNextAction(facts) {
|
|
|
132
132
|
recommendedCommand: `yui task work review ${task.id}/${candidateReady.id}`
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
|
-
const runRef = ref("
|
|
135
|
+
const runRef = ref("turn", activeReview.reviewerTurnId);
|
|
136
136
|
return buildAction(facts, {
|
|
137
137
|
kind: "repair-protocol-inconsistency",
|
|
138
|
-
reason: `ReviewRound ${activeReview.id} references Reviewer
|
|
138
|
+
reason: `ReviewRound ${activeReview.id} references Reviewer Turn ${activeReview.reviewerTurnId}, but that Turn is not active.`,
|
|
139
139
|
refs: [reviewRef, runRef],
|
|
140
140
|
conflicts: [reviewRef, runRef],
|
|
141
141
|
preconditions: [
|
|
142
|
-
{ fact: "Reviewer
|
|
142
|
+
{ fact: "Reviewer Turn is active", satisfied: false, ref: runRef }
|
|
143
143
|
]
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
146
|
return buildAction(facts, {
|
|
147
147
|
kind: "wait-for-owned-execution",
|
|
148
|
-
reason: `Reviewer
|
|
149
|
-
refs: [reviewRef, ref("
|
|
148
|
+
reason: `Reviewer Turn ${reviewRun.id} is evaluating Candidate ${candidateReady.id}/${candidate?.id ?? "unknown"}.`,
|
|
149
|
+
refs: [reviewRef, ref("turn", reviewRun.id)],
|
|
150
150
|
preconditions: [
|
|
151
151
|
{ fact: "ReviewRound is running", satisfied: true, ref: reviewRef },
|
|
152
|
-
{ fact: "Reviewer
|
|
152
|
+
{ fact: "Reviewer Turn is active", satisfied: true, ref: ref("turn", reviewRun.id) }
|
|
153
153
|
]
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
|
-
if (activeReview.
|
|
157
|
-
const runRef = ref("
|
|
156
|
+
if (activeReview.reviewerTurnId !== undefined) {
|
|
157
|
+
const runRef = ref("turn", activeReview.reviewerTurnId);
|
|
158
158
|
return buildAction(facts, {
|
|
159
159
|
kind: "repair-protocol-inconsistency",
|
|
160
|
-
reason: `Pending ReviewRound ${activeReview.id} already references Reviewer
|
|
160
|
+
reason: `Pending ReviewRound ${activeReview.id} already references Reviewer Turn ${activeReview.reviewerTurnId}.`,
|
|
161
161
|
refs: [reviewRef, runRef],
|
|
162
162
|
conflicts: [reviewRef, runRef],
|
|
163
163
|
preconditions: [
|
|
164
|
-
{ fact: "Pending ReviewRound has no Reviewer
|
|
164
|
+
{ fact: "Pending ReviewRound has no Reviewer Turn", satisfied: false, ref: runRef }
|
|
165
165
|
]
|
|
166
166
|
});
|
|
167
167
|
}
|
|
@@ -171,7 +171,7 @@ export function projectNextAction(facts) {
|
|
|
171
171
|
refs: [reviewRef],
|
|
172
172
|
preconditions: [
|
|
173
173
|
{ fact: "ReviewRound is pending", satisfied: true, ref: reviewRef },
|
|
174
|
-
{ fact: "Reviewer
|
|
174
|
+
{ fact: "Reviewer Turn exists", satisfied: false }
|
|
175
175
|
],
|
|
176
176
|
recommendedCommand: `yui task work review ${task.id}/${candidateReady.id}`
|
|
177
177
|
});
|
|
@@ -211,15 +211,15 @@ export function projectNextAction(facts) {
|
|
|
211
211
|
judgmentRequired: `Leader must judge Candidate ${candidateReady.id}/${candidate?.id ?? "unknown"} against the Task objective, acceptance criteria, and delivery risk.`
|
|
212
212
|
});
|
|
213
213
|
}
|
|
214
|
-
//
|
|
214
|
+
// Turn purpose owns routing. Review Turns remain attached to their exact
|
|
215
215
|
// ReviewRound branches below instead of being mistaken for Worker delivery.
|
|
216
|
-
const activeDelegatedExecutions = facts.
|
|
216
|
+
const activeDelegatedExecutions = facts.activeTurns.filter((run) => (run.purpose === "execution" && run.roleName !== "leader"));
|
|
217
217
|
if (activeDelegatedExecutions.length > 0) {
|
|
218
218
|
return buildAction(facts, {
|
|
219
219
|
kind: "wait-for-owned-execution",
|
|
220
|
-
reason: `${activeDelegatedExecutions.length} delegated execution
|
|
221
|
-
refs: activeDelegatedExecutions.map((run) => ref("
|
|
222
|
-
preconditions: activeDelegatedExecutions.map((run) => ({ fact: `Execution
|
|
220
|
+
reason: `${activeDelegatedExecutions.length} delegated execution Turn(s) are active; wait for their completion.`,
|
|
221
|
+
refs: activeDelegatedExecutions.map((run) => ref("turn", run.id)),
|
|
222
|
+
preconditions: activeDelegatedExecutions.map((run) => ({ fact: `Execution Turn ${run.id} is active`, satisfied: true, ref: ref("turn", run.id) }))
|
|
223
223
|
});
|
|
224
224
|
}
|
|
225
225
|
const failedWork = facts.workItems.find((item) => item.status === "failed");
|
|
@@ -446,18 +446,18 @@ export function projectNextAction(facts) {
|
|
|
446
446
|
if (reviewGroupAwaitingResolution(activeFinal)) {
|
|
447
447
|
return buildResolveReviewGroupAction(facts, activeFinal);
|
|
448
448
|
}
|
|
449
|
-
if (activeFinal.
|
|
449
|
+
if (activeFinal.reviewerTurnId === undefined) {
|
|
450
450
|
return buildAction(facts, {
|
|
451
451
|
kind: "repair-protocol-inconsistency",
|
|
452
|
-
reason: `Task-final ReviewRound ${activeFinal.id} is running but has no Reviewer
|
|
452
|
+
reason: `Task-final ReviewRound ${activeFinal.id} is running but has no Reviewer Turn.`,
|
|
453
453
|
refs: [reviewRef],
|
|
454
454
|
conflicts: [reviewRef],
|
|
455
455
|
preconditions: [
|
|
456
|
-
{ fact: "Running Task-final ReviewRound has an exact Reviewer
|
|
456
|
+
{ fact: "Running Task-final ReviewRound has an exact Reviewer Turn", satisfied: false, ref: reviewRef }
|
|
457
457
|
]
|
|
458
458
|
});
|
|
459
459
|
}
|
|
460
|
-
const reviewRun = activeReviewRoundRun(activeFinal, facts.
|
|
460
|
+
const reviewRun = activeReviewRoundRun(activeFinal, facts.activeTurns);
|
|
461
461
|
if (reviewRun === undefined) {
|
|
462
462
|
if (reviewGroupHasResourceQueue(activeFinal)) {
|
|
463
463
|
return buildAction(facts, {
|
|
@@ -471,24 +471,24 @@ export function projectNextAction(facts) {
|
|
|
471
471
|
recommendedCommand: `yui task review request ${task.id} --role ${activeFinal.reviewerRoleName}`
|
|
472
472
|
});
|
|
473
473
|
}
|
|
474
|
-
const runRef = ref("
|
|
474
|
+
const runRef = ref("turn", activeFinal.reviewerTurnId);
|
|
475
475
|
return buildAction(facts, {
|
|
476
476
|
kind: "repair-protocol-inconsistency",
|
|
477
|
-
reason: `Task-final ReviewRound ${activeFinal.id} references Reviewer
|
|
477
|
+
reason: `Task-final ReviewRound ${activeFinal.id} references Reviewer Turn ${activeFinal.reviewerTurnId}, but that Turn is not active.`,
|
|
478
478
|
refs: [reviewRef, runRef],
|
|
479
479
|
conflicts: [reviewRef, runRef],
|
|
480
480
|
preconditions: [
|
|
481
|
-
{ fact: "Reviewer
|
|
481
|
+
{ fact: "Reviewer Turn is active", satisfied: false, ref: runRef }
|
|
482
482
|
]
|
|
483
483
|
});
|
|
484
484
|
}
|
|
485
485
|
return buildAction(facts, {
|
|
486
486
|
kind: "wait-for-owned-execution",
|
|
487
|
-
reason: `Reviewer
|
|
488
|
-
refs: [reviewRef, ref("
|
|
487
|
+
reason: `Reviewer Turn ${reviewRun.id} is executing frozen Task-final Review ${activeFinal.id}; this Review does not globally pause Leader decisions on newer facts.`,
|
|
488
|
+
refs: [reviewRef, ref("turn", reviewRun.id)],
|
|
489
489
|
preconditions: [
|
|
490
490
|
{ fact: "Task-final ReviewRound is running", satisfied: true, ref: reviewRef },
|
|
491
|
-
{ fact: "Reviewer
|
|
491
|
+
{ fact: "Reviewer Turn is active", satisfied: true, ref: ref("turn", reviewRun.id) }
|
|
492
492
|
],
|
|
493
493
|
alternatives: [
|
|
494
494
|
{
|
|
@@ -506,15 +506,15 @@ export function projectNextAction(facts) {
|
|
|
506
506
|
judgmentRequired: "Leader decides whether the current facts justify waiting, continuing development, direct review, or another Reviewer."
|
|
507
507
|
});
|
|
508
508
|
}
|
|
509
|
-
if (activeFinal.
|
|
510
|
-
const runRef = ref("
|
|
509
|
+
if (activeFinal.reviewerTurnId !== undefined) {
|
|
510
|
+
const runRef = ref("turn", activeFinal.reviewerTurnId);
|
|
511
511
|
return buildAction(facts, {
|
|
512
512
|
kind: "repair-protocol-inconsistency",
|
|
513
|
-
reason: `Pending Task-final ReviewRound ${activeFinal.id} already references Reviewer
|
|
513
|
+
reason: `Pending Task-final ReviewRound ${activeFinal.id} already references Reviewer Turn ${activeFinal.reviewerTurnId}.`,
|
|
514
514
|
refs: [reviewRef, runRef],
|
|
515
515
|
conflicts: [reviewRef, runRef],
|
|
516
516
|
preconditions: [
|
|
517
|
-
{ fact: "Pending Task-final ReviewRound has no Reviewer
|
|
517
|
+
{ fact: "Pending Task-final ReviewRound has no Reviewer Turn", satisfied: false, ref: runRef }
|
|
518
518
|
]
|
|
519
519
|
});
|
|
520
520
|
}
|
|
@@ -524,7 +524,7 @@ export function projectNextAction(facts) {
|
|
|
524
524
|
refs: [reviewRef],
|
|
525
525
|
preconditions: [
|
|
526
526
|
{ fact: "Task-final ReviewRound is pending", satisfied: true, ref: reviewRef },
|
|
527
|
-
{ fact: "Reviewer
|
|
527
|
+
{ fact: "Reviewer Turn exists", satisfied: false }
|
|
528
528
|
],
|
|
529
529
|
recommendedCommand: `yui task review retry ${task.id}/${activeFinal.id}`
|
|
530
530
|
});
|
|
@@ -599,24 +599,24 @@ export function projectNextAction(facts) {
|
|
|
599
599
|
recommendedCommand: `yui task complete ${task.id} --summary-file -`
|
|
600
600
|
});
|
|
601
601
|
}
|
|
602
|
-
function
|
|
603
|
-
return lane.
|
|
602
|
+
function hasExactTurn(lane) {
|
|
603
|
+
return lane.turnId !== undefined;
|
|
604
604
|
}
|
|
605
605
|
function buildExecutionLaneRecoveryAction(facts, lane) {
|
|
606
606
|
const refs = [
|
|
607
607
|
ref("execution-group", lane.groupId),
|
|
608
608
|
ref("execution-lane", lane.laneId),
|
|
609
|
-
ref("
|
|
609
|
+
ref("turn", lane.turnId)
|
|
610
610
|
];
|
|
611
611
|
return buildAction(facts, {
|
|
612
612
|
kind: "retry-execution-lane",
|
|
613
|
-
reason: `Execution Lane ${lane.laneId} is durably failed; retry only exact
|
|
613
|
+
reason: `Execution Lane ${lane.laneId} is durably failed; retry only exact Turn ${lane.turnId} and retain sibling results.`,
|
|
614
614
|
refs,
|
|
615
615
|
preconditions: [
|
|
616
616
|
{ fact: "Execution Lane is failed and unresolved", satisfied: true, ref: refs[1] },
|
|
617
|
-
{ fact: "Exact failed
|
|
617
|
+
{ fact: "Exact failed Turn is retained", satisfied: true, ref: refs[2] }
|
|
618
618
|
],
|
|
619
|
-
recommendedCommand: `yui task
|
|
619
|
+
recommendedCommand: `yui task turn retry ${facts.task.id}/${lane.turnId}`
|
|
620
620
|
});
|
|
621
621
|
}
|
|
622
622
|
function exhaustedExplorationReason(item, executionGroups) {
|
|
@@ -655,8 +655,7 @@ export function durableStateFingerprint(facts) {
|
|
|
655
655
|
...facts.changeSets.map((changeSet) => `change-set:${changeSet.id}:${changeSet.headCommit}`),
|
|
656
656
|
...facts.integrations.map((attempt) => `integration:${attempt.id}:${attempt.status}:${attempt.updatedAt}`),
|
|
657
657
|
...facts.integrationQueueEntries.map((entry) => `integration-queue:${entry.id}:${entry.status}:${entry.updatedAt}`),
|
|
658
|
-
...facts.reviewRounds.map((round) => `review:${round.id}:${round.status}:${round.endedAt ?? ""}`)
|
|
659
|
-
...facts.taskFinalReviewContractEvents.map((event) => `task-final-review-event:${event.id}:${event.createdAt}`)
|
|
658
|
+
...facts.reviewRounds.map((round) => `review:${round.id}:${round.status}:${round.endedAt ?? ""}`)
|
|
660
659
|
];
|
|
661
660
|
return createHash("sha256").update(parts.join("\n")).digest("hex");
|
|
662
661
|
}
|
|
@@ -692,7 +691,7 @@ function buildExecutionStageAction(facts, item) {
|
|
|
692
691
|
const resources = projected?.resources;
|
|
693
692
|
if (resources === undefined)
|
|
694
693
|
return null;
|
|
695
|
-
const usableLaneIds = group.lanes.filter(({ status }) =>
|
|
694
|
+
const usableLaneIds = group.lanes.filter(({ status }) => status === "completed").map(({ id }) => id);
|
|
696
695
|
const stageResultsValid = candidateConvergenceStageResultsValid(group);
|
|
697
696
|
const disagreement = candidateConvergenceDisagreement(group);
|
|
698
697
|
const routing = routeExecutionStage({
|
|
@@ -824,11 +823,11 @@ function buildExecutionStageAction(facts, item) {
|
|
|
824
823
|
if (resources.activeLaneIds.length > 0) {
|
|
825
824
|
return buildAction(facts, {
|
|
826
825
|
kind: "repair-protocol-inconsistency",
|
|
827
|
-
reason: `ExecutionGroup ${group.id} retains active Lanes but no delegated
|
|
826
|
+
reason: `ExecutionGroup ${group.id} retains active Lanes but no delegated Turn is active.`,
|
|
828
827
|
refs,
|
|
829
828
|
conflicts: refs,
|
|
830
829
|
preconditions: [
|
|
831
|
-
{ fact: "Every active Lane has an active exact
|
|
830
|
+
{ fact: "Every active Lane has an active exact Turn", satisfied: false, ref: refs[1] }
|
|
832
831
|
]
|
|
833
832
|
});
|
|
834
833
|
}
|
|
@@ -843,25 +842,25 @@ function latestActiveWorkItemReview(rounds, item, candidate) {
|
|
|
843
842
|
&& round.candidateId === candidate.id
|
|
844
843
|
&& (round.status === "pending" || round.status === "running")));
|
|
845
844
|
}
|
|
846
|
-
function activeReviewRoundRun(round,
|
|
845
|
+
function activeReviewRoundRun(round, activeTurns) {
|
|
847
846
|
if (round.executionGroup !== undefined) {
|
|
848
847
|
for (const lane of round.executionGroup.lanes) {
|
|
849
848
|
if (lane.status !== "running"
|
|
850
849
|
|| lane.reviewRoundId !== round.id
|
|
851
|
-
|| lane.
|
|
850
|
+
|| lane.turnId === undefined) {
|
|
852
851
|
continue;
|
|
853
852
|
}
|
|
854
|
-
const run =
|
|
853
|
+
const run = activeTurns.find((candidate) => (candidate.id === lane.turnId && candidate.roleName === lane.roleName));
|
|
855
854
|
if (run !== undefined)
|
|
856
855
|
return run;
|
|
857
856
|
}
|
|
858
857
|
return undefined;
|
|
859
858
|
}
|
|
860
|
-
if (round.
|
|
859
|
+
if (round.reviewerTurnId === undefined)
|
|
861
860
|
return undefined;
|
|
862
|
-
return
|
|
861
|
+
return activeTurns.find((run) => (run.id === round.reviewerTurnId && run.roleName === round.reviewerRoleName));
|
|
863
862
|
}
|
|
864
|
-
const TERMINAL_REVIEW_LANE_STATUSES = new Set(["
|
|
863
|
+
const TERMINAL_REVIEW_LANE_STATUSES = new Set(["completed", "failed"]);
|
|
865
864
|
function isPanelReviewRound(round) {
|
|
866
865
|
return round.executionGroup !== undefined
|
|
867
866
|
&& (round.executionGroup.lanes.length > 1
|
|
@@ -878,7 +877,7 @@ function reviewGroupHasResourceQueue(round) {
|
|
|
878
877
|
return round.executionGroup !== undefined
|
|
879
878
|
&& round.executionGroup.resolution === undefined
|
|
880
879
|
&& round.executionGroup.lanes.some((lane) => (lane.status === "pending"
|
|
881
|
-
&& lane.
|
|
880
|
+
&& lane.turnId === undefined));
|
|
882
881
|
}
|
|
883
882
|
function buildResolveReviewGroupAction(facts, round) {
|
|
884
883
|
const group = round.executionGroup;
|
|
@@ -921,35 +920,35 @@ function buildResolveReviewGroupAction(facts, round) {
|
|
|
921
920
|
judgmentRequired: `Leader must judge Review panel ${group.id} against the Task objective, acceptance criteria, and delivery risk.`
|
|
922
921
|
});
|
|
923
922
|
}
|
|
924
|
-
function reviewRoundConflict(round,
|
|
923
|
+
function reviewRoundConflict(round, activeTurns) {
|
|
925
924
|
const reviewRef = ref("review-round", round.id);
|
|
926
925
|
if (round.status === "running") {
|
|
927
926
|
if (reviewGroupAwaitingResolution(round)) {
|
|
928
927
|
return null;
|
|
929
928
|
}
|
|
930
|
-
if (round.
|
|
929
|
+
if (round.reviewerTurnId === undefined) {
|
|
931
930
|
return {
|
|
932
|
-
reason: `ReviewRound ${round.id} is running but has no Reviewer
|
|
931
|
+
reason: `ReviewRound ${round.id} is running but has no Reviewer Turn.`,
|
|
933
932
|
conflicts: [reviewRef]
|
|
934
933
|
};
|
|
935
934
|
}
|
|
936
|
-
if (activeReviewRoundRun(round,
|
|
935
|
+
if (activeReviewRoundRun(round, activeTurns) === undefined) {
|
|
937
936
|
if (reviewGroupHasResourceQueue(round))
|
|
938
937
|
return null;
|
|
939
|
-
const runRef = ref("
|
|
938
|
+
const runRef = ref("turn", round.reviewerTurnId);
|
|
940
939
|
return {
|
|
941
|
-
reason: `ReviewRound ${round.id} references Reviewer
|
|
940
|
+
reason: `ReviewRound ${round.id} references Reviewer Turn ${round.reviewerTurnId}, but that Turn is not active.`,
|
|
942
941
|
conflicts: [reviewRef, runRef]
|
|
943
942
|
};
|
|
944
943
|
}
|
|
945
944
|
}
|
|
946
945
|
if (round.status === "pending") {
|
|
947
|
-
const
|
|
948
|
-
?? round.executionGroup?.lanes.find((lane) => lane.
|
|
949
|
-
if (
|
|
950
|
-
const runRef = ref("
|
|
946
|
+
const launchedTurnId = round.reviewerTurnId
|
|
947
|
+
?? round.executionGroup?.lanes.find((lane) => lane.turnId !== undefined)?.turnId;
|
|
948
|
+
if (launchedTurnId !== undefined) {
|
|
949
|
+
const runRef = ref("turn", launchedTurnId);
|
|
951
950
|
return {
|
|
952
|
-
reason: `Pending ReviewRound ${round.id} already references Reviewer
|
|
951
|
+
reason: `Pending ReviewRound ${round.id} already references Reviewer Turn ${launchedTurnId}.`,
|
|
953
952
|
conflicts: [reviewRef, runRef]
|
|
954
953
|
};
|
|
955
954
|
}
|
|
@@ -992,7 +991,7 @@ function taskFinalReviewContract(facts) {
|
|
|
992
991
|
return taskFinalReviewContractResolution(facts)?.effective;
|
|
993
992
|
}
|
|
994
993
|
function taskFinalReviewContractResolution(facts) {
|
|
995
|
-
return resolveRecordedTaskFinalReviewContract(facts.task.id, facts.workItems, facts.reviewRounds
|
|
994
|
+
return resolveRecordedTaskFinalReviewContract(facts.task.id, facts.workItems, facts.reviewRounds);
|
|
996
995
|
}
|
|
997
996
|
function taskFinalReviewRequired(facts) {
|
|
998
997
|
return taskFinalReviewContract(facts) !== undefined;
|
|
@@ -1073,7 +1072,7 @@ export function nextActionReviewOutcomeEvidence(facts) {
|
|
|
1073
1072
|
if (evidence === undefined)
|
|
1074
1073
|
return undefined;
|
|
1075
1074
|
return {
|
|
1076
|
-
|
|
1075
|
+
listTurns: () => evidence.turns,
|
|
1077
1076
|
listReviewFindings: () => evidence.reviewFindings,
|
|
1078
1077
|
listEvents: () => evidence.events
|
|
1079
1078
|
};
|
|
@@ -1095,16 +1094,14 @@ function detectProtocolInconsistency(facts) {
|
|
|
1095
1094
|
.filter((round) => ((round.scope ?? "work-item") === "task"
|
|
1096
1095
|
&& round.taskFinalReviewContract !== undefined))
|
|
1097
1096
|
.map((round) => ref("review-round", round.id));
|
|
1098
|
-
const eventRefs = facts.taskFinalReviewContractEvents
|
|
1099
|
-
.map((event) => ref("task-event", event.id));
|
|
1100
1097
|
return {
|
|
1101
|
-
reason: "Task-final Review contract
|
|
1098
|
+
reason: "Task-final Review contract is inconsistent: "
|
|
1102
1099
|
+ (error instanceof Error ? error.message : String(error)),
|
|
1103
|
-
conflicts: [...candidateRefs, ...reviewRefs
|
|
1100
|
+
conflicts: [...candidateRefs, ...reviewRefs]
|
|
1104
1101
|
};
|
|
1105
1102
|
}
|
|
1106
1103
|
for (const round of facts.reviewRounds) {
|
|
1107
|
-
const reviewConflict = reviewRoundConflict(round, facts.
|
|
1104
|
+
const reviewConflict = reviewRoundConflict(round, facts.activeTurns);
|
|
1108
1105
|
if (reviewConflict !== null)
|
|
1109
1106
|
return reviewConflict;
|
|
1110
1107
|
}
|
package/dist/task/task.js
CHANGED
|
@@ -242,10 +242,8 @@ export function validateTask(task) {
|
|
|
242
242
|
normalizeProjectBindings(task.projectBindings);
|
|
243
243
|
if (task.cwd !== undefined)
|
|
244
244
|
requireText(task.cwd, "Task workspace");
|
|
245
|
-
if (task
|
|
246
|
-
|
|
247
|
-
&& task.legacyDeliveryPath !== "integrated") {
|
|
248
|
-
throw new Error("Task legacy delivery path is invalid.");
|
|
245
|
+
if (Object.hasOwn(task, "legacyDeliveryPath")) {
|
|
246
|
+
throw new Error("Task contains the removed delivery-path field.");
|
|
249
247
|
}
|
|
250
248
|
const completionFields = [task.completedAt, task.completedBy, task.completionSummary];
|
|
251
249
|
const hasAnyCompletion = completionFields.some((value) => value !== undefined);
|
|
@@ -2,7 +2,7 @@ import { requireIdentity } from "../domain/validation.js";
|
|
|
2
2
|
export const TASK_RECORD_ID_PREFIXES = {
|
|
3
3
|
workItem: "work-item",
|
|
4
4
|
contextSnapshot: "context-snapshot",
|
|
5
|
-
|
|
5
|
+
turn: "turn",
|
|
6
6
|
reviewRound: "review-round",
|
|
7
7
|
reviewFinding: "review-finding",
|
|
8
8
|
changeSet: "change-set",
|
|
@@ -23,8 +23,8 @@ export function formatTaskRecordReference(taskId, localId, kind) {
|
|
|
23
23
|
const reference = validateTaskRecordReference({ taskId, localId }, kind);
|
|
24
24
|
return `${reference.taskId}/${reference.localId}`;
|
|
25
25
|
}
|
|
26
|
-
export function
|
|
27
|
-
return `
|
|
26
|
+
export function formatTurnReceiptId(taskId, turnId) {
|
|
27
|
+
return `turn:${formatTaskRecordReference(taskId, turnId, "turn")}`;
|
|
28
28
|
}
|
|
29
29
|
export function formatInputRequestReceiptId(taskId, requestId) {
|
|
30
30
|
return `input-request:${formatTaskRecordReference(taskId, requestId, "inputRequest")}`;
|