@zq-silk/yui 0.15.7 → 0.15.9
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 +194 -399
- package/ARCHITECTURE.zh-CN.md +151 -0
- package/README.md +306 -1131
- package/dist/agent/adapterCatalog.js +15 -2
- package/dist/agent/agent.js +23 -3
- package/dist/agent/argumentPolicy.js +7 -1
- package/dist/agent/connectionPlan.js +62 -0
- package/dist/agent/executionComponents.js +158 -0
- package/dist/agent/launchEnvironment.js +31 -3
- package/dist/agent/managedRuntimeEnvironment.js +3 -5
- package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
- package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
- package/dist/artifacts/artifactCapability.js +74 -0
- package/dist/artifacts/artifactCommitLock.js +249 -0
- package/dist/artifacts/artifactPaths.js +151 -0
- package/dist/artifacts/gitArtifactRef.js +146 -0
- package/dist/artifacts/managedGit.js +332 -0
- package/dist/artifacts/taskArtifactRepository.js +277 -0
- package/dist/brief/taskBrief.js +12 -0
- package/dist/cli/agentConfigurationPicker.js +13 -0
- package/dist/cli/commandCatalog.js +165 -74
- package/dist/cli/interactionCandidates.js +5 -5
- package/dist/cli/interactionPolicy.js +38 -8
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/managedDiagnostics.js +28 -0
- package/dist/cli/operatorWizard.js +1 -7
- package/dist/cli/roleOptionOrder.js +27 -0
- package/dist/cli/roleWizard.js +50 -14
- package/dist/cli/updateOrchestrator.js +1 -1
- package/dist/cli/updatePorts.js +3 -4
- package/dist/cli.js +245 -95
- package/dist/commands/agentCommands.js +72 -14
- package/dist/commands/capabilityCommands.js +9 -6
- package/dist/commands/configCommands.js +20 -20
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/executionAuditCommands.js +24 -24
- package/dist/commands/globalRoleCommands.js +1 -1
- package/dist/commands/grantCommands.js +4 -4
- package/dist/commands/operatorCommands.js +34 -9
- package/dist/commands/projectCommands.js +4 -4
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/roleConfiguration.js +25 -5
- package/dist/commands/roleRuntimeGuard.js +4 -5
- package/dist/commands/sessionCommands.js +3 -7
- package/dist/commands/taskActivationCommands.js +281 -0
- package/dist/commands/taskActor.js +28 -49
- package/dist/commands/taskCommands.js +1461 -720
- package/dist/commands/taskContextCommand.js +39 -583
- package/dist/commands/taskExecutionCommands.js +32 -32
- package/dist/commands/taskInputCommands.js +40 -104
- package/dist/commands/taskIntegrationCommands.js +3 -2
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -8
- package/dist/commands/taskOverviewCommand.js +33 -45
- package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
- package/dist/commands/taskRoleRuntimeStatus.js +133 -102
- package/dist/commands/telemetryCommands.js +36 -38
- package/dist/config/configCatalog.js +4 -4
- package/dist/config/yuiConfig.js +8 -8
- package/dist/context/contextSnapshot.js +10 -10
- package/dist/context/dispatchContext.js +11 -11
- package/dist/context/roleSessionContext.js +6 -3
- package/dist/context/{turnContextPack.js → runContextPack.js} +158 -81
- package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
- package/dist/context/sessionBootstrapManifest.js +21 -2
- package/dist/context/sourceRunContext.js +30 -0
- package/dist/context/taskContext.js +481 -0
- package/dist/context/wakeNotification.js +27 -27
- package/dist/controller/agentRuntimeObserver.js +21 -24
- package/dist/controller/capabilityBridge.js +17 -6
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +120 -188
- package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
- package/dist/controller/jobControl.js +54 -85
- package/dist/controller/resourceInventory.js +8 -27
- package/dist/controller/resourceInventoryLinux.js +12 -13
- package/dist/controller/runtime.js +529 -479
- package/dist/controller/runtimeEventInbox.js +55 -25
- package/dist/controller/runtimeEventProcessor.js +22 -31
- package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
- package/dist/controller/runtimeLaunchCoordinator.js +80 -426
- package/dist/controller/runtimeObservationHook.js +14 -18
- package/dist/controller/sessionNotify.js +16 -24
- package/dist/controller/sessionOwnerReconciliation.js +168 -50
- package/dist/controller/structuredProviderObservation.js +138 -99
- package/dist/coordination/workMailbox.js +3 -3
- package/dist/coordination/workMailboxQueue.js +36 -33
- package/dist/core/boundedRpc.js +8 -1
- package/dist/core/controllerClient.js +20 -1
- package/dist/core/controllerServer.js +4 -4
- package/dist/doctor/doctor.js +13 -2
- package/dist/domain/agentResultTransport.js +9 -9
- package/dist/execution/codexThreadNaming.js +2 -8
- package/dist/execution/executionHealth.js +51 -63
- package/dist/execution/reviewMainRun.js +137 -0
- package/dist/execution/workItemExecution.js +28 -29
- package/dist/execution/workItemExecutionProjection.js +99 -107
- package/dist/execution/workItemMainRun.js +141 -0
- package/dist/executor/agentAdapter.js +227 -20
- package/dist/executor/agentConfigurationCatalog.js +126 -4
- package/dist/executor/agentConfigurationProbe.js +162 -4
- package/dist/executor/agentExecutor.js +79 -78
- package/dist/executor/effectiveLaunch.js +105 -18
- package/dist/executor/executorRegistry.js +29 -44
- package/dist/executor/fileRoleLaunchPlanner.js +229 -154
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +6 -3
- package/dist/input/inputRequest.js +12 -10
- package/dist/integration/gitIntegrationService.js +4 -11
- package/dist/integration/integrationQueueService.js +4 -4
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/kernel/builtinCapabilities.js +255 -12
- package/dist/kernel/capabilityRegistry.js +64 -18
- package/dist/kernel/instanceHost.js +12 -1
- package/dist/kernel/kernelPorts.js +2 -2
- package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
- package/dist/lifecycle/exactRunTerminalization.js +449 -0
- package/dist/message/message.js +118 -6
- package/dist/message/messageContinuation.js +204 -0
- package/dist/observability/executionAudit.js +70 -72
- package/dist/observability/faultClassification.js +2 -2
- package/dist/observability/orchestrationMetrics.js +8 -8
- package/dist/operator/operatorSessionHistory.js +1 -7
- package/dist/output/agentConfigurationPresentation.js +8 -3
- package/dist/output/agentRunConfigurationPresentation.js +128 -0
- package/dist/output/rolePresentation.js +54 -3
- package/dist/plugins/pluginChild.js +104 -0
- package/dist/plugins/pluginIntent.js +26 -0
- package/dist/plugins/pluginInterpreter.js +43 -0
- package/dist/plugins/pluginPackage.js +101 -0
- package/dist/plugins/pluginProcess.js +112 -0
- package/dist/plugins/pluginService.js +388 -0
- package/dist/profile/agentProfile.js +1 -1
- package/dist/repository/gitWorkspace.js +26 -4
- package/dist/repository/project.js +19 -4
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +20 -27
- package/dist/repository/taskWorkspacePreparer.js +344 -83
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +3 -3
- package/dist/resources/projectResource.js +75 -0
- package/dist/resources/projectResourceService.js +343 -0
- package/dist/resources/resourceDiscovery.js +6 -6
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/resourceRegistrar.js +1 -1
- package/dist/resources/resourceTypes.js +1 -1
- package/dist/review/deltaRecheck.js +3 -3
- package/dist/review/reviewAcceptance.js +16 -16
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewRound.js +21 -20
- package/dist/review/reviewerAvailability.js +2 -2
- package/dist/role/role.js +51 -7
- package/dist/role/taskRoleUpdate.js +30 -0
- package/dist/runtime/acpProtocol.js +425 -0
- package/dist/runtime/acpSession.js +731 -0
- package/dist/runtime/acpSessionConfiguration.js +260 -0
- package/dist/runtime/agentDriver.js +30 -11
- package/dist/runtime/agentEndpoint.js +278 -0
- package/dist/runtime/agentEndpointIdentity.js +86 -0
- package/dist/runtime/agentEndpointOwnership.js +239 -0
- package/dist/runtime/agentError.js +2 -10
- package/dist/runtime/agentHost.js +565 -314
- package/dist/runtime/agentRunConfiguration.js +258 -0
- package/dist/runtime/builtinAgentDrivers.js +134 -18
- package/dist/runtime/builtinAgentErrorMappers.js +55 -3
- package/dist/runtime/builtinTranscriptUsage.js +1 -1
- package/dist/runtime/claude-process-owner +0 -0
- package/dist/runtime/codexAppServerRuntime.js +38 -30
- package/dist/runtime/codexInteractiveHost.js +41 -6
- package/dist/runtime/continuationManager.js +2 -6
- package/dist/runtime/executionEnvironment.js +30 -0
- package/dist/runtime/firstProgressAdvisory.js +11 -11
- package/dist/runtime/index.js +4 -3
- package/dist/runtime/jsonLineChannel.js +109 -0
- package/dist/runtime/launchBroker.js +91 -16
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +10 -18
- package/dist/runtime/managedCaller.js +61 -17
- package/dist/runtime/nativeSessionControl.js +102 -0
- package/dist/runtime/ports.js +6 -21
- package/dist/runtime/processExitObservation.js +8 -7
- package/dist/runtime/promptEnvelope.js +17 -6
- package/dist/runtime/providerContinuation.js +3 -9
- package/dist/runtime/providerContinuationReconciliationService.js +4 -13
- package/dist/runtime/providerControl.js +2 -7
- package/dist/runtime/providerRuntimeIdentity.js +110 -222
- package/dist/runtime/providerRuntimeReconciler.js +5 -9
- package/dist/runtime/runtimeBinding.js +0 -1
- package/dist/runtime/runtimeContinuationProjection.js +4 -7
- package/dist/runtime/runtimeDeadlines.js +9 -0
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +29 -65
- package/dist/runtime/runtimeProjection.js +43 -51
- package/dist/runtime/runtimeSessionCandidate.js +1 -3
- package/dist/runtime/sessionLaunchRequest.js +3 -7
- package/dist/runtime/sessionOwnerIdentity.js +7 -54
- package/dist/runtime/sessionOwnerRegistry.js +22 -17
- package/dist/runtime/sessionReconciliation.js +4 -8
- package/dist/runtime/sessionTerminationGuard.js +70 -259
- package/dist/runtime/sessionTokenMetrics.js +5 -16
- package/dist/runtime/structuredProviderHost.js +237 -117
- package/dist/runtime/taskRuntimeIsolation.js +39 -122
- package/dist/runtime/tmuxAdapters.js +39 -86
- package/dist/scheduler/activeRoleRunDelivery.js +354 -0
- package/dist/scheduler/leaderWakeupProcessor.js +75 -266
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +80 -9
- package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
- package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
- package/dist/scheduler/taskExecutionProjection.js +120 -124
- package/dist/scheduler/taskObservabilityProjection.js +29 -29
- package/dist/scheduler/taskWake.js +11 -4
- package/dist/scheduler/wakeReason.js +9 -1
- package/dist/setup/setupCommand.js +3 -7
- package/dist/storage/migrations/agentRunContract.js +159 -0
- package/dist/storage/migrations/artifactsToGit.js +338 -0
- package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
- package/dist/storage/migrations/submitIntent.js +126 -0
- package/dist/storage/sqliteSchema.js +467 -7
- package/dist/storage/sqliteStore.js +355 -220
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +10 -5
- package/dist/storage/taskStore.js +13 -11
- package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
- package/dist/surface/surfaceContributions.js +102 -0
- package/dist/task/completionReadiness.js +32 -6
- package/dist/task/deliveryGuard.js +16 -16
- package/dist/task/draftPlan.js +72 -12
- package/dist/task/nextAction.js +144 -128
- package/dist/task/remoteDelivery.js +6 -6
- package/dist/task/task.js +184 -18
- package/dist/task/taskActivation.js +327 -0
- package/dist/task/taskActivationService.js +408 -0
- package/dist/task/taskRecordReference.js +5 -4
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/task/taskSubmission.js +236 -0
- package/dist/telemetry/sqliteTelemetryStore.js +55 -68
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +2 -2
- package/dist/web/assets/assetManifest.js +2 -0
- package/dist/web/assets/client/app.js +121 -20
- package/dist/web/assets/client/components.js +87 -54
- package/dist/web/assets/client/i18n.js +83 -41
- package/dist/web/assets/client/markdown.js +1 -1
- package/dist/web/assets/client/taskSurface.js +442 -0
- package/dist/web/assets/client/view.js +49 -44
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +22 -4
- package/dist/web/controllerWeb.js +60 -0
- package/dist/web/webMutation.js +28 -0
- package/dist/web/webServer.js +133 -8
- package/dist/web/webSnapshot.js +81 -74
- package/dist/web/webTaskSurface.js +64 -0
- package/dist/workItem/dependencyGate.js +1 -1
- package/dist/workItem/workItem.js +84 -48
- package/dist/workspace/workItemChangeSetManager.js +16 -9
- package/docs/agent-result-consumption.md +96 -0
- package/docs/agent-result-consumption.zh-CN.md +81 -0
- package/docs/agent-runtime-drivers.md +93 -0
- package/docs/agent-runtime-drivers.zh-CN.md +77 -0
- package/docs/architecture/README.md +50 -0
- package/docs/architecture/README.zh-CN.md +43 -0
- package/docs/architecture/capabilities-and-resources.md +118 -0
- package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
- package/docs/managed-turn-and-session-runtime.md +224 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
- package/docs/observability/README.md +83 -0
- package/docs/observability/README.zh-CN.md +71 -0
- package/docs/plugin-sdk.md +393 -0
- package/docs/plugin-sdk.zh-CN.md +293 -0
- package/docs/provider-runtime.md +165 -0
- package/docs/provider-runtime.zh-CN.md +132 -0
- package/docs/release-workflow.md +305 -0
- package/docs/release-workflow.zh-CN.md +237 -0
- package/docs/roles-and-configuration.md +115 -0
- package/docs/roles-and-configuration.zh-CN.md +96 -0
- package/docs/sqlite-control-plane-design.md +78 -0
- package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
- package/docs/task-dag-semantics.md +80 -0
- package/docs/task-dag-semantics.zh-CN.md +59 -0
- package/docs/task-delivery.md +105 -0
- package/docs/task-delivery.zh-CN.md +82 -0
- package/docs/task-local-identity.md +8 -6
- package/docs/task-local-identity.zh-CN.md +58 -0
- package/docs/testing/verification-levels.md +88 -0
- package/docs/testing/verification-levels.zh-CN.md +69 -0
- package/i18n/README.zh-CN.md +270 -722
- package/package.json +3 -2
- package/skills/yui-leader/SKILL.md +88 -304
- package/skills/yui-leader/references/execution.md +303 -0
- package/skills/yui-leader/references/integration.md +39 -0
- package/skills/yui-leader/references/planning.md +109 -0
- package/skills/yui-leader/references/replicated-execution.md +42 -0
- package/skills/yui-leader/references/task-plugins.md +37 -0
- package/skills/yui-operator/SKILL.md +46 -62
- package/skills/yui-reviewer/SKILL.md +35 -36
- package/skills/yui-runtime/SKILL.md +88 -24
- package/skills/yui-runtime/references/publication.md +22 -0
- package/skills/yui-runtime/references/recovery.md +64 -0
- package/skills/yui-worker/SKILL.md +37 -39
- package/dist/cli/roleOptionCatalog.js +0 -68
- package/dist/context/sourceTurnContext.js +0 -30
- package/dist/execution/reviewMainTurn.js +0 -161
- package/dist/execution/workItemMainTurn.js +0 -164
- package/dist/lifecycle/exactTurnTerminalization.js +0 -407
- package/dist/runtime/preallocatedNativeSession.js +0 -13
- package/dist/runtime/runtimeStopReceipt.js +0 -42
- package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { reconciliationIntervalMilliseconds } from "../config/yuiConfig.js";
|
|
2
|
-
import { LEADER_WAKE_AGGREGATION_MS,
|
|
2
|
+
import { LEADER_WAKE_AGGREGATION_MS, processLeaderWakeups } from "../scheduler/leaderWakeupProcessor.js";
|
|
3
3
|
import { pendingWakeupsMatch } from "../scheduler/pendingWakeup.js";
|
|
4
|
-
import {
|
|
4
|
+
import { processActiveRoleRunDeliveries } from "../scheduler/activeRoleRunDelivery.js";
|
|
5
5
|
import { selectedActiveSchedulerTasks } from "../scheduler/ports.js";
|
|
6
|
-
import {
|
|
7
|
-
import { DEFAULT_STALL_WINDOW_MS, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS,
|
|
6
|
+
import { reconcileExitedRoleRuns } from "../scheduler/roleRunLiveness.js";
|
|
7
|
+
import { DEFAULT_STALL_WINDOW_MS, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, reconcileStalledRoleRuns } from "../scheduler/roleRunStall.js";
|
|
8
8
|
import { processOperatorInputNotifications } from "../scheduler/operatorInputNotificationProcessor.js";
|
|
9
9
|
import { startControllerServer } from "../core/controllerServer.js";
|
|
10
10
|
import { monotonicMilliseconds } from "../core/controllerTelemetry.js";
|
|
@@ -14,8 +14,9 @@ import { KeyedWorkQueue } from "../coordination/keyedWorkQueue.js";
|
|
|
14
14
|
import { MailboxScheduler } from "../coordination/mailboxScheduler.js";
|
|
15
15
|
import { nearestDeadlineBatch } from "../coordination/deadlineScheduler.js";
|
|
16
16
|
import { mailboxHasWork, nextPendingBatch } from "../coordination/workMailbox.js";
|
|
17
|
-
import { hasRuntimeCleanupObligation
|
|
17
|
+
import { hasRuntimeCleanupObligation } from "../runtime/lifecycleReservation.js";
|
|
18
18
|
import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
19
|
+
import { activationRequestIsControllerAdoptable } from "../task/taskActivation.js";
|
|
19
20
|
import { parseDurableJobAcknowledgeParams, parseDurableJobCancelParams, parseDurableJobRefParams, parseDurableJobStartParams } from "./jobControl.js";
|
|
20
21
|
const DEFAULT_RECONCILIATION_INTERVAL_MS = reconciliationIntervalMilliseconds();
|
|
21
22
|
const DEFAULT_SIGNAL_WINDOW_MS = 100;
|
|
@@ -26,7 +27,6 @@ const DEFAULT_DELIVERY_TIMEOUT_MS = 120_000;
|
|
|
26
27
|
const DEFAULT_TASK_ORCHESTRATION_RETRY_LIMIT = 2;
|
|
27
28
|
const DEFAULT_TASK_CONCURRENCY = 4;
|
|
28
29
|
const MAX_TASK_CONCURRENCY = 32;
|
|
29
|
-
const RUNTIME_RESERVATION_RECOVERY_AGE_MS = 120_000;
|
|
30
30
|
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
31
31
|
const CONTROLLER_LATENCY_BUCKETS_MS = [10, 50, 100, 250, 500, 1_000, 3_000];
|
|
32
32
|
class RuntimeEventApplyError extends AggregateError {
|
|
@@ -45,7 +45,7 @@ const ZERO_DRAIN_METRICS = Object.freeze({
|
|
|
45
45
|
* Runs one lean scheduler pass. Due native Turn completions are folded before
|
|
46
46
|
* liveness, so a valid Hook boundary fences destructive process reconciliation.
|
|
47
47
|
*/
|
|
48
|
-
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS, maintenanceFence, onMaintenanceFenceDefer, blockedTaskIds = new Set(), diagnosticAfterMs = DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, leaderWakeFence) {
|
|
48
|
+
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS, maintenanceFence, onMaintenanceFenceDefer, blockedTaskIds = new Set(), diagnosticAfterMs = DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, leaderWakeFence, onError) {
|
|
49
49
|
const compiledSelection = compileReconcileSelection(scope);
|
|
50
50
|
const selection = includeOperator
|
|
51
51
|
? { ...compiledSelection, blockedTaskIds }
|
|
@@ -54,12 +54,7 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
54
54
|
// control sockets when several scheduler phases repeat it in one native
|
|
55
55
|
// event-loop turn. Give already-written requests a poll boundary before the
|
|
56
56
|
// next durable phase; later phases retain their existing CAS fences.
|
|
57
|
-
await
|
|
58
|
-
// A dormant Session may still name a Host that disappeared after its last
|
|
59
|
-
// Provider Turn. Detach that disposable Host before claiming the next Turn,
|
|
60
|
-
// so retained Agent intent restores the same Session instead of first
|
|
61
|
-
// connecting to a known-dead control socket.
|
|
62
|
-
await reconcileDormantRuntimeOwners(store, delivery, lifecycleHost, scope, now, blockedTaskIds);
|
|
57
|
+
await controlEventLoopRun();
|
|
63
58
|
const failedCleanupRoles = await processSelectedRoleRuntimeCleanups(store, delivery, lifecycleHost, scope, now, runtimeCleanupOutcomes, blockedTaskIds);
|
|
64
59
|
const roleSelection = selectionWithoutFailedCleanupRoles(store, selection, failedCleanupRoles);
|
|
65
60
|
const availableWakeupSelection = () => (leaderWakeFence?.() === true
|
|
@@ -74,13 +69,18 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
74
69
|
const initialWakeupResults = await processLeaderWakeups(store, delivery, now, exactTaskSelection(new Set(initialWakeups.keys())));
|
|
75
70
|
// Preserve ready-Leader-first ordering, then bound the repeated state
|
|
76
71
|
// projections that follow it in this pass.
|
|
77
|
-
await
|
|
72
|
+
await controlEventLoopRun();
|
|
73
|
+
// A Task whose deferred activation was just released must become active
|
|
74
|
+
// before the workspace phase, so its first workspace preparation happens in
|
|
75
|
+
// this same pass rather than waiting for the next one.
|
|
76
|
+
await adoptReleasedTaskActivations(store, workspacePreparer, selection, onError);
|
|
77
|
+
await controlEventLoopRun();
|
|
78
78
|
const workspacePreparation = await prepareActiveWorkspaces(store, workspacePreparer, selection, maintenanceFence, onMaintenanceFenceDefer);
|
|
79
|
-
await
|
|
80
|
-
const
|
|
81
|
-
await
|
|
82
|
-
const
|
|
83
|
-
? [formatTaskRecordReference(result.taskId, result.
|
|
79
|
+
await controlEventLoopRun();
|
|
80
|
+
const activeRunDeliveries = await processActiveRoleRunDeliveries(store, delivery, now, roleSelection);
|
|
81
|
+
await controlEventLoopRun();
|
|
82
|
+
const unsettledRunRefs = new Set(activeRunDeliveries.flatMap((result) => (result.reason === "delivery-uncertain"
|
|
83
|
+
? [formatTaskRecordReference(result.taskId, result.runId, "run")]
|
|
84
84
|
: [])));
|
|
85
85
|
// Every successful Task has completed the targeted phases owned by its
|
|
86
86
|
// mailbox at this boundary. Settle that exact claim before advisory
|
|
@@ -92,28 +92,27 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
const newlyIdleBusyTaskIds = new Set(initialWakeupResults.flatMap((result) => (result.reason === "busy"
|
|
95
|
-
&& store.
|
|
95
|
+
&& store.getActiveRun(result.taskId, "leader") === null
|
|
96
96
|
? [result.taskId]
|
|
97
97
|
: [])));
|
|
98
|
-
// Phase-one Leader
|
|
99
|
-
// Keep every newly claimed
|
|
100
|
-
// a later pass can observe its stable provider/runtime
|
|
98
|
+
// Phase-one Leader AgentRuns did not exist at the pass's liveness boundary.
|
|
99
|
+
// Keep every newly claimed AgentRun outside destructive absence decisions until
|
|
100
|
+
// a later pass can observe its stable provider/runtime.
|
|
101
101
|
for (const result of initialWakeupResults) {
|
|
102
|
-
if (result.
|
|
103
|
-
&& store.
|
|
104
|
-
|
|
102
|
+
if (result.runId !== undefined
|
|
103
|
+
&& store.getActiveRun(result.taskId, "leader")?.id === result.runId) {
|
|
104
|
+
unsettledRunRefs.add(formatTaskRecordReference(result.taskId, result.runId, "run"));
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
// Let socket callbacks queued during the bounded scheduler phases run
|
|
108
108
|
// before starting a potentially large liveness inventory.
|
|
109
|
-
await
|
|
109
|
+
await controlEventLoopRun();
|
|
110
110
|
const liveStatuses = new Map();
|
|
111
111
|
const resourceEvidence = new Map();
|
|
112
|
-
const
|
|
113
|
-
await
|
|
114
|
-
await
|
|
115
|
-
await
|
|
116
|
-
await reconcileDormantRuntimeOwners(store, delivery, lifecycleHost, scope, now, selection.blockedTaskIds);
|
|
112
|
+
const failedRunRefs = await reconcileExitedRoleRuns(store, delivery, now, roleSelection, unsettledRunRefs, liveStatuses, resourceEvidence, scope.kind === "dirty");
|
|
113
|
+
await controlEventLoopRun();
|
|
114
|
+
await reconcileStalledRoleRuns(store, delivery, now, roleSelection, stallWindowMs, liveStatuses, resourceEvidence, diagnosticAfterMs);
|
|
115
|
+
await controlEventLoopRun();
|
|
117
116
|
const selectedInputTaskIds = selectedTaskIdsForBoundedPass(store, selection);
|
|
118
117
|
const autoResolvedInputs = selectedInputTaskIds === undefined
|
|
119
118
|
? store.resolveExpiredInputRecommendations(now)
|
|
@@ -148,8 +147,8 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
148
147
|
? await processOperatorInputNotifications(store, delivery, selection, now)
|
|
149
148
|
: [];
|
|
150
149
|
return {
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
activeRunDeliveries,
|
|
151
|
+
failedRunRefs,
|
|
153
152
|
wakeups: mergeWakeupPhaseResults(initialWakeupResults, laterWakeups),
|
|
154
153
|
inputNotifications,
|
|
155
154
|
autoResolvedInputs
|
|
@@ -218,34 +217,6 @@ async function processSelectedRoleRuntimeCleanups(store, delivery, lifecycleHost
|
|
|
218
217
|
if (!await lifecycleHost.stopOwner(owner)) {
|
|
219
218
|
throw new Error(`Role runtime cleanup could not confirm the host stopped: ${runtimeOwnerLabel(owner)}.`);
|
|
220
219
|
}
|
|
221
|
-
if (target.kind === "role-runtime") {
|
|
222
|
-
const session = store.getRoleSession(target.taskId, target.roleName);
|
|
223
|
-
const reservedRuntimeGenerationId = isRuntimeLaunchReservation(mailbox.processing)
|
|
224
|
-
? mailbox.processing.batchId
|
|
225
|
-
: undefined;
|
|
226
|
-
// A failed fresh-Conversation launch can leave two exact resource
|
|
227
|
-
// generations: the detached Session's last committed launch and the
|
|
228
|
-
// replacement reservation. They are not competing authorities. The
|
|
229
|
-
// owner-wide stop has already proven physical zero, so clean both
|
|
230
|
-
// exact launch roots idempotently before settling the mailbox.
|
|
231
|
-
const runtimeGenerationIds = new Set([
|
|
232
|
-
reservedRuntimeGenerationId,
|
|
233
|
-
session?.runtimeGenerationId
|
|
234
|
-
].filter((runtimeGenerationId) => runtimeGenerationId !== undefined));
|
|
235
|
-
if (lifecycleHost.cleanupTaskLaunch !== undefined) {
|
|
236
|
-
const task = store.getTask(target.taskId);
|
|
237
|
-
const reason = task?.status === "completed"
|
|
238
|
-
? "completion"
|
|
239
|
-
: "interruption";
|
|
240
|
-
for (const runtimeGenerationId of runtimeGenerationIds) {
|
|
241
|
-
lifecycleHost.cleanupTaskLaunch({
|
|
242
|
-
taskId: target.taskId,
|
|
243
|
-
runtimeGenerationId,
|
|
244
|
-
reason
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
220
|
if (store.completeRuntimeCleanup === undefined
|
|
250
221
|
|| !store.completeRuntimeCleanup(target, now)) {
|
|
251
222
|
throw new Error(`Role runtime cleanup mailbox changed: ${runtimeOwnerLabel(owner)}.`);
|
|
@@ -259,95 +230,9 @@ async function processSelectedRoleRuntimeCleanups(store, delivery, lifecycleHost
|
|
|
259
230
|
}
|
|
260
231
|
continue;
|
|
261
232
|
}
|
|
262
|
-
const reservation = mailbox.processing;
|
|
263
|
-
if (reservation === null
|
|
264
|
-
|| !isRuntimeLaunchReservation(reservation)
|
|
265
|
-
|| now.getTime() - Date.parse(reservation.startedAt)
|
|
266
|
-
< RUNTIME_RESERVATION_RECOVERY_AGE_MS) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
if (lifecycleHost === undefined) {
|
|
271
|
-
throw new Error("Role runtime reservation inspection is unavailable.");
|
|
272
|
-
}
|
|
273
|
-
const inspection = await lifecycleHost.inspectOwner(owner);
|
|
274
|
-
if (inspection.state === "running" || inspection.state === "starting") {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (inspection.state === "unavailable") {
|
|
278
|
-
throw new Error(`Role runtime reservation could not inspect the host: ${runtimeOwnerLabel(owner)}.`);
|
|
279
|
-
}
|
|
280
|
-
const completed = store.completeStoppedRuntimeReservation === undefined
|
|
281
|
-
? store.completeWorkMailbox(target, reservation.batchId)
|
|
282
|
-
: store.completeStoppedRuntimeReservation(target, reservation.batchId, now);
|
|
283
|
-
if (!completed) {
|
|
284
|
-
throw new Error(`Role runtime reservation mailbox changed: ${runtimeOwnerLabel(owner)}.`);
|
|
285
|
-
}
|
|
286
|
-
forgetPreparedRuntimeOwner(delivery, owner);
|
|
287
|
-
outcomes.push({ target, batchId, status: "completed" });
|
|
288
|
-
}
|
|
289
|
-
catch (error) {
|
|
290
|
-
markFailedRuntimeTarget(failedRoles, target);
|
|
291
|
-
outcomes.push({ target, batchId, status: "failed", error });
|
|
292
|
-
}
|
|
293
233
|
}
|
|
294
234
|
return failedRoles;
|
|
295
235
|
}
|
|
296
|
-
async function reconcileDormantRuntimeOwners(store, delivery, lifecycleHost, scope, now, blockedTaskIds = new Set()) {
|
|
297
|
-
if (lifecycleHost === undefined
|
|
298
|
-
|| store.listDormantRuntimeOwners === undefined) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
const selectedOwners = scope.kind === "full"
|
|
302
|
-
? undefined
|
|
303
|
-
: new Set(selectedRuntimeLifecycleTargets(store, scope, blockedTaskIds)
|
|
304
|
-
.map((target) => runtimeOwnerIdentity(runtimeOwner(target))));
|
|
305
|
-
const candidates = store.listDormantRuntimeOwners().filter((candidate) => ((candidate.owner.scope !== "task"
|
|
306
|
-
|| !blockedTaskIds.has(candidate.owner.taskId))
|
|
307
|
-
&& (selectedOwners === undefined
|
|
308
|
-
|| selectedOwners.has(runtimeOwnerIdentity(candidate.owner)))));
|
|
309
|
-
if (candidates.length === 0)
|
|
310
|
-
return;
|
|
311
|
-
const owners = candidates.map((candidate) => candidate.owner);
|
|
312
|
-
let inspections;
|
|
313
|
-
try {
|
|
314
|
-
inspections = lifecycleHost.inspectOwners === undefined
|
|
315
|
-
? await Promise.all(owners.map(async (owner) => ({
|
|
316
|
-
owner,
|
|
317
|
-
inspection: await lifecycleHost.inspectOwner(owner)
|
|
318
|
-
})))
|
|
319
|
-
: await lifecycleHost.inspectOwners(owners);
|
|
320
|
-
}
|
|
321
|
-
catch {
|
|
322
|
-
// Host inventory is an advisory safety scan. Unknown state must never
|
|
323
|
-
// mutate persisted session facts; the next full pass will retry.
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
const requested = new Set(owners.map(runtimeOwnerIdentity));
|
|
327
|
-
const byOwner = new Map();
|
|
328
|
-
for (const result of inspections) {
|
|
329
|
-
const identity = runtimeOwnerIdentity(result.owner);
|
|
330
|
-
if (!requested.has(identity)
|
|
331
|
-
|| byOwner.has(identity)) {
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
byOwner.set(identity, result.inspection);
|
|
335
|
-
}
|
|
336
|
-
if (byOwner.size !== requested.size)
|
|
337
|
-
return;
|
|
338
|
-
for (const candidate of candidates) {
|
|
339
|
-
if (byOwner.get(runtimeOwnerIdentity(candidate.owner))?.state
|
|
340
|
-
=== "stopped") {
|
|
341
|
-
if (candidate.runtimeGenerationId !== undefined) {
|
|
342
|
-
// The exact launch-owned resources must settle through the durable
|
|
343
|
-
// cleanup lane before its Host fact is detached. The resumable Session
|
|
344
|
-
// remains active; the candidate is the CAS fence against a concurrent
|
|
345
|
-
// Hook or replacement launch.
|
|
346
|
-
store.enqueueRuntimeHostDetach?.(candidate.owner, now, candidate);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
236
|
function forgetPreparedRuntimeOwner(delivery, owner) {
|
|
352
237
|
if (owner.scope !== "task")
|
|
353
238
|
return;
|
|
@@ -356,11 +241,6 @@ function forgetPreparedRuntimeOwner(delivery, owner) {
|
|
|
356
241
|
roleName: owner.roleName
|
|
357
242
|
});
|
|
358
243
|
}
|
|
359
|
-
function runtimeOwnerIdentity(owner) {
|
|
360
|
-
return owner.scope === "task"
|
|
361
|
-
? `task\0${owner.taskId}\0${owner.roleName}`
|
|
362
|
-
: `global\0${owner.roleName}`;
|
|
363
|
-
}
|
|
364
244
|
function selectedTaskIdsForBoundedPass(store, selection) {
|
|
365
245
|
if (!selection.full) {
|
|
366
246
|
if ((selection.blockedTaskIds?.size ?? 0) === 0)
|
|
@@ -575,6 +455,67 @@ export function compileReconcileSelection(scope) {
|
|
|
575
455
|
blockedTaskIds: new Set()
|
|
576
456
|
};
|
|
577
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* Adopts activation requests whose deferral has been released.
|
|
460
|
+
*
|
|
461
|
+
* The deferral is only ever released by the planning Turn ending, so this phase
|
|
462
|
+
* re-reads the request instead of trusting the signal that woke it: a request
|
|
463
|
+
* cancelled, or a Task retired or stopped, while the Turn was still running is
|
|
464
|
+
* left alone rather than replayed as historical intent. Adoption itself belongs
|
|
465
|
+
* to the preparer's single activation boundary, so status and environment facts
|
|
466
|
+
* still commit together, and a failure here leaves a continuable Draft.
|
|
467
|
+
*
|
|
468
|
+
* Full reconciliation resolves the candidates from the durable pending-request
|
|
469
|
+
* projection rather than from dirty keys. A Controller that restarts after the
|
|
470
|
+
* releasing signal was enqueued has no dirty key for it, and the startup pass
|
|
471
|
+
* claims and completes that Task's mailbox — so without the projection a
|
|
472
|
+
* released request would wait for unrelated traffic on the Task.
|
|
473
|
+
*/
|
|
474
|
+
async function adoptReleasedTaskActivations(store, workspace, selection, onError) {
|
|
475
|
+
if (workspace === undefined)
|
|
476
|
+
return;
|
|
477
|
+
const candidates = selection.full
|
|
478
|
+
? (store.listPendingActivationRequestTaskIds?.()
|
|
479
|
+
?? store.listTasks().flatMap((task) => (task.status === "draft" && task.activationRequest?.disposition === "pending"
|
|
480
|
+
? [task.id]
|
|
481
|
+
: [])))
|
|
482
|
+
: selection.taskIds;
|
|
483
|
+
for (const taskId of candidates) {
|
|
484
|
+
if (selection.blockedTaskIds?.has(taskId))
|
|
485
|
+
continue;
|
|
486
|
+
const task = store.getTask(taskId);
|
|
487
|
+
if (task?.status !== "draft" || task.executionGate.state !== "enabled")
|
|
488
|
+
continue;
|
|
489
|
+
const request = task.activationRequest;
|
|
490
|
+
if (request?.disposition !== "pending")
|
|
491
|
+
continue;
|
|
492
|
+
// Continue only requests with a provable source: a released deferral, or an
|
|
493
|
+
// immediate request carrying a recognised origin (explicit action, or a
|
|
494
|
+
// develop submission accepted while unplanned). This admits legal
|
|
495
|
+
// Operator/user immediate requests the old actor filter dropped, while
|
|
496
|
+
// still refusing origin-less historical requests, which stay behind the
|
|
497
|
+
// explicit `yui task activate` boundary.
|
|
498
|
+
if (!activationRequestIsControllerAdoptable(request))
|
|
499
|
+
continue;
|
|
500
|
+
// Later Draft discussion is a Session notification, not another AgentRun.
|
|
501
|
+
// Its durable activation intent is sufficient once the exact native input
|
|
502
|
+
// is settled. Never create a synthetic Run merely to release that intent.
|
|
503
|
+
if (store.getActiveRun(taskId, "leader") !== null)
|
|
504
|
+
continue;
|
|
505
|
+
const provider = store.getTaskRoleSessionSet?.(taskId, "leader")?.providerBinding;
|
|
506
|
+
if (provider?.run != null
|
|
507
|
+
&& ["submitting", "accepted", "delivery-unknown"].includes(provider.run.status))
|
|
508
|
+
continue;
|
|
509
|
+
try {
|
|
510
|
+
await workspace.activateTaskWorkspace(taskId);
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
// Activation failure is durable Task state, not a Controller fault: the
|
|
514
|
+
// request records it and the Draft stays continuable.
|
|
515
|
+
onError?.(error);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
578
519
|
async function prepareActiveWorkspaces(store, workspace, selection, maintenanceFence, onMaintenanceFenceDefer) {
|
|
579
520
|
if (workspace === undefined)
|
|
580
521
|
return { failed: new Set(), ready: new Set() };
|
|
@@ -689,8 +630,8 @@ function partitionDirtyScope(keys) {
|
|
|
689
630
|
}
|
|
690
631
|
function emptyControllerSchedulerResult() {
|
|
691
632
|
return {
|
|
692
|
-
|
|
693
|
-
|
|
633
|
+
activeRunDeliveries: [],
|
|
634
|
+
failedRunRefs: [],
|
|
694
635
|
wakeups: [],
|
|
695
636
|
inputNotifications: [],
|
|
696
637
|
autoResolvedInputs: []
|
|
@@ -707,8 +648,8 @@ function runtimeTaskFailureIds(result) {
|
|
|
707
648
|
}
|
|
708
649
|
function mergeControllerSchedulerResults(results) {
|
|
709
650
|
return {
|
|
710
|
-
|
|
711
|
-
|
|
651
|
+
activeRunDeliveries: results.flatMap((result) => result.activeRunDeliveries),
|
|
652
|
+
failedRunRefs: results.flatMap((result) => result.failedRunRefs),
|
|
712
653
|
wakeups: results.flatMap((result) => result.wakeups),
|
|
713
654
|
inputNotifications: results.flatMap((result) => result.inputNotifications),
|
|
714
655
|
autoResolvedInputs: results.flatMap((result) => result.autoResolvedInputs)
|
|
@@ -791,8 +732,8 @@ export class FileTaskController {
|
|
|
791
732
|
: this.#deliveryRetryLimit;
|
|
792
733
|
this.#taskOrchestrationRetryLimit = positiveInteger(options.taskOrchestrationRetryLimit, DEFAULT_TASK_ORCHESTRATION_RETRY_LIMIT, "Controller Task orchestration retry limit");
|
|
793
734
|
this.#taskConcurrency = boundedPositiveInteger(options.taskConcurrency, DEFAULT_TASK_CONCURRENCY, MAX_TASK_CONCURRENCY, "Controller Task concurrency");
|
|
794
|
-
this.#stallWindowMs = positiveInteger(options.stallWindowMs, DEFAULT_STALL_WINDOW_MS, "Controller
|
|
795
|
-
this.#diagnosticAfterMs = positiveInteger(options.diagnosticAfterMs, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, "Controller
|
|
735
|
+
this.#stallWindowMs = positiveInteger(options.stallWindowMs, DEFAULT_STALL_WINDOW_MS, "Controller AgentRun stall window");
|
|
736
|
+
this.#diagnosticAfterMs = positiveInteger(options.diagnosticAfterMs, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, "Controller AgentRun diagnostic threshold");
|
|
796
737
|
this.#runtimeEventProcessor = options.runtimeEventProcessor;
|
|
797
738
|
this.#runtimeObserver = options.runtimeObserver;
|
|
798
739
|
this.#runtimeObserverIntervalMs = positiveInteger(options.runtimeObserverIntervalMs, DEFAULT_RUNTIME_OBSERVER_INTERVAL_MS, "Controller runtime observer interval");
|
|
@@ -1050,7 +991,7 @@ export class FileTaskController {
|
|
|
1050
991
|
}
|
|
1051
992
|
// Detached reconciliation is deliberately confined to the low-rate
|
|
1052
993
|
// full pass. It queries only identities already present in Task
|
|
1053
|
-
// facts and cannot start a model
|
|
994
|
+
// facts and cannot start a model AgentRun or scan unknown children.
|
|
1054
995
|
if (scope.kind === "full" && this.#continuationReconciler !== undefined) {
|
|
1055
996
|
await this.#continuationReconciler.reconcile(this.#now());
|
|
1056
997
|
}
|
|
@@ -1059,7 +1000,7 @@ export class FileTaskController {
|
|
|
1059
1000
|
// processes Leader wakeups.
|
|
1060
1001
|
this.#jobSupervisor?.reconcile(this.#now());
|
|
1061
1002
|
if (scope.kind === "full") {
|
|
1062
|
-
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, runtimeFailedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence);
|
|
1003
|
+
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, runtimeFailedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence, this.#onError);
|
|
1063
1004
|
}
|
|
1064
1005
|
else {
|
|
1065
1006
|
const dirtyPass = await this.#runDirtySchedulerPass(scope, runtimeCleanupOutcomes, runtimeFailedTaskIds);
|
|
@@ -1144,7 +1085,7 @@ export class FileTaskController {
|
|
|
1144
1085
|
if (this.#pendingFull || this.#pendingKeys.size > 0 || pendingRuntimeDrain) {
|
|
1145
1086
|
// A continuous Hook signal stream must yield to socket callbacks
|
|
1146
1087
|
// between bounded scheduler passes.
|
|
1147
|
-
await
|
|
1088
|
+
await eventLoopRun();
|
|
1148
1089
|
}
|
|
1149
1090
|
}
|
|
1150
1091
|
return result;
|
|
@@ -1159,7 +1100,7 @@ export class FileTaskController {
|
|
|
1159
1100
|
const taskScopes = partition.taskScopes.filter((taskScope) => (!blockedTaskIds.has(taskScope.taskId)));
|
|
1160
1101
|
const orderedResults = [];
|
|
1161
1102
|
if (partition.globalKeys.length > 0) {
|
|
1162
|
-
orderedResults.push(await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: partition.globalKeys }, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence));
|
|
1103
|
+
orderedResults.push(await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: partition.globalKeys }, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence, this.#onError));
|
|
1163
1104
|
}
|
|
1164
1105
|
if (taskScopes.length === 0
|
|
1165
1106
|
|| this.#stopped
|
|
@@ -1192,7 +1133,7 @@ export class FileTaskController {
|
|
|
1192
1133
|
if (this.#stopped || this.#pendingFull)
|
|
1193
1134
|
continue;
|
|
1194
1135
|
try {
|
|
1195
|
-
taskResults[selected.index] = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: selected.taskScope.keys }, false, taskCleanupOutcomes[selected.index], this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence);
|
|
1136
|
+
taskResults[selected.index] = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: selected.taskScope.keys }, false, taskCleanupOutcomes[selected.index], this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence, this.#onError);
|
|
1196
1137
|
this.#clearTaskPassRetry(selected.taskScope.taskId);
|
|
1197
1138
|
}
|
|
1198
1139
|
catch (error) {
|
|
@@ -1424,13 +1365,7 @@ export class FileTaskController {
|
|
|
1424
1365
|
at: aggregationAt
|
|
1425
1366
|
}];
|
|
1426
1367
|
}
|
|
1427
|
-
|
|
1428
|
-
return forceAt > now && this.store.getActiveTurn(wakeup.taskId, "leader") !== null
|
|
1429
|
-
? [{
|
|
1430
|
-
key: `role:${encodeURIComponent(wakeup.taskId)}/leader`,
|
|
1431
|
-
at: forceAt
|
|
1432
|
-
}]
|
|
1433
|
-
: [];
|
|
1368
|
+
return [];
|
|
1434
1369
|
});
|
|
1435
1370
|
const nearest = nearestDeadlineBatch(deadlines);
|
|
1436
1371
|
if (nearest === null)
|
|
@@ -1449,7 +1384,7 @@ export class FileTaskController {
|
|
|
1449
1384
|
const settled = new Set();
|
|
1450
1385
|
const writerBlocked = new Set();
|
|
1451
1386
|
const resignal = new Set();
|
|
1452
|
-
for (const delivery of result.
|
|
1387
|
+
for (const delivery of result.activeRunDeliveries) {
|
|
1453
1388
|
const key = `role:${encodeURIComponent(delivery.taskId)}/${encodeURIComponent(delivery.roleName)}`;
|
|
1454
1389
|
if (delivery.terminalized === true) {
|
|
1455
1390
|
settled.add(key);
|
|
@@ -1459,7 +1394,7 @@ export class FileTaskController {
|
|
|
1459
1394
|
writerBlocked.add(key);
|
|
1460
1395
|
else if (delivery.reason === "not-ready"
|
|
1461
1396
|
|| delivery.reason === "runtime-unavailable") {
|
|
1462
|
-
retry.set(key, { identity: delivery.
|
|
1397
|
+
retry.set(key, { identity: delivery.runId });
|
|
1463
1398
|
}
|
|
1464
1399
|
else if (delivery.status === "delivered" || delivery.status === "already-delivered")
|
|
1465
1400
|
settled.add(key);
|
|
@@ -1467,8 +1402,8 @@ export class FileTaskController {
|
|
|
1467
1402
|
for (const wakeup of result.wakeups) {
|
|
1468
1403
|
const key = `role:${encodeURIComponent(wakeup.taskId)}/leader`;
|
|
1469
1404
|
if (wakeup.reason === "not-ready"
|
|
1470
|
-
|| (wakeup.reason === "busy" && wakeup.
|
|
1471
|
-
retry.set(key, { identity: wakeup.
|
|
1405
|
+
|| (wakeup.reason === "busy" && wakeup.runId !== undefined)) {
|
|
1406
|
+
retry.set(key, { identity: wakeup.runId ?? key });
|
|
1472
1407
|
}
|
|
1473
1408
|
else if (wakeup.status === "dispatched")
|
|
1474
1409
|
settled.add(key);
|
|
@@ -1575,9 +1510,9 @@ export class FileTaskController {
|
|
|
1575
1510
|
timer.unref();
|
|
1576
1511
|
this.#deliveryRetryTimers.set(key, timer);
|
|
1577
1512
|
}
|
|
1578
|
-
#terminalizePreparedAfterRetryExhaustion(key,
|
|
1513
|
+
#terminalizePreparedAfterRetryExhaustion(key, runId, failure) {
|
|
1579
1514
|
if (!key.startsWith("role:")
|
|
1580
|
-
||
|
|
1515
|
+
|| runId.startsWith("runtime-cleanup:")
|
|
1581
1516
|
|| failure === undefined) {
|
|
1582
1517
|
return;
|
|
1583
1518
|
}
|
|
@@ -1586,10 +1521,10 @@ export class FileTaskController {
|
|
|
1586
1521
|
return;
|
|
1587
1522
|
if (target.taskId !== failure.taskId
|
|
1588
1523
|
|| target.roleName !== failure.roleName
|
|
1589
|
-
||
|
|
1590
|
-
throw new Error(`Role delivery retry identity changed: ${key}/${
|
|
1524
|
+
|| runId !== failure.runId) {
|
|
1525
|
+
throw new Error(`Role delivery retry identity changed: ${key}/${runId}.`);
|
|
1591
1526
|
}
|
|
1592
|
-
const result = this.store.
|
|
1527
|
+
const result = this.store.saveRoleRunDeliveryFailure({
|
|
1593
1528
|
...failure,
|
|
1594
1529
|
now: this.#now()
|
|
1595
1530
|
});
|
|
@@ -1599,10 +1534,7 @@ export class FileTaskController {
|
|
|
1599
1534
|
this.delivery.forgetPrepared?.({
|
|
1600
1535
|
taskId: failure.taskId,
|
|
1601
1536
|
roleName: failure.roleName,
|
|
1602
|
-
|
|
1603
|
-
...(failure.runtimeGenerationId === undefined
|
|
1604
|
-
? {}
|
|
1605
|
-
: { runtimeGenerationId: failure.runtimeGenerationId })
|
|
1537
|
+
runId: failure.runId,
|
|
1606
1538
|
});
|
|
1607
1539
|
if (!this.#stopped)
|
|
1608
1540
|
this.signal(key);
|
|
@@ -1808,15 +1740,15 @@ class ControllerDispatcherServiceTimeMetrics {
|
|
|
1808
1740
|
};
|
|
1809
1741
|
}
|
|
1810
1742
|
}
|
|
1811
|
-
function
|
|
1743
|
+
function eventLoopRun() {
|
|
1812
1744
|
return new Promise((resolve) => setImmediate(resolve));
|
|
1813
1745
|
}
|
|
1814
|
-
async function
|
|
1746
|
+
async function controlEventLoopRun() {
|
|
1815
1747
|
// A setImmediate scheduled from the check phase may resume before the next
|
|
1816
1748
|
// poll phase. Two turns guarantee already-written socket data gets one poll
|
|
1817
1749
|
// opportunity before another synchronous scheduler projection starts.
|
|
1818
|
-
await
|
|
1819
|
-
await
|
|
1750
|
+
await eventLoopRun();
|
|
1751
|
+
await eventLoopRun();
|
|
1820
1752
|
}
|
|
1821
1753
|
function signalMailboxKey(value) {
|
|
1822
1754
|
if (typeof value !== "object"
|