feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,365 @@
import type { ModelGatewayProfileAudit } from '@qinglong/ai/profile';
import { BoundModelProviderCredentialProvider } from '@qinglong/ai/provider-credential';
import { PostgresModelProviderCredentialReader } from '@qinglong/ai/postgres-model-provider-credential-storage';
import { loadProjectedModelGatewayProviderAuthority } from '@qinglong/ai/projected-model-gateway-authority';
import { createProjectedModelProviderSecretMaterialProvider } from '@qinglong/ai/projected-model-provider-secret-material';
import { createPluginPackagePromptOutputProjectedKeyring } from '@qinglong/ai/plugin-package-prompt-output-projected-keyring';
import {
bootstrapPostgresPluginPackagePromptApplication,
type BootstrapPostgresPluginPackagePromptApplicationResult,
} from '@qinglong/ai/postgres-plugin-package-prompt-application';
import { createPostgresDatabaseOpener } from '@qinglong/cluster-postgres/runtime';
import { PostgresProjectPolicyRepository } from '@qinglong/cluster-postgres/project-policy';
import type { ClusterControlStopResult } from '@qinglong/runtime-core';
import { ProjectPolicyEngine } from '@qinglong/runtime-core/project-policy';
import type { ClusterControlApplicationResult } from './application';
import type {
ClusterControlEnvironment,
EnabledClusterControlConfig,
} from '../production-process/config';
import {
startProductionClusterControlApplication,
type ProductionClusterControlApplicationOptions,
} from './productionApplication';
export interface EnabledProductionClusterAiConfig {
readonly enabled: true;
readonly providerAuthorityFile: string;
readonly secretRootDirectory: string;
readonly promptOutputKeyringRootDirectory?: string;
readonly maxConcurrent: number;
readonly recoveryLimit: number;
readonly databaseMaxConnections: number;
}
export interface ProductionClusterAiControlApplicationOptions {
readonly control: ProductionClusterControlApplicationOptions;
readonly ai: EnabledProductionClusterAiConfig;
readonly audit: (
record: Readonly<ModelGatewayProfileAudit>,
) => void | Promise<void>;
readonly startControl?: typeof startProductionClusterControlApplication;
readonly bootstrapPrompt?: typeof bootstrapPostgresPluginPackagePromptApplication;
}
export class ProductionClusterAiConfigError extends TypeError {
readonly code = 'QL3_CLUSTER_AI_CONFIG_INVALID';
constructor(message: string) {
super(`Cluster AI configuration is invalid: ${message}`);
this.name = 'ProductionClusterAiConfigError';
}
}
function booleanValue(
environment: ClusterControlEnvironment,
name: string,
defaultValue: boolean,
): boolean {
const value = environment[name];
if (value === undefined || value === '') return defaultValue;
if (value === 'true') return true;
if (value === 'false') return false;
throw new ProductionClusterAiConfigError(`${name} must be true or false`);
}
function boundedInteger(
environment: ClusterControlEnvironment,
name: string,
fallback: number,
minimum: number,
maximum: number,
): number {
const value = environment[name];
if (value === undefined || value === '') return fallback;
if (!/^\d+$/.test(value)) {
throw new ProductionClusterAiConfigError(`${name} must be an integer`);
}
const parsed = Number(value);
if (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) {
throw new ProductionClusterAiConfigError(
`${name} must be between ${minimum} and ${maximum}`,
);
}
return parsed;
}
function requiredPath(
environment: ClusterControlEnvironment,
name: string,
): string {
const value = environment[name];
if (
typeof value !== 'string' ||
value.length < 2 ||
value.length > 4096 ||
!value.startsWith('/') ||
/[\0\r\n]/.test(value)
) {
throw new ProductionClusterAiConfigError(`${name} is invalid`);
}
return value;
}
/** Parsed only by the explicit AI process entrypoint; the default CLI ignores it. */
export function loadProductionClusterAiConfig(
environment: ClusterControlEnvironment,
): EnabledProductionClusterAiConfig {
if (
!environment ||
typeof environment !== 'object' ||
Array.isArray(environment) ||
!booleanValue(environment, 'QL3_CLUSTER_AI_ENABLED', false)
) {
throw new ProductionClusterAiConfigError(
'QL3_CLUSTER_AI_ENABLED must be true',
);
}
const promptOutputEnabled = booleanValue(
environment,
'QL3_CLUSTER_AI_PROMPT_OUTPUT_ENABLED',
false,
);
return Object.freeze({
enabled: true,
providerAuthorityFile: requiredPath(
environment,
'QL3_CLUSTER_AI_PROVIDER_AUTHORITY_FILE',
),
secretRootDirectory: requiredPath(
environment,
'QL3_CLUSTER_AI_SECRET_ROOT',
),
...(promptOutputEnabled
? {
promptOutputKeyringRootDirectory: requiredPath(
environment,
'QL3_CLUSTER_AI_PROMPT_OUTPUT_KEYRING_ROOT',
),
}
: {}),
maxConcurrent: boundedInteger(
environment,
'QL3_CLUSTER_AI_MAX_CONCURRENT',
4,
1,
64,
),
recoveryLimit: boundedInteger(
environment,
'QL3_CLUSTER_AI_RECOVERY_LIMIT',
32,
1,
128,
),
databaseMaxConnections: boundedInteger(
environment,
'QL3_CLUSTER_AI_DATABASE_MAX_CONNECTIONS',
4,
1,
16,
),
});
}
function aiDatabaseOpener(
control: EnabledClusterControlConfig,
ai: EnabledProductionClusterAiConfig,
onUnavailable: (error: Error) => void,
) {
return createPostgresDatabaseOpener({
role: 'runtime',
connection: control.database.connection,
pool: {
...control.database.pool,
applicationName: 'qinglong-cluster-ai',
maxConnections: ai.databaseMaxConnections,
},
onPoolError: onUnavailable,
});
}
/**
* Explicit AI-enabled composition root. It keeps the normal control image and
* process AI-free while sharing the reviewed authentication/Policy pipeline
* and route registry when the separate AI image entrypoint is selected.
*/
export async function startProductionClusterAiControlApplication(
options: ProductionClusterAiControlApplicationOptions,
): Promise<ClusterControlApplicationResult> {
if (
!options ||
typeof options !== 'object' ||
Array.isArray(options) ||
typeof options.audit !== 'function'
) {
throw new TypeError('Production Cluster AI application options are invalid');
}
const startControl =
options.startControl ?? startProductionClusterControlApplication;
const bootstrapPrompt =
options.bootstrapPrompt ?? bootstrapPostgresPluginPackagePromptApplication;
if (typeof startControl !== 'function' || typeof bootstrapPrompt !== 'function') {
throw new TypeError('Production Cluster AI application factories are invalid');
}
const secretMaterial =
await createProjectedModelProviderSecretMaterialProvider({
rootDirectory: options.ai.secretRootDirectory,
});
const promptOutputKeys =
options.ai.promptOutputKeyringRootDirectory === undefined
? undefined
: await createPluginPackagePromptOutputProjectedKeyring({
rootDirectory: options.ai.promptOutputKeyringRootDirectory,
});
let aiDatabase:
| Awaited<ReturnType<ReturnType<typeof createPostgresDatabaseOpener>>>
| undefined;
let resolveAiUnavailable: ((error: Error) => void) | undefined;
let aiUnavailableError: Error | undefined;
const aiUnavailable = new Promise<Error>((resolve) => {
resolveAiUnavailable = resolve;
});
const onAiUnavailable = (error: Error): void => {
aiUnavailableError ??= error;
resolveAiUnavailable?.(aiUnavailableError);
resolveAiUnavailable = undefined;
};
let promptApplication:
| BootstrapPostgresPluginPackagePromptApplicationResult
| undefined;
let controlApplication: ClusterControlApplicationResult | undefined;
let stopPromise: Promise<ClusterControlStopResult> | undefined;
let promptOutputPolicy: ProjectPolicyEngine | undefined;
const promptOutputReadAuthorizer = Object.freeze({
async authorize(request: Readonly<{
principal: Parameters<ProjectPolicyEngine['authorize']>[0];
projectId: string;
}>) {
if (!aiDatabase) {
throw new Error('Cluster AI database is unavailable during output read');
}
promptOutputPolicy ??= new ProjectPolicyEngine(
new PostgresProjectPolicyRepository(aiDatabase.pool),
);
const decision = await promptOutputPolicy.authorize(
request.principal,
request.projectId,
'artifact.read',
);
return decision.effect === 'allow'
? Object.freeze({ effect: 'allow' as const })
: Object.freeze({
effect: decision.effect,
reasonCode: 'artifact_read_denied',
});
},
});
const stop = async (): Promise<ClusterControlStopResult> => {
stopPromise ??= (async () => {
const controlResult =
controlApplication?.status === 'active'
? await controlApplication.stop()
: 'stopped';
const promptResult = await promptApplication?.stop();
return controlResult === 'stopped' &&
(promptResult === undefined || promptResult === 'stopped')
? 'stopped'
: 'timed_out';
})();
return stopPromise;
};
try {
const openDatabase = aiDatabaseOpener(
options.control.config,
options.ai,
onAiUnavailable,
);
promptApplication = await bootstrapPrompt({
enabled: true,
async openDatabase() {
if (aiDatabase) {
throw new Error('Cluster AI database was opened more than once');
}
aiDatabase = await openDatabase();
return aiDatabase;
},
async loadProviders() {
if (!aiDatabase) {
throw new Error('Cluster AI database is unavailable during provider load');
}
const credentialStorage = new PostgresModelProviderCredentialReader(
aiDatabase.pool,
);
const credentials = new BoundModelProviderCredentialProvider({
bindings: credentialStorage,
secrets: secretMaterial,
audit: credentialStorage,
});
return loadProjectedModelGatewayProviderAuthority({
configFile: options.ai.providerAuthorityFile,
credentials,
});
},
audit: options.audit,
maxConcurrent: options.ai.maxConcurrent,
recoveryLimit: options.ai.recoveryLimit,
...(promptOutputKeys === undefined
? {}
: {
promptOutputKeys,
promptOutputRead: { authorizer: promptOutputReadAuthorizer },
}),
});
if (promptApplication.status !== 'active') {
throw new Error('Cluster AI Prompt application did not activate');
}
controlApplication = await startControl({
...options.control,
promptCatalog: {
capability: promptApplication.promptCatalog,
},
promptExecution: {
capability: promptApplication.promptExecutions,
},
promptExecutionInspection: {
capability: promptApplication.promptExecutionInspections,
},
...(promptApplication.promptOutputs === undefined
? {}
: {
promptOutputRead: {
capability: promptApplication.promptOutputs,
},
}),
...(promptApplication.promptExecutionOutputs === undefined
? {}
: {
promptExecutionOutputRead: {
capability: promptApplication.promptExecutionOutputs,
},
}),
});
if (controlApplication.status !== 'active') {
throw new Error('AI-enabled cluster-control did not activate');
}
const activeControl = controlApplication;
return Object.freeze({
status: 'active' as const,
address: activeControl.address,
evidence: activeControl.evidence,
recovery: activeControl.recovery,
unavailable: Promise.race([activeControl.unavailable, aiUnavailable]),
availabilityStatus() {
return aiUnavailableError
? 'unavailable'
: activeControl.availabilityStatus();
},
stop,
});
} catch (error) {
await stop().catch(() => undefined);
throw error;
}
}
@@ -0,0 +1,244 @@
import type {
ClusterControlActivationAudit,
ClusterControlActivationStack,
ClusterControlReadinessEvidence,
ClusterControlRuntimeActivationResult,
ClusterControlStartupRecoverySummary,
ClusterControlStopResult,
DeploymentProfile,
OpenPostgresDatabase,
} from '@qinglong/runtime-core';
import {
bootstrapClusterControlRuntime,
type ClusterControlAssemblyInput,
type ClusterControlRecoveryRuntimeOptions,
type ClusterRunCancellationConvergenceRuntimeOptions,
type ClusterSchedulerRuntimeOptions,
type ClusterWorkerRuntimeDependencies,
} from './clusterControlRuntime';
import { assertClusterControlApiCredentialPepper } from '../authentication/apiCredentialAuthenticator';
import {
startClusterControlHttpSurface,
type ClusterControlAdmissionPipeline,
type ClusterControlHttpAddress,
type ClusterControlHttpSurfaceOptions,
} from '../transport/httpSurface';
import type { ClusterControlAvailabilitySource } from '../database/availability';
export interface ClusterControlApplicationStack {
reconcile(): Promise<ClusterControlStartupRecoverySummary>;
startLifecycles(): Promise<boolean>;
admission: ClusterControlAdmissionPipeline;
stop(): Promise<ClusterControlStopResult>;
}
export interface ClusterControlApplicationOptions {
readonly enabled?: boolean;
readonly profile: DeploymentProfile;
readonly apiCredentialPepper?: string;
readonly recovery?: ClusterControlRecoveryRuntimeOptions;
readonly scheduler?: ClusterSchedulerRuntimeOptions;
readonly cancellationConvergence?: ClusterRunCancellationConvergenceRuntimeOptions;
readonly workerRuntime?: ClusterWorkerRuntimeDependencies;
readonly openDatabase: OpenPostgresDatabase;
readonly availability: ClusterControlAvailabilitySource;
readonly http: ClusterControlHttpSurfaceOptions;
readonly create: (
input: ClusterControlAssemblyInput,
) => ClusterControlApplicationStack;
readonly audit: (
record: ClusterControlActivationAudit,
) => void | Promise<void>;
}
export type ClusterControlApplicationResult =
| { readonly status: 'disabled'; stop(): Promise<'stopped'> }
| {
readonly status: 'active';
readonly address: ClusterControlHttpAddress;
readonly evidence: ClusterControlReadinessEvidence;
readonly recovery: ClusterControlStartupRecoverySummary;
readonly unavailable: Promise<Error>;
availabilityStatus(): 'ready' | 'unavailable' | 'stopped';
stop(): Promise<ClusterControlStopResult>;
};
export class ClusterControlDatabaseUnavailableError extends Error {
readonly code = 'CLUSTER_CONTROL_DATABASE_UNAVAILABLE';
constructor() {
super('Cluster-control database became unavailable');
this.name = 'ClusterControlDatabaseUnavailableError';
}
}
function inactiveBootstrap(
options: ClusterControlApplicationOptions,
): Promise<ClusterControlRuntimeActivationResult> {
return bootstrapClusterControlRuntime({
...(options.enabled === undefined ? {} : { enabled: options.enabled }),
profile: options.profile,
...(options.apiCredentialPepper === undefined
? {}
: { apiCredentialPepper: options.apiCredentialPepper }),
...(options.recovery === undefined ? {} : { recovery: options.recovery }),
...(options.scheduler === undefined
? {}
: { scheduler: options.scheduler }),
...(options.cancellationConvergence === undefined
? {}
: { cancellationConvergence: options.cancellationConvergence }),
...(options.workerRuntime === undefined
? {}
: { workerRuntime: options.workerRuntime }),
openDatabase: options.openDatabase,
create() {
throw new Error('Inactive cluster-control unexpectedly created a stack');
},
audit: options.audit,
});
}
/**
* Starts the cluster probe surface before database readiness, then installs the
* /api/v3 admission handler only after recovery and lifecycles are safe. Stop
* withdraws and drains admission before stack, Pool and listener shutdown.
*/
export async function startClusterControlApplication(
options: ClusterControlApplicationOptions,
): Promise<ClusterControlApplicationResult> {
const enabled = options.enabled ?? false;
if (!enabled || options.profile !== 'cluster-control') {
const inactive = await inactiveBootstrap(options);
if (inactive.status !== 'disabled') {
throw new Error('Inactive cluster-control unexpectedly became active');
}
return inactive;
}
assertClusterControlApiCredentialPepper(options.apiCredentialPepper ?? '');
const apiCredentialPepper = options.apiCredentialPepper!;
if (
!options.availability ||
typeof options.availability.subscribe !== 'function'
) {
throw new TypeError('Cluster-control availability source is invalid');
}
const http = await startClusterControlHttpSurface(options.http);
let activation: ClusterControlRuntimeActivationResult | undefined;
let unavailableError: Error | undefined;
let unavailableStopPromise: Promise<ClusterControlStopResult> | undefined;
let availabilityStatus: 'ready' | 'unavailable' | 'stopped' = 'ready';
let unsubscribeAvailability: (() => void) | undefined;
let resolveUnavailable: ((error: Error) => void) | undefined;
const unavailable = new Promise<Error>((resolve) => {
resolveUnavailable = resolve;
});
const withdrawForUnavailable = (error: Error): Promise<void> => {
unavailableError ??= error;
availabilityStatus = 'unavailable';
resolveUnavailable?.(unavailableError);
resolveUnavailable = undefined;
if (!activation || activation.status === 'disabled')
return Promise.resolve();
unavailableStopPromise ??= activation.stop();
return unavailableStopPromise.then(
() => undefined,
() => undefined,
);
};
try {
unsubscribeAvailability = options.availability.subscribe(
withdrawForUnavailable,
);
activation = await bootstrapClusterControlRuntime({
enabled: true,
profile: options.profile,
apiCredentialPepper,
...(options.recovery === undefined ? {} : { recovery: options.recovery }),
...(options.scheduler === undefined
? {}
: { scheduler: options.scheduler }),
...(options.cancellationConvergence === undefined
? {}
: { cancellationConvergence: options.cancellationConvergence }),
...(options.workerRuntime === undefined
? {}
: { workerRuntime: options.workerRuntime }),
openDatabase: options.openDatabase,
create(input): ClusterControlActivationStack {
const application = options.create(input);
if (
!application ||
typeof application !== 'object' ||
!application.admission ||
typeof application.admission.prepare !== 'function'
) {
throw new TypeError(
'Cluster-control application stack has no admission pipeline',
);
}
return {
reconcile: () => application.reconcile(),
startLifecycles: () => application.startLifecycles(),
installAdmission: () =>
http.installAdmission(input.evidence, application.admission),
stop: () => application.stop(),
};
},
audit: options.audit,
});
if (activation.status === 'disabled') {
unsubscribeAvailability();
await http.close();
return activation;
}
if (unavailableError) {
await withdrawForUnavailable(unavailableError);
throw new ClusterControlDatabaseUnavailableError();
}
const activeActivation = activation;
let stopPromise: Promise<ClusterControlStopResult> | undefined;
return {
status: 'active',
address: http.address,
evidence: activeActivation.evidence,
recovery: activeActivation.recovery,
unavailable,
availabilityStatus: () => availabilityStatus,
stop() {
if (stopPromise) return stopPromise;
availabilityStatus = 'stopped';
unsubscribeAvailability?.();
unsubscribeAvailability = undefined;
stopPromise = (async () => {
let result: ClusterControlStopResult | undefined;
let primaryError: unknown;
try {
result = await activeActivation.stop();
} catch (error) {
primaryError = error;
}
try {
await http.close();
} catch (error) {
primaryError ??= error;
}
if (primaryError) throw primaryError;
return result!;
})();
return stopPromise;
},
};
} catch (error) {
unsubscribeAvailability?.();
try {
await http.close();
} catch {
// Preserve the readiness/assembly/activation failure.
}
throw error;
}
}
@@ -0,0 +1,842 @@
import { randomUUID } from 'node:crypto';
import {
activateClusterControlRuntime,
ClusterRunLostRetryCoordinator,
ClusterRunCancellationConvergenceCoordinator,
ClusterControlRecoveryEvidenceRegistry,
ClusterControlRecoveryConvergenceVerifier,
ClusterControlRecoverySupervisor,
ClusterControlStartupRecoveryCoordinator,
EvidenceBasedClusterControlRecoveryProcessor,
MAX_CLUSTER_CONTROL_RECOVERY_CLAIMS_PER_PASS,
MAX_CLUSTER_CONTROL_RECOVERY_CLAIM_LEASE_MS,
MAX_CLUSTER_CONTROL_RECOVERY_EVIDENCE_TIMEOUT_MS,
MAX_CLUSTER_CONTROL_RECOVERY_RETRY_DELAY_MS,
MAX_CLUSTER_CONTROL_STARTUP_RECOVERY_PASSES,
MAX_CLUSTER_RUN_CANCELLATION_CONVERGENCE_PAGE_SIZE,
MAX_CLUSTER_RUN_CANCELLATION_CONVERGENCE_PAGES_PER_CYCLE,
type ClusterControlActivationAudit,
type ClusterControlActivationStack,
type ClusterControlReadinessEvidence,
type ClusterControlRecoveryExecutorEvidenceProvider,
type ClusterControlRuntimeActivationResult,
type ClusterControlStopResult,
type DeploymentProfile,
type OpenPostgresDatabase,
type PostgresDatabaseResource,
type PostgresPool,
type ProjectPolicyRepository,
type RunRepository,
type ClusterRunCancellationConvergenceCycleResult,
} from '@qinglong/runtime-core';
import type { ClusterRunCancellationRepository } from '@qinglong/runtime-core/cluster-run-cancellation';
import type { ProjectRunListReader } from '@qinglong/runtime-core/project-run-list';
import type { ClusterScheduleStore } from '@qinglong/runtime-core/cluster-scheduler';
import type { TaskDefinitionSource } from '@qinglong/runtime-core/task-definition';
import type { TriggerSource } from '@qinglong/runtime-core/trigger';
import type { ClusterTaskExecutionRevisionSource } from '@qinglong/runtime-core/cluster-execution-revision';
import type {
ProjectToolDefinitionSnapshotRepository,
ProjectToolDefinitionSnapshotSourceRepository,
} from '@qinglong/runtime-core/project-tool-definition-snapshot';
import type { StepRunRepository } from '@qinglong/runtime-core/step-run';
import type { ToolExecutionCompletionRepository } from '@qinglong/runtime-core/tool-execution-completion';
import type { ToolExecutionFailureCompletionRepository } from '@qinglong/runtime-core/tool-execution-failure-completion';
import type { ToolExecutionStartBarrierRepository } from '@qinglong/runtime-core/tool-execution-start-barrier';
import type { ToolInvocationArtifactRepository } from '@qinglong/runtime-core/tool-invocation-artifact';
import type { ToolResultKeyCatalogReader } from '@qinglong/runtime-core/tool-result-key-catalog';
import type { ToolExecutionResultRekeyReader } from '@qinglong/runtime-core/tool-result-rekey';
import {
assertPostgresSchemaReady,
PostgresClusterControlRecoverySource,
PostgresClusterControlRecoveryClaimRepository,
PostgresClusterControlRecoveryResolutionRepository,
PostgresClusterRuntimeRecoverySource,
PostgresClusterRunLostRetryRepository,
PostgresClusterRunCancellationRepository,
PostgresClusterRunCancellationConvergenceRepository,
PostgresProjectPolicyRepository,
PostgresApiCredentialRepository,
PostgresSecurityAuditRepository,
PostgresRunRepository,
PostgresWorkerExecutionAttestationRepository,
PostgresTaskDefinitionSource,
PostgresTaskExecutionRevisionSource,
PostgresTriggerSource,
PostgresClusterScheduleRepository,
PostgresRemoteWorkerAttestationEvidenceProvider,
PostgresProjectToolDefinitionSnapshotRepository,
PostgresStepRunRepository,
PostgresToolExecutionCompletionRepository,
PostgresToolExecutionFailureCompletionRepository,
PostgresToolExecutionStartBarrierRepository,
PostgresToolInvocationArtifactRepository,
PostgresToolResultKeyCatalogReader,
PostgresToolResultRekeyReader,
type PostgresSchemaReadinessReport,
} from '@qinglong/cluster-postgres/runtime';
import { PostgresPluginPackageWorkflowFrontierRepository } from '@qinglong/cluster-postgres/plugin-package-workflow-frontier';
import { PostgresPluginPackageWorkflowTaskAttemptAdmissionRepository } from '@qinglong/cluster-postgres/plugin-package-workflow-task-attempt-admission';
import { PostgresTaskStartRepository } from '@qinglong/cluster-postgres/task-start';
import { PostgresPluginPackageAutomationPublicationRepository } from '@qinglong/cluster-postgres/plugin-package-automation-publication';
import { PostgresPluginPackageMaterializedRevisionRepository } from '@qinglong/cluster-postgres/plugin-package-materialized-revision';
import {
PostgresAuthorizedPluginPackageWorkflowAdmissionRepository,
PostgresAuthorizedPluginPackageWorkflowRunEventListRepository,
PostgresAuthorizedPluginPackageWorkflowRunInspectionRepository,
PostgresAuthorizedPluginPackageWorkflowRunListRepository,
PostgresAuthorizedPluginPackageWorkflowStepRunListRepository,
} from '@qinglong/cluster-postgres/plugin-package-workflow-administration';
import {
assertClusterControlApiCredentialPepper,
createClusterControlApiCredentialAuthenticator,
} from '../authentication/apiCredentialAuthenticator';
import type {
ClusterControlRequestAuthenticator,
ClusterControlSecurityAuditSink,
} from '../transport/admissionPipeline';
import {
MAX_CLUSTER_SCHEDULE_CLAIMS_PER_CYCLE,
ClusterSchedulerCoordinator,
ClusterSchedulerLifecycle,
type ClusterSchedulerCycleSummary,
} from '../scheduling/scheduler';
import { ClusterWorkflowSchedulerCoordinator } from '../scheduling/workflowScheduler';
import { ClusterRuntimeSchedulerCoordinator } from '../scheduling/runtimeScheduler';
import { ClusterRunCancellationConvergenceLifecycle } from '../run/runCancellationLifecycle';
import type { TaskStartRepository } from '@qinglong/runtime-core/task-start';
import {
createClusterWorkerRuntimePort,
type ClusterWorkerRuntimeDependencies,
type ClusterWorkerRuntimePort,
} from '../remote-execution/workerRuntimePort';
import {
createClusterPluginPackageWorkflowAdministrationCapability,
type ClusterPluginPackageWorkflowAdministrationCapability,
} from '../plugin-package/workflow/pluginPackageWorkflowAdministration';
export interface ClusterTrustedToolStorage {
readonly invocationArtifacts: ToolInvocationArtifactRepository;
readonly stepRuns: StepRunRepository;
readonly startBarriers: ToolExecutionStartBarrierRepository;
readonly completions: ToolExecutionCompletionRepository;
readonly failureCompletions: ToolExecutionFailureCompletionRepository;
readonly resultKeyCatalog: ToolResultKeyCatalogReader;
readonly resultRekeys: ToolExecutionResultRekeyReader;
readonly toolDefinitionSnapshots: ProjectToolDefinitionSnapshotRepository &
ProjectToolDefinitionSnapshotSourceRepository;
}
export interface ClusterControlAssemblyInput {
readonly evidence: ClusterControlReadinessEvidence;
readonly policies: ProjectPolicyRepository;
readonly runs: RunRepository & ProjectRunListReader;
readonly runCancellation: ClusterRunCancellationRepository;
readonly taskStart: TaskStartRepository;
readonly taskDefinitions: TaskDefinitionSource;
readonly taskExecutionRevisions: ClusterTaskExecutionRevisionSource;
readonly triggers: TriggerSource;
readonly schedules: ClusterScheduleStore;
readonly trustedToolStorage: ClusterTrustedToolStorage;
readonly authenticator: ClusterControlRequestAuthenticator;
readonly securityAudit: ClusterControlSecurityAuditSink;
readonly workflowAdministration: ClusterPluginPackageWorkflowAdministrationCapability;
readonly workerRuntime?: ClusterWorkerRuntimePort;
}
export interface ClusterControlRecoveryRuntimeOptions {
readonly ownerId: string;
readonly providers?: readonly ClusterControlRecoveryExecutorEvidenceProvider[];
readonly claimLimit?: number;
readonly claimLeaseMs?: number;
readonly retryDelayMs?: number;
readonly providerTimeoutMs?: number;
readonly maxStartupPasses?: number;
}
export interface ClusterSchedulerRuntimeOptions {
readonly ownerId?: string;
readonly claimLeaseMs?: number;
readonly maxClaimsPerCycle?: number;
readonly misfireGraceMs?: number;
readonly intervalMs?: number;
readonly stopTimeoutMs?: number;
readonly onDiagnostic?: (
error: unknown,
summary?: ClusterSchedulerCycleSummary,
) => void | Promise<void>;
}
export interface ClusterRunCancellationConvergenceRuntimeOptions {
readonly pageSize?: number;
readonly maxPages?: number;
readonly intervalMs?: number;
readonly stopTimeoutMs?: number;
readonly onDiagnostic?: (
error: unknown,
summary?: Readonly<ClusterRunCancellationConvergenceCycleResult>,
) => void | Promise<void>;
}
export interface ClusterControlBootstrapOptions {
readonly enabled?: boolean;
readonly profile: DeploymentProfile;
readonly apiCredentialPepper?: string;
readonly recovery?: ClusterControlRecoveryRuntimeOptions;
readonly scheduler?: ClusterSchedulerRuntimeOptions;
readonly cancellationConvergence?: ClusterRunCancellationConvergenceRuntimeOptions;
readonly workerRuntime?: ClusterWorkerRuntimeDependencies;
readonly openDatabase: OpenPostgresDatabase;
readonly create: (
input: ClusterControlAssemblyInput,
) => ClusterControlActivationStack;
readonly audit: (
record: ClusterControlActivationAudit,
) => void | Promise<void>;
}
interface PreparedRecoveryRuntime {
readonly providers: readonly ClusterControlRecoveryExecutorEvidenceProvider[];
readonly providerTimeoutMs: number;
readonly ownerId: string;
readonly claimLimit: number;
readonly claimLeaseMs: number;
readonly retryDelayMs: number;
readonly maxStartupPasses: number;
}
interface PreparedSchedulerRuntime {
readonly ownerId: string;
readonly claimLeaseMs: number;
readonly maxClaimsPerCycle: number;
readonly misfireGraceMs: number;
readonly intervalMs: number;
readonly stopTimeoutMs: number;
readonly onDiagnostic?: ClusterSchedulerRuntimeOptions['onDiagnostic'];
}
interface PreparedCancellationConvergenceRuntime {
readonly pageSize: number;
readonly maxPages: number;
readonly intervalMs: number;
readonly stopTimeoutMs: number;
readonly onDiagnostic?: ClusterRunCancellationConvergenceRuntimeOptions['onDiagnostic'];
}
function boundedInteger(
name: string,
value: number | undefined,
fallback: number,
minimum: number,
maximum: number,
): number {
const normalized = value ?? fallback;
if (
!Number.isSafeInteger(normalized) ||
normalized < minimum ||
normalized > maximum
) {
throw new RangeError(`${name} must be between ${minimum} and ${maximum}`);
}
return normalized;
}
function prepareRecoveryRuntime(
options: ClusterControlRecoveryRuntimeOptions | undefined,
): PreparedRecoveryRuntime {
if (!options) {
throw new TypeError(
'Enabled cluster-control requires bounded recovery configuration',
);
}
if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(options.ownerId)) {
throw new TypeError('Cluster-control recovery ownerId is invalid');
}
const claimLeaseMs = boundedInteger(
'Cluster-control recovery claim lease',
options.claimLeaseMs,
30_000,
1_000,
MAX_CLUSTER_CONTROL_RECOVERY_CLAIM_LEASE_MS,
);
const providerTimeoutMs = boundedInteger(
'Cluster-control recovery evidence timeout',
options.providerTimeoutMs,
5_000,
1,
MAX_CLUSTER_CONTROL_RECOVERY_EVIDENCE_TIMEOUT_MS,
);
if (providerTimeoutMs + 250 > claimLeaseMs) {
throw new RangeError(
'Cluster-control recovery evidence timeout must leave at least 250ms for fenced settlement',
);
}
return Object.freeze({
providers: Object.freeze([...(options.providers ?? [])]),
providerTimeoutMs,
ownerId: options.ownerId,
claimLimit: boundedInteger(
'Cluster-control recovery claim limit',
options.claimLimit,
16,
1,
MAX_CLUSTER_CONTROL_RECOVERY_CLAIMS_PER_PASS,
),
claimLeaseMs,
retryDelayMs: boundedInteger(
'Cluster-control recovery retry delay',
options.retryDelayMs,
5_000,
0,
MAX_CLUSTER_CONTROL_RECOVERY_RETRY_DELAY_MS,
),
maxStartupPasses: boundedInteger(
'Cluster-control startup recovery passes',
options.maxStartupPasses,
8,
1,
MAX_CLUSTER_CONTROL_STARTUP_RECOVERY_PASSES,
),
});
}
function prepareSchedulerRuntime(
options: ClusterSchedulerRuntimeOptions | undefined,
fallbackOwnerId: string,
): PreparedSchedulerRuntime {
const allowedKeys = new Set([
'claimLeaseMs',
'intervalMs',
'maxClaimsPerCycle',
'misfireGraceMs',
'onDiagnostic',
'ownerId',
'stopTimeoutMs',
]);
if (
options !== undefined &&
(!options ||
typeof options !== 'object' ||
Array.isArray(options) ||
Object.keys(options).some((key) => !allowedKeys.has(key)))
) {
throw new TypeError('Cluster scheduler configuration is invalid');
}
const ownerId = options?.ownerId ?? fallbackOwnerId;
if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(ownerId)) {
throw new TypeError('Cluster scheduler ownerId is invalid');
}
if (
options?.onDiagnostic !== undefined &&
typeof options.onDiagnostic !== 'function'
) {
throw new TypeError('Cluster scheduler diagnostic sink is invalid');
}
return Object.freeze({
ownerId,
claimLeaseMs: boundedInteger(
'Cluster scheduler claim lease',
options?.claimLeaseMs,
30_000,
1_000,
60_000,
),
maxClaimsPerCycle: boundedInteger(
'Cluster scheduler claim budget',
options?.maxClaimsPerCycle,
16,
1,
MAX_CLUSTER_SCHEDULE_CLAIMS_PER_CYCLE,
),
misfireGraceMs: boundedInteger(
'Cluster scheduler misfire grace',
options?.misfireGraceMs,
30_000,
0,
5 * 60_000,
),
intervalMs: boundedInteger(
'Cluster scheduler interval',
options?.intervalMs,
1_000,
250,
60 * 60_000,
),
stopTimeoutMs: boundedInteger(
'Cluster scheduler stop timeout',
options?.stopTimeoutMs,
10_000,
100,
30_000,
),
...(options?.onDiagnostic === undefined
? {}
: { onDiagnostic: options.onDiagnostic }),
});
}
function prepareCancellationConvergenceRuntime(
options: ClusterRunCancellationConvergenceRuntimeOptions | undefined,
): PreparedCancellationConvergenceRuntime {
const allowedKeys = new Set([
'intervalMs',
'maxPages',
'onDiagnostic',
'pageSize',
'stopTimeoutMs',
]);
if (
options !== undefined &&
(!options ||
typeof options !== 'object' ||
Array.isArray(options) ||
Object.keys(options).some((key) => !allowedKeys.has(key)))
) {
throw new TypeError(
'Cluster Run cancellation convergence configuration is invalid',
);
}
if (
options?.onDiagnostic !== undefined &&
typeof options.onDiagnostic !== 'function'
) {
throw new TypeError(
'Cluster Run cancellation convergence diagnostic sink is invalid',
);
}
return Object.freeze({
pageSize: boundedInteger(
'Cluster Run cancellation convergence page size',
options?.pageSize,
32,
1,
MAX_CLUSTER_RUN_CANCELLATION_CONVERGENCE_PAGE_SIZE,
),
maxPages: boundedInteger(
'Cluster Run cancellation convergence page limit',
options?.maxPages,
4,
1,
MAX_CLUSTER_RUN_CANCELLATION_CONVERGENCE_PAGES_PER_CYCLE,
),
intervalMs: boundedInteger(
'Cluster Run cancellation convergence interval',
options?.intervalMs,
1_000,
250,
60 * 60_000,
),
stopTimeoutMs: boundedInteger(
'Cluster Run cancellation convergence stop timeout',
options?.stopTimeoutMs,
10_000,
100,
30_000,
),
...(options?.onDiagnostic === undefined
? {}
: { onDiagnostic: options.onDiagnostic }),
});
}
function readinessEvidence(
report: PostgresSchemaReadinessReport,
): ClusterControlReadinessEvidence {
return Object.freeze({
contractName: report.contractName,
contractVersion: report.contractVersion,
serverMajor: report.serverMajor,
migrationIds: Object.freeze([...report.migrationIds]),
});
}
/**
* Owns the cluster database around the readiness-first activation gate.
* Repository and service construction happens through create() only after the
* runtime role, migration history and catalog contract are proven ready.
*/
export async function bootstrapClusterControlRuntime(
options: ClusterControlBootstrapOptions,
): Promise<ClusterControlRuntimeActivationResult> {
let recoveryRuntime: PreparedRecoveryRuntime | undefined;
let schedulerRuntime: PreparedSchedulerRuntime | undefined;
let cancellationConvergenceRuntime:
| PreparedCancellationConvergenceRuntime
| undefined;
let recoveryRegistry: ClusterControlRecoveryEvidenceRegistry | undefined;
if ((options.enabled ?? false) && options.profile === 'cluster-control') {
assertClusterControlApiCredentialPepper(options.apiCredentialPepper ?? '');
recoveryRuntime = prepareRecoveryRuntime(options.recovery);
schedulerRuntime = prepareSchedulerRuntime(
options.scheduler,
recoveryRuntime.ownerId,
);
cancellationConvergenceRuntime = prepareCancellationConvergenceRuntime(
options.cancellationConvergence,
);
}
let database: PostgresDatabaseResource | undefined;
let closePromise: Promise<void> | undefined;
const closeDatabase = (): Promise<void> => {
if (!database) return Promise.resolve();
closePromise ??= Promise.resolve().then(() => database!.close());
return closePromise;
};
try {
const activation = await activateClusterControlRuntime({
...(options.enabled === undefined ? {} : { enabled: options.enabled }),
profile: options.profile,
readiness: {
async assertReady() {
if (database) {
throw new Error(
'Cluster-control database was opened more than once',
);
}
database = await options.openDatabase();
return readinessEvidence(
await assertPostgresSchemaReady(database.pool),
);
},
},
create(evidence) {
if (!database) {
throw new Error(
'Cluster-control database is unavailable after readiness',
);
}
const recovery = new PostgresClusterControlRecoverySource(
database.pool,
);
const recoveryClaims =
new PostgresClusterControlRecoveryClaimRepository(database.pool);
const recoveryTransitions =
new PostgresClusterControlRecoveryResolutionRepository(database.pool);
if (!recoveryRuntime) {
throw new Error(
'Cluster-control recovery runtime is unavailable after readiness',
);
}
if (!schedulerRuntime) {
throw new Error(
'Cluster scheduler runtime is unavailable after readiness',
);
}
if (!cancellationConvergenceRuntime) {
throw new Error(
'Cluster Run cancellation convergence runtime is unavailable after readiness',
);
}
const remoteAttestations =
new PostgresWorkerExecutionAttestationRepository(database.pool);
recoveryRegistry = new ClusterControlRecoveryEvidenceRegistry(
[
...recoveryRuntime.providers,
new PostgresRemoteWorkerAttestationEvidenceProvider(
database.pool,
remoteAttestations,
),
],
{ timeoutMs: recoveryRuntime.providerTimeoutMs },
);
const recoveryProcessor =
new EvidenceBasedClusterControlRecoveryProcessor(
recoveryTransitions,
recoveryRegistry,
{ retryDelayMs: recoveryRuntime.retryDelayMs },
);
const recoverySupervisor = new ClusterControlRecoverySupervisor(
recoveryClaims,
recoveryProcessor,
{
ownerId: recoveryRuntime.ownerId,
limit: recoveryRuntime.claimLimit,
leaseMs: recoveryRuntime.claimLeaseMs,
retryDelayMs: recoveryRuntime.retryDelayMs,
},
);
const recoveryCoordinator =
new ClusterControlStartupRecoveryCoordinator(recoverySupervisor, {
maxPasses: recoveryRuntime.maxStartupPasses,
});
const runtimeRecoverySupervisor = new ClusterControlRecoverySupervisor(
new PostgresClusterControlRecoveryClaimRepository(
database.pool,
randomUUID,
(queryable) => new PostgresClusterRuntimeRecoverySource(queryable),
),
recoveryProcessor,
{
ownerId: recoveryRuntime.ownerId,
limit: recoveryRuntime.claimLimit,
leaseMs: recoveryRuntime.claimLeaseMs,
retryDelayMs: recoveryRuntime.retryDelayMs,
},
);
const schedules = new PostgresClusterScheduleRepository(database.pool);
const runs = new PostgresRunRepository(database.pool);
const trustedToolStorage: ClusterTrustedToolStorage = Object.freeze({
invocationArtifacts: new PostgresToolInvocationArtifactRepository(
database.pool,
),
stepRuns: new PostgresStepRunRepository(database.pool),
startBarriers: new PostgresToolExecutionStartBarrierRepository(
database.pool,
),
completions: new PostgresToolExecutionCompletionRepository(
database.pool,
),
failureCompletions:
new PostgresToolExecutionFailureCompletionRepository(database.pool),
resultKeyCatalog: new PostgresToolResultKeyCatalogReader(
database.pool,
),
resultRekeys: new PostgresToolResultRekeyReader(database.pool),
toolDefinitionSnapshots:
new PostgresProjectToolDefinitionSnapshotRepository(database.pool),
});
const workflowScheduler = new ClusterWorkflowSchedulerCoordinator(
new ClusterSchedulerCoordinator(schedules, {
ownerId: schedulerRuntime.ownerId,
claimLeaseMs: schedulerRuntime.claimLeaseMs,
maxClaimsPerCycle: schedulerRuntime.maxClaimsPerCycle,
misfireGraceMs: schedulerRuntime.misfireGraceMs,
}),
new PostgresPluginPackageWorkflowFrontierRepository(database.pool),
new PostgresPluginPackageWorkflowTaskAttemptAdmissionRepository(
database.pool,
),
{
frontierPageSize: 32,
frontierMaxPages: 4,
taskAttemptPageSize: 32,
taskAttemptMaxPages: 4,
},
);
const runtimeScheduler = new ClusterRuntimeSchedulerCoordinator(
runtimeRecoverySupervisor,
new ClusterRunLostRetryCoordinator(
new PostgresClusterRunLostRetryRepository(database.pool),
{ pageSize: 16 },
),
workflowScheduler,
);
const schedulerLifecycle = new ClusterSchedulerLifecycle(
runtimeScheduler,
{
intervalMs: schedulerRuntime.intervalMs,
stopTimeoutMs: schedulerRuntime.stopTimeoutMs,
...(schedulerRuntime.onDiagnostic === undefined
? {}
: { onDiagnostic: schedulerRuntime.onDiagnostic }),
},
);
const cancellationConvergenceLifecycle =
new ClusterRunCancellationConvergenceLifecycle(
new ClusterRunCancellationConvergenceCoordinator(
new PostgresClusterRunCancellationConvergenceRepository(
database.pool,
),
{
pageSize: cancellationConvergenceRuntime.pageSize,
maxPages: cancellationConvergenceRuntime.maxPages,
},
),
{
intervalMs: cancellationConvergenceRuntime.intervalMs,
stopTimeoutMs: cancellationConvergenceRuntime.stopTimeoutMs,
...(cancellationConvergenceRuntime.onDiagnostic === undefined
? {}
: {
onDiagnostic: cancellationConvergenceRuntime.onDiagnostic,
}),
},
);
const runCancellation = new PostgresClusterRunCancellationRepository(
database.pool,
);
const taskStart = new PostgresTaskStartRepository(database.pool);
const application = options.create({
evidence,
authenticator: createClusterControlApiCredentialAuthenticator(
new PostgresApiCredentialRepository(database.pool),
options.apiCredentialPepper ?? '',
),
policies: new PostgresProjectPolicyRepository(database.pool),
runs,
runCancellation,
taskStart,
taskDefinitions: new PostgresTaskDefinitionSource(database.pool),
taskExecutionRevisions: new PostgresTaskExecutionRevisionSource(
database.pool,
),
triggers: new PostgresTriggerSource(database.pool),
schedules,
trustedToolStorage,
securityAudit: new PostgresSecurityAuditRepository(database.pool),
workflowAdministration:
createClusterPluginPackageWorkflowAdministrationCapability(
new PostgresPluginPackageAutomationPublicationRepository(
database.pool,
),
new PostgresPluginPackageMaterializedRevisionRepository(
database.pool,
),
new PostgresAuthorizedPluginPackageWorkflowAdmissionRepository(
database.pool,
),
new PostgresAuthorizedPluginPackageWorkflowRunInspectionRepository(
database.pool,
),
new PostgresAuthorizedPluginPackageWorkflowRunListRepository(
database.pool,
),
new PostgresAuthorizedPluginPackageWorkflowStepRunListRepository(
database.pool,
),
new PostgresAuthorizedPluginPackageWorkflowRunEventListRepository(
database.pool,
),
runCancellation,
),
...(options.workerRuntime === undefined
? {}
: {
workerRuntime: createClusterWorkerRuntimePort(
database.pool,
options.workerRuntime,
),
}),
});
const convergence = new ClusterControlRecoveryConvergenceVerifier(
recovery,
);
return {
async reconcile() {
const outstanding = await convergence.verify();
if (!outstanding.safe) {
const system = await recoveryCoordinator.reconcile();
if (
!system.safe ||
system.remaining !== 0 ||
system.failed !== 0
) {
return system;
}
}
const summary = await application.reconcile();
if (
!summary.safe ||
summary.remaining !== 0 ||
summary.failed !== 0
) {
return summary;
}
return convergence.verify();
},
async startLifecycles() {
if (!(await application.startLifecycles())) return false;
schedulerLifecycle.start();
cancellationConvergenceLifecycle.start();
return true;
},
installAdmission: () => application.installAdmission(),
async stop() {
recoveryRegistry?.dispose();
let schedulerStatus: 'stopped' | 'timed_out' = 'stopped';
let cancellationStatus: 'stopped' | 'timed_out' = 'stopped';
let applicationStatus: ClusterControlStopResult = 'stopped';
let primaryError: unknown;
try {
cancellationStatus = (
await cancellationConvergenceLifecycle.stopAndDrain()
).status;
} catch (error) {
primaryError = error;
}
try {
schedulerStatus = (await schedulerLifecycle.stopAndDrain())
.status;
} catch (error) {
primaryError ??= error;
}
try {
applicationStatus = await application.stop();
} catch (error) {
primaryError ??= error;
}
if (primaryError) throw primaryError;
return cancellationStatus === 'timed_out' ||
schedulerStatus === 'timed_out' ||
applicationStatus === 'timed_out'
? 'timed_out'
: 'stopped';
},
};
},
audit: options.audit,
});
if (activation.status === 'disabled') return activation;
let stopPromise: Promise<ClusterControlStopResult> | undefined;
return {
...activation,
stop() {
if (stopPromise) return stopPromise;
stopPromise = (async () => {
let result: ClusterControlStopResult | undefined;
let primaryError: unknown;
try {
result = await activation.stop();
} catch (error) {
primaryError = error;
}
try {
await closeDatabase();
} catch (error) {
primaryError ??= error;
}
if (primaryError) throw primaryError;
return result!;
})();
return stopPromise;
},
};
} catch (error) {
recoveryRegistry?.dispose();
try {
await closeDatabase();
} catch {
// Preserve the readiness/assembly/activation failure.
}
throw error;
}
}
export type {
ClusterControlActivationAudit,
ClusterControlActivationStack,
ClusterControlReadinessEvidence,
ClusterControlRuntimeActivationResult,
ClusterControlStopResult,
DeploymentProfile,
OpenPostgresDatabase,
PostgresDatabaseResource,
PostgresPool,
ProjectPolicyRepository,
RunRepository,
ClusterRunCancellationRepository,
ClusterControlRequestAuthenticator,
ClusterControlSecurityAuditSink,
ClusterControlRecoveryExecutorEvidenceProvider,
ClusterScheduleStore,
};
export { ClusterRunCancellationConvergenceLifecycle } from '../run/runCancellationLifecycle';
export * from '../scheduling/scheduler';
export * from '../scheduling/workflowScheduler';
export * from '../scheduling/runtimeScheduler';
export * from '../remote-execution/remoteWorkerDispatcher';
export * from '../remote-execution/workerRuntimePort';
@@ -0,0 +1,410 @@
import { randomUUID } from 'node:crypto';
import type {
ClusterControlStartupRecoverySummary,
ClusterControlStopResult,
} from '@qinglong/runtime-core';
import type { RemoteWorkerSecretValueProvider } from '@qinglong/runtime-core/remote-secret-delivery';
import {
startClusterControlApplication,
type ClusterControlApplicationOptions,
type ClusterControlApplicationResult,
type ClusterControlApplicationStack,
} from './application';
import {
createClusterControlDatabaseBinding,
type EnabledClusterControlConfig,
} from '../production-process/config';
import {
createClusterControlAdmissionPipeline,
createClusterControlProjectPolicyAuthorizer,
} from '../transport/admissionPipeline';
import { createClusterControlRouteRegistry } from '../transport/routeRegistry';
import { CLUSTER_CONTROL_HTTP_DEFAULTS } from '../transport/httpSurface';
import { createClusterControlRunReadRoute } from '../run/runReadRoute';
import { createClusterControlRunListRoute } from '../run/runListRoute';
import { createClusterControlRunEventListRoute } from '../run/runEventListRoute';
import { createClusterControlRunStepListRoute } from '../run/runStepListRoute';
import { createClusterControlTaskListRoute } from '../task/taskListRoute';
import { createClusterControlTaskReadRoute } from '../task/taskReadRoute';
import { createClusterControlTaskStartRoute } from '../task/taskStartRoute';
import {
createClusterControlPluginPackagePromptExecutionRoute,
type ClusterPluginPackagePromptExecutionCapability,
} from '../plugin-package/prompt/pluginPackagePromptExecutionRoute';
import {
createClusterControlPluginPackagePromptCatalogRoute,
type ClusterPluginPackagePromptCatalogCapability,
} from '../plugin-package/prompt/pluginPackagePromptCatalogRoute';
import {
createClusterControlPluginPackagePromptOutputReadRoute,
type ClusterPluginPackagePromptOutputReadCapability,
} from '../plugin-package/prompt/pluginPackagePromptOutputReadRoute';
import {
createClusterControlPluginPackagePromptExecutionInspectionRoute,
type ClusterPluginPackagePromptExecutionInspectionCapability,
} from '../plugin-package/prompt/pluginPackagePromptExecutionInspectionRoute';
import {
createClusterControlPluginPackagePromptExecutionOutputReadRoute,
type ClusterPluginPackagePromptExecutionOutputReadCapability,
} from '../plugin-package/prompt/pluginPackagePromptExecutionOutputReadRoute';
import {
createClusterControlRunCancellationRoute,
type ClusterRunCancellationEventIdFactory,
} from '../run/runCancellationRoute';
import type { ClusterControlAssemblyInput } from './clusterControlRuntime';
import type { ClusterRemoteWorkerArtifactStore } from '../remote-execution/remoteWorkerCompletionService';
import type { EnabledClusterWorkerIngressConfig } from '../worker-ingress/workerIngressConfig';
import {
startProductionClusterWorkerIngress,
type ProductionClusterWorkerIngressOptions as ProductionClusterWorkerIngressStarterOptions,
} from '../worker-ingress/productionWorkerIngress';
import type { ClusterWorkerIngressApplicationResult } from '../worker-ingress/workerIngressApplication';
import { createClusterControlPluginPackageWorkflowRoutes } from '../plugin-package/workflow/pluginPackageWorkflowRoute';
export const PRODUCTION_CLUSTER_CONTROL_ROUTE_OPERATIONS = Object.freeze([
'task.get',
'task.list',
'task.start',
'run.get',
'run.list',
'run.events.list',
'run.steps.list',
'run.cancel',
'workflow.read',
'workflow.run.read',
'workflow.run.list',
'workflow.step.list',
'workflow.event.list',
'workflow.start',
'workflow.cancel',
] as const);
export const PRODUCTION_CLUSTER_CONTROL_OPTIONAL_ROUTE_OPERATIONS =
Object.freeze([
'prompt.read',
'prompt.execute',
'prompt.execution.read',
'prompt.execution.output.read',
'prompt.output.read',
] as const);
export interface ProductionClusterControlAssemblyOptions {
readonly createEventId?: ClusterRunCancellationEventIdFactory;
readonly promptCatalog?: Readonly<{
readonly capability: ClusterPluginPackagePromptCatalogCapability;
}>;
readonly promptExecution?: Readonly<{
readonly capability: ClusterPluginPackagePromptExecutionCapability;
readonly maxExecutionMs?: number;
readonly now?: () => number;
}>;
readonly promptExecutionInspection?: Readonly<{
readonly capability: ClusterPluginPackagePromptExecutionInspectionCapability;
readonly now?: () => number;
}>;
readonly promptOutputRead?: Readonly<{
readonly capability: ClusterPluginPackagePromptOutputReadCapability;
}>;
readonly promptExecutionOutputRead?: Readonly<{
readonly capability: ClusterPluginPackagePromptExecutionOutputReadCapability;
}>;
readonly workerIngress?: Readonly<{
readonly config: EnabledClusterWorkerIngressConfig;
readonly onDiagnostic?: (error: unknown) => void | Promise<void>;
}>;
readonly startWorkerIngress?: (
options: ProductionClusterWorkerIngressStarterOptions,
) => Promise<ClusterWorkerIngressApplicationResult>;
}
export interface ProductionClusterWorkerIngressOptions {
readonly config: EnabledClusterWorkerIngressConfig;
readonly artifactStore: ClusterRemoteWorkerArtifactStore;
readonly secretProvider?: RemoteWorkerSecretValueProvider;
readonly onDiagnostic?: (error: unknown) => void | Promise<void>;
}
export interface ProductionClusterControlApplicationOptions
extends Omit<
ClusterControlApplicationOptions,
| 'create'
| 'enabled'
| 'profile'
| 'apiCredentialPepper'
| 'openDatabase'
| 'availability'
| 'http'
| 'workerRuntime'
> {
readonly config: EnabledClusterControlConfig;
readonly createEventId?: ClusterRunCancellationEventIdFactory;
readonly promptCatalog?: Readonly<{
readonly capability: ClusterPluginPackagePromptCatalogCapability;
}>;
readonly promptExecution?: Readonly<{
readonly capability: ClusterPluginPackagePromptExecutionCapability;
}>;
readonly promptExecutionInspection?: Readonly<{
readonly capability: ClusterPluginPackagePromptExecutionInspectionCapability;
}>;
readonly promptOutputRead?: Readonly<{
readonly capability: ClusterPluginPackagePromptOutputReadCapability;
}>;
readonly promptExecutionOutputRead?: Readonly<{
readonly capability: ClusterPluginPackagePromptExecutionOutputReadCapability;
}>;
readonly workerIngress?: ProductionClusterWorkerIngressOptions;
}
const SAFE_RECOVERY: Readonly<ClusterControlStartupRecoverySummary> =
Object.freeze({ safe: true, remaining: 0, failed: 0 });
function eventIdFactory(
candidate: ClusterRunCancellationEventIdFactory | undefined,
): ClusterRunCancellationEventIdFactory {
if (candidate !== undefined && typeof candidate !== 'function') {
throw new TypeError(
'Production cluster-control event ID factory is invalid',
);
}
return candidate ?? randomUUID;
}
/**
* The reviewed production business surface. Bootstrap still owns PostgreSQL,
* startup recovery, the scheduler and cancellation convergence; this stack
* owns only the exact route allowlist and its admission pipeline.
*/
export function createProductionClusterControlApplicationStack(
input: ClusterControlAssemblyInput,
options: ProductionClusterControlAssemblyOptions = {},
): ClusterControlApplicationStack {
const createEventId = eventIdFactory(options.createEventId);
const workerIngressStarter =
options.startWorkerIngress ?? startProductionClusterWorkerIngress;
if (typeof workerIngressStarter !== 'function') {
throw new TypeError('Production Worker ingress starter is invalid');
}
const routeDefinitions = [
createClusterControlTaskReadRoute(input.taskDefinitions),
createClusterControlTaskListRoute(input.taskDefinitions),
createClusterControlTaskStartRoute(input.taskStart, createEventId),
createClusterControlRunReadRoute(input.runs),
createClusterControlRunListRoute(input.runs),
createClusterControlRunEventListRoute(input.runs),
createClusterControlRunStepListRoute(
input.runs,
input.trustedToolStorage.stepRuns,
),
createClusterControlRunCancellationRoute(
input.runCancellation,
createEventId,
),
...createClusterControlPluginPackageWorkflowRoutes(
input.workflowAdministration,
Date.now,
createEventId,
),
...(options.promptCatalog === undefined
? []
: [
createClusterControlPluginPackagePromptCatalogRoute(
options.promptCatalog.capability,
),
]),
...(options.promptExecution === undefined
? []
: [
createClusterControlPluginPackagePromptExecutionRoute(
options.promptExecution.capability,
{
...(options.promptExecution.maxExecutionMs === undefined
? {}
: { maxExecutionMs: options.promptExecution.maxExecutionMs }),
...(options.promptExecution.now === undefined
? {}
: { now: options.promptExecution.now }),
createEventId,
},
),
]),
...(options.promptExecutionInspection === undefined
? []
: [
createClusterControlPluginPackagePromptExecutionInspectionRoute(
options.promptExecutionInspection.capability,
{
...(options.promptExecutionInspection.now === undefined
? {}
: { now: options.promptExecutionInspection.now }),
createEventId,
},
),
]),
...(options.promptOutputRead === undefined
? []
: [
createClusterControlPluginPackagePromptOutputReadRoute(
options.promptOutputRead.capability,
),
]),
...(options.promptExecutionOutputRead === undefined
? []
: [
createClusterControlPluginPackagePromptExecutionOutputReadRoute(
options.promptExecutionOutputRead.capability,
),
]),
];
const routes = createClusterControlRouteRegistry(routeDefinitions);
const expectedRouteCount =
PRODUCTION_CLUSTER_CONTROL_ROUTE_OPERATIONS.length +
(options.promptCatalog === undefined ? 0 : 1) +
(options.promptExecution === undefined ? 0 : 1) +
(options.promptExecutionInspection === undefined ? 0 : 1) +
(options.promptOutputRead === undefined ? 0 : 1) +
(options.promptExecutionOutputRead === undefined ? 0 : 1);
if (routes.size !== expectedRouteCount) {
throw new Error('Production cluster-control route allowlist is incomplete');
}
const admission = createClusterControlAdmissionPipeline({
routes,
authenticator: input.authenticator,
policy: createClusterControlProjectPolicyAuthorizer(input.policies),
audit: input.securityAudit,
});
let workerIngress:
| Extract<ClusterWorkerIngressApplicationResult, { status: 'active' }>
| undefined;
let workerIngressStart:
| Promise<
Extract<ClusterWorkerIngressApplicationResult, { status: 'active' }>
>
| undefined;
let workerIngressUnavailable: unknown;
let workerIngressStop: Promise<'stopped'> | undefined;
const stopWorkerIngress = (): Promise<'stopped'> => {
if (!workerIngress) return Promise.resolve('stopped' as const);
workerIngressStop ??= workerIngress.stop();
return workerIngressStop;
};
const startWorkerIngress = async (): Promise<void> => {
const ingress = options.workerIngress;
if (!ingress) return;
if (!input.workerRuntime) {
throw new Error(
'Production Worker ingress requires an injected runtime service port',
);
}
workerIngressStart ??= (async () => {
const result = await workerIngressStarter({
config: ingress.config,
runtime: input.workerRuntime!,
onPoolError(error) {
workerIngressUnavailable ??= error;
void Promise.resolve(ingress.onDiagnostic?.(error)).catch(
() => undefined,
);
void stopWorkerIngress().catch(() => undefined);
},
});
if (result.status !== 'active') {
throw new Error('Production Worker ingress did not activate');
}
workerIngress = result;
if (workerIngressUnavailable !== undefined) {
await stopWorkerIngress();
throw new Error(
'Production Worker ingress database became unavailable during activation',
);
}
return result;
})();
await workerIngressStart;
};
return Object.freeze({
async reconcile(): Promise<ClusterControlStartupRecoverySummary> {
return SAFE_RECOVERY;
},
async startLifecycles(): Promise<boolean> {
await startWorkerIngress();
return true;
},
admission,
async stop(): Promise<ClusterControlStopResult> {
await stopWorkerIngress();
return 'stopped';
},
});
}
/** Starts cluster-control with the reviewed production route allowlist. */
export function startProductionClusterControlApplication(
options: ProductionClusterControlApplicationOptions,
): Promise<ClusterControlApplicationResult> {
const createEventId = eventIdFactory(options.createEventId);
const {
createEventId: _ignoredCreateEventId,
config,
workerIngress,
promptCatalog,
promptExecution,
promptExecutionInspection,
promptOutputRead,
promptExecutionOutputRead,
...applicationOptions
} = options;
const database = createClusterControlDatabaseBinding(config);
return startClusterControlApplication({
...applicationOptions,
enabled: true,
profile: 'cluster-control',
apiCredentialPepper: config.security.apiCredentialPepper,
http: config.http,
...(workerIngress === undefined
? {}
: {
workerRuntime: {
artifactStore: workerIngress.artifactStore,
...(workerIngress.secretProvider === undefined
? {}
: { secretProvider: workerIngress.secretProvider }),
},
}),
...database,
create: (input) =>
createProductionClusterControlApplicationStack(input, {
createEventId,
...(promptCatalog === undefined ? {} : { promptCatalog }),
...(promptExecution === undefined
? {}
: {
promptExecution: {
capability: promptExecution.capability,
maxExecutionMs: Math.max(
1,
(config.http.requestTimeoutMs ??
CLUSTER_CONTROL_HTTP_DEFAULTS.requestTimeoutMs) - 100,
),
},
}),
...(promptExecutionInspection === undefined
? {}
: { promptExecutionInspection }),
...(promptOutputRead === undefined ? {} : { promptOutputRead }),
...(promptExecutionOutputRead === undefined
? {}
: { promptExecutionOutputRead }),
...(workerIngress === undefined
? {}
: {
workerIngress: {
config: workerIngress.config,
...(workerIngress.onDiagnostic === undefined
? {}
: { onDiagnostic: workerIngress.onDiagnostic }),
},
}),
}),
});
}