@kici-dev/orchestrator 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "node:module";
2
2
  import { AgentDeliveryMode, AgentPlatform, BaseColdStore, ChunkRequestWaiter, RingBuffer, addLogsToArchive, chunkBuffer, computeBackoffDelay, computeMigrationsHash, createDb, createHealthRoutes, createLogger, createMeter, createMetricsRoutes, createPool, createS3Client, decrypt, decryptJson, deriveKey, encodeKeySegment, encrypt, enrichRequestContext, formatDuration, getPrometheusExporter, getReconnectDelay, getRequestContext, guardStartup, initTelemetry, isPgUniqueViolation, logger, parseDatabaseUrl, redactConfig, requestContext, serializeError, setServiceName, setupGracefulShutdown, sha256, storeMigrationContentHash, toErrorMessage, validateRequiredTools } from "@kici-dev/shared";
3
- import { ALLOWED_SYSTEM_VARS, ARTIFACT_NAME_MAX_LENGTH, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, AgentFailureCategory, ApprovalDecision, ArtifactCompleteAckOutcome, ArtifactDownloadOutcome, ArtifactUploadOutcome, AttestationOrigin, BREAKING_FLOOR, CANONICAL_STATUSES, CacheRefScope, CheckMode, CheckRunConclusion, CheckStepOutcome, ConcurrencyStrategy, ContextDeleteErrorCode, ContextGateRejectReason, DASHBOARD_REQUEST_TYPE_SET, DEFAULT_APPROVAL_EXPIRY_HOURS, DEFAULT_CONCURRENCY_STRATEGY, DEFAULT_HOLD_EXPIRY_SECONDS, DashboardResponseErrorCode, DeploymentContainerRuntimeSchema, DeploymentModeSchema, EVENT_LOG_PAYLOAD_CHUNK_BYTES, EventLogPayloadStreamError, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, FanoutCause, FanoutError, HeldRunQueueType, HoldScope, HoldType, INIT_LABEL, InitFailureCategory, InventorySelectorSchema, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, LabelMatcher, LockFileParseError, LogStream, MIN_PROTOCOL_VERSION, ORCH_AGENT_CAPABILITIES, ORCH_CAPABILITIES, OWN_INGRESS_MODES, OrchLogPhase, OrchRole, OrchestratorMode, PLATFORM_CONNECTED_MODES, PLATFORM_TAINT_LABELS, PLATFORM_TO_ORCH_RECOGNIZED_TYPES, PRIVILEGED_ROOT_LABEL, PROTOCOL_VERSION, PayloadOmittedReason, RELAY_INGRESS_MODES, RegisterableTriggerType, RunFailureClass, SCHEMA_VERSION, SECURITY_HOLD_JOB_IDS, SSH_TRANSPORT_CAPABILITY, ScalerBackendType, ScalerEventType, ScalerEventType as ScalerEventType$1, SourceOrigin, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, TimeoutReason, TriggerSource, VariantKind, WEBHOOK_RELAY_MAX_BODY_BYTES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_DISPATCH_ACK_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WebhookRelayResult, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentLabelOf, agentToOrchestratorMessageSchema, agentTypeLabel, approvalTimeoutSecondsSchema, artifactInvalidNameError, assertValidScopeName, attestationVerifyStatusSchema, buildTrustedPassthroughEnv, buildUnsupportedMessageNack, canonicalizeCapability, checkArtifactName, coerceDispatchInputs, collectDiscriminatorTypes, createWorkflowDecision, dashboardArtifactsListResponseSchema, dashboardAttestationGetResponseSchema, dashboardAttestationsListAllResponseSchema, dashboardAttestationsListResponseSchema, dashboardRunDetailApiResponseSchema, dashboardStepLogsApiResponseSchema, deriveOsArchLabels, derivePlatformTaints, fanoutEnvelopeFields, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, githubIngressPath, githubWebhookPath, hasPlatformCapability, hostLabel, hostSatisfiesTarget, hostToScalerPlatform, installGateJobId, isFailureStatus, isKnownCapability, isLockDynamicJobFn, isLockInlineValue, isLockParallelStep, isLockStaticJob, isSelfReportedLabel, joinRequestSchema, logPullPlatformToOrchSchema, matchAllWorkflows, matchScopePattern, matchWorkflowsForEvent, matcherSatisfiedBy, materializeFanout, materializeResolvedHosts, materializeResolvedMatrix, matrixEnvelopeFields, mergeOrderedMaps, minAccessLogWarmDays, minSecretAuditLogWarmDays, normalizePersistedHoldType, partitionMatchers, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, persistedHoldTypeSpellings, platformToOrchestratorMessageSchema, platformToOsArchLabels, platformToTaints, resolveRoleLabels, resolveScheduleInputs, resolveSecretsWithProvenance, scalerAgentLabels, scalerLabel, scalerPlatformSchema, scheduleTriggerKey, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, stateReplaySchema, stringifyActor, trustedContributorHoldReason, unknownContributorHoldReason, validateScopeName, wrapUntrusted } from "@kici-dev/engine";
3
+ import { ALLOWED_SYSTEM_VARS, ARTIFACT_NAME_MAX_LENGTH, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, AgentFailureCategory, ApprovalDecision, ArtifactCompleteAckOutcome, ArtifactDownloadOutcome, ArtifactUploadOutcome, AttestationOrigin, BREAKING_FLOOR, CANONICAL_STATUSES, CacheRefScope, CheckMode, CheckRunConclusion, CheckStepOutcome, ConcurrencyStrategy, ContextDeleteErrorCode, ContextGateRejectReason, DASHBOARD_REQUEST_TYPE_SET, DEFAULT_APPROVAL_EXPIRY_HOURS, DEFAULT_CONCURRENCY_STRATEGY, DEFAULT_HOLD_EXPIRY_SECONDS, DashboardResponseErrorCode, DeploymentContainerRuntimeSchema, DeploymentModeSchema, EVENT_LOG_PAYLOAD_CHUNK_BYTES, EventLogPayloadStreamError, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, FanoutCause, FanoutError, HeldRunQueueType, HoldScope, HoldType, INIT_LABEL, InitFailureCategory, InventorySelectorSchema, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, LabelMatcher, LockFileParseError, LogStream, MIN_PROTOCOL_VERSION, ORCH_AGENT_CAPABILITIES, ORCH_CAPABILITIES, OWN_INGRESS_MODES, OrchLogPhase, OrchRole, OrchestratorMode, PLATFORM_CONNECTED_MODES, PLATFORM_TAINT_LABELS, PLATFORM_TO_ORCH_RECOGNIZED_TYPES, PRIVILEGED_ROOT_LABEL, PROTOCOL_VERSION, PayloadOmittedReason, RELAY_INGRESS_MODES, RegisterableTriggerType, RunFailureClass, SCHEMA_VERSION, SECURITY_HOLD_JOB_IDS, SSH_TRANSPORT_CAPABILITY, ScalerBackendType, ScalerEventType, ScalerEventType as ScalerEventType$1, SourceOrigin, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, TimeoutReason, TriggerSource, VariantKind, WEBHOOK_RELAY_MAX_BODY_BYTES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_DISPATCH_ACK_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WebhookRelayResult, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentLabelOf, agentToOrchestratorMessageSchema, agentTypeLabel, approvalTimeoutSecondsSchema, artifactInvalidNameError, assertValidScopeName, assertValidSecretKey, attestationVerifyStatusSchema, buildTrustedPassthroughEnv, buildUnsupportedMessageNack, canonicalizeCapability, checkArtifactName, coerceDispatchInputs, collectDiscriminatorTypes, createWorkflowDecision, dashboardArtifactsListResponseSchema, dashboardAttestationGetResponseSchema, dashboardAttestationsListAllResponseSchema, dashboardAttestationsListResponseSchema, dashboardRunDetailApiResponseSchema, dashboardStepLogsApiResponseSchema, deriveOsArchLabels, derivePlatformTaints, fanoutEnvelopeFields, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, githubIngressPath, githubWebhookPath, hasPlatformCapability, hostLabel, hostSatisfiesTarget, hostToScalerPlatform, installGateJobId, isFailureStatus, isKnownCapability, isLockDynamicJobFn, isLockInlineValue, isLockParallelStep, isLockStaticJob, isSelfReportedLabel, joinRequestSchema, logPullPlatformToOrchSchema, matchAllWorkflows, matchScopePattern, matchWorkflowsForEvent, matcherSatisfiedBy, materializeFanout, materializeResolvedHosts, materializeResolvedMatrix, matrixEnvelopeFields, mergeOrderedMaps, minAccessLogWarmDays, minSecretAuditLogWarmDays, normalizePersistedHoldType, partitionMatchers, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, persistedHoldTypeSpellings, platformToOrchestratorMessageSchema, platformToOsArchLabels, platformToTaints, resolveRoleLabels, resolveScheduleInputs, resolveSecretsWithProvenance, scalerAgentLabels, scalerLabel, scalerPlatformSchema, scheduleTriggerKey, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, stateReplaySchema, stringifyActor, trustedContributorHoldReason, unknownContributorHoldReason, validateScopeName, validateSecretKey, wrapUntrusted } from "@kici-dev/engine";
4
4
  import { X509Certificate, createCipheriv, createDecipheriv, createHash, createHmac, createPrivateKey, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
5
5
  import * as fs$1 from "node:fs";
6
6
  import { chmodSync, closeSync, createReadStream, createWriteStream, fsyncSync, mkdirSync, mkdtempSync, openSync, promises, readFileSync, renameSync, rmSync, statSync, unwatchFile, watchFile, writeFileSync, writeSync } from "node:fs";
@@ -162,7 +162,7 @@ async function cancelRunWithReason(deps, runId, reason, options = {}) {
162
162
  const force = options.force ?? false;
163
163
  const runRow = await db.selectFrom("execution_runs").select(["status"]).where("run_id", "=", runId).executeTakeFirst();
164
164
  if (runRow && TERMINAL_RUN_STATES.has(runRow.status)) {
165
- logger$129.info("Cancel ignored: run already terminal", {
165
+ logger$131.info("Cancel ignored: run already terminal", {
166
166
  runId,
167
167
  status: runRow.status
168
168
  });
@@ -190,7 +190,7 @@ async function cancelRunWithReason(deps, runId, reason, options = {}) {
190
190
  }));
191
191
  agentsNotified++;
192
192
  } catch (err) {
193
- logger$129.warn("Failed to send job.cancel to agent; treating job as orphaned", {
193
+ logger$131.warn("Failed to send job.cancel to agent; treating job as orphaned", {
194
194
  runId,
195
195
  jobId,
196
196
  agentId,
@@ -201,7 +201,8 @@ async function cancelRunWithReason(deps, runId, reason, options = {}) {
201
201
  const pendingResult = await db.updateTable("execution_jobs").set({
202
202
  status: ExecutionJobStatus.enum.cancelled,
203
203
  completed_at: /* @__PURE__ */ new Date(),
204
- error_message: reason
204
+ error_message: reason,
205
+ routing_reason: null
205
206
  }).where("run_id", "=", runId).where("status", "in", [ExecutionJobStatus.enum.pending, ExecutionJobStatus.enum.queued]).execute();
206
207
  const pendingCancelled = Number(pendingResult[0]?.numUpdatedRows ?? 0);
207
208
  await jobQueue.cancelByRunId(runId);
@@ -220,7 +221,7 @@ async function cancelRunWithReason(deps, runId, reason, options = {}) {
220
221
  orphansCancelled = Number(orphanResult[0]?.numUpdatedRows ?? 0);
221
222
  await executionTracker.completeRunIfAllJobsTerminal(runId);
222
223
  }
223
- logger$129.info("Cancelled run", {
224
+ logger$131.info("Cancelled run", {
224
225
  runId,
225
226
  agentsNotified,
226
227
  pendingCancelled,
@@ -233,9 +234,9 @@ async function cancelRunWithReason(deps, runId, reason, options = {}) {
233
234
  alreadyTerminal: false
234
235
  };
235
236
  }
236
- var logger$129;
237
+ var logger$131;
237
238
  var init_cancel_run = __esmMin((() => {
238
- logger$129 = createLogger({ prefix: "cancel-run" });
239
+ logger$131 = createLogger({ prefix: "cancel-run" });
239
240
  }));
240
241
  //#endregion
241
242
  //#region src/cancel/dashboard-cancel-handler.ts
@@ -491,7 +492,7 @@ function readDeploymentIdentity(env = process.env, execPath = process.execPath,
491
492
  * `test.relay.uploads.init` relay handler — the developer never reaches the
492
493
  * orchestrator's HTTP API directly.
493
494
  */
494
- const logger$128 = createLogger({ prefix: "uploads" });
495
+ const logger$130 = createLogger({ prefix: "uploads" });
495
496
  /**
496
497
  * Sanitize a routing key for use in S3 storage paths.
497
498
  * Replaces characters that are problematic in S3 keys.
@@ -533,7 +534,7 @@ async function initTestUpload(deps, params) {
533
534
  expires_at: expiresAt,
534
535
  created_by: params.createdBy ?? null
535
536
  }).execute();
536
- logger$128.info("Upload initialized", {
537
+ logger$130.info("Upload initialized", {
537
538
  uploadId,
538
539
  routingKey,
539
540
  sha: sha ?? "unknown",
@@ -1092,6 +1093,7 @@ var prometheus_exports = /* @__PURE__ */ __exportAll({
1092
1093
  trustMatchRefusedNoIdTotal: () => trustMatchRefusedNoIdTotal,
1093
1094
  trustPolicyDecisionsTotal: () => trustPolicyDecisionsTotal,
1094
1095
  universalGitRegistrationErrorsTotal: () => universalGitRegistrationErrorsTotal,
1096
+ unroutableFastFailedTotal: () => unroutableFastFailedTotal,
1095
1097
  webhooksProcessedTotal: () => webhooksProcessedTotal,
1096
1098
  webhooksReceivedTotal: () => webhooksReceivedTotal,
1097
1099
  wsNackReceivedTotal: () => wsNackReceivedTotal,
@@ -1276,7 +1278,7 @@ function registerOrchestratorMetrics() {
1276
1278
  _observableGaugesRegistered = true;
1277
1279
  for (const register of _observableGauges) register();
1278
1280
  }
1279
- var _meter$1, _observableGauges, _agentsActiveValue, _configVersionValue, _drainingValue, _declaredHostsUnreachableValue, _staleRunsCurrentValue, _pendingAttestationsValue, _pendingAttestationOldestAgeSeconds, _rejectedAttestationsValue, _dbCollationDrift, _scalerUsageRows, _scalerSpawnRefusalsValue, scalerRedispatchTotal, _queueDepthBreakdown, _everSeenQueueLabels, EMPTY_INGEST_STATE, _ingest, _ingestLimits, ingestShedTotal, stateReplayBreakerTripsTotal, ingestAdmittedTotal, _overflowBuffered, ingestOverflowCapturedTotal, ingestOverflowReplayedTotal, ingestOverflowDroppedTotal, webhooksReceivedTotal, webhooksProcessedTotal, trustPolicyDecisionsTotal, triggerMatchDurationSeconds, dedupHitsTotal, pgPoolClientErrorsTotal, sourceCacheHitsTotal, sourceCacheMissesTotal, depCacheHitsTotal, depCacheMissesTotal, buildDurationSeconds, executionsTotal, executionDurationSeconds, stepsTotal, githubCheckRunTotal, logChunksReceivedTotal, logBytesStoredTotal, scalerConfigReloadsTotal, ScalerSpawnFailureBound, scalerSpawnFailuresTotal, configReloadTotal, staleRunsDetectedTotal, staleDetectionDurationSeconds, crossSourceFanoutSize, crossSourceErrorsTotal, universalGitRegistrationErrorsTotal, trustMatchRefusedNoIdTotal, eventDispatchSuccessTotal, eventRetryTotal, eventDlqTotal, eventLeaseExpirationsTotal, eventAttemptsHistogram, _eventDlqDepthValue, InstallSecretsDecisionReason, InstallSecretsChannel, installSecretsDecisionsTotal, installSecretsRegistryUsedTotal, installSecretsContributorStrippedTotal, installSecretsTokenResolutionDurationSeconds, dispatchQueueRowsPrunedTotal, stepLogsPrunedTotal, checkRunTrackingRowsPrunedTotal, wsUnsupportedMessageSentTotal, wsNackReceivedTotal, wsPlatformCapabilityGapTotal, _observableGaugesRegistered;
1281
+ var _meter$1, _observableGauges, _agentsActiveValue, _configVersionValue, _drainingValue, _declaredHostsUnreachableValue, _staleRunsCurrentValue, _pendingAttestationsValue, _pendingAttestationOldestAgeSeconds, _rejectedAttestationsValue, _dbCollationDrift, _scalerUsageRows, _scalerSpawnRefusalsValue, scalerRedispatchTotal, _queueDepthBreakdown, _everSeenQueueLabels, EMPTY_INGEST_STATE, _ingest, _ingestLimits, ingestShedTotal, stateReplayBreakerTripsTotal, ingestAdmittedTotal, _overflowBuffered, ingestOverflowCapturedTotal, ingestOverflowReplayedTotal, ingestOverflowDroppedTotal, webhooksReceivedTotal, webhooksProcessedTotal, trustPolicyDecisionsTotal, triggerMatchDurationSeconds, dedupHitsTotal, pgPoolClientErrorsTotal, sourceCacheHitsTotal, sourceCacheMissesTotal, depCacheHitsTotal, depCacheMissesTotal, buildDurationSeconds, executionsTotal, executionDurationSeconds, stepsTotal, githubCheckRunTotal, logChunksReceivedTotal, logBytesStoredTotal, scalerConfigReloadsTotal, ScalerSpawnFailureBound, scalerSpawnFailuresTotal, configReloadTotal, staleRunsDetectedTotal, staleDetectionDurationSeconds, crossSourceFanoutSize, crossSourceErrorsTotal, universalGitRegistrationErrorsTotal, trustMatchRefusedNoIdTotal, eventDispatchSuccessTotal, eventRetryTotal, eventDlqTotal, eventLeaseExpirationsTotal, eventAttemptsHistogram, _eventDlqDepthValue, InstallSecretsDecisionReason, InstallSecretsChannel, installSecretsDecisionsTotal, installSecretsRegistryUsedTotal, installSecretsContributorStrippedTotal, installSecretsTokenResolutionDurationSeconds, dispatchQueueRowsPrunedTotal, unroutableFastFailedTotal, stepLogsPrunedTotal, checkRunTrackingRowsPrunedTotal, wsUnsupportedMessageSentTotal, wsNackReceivedTotal, wsPlatformCapabilityGapTotal, _observableGaugesRegistered;
1280
1282
  var init_prometheus = __esmMin((() => {
1281
1283
  _observableGauges = [];
1282
1284
  _agentsActiveValue = 0;
@@ -1533,6 +1535,7 @@ var init_prometheus = __esmMin((() => {
1533
1535
  ] }
1534
1536
  });
1535
1537
  dispatchQueueRowsPrunedTotal = lazyCounter$1("kici_orch_dispatch_queue_rows_pruned_total", { description: "Terminal dispatch_queue rows deleted by the retention sweep" });
1538
+ unroutableFastFailedTotal = lazyCounter$1("kici_orch_unroutable_fast_failed_total", { description: "Jobs terminalized as unroutable by the fast-fail probe (not the queue timeout)" });
1536
1539
  stepLogsPrunedTotal = lazyCounter$1("kici_orch_step_logs_pruned_total", { description: "Step-log objects deleted by the retention sweep" });
1537
1540
  checkRunTrackingRowsPrunedTotal = lazyCounter$1("kici_orch_check_run_tracking_rows_pruned_total", { description: "check_run_tracking rows deleted by the retention sweep" });
1538
1541
  wsUnsupportedMessageSentTotal = lazyCounter$1("kici_orch_ws_unsupported_message_sent_total", { description: "NACKs sent to the Platform for an unrecognized inbound message type (version skew)" });
@@ -1565,7 +1568,7 @@ var trust_resolver_exports = /* @__PURE__ */ __exportAll({
1565
1568
  function findIdentityLink(identityLinks, provider, providerUsername, providerUserId) {
1566
1569
  if (providerUserId === void 0 || providerUserId.length === 0) {
1567
1570
  trustMatchRefusedNoIdTotal.add(1, { reason: "event_missing" });
1568
- logger$127.warn("Trust match refused: webhook event has no provider numeric id", {
1571
+ logger$129.warn("Trust match refused: webhook event has no provider numeric id", {
1569
1572
  provider,
1570
1573
  providerUsername
1571
1574
  });
@@ -1577,7 +1580,7 @@ function findIdentityLink(identityLinks, provider, providerUsername, providerUse
1577
1580
  if (byUsername) {
1578
1581
  const reason = byUsername.providerUserId === null || byUsername.providerUserId === void 0 ? "link_missing" : "id_mismatch";
1579
1582
  trustMatchRefusedNoIdTotal.add(1, { reason });
1580
- logger$127.warn("Trust match refused: numeric id missing on link or did not match event", {
1583
+ logger$129.warn("Trust match refused: numeric id missing on link or did not match event", {
1581
1584
  provider,
1582
1585
  providerUsername,
1583
1586
  providerUserId,
@@ -1605,10 +1608,10 @@ function isReadOrHigher(permission) {
1605
1608
  function isCiTrustWriteOrHigher(level) {
1606
1609
  return level === "write" || level === "admin";
1607
1610
  }
1608
- var logger$127, TrustResolver$1;
1611
+ var logger$129, TrustResolver$1;
1609
1612
  var init_trust_resolver = __esmMin((() => {
1610
1613
  init_prometheus();
1611
- logger$127 = createLogger({ prefix: "trust-resolver" });
1614
+ logger$129 = createLogger({ prefix: "trust-resolver" });
1612
1615
  TrustResolver$1 = class {
1613
1616
  contributorCache;
1614
1617
  constructor(contributorCache) {
@@ -1739,14 +1742,14 @@ async function handleApprovalComment(params) {
1739
1742
  const { commentBody, commenterUsername, commenterUserId, provider, repoIdentifier, prNumber, orgId, identityLinks, orgMemberPermissions, heldRunStore } = params;
1740
1743
  const command = parseKiciCommand(commentBody);
1741
1744
  if (!command) return { handled: false };
1742
- logger$126.info("Processing /kici command", {
1745
+ logger$128.info("Processing /kici command", {
1743
1746
  action: command.action,
1744
1747
  commenter: commenterUsername,
1745
1748
  runId: command.runId
1746
1749
  });
1747
1750
  const identityLink = findIdentityLink(identityLinks, provider, commenterUsername, commenterUserId);
1748
1751
  if (!identityLink) {
1749
- logger$126.info("No identity link for commenter", {
1752
+ logger$128.info("No identity link for commenter", {
1750
1753
  commenter: commenterUsername,
1751
1754
  provider
1752
1755
  });
@@ -1757,7 +1760,7 @@ async function handleApprovalComment(params) {
1757
1760
  }
1758
1761
  const ciTrustLevel = orgMemberPermissions.get(identityLink.userId) ?? "none";
1759
1762
  if (ciTrustLevel !== "write" && ciTrustLevel !== "admin") {
1760
- logger$126.info("Insufficient ci_trust level", {
1763
+ logger$128.info("Insufficient ci_trust level", {
1761
1764
  commenter: commenterUsername,
1762
1765
  userId: identityLink.userId,
1763
1766
  ciTrustLevel
@@ -1769,7 +1772,7 @@ async function handleApprovalComment(params) {
1769
1772
  }
1770
1773
  const pendingHolds = await heldRunStore.listPendingSecurityHoldsForPr(orgId, repoIdentifier, prNumber);
1771
1774
  if (pendingHolds.length === 0) {
1772
- logger$126.info("No pending security holds found for PR", {
1775
+ logger$128.info("No pending security holds found for PR", {
1773
1776
  orgId,
1774
1777
  repoIdentifier,
1775
1778
  prNumber
@@ -1778,7 +1781,7 @@ async function handleApprovalComment(params) {
1778
1781
  }
1779
1782
  const targetHolds = command.runId ? pendingHolds.filter((h) => h.run_id === command.runId) : pendingHolds;
1780
1783
  if (targetHolds.length === 0) {
1781
- logger$126.info("No matching security holds found", {
1784
+ logger$128.info("No matching security holds found", {
1782
1785
  orgId,
1783
1786
  runId: command.runId
1784
1787
  });
@@ -1789,14 +1792,14 @@ async function handleApprovalComment(params) {
1789
1792
  for (const hold of targetHolds) try {
1790
1793
  if (approved) {
1791
1794
  await heldRunStore.approveByQueueType(orgId, hold.id, identityLink.userId, "security");
1792
- logger$126.info("Security hold approved", {
1795
+ logger$128.info("Security hold approved", {
1793
1796
  heldRunId: hold.id,
1794
1797
  runId: hold.run_id,
1795
1798
  approvedBy: identityLink.userId
1796
1799
  });
1797
1800
  } else {
1798
1801
  await heldRunStore.reject(orgId, hold.id, `Rejected by ${commenterUsername} via /kici reject`);
1799
- logger$126.info("Security hold rejected", {
1802
+ logger$128.info("Security hold rejected", {
1800
1803
  heldRunId: hold.id,
1801
1804
  runId: hold.run_id,
1802
1805
  rejectedBy: commenterUsername
@@ -1804,7 +1807,7 @@ async function handleApprovalComment(params) {
1804
1807
  }
1805
1808
  processedCount++;
1806
1809
  } catch (err) {
1807
- logger$126.error("Failed to process security hold", {
1810
+ logger$128.error("Failed to process security hold", {
1808
1811
  heldRunId: hold.id,
1809
1812
  action: command.action,
1810
1813
  error: toErrorMessage(err)
@@ -1814,15 +1817,15 @@ async function handleApprovalComment(params) {
1814
1817
  const title = approved ? "Approved" : "Rejected";
1815
1818
  const summary = approved ? `Approved by ${commenterUsername} via /kici approve` : `Rejected by ${commenterUsername} via /kici reject`;
1816
1819
  params.checkStatusPoster.postCheckStatus(params.repoIdentifier, params.commitSha, approved ? "success" : "failure", title, summary, params.credentials).catch((err) => {
1817
- logger$126.warn("Failed to update check status after approval", { error: toErrorMessage(err) });
1820
+ logger$128.warn("Failed to update check status after approval", { error: toErrorMessage(err) });
1818
1821
  });
1819
1822
  }
1820
1823
  return { handled: true };
1821
1824
  }
1822
- var logger$126;
1825
+ var logger$128;
1823
1826
  var init_comment_handler = __esmMin((() => {
1824
1827
  init_trust_resolver();
1825
- logger$126 = createLogger({ prefix: "comment-handler" });
1828
+ logger$128 = createLogger({ prefix: "comment-handler" });
1826
1829
  }));
1827
1830
  //#endregion
1828
1831
  //#region src/registration/extractor.ts
@@ -1916,9 +1919,9 @@ function payloadFromObject$1(payload) {
1916
1919
  function payloadFromRawBody(body) {
1917
1920
  return { raw: Buffer.from(body, "utf-8") };
1918
1921
  }
1919
- var logger$125, EventLogWriter;
1922
+ var logger$127, EventLogWriter;
1920
1923
  var init_event_log$1 = __esmMin((() => {
1921
- logger$125 = createLogger({ prefix: "event-log" });
1924
+ logger$127 = createLogger({ prefix: "event-log" });
1922
1925
  EventLogWriter = class EventLogWriter {
1923
1926
  db;
1924
1927
  logStorage;
@@ -1955,7 +1958,7 @@ var init_event_log$1 = __esmMin((() => {
1955
1958
  if (sizeBytes > maxBytes) {
1956
1959
  payloadOmitted = true;
1957
1960
  payloadOmittedReason = PayloadOmittedReason.enum.size_exceeded;
1958
- logger$125.warn("Webhook payload exceeds soft cap; recording metadata only", {
1961
+ logger$127.warn("Webhook payload exceeds soft cap; recording metadata only", {
1959
1962
  deliveryId: info.deliveryId,
1960
1963
  sizeBytes,
1961
1964
  maxBytes
@@ -1969,7 +1972,7 @@ var init_event_log$1 = __esmMin((() => {
1969
1972
  } catch (err) {
1970
1973
  payloadOmitted = true;
1971
1974
  payloadOmittedReason = PayloadOmittedReason.enum.storage_failed;
1972
- logger$125.error("Failed to upload event-log payload to object storage", {
1975
+ logger$127.error("Failed to upload event-log payload to object storage", {
1973
1976
  deliveryId: info.deliveryId,
1974
1977
  orgId: outcome.orgId,
1975
1978
  error: toErrorMessage(err)
@@ -2006,7 +2009,7 @@ var init_event_log$1 = __esmMin((() => {
2006
2009
  ref: row.ref
2007
2010
  })).execute();
2008
2011
  } catch (err) {
2009
- logger$125.error("Failed to record event_log row", {
2012
+ logger$127.error("Failed to record event_log row", {
2010
2013
  deliveryId: info.deliveryId,
2011
2014
  orgId: outcome.orgId,
2012
2015
  error: toErrorMessage(err)
@@ -2764,6 +2767,7 @@ var init_schema = __esmMin((() => {
2764
2767
  rosterTtlMs: z.coerce.number().default(18e5),
2765
2768
  queueMaxDepth: z.coerce.number().default(1e3),
2766
2769
  queueTimeoutMs: z.coerce.number().default(36e5),
2770
+ unroutableGraceMs: z.coerce.number().default(12e4),
2767
2771
  /**
2768
2772
  * Operator-facing backpressure warning threshold. See `configSchema` in
2769
2773
  * `packages/orchestrator/src/config.ts` for the user-facing prose.
@@ -3243,6 +3247,7 @@ function flattenToAppConfig(merged) {
3243
3247
  const queue = merged.queue;
3244
3248
  flat.queueMaxDepth = queue?.maxDepth ?? 1e3;
3245
3249
  flat.queueTimeoutMs = queue?.timeoutMs ?? 36e5;
3250
+ flat.unroutableGraceMs = queue?.unroutableGraceMs ?? 12e4;
3246
3251
  flat.queueBackpressureThreshold = queue?.backpressureThreshold ?? 100;
3247
3252
  const lfCache = merged.lockfileCache;
3248
3253
  flat.lockfileCacheMax = lfCache?.max ?? 500;
@@ -3334,9 +3339,9 @@ function satisfiesMandatoryLabels(agent, requiredLabels) {
3334
3339
  for (const label of agent.mandatoryLabels) if (!requiredSet.has(label)) return false;
3335
3340
  return true;
3336
3341
  }
3337
- var logger$124, AgentRegistry;
3342
+ var logger$126, AgentRegistry;
3338
3343
  var init_registry = __esmMin((() => {
3339
- logger$124 = createLogger({ prefix: "agent-registry" });
3344
+ logger$126 = createLogger({ prefix: "agent-registry" });
3340
3345
  AgentRegistry = class {
3341
3346
  /** Primary: agentId -> AgentEntry */
3342
3347
  agents = /* @__PURE__ */ new Map();
@@ -3459,7 +3464,7 @@ var init_registry = __esmMin((() => {
3459
3464
  arch,
3460
3465
  instanceId,
3461
3466
  properties: metadata?.properties
3462
- }).catch((err) => logger$124.warn("host_roster upsert failed (best-effort)", {
3467
+ }).catch((err) => logger$126.warn("host_roster upsert failed (best-effort)", {
3463
3468
  agentId,
3464
3469
  error: toErrorMessage(err)
3465
3470
  }));
@@ -3854,9 +3859,9 @@ var init_leader_gated_scheduler = __esmMin((() => {
3854
3859
  * Driven by the leader-only host-roster reaper's tick (one timer, one leader),
3855
3860
  * so this class owns no timer of its own — just a testable `scan()`.
3856
3861
  */
3857
- var logger$123, RebootDeadlineSweep;
3862
+ var logger$125, RebootDeadlineSweep;
3858
3863
  var init_reboot_deadline_sweep = __esmMin((() => {
3859
- logger$123 = createLogger({ prefix: "reboot-deadline-sweep" });
3864
+ logger$125 = createLogger({ prefix: "reboot-deadline-sweep" });
3860
3865
  RebootDeadlineSweep = class {
3861
3866
  rosterStore;
3862
3867
  constructor(deps) {
@@ -3868,21 +3873,21 @@ var init_reboot_deadline_sweep = __esmMin((() => {
3868
3873
  const expired = await this.rosterStore.listExpiredRebootPending(Date.now());
3869
3874
  for (const agentId of expired) {
3870
3875
  await this.rosterStore.clearRebootPending(agentId);
3871
- logger$123.warn("Host did not return after reboot within deadline; cleared reboot-pending", { agentId });
3876
+ logger$125.warn("Host did not return after reboot within deadline; cleared reboot-pending", { agentId });
3872
3877
  }
3873
3878
  } catch (err) {
3874
- logger$123.error("Reboot deadline sweep error", { error: toErrorMessage(err) });
3879
+ logger$125.error("Reboot deadline sweep error", { error: toErrorMessage(err) });
3875
3880
  }
3876
3881
  }
3877
3882
  };
3878
3883
  }));
3879
3884
  //#endregion
3880
3885
  //#region src/agent/host-roster-reaper.ts
3881
- var logger$122, HostRosterReaper;
3886
+ var logger$124, HostRosterReaper;
3882
3887
  var init_host_roster_reaper = __esmMin((() => {
3883
3888
  init_leader_gated_scheduler();
3884
3889
  init_reboot_deadline_sweep();
3885
- logger$122 = createLogger({ prefix: "host-roster-reaper" });
3890
+ logger$124 = createLogger({ prefix: "host-roster-reaper" });
3886
3891
  HostRosterReaper = class {
3887
3892
  store;
3888
3893
  ttlMs;
@@ -3901,7 +3906,7 @@ var init_host_roster_reaper = __esmMin((() => {
3901
3906
  this.scheduler = new LeaderGatedScheduler({
3902
3907
  name: "host roster reaper",
3903
3908
  intervalMs: this.scanIntervalMs,
3904
- logger: logger$122,
3909
+ logger: logger$124,
3905
3910
  tick: () => this.tick()
3906
3911
  });
3907
3912
  }
@@ -3918,10 +3923,10 @@ var init_host_roster_reaper = __esmMin((() => {
3918
3923
  async tick() {
3919
3924
  if (!this.scheduler.isLeader) return;
3920
3925
  const deleted = await this.store.reapEphemeralPastTtl(this.ttlMs);
3921
- if (deleted > 0) logger$122.info("Reaped expired ephemeral hosts", { deleted });
3926
+ if (deleted > 0) logger$124.info("Reaped expired ephemeral hosts", { deleted });
3922
3927
  const unreachable = await this.store.countStaticUnreachable(this.graceMs);
3923
3928
  this.setUnreachableGauge(unreachable);
3924
- if (unreachable > 0) logger$122.warn("Declared hosts unreachable", { count: unreachable });
3929
+ if (unreachable > 0) logger$124.warn("Declared hosts unreachable", { count: unreachable });
3925
3930
  await this.rebootSweep.scan();
3926
3931
  }
3927
3932
  };
@@ -3929,6 +3934,22 @@ var init_host_roster_reaper = __esmMin((() => {
3929
3934
  //#endregion
3930
3935
  //#region src/queue/job-queue.ts
3931
3936
  /**
3937
+ * Shared row -> {@link ExpiredJobInfo} mapping, so the expiry sweep and the
3938
+ * unroutable probe can never read a job's selectors differently.
3939
+ */
3940
+ function rowToExpiredJobInfo(r) {
3941
+ return {
3942
+ id: r.id,
3943
+ runId: r.run_id,
3944
+ jobName: r.job_name,
3945
+ lastProvisioningError: r.last_provisioning_error ?? null,
3946
+ runsOnLabels: parseSelectorColumnForExpiry(r.runs_on_labels, "runs_on_labels"),
3947
+ runsOnPatterns: parseSelectorColumnForExpiry(r.runs_on_patterns, "runs_on_patterns"),
3948
+ excludeLabels: parseSelectorColumnForExpiry(r.exclude_labels, "exclude_labels"),
3949
+ excludePatterns: parseSelectorColumnForExpiry(r.exclude_patterns, "exclude_patterns")
3950
+ };
3951
+ }
3952
+ /**
3932
3953
  * Parse a `dispatch_queue` jsonb pattern column into a `LabelMatcher[]`. Handles
3933
3954
  * both the auto-parsed array form (from the pg driver) and the JSON string form
3934
3955
  * (from tests / a non-parsing driver). A missing value yields `[]`.
@@ -3959,9 +3980,9 @@ function parseSelectorColumnForExpiry(v, column) {
3959
3980
  if (typeof v === "string") try {
3960
3981
  const parsed = JSON.parse(v);
3961
3982
  if (Array.isArray(parsed)) return parsed;
3962
- logger$121.warn("dispatch_queue selector column is not a JSON array", { column });
3983
+ logger$123.warn("dispatch_queue selector column is not a JSON array", { column });
3963
3984
  } catch {
3964
- logger$121.warn("dispatch_queue selector column holds malformed JSON", { column });
3985
+ logger$123.warn("dispatch_queue selector column holds malformed JSON", { column });
3965
3986
  }
3966
3987
  return [];
3967
3988
  }
@@ -3976,9 +3997,9 @@ function jobPatternsSatisfiedBy(job, labels) {
3976
3997
  if (job.excludePatterns.some((p) => matcherSatisfiedBy(p, labels))) return false;
3977
3998
  return true;
3978
3999
  }
3979
- var logger$121, JobQueue;
4000
+ var logger$123, JobQueue;
3980
4001
  var init_job_queue = __esmMin((() => {
3981
- logger$121 = createLogger({ prefix: "job-queue" });
4002
+ logger$123 = createLogger({ prefix: "job-queue" });
3982
4003
  JobQueue = class {
3983
4004
  db;
3984
4005
  /** Cluster-wide fallback for queue_max_depth when cluster_settings is null. */
@@ -4287,16 +4308,7 @@ var init_job_queue = __esmMin((() => {
4287
4308
  ]).where("status", "=", "pending").where("expires_at", "is not", null).where("expires_at", "<", now).execute();
4288
4309
  if (rows.length === 0) return [];
4289
4310
  await this.db.updateTable("dispatch_queue").set({ status: "expired" }).where("id", "in", rows.map((r) => r.id)).execute();
4290
- return rows.map((r) => ({
4291
- id: r.id,
4292
- runId: r.run_id,
4293
- jobName: r.job_name,
4294
- lastProvisioningError: r.last_provisioning_error ?? null,
4295
- runsOnLabels: parseSelectorColumnForExpiry(r.runs_on_labels, "runs_on_labels"),
4296
- runsOnPatterns: parseSelectorColumnForExpiry(r.runs_on_patterns, "runs_on_patterns"),
4297
- excludeLabels: parseSelectorColumnForExpiry(r.exclude_labels, "exclude_labels"),
4298
- excludePatterns: parseSelectorColumnForExpiry(r.exclude_patterns, "exclude_patterns")
4299
- }));
4311
+ return rows.map((r) => rowToExpiredJobInfo(r));
4300
4312
  }
4301
4313
  /**
4302
4314
  * Bulk-fail every still-non-terminal dispatch_queue entry for a run.
@@ -4571,7 +4583,8 @@ var init_job_queue = __esmMin((() => {
4571
4583
  dispatch_attempts: sql`dispatch_attempts + 1`,
4572
4584
  ack_deadline: null,
4573
4585
  ack_agent_id: null,
4574
- agent_id: null
4586
+ agent_id: null,
4587
+ unroutable_since: null
4575
4588
  }).where("id", "=", jobId).where("status", "=", "dispatched").returning("dispatch_attempts").executeTakeFirst();
4576
4589
  this.depthCache = null;
4577
4590
  this.breakdownCache = null;
@@ -4694,6 +4707,59 @@ var init_job_queue = __esmMin((() => {
4694
4707
  return (await this.pendingOldestFirstQuery().limit(limit).execute()).map((row) => this.rowToQueuedJob(row));
4695
4708
  }
4696
4709
  /**
4710
+ * Pending, non-expired jobs with the facts the unroutable probe needs:
4711
+ * routing selectors, any recorded provisioning error, and the grace clock.
4712
+ *
4713
+ * Read-only — no claim, no `FOR UPDATE`; the probe never dispatches. Reuses
4714
+ * the shared pending query so it inherits the same FIFO ordering and
4715
+ * not-yet-expired filter the rest of the queue uses.
4716
+ */
4717
+ async listUnroutableCandidates(limit) {
4718
+ return (await this.pendingOldestFirstQuery().limit(limit).execute()).map((row) => ({
4719
+ ...rowToExpiredJobInfo(row),
4720
+ unroutableSince: row.unroutable_since ? new Date(row.unroutable_since) : null
4721
+ }));
4722
+ }
4723
+ /**
4724
+ * Stamp the grace clock the first time a job reads unroutable.
4725
+ *
4726
+ * The `unroutable_since IS NULL` guard is load-bearing, not defensive: the
4727
+ * cleanup/probe ticks are NOT leader-gated, so without it two coordinators
4728
+ * would each re-stamp `now` on every tick, pushing the deadline outward
4729
+ * forever and preventing the grace from ever elapsing.
4730
+ */
4731
+ async markUnroutableSince(id, at) {
4732
+ await this.db.updateTable("dispatch_queue").set({ unroutable_since: at }).where("id", "=", id).where("unroutable_since", "is", null).execute();
4733
+ }
4734
+ /** Clear the grace clock after the job reads routable again. */
4735
+ async clearUnroutableState(id) {
4736
+ await this.db.updateTable("dispatch_queue").set({ unroutable_since: null }).where("id", "=", id).execute();
4737
+ }
4738
+ /**
4739
+ * Claim a still-pending row for fast-fail, moving it out of the queue.
4740
+ *
4741
+ * Mirrors {@link markExpired}: the queue row has to leave `Pending` in the
4742
+ * same breath the job is terminalized, and for the same two reasons.
4743
+ * A row left pending is still dispatchable, so an agent connecting later
4744
+ * would pick up a job whose `execution_jobs` row already reads terminal; and
4745
+ * the probe re-lists it on every tick, re-running the whole terminalize path
4746
+ * (and re-counting the fast-fail metric) until the queue timeout finally
4747
+ * expires it.
4748
+ *
4749
+ * The `status = Pending` guard is also the concurrency arbiter — probe ticks
4750
+ * are NOT leader-gated, so exactly one coordinator's UPDATE hits a row and
4751
+ * the losers get `false` and move on.
4752
+ *
4753
+ * @returns true when this call claimed the row, false when it was already
4754
+ * dispatched, cancelled, expired, or claimed by another coordinator.
4755
+ */
4756
+ async claimUnroutable(id) {
4757
+ const result = await this.db.updateTable("dispatch_queue").set({ status: "expired" }).where("id", "=", id).where("status", "=", "pending").executeTakeFirst();
4758
+ this.depthCache = null;
4759
+ this.breakdownCache = null;
4760
+ return Number(result.numUpdatedRows ?? 0) > 0;
4761
+ }
4762
+ /**
4697
4763
  * Convert a DB row to a QueuedJob object.
4698
4764
  * Handles both auto-parsed JSONB arrays (from pg driver) and JSON strings (from tests).
4699
4765
  */
@@ -4732,6 +4798,82 @@ var init_job_queue = __esmMin((() => {
4732
4798
  };
4733
4799
  }));
4734
4800
  //#endregion
4801
+ //#region src/reporting/log-retention.ts
4802
+ /**
4803
+ * Delete step-log objects older than `ttlDays` in one bulk pass.
4804
+ *
4805
+ * Step-log objects are write-once (appended during the run, untouched after
4806
+ * finalize), so last-modified time is the correct expiry basis — a recent or
4807
+ * still-running run's objects were all written within the window and survive.
4808
+ * `ttlDays <= 0` disables the sweep (returns 0). Expired objects are collected
4809
+ * then bulk-deleted via `deleteMany` (S3 DeleteObjects), so a large sweep is a
4810
+ * handful of API calls, not one-per-object. A delete failure is logged and the
4811
+ * cleanup tick is not aborted.
4812
+ *
4813
+ * @returns Number of objects deleted.
4814
+ */
4815
+ async function pruneExpiredLogs(storage, ttlDays, now = /* @__PURE__ */ new Date()) {
4816
+ if (ttlDays <= 0) return 0;
4817
+ const cutoff = now.getTime() - ttlDays * 864e5;
4818
+ const expired = (await storage.listWithMetadata(LOG_ROOT_PREFIX)).filter((o) => o.lastModified.getTime() < cutoff).map((o) => o.path);
4819
+ if (expired.length === 0) return 0;
4820
+ try {
4821
+ return await storage.deleteMany(expired);
4822
+ } catch (err) {
4823
+ logger$122.error("Failed to bulk-delete expired log objects", {
4824
+ count: expired.length,
4825
+ error: toErrorMessage(err)
4826
+ });
4827
+ return 0;
4828
+ }
4829
+ }
4830
+ var logger$122, LOG_ROOT_PREFIX;
4831
+ var init_log_retention = __esmMin((() => {
4832
+ logger$122 = createLogger({ prefix: "log-retention" });
4833
+ LOG_ROOT_PREFIX = "executions/";
4834
+ }));
4835
+ //#endregion
4836
+ //#region src/pipeline/request-idempotency.ts
4837
+ /**
4838
+ * Atomically claim a run-minting request by its Platform `requestId`. Returns
4839
+ * the run id to use. `claimed: false` means a sibling coordinator already owns
4840
+ * this requestId (a relay failover re-sent the same request): the caller MUST
4841
+ * return `{ newRunId }` WITHOUT creating or dispatching a run, so one user
4842
+ * click yields exactly one run.
4843
+ *
4844
+ * Shared by `run.rerun.request` and `run.manual_schedule.request` — both mint a
4845
+ * fresh run and both ride the Platform's timeout-driven failover path. HA
4846
+ * coordinator siblings share one orchestrator DB, so the `INSERT … ON CONFLICT
4847
+ * (request_id) DO NOTHING` is the single point of arbitration: exactly one hop
4848
+ * inserts and wins; the loser reads back the winner's `new_run_id`.
4849
+ */
4850
+ async function claimRequestId(db, requestId) {
4851
+ const candidate = randomUUID();
4852
+ if (await db.insertInto("request_idempotency").values({
4853
+ request_id: requestId,
4854
+ new_run_id: candidate
4855
+ }).onConflict((oc) => oc.column("request_id").doNothing()).returning("new_run_id").executeTakeFirst()) return {
4856
+ newRunId: candidate,
4857
+ claimed: true
4858
+ };
4859
+ return {
4860
+ newRunId: (await db.selectFrom("request_idempotency").select("new_run_id").where("request_id", "=", requestId).executeTakeFirstOrThrow()).new_run_id,
4861
+ claimed: false
4862
+ };
4863
+ }
4864
+ /**
4865
+ * Prune `request_idempotency` rows older than 1h. The request budget is ~10s,
4866
+ * so a claimed requestId is never re-sent after an hour; keeping the table
4867
+ * bounded avoids unbounded growth on a long-lived coordinator.
4868
+ *
4869
+ * @returns the number of rows deleted.
4870
+ */
4871
+ async function pruneRequestIdempotency(db) {
4872
+ const result = await db.deleteFrom("request_idempotency").where("created_at", "<", sql`now() - interval '1 hour'`).executeTakeFirst();
4873
+ return Number(result.numDeletedRows ?? 0n);
4874
+ }
4875
+ var init_request_idempotency = __esmMin((() => {}));
4876
+ //#endregion
4735
4877
  //#region src/providers/github/auth.ts
4736
4878
  /**
4737
4879
  * GitHub clone token provider and authentication utilities.
@@ -5020,12 +5162,12 @@ function buildJobFailureDescription(data) {
5020
5162
  if (data.error) return `Job error: ${data.error}`;
5021
5163
  return "Job failed";
5022
5164
  }
5023
- var logger$120, PROGRESS_DEBOUNCE_MS, CheckRunReporter;
5165
+ var logger$121, PROGRESS_DEBOUNCE_MS, CheckRunReporter;
5024
5166
  var init_check_run_reporter = __esmMin((() => {
5025
5167
  init_auth();
5026
5168
  init_prometheus();
5027
5169
  init_check_run_summary();
5028
- logger$120 = createLogger({ prefix: "check-run-reporter" });
5170
+ logger$121 = createLogger({ prefix: "check-run-reporter" });
5029
5171
  PROGRESS_DEBOUNCE_MS = 5e3;
5030
5172
  CheckRunReporter = class {
5031
5173
  deps;
@@ -5116,7 +5258,7 @@ var init_check_run_reporter = __esmMin((() => {
5116
5258
  */
5117
5259
  setPending(opts) {
5118
5260
  this.doSetPending(opts).catch((err) => {
5119
- logger$120.error("Failed to set pending check run", {
5261
+ logger$121.error("Failed to set pending check run", {
5120
5262
  error: toErrorMessage(err),
5121
5263
  provider: opts.provider,
5122
5264
  owner: opts.owner,
@@ -5141,7 +5283,7 @@ var init_check_run_reporter = __esmMin((() => {
5141
5283
  */
5142
5284
  updateJobStatus(opts) {
5143
5285
  this.doUpdateJobStatus(opts).catch((err) => {
5144
- logger$120.error("Failed to update job check run", {
5286
+ logger$121.error("Failed to update job check run", {
5145
5287
  error: toErrorMessage(err),
5146
5288
  provider: opts.provider,
5147
5289
  owner: opts.owner,
@@ -5160,7 +5302,7 @@ var init_check_run_reporter = __esmMin((() => {
5160
5302
  */
5161
5303
  updateWorkflowStatus(opts) {
5162
5304
  this.doUpdateWorkflowStatus(opts).catch((err) => {
5163
- logger$120.error("Failed to update workflow check run", {
5305
+ logger$121.error("Failed to update workflow check run", {
5164
5306
  error: toErrorMessage(err),
5165
5307
  provider: opts.provider,
5166
5308
  owner: opts.owner,
@@ -5185,7 +5327,7 @@ var init_check_run_reporter = __esmMin((() => {
5185
5327
  */
5186
5328
  cleanupStaleCheckRuns(opts) {
5187
5329
  this.doCleanupStaleCheckRuns(opts).catch((err) => {
5188
- logger$120.error("Failed to clean up stale check runs", {
5330
+ logger$121.error("Failed to clean up stale check runs", {
5189
5331
  error: toErrorMessage(err),
5190
5332
  provider: opts.provider,
5191
5333
  owner: opts.owner,
@@ -5204,7 +5346,7 @@ var init_check_run_reporter = __esmMin((() => {
5204
5346
  */
5205
5347
  updateStepProgress(opts) {
5206
5348
  this.doUpdateStepProgress(opts).catch((err) => {
5207
- logger$120.error("Failed to update step progress", {
5349
+ logger$121.error("Failed to update step progress", {
5208
5350
  error: toErrorMessage(err),
5209
5351
  provider: opts.provider,
5210
5352
  workflowName: opts.workflowName,
@@ -5227,7 +5369,7 @@ var init_check_run_reporter = __esmMin((() => {
5227
5369
  this.persistBuildCreationPending(key, opts.runId);
5228
5370
  this.trackRunKey(opts.runId, key);
5229
5371
  const creation = this.doSetBuildPending(opts).catch((err) => {
5230
- logger$120.error("Failed to set build pending check run", {
5372
+ logger$121.error("Failed to set build pending check run", {
5231
5373
  error: toErrorMessage(err),
5232
5374
  provider: opts.provider,
5233
5375
  owner: opts.owner,
@@ -5246,7 +5388,7 @@ var init_check_run_reporter = __esmMin((() => {
5246
5388
  */
5247
5389
  setBuildComplete(opts) {
5248
5390
  this.doSetBuildComplete(opts).catch((err) => {
5249
- logger$120.error("Failed to set build complete check run", {
5391
+ logger$121.error("Failed to set build complete check run", {
5250
5392
  error: toErrorMessage(err),
5251
5393
  provider: opts.provider,
5252
5394
  owner: opts.owner,
@@ -5298,7 +5440,7 @@ var init_check_run_reporter = __esmMin((() => {
5298
5440
  */
5299
5441
  async recoverState() {
5300
5442
  if (!this.deps.trackingStore) return;
5301
- logger$120.info("CheckRunReporter recovered (DB-backed state lookups enabled)");
5443
+ logger$121.info("CheckRunReporter recovered (DB-backed state lookups enabled)");
5302
5444
  }
5303
5445
  /** Track a check run key associated with a runId for later cleanup. */
5304
5446
  trackRunKey(runId, key) {
@@ -5340,7 +5482,7 @@ var init_check_run_reporter = __esmMin((() => {
5340
5482
  await this.deps.trackingStore.setCheckRunId(this.parseKey(key), checkRunId, runId);
5341
5483
  if (runId) await this.deps.trackingStore.markBuildCreationComplete(this.parseKey(key));
5342
5484
  } catch (err) {
5343
- logger$120.warn("Failed to persist check_run_tracking row; cache-only fallback", {
5485
+ logger$121.warn("Failed to persist check_run_tracking row; cache-only fallback", {
5344
5486
  key,
5345
5487
  error: toErrorMessage(err)
5346
5488
  });
@@ -5360,7 +5502,7 @@ var init_check_run_reporter = __esmMin((() => {
5360
5502
  if (fromDb !== void 0) this.checkRunIds.set(key, fromDb);
5361
5503
  return fromDb;
5362
5504
  } catch (err) {
5363
- logger$120.warn("Failed to read check_run_tracking row; treating as miss", {
5505
+ logger$121.warn("Failed to read check_run_tracking row; treating as miss", {
5364
5506
  key,
5365
5507
  error: toErrorMessage(err)
5366
5508
  });
@@ -5376,7 +5518,7 @@ var init_check_run_reporter = __esmMin((() => {
5376
5518
  try {
5377
5519
  await this.deps.trackingStore.setStepProgress(this.parseKey(key), steps, runId);
5378
5520
  } catch (err) {
5379
- logger$120.warn("Failed to persist step-progress; cache-only fallback", {
5521
+ logger$121.warn("Failed to persist step-progress; cache-only fallback", {
5380
5522
  key,
5381
5523
  error: toErrorMessage(err)
5382
5524
  });
@@ -5391,7 +5533,7 @@ var init_check_run_reporter = __esmMin((() => {
5391
5533
  try {
5392
5534
  await this.deps.trackingStore.markInProgressSent(this.parseKey(key), runId);
5393
5535
  } catch (err) {
5394
- logger$120.warn("Failed to persist in-progress-sent marker; cache-only fallback", {
5536
+ logger$121.warn("Failed to persist in-progress-sent marker; cache-only fallback", {
5395
5537
  key,
5396
5538
  error: toErrorMessage(err)
5397
5539
  });
@@ -5405,7 +5547,7 @@ var init_check_run_reporter = __esmMin((() => {
5405
5547
  try {
5406
5548
  await this.deps.trackingStore.markBuildCreationPending(this.parseKey(key), runId);
5407
5549
  } catch (err) {
5408
- logger$120.warn("Failed to persist build-creation-pending marker", {
5550
+ logger$121.warn("Failed to persist build-creation-pending marker", {
5409
5551
  key,
5410
5552
  error: toErrorMessage(err)
5411
5553
  });
@@ -5471,12 +5613,12 @@ var init_check_run_reporter = __esmMin((() => {
5471
5613
  }
5472
5614
  async doSetPending(opts) {
5473
5615
  if (opts.provider !== "github") {
5474
- logger$120.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5616
+ logger$121.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5475
5617
  return;
5476
5618
  }
5477
5619
  const githubConfig = this.resolveGithubConfig(opts.routingKey);
5478
5620
  if (!githubConfig || !opts.installationId) {
5479
- logger$120.debug("GitHub config or installationId missing, skipping check run", {
5621
+ logger$121.debug("GitHub config or installationId missing, skipping check run", {
5480
5622
  hasConfig: !!githubConfig,
5481
5623
  hasInstallationId: !!opts.installationId
5482
5624
  });
@@ -5526,19 +5668,19 @@ var init_check_run_reporter = __esmMin((() => {
5526
5668
  }
5527
5669
  async doUpdateJobStatus(opts) {
5528
5670
  if (opts.provider !== "github") {
5529
- logger$120.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5671
+ logger$121.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5530
5672
  return;
5531
5673
  }
5532
5674
  const githubConfig = this.resolveGithubConfig(opts.routingKey);
5533
5675
  if (!githubConfig || !opts.installationId) {
5534
- logger$120.debug("GitHub config or installationId missing, skipping check run update");
5676
+ logger$121.debug("GitHub config or installationId missing, skipping check run update");
5535
5677
  return;
5536
5678
  }
5537
5679
  const checkName = `kici/${opts.workflowName}/job/${opts.jobName}`;
5538
5680
  const key = this.checkRunKey(opts.owner, opts.repo, opts.sha, checkName);
5539
5681
  const checkRunId = await this.resolveCheckRunId(key);
5540
5682
  if (!checkRunId) {
5541
- logger$120.warn("Check run ID not found for job update, skipping", { key });
5683
+ logger$121.warn("Check run ID not found for job update, skipping", { key });
5542
5684
  return;
5543
5685
  }
5544
5686
  const pendingTimer = this.progressTimers.get(key);
@@ -5611,18 +5753,18 @@ var init_check_run_reporter = __esmMin((() => {
5611
5753
  }
5612
5754
  async doUpdateWorkflowStatus(opts) {
5613
5755
  if (opts.provider !== "github") {
5614
- logger$120.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5756
+ logger$121.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5615
5757
  return;
5616
5758
  }
5617
5759
  const githubConfig = this.resolveGithubConfig(opts.routingKey);
5618
5760
  if (!githubConfig || !opts.installationId) {
5619
- logger$120.debug("GitHub config or installationId missing, skipping check run update");
5761
+ logger$121.debug("GitHub config or installationId missing, skipping check run update");
5620
5762
  return;
5621
5763
  }
5622
5764
  const key = this.checkRunKey(opts.owner, opts.repo, opts.sha, `kici/${opts.workflowName}`);
5623
5765
  const checkRunId = await this.resolveCheckRunId(key);
5624
5766
  if (!checkRunId) {
5625
- logger$120.warn("Check run ID not found for workflow update, skipping", { key });
5767
+ logger$121.warn("Check run ID not found for workflow update, skipping", { key });
5626
5768
  return;
5627
5769
  }
5628
5770
  const octokit = createInstallationOctokit(githubConfig, opts.installationId);
@@ -5645,12 +5787,12 @@ var init_check_run_reporter = __esmMin((() => {
5645
5787
  }
5646
5788
  async doCleanupStaleCheckRuns(opts) {
5647
5789
  if (opts.provider !== "github") {
5648
- logger$120.debug("Stale check run cleanup not supported for provider, skipping", { provider: opts.provider });
5790
+ logger$121.debug("Stale check run cleanup not supported for provider, skipping", { provider: opts.provider });
5649
5791
  return;
5650
5792
  }
5651
5793
  const githubConfig = this.resolveGithubConfig(opts.routingKey);
5652
5794
  if (!githubConfig) {
5653
- logger$120.debug("GitHub config not available for stale cleanup, skipping", { routingKey: opts.routingKey });
5795
+ logger$121.debug("GitHub config not available for stale cleanup, skipping", { routingKey: opts.routingKey });
5654
5796
  return;
5655
5797
  }
5656
5798
  const appOctokit = new Octokit({
@@ -5668,7 +5810,7 @@ var init_check_run_reporter = __esmMin((() => {
5668
5810
  });
5669
5811
  installationId = data.id;
5670
5812
  } catch (err) {
5671
- logger$120.warn("Could not find installation for repo, skipping stale cleanup", {
5813
+ logger$121.warn("Could not find installation for repo, skipping stale cleanup", {
5672
5814
  owner: opts.owner,
5673
5815
  repo: opts.repo,
5674
5816
  error: toErrorMessage(err)
@@ -5703,14 +5845,14 @@ var init_check_run_reporter = __esmMin((() => {
5703
5845
  });
5704
5846
  cleanedCount++;
5705
5847
  } catch (updateErr) {
5706
- logger$120.warn("Failed to update stale check run", {
5848
+ logger$121.warn("Failed to update stale check run", {
5707
5849
  checkRunId: checkRun.id,
5708
5850
  checkName: checkRun.name,
5709
5851
  error: toErrorMessage(updateErr)
5710
5852
  });
5711
5853
  }
5712
5854
  if (cleanedCount > 0) {
5713
- logger$120.info("Cleaned up stale check runs", {
5855
+ logger$121.info("Cleaned up stale check runs", {
5714
5856
  owner: opts.owner,
5715
5857
  repo: opts.repo,
5716
5858
  sha: opts.sha,
@@ -5720,7 +5862,7 @@ var init_check_run_reporter = __esmMin((() => {
5720
5862
  githubCheckRunTotal.add(cleanedCount, { operation: "stale_cleanup" });
5721
5863
  }
5722
5864
  } catch (err) {
5723
- logger$120.error("Failed to list check runs for stale cleanup", {
5865
+ logger$121.error("Failed to list check runs for stale cleanup", {
5724
5866
  owner: opts.owner,
5725
5867
  repo: opts.repo,
5726
5868
  sha: opts.sha,
@@ -5786,7 +5928,7 @@ var init_check_run_reporter = __esmMin((() => {
5786
5928
  const timer = setTimeout(() => {
5787
5929
  this.progressTimers.delete(key);
5788
5930
  this.flushProgress(key, opts).catch((err) => {
5789
- logger$120.error("Failed to flush step progress", {
5931
+ logger$121.error("Failed to flush step progress", {
5790
5932
  error: toErrorMessage(err),
5791
5933
  key
5792
5934
  });
@@ -5826,12 +5968,12 @@ var init_check_run_reporter = __esmMin((() => {
5826
5968
  }
5827
5969
  async doSetBuildPending(opts) {
5828
5970
  if (opts.provider !== "github") {
5829
- logger$120.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5971
+ logger$121.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5830
5972
  return;
5831
5973
  }
5832
5974
  const githubConfig = this.resolveGithubConfig(opts.routingKey);
5833
5975
  if (!githubConfig || !opts.installationId) {
5834
- logger$120.debug("GitHub config or installationId missing, skipping build check run", {
5976
+ logger$121.debug("GitHub config or installationId missing, skipping build check run", {
5835
5977
  hasConfig: !!githubConfig,
5836
5978
  hasInstallationId: !!opts.installationId
5837
5979
  });
@@ -5860,12 +6002,12 @@ var init_check_run_reporter = __esmMin((() => {
5860
6002
  }
5861
6003
  async doSetBuildComplete(opts) {
5862
6004
  if (opts.provider !== "github") {
5863
- logger$120.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
6005
+ logger$121.warn("Check runs not supported for provider, skipping", { provider: opts.provider });
5864
6006
  return;
5865
6007
  }
5866
6008
  const githubConfig = this.resolveGithubConfig(opts.routingKey);
5867
6009
  if (!githubConfig || !opts.installationId) {
5868
- logger$120.debug("GitHub config or installationId missing, skipping build check run update");
6010
+ logger$121.debug("GitHub config or installationId missing, skipping build check run update");
5869
6011
  return;
5870
6012
  }
5871
6013
  const buildCheckName = `kici/${opts.workflowName}/setup`;
@@ -5874,7 +6016,7 @@ var init_check_run_reporter = __esmMin((() => {
5874
6016
  if (pending) await pending;
5875
6017
  const checkRunId = await this.resolveCheckRunId(key);
5876
6018
  if (!checkRunId) {
5877
- logger$120.warn("Check run ID not found for build update, skipping", { key });
6019
+ logger$121.warn("Check run ID not found for build update, skipping", { key });
5878
6020
  return;
5879
6021
  }
5880
6022
  const octokit = createInstallationOctokit(githubConfig, opts.installationId);
@@ -5930,7 +6072,7 @@ var init_check_run_reporter = __esmMin((() => {
5930
6072
  };
5931
6073
  default: {
5932
6074
  const unexpected = status;
5933
- logger$120.warn("Unexpected terminal job status mapping a build conclusion", { status: unexpected });
6075
+ logger$121.warn("Unexpected terminal job status mapping a build conclusion", { status: unexpected });
5934
6076
  return {
5935
6077
  conclusion: CheckRunConclusion.enum.failure,
5936
6078
  description: customDescription ?? "Build finished with an unrecognised status"
@@ -5973,7 +6115,7 @@ var init_check_run_reporter = __esmMin((() => {
5973
6115
  };
5974
6116
  default: {
5975
6117
  const unexpected = state;
5976
- logger$120.warn("Unexpected terminal job status mapping a job conclusion", { status: unexpected });
6118
+ logger$121.warn("Unexpected terminal job status mapping a job conclusion", { status: unexpected });
5977
6119
  return {
5978
6120
  conclusion: CheckRunConclusion.enum.failure,
5979
6121
  description: customDescription ?? "Job finished with an unrecognised status"
@@ -6016,7 +6158,7 @@ var init_check_run_reporter = __esmMin((() => {
6016
6158
  };
6017
6159
  default: {
6018
6160
  const unexpected = status;
6019
- logger$120.warn("Unexpected terminal job status mapping a workflow conclusion", { status: unexpected });
6161
+ logger$121.warn("Unexpected terminal job status mapping a workflow conclusion", { status: unexpected });
6020
6162
  return {
6021
6163
  conclusion: CheckRunConclusion.enum.failure,
6022
6164
  description: customDescription ?? "Workflow finished with an unrecognised status"
@@ -6046,12 +6188,12 @@ var init_check_run_reporter = __esmMin((() => {
6046
6188
  if (error.status === 403) {
6047
6189
  const rateRemaining = error.response?.headers?.["x-ratelimit-remaining"];
6048
6190
  const rateReset = error.response?.headers?.["x-ratelimit-reset"];
6049
- logger$120.error("GitHub API 403 creating check run", {
6191
+ logger$121.error("GitHub API 403 creating check run", {
6050
6192
  name: params.name,
6051
6193
  rateRemaining,
6052
6194
  rateReset
6053
6195
  });
6054
- } else logger$120.error("GitHub API error creating check run", {
6196
+ } else logger$121.error("GitHub API error creating check run", {
6055
6197
  name: params.name,
6056
6198
  status: error.status,
6057
6199
  error: toErrorMessage(err)
@@ -6088,12 +6230,12 @@ var init_check_run_reporter = __esmMin((() => {
6088
6230
  if (error.status === 403) {
6089
6231
  const rateRemaining = error.response?.headers?.["x-ratelimit-remaining"];
6090
6232
  const rateReset = error.response?.headers?.["x-ratelimit-reset"];
6091
- logger$120.error("GitHub API 403 updating check run", {
6233
+ logger$121.error("GitHub API 403 updating check run", {
6092
6234
  checkRunId: params.check_run_id,
6093
6235
  rateRemaining,
6094
6236
  rateReset
6095
6237
  });
6096
- } else logger$120.error("GitHub API error updating check run", {
6238
+ } else logger$121.error("GitHub API error updating check run", {
6097
6239
  checkRunId: params.check_run_id,
6098
6240
  status: error.status,
6099
6241
  error: toErrorMessage(err)
@@ -6102,7 +6244,7 @@ var init_check_run_reporter = __esmMin((() => {
6102
6244
  if (patchAccepted && params.status === "completed" && trackingKey && this.deps.trackingStore) try {
6103
6245
  await this.deps.trackingStore.markTerminalSent(this.parseKey(trackingKey), trackingRunId);
6104
6246
  } catch (err) {
6105
- logger$120.warn("Failed to stamp terminal_sent_at; continuing", {
6247
+ logger$121.warn("Failed to stamp terminal_sent_at; continuing", {
6106
6248
  key: trackingKey,
6107
6249
  error: toErrorMessage(err)
6108
6250
  });
@@ -6145,7 +6287,7 @@ function reportJobCheckRunCompletion(deps, input) {
6145
6287
  try {
6146
6288
  postJobCheckRunCompletion(deps, input);
6147
6289
  } catch (err) {
6148
- logger$119.error("Failed to report job check-run completion", {
6290
+ logger$120.error("Failed to report job check-run completion", {
6149
6291
  error: toErrorMessage(err),
6150
6292
  runId: input.runId,
6151
6293
  jobId: input.jobId,
@@ -6157,7 +6299,7 @@ function postJobCheckRunCompletion(deps, input) {
6157
6299
  if (!isTerminalJobStatus(input.status)) return;
6158
6300
  const execContext = deps.getExecutionContext(input.runId);
6159
6301
  if (!execContext) {
6160
- logger$119.debug("No execution context for job check-run completion, skipping", {
6302
+ logger$120.debug("No execution context for job check-run completion, skipping", {
6161
6303
  runId: input.runId,
6162
6304
  jobId: input.jobId
6163
6305
  });
@@ -6182,105 +6324,107 @@ function postJobCheckRunCompletion(deps, input) {
6182
6324
  runId: input.runId
6183
6325
  });
6184
6326
  }
6185
- var logger$119;
6327
+ var logger$120;
6186
6328
  var init_job_check_run_completion = __esmMin((() => {
6187
6329
  init_check_run_reporter();
6188
- logger$119 = createLogger({ prefix: "check-run-completion" });
6330
+ logger$120 = createLogger({ prefix: "check-run-completion" });
6189
6331
  }));
6190
6332
  //#endregion
6191
- //#region src/reporting/log-retention.ts
6333
+ //#region src/queue/terminalize-unroutable.ts
6192
6334
  /**
6193
- * Delete step-log objects older than `ttlDays` in one bulk pass.
6194
- *
6195
- * Step-log objects are write-once (appended during the run, untouched after
6196
- * finalize), so last-modified time is the correct expiry basis — a recent or
6197
- * still-running run's objects were all written within the window and survive.
6198
- * `ttlDays <= 0` disables the sweep (returns 0). Expired objects are collected
6199
- * then bulk-deleted via `deleteMany` (S3 DeleteObjects), so a large sweep is a
6200
- * handful of API calls, not one-per-object. A delete failure is logged and the
6201
- * cleanup tick is not aborted.
6202
- *
6203
- * @returns Number of objects deleted.
6335
+ * The operator-facing reason a job is `unroutable`, naming the exact selectors
6336
+ * that went unmatched. Regex matchers are rendered as their source so the
6337
+ * message stays readable rather than printing `[object Object]`.
6204
6338
  */
6205
- async function pruneExpiredLogs(storage, ttlDays, now = /* @__PURE__ */ new Date()) {
6206
- if (ttlDays <= 0) return 0;
6207
- const cutoff = now.getTime() - ttlDays * 864e5;
6208
- const expired = (await storage.listWithMetadata(LOG_ROOT_PREFIX)).filter((o) => o.lastModified.getTime() < cutoff).map((o) => o.path);
6209
- if (expired.length === 0) return 0;
6210
- try {
6211
- return await storage.deleteMany(expired);
6212
- } catch (err) {
6213
- logger$118.error("Failed to bulk-delete expired log objects", {
6214
- count: expired.length,
6215
- error: toErrorMessage(err)
6216
- });
6217
- return 0;
6218
- }
6339
+ function renderMatcher(m) {
6340
+ return m.kind === "exact" ? m.value : `/${m.source}/${m.flags}`;
6341
+ }
6342
+ function unroutableMessage(job) {
6343
+ const required = [...job.runsOnLabels, ...job.runsOnPatterns.map(renderMatcher)];
6344
+ const excluded = [...job.excludeLabels, ...job.excludePatterns.map(renderMatcher)];
6345
+ const parts = [required.length > 0 ? `runsOn [${required.join(", ")}]` : "this job (it declares no runsOn, so any agent would do)"];
6346
+ if (excluded.length > 0) parts.push(`excluding [${excluded.join(", ")}]`);
6347
+ return `No connected agent or scaler backend currently matches ${parts.join(" ")} the job was never dispatched`;
6219
6348
  }
6220
- var logger$118, LOG_ROOT_PREFIX;
6221
- var init_log_retention = __esmMin((() => {
6222
- logger$118 = createLogger({ prefix: "log-retention" });
6223
- LOG_ROOT_PREFIX = "executions/";
6224
- }));
6225
- //#endregion
6226
- //#region src/pipeline/request-idempotency.ts
6227
6349
  /**
6228
- * Atomically claim a run-minting request by its Platform `requestId`. Returns
6229
- * the run id to use. `claimed: false` means a sibling coordinator already owns
6230
- * this requestId (a relay failover re-sent the same request): the caller MUST
6231
- * return `{ newRunId }` WITHOUT creating or dispatching a run, so one user
6232
- * click yields exactly one run.
6350
+ * Split the two reasons a queued job never ran: nothing in the fleet matched
6351
+ * its `runsOn` (`unroutable` a label/fleet problem an operator has to fix)
6352
+ * versus something matched but never produced a usable agent
6353
+ * (`timed_out_stale` a capacity or provisioning problem).
6233
6354
  *
6234
- * Shared by `run.rerun.request` and `run.manual_schedule.request` both mint a
6235
- * fresh run and both ride the Platform's timeout-driven failover path. HA
6236
- * coordinator siblings share one orchestrator DB, so the `INSERT ON CONFLICT
6237
- * (request_id) DO NOTHING` is the single point of arbitration: exactly one hop
6238
- * inserts and wins; the loser reads back the winner's `new_run_id`.
6355
+ * Shared by the unroutable probe (which asks on a short tick, gated by a grace
6356
+ * window) and the queue-expiry sweep (which asks once at expiry, as the
6357
+ * backstop). One verdict, two moments in time a second copy of this logic is
6358
+ * exactly the drift this module exists to prevent.
6239
6359
  */
6240
- async function claimRequestId(db, requestId) {
6241
- const candidate = randomUUID();
6242
- if (await db.insertInto("request_idempotency").values({
6243
- request_id: requestId,
6244
- new_run_id: candidate
6245
- }).onConflict((oc) => oc.column("request_id").doNothing()).returning("new_run_id").executeTakeFirst()) return {
6246
- newRunId: candidate,
6247
- claimed: true
6248
- };
6360
+ function classifyUnroutable(job, canRouteLabels) {
6361
+ const unroutable = job.lastProvisioningError === null && canRouteLabels !== void 0 && !canRouteLabels(job.runsOnLabels, job.runsOnPatterns, job.excludeLabels, job.excludePatterns);
6249
6362
  return {
6250
- newRunId: (await db.selectFrom("request_idempotency").select("new_run_id").where("request_id", "=", requestId).executeTakeFirstOrThrow()).new_run_id,
6251
- claimed: false
6363
+ unroutable,
6364
+ status: unroutable ? ExecutionJobStatus.enum.unroutable : ExecutionJobStatus.enum.timed_out_stale,
6365
+ errorMessage: unroutable ? unroutableMessage(job) : job.lastProvisioningError ?? GENERIC_MESSAGE
6252
6366
  };
6253
6367
  }
6254
6368
  /**
6255
- * Prune `request_idempotency` rows older than 1h. The request budget is ~10s,
6256
- * so a claimed requestId is never re-sent after an hour; keeping the table
6257
- * bounded avoids unbounded growth on a long-lived coordinator.
6369
+ * Settle one never-dispatched job: write the terminal status locally, surface
6370
+ * the reason at run level, forward to Platform, and resolve its check run.
6258
6371
  *
6259
- * @returns the number of rows deleted.
6372
+ * @returns the run id when this call actually terminalized the job (so the
6373
+ * caller can complete the run), or null when another coordinator got there
6374
+ * first or the job was no longer pending.
6260
6375
  */
6261
- async function pruneRequestIdempotency(db) {
6262
- const result = await db.deleteFrom("request_idempotency").where("created_at", "<", sql`now() - interval '1 hour'`).executeTakeFirst();
6263
- return Number(result.numDeletedRows ?? 0n);
6376
+ async function terminalizeUnroutableJob(deps, job) {
6377
+ const { status, errorMessage, unroutable } = classifyUnroutable(job, deps.canRouteLabels);
6378
+ try {
6379
+ const ejResult = await deps.db.updateTable("execution_jobs").set({
6380
+ status,
6381
+ completed_at: /* @__PURE__ */ new Date(),
6382
+ error_message: errorMessage
6383
+ }).where("run_id", "=", sql`${job.runId}::uuid`).where("job_name", "=", job.jobName).where("status", "in", [ExecutionJobStatus.enum.pending, ExecutionJobStatus.enum.queued]).executeTakeFirst();
6384
+ if (!ejResult.numUpdatedRows || ejResult.numUpdatedRows === 0n) return null;
6385
+ const runReason = unroutable ? errorMessage : job.lastProvisioningError;
6386
+ if (runReason) await deps.db.updateTable("execution_runs").set({ failure_reason: runReason }).where("run_id", "=", sql`${job.runId}::uuid`).where("failure_reason", "is", null).execute();
6387
+ const ejRow = await deps.db.selectFrom("execution_jobs").select(["job_id"]).where("run_id", "=", sql`${job.runId}::uuid`).where("job_name", "=", job.jobName).executeTakeFirst();
6388
+ if (ejRow) {
6389
+ deps.executionTracker.updateInMemoryJob(job.runId, ejRow.job_id, status);
6390
+ deps.executionTracker.forwardJobTerminalStatus(job.runId, ejRow.job_id, job.jobName, status, errorMessage);
6391
+ deps.executionTracker.emitInfraEvent(job.runId, "orchestrator.job.queue_expired", {
6392
+ jobId: ejRow.job_id,
6393
+ metadata: {
6394
+ jobName: job.jobName,
6395
+ reason: errorMessage
6396
+ }
6397
+ });
6398
+ if (deps.checkRunReporter) reportJobCheckRunCompletion({
6399
+ checkRunReporter: deps.checkRunReporter,
6400
+ getExecutionContext: (runId) => deps.executionTracker.getExecutionContext(runId)
6401
+ }, {
6402
+ runId: job.runId,
6403
+ jobId: ejRow.job_id,
6404
+ jobName: job.jobName,
6405
+ status,
6406
+ description: errorMessage
6407
+ });
6408
+ }
6409
+ return job.runId;
6410
+ } catch (err) {
6411
+ logger$119.error("Failed to forward never-dispatched job status", {
6412
+ runId: job.runId,
6413
+ jobName: job.jobName,
6414
+ error: toErrorMessage(err)
6415
+ });
6416
+ return null;
6417
+ }
6264
6418
  }
6265
- var init_request_idempotency = __esmMin((() => {}));
6419
+ var logger$119, GENERIC_MESSAGE;
6420
+ var init_terminalize_unroutable = __esmMin((() => {
6421
+ init_job_check_run_completion();
6422
+ logger$119 = createLogger({ prefix: "terminalize-unroutable" });
6423
+ GENERIC_MESSAGE = "Queue timeout expired (job was never dispatched to an agent)";
6424
+ }));
6266
6425
  //#endregion
6267
6426
  //#region src/queue/cleanup.ts
6268
6427
  /**
6269
- * The operator-facing reason an expired job is `unroutable`, naming the exact
6270
- * selectors that went unmatched. Regex matchers are rendered as their source so
6271
- * the message stays readable rather than printing `[object Object]`.
6272
- */
6273
- function renderMatcher(m) {
6274
- return m.kind === "exact" ? m.value : `/${m.source}/${m.flags}`;
6275
- }
6276
- function unroutableMessage(job) {
6277
- const required = [...job.runsOnLabels, ...job.runsOnPatterns.map(renderMatcher)];
6278
- const excluded = [...job.excludeLabels, ...job.excludePatterns.map(renderMatcher)];
6279
- const parts = [required.length > 0 ? `runsOn [${required.join(", ")}]` : "this job (it declares no runsOn, so any agent would do)"];
6280
- if (excluded.length > 0) parts.push(`excluding [${excluded.join(", ")}]`);
6281
- return `No connected agent or scaler backend currently matches ${parts.join(" ")} — the job was never dispatched`;
6282
- }
6283
- /**
6284
6428
  * Run a single cleanup pass: remove expired dedup_cache entries and
6285
6429
  * mark expired dispatch_queue entries.
6286
6430
  *
@@ -6304,31 +6448,31 @@ async function runCleanup(dedup, queue, extras) {
6304
6448
  if (extras) {
6305
6449
  try {
6306
6450
  const pruned = await pruneRequestIdempotency(extras.db);
6307
- if (pruned > 0) logger$117.info("Pruned stale request idempotency claims", { pruned });
6451
+ if (pruned > 0) logger$118.info("Pruned stale request idempotency claims", { pruned });
6308
6452
  } catch (err) {
6309
- logger$117.error("Failed to prune request idempotency claims", { error: toErrorMessage(err) });
6453
+ logger$118.error("Failed to prune request idempotency claims", { error: toErrorMessage(err) });
6310
6454
  }
6311
6455
  const ttlDays = extras.dispatchQueueTtlDays ?? 30;
6312
6456
  try {
6313
6457
  dispatchRowsPruned = await queue.pruneTerminalDispatchRows(ttlDays);
6314
6458
  if (dispatchRowsPruned > 0) {
6315
6459
  dispatchQueueRowsPrunedTotal.add(dispatchRowsPruned);
6316
- logger$117.info("Pruned terminal dispatch_queue rows", {
6460
+ logger$118.info("Pruned terminal dispatch_queue rows", {
6317
6461
  dispatchRowsPruned,
6318
6462
  ttlDays
6319
6463
  });
6320
6464
  }
6321
6465
  } catch (err) {
6322
- logger$117.error("Failed to prune terminal dispatch_queue rows", { error: toErrorMessage(err) });
6466
+ logger$118.error("Failed to prune terminal dispatch_queue rows", { error: toErrorMessage(err) });
6323
6467
  }
6324
6468
  if (extras.logStorage && extras.logStorageIsS3) try {
6325
6469
  logObjectsPruned = await pruneExpiredLogs(extras.logStorage, extras.stepLogTtlDays ?? 90);
6326
6470
  if (logObjectsPruned > 0) {
6327
6471
  stepLogsPrunedTotal.add(logObjectsPruned);
6328
- logger$117.info("Pruned expired step-log objects", { logObjectsPruned });
6472
+ logger$118.info("Pruned expired step-log objects", { logObjectsPruned });
6329
6473
  }
6330
6474
  } catch (err) {
6331
- logger$117.error("Failed to prune expired step-log objects", { error: toErrorMessage(err) });
6475
+ logger$118.error("Failed to prune expired step-log objects", { error: toErrorMessage(err) });
6332
6476
  }
6333
6477
  if (extras.checkRunTrackingStore) {
6334
6478
  const checkRunTtlDefault = extras.checkRunTrackingTtlDays ?? 7;
@@ -6337,81 +6481,44 @@ async function runCleanup(dedup, queue, extras) {
6337
6481
  checkRunRowsPruned = await extras.checkRunTrackingStore.pruneStale(ttlDays);
6338
6482
  if (checkRunRowsPruned > 0) {
6339
6483
  checkRunTrackingRowsPrunedTotal.add(checkRunRowsPruned);
6340
- logger$117.info("Pruned stale check-run-tracking rows", {
6484
+ logger$118.info("Pruned stale check-run-tracking rows", {
6341
6485
  checkRunRowsPruned,
6342
6486
  ttlDays
6343
6487
  });
6344
6488
  }
6345
6489
  } catch (err) {
6346
- logger$117.error("Failed to prune stale check-run-tracking rows", { error: toErrorMessage(err) });
6490
+ logger$118.error("Failed to prune stale check-run-tracking rows", { error: toErrorMessage(err) });
6347
6491
  }
6348
6492
  }
6349
6493
  }
6350
6494
  if (extras && expiredJobs.length > 0) {
6351
6495
  const affectedRunIds = /* @__PURE__ */ new Set();
6352
- const genericMessage = "Queue timeout expired (job was never dispatched to an agent)";
6353
6496
  for (const job of expiredJobs) {
6354
- const unroutable = job.lastProvisioningError === null && extras.canRouteLabels !== void 0 && !extras.canRouteLabels(job.runsOnLabels, job.runsOnPatterns, job.excludeLabels, job.excludePatterns);
6355
- const status = unroutable ? ExecutionJobStatus.enum.unroutable : ExecutionJobStatus.enum.timed_out_stale;
6356
- const errorMessage = unroutable ? unroutableMessage(job) : job.lastProvisioningError ?? genericMessage;
6357
- try {
6358
- const ejResult = await extras.db.updateTable("execution_jobs").set({
6359
- status,
6360
- completed_at: /* @__PURE__ */ new Date(),
6361
- error_message: errorMessage
6362
- }).where("run_id", "=", sql`${job.runId}::uuid`).where("job_name", "=", job.jobName).where("status", "in", [ExecutionJobStatus.enum.pending, ExecutionJobStatus.enum.queued]).executeTakeFirst();
6363
- if (ejResult.numUpdatedRows && ejResult.numUpdatedRows > 0n) {
6364
- const runReason = unroutable ? errorMessage : job.lastProvisioningError;
6365
- if (runReason) await extras.db.updateTable("execution_runs").set({ failure_reason: runReason }).where("run_id", "=", sql`${job.runId}::uuid`).where("failure_reason", "is", null).execute();
6366
- const ejRow = await extras.db.selectFrom("execution_jobs").select(["job_id"]).where("run_id", "=", sql`${job.runId}::uuid`).where("job_name", "=", job.jobName).executeTakeFirst();
6367
- if (ejRow) {
6368
- extras.executionTracker.updateInMemoryJob(job.runId, ejRow.job_id, status);
6369
- extras.executionTracker.forwardJobTerminalStatus(job.runId, ejRow.job_id, job.jobName, status, errorMessage);
6370
- extras.executionTracker.emitInfraEvent(job.runId, "orchestrator.job.queue_expired", {
6371
- jobId: ejRow.job_id,
6372
- metadata: {
6373
- jobName: job.jobName,
6374
- reason: errorMessage
6375
- }
6376
- });
6377
- if (extras.checkRunReporter) reportJobCheckRunCompletion({
6378
- checkRunReporter: extras.checkRunReporter,
6379
- getExecutionContext: (runId) => extras.executionTracker.getExecutionContext(runId)
6380
- }, {
6381
- runId: job.runId,
6382
- jobId: ejRow.job_id,
6383
- jobName: job.jobName,
6384
- status,
6385
- description: errorMessage
6386
- });
6387
- }
6388
- affectedRunIds.add(job.runId);
6389
- }
6390
- } catch (err) {
6391
- logger$117.error("Failed to forward expired job status", {
6392
- runId: job.runId,
6393
- jobName: job.jobName,
6394
- error: toErrorMessage(err)
6395
- });
6396
- }
6497
+ const runId = await terminalizeUnroutableJob({
6498
+ db: extras.db,
6499
+ executionTracker: extras.executionTracker,
6500
+ checkRunReporter: extras.checkRunReporter,
6501
+ canRouteLabels: extras.canRouteLabels
6502
+ }, job);
6503
+ if (runId) affectedRunIds.add(runId);
6397
6504
  }
6398
6505
  for (const runId of affectedRunIds) try {
6399
6506
  await extras.executionTracker.completeRunIfAllJobsTerminal(runId);
6400
6507
  } catch (err) {
6401
- logger$117.error("Error checking run completion after queue expiry", {
6508
+ logger$118.error("Error checking run completion after queue expiry", {
6402
6509
  runId,
6403
6510
  error: toErrorMessage(err)
6404
6511
  });
6405
6512
  }
6406
6513
  }
6407
- if (dedupDeleted > 0 || queueExpired > 0 || dispatchRowsPruned > 0 || logObjectsPruned > 0 || checkRunRowsPruned > 0) logger$117.info("Cleanup completed", {
6514
+ if (dedupDeleted > 0 || queueExpired > 0 || dispatchRowsPruned > 0 || logObjectsPruned > 0 || checkRunRowsPruned > 0) logger$118.info("Cleanup completed", {
6408
6515
  dedupDeleted,
6409
6516
  queueExpired,
6410
6517
  dispatchRowsPruned,
6411
6518
  logObjectsPruned,
6412
6519
  checkRunRowsPruned
6413
6520
  });
6414
- else logger$117.debug("Cleanup completed, nothing to clean");
6521
+ else logger$118.debug("Cleanup completed, nothing to clean");
6415
6522
  return {
6416
6523
  dedupDeleted,
6417
6524
  queueExpired,
@@ -6432,13 +6539,100 @@ function createCleanupHandler(dedup, queue, extras) {
6432
6539
  await runCleanup(dedup, queue, extras);
6433
6540
  };
6434
6541
  }
6435
- var logger$117;
6542
+ var logger$118;
6436
6543
  var init_cleanup$1 = __esmMin((() => {
6437
- init_job_check_run_completion();
6438
6544
  init_log_retention();
6439
6545
  init_request_idempotency();
6440
6546
  init_prometheus();
6441
- logger$117 = createLogger({ prefix: "cleanup" });
6547
+ init_terminalize_unroutable();
6548
+ logger$118 = createLogger({ prefix: "cleanup" });
6549
+ }));
6550
+ //#endregion
6551
+ //#region src/queue/unroutable-probe.ts
6552
+ /**
6553
+ * Probe cadence, derived from the grace rather than configured separately.
6554
+ *
6555
+ * The tick is an implementation detail of the grace window — it only has to be
6556
+ * fine-grained enough that the grace elapses on time — not independent policy,
6557
+ * so it deliberately does not earn its own cluster knob.
6558
+ */
6559
+ function probeTickIntervalMs(graceMs) {
6560
+ return Math.min(TICK_CEILING_MS, Math.max(TICK_FLOOR_MS, Math.floor(graceMs / 4)));
6561
+ }
6562
+ /**
6563
+ * Write the routing reason onto a job that is still waiting to be routed.
6564
+ *
6565
+ * The status guard matters: the reason is a statement about a job that has not
6566
+ * been picked up, so it must never annotate one that already started or
6567
+ * finished between the probe's read and this write.
6568
+ */
6569
+ function makeRoutingReasonWriter(db) {
6570
+ return async (runId, jobName, reason) => {
6571
+ await db.updateTable("execution_jobs").set({ routing_reason: reason }).where("run_id", "=", sql`${runId}::uuid`).where("job_name", "=", jobName).where("status", "in", [ExecutionJobStatus.enum.pending, ExecutionJobStatus.enum.queued]).execute();
6572
+ };
6573
+ }
6574
+ /**
6575
+ * Build the per-tick handler for the unroutable probe.
6576
+ *
6577
+ * The probe consults the SAME routability predicate the queue-expiry sweep uses
6578
+ * — one verdict, two moments in time — but asks on a short tick instead of once
6579
+ * an hour. On the first unroutable verdict it records the reason (so the cause
6580
+ * is visible while the job still waits) and starts a grace clock; only once the
6581
+ * job has been CONTINUOUSLY unroutable for the whole grace does it terminalize.
6582
+ * A job that reads routable again has both cleared, so a scaler reload or an
6583
+ * agent reconnect can never cost it its place in the queue.
6584
+ */
6585
+ function createUnroutableProbeHandler(deps) {
6586
+ return async () => {
6587
+ const graceMs = await deps.getGraceMs();
6588
+ if (graceMs <= 0) return;
6589
+ const candidates = await deps.queue.listUnroutableCandidates(deps.batchLimit ?? DEFAULT_BATCH_LIMIT$1);
6590
+ const now = Date.now();
6591
+ for (const job of candidates) {
6592
+ const verdict = classifyUnroutable(job, deps.canRouteLabels);
6593
+ if (!verdict.unroutable) {
6594
+ if (job.unroutableSince !== null) {
6595
+ await deps.queue.clearUnroutableState(job.id);
6596
+ await deps.setRoutingReason(job.runId, job.jobName, null);
6597
+ logger$117.info("Job became routable again; cleared unroutable state", {
6598
+ runId: job.runId,
6599
+ jobName: job.jobName
6600
+ });
6601
+ }
6602
+ continue;
6603
+ }
6604
+ if (job.unroutableSince === null) {
6605
+ await deps.queue.markUnroutableSince(job.id, new Date(now));
6606
+ await deps.setRoutingReason(job.runId, job.jobName, verdict.errorMessage);
6607
+ logger$117.warn("Job is unroutable; starting grace window", {
6608
+ runId: job.runId,
6609
+ jobName: job.jobName,
6610
+ graceMs,
6611
+ reason: verdict.errorMessage
6612
+ });
6613
+ continue;
6614
+ }
6615
+ if (now - job.unroutableSince.getTime() >= graceMs) {
6616
+ if (!await deps.queue.claimUnroutable(job.id)) continue;
6617
+ await deps.terminalize(job);
6618
+ deps.onFastFailed?.();
6619
+ logger$117.warn("Job stayed unroutable for the whole grace window; failed it", {
6620
+ runId: job.runId,
6621
+ jobName: job.jobName,
6622
+ graceMs
6623
+ });
6624
+ }
6625
+ }
6626
+ };
6627
+ }
6628
+ var logger$117, TICK_FLOOR_MS, TICK_CEILING_MS, DEFAULT_BATCH_LIMIT$1, DEFAULT_UNROUTABLE_GRACE_MS;
6629
+ var init_unroutable_probe = __esmMin((() => {
6630
+ init_terminalize_unroutable();
6631
+ logger$117 = createLogger({ prefix: "unroutable-probe" });
6632
+ TICK_FLOOR_MS = 5e3;
6633
+ TICK_CEILING_MS = 3e4;
6634
+ DEFAULT_BATCH_LIMIT$1 = 200;
6635
+ DEFAULT_UNROUTABLE_GRACE_MS = 12e4;
6442
6636
  }));
6443
6637
  //#endregion
6444
6638
  //#region src/metrics/scheduled-jobs.ts
@@ -6670,7 +6864,8 @@ var init_scheduled_job = __esmMin((() => {
6670
6864
  "orphan-secret-cleanup",
6671
6865
  "token-cleanup",
6672
6866
  "cold-store-archive",
6673
- "cold-store-purge"
6867
+ "cold-store-purge",
6868
+ "unroutable-probe"
6674
6869
  ]);
6675
6870
  ACCESS_LOG_ACTION_TICK_FAILURE = "scheduled_job.tick";
6676
6871
  ACCESS_LOG_ACTION_TRIGGER = "scheduled_job.trigger";
@@ -6692,6 +6887,12 @@ function bootstrapOrchestratorScheduledJobs(deps, registrations) {
6692
6887
  intervalMs: registrations.cleanup.intervalMs,
6693
6888
  handler: registrations.cleanup.handler
6694
6889
  }));
6890
+ if (registrations.unroutableProbe) handles.push(registerOrchestratorScheduledJob({
6891
+ ...common,
6892
+ name: "unroutable-probe",
6893
+ intervalMs: registrations.unroutableProbe.intervalMs,
6894
+ handler: registrations.unroutableProbe.handler
6895
+ }));
6695
6896
  if (registrations.orphanSecretCleanup) handles.push(registerOrchestratorScheduledJob({
6696
6897
  ...common,
6697
6898
  name: "orphan-secret-cleanup",
@@ -18936,17 +19137,36 @@ var init_pg_secret_store = __esmMin((() => {
18936
19137
  }
18937
19138
  return result;
18938
19139
  }
18939
- /**
18940
- * Set (create or update) a secret in a scope.
18941
- * Encrypts the value with AAD = "orgId:scope:key".
18942
- */
18943
19140
  /** Check if a scope is internal/operational (always allowed regardless of toggle). */
18944
19141
  isInternalScope(scope) {
18945
19142
  const colonIdx = scope.indexOf(":");
18946
19143
  const path = colonIdx >= 0 ? scope.slice(colonIdx + 1) : scope;
18947
19144
  return path.startsWith("__source__/") || path.startsWith("__webhook__/");
18948
19145
  }
19146
+ /**
19147
+ * Set (create or update) a secret in a scope.
19148
+ * Encrypts the value with AAD = "orgId:scope:key".
19149
+ *
19150
+ * Rejects a key outside `[A-Za-z0-9._-]` before doing anything else. The AAD
19151
+ * is a plain concatenation, so a `:` in the key would let two distinct
19152
+ * locations render one AAD (scope 'b' + key 'c:d' equals scope 'b:c' + key
19153
+ * 'd') and a ciphertext written at one would authenticate at the other. The
19154
+ * check sits ahead of the customerSecretsEnabled gate so internal scopes get
19155
+ * no exemption — the binding has to hold for every writer.
19156
+ *
19157
+ * Callers pass a bare scope path, so the AAD's middle field is colon-free
19158
+ * too: the admin route and the dashboard handler both run the scope
19159
+ * validator immediately before calling in, and `source-store` builds its
19160
+ * scope from a uuid. That precondition is what makes the whole triple
19161
+ * recoverable, and it is the caller's to keep — this method does not
19162
+ * re-check it.
19163
+ *
19164
+ * Write-path only: getSecrets, listKeys, deleteSecret, deleteScope,
19165
+ * renameScope, getAllSecrets and createScope stay unvalidated, which is what
19166
+ * keeps a key stored before this rule readable and deletable.
19167
+ */
18949
19168
  async setSecret(orgId, scope, key, value) {
19169
+ assertValidSecretKey(key);
18950
19170
  if (!this.customerSecretsEnabled && !this.isInternalScope(scope)) throw new Error("PG customer secrets are disabled. Use an external secret backend or enable pgCustomerSecrets in config.");
18951
19171
  const aad = `${orgId}:${scope}:${key}`;
18952
19172
  const encrypted = encrypt(value, this.masterKey, this.keyVersion, aad);
@@ -20910,10 +21130,10 @@ var init_admin_sources = __esmMin((() => {
20910
21130
  //#endregion
20911
21131
  //#region src/db/migrations/001_initial.ts
20912
21132
  var _001_initial_exports = /* @__PURE__ */ __exportAll({
20913
- down: () => down$106,
20914
- up: () => up$106
21133
+ down: () => down$107,
21134
+ up: () => up$107
20915
21135
  });
20916
- async function up$106(db) {
21136
+ async function up$107(db) {
20917
21137
  for (const stmt of DDL_STATEMENTS) await sql.raw(stmt).execute(db);
20918
21138
  await sql`
20919
21139
  INSERT INTO cluster_meta (key, value)
@@ -20935,7 +21155,7 @@ async function up$106(db) {
20935
21155
  * Rollback drops everything created above. Uses CASCADE on table drops to cut
20936
21156
  * through the FK graph without relying on exact topological order.
20937
21157
  */
20938
- async function down$106(db) {
21158
+ async function down$107(db) {
20939
21159
  for (const [trig, tbl] of [["source_secrets_change_trigger", "scoped_secrets"], ["sources_change_trigger", "sources"]]) await sql.raw(`DROP TRIGGER IF EXISTS ${trig} ON public.${tbl}`).execute(db);
20940
21160
  for (const table of [
20941
21161
  "workflow_registrations",
@@ -21655,8 +21875,8 @@ var init__001_initial = __esmMin((() => {
21655
21875
  //#endregion
21656
21876
  //#region src/db/migrations/002_config_versions_key_version.ts
21657
21877
  var _002_config_versions_key_version_exports = /* @__PURE__ */ __exportAll({
21658
- down: () => down$105,
21659
- up: () => up$105
21878
+ down: () => down$106,
21879
+ up: () => up$106
21660
21880
  });
21661
21881
  /**
21662
21882
  * Add key_version column to config_versions so that sensitive-field encryption
@@ -21670,13 +21890,13 @@ var _002_config_versions_key_version_exports = /* @__PURE__ */ __exportAll({
21670
21890
  * No index is needed: rotation does a full-table scan; reads are by
21671
21891
  * `version` primary key and never filter on `key_version`.
21672
21892
  */
21673
- async function up$105(db) {
21893
+ async function up$106(db) {
21674
21894
  await sql`
21675
21895
  ALTER TABLE public.config_versions
21676
21896
  ADD COLUMN key_version integer NOT NULL DEFAULT 1
21677
21897
  `.execute(db);
21678
21898
  }
21679
- async function down$105(db) {
21899
+ async function down$106(db) {
21680
21900
  await sql`
21681
21901
  ALTER TABLE public.config_versions
21682
21902
  DROP COLUMN key_version
@@ -21686,8 +21906,8 @@ var init__002_config_versions_key_version = __esmMin((() => {}));
21686
21906
  //#endregion
21687
21907
  //#region src/db/migrations/003_access_log.ts
21688
21908
  var _003_access_log_exports = /* @__PURE__ */ __exportAll({
21689
- down: () => down$104,
21690
- up: () => up$104
21909
+ down: () => down$105,
21910
+ up: () => up$105
21691
21911
  });
21692
21912
  /**
21693
21913
  * Access log: one row per read or orchestrator-admin mutation attributable
@@ -21711,7 +21931,7 @@ var _003_access_log_exports = /* @__PURE__ */ __exportAll({
21711
21931
  * Retention is TTL-based via expires_at; packages/orchestrator/src/queue/
21712
21932
  * cleanup.ts picks up the prune pass.
21713
21933
  */
21714
- async function up$104(db) {
21934
+ async function up$105(db) {
21715
21935
  await sql`
21716
21936
  CREATE TABLE public.access_log (
21717
21937
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -21749,21 +21969,21 @@ async function up$104(db) {
21749
21969
  ON public.access_log (actor_type, actor_id, created_at DESC)
21750
21970
  `.execute(db);
21751
21971
  }
21752
- async function down$104(db) {
21972
+ async function down$105(db) {
21753
21973
  await sql`DROP TABLE IF EXISTS public.access_log`.execute(db);
21754
21974
  }
21755
21975
  var init__003_access_log = __esmMin((() => {}));
21756
21976
  //#endregion
21757
21977
  //#region src/db/migrations/004_rename_bundle_to_source.ts
21758
21978
  var _004_rename_bundle_to_source_exports = /* @__PURE__ */ __exportAll({
21759
- down: () => down$103,
21760
- up: () => up$103
21979
+ down: () => down$104,
21980
+ up: () => up$104
21761
21981
  });
21762
- async function up$103(db) {
21982
+ async function up$104(db) {
21763
21983
  await db.schema.alterTable("dispatch_queue").renameColumn("bundle_url", "source_tar_url").execute();
21764
21984
  await db.schema.alterTable("dispatch_queue").renameColumn("bundle_hash", "source_tar_hash").execute();
21765
21985
  }
21766
- async function down$103(db) {
21986
+ async function down$104(db) {
21767
21987
  await db.schema.alterTable("dispatch_queue").renameColumn("source_tar_url", "bundle_url").execute();
21768
21988
  await db.schema.alterTable("dispatch_queue").renameColumn("source_tar_hash", "bundle_hash").execute();
21769
21989
  }
@@ -21771,8 +21991,8 @@ var init__004_rename_bundle_to_source = __esmMin((() => {}));
21771
21991
  //#endregion
21772
21992
  //#region src/db/migrations/005_cold_store_chunk_counter.ts
21773
21993
  var _005_cold_store_chunk_counter_exports = /* @__PURE__ */ __exportAll({
21774
- down: () => down$102,
21775
- up: () => up$102
21994
+ down: () => down$103,
21995
+ up: () => up$103
21776
21996
  });
21777
21997
  /**
21778
21998
  * Cold-store chunk counter table.
@@ -21789,7 +22009,7 @@ var _005_cold_store_chunk_counter_exports = /* @__PURE__ */ __exportAll({
21789
22009
  *
21790
22010
  * sections 5 and 8.
21791
22011
  */
21792
- async function up$102(db) {
22012
+ async function up$103(db) {
21793
22013
  await sql`
21794
22014
  CREATE TABLE public.cold_store_chunk_counts (
21795
22015
  db TEXT NOT NULL,
@@ -21807,15 +22027,15 @@ async function up$102(db) {
21807
22027
  ON public.cold_store_chunk_counts (db, table_name)
21808
22028
  `.execute(db);
21809
22029
  }
21810
- async function down$102(db) {
22030
+ async function down$103(db) {
21811
22031
  await sql`DROP TABLE IF EXISTS public.cold_store_chunk_counts`.execute(db);
21812
22032
  }
21813
22033
  var init__005_cold_store_chunk_counter = __esmMin((() => {}));
21814
22034
  //#endregion
21815
22035
  //#region src/db/migrations/006_runs_jobs_steps_archived_at.ts
21816
22036
  var _006_runs_jobs_steps_archived_at_exports = /* @__PURE__ */ __exportAll({
21817
- down: () => down$101,
21818
- up: () => up$101
22037
+ down: () => down$102,
22038
+ up: () => up$102
21819
22039
  });
21820
22040
  /**
21821
22041
  * `execution_runs` / `execution_jobs` / `execution_steps` cold-store
@@ -21851,7 +22071,7 @@ var _006_runs_jobs_steps_archived_at_exports = /* @__PURE__ */ __exportAll({
21851
22071
  * - `idx_execution_jobs_routing_key_created (routing_key, created_at)`
21852
22072
  * - `idx_execution_steps_routing_key_created (routing_key, created_at)`
21853
22073
  */
21854
- async function up$101(db) {
22074
+ async function up$102(db) {
21855
22075
  await sql`
21856
22076
  ALTER TABLE public.execution_runs
21857
22077
  ADD COLUMN archived_at TIMESTAMPTZ NULL,
@@ -21896,7 +22116,7 @@ async function up$101(db) {
21896
22116
  ON public.execution_steps (routing_key, created_at)
21897
22117
  `.execute(db);
21898
22118
  }
21899
- async function down$101(db) {
22119
+ async function down$102(db) {
21900
22120
  await sql`DROP INDEX IF EXISTS public.idx_execution_steps_routing_key_created`.execute(db);
21901
22121
  await sql`
21902
22122
  ALTER TABLE public.execution_steps
@@ -21922,8 +22142,8 @@ var init__006_runs_jobs_steps_archived_at = __esmMin((() => {}));
21922
22142
  //#endregion
21923
22143
  //#region src/db/migrations/007_audit_logs_archived_at.ts
21924
22144
  var _007_audit_logs_archived_at_exports = /* @__PURE__ */ __exportAll({
21925
- down: () => down$100,
21926
- up: () => up$100
22145
+ down: () => down$101,
22146
+ up: () => up$101
21927
22147
  });
21928
22148
  /**
21929
22149
  * `secret_audit_log` and `access_log` cold-store schema additions, plus
@@ -21963,7 +22183,7 @@ var _007_audit_logs_archived_at_exports = /* @__PURE__ */ __exportAll({
21963
22183
  * `down()` would not have meaningful retention bounds. Acceptable for
21964
22184
  * staging.
21965
22185
  */
21966
- async function up$100(db) {
22186
+ async function up$101(db) {
21967
22187
  await sql`
21968
22188
  ALTER TABLE public.secret_audit_log
21969
22189
  ADD COLUMN archived_at TIMESTAMPTZ NULL,
@@ -21984,7 +22204,7 @@ async function up$100(db) {
21984
22204
  DROP COLUMN IF EXISTS expires_at
21985
22205
  `.execute(db);
21986
22206
  }
21987
- async function down$100(db) {
22207
+ async function down$101(db) {
21988
22208
  await sql`
21989
22209
  ALTER TABLE public.access_log
21990
22210
  ADD COLUMN expires_at TIMESTAMPTZ NOT NULL DEFAULT (now() + INTERVAL '90 days')
@@ -22013,8 +22233,8 @@ var init__007_audit_logs_archived_at = __esmMin((() => {}));
22013
22233
  //#endregion
22014
22234
  //#region src/db/migrations/008_event_log_archived_at.ts
22015
22235
  var _008_event_log_archived_at_exports = /* @__PURE__ */ __exportAll({
22016
- down: () => down$99,
22017
- up: () => up$99
22236
+ down: () => down$100,
22237
+ up: () => up$100
22018
22238
  });
22019
22239
  /**
22020
22240
  * `event_log` cold-store schema additions plus removal of the
@@ -22052,7 +22272,7 @@ var _008_event_log_archived_at_exports = /* @__PURE__ */ __exportAll({
22052
22272
  * — best effort; rows inserted between `up()` and a hypothetical
22053
22273
  * `down()` would not have meaningful retention bounds.
22054
22274
  */
22055
- async function up$99(db) {
22275
+ async function up$100(db) {
22056
22276
  await sql`
22057
22277
  ALTER TABLE public.event_log
22058
22278
  ADD COLUMN archived_at TIMESTAMPTZ NULL,
@@ -22068,7 +22288,7 @@ async function up$99(db) {
22068
22288
  DROP COLUMN IF EXISTS expires_at
22069
22289
  `.execute(db);
22070
22290
  }
22071
- async function down$99(db) {
22291
+ async function down$100(db) {
22072
22292
  await sql`
22073
22293
  ALTER TABLE public.event_log
22074
22294
  ADD COLUMN expires_at TIMESTAMPTZ NOT NULL DEFAULT (now() + INTERVAL '30 days')
@@ -22088,8 +22308,8 @@ var init__008_event_log_archived_at = __esmMin((() => {}));
22088
22308
  //#endregion
22089
22309
  //#region src/db/migrations/009_access_log_trigram.ts
22090
22310
  var _009_access_log_trigram_exports = /* @__PURE__ */ __exportAll({
22091
- down: () => down$98,
22092
- up: () => up$98
22311
+ down: () => down$99,
22312
+ up: () => up$99
22093
22313
  });
22094
22314
  /**
22095
22315
  * Trigram (pg_trgm) index on access_log.error_message for the federated
@@ -22102,7 +22322,7 @@ var _009_access_log_trigram_exports = /* @__PURE__ */ __exportAll({
22102
22322
  * EXISTS` are both safe to re-run. No CONCURRENTLY because Kysely runs
22103
22323
  * migrations inside a transaction; the lock is brief on a sampled table.
22104
22324
  */
22105
- async function up$98(db) {
22325
+ async function up$99(db) {
22106
22326
  await sql`CREATE EXTENSION IF NOT EXISTS pg_trgm`.execute(db);
22107
22327
  await sql`
22108
22328
  CREATE INDEX IF NOT EXISTS access_log_error_message_trgm_idx
@@ -22111,15 +22331,15 @@ async function up$98(db) {
22111
22331
  WHERE error_message IS NOT NULL
22112
22332
  `.execute(db);
22113
22333
  }
22114
- async function down$98(db) {
22334
+ async function down$99(db) {
22115
22335
  await sql`DROP INDEX IF EXISTS public.access_log_error_message_trgm_idx`.execute(db);
22116
22336
  }
22117
22337
  var init__009_access_log_trigram = __esmMin((() => {}));
22118
22338
  //#endregion
22119
22339
  //#region src/db/migrations/010_cold_store_chunks.ts
22120
22340
  var _010_cold_store_chunks_exports = /* @__PURE__ */ __exportAll({
22121
- down: () => down$97,
22122
- up: () => up$97
22341
+ down: () => down$98,
22342
+ up: () => up$98
22123
22343
  });
22124
22344
  /**
22125
22345
  * Cold-store chunk index — Phase 2 (cold-store purge).
@@ -22151,7 +22371,7 @@ var _010_cold_store_chunks_exports = /* @__PURE__ */ __exportAll({
22151
22371
  * forever. Adapters that don't opt into per-bucket archival via
22152
22372
  * `coldTtlDays` don't insert here either.
22153
22373
  */
22154
- async function up$97(db) {
22374
+ async function up$98(db) {
22155
22375
  await sql`
22156
22376
  CREATE TABLE public.cold_store_chunks (
22157
22377
  db TEXT NOT NULL,
@@ -22178,15 +22398,15 @@ async function up$97(db) {
22178
22398
  ON public.cold_store_chunks (db, table_name, tenant_id, archived_at DESC)
22179
22399
  `.execute(db);
22180
22400
  }
22181
- async function down$97(db) {
22401
+ async function down$98(db) {
22182
22402
  await sql`DROP TABLE IF EXISTS public.cold_store_chunks`.execute(db);
22183
22403
  }
22184
22404
  var init__010_cold_store_chunks = __esmMin((() => {}));
22185
22405
  //#endregion
22186
22406
  //#region src/db/migrations/011_drop_source_secrets_notify.ts
22187
22407
  var _011_drop_source_secrets_notify_exports = /* @__PURE__ */ __exportAll({
22188
- down: () => down$96,
22189
- up: () => up$96
22408
+ down: () => down$97,
22409
+ up: () => up$97
22190
22410
  });
22191
22411
  /**
22192
22412
  * Drop the `source_secrets_change_trigger` and the
@@ -22205,11 +22425,11 @@ var _011_drop_source_secrets_notify_exports = /* @__PURE__ */ __exportAll({
22205
22425
  * in `001_initial.ts`. They wake up no consumer until the `WebhookSecretManager`
22206
22426
  * is restored, so this migration is safe to roll back.
22207
22427
  */
22208
- async function up$96(db) {
22428
+ async function up$97(db) {
22209
22429
  await sql`DROP TRIGGER IF EXISTS source_secrets_change_trigger ON public.scoped_secrets`.execute(db);
22210
22430
  await sql`DROP FUNCTION IF EXISTS public.notify_source_secrets_change() CASCADE`.execute(db);
22211
22431
  }
22212
- async function down$96(db) {
22432
+ async function down$97(db) {
22213
22433
  await sql`
22214
22434
  CREATE OR REPLACE FUNCTION public.notify_source_secrets_change() RETURNS trigger
22215
22435
  LANGUAGE plpgsql
@@ -22249,8 +22469,8 @@ var init__011_drop_source_secrets_notify = __esmMin((() => {}));
22249
22469
  //#endregion
22250
22470
  //#region src/db/migrations/012_peer_credentials_active_uniq.ts
22251
22471
  var _012_peer_credentials_active_uniq_exports = /* @__PURE__ */ __exportAll({
22252
- down: () => down$95,
22253
- up: () => up$95
22472
+ down: () => down$96,
22473
+ up: () => up$96
22254
22474
  });
22255
22475
  /**
22256
22476
  * Add a partial unique index on `peer_credentials (instance_id) WHERE
@@ -22276,7 +22496,7 @@ var _012_peer_credentials_active_uniq_exports = /* @__PURE__ */ __exportAll({
22276
22496
  * `down()` only drops the index; it does NOT undo the dedupe (there's no
22277
22497
  * safe way to recreate revoked rows, and the dedupe is monotonic).
22278
22498
  */
22279
- async function up$95(db) {
22499
+ async function up$96(db) {
22280
22500
  await sql`
22281
22501
  UPDATE public.peer_credentials
22282
22502
  SET revoked_at = NOW()
@@ -22294,15 +22514,15 @@ async function up$95(db) {
22294
22514
  WHERE revoked_at IS NULL
22295
22515
  `.execute(db);
22296
22516
  }
22297
- async function down$95(db) {
22517
+ async function down$96(db) {
22298
22518
  await sql`DROP INDEX IF EXISTS public.peer_credentials_active_uniq`.execute(db);
22299
22519
  }
22300
22520
  var init__012_peer_credentials_active_uniq = __esmMin((() => {}));
22301
22521
  //#endregion
22302
22522
  //#region src/db/migrations/013_execution_log_bytes.ts
22303
22523
  var _013_execution_log_bytes_exports = /* @__PURE__ */ __exportAll({
22304
- down: () => down$94,
22305
- up: () => up$94
22524
+ down: () => down$95,
22525
+ up: () => up$95
22306
22526
  });
22307
22527
  /**
22308
22528
  * Add `log_bytes BIGINT NOT NULL DEFAULT 0` columns to `execution_runs` and
@@ -22321,7 +22541,7 @@ var _013_execution_log_bytes_exports = /* @__PURE__ */ __exportAll({
22321
22541
  *
22322
22542
  * Idempotent (`ADD COLUMN IF NOT EXISTS`).
22323
22543
  */
22324
- async function up$94(db) {
22544
+ async function up$95(db) {
22325
22545
  await sql`
22326
22546
  ALTER TABLE public.execution_runs
22327
22547
  ADD COLUMN IF NOT EXISTS log_bytes BIGINT NOT NULL DEFAULT 0
@@ -22331,7 +22551,7 @@ async function up$94(db) {
22331
22551
  ADD COLUMN IF NOT EXISTS log_bytes BIGINT NOT NULL DEFAULT 0
22332
22552
  `.execute(db);
22333
22553
  }
22334
- async function down$94(db) {
22554
+ async function down$95(db) {
22335
22555
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS log_bytes`.execute(db);
22336
22556
  await sql`ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS log_bytes`.execute(db);
22337
22557
  }
@@ -22339,8 +22559,8 @@ var init__013_execution_log_bytes = __esmMin((() => {}));
22339
22559
  //#endregion
22340
22560
  //#region src/db/migrations/014_kici_events_lease_retry.ts
22341
22561
  var _014_kici_events_lease_retry_exports = /* @__PURE__ */ __exportAll({
22342
- down: () => down$93,
22343
- up: () => up$93
22562
+ down: () => down$94,
22563
+ up: () => up$94
22344
22564
  });
22345
22565
  /**
22346
22566
  * Add lease + retry + DLQ columns to `kici_events` so the EventRouter can
@@ -22374,7 +22594,7 @@ var _014_kici_events_lease_retry_exports = /* @__PURE__ */ __exportAll({
22374
22594
  *
22375
22595
  * Idempotent (`ADD COLUMN IF NOT EXISTS` + `CREATE INDEX IF NOT EXISTS`).
22376
22596
  */
22377
- async function up$93(db) {
22597
+ async function up$94(db) {
22378
22598
  await sql`
22379
22599
  ALTER TABLE public.kici_events
22380
22600
  ADD COLUMN IF NOT EXISTS claimed_at TIMESTAMPTZ,
@@ -22405,7 +22625,7 @@ async function up$93(db) {
22405
22625
  WHERE dlq_at IS NOT NULL
22406
22626
  `.execute(db);
22407
22627
  }
22408
- async function down$93(db) {
22628
+ async function down$94(db) {
22409
22629
  await sql`DROP INDEX IF EXISTS public.idx_kici_events_dlq`.execute(db);
22410
22630
  await sql`DROP INDEX IF EXISTS public.idx_kici_events_lease_expired`.execute(db);
22411
22631
  await sql`DROP INDEX IF EXISTS public.idx_kici_events_retry_due`.execute(db);
@@ -22424,8 +22644,8 @@ var init__014_kici_events_lease_retry = __esmMin((() => {}));
22424
22644
  //#endregion
22425
22645
  //#region src/db/migrations/015_org_settings_customer_scoped.ts
22426
22646
  var _015_org_settings_customer_scoped_exports = /* @__PURE__ */ __exportAll({
22427
- down: () => down$92,
22428
- up: () => up$92
22647
+ down: () => down$93,
22648
+ up: () => up$93
22429
22649
  });
22430
22650
  /**
22431
22651
  * Org-scope `org_settings` and qualify each glob entry by source.
@@ -22453,7 +22673,7 @@ var _015_org_settings_customer_scoped_exports = /* @__PURE__ */ __exportAll({
22453
22673
  * Idempotent: a re-run on an already-migrated DB sees `customer_id` exists
22454
22674
  * and the list columns are already jsonb, so it is a no-op.
22455
22675
  */
22456
- async function up$92(db) {
22676
+ async function up$93(db) {
22457
22677
  if ((await sql`
22458
22678
  SELECT EXISTS (
22459
22679
  SELECT 1 FROM information_schema.columns
@@ -22578,7 +22798,7 @@ async function up$92(db) {
22578
22798
  await sql`DROP TABLE _org_settings_merged`.execute(db);
22579
22799
  await sql`DROP TABLE _org_settings_stage`.execute(db);
22580
22800
  }
22581
- async function down$92(db) {
22801
+ async function down$93(db) {
22582
22802
  if (!(await sql`
22583
22803
  SELECT EXISTS (
22584
22804
  SELECT 1 FROM information_schema.columns
@@ -22604,8 +22824,8 @@ var init__015_org_settings_customer_scoped = __esmMin((() => {}));
22604
22824
  //#endregion
22605
22825
  //#region src/db/migrations/016_org_settings_allow_http_npm.ts
22606
22826
  var _016_org_settings_allow_http_npm_exports = /* @__PURE__ */ __exportAll({
22607
- down: () => down$91,
22608
- up: () => up$91
22827
+ down: () => down$92,
22828
+ up: () => up$92
22609
22829
  });
22610
22830
  /**
22611
22831
  * Add `org_settings.allow_http_npm_registries boolean NOT NULL DEFAULT false`.
@@ -22618,7 +22838,7 @@ var _016_org_settings_allow_http_npm_exports = /* @__PURE__ */ __exportAll({
22618
22838
  *
22619
22839
  * Idempotent: a re-run on a DB that already has the column is a no-op.
22620
22840
  */
22621
- async function up$91(db) {
22841
+ async function up$92(db) {
22622
22842
  if ((await sql`
22623
22843
  SELECT EXISTS (
22624
22844
  SELECT 1 FROM information_schema.columns
@@ -22632,7 +22852,7 @@ async function up$91(db) {
22632
22852
  ADD COLUMN allow_http_npm_registries boolean NOT NULL DEFAULT false
22633
22853
  `.execute(db);
22634
22854
  }
22635
- async function down$91(db) {
22855
+ async function down$92(db) {
22636
22856
  await sql`
22637
22857
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS allow_http_npm_registries
22638
22858
  `.execute(db);
@@ -22641,13 +22861,13 @@ var init__016_org_settings_allow_http_npm = __esmMin((() => {}));
22641
22861
  //#endregion
22642
22862
  //#region src/db/migrations/017_org_id_widen.ts
22643
22863
  var _017_org_id_widen_exports = /* @__PURE__ */ __exportAll({
22644
- down: () => down$90,
22645
- up: () => up$90
22864
+ down: () => down$91,
22865
+ up: () => up$91
22646
22866
  });
22647
- async function up$90(db) {
22867
+ async function up$91(db) {
22648
22868
  for (const table of ORG_ID_TABLES$1) await sql.raw(`ALTER TABLE public.${table} ALTER COLUMN org_id TYPE varchar(16)`).execute(db);
22649
22869
  }
22650
- async function down$90(db) {
22870
+ async function down$91(db) {
22651
22871
  for (const table of ORG_ID_TABLES$1) await sql.raw(`ALTER TABLE public.${table} ALTER COLUMN org_id TYPE varchar(12)`).execute(db);
22652
22872
  }
22653
22873
  var ORG_ID_TABLES$1;
@@ -22666,14 +22886,14 @@ var init__017_org_id_widen = __esmMin((() => {
22666
22886
  //#endregion
22667
22887
  //#region src/db/migrations/018_org_id_prefix_backfill.ts
22668
22888
  var _018_org_id_prefix_backfill_exports = /* @__PURE__ */ __exportAll({
22669
- down: () => down$89,
22670
- up: () => up$89
22889
+ down: () => down$90,
22890
+ up: () => up$90
22671
22891
  });
22672
- async function up$89(db) {
22892
+ async function up$90(db) {
22673
22893
  for (const table of ORG_ID_TABLES) await sql.raw(`UPDATE public.${table} SET org_id = 'org_' || org_id WHERE org_id <> 'kici-admin' AND org_id NOT LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
22674
22894
  for (const table of CUSTOMER_ID_TABLES) await sql.raw(`UPDATE public.${table} SET customer_id = 'org_' || customer_id WHERE customer_id <> 'kici-admin' AND customer_id NOT LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
22675
22895
  }
22676
- async function down$89(db) {
22896
+ async function down$90(db) {
22677
22897
  for (const table of CUSTOMER_ID_TABLES) await sql.raw(`UPDATE public.${table} SET customer_id = substring(customer_id from 5) WHERE customer_id LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
22678
22898
  for (const table of ORG_ID_TABLES) await sql.raw(`UPDATE public.${table} SET org_id = substring(org_id from 5) WHERE org_id LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
22679
22899
  }
@@ -22699,8 +22919,8 @@ var init__018_org_id_prefix_backfill = __esmMin((() => {
22699
22919
  //#endregion
22700
22920
  //#region src/db/migrations/019_generic_sources_change_notify.ts
22701
22921
  var _019_generic_sources_change_notify_exports = /* @__PURE__ */ __exportAll({
22702
- down: () => down$88,
22703
- up: () => up$88
22922
+ down: () => down$89,
22923
+ up: () => up$89
22704
22924
  });
22705
22925
  /**
22706
22926
  * Add a Postgres trigger on `generic_webhook_sources` that emits
@@ -22723,7 +22943,7 @@ var _019_generic_sources_change_notify_exports = /* @__PURE__ */ __exportAll({
22723
22943
  * (`notify_sources_change()` + `sources_change_trigger`, defined in
22724
22944
  * `001_initial.ts`).
22725
22945
  */
22726
- async function up$88(db) {
22946
+ async function up$89(db) {
22727
22947
  await sql`
22728
22948
  CREATE FUNCTION public.notify_generic_sources_change() RETURNS trigger
22729
22949
  LANGUAGE plpgsql
@@ -22744,7 +22964,7 @@ async function up$88(db) {
22744
22964
  FOR EACH ROW EXECUTE FUNCTION public.notify_generic_sources_change()
22745
22965
  `.execute(db);
22746
22966
  }
22747
- async function down$88(db) {
22967
+ async function down$89(db) {
22748
22968
  await sql`DROP TRIGGER IF EXISTS generic_sources_change_trigger ON public.generic_webhook_sources`.execute(db);
22749
22969
  await sql`DROP FUNCTION IF EXISTS public.notify_generic_sources_change()`.execute(db);
22750
22970
  }
@@ -22752,8 +22972,8 @@ var init__019_generic_sources_change_notify = __esmMin((() => {}));
22752
22972
  //#endregion
22753
22973
  //#region src/db/migrations/020_org_settings_dashboard_write_policy.ts
22754
22974
  var _020_org_settings_dashboard_write_policy_exports = /* @__PURE__ */ __exportAll({
22755
- down: () => down$87,
22756
- up: () => up$87
22975
+ down: () => down$88,
22976
+ up: () => up$88
22757
22977
  });
22758
22978
  /**
22759
22979
  * Add `org_settings.dashboard_write_policy jsonb NOT NULL DEFAULT '{}'`.
@@ -22768,7 +22988,7 @@ var _020_org_settings_dashboard_write_policy_exports = /* @__PURE__ */ __exportA
22768
22988
  *
22769
22989
  * Idempotent: a re-run on a DB that already has the column is a no-op.
22770
22990
  */
22771
- async function up$87(db) {
22991
+ async function up$88(db) {
22772
22992
  if ((await sql`
22773
22993
  SELECT EXISTS (
22774
22994
  SELECT 1 FROM information_schema.columns
@@ -22782,7 +23002,7 @@ async function up$87(db) {
22782
23002
  ADD COLUMN dashboard_write_policy jsonb NOT NULL DEFAULT '{}'::jsonb
22783
23003
  `.execute(db);
22784
23004
  }
22785
- async function down$87(db) {
23005
+ async function down$88(db) {
22786
23006
  await sql`
22787
23007
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS dashboard_write_policy
22788
23008
  `.execute(db);
@@ -22791,8 +23011,8 @@ var init__020_org_settings_dashboard_write_policy = __esmMin((() => {}));
22791
23011
  //#endregion
22792
23012
  //#region src/db/migrations/021_check_run_tracking.ts
22793
23013
  var _021_check_run_tracking_exports = /* @__PURE__ */ __exportAll({
22794
- down: () => down$86,
22795
- up: () => up$86
23014
+ down: () => down$87,
23015
+ up: () => up$87
22796
23016
  });
22797
23017
  /**
22798
23018
  * Add `check_run_tracking` table for HA-safe check-run state persistence.
@@ -22816,7 +23036,7 @@ var _021_check_run_tracking_exports = /* @__PURE__ */ __exportAll({
22816
23036
  *
22817
23037
  * Idempotent: a re-run on a DB that already has the table is a no-op.
22818
23038
  */
22819
- async function up$86(db) {
23039
+ async function up$87(db) {
22820
23040
  if ((await sql`
22821
23041
  SELECT EXISTS (
22822
23042
  SELECT 1 FROM information_schema.tables
@@ -22847,15 +23067,15 @@ async function up$86(db) {
22847
23067
  WHERE run_id IS NOT NULL
22848
23068
  `.execute(db);
22849
23069
  }
22850
- async function down$86(db) {
23070
+ async function down$87(db) {
22851
23071
  await sql`DROP TABLE IF EXISTS public.check_run_tracking`.execute(db);
22852
23072
  }
22853
23073
  var init__021_check_run_tracking = __esmMin((() => {}));
22854
23074
  //#endregion
22855
23075
  //#region src/db/migrations/022_scaler_manager_state.ts
22856
23076
  var _022_scaler_manager_state_exports = /* @__PURE__ */ __exportAll({
22857
- down: () => down$85,
22858
- up: () => up$85
23077
+ down: () => down$86,
23078
+ up: () => up$86
22859
23079
  });
22860
23080
  /**
22861
23081
  * Add three tables persisting `ScalerManager` per-coord state:
@@ -22882,7 +23102,7 @@ var _022_scaler_manager_state_exports = /* @__PURE__ */ __exportAll({
22882
23102
  * Idempotent: a re-run on a DB that already has any of these tables
22883
23103
  * leaves the existing one alone.
22884
23104
  */
22885
- async function up$85(db) {
23105
+ async function up$86(db) {
22886
23106
  const tableExists = async (name) => {
22887
23107
  return (await sql`
22888
23108
  SELECT EXISTS (
@@ -22932,7 +23152,7 @@ async function up$85(db) {
22932
23152
  `.execute(db);
22933
23153
  }
22934
23154
  }
22935
- async function down$85(db) {
23155
+ async function down$86(db) {
22936
23156
  await sql`DROP TABLE IF EXISTS public.scaler_reservations`.execute(db);
22937
23157
  await sql`DROP TABLE IF EXISTS public.scaler_agent_jobs`.execute(db);
22938
23158
  await sql`DROP TABLE IF EXISTS public.scaler_spawning_agents`.execute(db);
@@ -22941,8 +23161,8 @@ var init__022_scaler_manager_state = __esmMin((() => {}));
22941
23161
  //#endregion
22942
23162
  //#region src/db/migrations/023_dispatch_queue_recovery_deadline.ts
22943
23163
  var _023_dispatch_queue_recovery_deadline_exports = /* @__PURE__ */ __exportAll({
22944
- down: () => down$84,
22945
- up: () => up$84
23164
+ down: () => down$85,
23165
+ up: () => up$85
22946
23166
  });
22947
23167
  /**
22948
23168
  * Add `dispatch_queue.recovery_deadline TIMESTAMPTZ` and
@@ -22966,7 +23186,7 @@ var _023_dispatch_queue_recovery_deadline_exports = /* @__PURE__ */ __exportAll(
22966
23186
  * Idempotent: re-running on a DB that already has either column is a
22967
23187
  * no-op.
22968
23188
  */
22969
- async function up$84(db) {
23189
+ async function up$85(db) {
22970
23190
  const colExists = async (name) => {
22971
23191
  return (await sql`
22972
23192
  SELECT EXISTS (
@@ -22991,7 +23211,7 @@ async function up$84(db) {
22991
23211
  WHERE recovery_deadline IS NOT NULL
22992
23212
  `.execute(db);
22993
23213
  }
22994
- async function down$84(db) {
23214
+ async function down$85(db) {
22995
23215
  await sql`DROP INDEX IF EXISTS public.idx_dispatch_queue_recovery_deadline`.execute(db);
22996
23216
  await sql`
22997
23217
  ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS recovery_agent_id
@@ -23004,8 +23224,8 @@ var init__023_dispatch_queue_recovery_deadline = __esmMin((() => {}));
23004
23224
  //#endregion
23005
23225
  //#region src/db/migrations/024_dispatch_queue_provisioning_error.ts
23006
23226
  var _024_dispatch_queue_provisioning_error_exports = /* @__PURE__ */ __exportAll({
23007
- down: () => down$83,
23008
- up: () => up$83
23227
+ down: () => down$84,
23228
+ up: () => up$84
23009
23229
  });
23010
23230
  /**
23011
23231
  * Add `dispatch_queue.last_provisioning_error TEXT` recording the most
@@ -23021,7 +23241,7 @@ var _024_dispatch_queue_provisioning_error_exports = /* @__PURE__ */ __exportAll
23021
23241
  *
23022
23242
  * Idempotent: re-running on a DB that already has the column is a no-op.
23023
23243
  */
23024
- async function up$83(db) {
23244
+ async function up$84(db) {
23025
23245
  const colExists = async (name) => {
23026
23246
  return (await sql`
23027
23247
  SELECT EXISTS (
@@ -23037,7 +23257,7 @@ async function up$83(db) {
23037
23257
  ADD COLUMN last_provisioning_error TEXT
23038
23258
  `.execute(db);
23039
23259
  }
23040
- async function down$83(db) {
23260
+ async function down$84(db) {
23041
23261
  await sql`
23042
23262
  ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS last_provisioning_error
23043
23263
  `.execute(db);
@@ -23046,8 +23266,8 @@ var init__024_dispatch_queue_provisioning_error = __esmMin((() => {}));
23046
23266
  //#endregion
23047
23267
  //#region src/db/migrations/025_init_failure.ts
23048
23268
  var _025_init_failure_exports = /* @__PURE__ */ __exportAll({
23049
- down: () => down$82,
23050
- up: () => up$82
23269
+ down: () => down$83,
23270
+ up: () => up$83
23051
23271
  });
23052
23272
  /**
23053
23273
  * Add `init_failure jsonb` columns to `execution_runs` and `execution_jobs`.
@@ -23061,7 +23281,7 @@ var _025_init_failure_exports = /* @__PURE__ */ __exportAll({
23061
23281
  * Idempotent: re-running on a DB that already has either column is a no-op
23062
23282
  * for that column.
23063
23283
  */
23064
- async function up$82(db) {
23284
+ async function up$83(db) {
23065
23285
  const colExists = async (table, name) => {
23066
23286
  return (await sql`
23067
23287
  SELECT EXISTS (
@@ -23081,7 +23301,7 @@ async function up$82(db) {
23081
23301
  ADD COLUMN init_failure JSONB DEFAULT NULL
23082
23302
  `.execute(db);
23083
23303
  }
23084
- async function down$82(db) {
23304
+ async function down$83(db) {
23085
23305
  await sql`
23086
23306
  ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS init_failure
23087
23307
  `.execute(db);
@@ -23093,8 +23313,8 @@ var init__025_init_failure = __esmMin((() => {}));
23093
23313
  //#endregion
23094
23314
  //#region src/db/migrations/026_event_log_lockfile_corrupt.ts
23095
23315
  var _026_event_log_lockfile_corrupt_exports = /* @__PURE__ */ __exportAll({
23096
- down: () => down$81,
23097
- up: () => up$81
23316
+ down: () => down$82,
23317
+ up: () => up$82
23098
23318
  });
23099
23319
  /**
23100
23320
  * Extend the event_log.status CHECK constraint with 'lockfile_corrupt' so the
@@ -23103,7 +23323,7 @@ var _026_event_log_lockfile_corrupt_exports = /* @__PURE__ */ __exportAll({
23103
23323
  *
23104
23324
  * Idempotent: the DROP ... IF EXISTS / re-ADD pair re-runs cleanly.
23105
23325
  */
23106
- async function up$81(db) {
23326
+ async function up$82(db) {
23107
23327
  await sql`ALTER TABLE event_log DROP CONSTRAINT IF EXISTS event_log_status_check`.execute(db);
23108
23328
  await sql`
23109
23329
  ALTER TABLE event_log ADD CONSTRAINT event_log_status_check
@@ -23113,7 +23333,7 @@ async function up$81(db) {
23113
23333
  ])))
23114
23334
  `.execute(db);
23115
23335
  }
23116
- async function down$81(db) {
23336
+ async function down$82(db) {
23117
23337
  await sql`ALTER TABLE event_log DROP CONSTRAINT IF EXISTS event_log_status_check`.execute(db);
23118
23338
  await sql`
23119
23339
  ALTER TABLE event_log ADD CONSTRAINT event_log_status_check
@@ -23127,8 +23347,8 @@ var init__026_event_log_lockfile_corrupt = __esmMin((() => {}));
23127
23347
  //#endregion
23128
23348
  //#region src/db/migrations/027_workflow_timeout.ts
23129
23349
  var _027_workflow_timeout_exports = /* @__PURE__ */ __exportAll({
23130
- down: () => down$80,
23131
- up: () => up$80
23350
+ down: () => down$81,
23351
+ up: () => up$81
23132
23352
  });
23133
23353
  /**
23134
23354
  * Add `workflow_timeout_ms integer` to `execution_runs`.
@@ -23146,13 +23366,13 @@ var _027_workflow_timeout_exports = /* @__PURE__ */ __exportAll({
23146
23366
  *
23147
23367
  * Idempotent: re-running on a DB that already has the column is a no-op.
23148
23368
  */
23149
- async function up$80(db) {
23369
+ async function up$81(db) {
23150
23370
  await sql`
23151
23371
  ALTER TABLE public.execution_runs
23152
23372
  ADD COLUMN IF NOT EXISTS workflow_timeout_ms INTEGER DEFAULT NULL
23153
23373
  `.execute(db);
23154
23374
  }
23155
- async function down$80(db) {
23375
+ async function down$81(db) {
23156
23376
  await sql`
23157
23377
  ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS workflow_timeout_ms
23158
23378
  `.execute(db);
@@ -23161,8 +23381,8 @@ var init__027_workflow_timeout = __esmMin((() => {}));
23161
23381
  //#endregion
23162
23382
  //#region src/db/migrations/028_org_settings_user_cache.ts
23163
23383
  var _028_org_settings_user_cache_exports = /* @__PURE__ */ __exportAll({
23164
- down: () => down$79,
23165
- up: () => up$79
23384
+ down: () => down$80,
23385
+ up: () => up$80
23166
23386
  });
23167
23387
  /**
23168
23388
  * Add `org_settings.user_cache_quota_bytes bigint` and
@@ -23181,7 +23401,7 @@ var _028_org_settings_user_cache_exports = /* @__PURE__ */ __exportAll({
23181
23401
  *
23182
23402
  * Idempotent: a re-run on a DB that already has either column skips it.
23183
23403
  */
23184
- async function columnExists$5(db, column) {
23404
+ async function columnExists$6(db, column) {
23185
23405
  return (await sql`
23186
23406
  SELECT EXISTS (
23187
23407
  SELECT 1 FROM information_schema.columns
@@ -23191,17 +23411,17 @@ async function columnExists$5(db, column) {
23191
23411
  ) AS exists
23192
23412
  `.execute(db)).rows[0]?.exists ?? false;
23193
23413
  }
23194
- async function up$79(db) {
23195
- if (!await columnExists$5(db, "user_cache_quota_bytes")) await sql`
23414
+ async function up$80(db) {
23415
+ if (!await columnExists$6(db, "user_cache_quota_bytes")) await sql`
23196
23416
  ALTER TABLE public.org_settings
23197
23417
  ADD COLUMN user_cache_quota_bytes bigint
23198
23418
  `.execute(db);
23199
- if (!await columnExists$5(db, "user_cache_ttl_ms")) await sql`
23419
+ if (!await columnExists$6(db, "user_cache_ttl_ms")) await sql`
23200
23420
  ALTER TABLE public.org_settings
23201
23421
  ADD COLUMN user_cache_ttl_ms bigint
23202
23422
  `.execute(db);
23203
23423
  }
23204
- async function down$79(db) {
23424
+ async function down$80(db) {
23205
23425
  await sql`
23206
23426
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS user_cache_quota_bytes
23207
23427
  `.execute(db);
@@ -23213,8 +23433,8 @@ var init__028_org_settings_user_cache = __esmMin((() => {}));
23213
23433
  //#endregion
23214
23434
  //#region src/db/migrations/029_dispatch_queue_attempts.ts
23215
23435
  var _029_dispatch_queue_attempts_exports = /* @__PURE__ */ __exportAll({
23216
- down: () => down$78,
23217
- up: () => up$78
23436
+ down: () => down$79,
23437
+ up: () => up$79
23218
23438
  });
23219
23439
  /**
23220
23440
  * Add `dispatch_queue.dispatch_attempts INT NOT NULL DEFAULT 0`.
@@ -23228,7 +23448,7 @@ var _029_dispatch_queue_attempts_exports = /* @__PURE__ */ __exportAll({
23228
23448
  *
23229
23449
  * Idempotent: re-running on a DB that already has the column is a no-op.
23230
23450
  */
23231
- async function up$78(db) {
23451
+ async function up$79(db) {
23232
23452
  if (!((await sql`
23233
23453
  SELECT EXISTS (
23234
23454
  SELECT 1 FROM information_schema.columns
@@ -23241,7 +23461,7 @@ async function up$78(db) {
23241
23461
  ADD COLUMN dispatch_attempts INT NOT NULL DEFAULT 0
23242
23462
  `.execute(db);
23243
23463
  }
23244
- async function down$78(db) {
23464
+ async function down$79(db) {
23245
23465
  await sql`
23246
23466
  ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS dispatch_attempts
23247
23467
  `.execute(db);
@@ -23250,8 +23470,8 @@ var init__029_dispatch_queue_attempts = __esmMin((() => {}));
23250
23470
  //#endregion
23251
23471
  //#region src/db/migrations/030_held_runs_env_set_null.ts
23252
23472
  var _030_held_runs_env_set_null_exports = /* @__PURE__ */ __exportAll({
23253
- down: () => down$77,
23254
- up: () => up$77
23473
+ down: () => down$78,
23474
+ up: () => up$78
23255
23475
  });
23256
23476
  /**
23257
23477
  * held_runs.environment_id becomes nullable with ON DELETE SET NULL so
@@ -23262,14 +23482,14 @@ var _030_held_runs_env_set_null_exports = /* @__PURE__ */ __exportAll({
23262
23482
  * Idempotent: dropping the NOT NULL and the constraint are both no-ops on a
23263
23483
  * re-run, and the constraint is re-created with the SET NULL action.
23264
23484
  */
23265
- async function up$77(db) {
23485
+ async function up$78(db) {
23266
23486
  await sql`ALTER TABLE public.held_runs ALTER COLUMN environment_id DROP NOT NULL`.execute(db);
23267
23487
  await sql`ALTER TABLE public.held_runs DROP CONSTRAINT IF EXISTS held_runs_environment_id_fkey`.execute(db);
23268
23488
  await sql`ALTER TABLE public.held_runs
23269
23489
  ADD CONSTRAINT held_runs_environment_id_fkey
23270
23490
  FOREIGN KEY (environment_id) REFERENCES public.environments(id) ON DELETE SET NULL`.execute(db);
23271
23491
  }
23272
- async function down$77(db) {
23492
+ async function down$78(db) {
23273
23493
  await sql`ALTER TABLE public.held_runs DROP CONSTRAINT IF EXISTS held_runs_environment_id_fkey`.execute(db);
23274
23494
  await sql`ALTER TABLE public.held_runs
23275
23495
  ADD CONSTRAINT held_runs_environment_id_fkey
@@ -23280,8 +23500,8 @@ var init__030_held_runs_env_set_null = __esmMin((() => {}));
23280
23500
  //#endregion
23281
23501
  //#region src/db/migrations/031_dispatch_queue_ack_deadline.ts
23282
23502
  var _031_dispatch_queue_ack_deadline_exports = /* @__PURE__ */ __exportAll({
23283
- down: () => down$76,
23284
- up: () => up$76
23503
+ down: () => down$77,
23504
+ up: () => up$77
23285
23505
  });
23286
23506
  /**
23287
23507
  * Add `dispatch_queue.ack_deadline TIMESTAMPTZ` and
@@ -23298,7 +23518,7 @@ var _031_dispatch_queue_ack_deadline_exports = /* @__PURE__ */ __exportAll({
23298
23518
  *
23299
23519
  * Idempotent: re-running on a DB that already has either column is a no-op.
23300
23520
  */
23301
- async function up$76(db) {
23521
+ async function up$77(db) {
23302
23522
  const colExists = async (name) => {
23303
23523
  return (await sql`
23304
23524
  SELECT EXISTS (
@@ -23323,7 +23543,7 @@ async function up$76(db) {
23323
23543
  WHERE ack_deadline IS NOT NULL
23324
23544
  `.execute(db);
23325
23545
  }
23326
- async function down$76(db) {
23546
+ async function down$77(db) {
23327
23547
  await sql`DROP INDEX IF EXISTS public.idx_dispatch_queue_ack_deadline`.execute(db);
23328
23548
  await sql`ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS ack_agent_id`.execute(db);
23329
23549
  await sql`ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS ack_deadline`.execute(db);
@@ -23332,8 +23552,8 @@ var init__031_dispatch_queue_ack_deadline = __esmMin((() => {}));
23332
23552
  //#endregion
23333
23553
  //#region src/db/migrations/032_org_settings_dispatch_ack_timeout.ts
23334
23554
  var _032_org_settings_dispatch_ack_timeout_exports = /* @__PURE__ */ __exportAll({
23335
- down: () => down$75,
23336
- up: () => up$75
23555
+ down: () => down$76,
23556
+ up: () => up$76
23337
23557
  });
23338
23558
  /**
23339
23559
  * Add `org_settings.dispatch_ack_timeout_ms BIGINT` (nullable).
@@ -23345,7 +23565,7 @@ var _032_org_settings_dispatch_ack_timeout_exports = /* @__PURE__ */ __exportAll
23345
23565
  *
23346
23566
  * Idempotent: a re-run on a DB that already has the column is a no-op.
23347
23567
  */
23348
- async function up$75(db) {
23568
+ async function up$76(db) {
23349
23569
  if ((await sql`
23350
23570
  SELECT EXISTS (
23351
23571
  SELECT 1 FROM information_schema.columns
@@ -23359,7 +23579,7 @@ async function up$75(db) {
23359
23579
  ADD COLUMN dispatch_ack_timeout_ms BIGINT
23360
23580
  `.execute(db);
23361
23581
  }
23362
- async function down$75(db) {
23582
+ async function down$76(db) {
23363
23583
  await sql`
23364
23584
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS dispatch_ack_timeout_ms
23365
23585
  `.execute(db);
@@ -23368,8 +23588,8 @@ var init__032_org_settings_dispatch_ack_timeout = __esmMin((() => {}));
23368
23588
  //#endregion
23369
23589
  //#region src/db/migrations/033_org_settings_approval.ts
23370
23590
  var _033_org_settings_approval_exports = /* @__PURE__ */ __exportAll({
23371
- down: () => down$74,
23372
- up: () => up$74
23591
+ down: () => down$75,
23592
+ up: () => up$75
23373
23593
  });
23374
23594
  /**
23375
23595
  * Add the two approval-policy columns to `org_settings`:
@@ -23386,7 +23606,7 @@ var _033_org_settings_approval_exports = /* @__PURE__ */ __exportAll({
23386
23606
  * and the orchestrator admin route. Idempotent: a re-run on a DB that already
23387
23607
  * has the columns is a no-op (each column is guarded independently).
23388
23608
  */
23389
- async function up$74(db) {
23609
+ async function up$75(db) {
23390
23610
  const colExists = async (column) => {
23391
23611
  return (await sql`
23392
23612
  SELECT EXISTS (
@@ -23406,7 +23626,7 @@ async function up$74(db) {
23406
23626
  ADD COLUMN allow_self_approval BOOLEAN NOT NULL DEFAULT true
23407
23627
  `.execute(db);
23408
23628
  }
23409
- async function down$74(db) {
23629
+ async function down$75(db) {
23410
23630
  await sql`
23411
23631
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS approval_expiry_seconds
23412
23632
  `.execute(db);
@@ -23418,8 +23638,8 @@ var init__033_org_settings_approval = __esmMin((() => {}));
23418
23638
  //#endregion
23419
23639
  //#region src/db/migrations/034_held_runs_generalize.ts
23420
23640
  var _034_held_runs_generalize_exports = /* @__PURE__ */ __exportAll({
23421
- down: () => down$73,
23422
- up: () => up$73
23641
+ down: () => down$74,
23642
+ up: () => up$74
23423
23643
  });
23424
23644
  /**
23425
23645
  * Generalize `held_runs` from an environment-only hold into the unified
@@ -23441,7 +23661,7 @@ var _034_held_runs_generalize_exports = /* @__PURE__ */ __exportAll({
23441
23661
  * New `held_run_approvals` table: one row per approver decision, FK to
23442
23662
  * `held_runs.id` (uuid) with ON DELETE CASCADE.
23443
23663
  */
23444
- async function up$73(db) {
23664
+ async function up$74(db) {
23445
23665
  const colExists = async (column) => {
23446
23666
  return (await sql`
23447
23667
  SELECT EXISTS (
@@ -23474,7 +23694,7 @@ async function up$73(db) {
23474
23694
  ON public.held_run_approvals USING btree (held_run_id)
23475
23695
  `.execute(db);
23476
23696
  }
23477
- async function down$73(db) {
23697
+ async function down$74(db) {
23478
23698
  await sql`DROP TABLE IF EXISTS public.held_run_approvals`.execute(db);
23479
23699
  await sql`ALTER TABLE public.held_runs DROP COLUMN IF EXISTS approval_requirement`.execute(db);
23480
23700
  await sql`ALTER TABLE public.held_runs DROP COLUMN IF EXISTS trigger_source`.execute(db);
@@ -23485,8 +23705,8 @@ var init__034_held_runs_generalize = __esmMin((() => {}));
23485
23705
  //#endregion
23486
23706
  //#region src/db/migrations/035_pending_workflow_contexts.ts
23487
23707
  var _035_pending_workflow_contexts_exports = /* @__PURE__ */ __exportAll({
23488
- down: () => down$72,
23489
- up: () => up$72
23708
+ down: () => down$73,
23709
+ up: () => up$73
23490
23710
  });
23491
23711
  /**
23492
23712
  * Pending workflow dispatch context — backs resume of a workflow whose install
@@ -23495,7 +23715,7 @@ var _035_pending_workflow_contexts_exports = /* @__PURE__ */ __exportAll({
23495
23715
  * wait-timer expiry, concurrency slot free). The row is deleted once the resume
23496
23716
  * dispatch has been kicked off.
23497
23717
  */
23498
- async function up$72(db) {
23718
+ async function up$73(db) {
23499
23719
  await sql`
23500
23720
  CREATE TABLE IF NOT EXISTS public.pending_workflow_contexts (
23501
23721
  run_id text PRIMARY KEY,
@@ -23505,15 +23725,15 @@ async function up$72(db) {
23505
23725
  )
23506
23726
  `.execute(db);
23507
23727
  }
23508
- async function down$72(db) {
23728
+ async function down$73(db) {
23509
23729
  await sql`DROP TABLE IF EXISTS public.pending_workflow_contexts`.execute(db);
23510
23730
  }
23511
23731
  var init__035_pending_workflow_contexts = __esmMin((() => {}));
23512
23732
  //#endregion
23513
23733
  //#region src/db/migrations/036_attestations.ts
23514
23734
  var _036_attestations_exports = /* @__PURE__ */ __exportAll({
23515
- down: () => down$71,
23516
- up: () => up$71
23735
+ down: () => down$72,
23736
+ up: () => up$72
23517
23737
  });
23518
23738
  /**
23519
23739
  * Add the `attestations` table for build-provenance bundles.
@@ -23526,7 +23746,7 @@ var _036_attestations_exports = /* @__PURE__ */ __exportAll({
23526
23746
  *
23527
23747
  * Idempotent: a re-run on a DB that already has the table is a no-op.
23528
23748
  */
23529
- async function up$71(db) {
23749
+ async function up$72(db) {
23530
23750
  if ((await sql`
23531
23751
  SELECT EXISTS (
23532
23752
  SELECT 1 FROM information_schema.tables
@@ -23552,15 +23772,15 @@ async function up$71(db) {
23552
23772
  ON public.attestations (run_id, job_id)
23553
23773
  `.execute(db);
23554
23774
  }
23555
- async function down$71(db) {
23775
+ async function down$72(db) {
23556
23776
  await sql`DROP TABLE IF EXISTS public.attestations`.execute(db);
23557
23777
  }
23558
23778
  var init__036_attestations = __esmMin((() => {}));
23559
23779
  //#endregion
23560
23780
  //#region src/db/migrations/037_generic_sources_provider_type_local.ts
23561
23781
  var _037_generic_sources_provider_type_local_exports = /* @__PURE__ */ __exportAll({
23562
- down: () => down$70,
23563
- up: () => up$70
23782
+ down: () => down$71,
23783
+ up: () => up$71
23564
23784
  });
23565
23785
  /**
23566
23786
  * Replace the `generic_webhook_sources.provider_type` CHECK constraint so it
@@ -23577,7 +23797,7 @@ var _037_generic_sources_provider_type_local_exports = /* @__PURE__ */ __exportA
23577
23797
  * Idempotent: the constraint is dropped IF EXISTS and recreated; the data
23578
23798
  * backfill is a plain UPDATE that is a no-op once no `'internal'` rows remain.
23579
23799
  */
23580
- async function up$70(db) {
23800
+ async function up$71(db) {
23581
23801
  await sql`
23582
23802
  ALTER TABLE public.generic_webhook_sources
23583
23803
  DROP CONSTRAINT IF EXISTS generic_webhook_sources_provider_type_check
@@ -23593,7 +23813,7 @@ async function up$70(db) {
23593
23813
  CHECK (provider_type = ANY (ARRAY['generic'::text, 'local'::text]))
23594
23814
  `.execute(db);
23595
23815
  }
23596
- async function down$70(db) {
23816
+ async function down$71(db) {
23597
23817
  await sql`
23598
23818
  ALTER TABLE public.generic_webhook_sources
23599
23819
  DROP CONSTRAINT IF EXISTS generic_webhook_sources_provider_type_check
@@ -23613,8 +23833,8 @@ var init__037_generic_sources_provider_type_local = __esmMin((() => {}));
23613
23833
  //#endregion
23614
23834
  //#region src/db/migrations/038_remote_sources.ts
23615
23835
  var _038_remote_sources_exports = /* @__PURE__ */ __exportAll({
23616
- down: () => down$69,
23617
- up: () => up$69
23836
+ down: () => down$70,
23837
+ up: () => up$70
23618
23838
  });
23619
23839
  /**
23620
23840
  * `remote_sources` anchors a Platform-relayed `kici run remote` to its real
@@ -23626,7 +23846,7 @@ var _038_remote_sources_exports = /* @__PURE__ */ __exportAll({
23626
23846
  *
23627
23847
  * Idempotent: a re-run on a DB that already has the table is a no-op.
23628
23848
  */
23629
- async function up$69(db) {
23849
+ async function up$70(db) {
23630
23850
  if ((await sql`
23631
23851
  SELECT EXISTS (
23632
23852
  SELECT 1 FROM information_schema.tables
@@ -23645,15 +23865,15 @@ async function up$69(db) {
23645
23865
  )
23646
23866
  `.execute(db);
23647
23867
  }
23648
- async function down$69(db) {
23868
+ async function down$70(db) {
23649
23869
  await sql`DROP TABLE IF EXISTS public.remote_sources`.execute(db);
23650
23870
  }
23651
23871
  var init__038_remote_sources = __esmMin((() => {}));
23652
23872
  //#endregion
23653
23873
  //#region src/db/migrations/039_host_roster.ts
23654
23874
  var _039_host_roster_exports = /* @__PURE__ */ __exportAll({
23655
- down: () => down$68,
23656
- up: () => up$68
23875
+ down: () => down$69,
23876
+ up: () => up$69
23657
23877
  });
23658
23878
  /**
23659
23879
  * `host_roster` is KiCI's declared inventory: one durable row per agent the
@@ -23670,7 +23890,7 @@ var _039_host_roster_exports = /* @__PURE__ */ __exportAll({
23670
23890
  *
23671
23891
  * Idempotent: a re-run on a DB that already has the table is a no-op.
23672
23892
  */
23673
- async function up$68(db) {
23893
+ async function up$69(db) {
23674
23894
  if ((await sql`
23675
23895
  SELECT EXISTS (
23676
23896
  SELECT 1 FROM information_schema.tables
@@ -23700,15 +23920,15 @@ async function up$68(db) {
23700
23920
  await sql`CREATE INDEX idx_host_roster_reap
23701
23921
  ON public.host_roster (lifecycle_class, last_seen)`.execute(db);
23702
23922
  }
23703
- async function down$68(db) {
23923
+ async function down$69(db) {
23704
23924
  await sql`DROP TABLE IF EXISTS public.host_roster`.execute(db);
23705
23925
  }
23706
23926
  var init__039_host_roster = __esmMin((() => {}));
23707
23927
  //#endregion
23708
23928
  //#region src/db/migrations/040_runsonall_pin.ts
23709
23929
  var _040_runsonall_pin_exports = /* @__PURE__ */ __exportAll({
23710
- down: () => down$67,
23711
- up: () => up$67
23930
+ down: () => down$68,
23931
+ up: () => up$68
23712
23932
  });
23713
23933
  /**
23714
23934
  * Add the `runsOnAll` host fan-out columns:
@@ -23735,7 +23955,7 @@ async function colExists$12(db, table, name) {
23735
23955
  ) AS exists
23736
23956
  `.execute(db)).rows[0]?.exists ?? false;
23737
23957
  }
23738
- async function up$67(db) {
23958
+ async function up$68(db) {
23739
23959
  if (!await colExists$12(db, "dispatch_queue", "pinned_agent_id")) await sql`ALTER TABLE public.dispatch_queue ADD COLUMN pinned_agent_id TEXT`.execute(db);
23740
23960
  if (!await colExists$12(db, "execution_jobs", "base_job_name")) await sql`ALTER TABLE public.execution_jobs ADD COLUMN base_job_name TEXT`.execute(db);
23741
23961
  if (!await colExists$12(db, "execution_jobs", "variant_kind")) await sql`ALTER TABLE public.execution_jobs ADD COLUMN variant_kind TEXT`.execute(db);
@@ -23746,7 +23966,7 @@ async function up$67(db) {
23746
23966
  WHERE pinned_agent_id IS NOT NULL
23747
23967
  `.execute(db);
23748
23968
  }
23749
- async function down$67(db) {
23969
+ async function down$68(db) {
23750
23970
  await sql`DROP INDEX IF EXISTS public.idx_dispatch_queue_pinned_agent`.execute(db);
23751
23971
  await sql`ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS pinned_agent_id`.execute(db);
23752
23972
  await sql`ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS variant_label`.execute(db);
@@ -23757,8 +23977,8 @@ var init__040_runsonall_pin = __esmMin((() => {}));
23757
23977
  //#endregion
23758
23978
  //#region src/db/migrations/041_wave_gated.ts
23759
23979
  var _041_wave_gated_exports = /* @__PURE__ */ __exportAll({
23760
- down: () => down$66,
23761
- up: () => up$66
23980
+ down: () => down$67,
23981
+ up: () => up$67
23762
23982
  });
23763
23983
  /**
23764
23984
  * Add the rolling fan-out wave-gate columns:
@@ -23788,7 +24008,7 @@ async function colExists$11(db, table, name) {
23788
24008
  ) AS exists
23789
24009
  `.execute(db)).rows[0]?.exists ?? false;
23790
24010
  }
23791
- async function up$66(db) {
24011
+ async function up$67(db) {
23792
24012
  if (!await colExists$11(db, "execution_jobs", "wave_gated")) await sql`ALTER TABLE public.execution_jobs ADD COLUMN wave_gated boolean NOT NULL DEFAULT false`.execute(db);
23793
24013
  if (!await colExists$11(db, "execution_jobs", "wave_max_parallel")) await sql`ALTER TABLE public.execution_jobs ADD COLUMN wave_max_parallel integer`.execute(db);
23794
24014
  if (!await colExists$11(db, "execution_jobs", "wave_fail_fast")) await sql`ALTER TABLE public.execution_jobs ADD COLUMN wave_fail_fast boolean`.execute(db);
@@ -23797,7 +24017,7 @@ async function up$66(db) {
23797
24017
  ON public.execution_jobs (run_id, base_job_name, wave_gated)
23798
24018
  `.execute(db);
23799
24019
  }
23800
- async function down$66(db) {
24020
+ async function down$67(db) {
23801
24021
  await sql`DROP INDEX IF EXISTS public.idx_execution_jobs_wave`.execute(db);
23802
24022
  await sql`ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS wave_fail_fast`.execute(db);
23803
24023
  await sql`ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS wave_max_parallel`.execute(db);
@@ -23807,8 +24027,8 @@ var init__041_wave_gated = __esmMin((() => {}));
23807
24027
  //#endregion
23808
24028
  //#region src/db/migrations/042_dispatch_queue_patterns.ts
23809
24029
  var _042_dispatch_queue_patterns_exports = /* @__PURE__ */ __exportAll({
23810
- down: () => down$65,
23811
- up: () => up$65
24030
+ down: () => down$66,
24031
+ up: () => up$66
23812
24032
  });
23813
24033
  /**
23814
24034
  * Add pattern columns to dispatch_queue. Exact labels stay in runs_on_labels /
@@ -23834,11 +24054,11 @@ async function colExists$10(db, table, name) {
23834
24054
  ) AS exists
23835
24055
  `.execute(db)).rows[0]?.exists ?? false;
23836
24056
  }
23837
- async function up$65(db) {
24057
+ async function up$66(db) {
23838
24058
  if (!await colExists$10(db, "dispatch_queue", "runs_on_patterns")) await sql`ALTER TABLE public.dispatch_queue ADD COLUMN runs_on_patterns jsonb NOT NULL DEFAULT '[]'::jsonb`.execute(db);
23839
24059
  if (!await colExists$10(db, "dispatch_queue", "exclude_patterns")) await sql`ALTER TABLE public.dispatch_queue ADD COLUMN exclude_patterns jsonb NOT NULL DEFAULT '[]'::jsonb`.execute(db);
23840
24060
  }
23841
- async function down$65(db) {
24061
+ async function down$66(db) {
23842
24062
  await sql`ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS exclude_patterns`.execute(db);
23843
24063
  await sql`ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS runs_on_patterns`.execute(db);
23844
24064
  }
@@ -23846,8 +24066,8 @@ var init__042_dispatch_queue_patterns = __esmMin((() => {}));
23846
24066
  //#endregion
23847
24067
  //#region src/db/migrations/043_rerouted_to_peer.ts
23848
24068
  var _043_rerouted_to_peer_exports = /* @__PURE__ */ __exportAll({
23849
- down: () => down$64,
23850
- up: () => up$64
24069
+ down: () => down$65,
24070
+ up: () => up$65
23851
24071
  });
23852
24072
  /**
23853
24073
  * Add a nullable `rerouted_to_peer text` marker to execution_jobs. Non-null
@@ -23868,18 +24088,18 @@ async function colExists$9(db, table, name) {
23868
24088
  ) AS exists
23869
24089
  `.execute(db)).rows[0]?.exists ?? false;
23870
24090
  }
23871
- async function up$64(db) {
24091
+ async function up$65(db) {
23872
24092
  if (!await colExists$9(db, "execution_jobs", "rerouted_to_peer")) await sql`ALTER TABLE public.execution_jobs ADD COLUMN rerouted_to_peer text`.execute(db);
23873
24093
  }
23874
- async function down$64(db) {
24094
+ async function down$65(db) {
23875
24095
  await sql`ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS rerouted_to_peer`.execute(db);
23876
24096
  }
23877
24097
  var init__043_rerouted_to_peer = __esmMin((() => {}));
23878
24098
  //#endregion
23879
24099
  //#region src/db/migrations/044_check_mode.ts
23880
24100
  var _044_check_mode_exports = /* @__PURE__ */ __exportAll({
23881
- down: () => down$63,
23882
- up: () => up$63
24101
+ down: () => down$64,
24102
+ up: () => up$64
23883
24103
  });
23884
24104
  /**
23885
24105
  * Add idempotent check-mode columns:
@@ -23906,13 +24126,13 @@ async function colExists$8(db, table, name) {
23906
24126
  ) AS exists
23907
24127
  `.execute(db)).rows[0]?.exists ?? false;
23908
24128
  }
23909
- async function up$63(db) {
24129
+ async function up$64(db) {
23910
24130
  if (!await colExists$8(db, "execution_runs", "check_mode")) await sql`ALTER TABLE public.execution_runs ADD COLUMN check_mode text`.execute(db);
23911
24131
  if (!await colExists$8(db, "execution_steps", "check_outcome")) await sql`ALTER TABLE public.execution_steps ADD COLUMN check_outcome text`.execute(db);
23912
24132
  if (!await colExists$8(db, "execution_steps", "drift_summary")) await sql`ALTER TABLE public.execution_steps ADD COLUMN drift_summary text`.execute(db);
23913
24133
  if (!await colExists$8(db, "execution_steps", "drift")) await sql`ALTER TABLE public.execution_steps ADD COLUMN drift jsonb`.execute(db);
23914
24134
  }
23915
- async function down$63(db) {
24135
+ async function down$64(db) {
23916
24136
  await sql`ALTER TABLE public.execution_steps DROP COLUMN IF EXISTS drift`.execute(db);
23917
24137
  await sql`ALTER TABLE public.execution_steps DROP COLUMN IF EXISTS drift_summary`.execute(db);
23918
24138
  await sql`ALTER TABLE public.execution_steps DROP COLUMN IF EXISTS check_outcome`.execute(db);
@@ -23922,8 +24142,8 @@ var init__044_check_mode = __esmMin((() => {}));
23922
24142
  //#endregion
23923
24143
  //#region src/db/migrations/045_host_properties.ts
23924
24144
  var _045_host_properties_exports = /* @__PURE__ */ __exportAll({
23925
- down: () => down$62,
23926
- up: () => up$62
24145
+ down: () => down$63,
24146
+ up: () => up$63
23927
24147
  });
23928
24148
  /**
23929
24149
  * Add the typed host-vars dimension to the host roster:
@@ -23937,19 +24157,19 @@ var _045_host_properties_exports = /* @__PURE__ */ __exportAll({
23937
24157
  * Idempotent (`ADD COLUMN IF NOT EXISTS`): re-running on a DB that already has
23938
24158
  * the column is a no-op. Staging data is preserved (additive column).
23939
24159
  */
23940
- async function up$62(db) {
24160
+ async function up$63(db) {
23941
24161
  await sql`ALTER TABLE public.host_roster
23942
24162
  ADD COLUMN IF NOT EXISTS host_properties jsonb NOT NULL DEFAULT '{}'::jsonb`.execute(db);
23943
24163
  }
23944
- async function down$62(db) {
24164
+ async function down$63(db) {
23945
24165
  await sql`ALTER TABLE public.host_roster DROP COLUMN IF EXISTS host_properties`.execute(db);
23946
24166
  }
23947
24167
  var init__045_host_properties = __esmMin((() => {}));
23948
24168
  //#endregion
23949
24169
  //#region src/db/migrations/046_join_token_consumed_by_instance.ts
23950
24170
  var _046_join_token_consumed_by_instance_exports = /* @__PURE__ */ __exportAll({
23951
- down: () => down$61,
23952
- up: () => up$61
24171
+ down: () => down$62,
24172
+ up: () => up$62
23953
24173
  });
23954
24174
  /**
23955
24175
  * Record the joining peer's instanceId at first consumption of a join token:
@@ -23964,19 +24184,19 @@ var _046_join_token_consumed_by_instance_exports = /* @__PURE__ */ __exportAll({
23964
24184
  * Idempotent (`ADD COLUMN IF NOT EXISTS`): re-running on a DB that already has
23965
24185
  * the column is a no-op. Staging data is preserved (additive nullable column).
23966
24186
  */
23967
- async function up$61(db) {
24187
+ async function up$62(db) {
23968
24188
  await sql`ALTER TABLE public.join_tokens
23969
24189
  ADD COLUMN IF NOT EXISTS consumed_by_instance text`.execute(db);
23970
24190
  }
23971
- async function down$61(db) {
24191
+ async function down$62(db) {
23972
24192
  await sql`ALTER TABLE public.join_tokens DROP COLUMN IF EXISTS consumed_by_instance`.execute(db);
23973
24193
  }
23974
24194
  var init__046_join_token_consumed_by_instance = __esmMin((() => {}));
23975
24195
  //#endregion
23976
24196
  //#region src/db/migrations/047_needs_run_on.ts
23977
24197
  var _047_needs_run_on_exports = /* @__PURE__ */ __exportAll({
23978
- down: () => down$60,
23979
- up: () => up$60
24198
+ down: () => down$61,
24199
+ up: () => up$61
23980
24200
  });
23981
24201
  async function colExists$7(db, table, name) {
23982
24202
  return (await sql`
@@ -23988,7 +24208,7 @@ async function colExists$7(db, table, name) {
23988
24208
  ) AS exists
23989
24209
  `.execute(db)).rows[0]?.exists ?? false;
23990
24210
  }
23991
- async function up$60(db) {
24211
+ async function up$61(db) {
23992
24212
  if (!await colExists$7(db, "execution_job_needs", "run_on")) await sql`
23993
24213
  ALTER TABLE public.execution_job_needs
23994
24214
  ADD COLUMN run_on text NOT NULL DEFAULT ${sql.raw(SUCCESS_ONLY_DEFAULT)}
@@ -24007,7 +24227,7 @@ async function up$60(db) {
24007
24227
  await sql`ALTER TABLE public.execution_job_needs DROP COLUMN if_failed`.execute(db);
24008
24228
  }
24009
24229
  }
24010
- async function down$60(db) {
24230
+ async function down$61(db) {
24011
24231
  if (!await colExists$7(db, "execution_job_needs", "if_failed")) await sql`
24012
24232
  ALTER TABLE public.execution_job_needs
24013
24233
  ADD COLUMN if_failed text NOT NULL DEFAULT 'skip'
@@ -24036,8 +24256,8 @@ var init__047_needs_run_on = __esmMin((() => {
24036
24256
  //#endregion
24037
24257
  //#region src/db/migrations/048_host_reboot_pending.ts
24038
24258
  var _048_host_reboot_pending_exports = /* @__PURE__ */ __exportAll({
24039
- down: () => down$59,
24040
- up: () => up$59
24259
+ down: () => down$60,
24260
+ up: () => up$60
24041
24261
  });
24042
24262
  /**
24043
24263
  * Add `host_roster.reboot_pending_until timestamptz NULL` — the persisted
@@ -24054,19 +24274,19 @@ var _048_host_reboot_pending_exports = /* @__PURE__ */ __exportAll({
24054
24274
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
24055
24275
  * preserved.
24056
24276
  */
24057
- async function up$59(db) {
24277
+ async function up$60(db) {
24058
24278
  await sql`ALTER TABLE public.host_roster
24059
24279
  ADD COLUMN IF NOT EXISTS reboot_pending_until timestamptz`.execute(db);
24060
24280
  }
24061
- async function down$59(db) {
24281
+ async function down$60(db) {
24062
24282
  await sql`ALTER TABLE public.host_roster DROP COLUMN IF EXISTS reboot_pending_until`.execute(db);
24063
24283
  }
24064
24284
  var init__048_host_reboot_pending = __esmMin((() => {}));
24065
24285
  //#endregion
24066
24286
  //#region src/db/migrations/049_held_runs_payload.ts
24067
24287
  var _049_held_runs_payload_exports = /* @__PURE__ */ __exportAll({
24068
- down: () => down$58,
24069
- up: () => up$58
24288
+ down: () => down$59,
24289
+ up: () => up$59
24070
24290
  });
24071
24291
  /**
24072
24292
  * Add `held_runs.payload jsonb NULL` — the drift payload captured when a
@@ -24078,19 +24298,19 @@ var _049_held_runs_payload_exports = /* @__PURE__ */ __exportAll({
24078
24298
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
24079
24299
  * preserved.
24080
24300
  */
24081
- async function up$58(db) {
24301
+ async function up$59(db) {
24082
24302
  await sql`ALTER TABLE public.held_runs
24083
24303
  ADD COLUMN IF NOT EXISTS payload jsonb`.execute(db);
24084
24304
  }
24085
- async function down$58(db) {
24305
+ async function down$59(db) {
24086
24306
  await sql`ALTER TABLE public.held_runs DROP COLUMN IF EXISTS payload`.execute(db);
24087
24307
  }
24088
24308
  var init__049_held_runs_payload = __esmMin((() => {}));
24089
24309
  //#endregion
24090
24310
  //#region src/db/migrations/050_sources_slug.ts
24091
24311
  var _050_sources_slug_exports = /* @__PURE__ */ __exportAll({
24092
- down: () => down$57,
24093
- up: () => up$57
24312
+ down: () => down$58,
24313
+ up: () => up$58
24094
24314
  });
24095
24315
  /**
24096
24316
  * Add `sources.slug TEXT NULL` — the GitHub App slug (the URL-safe identifier
@@ -24105,19 +24325,19 @@ var _050_sources_slug_exports = /* @__PURE__ */ __exportAll({
24105
24325
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
24106
24326
  * preserved.
24107
24327
  */
24108
- async function up$57(db) {
24328
+ async function up$58(db) {
24109
24329
  await sql`ALTER TABLE public.sources
24110
24330
  ADD COLUMN IF NOT EXISTS slug text`.execute(db);
24111
24331
  }
24112
- async function down$57(db) {
24332
+ async function down$58(db) {
24113
24333
  await sql`ALTER TABLE public.sources DROP COLUMN IF EXISTS slug`.execute(db);
24114
24334
  }
24115
24335
  var init__050_sources_slug = __esmMin((() => {}));
24116
24336
  //#endregion
24117
24337
  //#region src/db/migrations/051_binding_host_pattern.ts
24118
24338
  var _051_binding_host_pattern_exports = /* @__PURE__ */ __exportAll({
24119
- down: () => down$56,
24120
- up: () => up$56
24339
+ down: () => down$57,
24340
+ up: () => up$57
24121
24341
  });
24122
24342
  /**
24123
24343
  * Add a per-host dimension to environment secret bindings:
@@ -24133,7 +24353,7 @@ var _051_binding_host_pattern_exports = /* @__PURE__ */ __exportAll({
24133
24353
  * Idempotent: re-running on a DB that already has the column / index is a no-op.
24134
24354
  * Additive — staging data is preserved.
24135
24355
  */
24136
- async function up$56(db) {
24356
+ async function up$57(db) {
24137
24357
  await sql`ALTER TABLE public.environment_bindings
24138
24358
  ADD COLUMN IF NOT EXISTS host_pattern text NOT NULL DEFAULT '**'`.execute(db);
24139
24359
  await sql`ALTER TABLE public.environment_bindings
@@ -24141,7 +24361,7 @@ async function up$56(db) {
24141
24361
  await sql`CREATE UNIQUE INDEX IF NOT EXISTS environment_bindings_env_scope_host_uniq
24142
24362
  ON public.environment_bindings (environment_id, scope_pattern, host_pattern)`.execute(db);
24143
24363
  }
24144
- async function down$56(db) {
24364
+ async function down$57(db) {
24145
24365
  await sql`DROP INDEX IF EXISTS public.environment_bindings_env_scope_host_uniq`.execute(db);
24146
24366
  await sql`ALTER TABLE public.environment_bindings
24147
24367
  DROP COLUMN IF EXISTS host_pattern`.execute(db);
@@ -24152,8 +24372,8 @@ var init__051_binding_host_pattern = __esmMin((() => {}));
24152
24372
  //#endregion
24153
24373
  //#region src/db/migrations/052_host_reach_metadata.ts
24154
24374
  var _052_host_reach_metadata_exports = /* @__PURE__ */ __exportAll({
24155
- down: () => down$55,
24156
- up: () => up$55
24375
+ down: () => down$56,
24376
+ up: () => up$56
24157
24377
  });
24158
24378
  /**
24159
24379
  * Add pre-agent reach metadata to the host roster so a declared host (no agent
@@ -24170,14 +24390,14 @@ var _052_host_reach_metadata_exports = /* @__PURE__ */ __exportAll({
24170
24390
  * behaves exactly as before. Idempotent (`ADD COLUMN IF NOT EXISTS`); additive,
24171
24391
  * so staging data is preserved.
24172
24392
  */
24173
- async function up$55(db) {
24393
+ async function up$56(db) {
24174
24394
  await sql`ALTER TABLE public.host_roster
24175
24395
  ADD COLUMN IF NOT EXISTS address text,
24176
24396
  ADD COLUMN IF NOT EXISTS ssh_user text,
24177
24397
  ADD COLUMN IF NOT EXISTS ssh_port integer,
24178
24398
  ADD COLUMN IF NOT EXISTS ssh_key_secret text`.execute(db);
24179
24399
  }
24180
- async function down$55(db) {
24400
+ async function down$56(db) {
24181
24401
  await sql`ALTER TABLE public.host_roster
24182
24402
  DROP COLUMN IF EXISTS address,
24183
24403
  DROP COLUMN IF EXISTS ssh_user,
@@ -24188,8 +24408,8 @@ var init__052_host_reach_metadata = __esmMin((() => {}));
24188
24408
  //#endregion
24189
24409
  //#region src/db/migrations/053_agent_token_single_use.ts
24190
24410
  var _053_agent_token_single_use_exports = /* @__PURE__ */ __exportAll({
24191
- down: () => down$54,
24192
- up: () => up$54
24411
+ down: () => down$55,
24412
+ up: () => up$55
24193
24413
  });
24194
24414
  /**
24195
24415
  * Add a single-use marker to agent tokens for the bootstrap (init-runner)
@@ -24204,11 +24424,11 @@ var _053_agent_token_single_use_exports = /* @__PURE__ */ __exportAll({
24204
24424
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
24205
24425
  * preserved.
24206
24426
  */
24207
- async function up$54(db) {
24427
+ async function up$55(db) {
24208
24428
  await sql`ALTER TABLE public.agent_tokens
24209
24429
  ADD COLUMN IF NOT EXISTS consumed_at timestamptz`.execute(db);
24210
24430
  }
24211
- async function down$54(db) {
24431
+ async function down$55(db) {
24212
24432
  await sql`ALTER TABLE public.agent_tokens
24213
24433
  DROP COLUMN IF EXISTS consumed_at`.execute(db);
24214
24434
  }
@@ -24216,8 +24436,8 @@ var init__053_agent_token_single_use = __esmMin((() => {}));
24216
24436
  //#endregion
24217
24437
  //#region src/db/migrations/054_local_working_tree.ts
24218
24438
  var _054_local_working_tree_exports = /* @__PURE__ */ __exportAll({
24219
- down: () => down$53,
24220
- up: () => up$53
24439
+ down: () => down$54,
24440
+ up: () => up$54
24221
24441
  });
24222
24442
  /**
24223
24443
  * Mark runs that executed an uploaded local working tree (`kici run remote`):
@@ -24230,11 +24450,11 @@ var _054_local_working_tree_exports = /* @__PURE__ */ __exportAll({
24230
24450
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive with a default, so staging
24231
24451
  * data is preserved.
24232
24452
  */
24233
- async function up$53(db) {
24453
+ async function up$54(db) {
24234
24454
  await sql`ALTER TABLE public.execution_runs
24235
24455
  ADD COLUMN IF NOT EXISTS local_working_tree boolean NOT NULL DEFAULT false`.execute(db);
24236
24456
  }
24237
- async function down$53(db) {
24457
+ async function down$54(db) {
24238
24458
  await sql`ALTER TABLE public.execution_runs
24239
24459
  DROP COLUMN IF EXISTS local_working_tree`.execute(db);
24240
24460
  }
@@ -24242,8 +24462,8 @@ var init__054_local_working_tree = __esmMin((() => {}));
24242
24462
  //#endregion
24243
24463
  //#region src/db/migrations/055_agent_token_mandatory_labels.ts
24244
24464
  var _055_agent_token_mandatory_labels_exports = /* @__PURE__ */ __exportAll({
24245
- down: () => down$52,
24246
- up: () => up$52
24465
+ down: () => down$53,
24466
+ up: () => up$53
24247
24467
  });
24248
24468
  /**
24249
24469
  * Add a token-bound mandatory-label taint to agent tokens:
@@ -24259,11 +24479,11 @@ var _055_agent_token_mandatory_labels_exports = /* @__PURE__ */ __exportAll({
24259
24479
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
24260
24480
  * preserved.
24261
24481
  */
24262
- async function up$52(db) {
24482
+ async function up$53(db) {
24263
24483
  await sql`ALTER TABLE public.agent_tokens
24264
24484
  ADD COLUMN IF NOT EXISTS mandatory_labels text`.execute(db);
24265
24485
  }
24266
- async function down$52(db) {
24486
+ async function down$53(db) {
24267
24487
  await sql`ALTER TABLE public.agent_tokens
24268
24488
  DROP COLUMN IF EXISTS mandatory_labels`.execute(db);
24269
24489
  }
@@ -24271,8 +24491,8 @@ var init__055_agent_token_mandatory_labels = __esmMin((() => {}));
24271
24491
  //#endregion
24272
24492
  //#region src/db/migrations/056_execution_jobs_environments.ts
24273
24493
  var _056_execution_jobs_environments_exports = /* @__PURE__ */ __exportAll({
24274
- down: () => down$51,
24275
- up: () => up$51
24494
+ down: () => down$52,
24495
+ up: () => up$52
24276
24496
  });
24277
24497
  /**
24278
24498
  * Add a per-job bound deployment-environment list to `execution_jobs`:
@@ -24287,11 +24507,11 @@ var _056_execution_jobs_environments_exports = /* @__PURE__ */ __exportAll({
24287
24507
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
24288
24508
  * preserved.
24289
24509
  */
24290
- async function up$51(db) {
24510
+ async function up$52(db) {
24291
24511
  await sql`ALTER TABLE public.execution_jobs
24292
24512
  ADD COLUMN IF NOT EXISTS environments text`.execute(db);
24293
24513
  }
24294
- async function down$51(db) {
24514
+ async function down$52(db) {
24295
24515
  await sql`ALTER TABLE public.execution_jobs
24296
24516
  DROP COLUMN IF EXISTS environments`.execute(db);
24297
24517
  }
@@ -24299,8 +24519,8 @@ var init__056_execution_jobs_environments = __esmMin((() => {}));
24299
24519
  //#endregion
24300
24520
  //#region src/db/migrations/057_step_concurrency.ts
24301
24521
  var _057_step_concurrency_exports = /* @__PURE__ */ __exportAll({
24302
- down: () => down$50,
24303
- up: () => up$50
24522
+ down: () => down$51,
24523
+ up: () => up$51
24304
24524
  });
24305
24525
  /**
24306
24526
  * Add parallel step-group concurrency columns to `execution_steps`:
@@ -24323,11 +24543,11 @@ async function colExists$6(db, table, name) {
24323
24543
  ) AS exists
24324
24544
  `.execute(db)).rows[0]?.exists ?? false;
24325
24545
  }
24326
- async function up$50(db) {
24546
+ async function up$51(db) {
24327
24547
  if (!await colExists$6(db, "execution_steps", "concurrency_kind")) await sql`ALTER TABLE public.execution_steps ADD COLUMN concurrency_kind text`.execute(db);
24328
24548
  if (!await colExists$6(db, "execution_steps", "group_id")) await sql`ALTER TABLE public.execution_steps ADD COLUMN group_id text`.execute(db);
24329
24549
  }
24330
- async function down$50(db) {
24550
+ async function down$51(db) {
24331
24551
  await sql`ALTER TABLE public.execution_steps DROP COLUMN IF EXISTS group_id`.execute(db);
24332
24552
  await sql`ALTER TABLE public.execution_steps DROP COLUMN IF EXISTS concurrency_kind`.execute(db);
24333
24553
  }
@@ -24335,8 +24555,8 @@ var init__057_step_concurrency = __esmMin((() => {}));
24335
24555
  //#endregion
24336
24556
  //#region src/db/migrations/058_access_log_agent_label.ts
24337
24557
  var _058_access_log_agent_label_exports = /* @__PURE__ */ __exportAll({
24338
- down: () => down$49,
24339
- up: () => up$49
24558
+ down: () => down$50,
24559
+ up: () => up$50
24340
24560
  });
24341
24561
  /**
24342
24562
  * Add `access_log.agent_label text` — the human-set name of the agent that
@@ -24356,18 +24576,18 @@ async function colExists$5(db, table, name) {
24356
24576
  ) AS exists
24357
24577
  `.execute(db)).rows[0]?.exists ?? false;
24358
24578
  }
24359
- async function up$49(db) {
24579
+ async function up$50(db) {
24360
24580
  if (!await colExists$5(db, "access_log", "agent_label")) await sql`ALTER TABLE public.access_log ADD COLUMN agent_label text`.execute(db);
24361
24581
  }
24362
- async function down$49(db) {
24582
+ async function down$50(db) {
24363
24583
  await sql`ALTER TABLE public.access_log DROP COLUMN IF EXISTS agent_label`.execute(db);
24364
24584
  }
24365
24585
  var init__058_access_log_agent_label = __esmMin((() => {}));
24366
24586
  //#endregion
24367
24587
  //#region src/db/migrations/059_attestation_verdict.ts
24368
24588
  var _059_attestation_verdict_exports = /* @__PURE__ */ __exportAll({
24369
- down: () => down$48,
24370
- up: () => up$48
24589
+ down: () => down$49,
24590
+ up: () => up$49
24371
24591
  });
24372
24592
  /**
24373
24593
  * Add server-side verification verdict columns to `attestations`, plus the
@@ -24394,7 +24614,7 @@ async function colExists$4(db, table, name) {
24394
24614
  ) AS exists
24395
24615
  `.execute(db)).rows[0]?.exists ?? false;
24396
24616
  }
24397
- async function up$48(db) {
24617
+ async function up$49(db) {
24398
24618
  if (await colExists$4(db, "attestations", "verify_status")) return;
24399
24619
  await sql`
24400
24620
  ALTER TABLE public.attestations
@@ -24407,7 +24627,7 @@ async function up$48(db) {
24407
24627
  await sql`CREATE INDEX idx_attestations_verify_status ON public.attestations (verify_status)`.execute(db);
24408
24628
  await sql`CREATE INDEX idx_attestations_created_at ON public.attestations (created_at)`.execute(db);
24409
24629
  }
24410
- async function down$48(db) {
24630
+ async function down$49(db) {
24411
24631
  await sql`DROP INDEX IF EXISTS idx_attestations_created_at`.execute(db);
24412
24632
  await sql`DROP INDEX IF EXISTS idx_attestations_verify_status`.execute(db);
24413
24633
  await sql`DROP INDEX IF EXISTS idx_attestations_subject_name`.execute(db);
@@ -24423,8 +24643,8 @@ var init__059_attestation_verdict = __esmMin((() => {}));
24423
24643
  //#endregion
24424
24644
  //#region src/db/migrations/060_run_trigger_actor.ts
24425
24645
  var _060_run_trigger_actor_exports = /* @__PURE__ */ __exportAll({
24426
- down: () => down$47,
24427
- up: () => up$47
24646
+ down: () => down$48,
24647
+ up: () => up$48
24428
24648
  });
24429
24649
  /**
24430
24650
  * Add the triggering-actor columns to `execution_runs`:
@@ -24452,12 +24672,12 @@ async function colExists$3(db, table, name) {
24452
24672
  ) AS exists
24453
24673
  `.execute(db)).rows[0]?.exists ?? false;
24454
24674
  }
24455
- async function up$47(db) {
24675
+ async function up$48(db) {
24456
24676
  if (!await colExists$3(db, "execution_runs", "trigger_actor_provider")) await sql`ALTER TABLE public.execution_runs ADD COLUMN trigger_actor_provider text`.execute(db);
24457
24677
  if (!await colExists$3(db, "execution_runs", "trigger_actor_username")) await sql`ALTER TABLE public.execution_runs ADD COLUMN trigger_actor_username text`.execute(db);
24458
24678
  if (!await colExists$3(db, "execution_runs", "trigger_actor_user_id")) await sql`ALTER TABLE public.execution_runs ADD COLUMN trigger_actor_user_id text`.execute(db);
24459
24679
  }
24460
- async function down$47(db) {
24680
+ async function down$48(db) {
24461
24681
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS trigger_actor_provider`.execute(db);
24462
24682
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS trigger_actor_username`.execute(db);
24463
24683
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS trigger_actor_user_id`.execute(db);
@@ -24466,8 +24686,8 @@ var init__060_run_trigger_actor = __esmMin((() => {}));
24466
24686
  //#endregion
24467
24687
  //#region src/db/migrations/061_execution_runs_environment_id.ts
24468
24688
  var _061_execution_runs_environment_id_exports = /* @__PURE__ */ __exportAll({
24469
- down: () => down$46,
24470
- up: () => up$46
24689
+ down: () => down$47,
24690
+ up: () => up$47
24471
24691
  });
24472
24692
  /**
24473
24693
  * Add `environment_id` to `execution_runs` so environment run-history can be
@@ -24503,7 +24723,7 @@ async function colExists$2(db, table, name) {
24503
24723
  ) AS exists
24504
24724
  `.execute(db)).rows[0]?.exists ?? false;
24505
24725
  }
24506
- async function up$46(db) {
24726
+ async function up$47(db) {
24507
24727
  if (!await colExists$2(db, "execution_runs", "environment_id")) await sql`
24508
24728
  ALTER TABLE public.execution_runs
24509
24729
  ADD COLUMN environment_id uuid
@@ -24525,7 +24745,7 @@ async function up$46(db) {
24525
24745
  WHERE e2.type = 'fixed' AND e2.name = er.environment) = 1
24526
24746
  `.execute(db);
24527
24747
  }
24528
- async function down$46(db) {
24748
+ async function down$47(db) {
24529
24749
  await sql`DROP INDEX IF EXISTS idx_execution_runs_environment_id`.execute(db);
24530
24750
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS environment_id`.execute(db);
24531
24751
  }
@@ -24533,8 +24753,8 @@ var init__061_execution_runs_environment_id = __esmMin((() => {}));
24533
24753
  //#endregion
24534
24754
  //#region src/db/migrations/062_execution_runs_agent_label.ts
24535
24755
  var _062_execution_runs_agent_label_exports = /* @__PURE__ */ __exportAll({
24536
- down: () => down$45,
24537
- up: () => up$45
24756
+ down: () => down$46,
24757
+ up: () => up$46
24538
24758
  });
24539
24759
  /**
24540
24760
  * Add the agent-provenance columns to `execution_runs`:
@@ -24559,11 +24779,11 @@ async function colExists$1(db, table, name) {
24559
24779
  ) AS exists
24560
24780
  `.execute(db)).rows[0]?.exists ?? false;
24561
24781
  }
24562
- async function up$45(db) {
24782
+ async function up$46(db) {
24563
24783
  if (!await colExists$1(db, "execution_runs", "triggered_by_agent_label")) await sql`ALTER TABLE public.execution_runs ADD COLUMN triggered_by_agent_label text`.execute(db);
24564
24784
  if (!await colExists$1(db, "execution_runs", "cancelled_by_agent_label")) await sql`ALTER TABLE public.execution_runs ADD COLUMN cancelled_by_agent_label text`.execute(db);
24565
24785
  }
24566
- async function down$45(db) {
24786
+ async function down$46(db) {
24567
24787
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS triggered_by_agent_label`.execute(db);
24568
24788
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS cancelled_by_agent_label`.execute(db);
24569
24789
  }
@@ -24571,8 +24791,8 @@ var init__062_execution_runs_agent_label = __esmMin((() => {}));
24571
24791
  //#endregion
24572
24792
  //#region src/db/migrations/063_access_log_agent_label_index.ts
24573
24793
  var _063_access_log_agent_label_index_exports = /* @__PURE__ */ __exportAll({
24574
- down: () => down$44,
24575
- up: () => up$44
24794
+ down: () => down$45,
24795
+ up: () => up$45
24576
24796
  });
24577
24797
  /**
24578
24798
  * Index `access_log.agent_label` (column added by migration 058) so the
@@ -24580,18 +24800,18 @@ var _063_access_log_agent_label_index_exports = /* @__PURE__ */ __exportAll({
24580
24800
  * the dashboard "agent name" filter) does an indexed exact-match lookup
24581
24801
  * instead of a scan. Idempotent.
24582
24802
  */
24583
- async function up$44(db) {
24803
+ async function up$45(db) {
24584
24804
  await sql`CREATE INDEX IF NOT EXISTS access_log_agent_label_idx ON public.access_log (agent_label)`.execute(db);
24585
24805
  }
24586
- async function down$44(db) {
24806
+ async function down$45(db) {
24587
24807
  await sql`DROP INDEX IF EXISTS access_log_agent_label_idx`.execute(db);
24588
24808
  }
24589
24809
  var init__063_access_log_agent_label_index = __esmMin((() => {}));
24590
24810
  //#endregion
24591
24811
  //#region src/db/migrations/064_execution_jobs_skipped_environments.ts
24592
24812
  var _064_execution_jobs_skipped_environments_exports = /* @__PURE__ */ __exportAll({
24593
- down: () => down$43,
24594
- up: () => up$43
24813
+ down: () => down$44,
24814
+ up: () => up$44
24595
24815
  });
24596
24816
  /**
24597
24817
  * Add the test-run skipped-environment columns to `execution_jobs`:
@@ -24606,13 +24826,13 @@ var _064_execution_jobs_skipped_environments_exports = /* @__PURE__ */ __exportA
24606
24826
  * Idempotent (`ADD COLUMN IF NOT EXISTS`); additive, so staging data is
24607
24827
  * preserved.
24608
24828
  */
24609
- async function up$43(db) {
24829
+ async function up$44(db) {
24610
24830
  await sql`ALTER TABLE public.execution_jobs
24611
24831
  ADD COLUMN IF NOT EXISTS skipped_environments text`.execute(db);
24612
24832
  await sql`ALTER TABLE public.execution_jobs
24613
24833
  ADD COLUMN IF NOT EXISTS env_warning text`.execute(db);
24614
24834
  }
24615
- async function down$43(db) {
24835
+ async function down$44(db) {
24616
24836
  await sql`ALTER TABLE public.execution_jobs
24617
24837
  DROP COLUMN IF EXISTS skipped_environments`.execute(db);
24618
24838
  await sql`ALTER TABLE public.execution_jobs
@@ -24622,8 +24842,8 @@ var init__064_execution_jobs_skipped_environments = __esmMin((() => {}));
24622
24842
  //#endregion
24623
24843
  //#region src/db/migrations/065_pending_attestations.ts
24624
24844
  var _065_pending_attestations_exports = /* @__PURE__ */ __exportAll({
24625
- down: () => down$42,
24626
- up: () => up$42
24845
+ down: () => down$43,
24846
+ up: () => up$43
24627
24847
  });
24628
24848
  /**
24629
24849
  * Add the `pending_attestations` deferred-attestation outbox and an idempotency
@@ -24643,7 +24863,7 @@ var _065_pending_attestations_exports = /* @__PURE__ */ __exportAll({
24643
24863
  *
24644
24864
  * Idempotent: guarded on table existence.
24645
24865
  */
24646
- async function up$42(db) {
24866
+ async function up$43(db) {
24647
24867
  if ((await sql`
24648
24868
  SELECT EXISTS (
24649
24869
  SELECT 1 FROM information_schema.tables
@@ -24682,7 +24902,7 @@ async function up$42(db) {
24682
24902
  ON public.attestations (run_id, job_id, subject_digest)
24683
24903
  `.execute(db);
24684
24904
  }
24685
- async function down$42(db) {
24905
+ async function down$43(db) {
24686
24906
  await sql`DROP INDEX IF EXISTS uq_attestations_run_job_subject`.execute(db);
24687
24907
  await sql`DROP TABLE IF EXISTS public.pending_attestations`.execute(db);
24688
24908
  }
@@ -24690,8 +24910,8 @@ var init__065_pending_attestations = __esmMin((() => {}));
24690
24910
  //#endregion
24691
24911
  //#region src/db/migrations/066_pending_attestations_rejected.ts
24692
24912
  var _066_pending_attestations_rejected_exports = /* @__PURE__ */ __exportAll({
24693
- down: () => down$41,
24694
- up: () => up$41
24913
+ down: () => down$42,
24914
+ up: () => up$42
24695
24915
  });
24696
24916
  /**
24697
24917
  * Add `rejected_at` to `pending_attestations`: the terminal-rejection marker for
@@ -24702,21 +24922,21 @@ var _066_pending_attestations_rejected_exports = /* @__PURE__ */ __exportAll({
24702
24922
  *
24703
24923
  * Idempotent: guarded on column existence.
24704
24924
  */
24705
- async function up$41(db) {
24706
- if (await columnExists$4(db, "pending_attestations", "rejected_at")) return;
24925
+ async function up$42(db) {
24926
+ if (await columnExists$5(db, "pending_attestations", "rejected_at")) return;
24707
24927
  await sql`
24708
24928
  ALTER TABLE public.pending_attestations
24709
24929
  ADD COLUMN rejected_at TIMESTAMPTZ
24710
24930
  `.execute(db);
24711
24931
  }
24712
- async function down$41(db) {
24713
- if (!await columnExists$4(db, "pending_attestations", "rejected_at")) return;
24932
+ async function down$42(db) {
24933
+ if (!await columnExists$5(db, "pending_attestations", "rejected_at")) return;
24714
24934
  await sql`
24715
24935
  ALTER TABLE public.pending_attestations
24716
24936
  DROP COLUMN rejected_at
24717
24937
  `.execute(db);
24718
24938
  }
24719
- async function columnExists$4(db, table, column) {
24939
+ async function columnExists$5(db, table, column) {
24720
24940
  return (await sql`
24721
24941
  SELECT EXISTS (
24722
24942
  SELECT 1 FROM information_schema.columns
@@ -24728,8 +24948,8 @@ var init__066_pending_attestations_rejected = __esmMin((() => {}));
24728
24948
  //#endregion
24729
24949
  //#region src/db/migrations/067_environments_to_contexts.ts
24730
24950
  var _067_environments_to_contexts_exports = /* @__PURE__ */ __exportAll({
24731
- down: () => down$40,
24732
- up: () => up$40
24951
+ down: () => down$41,
24952
+ up: () => up$41
24733
24953
  });
24734
24954
  /**
24735
24955
  * Rename the named-policy object from "environment" to "context" across the
@@ -24763,7 +24983,7 @@ var _067_environments_to_contexts_exports = /* @__PURE__ */ __exportAll({
24763
24983
  * columns automatically (Postgres references them by identity, not name), so
24764
24984
  * only the one hand-named index above needs an explicit rename.
24765
24985
  */
24766
- async function up$40(db) {
24986
+ async function up$41(db) {
24767
24987
  await sql`ALTER TABLE public.environments RENAME TO contexts`.execute(db);
24768
24988
  await sql`ALTER TABLE public.environment_bindings RENAME TO context_bindings`.execute(db);
24769
24989
  await sql`ALTER TABLE public.environment_variables RENAME TO context_variables`.execute(db);
@@ -24782,7 +25002,7 @@ async function up$40(db) {
24782
25002
  await sql`ALTER TABLE public.held_runs ALTER COLUMN queue_type SET DEFAULT 'context'`.execute(db);
24783
25003
  await sql`ALTER TABLE public.held_runs ALTER COLUMN trigger_source SET DEFAULT 'context'`.execute(db);
24784
25004
  }
24785
- async function down$40(db) {
25005
+ async function down$41(db) {
24786
25006
  await sql`ALTER TABLE public.held_runs ALTER COLUMN trigger_source SET DEFAULT 'environment'`.execute(db);
24787
25007
  await sql`ALTER TABLE public.held_runs ALTER COLUMN queue_type SET DEFAULT 'environment'`.execute(db);
24788
25008
  await sql`UPDATE public.held_runs SET trigger_source = 'environment' WHERE trigger_source = 'context'`.execute(db);
@@ -24805,8 +25025,8 @@ var init__067_environments_to_contexts = __esmMin((() => {}));
24805
25025
  //#endregion
24806
25026
  //#region src/db/migrations/068_request_idempotency.ts
24807
25027
  var _068_request_idempotency_exports = /* @__PURE__ */ __exportAll({
24808
- down: () => down$39,
24809
- up: () => up$39
25028
+ down: () => down$40,
25029
+ up: () => up$40
24810
25030
  });
24811
25031
  /**
24812
25032
  * Add the `request_idempotency` claim table: a `request_id`-keyed record that
@@ -24821,12 +25041,12 @@ var _068_request_idempotency_exports = /* @__PURE__ */ __exportAll({
24821
25041
  *
24822
25042
  * Idempotent: guarded on table existence.
24823
25043
  */
24824
- async function up$39(db) {
25044
+ async function up$40(db) {
24825
25045
  if (await tableExists$3(db, "request_idempotency")) return;
24826
25046
  await db.schema.createTable("request_idempotency").addColumn("request_id", "text", (c) => c.primaryKey()).addColumn("new_run_id", "text", (c) => c.notNull()).addColumn("created_at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)).execute();
24827
25047
  await db.schema.createIndex("idx_request_idempotency_created_at").on("request_idempotency").column("created_at").execute();
24828
25048
  }
24829
- async function down$39(db) {
25049
+ async function down$40(db) {
24830
25050
  await db.schema.dropTable("request_idempotency").ifExists().execute();
24831
25051
  }
24832
25052
  async function tableExists$3(db, table) {
@@ -24841,8 +25061,8 @@ var init__068_request_idempotency = __esmMin((() => {}));
24841
25061
  //#endregion
24842
25062
  //#region src/db/migrations/069_reroute_tunables.ts
24843
25063
  var _069_reroute_tunables_exports = /* @__PURE__ */ __exportAll({
24844
- down: () => down$38,
24845
- up: () => up$38
25064
+ down: () => down$39,
25065
+ up: () => up$39
24846
25066
  });
24847
25067
  /**
24848
25068
  * Add the three reroute-tunable columns to `org_settings` (all nullable):
@@ -24861,12 +25081,12 @@ var _069_reroute_tunables_exports = /* @__PURE__ */ __exportAll({
24861
25081
  * Idempotent: each column add is guarded on column existence, so a re-run on a
24862
25082
  * DB that already has a column is a no-op for that column.
24863
25083
  */
24864
- async function up$38(db) {
25084
+ async function up$39(db) {
24865
25085
  await addColumnIfMissing(db, "reroute_spawn_window_ms", "BIGINT");
24866
25086
  await addColumnIfMissing(db, "reroute_ack_timeout_ms", "BIGINT");
24867
25087
  await addColumnIfMissing(db, "reroute_max_hops", "INTEGER");
24868
25088
  }
24869
- async function down$38(db) {
25089
+ async function down$39(db) {
24870
25090
  await sql`ALTER TABLE public.org_settings DROP COLUMN IF EXISTS reroute_spawn_window_ms`.execute(db);
24871
25091
  await sql`ALTER TABLE public.org_settings DROP COLUMN IF EXISTS reroute_ack_timeout_ms`.execute(db);
24872
25092
  await sql`ALTER TABLE public.org_settings DROP COLUMN IF EXISTS reroute_max_hops`.execute(db);
@@ -24886,8 +25106,8 @@ var init__069_reroute_tunables = __esmMin((() => {}));
24886
25106
  //#endregion
24887
25107
  //#region src/db/migrations/070_execution_runs_failure_class.ts
24888
25108
  var _070_execution_runs_failure_class_exports = /* @__PURE__ */ __exportAll({
24889
- down: () => down$37,
24890
- up: () => up$37
25109
+ down: () => down$38,
25110
+ up: () => up$38
24891
25111
  });
24892
25112
  /**
24893
25113
  * Add `execution_runs.failure_class` — the reason a terminal run failed
@@ -24908,18 +25128,18 @@ async function colExists(db, table, name) {
24908
25128
  ) AS exists
24909
25129
  `.execute(db)).rows[0]?.exists ?? false;
24910
25130
  }
24911
- async function up$37(db) {
25131
+ async function up$38(db) {
24912
25132
  if (!await colExists(db, "execution_runs", "failure_class")) await sql`ALTER TABLE public.execution_runs ADD COLUMN failure_class text`.execute(db);
24913
25133
  }
24914
- async function down$37(db) {
25134
+ async function down$38(db) {
24915
25135
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS failure_class`.execute(db);
24916
25136
  }
24917
25137
  var init__070_execution_runs_failure_class = __esmMin((() => {}));
24918
25138
  //#endregion
24919
25139
  //#region src/db/migrations/071_batch_accumulation.ts
24920
25140
  var _071_batch_accumulation_exports = /* @__PURE__ */ __exportAll({
24921
- down: () => down$36,
24922
- up: () => up$36
25141
+ down: () => down$37,
25142
+ up: () => up$37
24923
25143
  });
24924
25144
  /**
24925
25145
  * Add the batch-accumulation tables that back the `workflows_failed_batch`
@@ -24943,7 +25163,7 @@ var _071_batch_accumulation_exports = /* @__PURE__ */ __exportAll({
24943
25163
  *
24944
25164
  * Idempotent: guarded on table existence.
24945
25165
  */
24946
- async function up$36(db) {
25166
+ async function up$37(db) {
24947
25167
  if ((await sql`
24948
25168
  SELECT EXISTS (
24949
25169
  SELECT 1 FROM information_schema.tables
@@ -24988,7 +25208,7 @@ async function up$36(db) {
24988
25208
  ON public.batch_accumulation_items (window_id)
24989
25209
  `.execute(db);
24990
25210
  }
24991
- async function down$36(db) {
25211
+ async function down$37(db) {
24992
25212
  await sql`DROP TABLE IF EXISTS public.batch_accumulation_items`.execute(db);
24993
25213
  await sql`DROP TABLE IF EXISTS public.batch_accumulation_windows`.execute(db);
24994
25214
  }
@@ -24996,8 +25216,8 @@ var init__071_batch_accumulation = __esmMin((() => {}));
24996
25216
  //#endregion
24997
25217
  //#region src/db/migrations/072_dispatch_queue_run_id_index.ts
24998
25218
  var _072_dispatch_queue_run_id_index_exports = /* @__PURE__ */ __exportAll({
24999
- down: () => down$35,
25000
- up: () => up$35
25219
+ down: () => down$36,
25220
+ up: () => up$36
25001
25221
  });
25002
25222
  /**
25003
25223
  * Add `idx_dispatch_queue_run_id` on `dispatch_queue (run_id)`.
@@ -25010,21 +25230,21 @@ var _072_dispatch_queue_run_id_index_exports = /* @__PURE__ */ __exportAll({
25010
25230
  *
25011
25231
  * Idempotent: `IF NOT EXISTS` makes a re-run a no-op.
25012
25232
  */
25013
- async function up$35(db) {
25233
+ async function up$36(db) {
25014
25234
  await sql`
25015
25235
  CREATE INDEX IF NOT EXISTS idx_dispatch_queue_run_id
25016
25236
  ON public.dispatch_queue (run_id)
25017
25237
  `.execute(db);
25018
25238
  }
25019
- async function down$35(db) {
25239
+ async function down$36(db) {
25020
25240
  await sql`DROP INDEX IF EXISTS public.idx_dispatch_queue_run_id`.execute(db);
25021
25241
  }
25022
25242
  var init__072_dispatch_queue_run_id_index = __esmMin((() => {}));
25023
25243
  //#endregion
25024
25244
  //#region src/db/migrations/073_org_settings_ingest_concurrency.ts
25025
25245
  var _073_org_settings_ingest_concurrency_exports = /* @__PURE__ */ __exportAll({
25026
- down: () => down$34,
25027
- up: () => up$34
25246
+ down: () => down$35,
25247
+ up: () => up$35
25028
25248
  });
25029
25249
  /**
25030
25250
  * Add `org_settings.ingest_max_concurrency BIGINT` (nullable).
@@ -25035,7 +25255,7 @@ var _073_org_settings_ingest_concurrency_exports = /* @__PURE__ */ __exportAll({
25035
25255
  *
25036
25256
  * Idempotent: a re-run on a DB that already has the column is a no-op.
25037
25257
  */
25038
- async function up$34(db) {
25258
+ async function up$35(db) {
25039
25259
  if ((await sql`
25040
25260
  SELECT EXISTS (
25041
25261
  SELECT 1 FROM information_schema.columns
@@ -25049,7 +25269,7 @@ async function up$34(db) {
25049
25269
  ADD COLUMN ingest_max_concurrency BIGINT
25050
25270
  `.execute(db);
25051
25271
  }
25052
- async function down$34(db) {
25272
+ async function down$35(db) {
25053
25273
  await sql`
25054
25274
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS ingest_max_concurrency
25055
25275
  `.execute(db);
@@ -25058,8 +25278,8 @@ var init__073_org_settings_ingest_concurrency = __esmMin((() => {}));
25058
25278
  //#endregion
25059
25279
  //#region src/db/migrations/074_normalize_zero_concurrency_limit.ts
25060
25280
  var _074_normalize_zero_concurrency_limit_exports = /* @__PURE__ */ __exportAll({
25061
- down: () => down$33,
25062
- up: () => up$33
25281
+ down: () => down$34,
25282
+ up: () => up$34
25063
25283
  });
25064
25284
  /**
25065
25285
  * Normalize degenerate context concurrency limits. A `concurrency_limit` of 0
@@ -25070,16 +25290,16 @@ var _074_normalize_zero_concurrency_limit_exports = /* @__PURE__ */ __exportAll(
25070
25290
  * Idempotent; down() is a no-op (a normalized 0 cannot — and should not — be
25071
25291
  * restored).
25072
25292
  */
25073
- async function up$33(db) {
25293
+ async function up$34(db) {
25074
25294
  await sql`UPDATE public.contexts SET concurrency_limit = NULL WHERE concurrency_limit <= 0`.execute(db);
25075
25295
  }
25076
- async function down$33(_db) {}
25296
+ async function down$34(_db) {}
25077
25297
  var init__074_normalize_zero_concurrency_limit = __esmMin((() => {}));
25078
25298
  //#endregion
25079
25299
  //#region src/db/migrations/075_ingest_overflow_buffer.ts
25080
25300
  var _075_ingest_overflow_buffer_exports = /* @__PURE__ */ __exportAll({
25081
- down: () => down$32,
25082
- up: () => up$32
25301
+ down: () => down$33,
25302
+ up: () => up$33
25083
25303
  });
25084
25304
  /**
25085
25305
  * Durable overflow buffer for shed webhook-ingest deliveries.
@@ -25093,7 +25313,7 @@ var _075_ingest_overflow_buffer_exports = /* @__PURE__ */ __exportAll({
25093
25313
  *
25094
25314
  * Idempotent: a re-run on a DB that already has the table is a no-op.
25095
25315
  */
25096
- async function up$32(db) {
25316
+ async function up$33(db) {
25097
25317
  if ((await sql`
25098
25318
  SELECT EXISTS (
25099
25319
  SELECT 1 FROM information_schema.tables
@@ -25126,15 +25346,15 @@ async function up$32(db) {
25126
25346
  ON public.ingest_overflow_buffer (delivery_id)
25127
25347
  `.execute(db);
25128
25348
  }
25129
- async function down$32(db) {
25349
+ async function down$33(db) {
25130
25350
  await sql`DROP TABLE IF EXISTS public.ingest_overflow_buffer`.execute(db);
25131
25351
  }
25132
25352
  var init__075_ingest_overflow_buffer = __esmMin((() => {}));
25133
25353
  //#endregion
25134
25354
  //#region src/db/migrations/076_artifacts.ts
25135
25355
  var _076_artifacts_exports = /* @__PURE__ */ __exportAll({
25136
- down: () => down$31,
25137
- up: () => up$31
25356
+ down: () => down$32,
25357
+ up: () => up$32
25138
25358
  });
25139
25359
  /**
25140
25360
  * Add the `artifacts` table for user-facing build artifacts and the per-org
@@ -25151,7 +25371,7 @@ var _076_artifacts_exports = /* @__PURE__ */ __exportAll({
25151
25371
  *
25152
25372
  * Idempotent: a re-run on a DB that already has the table / columns is a no-op.
25153
25373
  */
25154
- async function up$31(db) {
25374
+ async function up$32(db) {
25155
25375
  if (!(await sql`
25156
25376
  SELECT EXISTS (
25157
25377
  SELECT 1 FROM information_schema.tables
@@ -25187,7 +25407,7 @@ async function up$31(db) {
25187
25407
  ADD COLUMN IF NOT EXISTS artifact_ttl_ms BIGINT
25188
25408
  `.execute(db);
25189
25409
  }
25190
- async function down$31(db) {
25410
+ async function down$32(db) {
25191
25411
  await sql`DROP TABLE IF EXISTS public.artifacts`.execute(db);
25192
25412
  await sql`
25193
25413
  ALTER TABLE public.org_settings
@@ -25199,8 +25419,8 @@ var init__076_artifacts = __esmMin((() => {}));
25199
25419
  //#endregion
25200
25420
  //#region src/db/migrations/077_backup_runs.ts
25201
25421
  var _077_backup_runs_exports = /* @__PURE__ */ __exportAll({
25202
- down: () => down$30,
25203
- up: () => up$30
25422
+ down: () => down$31,
25423
+ up: () => up$31
25204
25424
  });
25205
25425
  /**
25206
25426
  * Add the `backup_runs` table: one row per successful `kici-admin db backup`,
@@ -25211,12 +25431,12 @@ var _077_backup_runs_exports = /* @__PURE__ */ __exportAll({
25211
25431
  *
25212
25432
  * Idempotent: guarded on table existence.
25213
25433
  */
25214
- async function up$30(db) {
25434
+ async function up$31(db) {
25215
25435
  if (await tableExists$2(db, "backup_runs")) return;
25216
25436
  await db.schema.createTable("backup_runs").addColumn("id", "bigserial", (c) => c.primaryKey()).addColumn("created_at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)).addColumn("dump_path", "text", (c) => c.notNull()).addColumn("byte_size", "bigint", (c) => c.notNull()).addColumn("secret_key_version", "integer").addColumn("pg_server_version", "text", (c) => c.notNull()).addColumn("migrations_hash", "text", (c) => c.notNull()).addColumn("hostname", "text", (c) => c.notNull()).execute();
25217
25437
  await db.schema.createIndex("idx_backup_runs_created_at").on("backup_runs").column("created_at").execute();
25218
25438
  }
25219
- async function down$30(db) {
25439
+ async function down$31(db) {
25220
25440
  await db.schema.dropTable("backup_runs").ifExists().execute();
25221
25441
  }
25222
25442
  async function tableExists$2(db, table) {
@@ -25231,8 +25451,8 @@ var init__077_backup_runs = __esmMin((() => {}));
25231
25451
  //#endregion
25232
25452
  //#region src/db/migrations/078_org_settings_backup_staleness.ts
25233
25453
  var _078_org_settings_backup_staleness_exports = /* @__PURE__ */ __exportAll({
25234
- down: () => down$29,
25235
- up: () => up$29
25454
+ down: () => down$30,
25455
+ up: () => up$30
25236
25456
  });
25237
25457
  /**
25238
25458
  * Add the nullable `org_settings.backup_staleness_warn_hours INTEGER` column:
@@ -25242,7 +25462,7 @@ var _078_org_settings_backup_staleness_exports = /* @__PURE__ */ __exportAll({
25242
25462
  *
25243
25463
  * Idempotent: guarded on column existence.
25244
25464
  */
25245
- async function up$29(db) {
25465
+ async function up$30(db) {
25246
25466
  if ((await sql`
25247
25467
  SELECT EXISTS (
25248
25468
  SELECT 1 FROM information_schema.columns
@@ -25256,7 +25476,7 @@ async function up$29(db) {
25256
25476
  ADD COLUMN backup_staleness_warn_hours INTEGER
25257
25477
  `.execute(db);
25258
25478
  }
25259
- async function down$29(db) {
25479
+ async function down$30(db) {
25260
25480
  await sql`
25261
25481
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS backup_staleness_warn_hours
25262
25482
  `.execute(db);
@@ -25265,8 +25485,8 @@ var init__078_org_settings_backup_staleness = __esmMin((() => {}));
25265
25485
  //#endregion
25266
25486
  //#region src/db/migrations/079_org_settings_scaler_spawn_timeout.ts
25267
25487
  var _079_org_settings_scaler_spawn_timeout_exports = /* @__PURE__ */ __exportAll({
25268
- down: () => down$28,
25269
- up: () => up$28
25488
+ down: () => down$29,
25489
+ up: () => up$29
25270
25490
  });
25271
25491
  /**
25272
25492
  * Add `org_settings.scaler_spawn_timeout_ms BIGINT` (nullable).
@@ -25278,7 +25498,7 @@ var _079_org_settings_scaler_spawn_timeout_exports = /* @__PURE__ */ __exportAll
25278
25498
  *
25279
25499
  * Idempotent: a re-run on a DB that already has the column is a no-op.
25280
25500
  */
25281
- async function up$28(db) {
25501
+ async function up$29(db) {
25282
25502
  if ((await sql`
25283
25503
  SELECT EXISTS (
25284
25504
  SELECT 1 FROM information_schema.columns
@@ -25292,7 +25512,7 @@ async function up$28(db) {
25292
25512
  ADD COLUMN scaler_spawn_timeout_ms BIGINT
25293
25513
  `.execute(db);
25294
25514
  }
25295
- async function down$28(db) {
25515
+ async function down$29(db) {
25296
25516
  await sql`
25297
25517
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS scaler_spawn_timeout_ms
25298
25518
  `.execute(db);
@@ -25301,8 +25521,8 @@ var init__079_org_settings_scaler_spawn_timeout = __esmMin((() => {}));
25301
25521
  //#endregion
25302
25522
  //#region src/db/migrations/080_cluster_settings.ts
25303
25523
  var _080_cluster_settings_exports = /* @__PURE__ */ __exportAll({
25304
- down: () => down$27,
25305
- up: () => up$27
25524
+ down: () => down$28,
25525
+ up: () => up$28
25306
25526
  });
25307
25527
  /**
25308
25528
  * Create `cluster_settings`: a single-row (id='default') table of fleet-wide
@@ -25317,7 +25537,7 @@ var _080_cluster_settings_exports = /* @__PURE__ */ __exportAll({
25317
25537
  *
25318
25538
  * Idempotent: a re-run on a DB that already has the table is a no-op.
25319
25539
  */
25320
- async function up$27(db) {
25540
+ async function up$28(db) {
25321
25541
  if ((await sql`
25322
25542
  SELECT EXISTS (
25323
25543
  SELECT 1 FROM information_schema.tables
@@ -25341,15 +25561,15 @@ async function up$27(db) {
25341
25561
  )
25342
25562
  `.execute(db);
25343
25563
  }
25344
- async function down$27(db) {
25564
+ async function down$28(db) {
25345
25565
  await sql`DROP TABLE IF EXISTS public.cluster_settings`.execute(db);
25346
25566
  }
25347
25567
  var init__080_cluster_settings = __esmMin((() => {}));
25348
25568
  //#endregion
25349
25569
  //#region src/db/migrations/081_org_settings_queue_timeout.ts
25350
25570
  var _081_org_settings_queue_timeout_exports = /* @__PURE__ */ __exportAll({
25351
- down: () => down$26,
25352
- up: () => up$26
25571
+ down: () => down$27,
25572
+ up: () => up$27
25353
25573
  });
25354
25574
  /**
25355
25575
  * Add `org_settings.queue_timeout_ms BIGINT` (nullable).
@@ -25366,7 +25586,7 @@ var _081_org_settings_queue_timeout_exports = /* @__PURE__ */ __exportAll({
25366
25586
  *
25367
25587
  * Idempotent: a re-run on a DB that already has the column is a no-op.
25368
25588
  */
25369
- async function up$26(db) {
25589
+ async function up$27(db) {
25370
25590
  if ((await sql`
25371
25591
  SELECT EXISTS (
25372
25592
  SELECT 1 FROM information_schema.columns
@@ -25380,7 +25600,7 @@ async function up$26(db) {
25380
25600
  ADD COLUMN queue_timeout_ms BIGINT
25381
25601
  `.execute(db);
25382
25602
  }
25383
- async function down$26(db) {
25603
+ async function down$27(db) {
25384
25604
  await sql`
25385
25605
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS queue_timeout_ms
25386
25606
  `.execute(db);
@@ -25389,8 +25609,8 @@ var init__081_org_settings_queue_timeout = __esmMin((() => {}));
25389
25609
  //#endregion
25390
25610
  //#region src/db/migrations/082_host_s3_reachable.ts
25391
25611
  var _082_host_s3_reachable_exports = /* @__PURE__ */ __exportAll({
25392
- down: () => down$25,
25393
- up: () => up$25
25612
+ down: () => down$26,
25613
+ up: () => up$26
25394
25614
  });
25395
25615
  /**
25396
25616
  * Add `host_roster.s3_reachable BOOLEAN` (nullable).
@@ -25404,7 +25624,7 @@ var _082_host_s3_reachable_exports = /* @__PURE__ */ __exportAll({
25404
25624
  *
25405
25625
  * Idempotent: a re-run on a DB that already has the column is a no-op.
25406
25626
  */
25407
- async function up$25(db) {
25627
+ async function up$26(db) {
25408
25628
  if ((await sql`
25409
25629
  SELECT EXISTS (
25410
25630
  SELECT 1 FROM information_schema.columns
@@ -25418,7 +25638,7 @@ async function up$25(db) {
25418
25638
  ADD COLUMN s3_reachable BOOLEAN
25419
25639
  `.execute(db);
25420
25640
  }
25421
- async function down$25(db) {
25641
+ async function down$26(db) {
25422
25642
  await sql`
25423
25643
  ALTER TABLE public.host_roster DROP COLUMN IF EXISTS s3_reachable
25424
25644
  `.execute(db);
@@ -25427,8 +25647,8 @@ var init__082_host_s3_reachable = __esmMin((() => {}));
25427
25647
  //#endregion
25428
25648
  //#region src/db/migrations/083_org_settings_artifact_caps.ts
25429
25649
  var _083_org_settings_artifact_caps_exports = /* @__PURE__ */ __exportAll({
25430
- down: () => down$24,
25431
- up: () => up$24
25650
+ down: () => down$25,
25651
+ up: () => up$25
25432
25652
  });
25433
25653
  /**
25434
25654
  * Add `org_settings.artifact_max_bytes` + `artifact_max_per_run` (both nullable
@@ -25444,7 +25664,7 @@ var _083_org_settings_artifact_caps_exports = /* @__PURE__ */ __exportAll({
25444
25664
  * Idempotent: guarded on column existence; a re-run on a DB that already has a
25445
25665
  * column is a no-op.
25446
25666
  */
25447
- async function up$24(db) {
25667
+ async function up$25(db) {
25448
25668
  for (const col of ["artifact_max_bytes", "artifact_max_per_run"]) {
25449
25669
  if ((await sql`
25450
25670
  SELECT EXISTS (
@@ -25457,7 +25677,7 @@ async function up$24(db) {
25457
25677
  await sql`ALTER TABLE public.org_settings ADD COLUMN ${sql.ref(col)} BIGINT`.execute(db);
25458
25678
  }
25459
25679
  }
25460
- async function down$24(db) {
25680
+ async function down$25(db) {
25461
25681
  await sql`ALTER TABLE public.org_settings DROP COLUMN IF EXISTS artifact_max_bytes`.execute(db);
25462
25682
  await sql`ALTER TABLE public.org_settings DROP COLUMN IF EXISTS artifact_max_per_run`.execute(db);
25463
25683
  }
@@ -25465,8 +25685,8 @@ var init__083_org_settings_artifact_caps = __esmMin((() => {}));
25465
25685
  //#endregion
25466
25686
  //#region src/db/migrations/084_orchestrator_signing_keys.ts
25467
25687
  var _084_orchestrator_signing_keys_exports = /* @__PURE__ */ __exportAll({
25468
- down: () => down$23,
25469
- up: () => up$23
25688
+ down: () => down$24,
25689
+ up: () => up$24
25470
25690
  });
25471
25691
  /**
25472
25692
  * Add the `orchestrator_signing_keys` table: the cluster-scoped, long-lived
@@ -25484,12 +25704,12 @@ var _084_orchestrator_signing_keys_exports = /* @__PURE__ */ __exportAll({
25484
25704
  *
25485
25705
  * Idempotent: guarded on table existence.
25486
25706
  */
25487
- async function up$23(db) {
25707
+ async function up$24(db) {
25488
25708
  if (await tableExists$1(db, "orchestrator_signing_keys")) return;
25489
25709
  await db.schema.createTable("orchestrator_signing_keys").addColumn("kid", "text", (c) => c.primaryKey()).addColumn("public_jwk", "jsonb", (c) => c.notNull()).addColumn("encrypted_private_jwk", "text").addColumn("key_version", "integer", (c) => c.notNull().defaultTo(1)).addColumn("alg", "text", (c) => c.notNull()).addColumn("signer_kind", "text", (c) => c.notNull()).addColumn("key_ref", "text").addColumn("status", "text", (c) => c.notNull().defaultTo("active")).addColumn("revocation_reason", "text").addColumn("created_at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)).addColumn("activated_at", "timestamptz").addColumn("retired_at", "timestamptz").addColumn("revoked_at", "timestamptz").execute();
25490
25710
  await db.schema.createIndex("idx_orch_signing_keys_status").on("orchestrator_signing_keys").column("status").execute();
25491
25711
  }
25492
- async function down$23(db) {
25712
+ async function down$24(db) {
25493
25713
  await db.schema.dropTable("orchestrator_signing_keys").ifExists().execute();
25494
25714
  }
25495
25715
  async function tableExists$1(db, table) {
@@ -25504,8 +25724,8 @@ var init__084_orchestrator_signing_keys = __esmMin((() => {}));
25504
25724
  //#endregion
25505
25725
  //#region src/db/migrations/085_cluster_settings_reroute_flap_grace_ms.ts
25506
25726
  var _085_cluster_settings_reroute_flap_grace_ms_exports = /* @__PURE__ */ __exportAll({
25507
- down: () => down$22,
25508
- up: () => up$22
25727
+ down: () => down$23,
25728
+ up: () => up$23
25509
25729
  });
25510
25730
  /**
25511
25731
  * Add `cluster_settings.reroute_flap_grace_ms` (nullable BIGINT).
@@ -25515,7 +25735,7 @@ var _085_cluster_settings_reroute_flap_grace_ms_exports = /* @__PURE__ */ __expo
25515
25735
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25516
25736
  * the column is a no-op.
25517
25737
  */
25518
- async function up$22(db) {
25738
+ async function up$23(db) {
25519
25739
  if ((await sql`
25520
25740
  SELECT EXISTS (
25521
25741
  SELECT 1 FROM information_schema.columns
@@ -25526,15 +25746,15 @@ async function up$22(db) {
25526
25746
  `.execute(db)).rows[0]?.exists) return;
25527
25747
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN reroute_flap_grace_ms BIGINT`.execute(db);
25528
25748
  }
25529
- async function down$22(db) {
25749
+ async function down$23(db) {
25530
25750
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS reroute_flap_grace_ms`.execute(db);
25531
25751
  }
25532
25752
  var init__085_cluster_settings_reroute_flap_grace_ms = __esmMin((() => {}));
25533
25753
  //#endregion
25534
25754
  //#region src/db/migrations/086_cluster_settings_max_fanout_hosts.ts
25535
25755
  var _086_cluster_settings_max_fanout_hosts_exports = /* @__PURE__ */ __exportAll({
25536
- down: () => down$21,
25537
- up: () => up$21
25756
+ down: () => down$22,
25757
+ up: () => up$22
25538
25758
  });
25539
25759
  /**
25540
25760
  * Add `cluster_settings.max_fanout_hosts` (nullable INTEGER).
@@ -25544,7 +25764,7 @@ var _086_cluster_settings_max_fanout_hosts_exports = /* @__PURE__ */ __exportAll
25544
25764
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25545
25765
  * the column is a no-op.
25546
25766
  */
25547
- async function up$21(db) {
25767
+ async function up$22(db) {
25548
25768
  if ((await sql`
25549
25769
  SELECT EXISTS (
25550
25770
  SELECT 1 FROM information_schema.columns
@@ -25555,15 +25775,15 @@ async function up$21(db) {
25555
25775
  `.execute(db)).rows[0]?.exists) return;
25556
25776
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN max_fanout_hosts INTEGER`.execute(db);
25557
25777
  }
25558
- async function down$21(db) {
25778
+ async function down$22(db) {
25559
25779
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS max_fanout_hosts`.execute(db);
25560
25780
  }
25561
25781
  var init__086_cluster_settings_max_fanout_hosts = __esmMin((() => {}));
25562
25782
  //#endregion
25563
25783
  //#region src/db/migrations/087_cluster_settings_event_router_rate_limit.ts
25564
25784
  var _087_cluster_settings_event_router_rate_limit_exports = /* @__PURE__ */ __exportAll({
25565
- down: () => down$20,
25566
- up: () => up$20
25785
+ down: () => down$21,
25786
+ up: () => up$21
25567
25787
  });
25568
25788
  /**
25569
25789
  * Add `cluster_settings.event_router_rate_limit_per_workflow_per_minute` (nullable INTEGER).
@@ -25573,7 +25793,7 @@ var _087_cluster_settings_event_router_rate_limit_exports = /* @__PURE__ */ __ex
25573
25793
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25574
25794
  * the column is a no-op.
25575
25795
  */
25576
- async function up$20(db) {
25796
+ async function up$21(db) {
25577
25797
  if ((await sql`
25578
25798
  SELECT EXISTS (
25579
25799
  SELECT 1 FROM information_schema.columns
@@ -25584,15 +25804,15 @@ async function up$20(db) {
25584
25804
  `.execute(db)).rows[0]?.exists) return;
25585
25805
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN event_router_rate_limit_per_workflow_per_minute INTEGER`.execute(db);
25586
25806
  }
25587
- async function down$20(db) {
25807
+ async function down$21(db) {
25588
25808
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS event_router_rate_limit_per_workflow_per_minute`.execute(db);
25589
25809
  }
25590
25810
  var init__087_cluster_settings_event_router_rate_limit = __esmMin((() => {}));
25591
25811
  //#endregion
25592
25812
  //#region src/db/migrations/088_cluster_settings_cache_max_tarball_bytes.ts
25593
25813
  var _088_cluster_settings_cache_max_tarball_bytes_exports = /* @__PURE__ */ __exportAll({
25594
- down: () => down$19,
25595
- up: () => up$19
25814
+ down: () => down$20,
25815
+ up: () => up$20
25596
25816
  });
25597
25817
  /**
25598
25818
  * Add `cluster_settings.cache_max_tarball_bytes` (nullable BIGINT).
@@ -25602,7 +25822,7 @@ var _088_cluster_settings_cache_max_tarball_bytes_exports = /* @__PURE__ */ __ex
25602
25822
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25603
25823
  * the column is a no-op.
25604
25824
  */
25605
- async function up$19(db) {
25825
+ async function up$20(db) {
25606
25826
  if ((await sql`
25607
25827
  SELECT EXISTS (
25608
25828
  SELECT 1 FROM information_schema.columns
@@ -25613,15 +25833,15 @@ async function up$19(db) {
25613
25833
  `.execute(db)).rows[0]?.exists) return;
25614
25834
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN cache_max_tarball_bytes BIGINT`.execute(db);
25615
25835
  }
25616
- async function down$19(db) {
25836
+ async function down$20(db) {
25617
25837
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS cache_max_tarball_bytes`.execute(db);
25618
25838
  }
25619
25839
  var init__088_cluster_settings_cache_max_tarball_bytes = __esmMin((() => {}));
25620
25840
  //#endregion
25621
25841
  //#region src/db/migrations/089_cluster_settings_cache_ttl_days.ts
25622
25842
  var _089_cluster_settings_cache_ttl_days_exports = /* @__PURE__ */ __exportAll({
25623
- down: () => down$18,
25624
- up: () => up$18
25843
+ down: () => down$19,
25844
+ up: () => up$19
25625
25845
  });
25626
25846
  /**
25627
25847
  * Add `cluster_settings.cache_ttl_days` (nullable INTEGER).
@@ -25631,7 +25851,7 @@ var _089_cluster_settings_cache_ttl_days_exports = /* @__PURE__ */ __exportAll({
25631
25851
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25632
25852
  * the column is a no-op.
25633
25853
  */
25634
- async function up$18(db) {
25854
+ async function up$19(db) {
25635
25855
  if ((await sql`
25636
25856
  SELECT EXISTS (
25637
25857
  SELECT 1 FROM information_schema.columns
@@ -25642,15 +25862,15 @@ async function up$18(db) {
25642
25862
  `.execute(db)).rows[0]?.exists) return;
25643
25863
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN cache_ttl_days INTEGER`.execute(db);
25644
25864
  }
25645
- async function down$18(db) {
25865
+ async function down$19(db) {
25646
25866
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS cache_ttl_days`.execute(db);
25647
25867
  }
25648
25868
  var init__089_cluster_settings_cache_ttl_days = __esmMin((() => {}));
25649
25869
  //#endregion
25650
25870
  //#region src/db/migrations/090_cluster_settings_concurrency_wait_timeout_ms.ts
25651
25871
  var _090_cluster_settings_concurrency_wait_timeout_ms_exports = /* @__PURE__ */ __exportAll({
25652
- down: () => down$17,
25653
- up: () => up$17
25872
+ down: () => down$18,
25873
+ up: () => up$18
25654
25874
  });
25655
25875
  /**
25656
25876
  * Add `cluster_settings.concurrency_wait_timeout_ms` (nullable BIGINT).
@@ -25660,7 +25880,7 @@ var _090_cluster_settings_concurrency_wait_timeout_ms_exports = /* @__PURE__ */
25660
25880
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25661
25881
  * the column is a no-op.
25662
25882
  */
25663
- async function up$17(db) {
25883
+ async function up$18(db) {
25664
25884
  if ((await sql`
25665
25885
  SELECT EXISTS (
25666
25886
  SELECT 1 FROM information_schema.columns
@@ -25671,15 +25891,15 @@ async function up$17(db) {
25671
25891
  `.execute(db)).rows[0]?.exists) return;
25672
25892
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN concurrency_wait_timeout_ms BIGINT`.execute(db);
25673
25893
  }
25674
- async function down$17(db) {
25894
+ async function down$18(db) {
25675
25895
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS concurrency_wait_timeout_ms`.execute(db);
25676
25896
  }
25677
25897
  var init__090_cluster_settings_concurrency_wait_timeout_ms = __esmMin((() => {}));
25678
25898
  //#endregion
25679
25899
  //#region src/db/migrations/091_cluster_settings_agent_token_ttl_ms.ts
25680
25900
  var _091_cluster_settings_agent_token_ttl_ms_exports = /* @__PURE__ */ __exportAll({
25681
- down: () => down$16,
25682
- up: () => up$16
25901
+ down: () => down$17,
25902
+ up: () => up$17
25683
25903
  });
25684
25904
  /**
25685
25905
  * Add `cluster_settings.agent_token_ttl_ms` (nullable BIGINT).
@@ -25689,7 +25909,7 @@ var _091_cluster_settings_agent_token_ttl_ms_exports = /* @__PURE__ */ __exportA
25689
25909
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25690
25910
  * the column is a no-op.
25691
25911
  */
25692
- async function up$16(db) {
25912
+ async function up$17(db) {
25693
25913
  if ((await sql`
25694
25914
  SELECT EXISTS (
25695
25915
  SELECT 1 FROM information_schema.columns
@@ -25700,15 +25920,15 @@ async function up$16(db) {
25700
25920
  `.execute(db)).rows[0]?.exists) return;
25701
25921
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN agent_token_ttl_ms BIGINT`.execute(db);
25702
25922
  }
25703
- async function down$16(db) {
25923
+ async function down$17(db) {
25704
25924
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS agent_token_ttl_ms`.execute(db);
25705
25925
  }
25706
25926
  var init__091_cluster_settings_agent_token_ttl_ms = __esmMin((() => {}));
25707
25927
  //#endregion
25708
25928
  //#region src/db/migrations/092_cluster_settings_version.ts
25709
25929
  var _092_cluster_settings_version_exports = /* @__PURE__ */ __exportAll({
25710
- down: () => down$15,
25711
- up: () => up$15
25930
+ down: () => down$16,
25931
+ up: () => up$16
25712
25932
  });
25713
25933
  /**
25714
25934
  * Add `cluster_settings.version` (monotonic BIGINT, bumped on each settings
@@ -25722,7 +25942,7 @@ var _092_cluster_settings_version_exports = /* @__PURE__ */ __exportAll({
25722
25942
  * Idempotent: guarded on column existence; a re-run on a DB that already has
25723
25943
  * the column is a no-op.
25724
25944
  */
25725
- async function up$15(db) {
25945
+ async function up$16(db) {
25726
25946
  if ((await sql`
25727
25947
  SELECT EXISTS (
25728
25948
  SELECT 1 FROM information_schema.columns
@@ -25733,15 +25953,15 @@ async function up$15(db) {
25733
25953
  `.execute(db)).rows[0]?.exists) return;
25734
25954
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN version BIGINT NOT NULL DEFAULT 0`.execute(db);
25735
25955
  }
25736
- async function down$15(db) {
25956
+ async function down$16(db) {
25737
25957
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS version`.execute(db);
25738
25958
  }
25739
25959
  var init__092_cluster_settings_version = __esmMin((() => {}));
25740
25960
  //#endregion
25741
25961
  //#region src/db/migrations/093_org_settings_sandbox_allowlist.ts
25742
25962
  var _093_org_settings_sandbox_allowlist_exports = /* @__PURE__ */ __exportAll({
25743
- down: () => down$14,
25744
- up: () => up$14
25963
+ down: () => down$15,
25964
+ up: () => up$15
25745
25965
  });
25746
25966
  /**
25747
25967
  * Add the per-org container-sandbox escape-hatch allow-list to `org_settings`:
@@ -25759,7 +25979,7 @@ var _093_org_settings_sandbox_allowlist_exports = /* @__PURE__ */ __exportAll({
25759
25979
  *
25760
25980
  * Idempotent: a re-run on a DB that already has a column skips that column.
25761
25981
  */
25762
- async function columnExists$3(db, column) {
25982
+ async function columnExists$4(db, column) {
25763
25983
  return (await sql`
25764
25984
  SELECT EXISTS (
25765
25985
  SELECT 1 FROM information_schema.columns
@@ -25769,17 +25989,17 @@ async function columnExists$3(db, column) {
25769
25989
  ) AS exists
25770
25990
  `.execute(db)).rows[0]?.exists ?? false;
25771
25991
  }
25772
- async function up$14(db) {
25773
- if (!await columnExists$3(db, "sandbox_allowed_capabilities")) await sql`
25992
+ async function up$15(db) {
25993
+ if (!await columnExists$4(db, "sandbox_allowed_capabilities")) await sql`
25774
25994
  ALTER TABLE public.org_settings
25775
25995
  ADD COLUMN sandbox_allowed_capabilities TEXT[]
25776
25996
  `.execute(db);
25777
- if (!await columnExists$3(db, "sandbox_allow_host_network")) await sql`
25997
+ if (!await columnExists$4(db, "sandbox_allow_host_network")) await sql`
25778
25998
  ALTER TABLE public.org_settings
25779
25999
  ADD COLUMN sandbox_allow_host_network BOOLEAN
25780
26000
  `.execute(db);
25781
26001
  }
25782
- async function down$14(db) {
26002
+ async function down$15(db) {
25783
26003
  await sql`
25784
26004
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS sandbox_allowed_capabilities
25785
26005
  `.execute(db);
@@ -25791,8 +26011,8 @@ var init__093_org_settings_sandbox_allowlist = __esmMin((() => {}));
25791
26011
  //#endregion
25792
26012
  //#region src/db/migrations/094_dashboard_encryption_keys.ts
25793
26013
  var _094_dashboard_encryption_keys_exports = /* @__PURE__ */ __exportAll({
25794
- down: () => down$13,
25795
- up: () => up$13
26014
+ down: () => down$14,
26015
+ up: () => up$14
25796
26016
  });
25797
26017
  /**
25798
26018
  * Add the `dashboard_encryption_keys` table: the cluster-scoped, long-lived
@@ -25811,12 +26031,12 @@ var _094_dashboard_encryption_keys_exports = /* @__PURE__ */ __exportAll({
25811
26031
  *
25812
26032
  * Idempotent: guarded on table existence.
25813
26033
  */
25814
- async function up$13(db) {
26034
+ async function up$14(db) {
25815
26035
  if (await tableExists(db, "dashboard_encryption_keys")) return;
25816
26036
  await db.schema.createTable("dashboard_encryption_keys").addColumn("kid", "text", (c) => c.primaryKey()).addColumn("public_jwk", "jsonb", (c) => c.notNull()).addColumn("encrypted_private_key", "text", (c) => c.notNull()).addColumn("status", "text", (c) => c.notNull().defaultTo("active")).addColumn("revocation_reason", "text").addColumn("created_at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)).addColumn("activated_at", "timestamptz").addColumn("revoked_at", "timestamptz").execute();
25817
26037
  await db.schema.createIndex("idx_dashboard_encryption_keys_status").on("dashboard_encryption_keys").column("status").execute();
25818
26038
  }
25819
- async function down$13(db) {
26039
+ async function down$14(db) {
25820
26040
  await db.schema.dropTable("dashboard_encryption_keys").ifExists().execute();
25821
26041
  }
25822
26042
  async function tableExists(db, table) {
@@ -25831,8 +26051,8 @@ var init__094_dashboard_encryption_keys = __esmMin((() => {}));
25831
26051
  //#endregion
25832
26052
  //#region src/db/migrations/095_dashboard_write_policy_tristate.ts
25833
26053
  var _095_dashboard_write_policy_tristate_exports = /* @__PURE__ */ __exportAll({
25834
- down: () => down$12,
25835
- up: () => up$12
26054
+ down: () => down$13,
26055
+ up: () => up$13
25836
26056
  });
25837
26057
  /**
25838
26058
  * Migrate stored `org_settings.dashboard_write_policy` JSONB from the legacy
@@ -25850,7 +26070,7 @@ var _095_dashboard_write_policy_tristate_exports = /* @__PURE__ */ __exportAll({
25850
26070
  * Pure SQL rewrite: for each row, rebuild the object keeping only non-`true`
25851
26071
  * entries and mapping `false` → `'disabled'`, leaving existing string values.
25852
26072
  */
25853
- async function up$12(db) {
26073
+ async function up$13(db) {
25854
26074
  await sql`
25855
26075
  UPDATE org_settings
25856
26076
  SET dashboard_write_policy = COALESCE(
@@ -25877,13 +26097,13 @@ async function up$12(db) {
25877
26097
  )
25878
26098
  `.execute(db);
25879
26099
  }
25880
- async function down$12() {}
26100
+ async function down$13() {}
25881
26101
  var init__095_dashboard_write_policy_tristate = __esmMin((() => {}));
25882
26102
  //#endregion
25883
26103
  //#region src/db/migrations/096_multi_schedule_cron_last_fired.ts
25884
26104
  var _096_multi_schedule_cron_last_fired_exports = /* @__PURE__ */ __exportAll({
25885
- down: () => down$11,
25886
- up: () => up$11
26105
+ down: () => down$12,
26106
+ up: () => up$12
25887
26107
  });
25888
26108
  /**
25889
26109
  * Track cron last-fired per (registration, schedule) instead of per
@@ -25898,7 +26118,7 @@ var _096_multi_schedule_cron_last_fired_exports = /* @__PURE__ */ __exportAll({
25898
26118
  *
25899
26119
  * Idempotent: re-running on an already-migrated DB skips each step.
25900
26120
  */
25901
- async function columnExists$2(db, column) {
26121
+ async function columnExists$3(db, column) {
25902
26122
  return (await sql`
25903
26123
  SELECT EXISTS (
25904
26124
  SELECT 1 FROM information_schema.columns
@@ -25918,8 +26138,8 @@ async function primaryKeyColumns(db) {
25918
26138
  ORDER BY a.attnum
25919
26139
  `.execute(db)).rows.map((row) => row.attname);
25920
26140
  }
25921
- async function up$11(db) {
25922
- if (!await columnExists$2(db, "schedule_key")) await sql`ALTER TABLE public.cron_last_fired ADD COLUMN schedule_key text`.execute(db);
26141
+ async function up$12(db) {
26142
+ if (!await columnExists$3(db, "schedule_key")) await sql`ALTER TABLE public.cron_last_fired ADD COLUMN schedule_key text`.execute(db);
25923
26143
  await sql`
25924
26144
  UPDATE public.cron_last_fired clf
25925
26145
  SET schedule_key = k.key
@@ -25945,7 +26165,7 @@ async function up$11(db) {
25945
26165
  `.execute(db);
25946
26166
  }
25947
26167
  }
25948
- async function down$11(db) {
26168
+ async function down$12(db) {
25949
26169
  await sql`
25950
26170
  DELETE FROM public.cron_last_fired a
25951
26171
  USING public.cron_last_fired b
@@ -25957,14 +26177,14 @@ async function down$11(db) {
25957
26177
  ALTER TABLE public.cron_last_fired
25958
26178
  ADD CONSTRAINT cron_last_fired_pkey PRIMARY KEY (registration_id)
25959
26179
  `.execute(db);
25960
- if (await columnExists$2(db, "schedule_key")) await sql`ALTER TABLE public.cron_last_fired DROP COLUMN schedule_key`.execute(db);
26180
+ if (await columnExists$3(db, "schedule_key")) await sql`ALTER TABLE public.cron_last_fired DROP COLUMN schedule_key`.execute(db);
25961
26181
  }
25962
26182
  var init__096_multi_schedule_cron_last_fired = __esmMin((() => {}));
25963
26183
  //#endregion
25964
26184
  //#region src/db/migrations/097_execution_runs_pr_number.ts
25965
26185
  var _097_execution_runs_pr_number_exports = /* @__PURE__ */ __exportAll({
25966
- down: () => down$10,
25967
- up: () => up$10
26186
+ down: () => down$11,
26187
+ up: () => up$11
25968
26188
  });
25969
26189
  /**
25970
26190
  * Add `pr_number INTEGER NULL` to `execution_runs`.
@@ -25977,7 +26197,7 @@ var _097_execution_runs_pr_number_exports = /* @__PURE__ */ __exportAll({
25977
26197
  *
25978
26198
  * Idempotent: a re-run on a DB that already has the column is a no-op.
25979
26199
  */
25980
- async function columnExists$1(db, column) {
26200
+ async function columnExists$2(db, column) {
25981
26201
  return (await sql`
25982
26202
  SELECT EXISTS (
25983
26203
  SELECT 1 FROM information_schema.columns
@@ -25987,13 +26207,13 @@ async function columnExists$1(db, column) {
25987
26207
  ) AS exists
25988
26208
  `.execute(db)).rows[0]?.exists ?? false;
25989
26209
  }
25990
- async function up$10(db) {
25991
- if (!await columnExists$1(db, "pr_number")) await sql`
26210
+ async function up$11(db) {
26211
+ if (!await columnExists$2(db, "pr_number")) await sql`
25992
26212
  ALTER TABLE public.execution_runs
25993
26213
  ADD COLUMN pr_number INTEGER
25994
26214
  `.execute(db);
25995
26215
  }
25996
- async function down$10(db) {
26216
+ async function down$11(db) {
25997
26217
  await sql`
25998
26218
  ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS pr_number
25999
26219
  `.execute(db);
@@ -26002,8 +26222,8 @@ var init__097_execution_runs_pr_number = __esmMin((() => {}));
26002
26222
  //#endregion
26003
26223
  //#region src/db/migrations/098_execution_runs_customer_id.ts
26004
26224
  var _098_execution_runs_customer_id_exports = /* @__PURE__ */ __exportAll({
26005
- down: () => down$9,
26006
- up: () => up$9
26225
+ down: () => down$10,
26226
+ up: () => up$10
26007
26227
  });
26008
26228
  /**
26009
26229
  * Denormalize the owning org onto `execution_runs` so the concurrency-gate
@@ -26021,7 +26241,7 @@ var _098_execution_runs_customer_id_exports = /* @__PURE__ */ __exportAll({
26021
26241
  *
26022
26242
  * Idempotent: re-running skips the column when it already exists.
26023
26243
  */
26024
- async function columnExists(db, column) {
26244
+ async function columnExists$1(db, column) {
26025
26245
  return (await sql`
26026
26246
  SELECT EXISTS (
26027
26247
  SELECT 1 FROM information_schema.columns
@@ -26031,8 +26251,8 @@ async function columnExists(db, column) {
26031
26251
  ) AS exists
26032
26252
  `.execute(db)).rows[0]?.exists ?? false;
26033
26253
  }
26034
- async function up$9(db) {
26035
- if (!await columnExists(db, "customer_id")) {
26254
+ async function up$10(db) {
26255
+ if (!await columnExists$1(db, "customer_id")) {
26036
26256
  await sql`
26037
26257
  ALTER TABLE public.execution_runs
26038
26258
  ADD COLUMN customer_id TEXT NOT NULL DEFAULT '__default__'
@@ -26055,7 +26275,7 @@ async function up$9(db) {
26055
26275
  ON public.execution_runs (customer_id, context)
26056
26276
  `.execute(db);
26057
26277
  }
26058
- async function down$9(db) {
26278
+ async function down$10(db) {
26059
26279
  await sql`DROP INDEX IF EXISTS execution_runs_customer_id_context_idx`.execute(db);
26060
26280
  await sql`
26061
26281
  ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS customer_id
@@ -26065,8 +26285,8 @@ var init__098_execution_runs_customer_id = __esmMin((() => {}));
26065
26285
  //#endregion
26066
26286
  //#region src/db/migrations/099_cluster_settings_dashboard_verified_issuer.ts
26067
26287
  var _099_cluster_settings_dashboard_verified_issuer_exports = /* @__PURE__ */ __exportAll({
26068
- down: () => down$8,
26069
- up: () => up$8
26288
+ down: () => down$9,
26289
+ up: () => up$9
26070
26290
  });
26071
26291
  /**
26072
26292
  * Add `cluster_settings.dashboard_verified_issuer` (nullable text).
@@ -26085,7 +26305,7 @@ var _099_cluster_settings_dashboard_verified_issuer_exports = /* @__PURE__ */ __
26085
26305
  * Idempotent: guarded on column existence; a re-run on a DB that already has the
26086
26306
  * column is a no-op.
26087
26307
  */
26088
- async function up$8(db) {
26308
+ async function up$9(db) {
26089
26309
  if ((await sql`
26090
26310
  SELECT EXISTS (
26091
26311
  SELECT 1 FROM information_schema.columns
@@ -26096,15 +26316,15 @@ async function up$8(db) {
26096
26316
  `.execute(db)).rows[0]?.exists) return;
26097
26317
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN dashboard_verified_issuer TEXT`.execute(db);
26098
26318
  }
26099
- async function down$8(db) {
26319
+ async function down$9(db) {
26100
26320
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS dashboard_verified_issuer`.execute(db);
26101
26321
  }
26102
26322
  var init__099_cluster_settings_dashboard_verified_issuer = __esmMin((() => {}));
26103
26323
  //#endregion
26104
26324
  //#region src/db/migrations/100_held_runs_hold_type_vocabulary.ts
26105
26325
  var _100_held_runs_hold_type_vocabulary_exports = /* @__PURE__ */ __exportAll({
26106
- down: () => down$7,
26107
- up: () => up$7
26326
+ down: () => down$8,
26327
+ up: () => up$8
26108
26328
  });
26109
26329
  /**
26110
26330
  * Realign `held_runs.hold_type` onto the engine's `HoldType` vocabulary.
@@ -26123,7 +26343,7 @@ var _100_held_runs_hold_type_vocabulary_exports = /* @__PURE__ */ __exportAll({
26123
26343
  *
26124
26344
  * Idempotent: a second run matches no rows.
26125
26345
  */
26126
- async function up$7(db) {
26346
+ async function up$8(db) {
26127
26347
  await sql`UPDATE public.held_runs SET hold_type = 'reviewer' WHERE hold_type = 'approval'`.execute(db);
26128
26348
  await sql`UPDATE public.held_runs SET hold_type = 'timer' WHERE hold_type = 'wait_timer'`.execute(db);
26129
26349
  }
@@ -26137,7 +26357,7 @@ async function up$7(db) {
26137
26357
  * `wait_timer` alone, so leaving those rows spelled `timer` would strand them
26138
26358
  * in the expire-and-fail path.
26139
26359
  */
26140
- async function down$7(db) {
26360
+ async function down$8(db) {
26141
26361
  await sql`UPDATE public.held_runs SET hold_type = 'approval' WHERE hold_type = 'reviewer'`.execute(db);
26142
26362
  await sql`UPDATE public.held_runs SET hold_type = 'wait_timer' WHERE hold_type = 'timer'`.execute(db);
26143
26363
  }
@@ -26145,8 +26365,8 @@ var init__100_held_runs_hold_type_vocabulary = __esmMin((() => {}));
26145
26365
  //#endregion
26146
26366
  //#region src/db/migrations/101_contexts_hold_expiry_drop_default.ts
26147
26367
  var _101_contexts_hold_expiry_drop_default_exports = /* @__PURE__ */ __exportAll({
26148
- down: () => down$6,
26149
- up: () => up$6
26368
+ down: () => down$7,
26369
+ up: () => up$7
26150
26370
  });
26151
26371
  /**
26152
26372
  * Give the context hold expiry a single default, and retire the stored zeroes.
@@ -26167,7 +26387,7 @@ var _101_contexts_hold_expiry_drop_default_exports = /* @__PURE__ */ __exportAll
26167
26387
  * Idempotent: dropping an absent default is a no-op and the UPDATE matches no
26168
26388
  * rows on a second run.
26169
26389
  */
26170
- async function up$6(db) {
26390
+ async function up$7(db) {
26171
26391
  await sql`ALTER TABLE public.contexts ALTER COLUMN hold_expiry_seconds DROP DEFAULT`.execute(db);
26172
26392
  await sql`UPDATE public.contexts SET hold_expiry_seconds = NULL WHERE hold_expiry_seconds = 0`.execute(db);
26173
26393
  }
@@ -26179,15 +26399,15 @@ async function up$6(db) {
26179
26399
  * back to `0` would resume cancelling every hold on its context — so a
26180
26400
  * rollback keeps them on the fallback rather than re-breaking them.
26181
26401
  */
26182
- async function down$6(db) {
26402
+ async function down$7(db) {
26183
26403
  await sql`ALTER TABLE public.contexts ALTER COLUMN hold_expiry_seconds SET DEFAULT 86400`.execute(db);
26184
26404
  }
26185
26405
  var init__101_contexts_hold_expiry_drop_default = __esmMin((() => {}));
26186
26406
  //#endregion
26187
26407
  //#region src/db/migrations/102_dispatch_queue_agent_id.ts
26188
26408
  var _102_dispatch_queue_agent_id_exports = /* @__PURE__ */ __exportAll({
26189
- down: () => down$5,
26190
- up: () => up$5
26409
+ down: () => down$6,
26410
+ up: () => up$6
26191
26411
  });
26192
26412
  /**
26193
26413
  * Add `dispatch_queue.agent_id` (nullable text).
@@ -26205,7 +26425,7 @@ var _102_dispatch_queue_agent_id_exports = /* @__PURE__ */ __exportAll({
26205
26425
  * Idempotent: guarded on column existence; a re-run on a DB that already has the
26206
26426
  * column is a no-op.
26207
26427
  */
26208
- async function up$5(db) {
26428
+ async function up$6(db) {
26209
26429
  if ((await sql`
26210
26430
  SELECT EXISTS (
26211
26431
  SELECT 1 FROM information_schema.columns
@@ -26216,15 +26436,15 @@ async function up$5(db) {
26216
26436
  `.execute(db)).rows[0]?.exists) return;
26217
26437
  await sql`ALTER TABLE public.dispatch_queue ADD COLUMN agent_id TEXT`.execute(db);
26218
26438
  }
26219
- async function down$5(db) {
26439
+ async function down$6(db) {
26220
26440
  await sql`ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS agent_id`.execute(db);
26221
26441
  }
26222
26442
  var init__102_dispatch_queue_agent_id = __esmMin((() => {}));
26223
26443
  //#endregion
26224
26444
  //#region src/db/migrations/103_cluster_settings_ownership_db_check_timeout_ms.ts
26225
26445
  var _103_cluster_settings_ownership_db_check_timeout_ms_exports = /* @__PURE__ */ __exportAll({
26226
- down: () => down$4,
26227
- up: () => up$4
26446
+ down: () => down$5,
26447
+ up: () => up$5
26228
26448
  });
26229
26449
  /**
26230
26450
  * Add `cluster_settings.ownership_db_check_timeout_ms` (nullable bigint).
@@ -26242,7 +26462,7 @@ var _103_cluster_settings_ownership_db_check_timeout_ms_exports = /* @__PURE__ *
26242
26462
  * Idempotent: guarded on column existence; a re-run on a DB that already has the
26243
26463
  * column is a no-op.
26244
26464
  */
26245
- async function up$4(db) {
26465
+ async function up$5(db) {
26246
26466
  if ((await sql`
26247
26467
  SELECT EXISTS (
26248
26468
  SELECT 1 FROM information_schema.columns
@@ -26253,15 +26473,15 @@ async function up$4(db) {
26253
26473
  `.execute(db)).rows[0]?.exists) return;
26254
26474
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN ownership_db_check_timeout_ms BIGINT`.execute(db);
26255
26475
  }
26256
- async function down$4(db) {
26476
+ async function down$5(db) {
26257
26477
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS ownership_db_check_timeout_ms`.execute(db);
26258
26478
  }
26259
26479
  var init__103_cluster_settings_ownership_db_check_timeout_ms = __esmMin((() => {}));
26260
26480
  //#endregion
26261
26481
  //#region src/db/migrations/104_check_run_terminal_sent.ts
26262
26482
  var _104_check_run_terminal_sent_exports = /* @__PURE__ */ __exportAll({
26263
- down: () => down$3,
26264
- up: () => up$3
26483
+ down: () => down$4,
26484
+ up: () => up$4
26265
26485
  });
26266
26486
  /**
26267
26487
  * Add `check_run_tracking.terminal_sent_at` (nullable timestamptz).
@@ -26281,7 +26501,7 @@ var _104_check_run_terminal_sent_exports = /* @__PURE__ */ __exportAll({
26281
26501
  * Idempotent: guarded on column existence; a re-run on a DB that already has
26282
26502
  * the column is a no-op.
26283
26503
  */
26284
- async function up$3(db) {
26504
+ async function up$4(db) {
26285
26505
  if ((await sql`
26286
26506
  SELECT EXISTS (
26287
26507
  SELECT 1 FROM information_schema.columns
@@ -26292,15 +26512,15 @@ async function up$3(db) {
26292
26512
  `.execute(db)).rows[0]?.exists) return;
26293
26513
  await sql`ALTER TABLE public.check_run_tracking ADD COLUMN terminal_sent_at TIMESTAMPTZ`.execute(db);
26294
26514
  }
26295
- async function down$3(db) {
26515
+ async function down$4(db) {
26296
26516
  await sql`ALTER TABLE public.check_run_tracking DROP COLUMN IF EXISTS terminal_sent_at`.execute(db);
26297
26517
  }
26298
26518
  var init__104_check_run_terminal_sent = __esmMin((() => {}));
26299
26519
  //#endregion
26300
26520
  //#region src/db/migrations/105_org_trust_policy.ts
26301
26521
  var _105_org_trust_policy_exports = /* @__PURE__ */ __exportAll({
26302
- down: () => down$2,
26303
- up: () => up$2
26522
+ down: () => down$3,
26523
+ up: () => up$3
26304
26524
  });
26305
26525
  /**
26306
26526
  * Create `org_trust_policy` — the orchestrator's cache of the Platform-owned org
@@ -26317,7 +26537,7 @@ var _105_org_trust_policy_exports = /* @__PURE__ */ __exportAll({
26317
26537
  *
26318
26538
  * Idempotent: guarded by IF NOT EXISTS, so a re-run is a no-op.
26319
26539
  */
26320
- async function up$2(db) {
26540
+ async function up$3(db) {
26321
26541
  await sql`
26322
26542
  CREATE TABLE IF NOT EXISTS public.org_trust_policy (
26323
26543
  customer_id TEXT PRIMARY KEY,
@@ -26330,15 +26550,15 @@ async function up$2(db) {
26330
26550
  )
26331
26551
  `.execute(db);
26332
26552
  }
26333
- async function down$2(db) {
26553
+ async function down$3(db) {
26334
26554
  await sql`DROP TABLE IF EXISTS public.org_trust_policy`.execute(db);
26335
26555
  }
26336
26556
  var init__105_org_trust_policy = __esmMin((() => {}));
26337
26557
  //#endregion
26338
26558
  //#region src/db/migrations/106_cluster_settings_check_run_tracking_ttl_days.ts
26339
26559
  var _106_cluster_settings_check_run_tracking_ttl_days_exports = /* @__PURE__ */ __exportAll({
26340
- down: () => down$1,
26341
- up: () => up$1
26560
+ down: () => down$2,
26561
+ up: () => up$2
26342
26562
  });
26343
26563
  /**
26344
26564
  * Add `cluster_settings.check_run_tracking_ttl_days` (nullable integer).
@@ -26354,7 +26574,7 @@ var _106_cluster_settings_check_run_tracking_ttl_days_exports = /* @__PURE__ */
26354
26574
  * Idempotent: guarded on column existence; a re-run on a database that already
26355
26575
  * has the column is a no-op.
26356
26576
  */
26357
- async function up$1(db) {
26577
+ async function up$2(db) {
26358
26578
  if ((await sql`
26359
26579
  SELECT EXISTS (
26360
26580
  SELECT 1 FROM information_schema.columns
@@ -26365,15 +26585,15 @@ async function up$1(db) {
26365
26585
  `.execute(db)).rows[0]?.exists) return;
26366
26586
  await sql`ALTER TABLE public.cluster_settings ADD COLUMN check_run_tracking_ttl_days INTEGER`.execute(db);
26367
26587
  }
26368
- async function down$1(db) {
26588
+ async function down$2(db) {
26369
26589
  await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS check_run_tracking_ttl_days`.execute(db);
26370
26590
  }
26371
26591
  var init__106_cluster_settings_check_run_tracking_ttl_days = __esmMin((() => {}));
26372
26592
  //#endregion
26373
26593
  //#region src/db/migrations/107_check_run_tracking_updated_at_index.ts
26374
26594
  var _107_check_run_tracking_updated_at_index_exports = /* @__PURE__ */ __exportAll({
26375
- down: () => down,
26376
- up: () => up
26595
+ down: () => down$1,
26596
+ up: () => up$1
26377
26597
  });
26378
26598
  /**
26379
26599
  * Add `idx_check_run_tracking_updated_at` on `check_run_tracking (updated_at)`.
@@ -26394,17 +26614,63 @@ var _107_check_run_tracking_updated_at_index_exports = /* @__PURE__ */ __exportA
26394
26614
  *
26395
26615
  * Idempotent: `IF NOT EXISTS` makes a re-run a no-op.
26396
26616
  */
26397
- async function up(db) {
26617
+ async function up$1(db) {
26398
26618
  await sql`
26399
26619
  CREATE INDEX IF NOT EXISTS idx_check_run_tracking_updated_at
26400
26620
  ON public.check_run_tracking (updated_at)
26401
26621
  `.execute(db);
26402
26622
  }
26403
- async function down(db) {
26623
+ async function down$1(db) {
26404
26624
  await sql`DROP INDEX IF EXISTS public.idx_check_run_tracking_updated_at`.execute(db);
26405
26625
  }
26406
26626
  var init__107_check_run_tracking_updated_at_index = __esmMin((() => {}));
26407
26627
  //#endregion
26628
+ //#region src/db/migrations/108_unroutable_fast_fail.ts
26629
+ var _108_unroutable_fast_fail_exports = /* @__PURE__ */ __exportAll({
26630
+ down: () => down,
26631
+ up: () => up
26632
+ });
26633
+ /**
26634
+ * Fast-fail support for jobs nothing in the fleet can run.
26635
+ *
26636
+ * Three additive, nullable columns:
26637
+ *
26638
+ * - `cluster_settings.unroutable_grace_ms` — how long a job may stay
26639
+ * continuously unroutable before it is terminalized. NULL means the
26640
+ * orchestrator's configured default applies; 0 disables fast-fail and leaves
26641
+ * the `queue_timeout_ms` backstop as the only path.
26642
+ * - `dispatch_queue.unroutable_since` — when the job first read unroutable.
26643
+ * Persisted rather than in-memory so a restart mid-grace resumes the same
26644
+ * clock instead of resetting it; an orchestrator that bounces every 90s must
26645
+ * not be able to keep a genuinely dead job alive forever. Cleared the moment
26646
+ * the job reads routable again.
26647
+ * - `execution_jobs.routing_reason` — the operator-facing reason, visible while
26648
+ * the job is still queued. Cleared on recovery.
26649
+ *
26650
+ * Idempotent: each column is guarded on existence, so a re-run is a no-op.
26651
+ */
26652
+ async function columnExists(db, table, column) {
26653
+ return (await sql`
26654
+ SELECT EXISTS (
26655
+ SELECT 1 FROM information_schema.columns
26656
+ WHERE table_schema = 'public'
26657
+ AND table_name = ${table}
26658
+ AND column_name = ${column}
26659
+ ) AS exists
26660
+ `.execute(db)).rows[0]?.exists === true;
26661
+ }
26662
+ async function up(db) {
26663
+ if (!await columnExists(db, "cluster_settings", "unroutable_grace_ms")) await sql`ALTER TABLE public.cluster_settings ADD COLUMN unroutable_grace_ms INTEGER`.execute(db);
26664
+ if (!await columnExists(db, "dispatch_queue", "unroutable_since")) await sql`ALTER TABLE public.dispatch_queue ADD COLUMN unroutable_since TIMESTAMPTZ`.execute(db);
26665
+ if (!await columnExists(db, "execution_jobs", "routing_reason")) await sql`ALTER TABLE public.execution_jobs ADD COLUMN routing_reason TEXT`.execute(db);
26666
+ }
26667
+ async function down(db) {
26668
+ await sql`ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS routing_reason`.execute(db);
26669
+ await sql`ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS unroutable_since`.execute(db);
26670
+ await sql`ALTER TABLE public.cluster_settings DROP COLUMN IF EXISTS unroutable_grace_ms`.execute(db);
26671
+ }
26672
+ var init__108_unroutable_fast_fail = __esmMin((() => {}));
26673
+ //#endregion
26408
26674
  //#region src/db/migration-provider.ts
26409
26675
  function createMigrationProvider() {
26410
26676
  return { async getMigrations() {
@@ -26515,7 +26781,8 @@ function createMigrationProvider() {
26515
26781
  "104_check_run_terminal_sent": _104_check_run_terminal_sent_exports,
26516
26782
  "105_org_trust_policy": _105_org_trust_policy_exports,
26517
26783
  "106_cluster_settings_check_run_tracking_ttl_days": _106_cluster_settings_check_run_tracking_ttl_days_exports,
26518
- "107_check_run_tracking_updated_at_index": _107_check_run_tracking_updated_at_index_exports
26784
+ "107_check_run_tracking_updated_at_index": _107_check_run_tracking_updated_at_index_exports,
26785
+ "108_unroutable_fast_fail": _108_unroutable_fast_fail_exports
26519
26786
  };
26520
26787
  } };
26521
26788
  }
@@ -26627,6 +26894,7 @@ var init_migration_provider = __esmMin((() => {
26627
26894
  init__105_org_trust_policy();
26628
26895
  init__106_cluster_settings_check_run_tracking_ttl_days();
26629
26896
  init__107_check_run_tracking_updated_at_index();
26897
+ init__108_unroutable_fast_fail();
26630
26898
  }));
26631
26899
  //#endregion
26632
26900
  //#region src/db/migrator.ts
@@ -27828,7 +28096,8 @@ var init_admin_cluster_settings = __esmMin((() => {
27828
28096
  checkRunTrackingTtlDays: "check_run_tracking_ttl_days",
27829
28097
  concurrencyWaitTimeoutMs: "concurrency_wait_timeout_ms",
27830
28098
  agentTokenTtlMs: "agent_token_ttl_ms",
27831
- ownershipDbCheckTimeoutMs: "ownership_db_check_timeout_ms"
28099
+ ownershipDbCheckTimeoutMs: "ownership_db_check_timeout_ms",
28100
+ unroutableGraceMs: "unroutable_grace_ms"
27832
28101
  };
27833
28102
  STRING_COLUMNS = { dashboardVerifiedIssuer: "dashboard_verified_issuer" };
27834
28103
  updateSchema$1 = z.object({
@@ -27850,6 +28119,8 @@ var init_admin_cluster_settings = __esmMin((() => {
27850
28119
  concurrencyWaitTimeoutMs: z.number().int().min(1e3).nullable().optional(),
27851
28120
  agentTokenTtlMs: z.number().int().min(1e3).nullable().optional(),
27852
28121
  ownershipDbCheckTimeoutMs: z.number().int().min(100).nullable().optional(),
28122
+ /** 0 disables unroutable fast-fail, so the floor is 0, not 1000. */
28123
+ unroutableGraceMs: z.number().int().min(0).nullable().optional(),
27853
28124
  /**
27854
28125
  * Verified-tier origin for browser-sealed dashboard writes. Must be an
27855
28126
  * absolute http(s) origin (the dashboard fetches `<issuer>/.well-known/jwks.json`
@@ -29521,6 +29792,8 @@ function createAdminRoutes(deps) {
29521
29792
  const resolved = await routeScope(scope);
29522
29793
  const scopeError = validateScopeName(resolved.path);
29523
29794
  if (scopeError) return c.json({ error: scopeError }, 400);
29795
+ const keyError = validateSecretKey(key);
29796
+ if (keyError) return c.json({ error: keyError }, 400);
29524
29797
  await resolved.store.setSecret(orgId, resolved.path, key, parsed.value);
29525
29798
  await deps.auditLogger.log({
29526
29799
  action: "setSecret",
@@ -32078,6 +32351,23 @@ function mapRunDetailStep(step) {
32078
32351
  ...step.group_id != null && { groupId: step.group_id }
32079
32352
  };
32080
32353
  }
32354
+ /**
32355
+ * The routing reason as a reader should see it.
32356
+ *
32357
+ * `routing_reason` is only meaningful while the job is still waiting to be
32358
+ * routed, and more than twenty call sites move a job out of `pending`/`queued`
32359
+ * — dispatch, cancel, the run-level failure cascades, the stale detector.
32360
+ * Requiring every one of them to also null the column would be fragile in the
32361
+ * one direction that matters: the site somebody forgets renders a finished job
32362
+ * as "waiting for an agent".
32363
+ *
32364
+ * So the guard lives here, at the read boundary both projections share, where
32365
+ * it cannot be forgotten by a writer that does not know this column exists.
32366
+ * The stale bytes may linger in the row; they are never shown.
32367
+ */
32368
+ function visibleRoutingReason(status, routingReason) {
32369
+ return status === ExecutionJobStatus.enum.pending || status === ExecutionJobStatus.enum.queued ? routingReason ?? null : null;
32370
+ }
32081
32371
  /** Map queried job + step rows into the dashboard run-detail job DTO shape. */
32082
32372
  function buildRunDetailJobs(jobs, lookups) {
32083
32373
  const { stepsByJob, secretKeysByJob, needsByJob } = lookups;
@@ -32098,6 +32388,7 @@ function buildRunDetailJobs(jobs, lookups) {
32098
32388
  agentId: job.agent_id ?? null,
32099
32389
  orchestratorId: null,
32100
32390
  errorMessage: job.error_message ?? null,
32391
+ routingReason: visibleRoutingReason(job.status, job.routing_reason ?? null),
32101
32392
  runsOnLabels: job.runs_on_labels ?? null,
32102
32393
  contexts: job.contexts ? typeof job.contexts === "string" ? JSON.parse(job.contexts) : job.contexts : null,
32103
32394
  skippedContexts: job.skipped_contexts ? typeof job.skipped_contexts === "string" ? JSON.parse(job.skipped_contexts) : job.skipped_contexts : null,
@@ -32671,6 +32962,7 @@ function createAdminRunRoutes(deps) {
32671
32962
  "completed_at",
32672
32963
  "duration_ms",
32673
32964
  "error_message",
32965
+ "routing_reason",
32674
32966
  "runs_on_labels",
32675
32967
  "created_at"
32676
32968
  ]).where("run_id", "=", runId).orderBy("created_at", "asc").execute();
@@ -32724,6 +33016,7 @@ function createAdminRunRoutes(deps) {
32724
33016
  completedAt: job.completed_at?.toISOString() ?? null,
32725
33017
  durationMs: job.duration_ms,
32726
33018
  errorMessage: job.error_message,
33019
+ routingReason: visibleRoutingReason(job.status, job.routing_reason),
32727
33020
  runsOnLabels: safeJsonParse$1(job.runs_on_labels),
32728
33021
  createdAt: job.created_at.toISOString(),
32729
33022
  needs: needsByJob.get(job.job_name) ?? null
@@ -34124,15 +34417,15 @@ var init_admin_config = __esmMin((() => {
34124
34417
  function createHealthRoutes$1(deps = {}) {
34125
34418
  return createHealthRoutes({
34126
34419
  livenessInfo: () => ({
34127
- version: "0.2.0",
34128
- buildDate: "2026-08-08T03:42:24.121Z",
34129
- buildCommit: "15d5e4447",
34130
- sdkVersion: "0.2.0",
34420
+ version: "0.4.0",
34421
+ buildDate: "2026-08-09T15:20:50.779Z",
34422
+ buildCommit: "ffd489464",
34423
+ sdkVersion: "0.4.0",
34131
34424
  sdkBundleHash: "fcd0a836aa1cb92debd93e0254450614d123b3748511aa4148d956fd72a7c29f",
34132
- sharedVersion: "0.2.0",
34425
+ sharedVersion: "0.4.0",
34133
34426
  sharedBundleHash: "f16fa528a8a9ef1bed8df369f0e88efafca8a9954a749005299fdbcdb93fa188",
34134
- engineVersion: "0.2.0",
34135
- engineBundleHash: "c579e54f7d0b0d5b16587a0528a3e66d32f63e2434bb471a93a01366296efd58"
34427
+ engineVersion: "0.4.0",
34428
+ engineBundleHash: "31e2d5c327284e1cac908d7f85cf6d878bbf87ea0da93ed09c6205ada6935f89"
34136
34429
  }),
34137
34430
  readinessCheck: deps.db ? async () => {
34138
34431
  const checks = {};
@@ -34167,7 +34460,7 @@ function createCapabilitiesRoutes() {
34167
34460
  const app = new Hono();
34168
34461
  app.get("/api/v1/capabilities", (c) => {
34169
34462
  const manifest = {
34170
- orchestratorVersion: "0.2.0",
34463
+ orchestratorVersion: "0.4.0",
34171
34464
  protocolVersion: PROTOCOL_VERSION,
34172
34465
  minProtocolVersion: MIN_PROTOCOL_VERSION
34173
34466
  };
@@ -36786,7 +37079,7 @@ var init_app = __esmMin((() => {
36786
37079
  init_log_chunk_sink();
36787
37080
  init_agent_metrics_aggregator();
36788
37081
  logger$57 = createLogger({ prefix: "app" });
36789
- ORCHESTRATOR_VERSION$2 = "0.2.0";
37082
+ ORCHESTRATOR_VERSION$2 = "0.4.0";
36790
37083
  SourceLocationStore = class {
36791
37084
  cache = /* @__PURE__ */ new Map();
36792
37085
  key(workflowName, jobName) {
@@ -43700,7 +43993,8 @@ var init_execution_tracker = __esmMin((() => {
43700
43993
  await this.db.updateTable("execution_jobs").set({
43701
43994
  status: ExecutionJobStatus.enum.failed,
43702
43995
  completed_at: now,
43703
- error_message: failureReason
43996
+ error_message: failureReason,
43997
+ routing_reason: null
43704
43998
  }).where("run_id", "=", runId).where("status", "in", [ExecutionJobStatus.enum.pending, ExecutionJobStatus.enum.queued]).execute();
43705
43999
  await this.jobQueue?.failByRunId(runId);
43706
44000
  const run = this.runs.get(runId);
@@ -43952,7 +44246,8 @@ var init_execution_tracker = __esmMin((() => {
43952
44246
  await this.db.updateTable("execution_jobs").set({
43953
44247
  status: ExecutionJobStatus.enum.failed,
43954
44248
  completed_at: now,
43955
- error_message: reason
44249
+ error_message: reason,
44250
+ routing_reason: null
43956
44251
  }).where("run_id", "=", runId).where("status", "in", [ExecutionJobStatus.enum.pending, ExecutionJobStatus.enum.queued]).execute();
43957
44252
  await this.jobQueue?.failByRunId(runId);
43958
44253
  executionsTotal.add(1, { status: ExecutionRunStatus.enum.failed });
@@ -45976,7 +46271,7 @@ var logger$44, SOFTWARE_VERSION$1, PeerClient$1;
45976
46271
  var init_peer_client = __esmMin((() => {
45977
46272
  init_peer_crypto();
45978
46273
  logger$44 = createLogger({ prefix: "peer-client" });
45979
- SOFTWARE_VERSION$1 = "0.2.0";
46274
+ SOFTWARE_VERSION$1 = "0.4.0";
45980
46275
  PeerClient$1 = class {
45981
46276
  ws = null;
45982
46277
  _state = "disconnected";
@@ -47939,7 +48234,7 @@ var init_peer_handler = __esmMin((() => {
47939
48234
  init_peer_crypto();
47940
48235
  init_join_token();
47941
48236
  logger$42 = createLogger({ prefix: "peer-handler" });
47942
- SOFTWARE_VERSION = "0.2.0";
48237
+ SOFTWARE_VERSION = "0.4.0";
47943
48238
  RATE_LIMIT_MAX = 5;
47944
48239
  RATE_LIMIT_WINDOW_MS = 6e4;
47945
48240
  }));
@@ -55968,6 +56263,7 @@ async function bootstrapOrchestrator$1(config, hooks, options) {
55968
56263
  logger$24.warn("cold-store singleton init skipped", { error: toErrorMessage(err) });
55969
56264
  }
55970
56265
  accessLogWriter.setColdStore(coldStoreSingleton);
56266
+ const canRouteLabels = (labels, patterns, excludeLabels, excludePatterns) => agentRegistry.hasMatchingAgent(labels, patterns, excludeLabels, excludePatterns) || (scalerManager?.hasBackendForLabels(labels, excludeLabels) ?? false);
55971
56267
  const scheduledJobHandles = bootstrapOrchestratorScheduledJobs({
55972
56268
  db,
55973
56269
  instanceId: config.instanceId
@@ -55985,7 +56281,26 @@ async function bootstrapOrchestrator$1(config, hooks, options) {
55985
56281
  clusterSettings,
55986
56282
  logStorage,
55987
56283
  logStorageIsS3: config.storage?.type === "s3",
55988
- canRouteLabels: (labels, patterns, excludeLabels, excludePatterns) => agentRegistry.hasMatchingAgent(labels, patterns, excludeLabels, excludePatterns) || (scalerManager?.hasBackendForLabels(labels, excludeLabels) ?? false)
56284
+ canRouteLabels
56285
+ })
56286
+ },
56287
+ unroutableProbe: {
56288
+ intervalMs: probeTickIntervalMs(config.unroutableGraceMs > 0 ? config.unroutableGraceMs : DEFAULT_UNROUTABLE_GRACE_MS),
56289
+ handler: createUnroutableProbeHandler({
56290
+ queue,
56291
+ getGraceMs: () => clusterSettings.getNumber("unroutable_grace_ms", config.unroutableGraceMs),
56292
+ canRouteLabels,
56293
+ setRoutingReason: makeRoutingReasonWriter(db),
56294
+ terminalize: async (job) => {
56295
+ await terminalizeUnroutableJob({
56296
+ db,
56297
+ executionTracker,
56298
+ checkRunReporter,
56299
+ canRouteLabels
56300
+ }, job);
56301
+ await executionTracker.completeRunIfAllJobsTerminal(job.runId);
56302
+ },
56303
+ onFastFailed: () => unroutableFastFailedTotal.add(1)
55989
56304
  })
55990
56305
  },
55991
56306
  orphanSecretCleanup: {
@@ -56973,6 +57288,9 @@ var init_orchestrator_core = __esmMin((() => {
56973
57288
  init_host_roster_reaper();
56974
57289
  init_job_queue();
56975
57290
  init_cleanup$1();
57291
+ init_terminalize_unroutable();
57292
+ init_unroutable_probe();
57293
+ init_prometheus();
56976
57294
  init_bootstrap();
56977
57295
  init_orchestrator_cold_store();
56978
57296
  init_depth_refresher();
@@ -56985,7 +57303,6 @@ var init_orchestrator_core = __esmMin((() => {
56985
57303
  init_dedup();
56986
57304
  init_observer_registry();
56987
57305
  init_agent_heartbeat();
56988
- init_prometheus();
56989
57306
  init_ingest_admission();
56990
57307
  init_loop_lag_source();
56991
57308
  init_org_ingest_cap_reader();
@@ -64584,6 +64901,12 @@ var init_config = __esmMin((() => {
64584
64901
  queueMaxDepth: z.coerce.number().default(1e3),
64585
64902
  queueTimeoutMs: z.coerce.number().default(36e5),
64586
64903
  /**
64904
+ * Grace a job may stay continuously unroutable (nothing in the fleet matches
64905
+ * its selectors) before it is terminalized. Cluster default; the live value
64906
+ * is the `unroutable_grace_ms` cluster setting. 0 = fast-fail disabled.
64907
+ */
64908
+ unroutableGraceMs: z.coerce.number().default(12e4),
64909
+ /**
64587
64910
  * Operator-facing backpressure warning threshold for the dispatch queue.
64588
64911
  * When pending-queue depth stays at or above this value for at least two
64589
64912
  * consecutive refresher ticks (~10s), the orchestrator emits a
@@ -64861,6 +65184,7 @@ var init_config = __esmMin((() => {
64861
65184
  lockfileCacheMaxBytes: "KICI_LOCKFILE_CACHE_MAX_BYTES",
64862
65185
  queueMaxDepth: "KICI_QUEUE_MAX_DEPTH",
64863
65186
  queueTimeoutMs: "KICI_QUEUE_TIMEOUT_MS",
65187
+ unroutableGraceMs: "KICI_UNROUTABLE_GRACE_MS",
64864
65188
  queueBackpressureThreshold: "KICI_QUEUE_BACKPRESSURE_THRESHOLD",
64865
65189
  workerConcurrency: "KICI_WORKER_CONCURRENCY",
64866
65190
  concurrencyWaitTimeoutMs: "KICI_CONCURRENCY_WAIT_TIMEOUT_MS",
@@ -67237,6 +67561,7 @@ var init_handler = __esmMin((() => {
67237
67561
  "completed_at",
67238
67562
  "duration_ms",
67239
67563
  "error_message",
67564
+ "routing_reason",
67240
67565
  "runs_on_labels",
67241
67566
  "contexts",
67242
67567
  "skipped_contexts",
@@ -69248,6 +69573,7 @@ var init_handler = __esmMin((() => {
69248
69573
  completed_at: coerceToDate(r.completed_at),
69249
69574
  duration_ms: typeof r.duration_ms === "number" ? r.duration_ms : null,
69250
69575
  error_message: typeof r.error_message === "string" ? r.error_message : null,
69576
+ routing_reason: typeof r.routing_reason === "string" ? r.routing_reason : null,
69251
69577
  runs_on_labels: typeof r.runs_on_labels === "string" ? r.runs_on_labels : null,
69252
69578
  contexts: typeof r.contexts === "string" ? r.contexts : null,
69253
69579
  skipped_contexts: typeof r.skipped_contexts === "string" ? r.skipped_contexts : null,
@@ -70248,6 +70574,7 @@ var init_dashboard_context_handler = __esmMin((() => {
70248
70574
  try {
70249
70575
  const { store, scope } = await this.resolveStoreForScope(msg.scope);
70250
70576
  assertValidScopeName(scope);
70577
+ assertValidSecretKey(msg.key);
70251
70578
  await store.setSecret(this.deps.orgId, scope, msg.key, resolved.plaintext);
70252
70579
  this.recordAccess(msg.actor, "secret.set", {
70253
70580
  type: "secret_scope",
@@ -75285,14 +75612,14 @@ var init_worker_core = __esmMin((() => {
75285
75612
  init_peer_outbox();
75286
75613
  init_worker_outbox_relay();
75287
75614
  init_app_on_error();
75288
- ORCHESTRATOR_VERSION$1 = "0.2.0";
75289
- WORKER_BUILD_COMMIT = "15d5e4447";
75290
- WORKER_SDK_VERSION = "0.2.0";
75615
+ ORCHESTRATOR_VERSION$1 = "0.4.0";
75616
+ WORKER_BUILD_COMMIT = "ffd489464";
75617
+ WORKER_SDK_VERSION = "0.4.0";
75291
75618
  WORKER_SDK_BUNDLE_HASH = "fcd0a836aa1cb92debd93e0254450614d123b3748511aa4148d956fd72a7c29f";
75292
- WORKER_SHARED_VERSION = "0.2.0";
75619
+ WORKER_SHARED_VERSION = "0.4.0";
75293
75620
  WORKER_SHARED_BUNDLE_HASH = "f16fa528a8a9ef1bed8df369f0e88efafca8a9954a749005299fdbcdb93fa188";
75294
- WORKER_ENGINE_VERSION = "0.2.0";
75295
- WORKER_ENGINE_BUNDLE_HASH = "c579e54f7d0b0d5b16587a0528a3e66d32f63e2434bb471a93a01366296efd58";
75621
+ WORKER_ENGINE_VERSION = "0.4.0";
75622
+ WORKER_ENGINE_BUNDLE_HASH = "31e2d5c327284e1cac908d7f85cf6d878bbf87ea0da93ed09c6205ada6935f89";
75296
75623
  logger$2 = createLogger({ prefix: "worker" });
75297
75624
  DRAIN_TIMEOUT_MS = 3e5;
75298
75625
  }));
@@ -75316,14 +75643,14 @@ var init_worker_core = __esmMin((() => {
75316
75643
  init_verify_inbound();
75317
75644
  init_ingest_overflow_types();
75318
75645
  init_scope_routing();
75319
- const ORCHESTRATOR_VERSION = "0.2.0";
75320
- const BUILD_COMMIT = "15d5e4447";
75321
- const SDK_VERSION = "0.2.0";
75646
+ const ORCHESTRATOR_VERSION = "0.4.0";
75647
+ const BUILD_COMMIT = "ffd489464";
75648
+ const SDK_VERSION = "0.4.0";
75322
75649
  const SDK_BUNDLE_HASH = "fcd0a836aa1cb92debd93e0254450614d123b3748511aa4148d956fd72a7c29f";
75323
- const SHARED_VERSION = "0.2.0";
75650
+ const SHARED_VERSION = "0.4.0";
75324
75651
  const SHARED_BUNDLE_HASH = "f16fa528a8a9ef1bed8df369f0e88efafca8a9954a749005299fdbcdb93fa188";
75325
- const ENGINE_VERSION = "0.2.0";
75326
- const ENGINE_BUNDLE_HASH = "c579e54f7d0b0d5b16587a0528a3e66d32f63e2434bb471a93a01366296efd58";
75652
+ const ENGINE_VERSION = "0.4.0";
75653
+ const ENGINE_BUNDLE_HASH = "31e2d5c327284e1cac908d7f85cf6d878bbf87ea0da93ed09c6205ada6935f89";
75327
75654
  const otelSdk = initTelemetry({
75328
75655
  serviceName: "kici-orchestrator",
75329
75656
  otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT