@kici-dev/orchestrator 0.1.27 → 0.2.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.
Files changed (270) hide show
  1. package/dist/__test-helpers__/mock-db.d.ts +2 -0
  2. package/dist/agent/dispatcher.d.ts +52 -2
  3. package/dist/agent/host-roster-reaper.d.ts +1 -2
  4. package/dist/agent/host-roster.d.ts +34 -0
  5. package/dist/agent/ownership-refusal.d.ts +12 -0
  6. package/dist/agent/ownership-tracker.d.ts +64 -16
  7. package/dist/agent/token-store.d.ts +13 -0
  8. package/dist/agent-packaging/availability.d.ts +27 -0
  9. package/dist/agent-packaging/build-package.d.ts +16 -0
  10. package/dist/agent-packaging/download.d.ts +30 -0
  11. package/dist/agent-packaging/index.d.ts +9 -0
  12. package/dist/agent-packaging/install-closure.d.ts +30 -0
  13. package/dist/agent-packaging/node-binary.d.ts +26 -0
  14. package/dist/agent-packaging/refresh.d.ts +50 -0
  15. package/dist/agent-packaging/store.d.ts +15 -0
  16. package/dist/agent-packaging/upload.d.ts +24 -0
  17. package/dist/app-on-error.d.ts +29 -0
  18. package/dist/app.d.ts +56 -4
  19. package/dist/artifacts/artifact-store.d.ts +233 -0
  20. package/dist/artifacts/failure-messages.d.ts +46 -0
  21. package/dist/audit/access-log.d.ts +18 -1
  22. package/dist/cache/dep-cache.d.ts +15 -0
  23. package/dist/cache/user-cache.d.ts +37 -0
  24. package/dist/cancel/cancel-run.d.ts +10 -3
  25. package/dist/cancel/dashboard-cancel-handler.d.ts +19 -0
  26. package/dist/cli/api-client.d.ts +22 -1
  27. package/dist/cli/commands/agent-package.d.ts +34 -0
  28. package/dist/cli/commands/check-run.d.ts +26 -0
  29. package/dist/cli/commands/cluster-settings.d.ts +55 -0
  30. package/dist/cli/commands/dashboard-encryption-key.d.ts +3 -0
  31. package/dist/cli/commands/db-backup.d.ts +71 -0
  32. package/dist/cli/commands/orchestrator-service/drain.d.ts +31 -0
  33. package/dist/cli/commands/orchestrator-service/index.d.ts +7 -4
  34. package/dist/cli/commands/orchestrator-service/install-env.d.ts +58 -0
  35. package/dist/cli/commands/secret.d.ts +45 -1
  36. package/dist/cli/commands/shared/admin-cli-access-log.d.ts +46 -0
  37. package/dist/cli/commands/shared/versioned-upgrade.d.ts +65 -2
  38. package/dist/cli/commands/signing-key.d.ts +3 -0
  39. package/dist/cli/commands/source.d.ts +12 -0
  40. package/dist/cli/commands/token.d.ts +9 -0
  41. package/dist/cli/commands/trust-policy.d.ts +48 -0
  42. package/dist/cli/join.d.ts +1 -1
  43. package/dist/cli/service/index.d.ts +2 -2
  44. package/dist/cli/service/instance/manifest.d.ts +17 -0
  45. package/dist/cli/service/instance/resolve.d.ts +11 -0
  46. package/dist/cli/wizard/orchestrator-wizard.d.ts +39 -11
  47. package/dist/cli.js +9818 -3408
  48. package/dist/cluster/cluster-settings-reader.d.ts +78 -0
  49. package/dist/cluster/coordinator.d.ts +81 -9
  50. package/dist/cluster/join-client.d.ts +1 -1
  51. package/dist/cluster/leader-gated-scheduler.d.ts +50 -0
  52. package/dist/cluster/orphan-recovery.d.ts +14 -0
  53. package/dist/cluster/peer-client.d.ts +12 -2
  54. package/dist/cluster/peer-handler.d.ts +15 -4
  55. package/dist/cluster/peer-registry.d.ts +12 -0
  56. package/dist/cluster/verified-issuer-poller.d.ts +11 -0
  57. package/dist/cluster/verified-issuer.d.ts +63 -0
  58. package/dist/cold-store/tables/access-log.d.ts +1 -1
  59. package/dist/cold-store/tables/event-log.d.ts +1 -1
  60. package/dist/cold-store/tables/execution-jobs.d.ts +1 -1
  61. package/dist/cold-store/tables/execution-runs.d.ts +1 -1
  62. package/dist/cold-store/tables/execution-steps.d.ts +1 -1
  63. package/dist/cold-store/tables/secret-audit-log.d.ts +1 -1
  64. package/dist/config/loader.d.ts +1 -1
  65. package/dist/config/resolver.d.ts +2 -1
  66. package/dist/config/schema.d.ts +8 -6
  67. package/dist/config/types.d.ts +3 -2
  68. package/dist/config.d.ts +363 -53
  69. package/dist/contexts/context-store.d.ts +21 -8
  70. package/dist/contexts/glob-specificity.d.ts +30 -0
  71. package/dist/contexts/held-runs.d.ts +51 -19
  72. package/dist/contexts/protection/aggregate.d.ts +2 -2
  73. package/dist/contexts/protection/concurrency-gate.d.ts +0 -3
  74. package/dist/contexts/protection/reviewer-gate.d.ts +0 -3
  75. package/dist/contexts/protection/satisfiability.d.ts +1 -1
  76. package/dist/contexts/protection/trust-gate.d.ts +0 -3
  77. package/dist/contexts/protection/wait-timer-gate.d.ts +0 -3
  78. package/dist/cron/cron-scheduler.d.ts +24 -4
  79. package/dist/cron/cron-store.d.ts +21 -7
  80. package/dist/dashboard/attestation-filters.d.ts +92 -74
  81. package/dist/dashboard/handler.d.ts +35 -1
  82. package/dist/db/migration-test-harness.d.ts +41 -0
  83. package/dist/db/migrations/069_reroute_tunables.d.ts +21 -0
  84. package/dist/db/migrations/070_execution_runs_failure_class.d.ts +4 -0
  85. package/dist/db/migrations/071_batch_accumulation.d.ts +26 -0
  86. package/dist/db/migrations/072_dispatch_queue_run_id_index.d.ts +15 -0
  87. package/dist/db/migrations/073_org_settings_ingest_concurrency.d.ts +13 -0
  88. package/dist/db/migrations/074_normalize_zero_concurrency_limit.d.ts +13 -0
  89. package/dist/db/migrations/075_ingest_overflow_buffer.d.ts +16 -0
  90. package/dist/db/migrations/076_artifacts.d.ts +19 -0
  91. package/dist/db/migrations/077_backup_runs.d.ts +13 -0
  92. package/dist/db/migrations/078_org_settings_backup_staleness.d.ts +12 -0
  93. package/dist/db/migrations/079_org_settings_scaler_spawn_timeout.d.ts +14 -0
  94. package/dist/db/migrations/080_cluster_settings.d.ts +17 -0
  95. package/dist/db/migrations/081_org_settings_queue_timeout.d.ts +19 -0
  96. package/dist/db/migrations/082_host_s3_reachable.d.ts +16 -0
  97. package/dist/db/migrations/083_org_settings_artifact_caps.d.ts +18 -0
  98. package/dist/db/migrations/084_orchestrator_signing_keys.d.ts +20 -0
  99. package/dist/db/migrations/085_cluster_settings_reroute_flap_grace_ms.d.ts +12 -0
  100. package/dist/db/migrations/086_cluster_settings_max_fanout_hosts.d.ts +12 -0
  101. package/dist/db/migrations/087_cluster_settings_event_router_rate_limit.d.ts +12 -0
  102. package/dist/db/migrations/088_cluster_settings_cache_max_tarball_bytes.d.ts +12 -0
  103. package/dist/db/migrations/089_cluster_settings_cache_ttl_days.d.ts +12 -0
  104. package/dist/db/migrations/090_cluster_settings_concurrency_wait_timeout_ms.d.ts +12 -0
  105. package/dist/db/migrations/091_cluster_settings_agent_token_ttl_ms.d.ts +12 -0
  106. package/dist/db/migrations/092_cluster_settings_version.d.ts +16 -0
  107. package/dist/db/migrations/093_org_settings_sandbox_allowlist.d.ts +4 -0
  108. package/dist/db/migrations/094_dashboard_encryption_keys.d.ts +21 -0
  109. package/dist/db/migrations/095_dashboard_write_policy_tristate.d.ts +20 -0
  110. package/dist/db/migrations/096_multi_schedule_cron_last_fired.d.ts +4 -0
  111. package/dist/db/migrations/097_execution_runs_pr_number.d.ts +4 -0
  112. package/dist/db/migrations/098_execution_runs_customer_id.d.ts +4 -0
  113. package/dist/db/migrations/099_cluster_settings_dashboard_verified_issuer.d.ts +21 -0
  114. package/dist/db/migrations/100_held_runs_hold_type_vocabulary.d.ts +31 -0
  115. package/dist/db/migrations/101_contexts_hold_expiry_drop_default.d.ts +31 -0
  116. package/dist/db/migrations/102_dispatch_queue_agent_id.d.ts +20 -0
  117. package/dist/db/migrations/103_cluster_settings_ownership_db_check_timeout_ms.d.ts +20 -0
  118. package/dist/db/migrations/104_check_run_terminal_sent.d.ts +22 -0
  119. package/dist/db/migrations/105_org_trust_policy.d.ts +19 -0
  120. package/dist/db/migrations/106_cluster_settings_check_run_tracking_ttl_days.d.ts +18 -0
  121. package/dist/db/migrations/107_check_run_tracking_updated_at_index.d.ts +23 -0
  122. package/dist/db/repos/dashboard-encryption-keys-repo.d.ts +48 -0
  123. package/dist/db/repos/signing-keys-repo.d.ts +34 -0
  124. package/dist/db/types.d.ts +421 -7
  125. package/dist/deployment/deployment-identity.d.ts +87 -2
  126. package/dist/diagnostics/checks/backup.d.ts +18 -0
  127. package/dist/diagnostics/checks/index.d.ts +2 -1
  128. package/dist/diagnostics/fleet-collector.d.ts +1 -1
  129. package/dist/drain/drain-controller.d.ts +52 -0
  130. package/dist/events/batch-accumulator.d.ts +63 -0
  131. package/dist/events/circuit-breaker.d.ts +9 -3
  132. package/dist/events/event-emitter.d.ts +31 -0
  133. package/dist/events/event-retry-scanner.d.ts +12 -2
  134. package/dist/events/event-router.d.ts +29 -0
  135. package/dist/firecracker/host-network.d.ts +2 -0
  136. package/dist/firecracker/net-interfaces.d.ts +14 -0
  137. package/dist/github-app-name-refresher/github-app-name-refresher.d.ts +18 -8
  138. package/dist/index.d.ts +2 -0
  139. package/dist/index.js +604 -16
  140. package/dist/lockfile-cache.d.ts +4 -0
  141. package/dist/lockfile-validate.d.ts +16 -9
  142. package/dist/metrics/prometheus.d.ts +112 -15
  143. package/dist/oidc/aws-kms-signer.d.ts +37 -0
  144. package/dist/oidc/command-signer.d.ts +23 -0
  145. package/dist/oidc/db-signer.d.ts +48 -0
  146. package/dist/oidc/id-token-claims.d.ts +22 -9
  147. package/dist/oidc/jwt.d.ts +5 -2
  148. package/dist/oidc/local-dev-signer.d.ts +1 -1
  149. package/dist/oidc/oidc-mint-registration.d.ts +27 -11
  150. package/dist/oidc/orchestrator-mint.d.ts +97 -0
  151. package/dist/oidc/orchestrator-signer-factory.d.ts +33 -0
  152. package/dist/oidc/reconcile-signing-key.d.ts +21 -0
  153. package/dist/oidc/signer.d.ts +25 -0
  154. package/dist/oidc/signing-key-status.d.ts +23 -0
  155. package/dist/orchestrator-core.d.ts +42 -2
  156. package/dist/pipeline/decorating-secret-resolver.d.ts +3 -2
  157. package/dist/pipeline/dispatch-matched-workflow.d.ts +41 -0
  158. package/dist/pipeline/install-secrets-resolver.d.ts +12 -1
  159. package/dist/pipeline/manual-schedule.d.ts +20 -13
  160. package/dist/pipeline/pending-workflow-context.d.ts +1 -1
  161. package/dist/pipeline/process-webhook.d.ts +57 -2
  162. package/dist/pipeline/processor.d.ts +44 -8
  163. package/dist/pipeline/rerun.d.ts +12 -13
  164. package/dist/pipeline/resolve-sandbox-grant.d.ts +28 -0
  165. package/dist/pipeline/route-or-dispatch-jobs.d.ts +71 -0
  166. package/dist/pipeline/sandbox-allowlist-reader.d.ts +33 -0
  167. package/dist/policy/dashboard-write-policy.d.ts +9 -4
  168. package/dist/provenance/backfill-run.d.ts +1 -0
  169. package/dist/provenance/trust-root.d.ts +13 -0
  170. package/dist/providers/generic/normalizer.d.ts +1 -1
  171. package/dist/providers/github/auth.d.ts +1 -1
  172. package/dist/providers/github/changed-files.d.ts +14 -6
  173. package/dist/providers/github/check-status-poster.d.ts +19 -3
  174. package/dist/providers/github/contributor-resolver.d.ts +1 -1
  175. package/dist/providers/github/lock-file.d.ts +1 -1
  176. package/dist/providers/github/normalizer.d.ts +1 -1
  177. package/dist/providers/github/repo-url.d.ts +1 -1
  178. package/dist/providers/local/lock-file-fetcher.d.ts +1 -1
  179. package/dist/providers/local/normalizer.d.ts +1 -1
  180. package/dist/providers/local/repo-url-builder.d.ts +1 -1
  181. package/dist/providers/universal-git/changed-files.d.ts +8 -7
  182. package/dist/providers/universal-git/clone-token.d.ts +1 -1
  183. package/dist/providers/universal-git/config.d.ts +4 -4
  184. package/dist/providers/universal-git/index.d.ts +5 -1
  185. package/dist/providers/universal-git/lock-file.d.ts +6 -1
  186. package/dist/providers/universal-git/normalizer.d.ts +1 -1
  187. package/dist/providers/universal-git/repo-url.d.ts +1 -1
  188. package/dist/queue/cleanup.d.ts +69 -8
  189. package/dist/queue/job-queue.d.ts +94 -14
  190. package/dist/queue/scheduled-job.d.ts +2 -2
  191. package/dist/registration/registration-index.d.ts +1 -1
  192. package/dist/reporting/agent-failure-category.d.ts +4 -1
  193. package/dist/reporting/check-run-reporter.d.ts +34 -14
  194. package/dist/reporting/check-run-tracking-store.d.ts +70 -8
  195. package/dist/reporting/execution-tracker.d.ts +156 -10
  196. package/dist/reporting/fs-log-storage.d.ts +31 -2
  197. package/dist/reporting/job-check-run-completion.d.ts +50 -0
  198. package/dist/reporting/log-chunk-sink.d.ts +47 -0
  199. package/dist/reporting/log-retention.d.ts +16 -0
  200. package/dist/reporting/log-storage.d.ts +64 -4
  201. package/dist/reporting/log-writer.d.ts +22 -7
  202. package/dist/reporting/peer-log-normalize.d.ts +14 -0
  203. package/dist/reporting/run-aggregator.d.ts +32 -32
  204. package/dist/reporting/s3-log-storage.d.ts +102 -8
  205. package/dist/routes/admin-auth.d.ts +90 -0
  206. package/dist/routes/admin-cluster-settings.d.ts +31 -0
  207. package/dist/routes/admin-events.d.ts +3 -0
  208. package/dist/routes/admin-orchestrator-drain.d.ts +35 -0
  209. package/dist/routes/admin-runs.d.ts +9 -0
  210. package/dist/routes/admin-sources.d.ts +7 -0
  211. package/dist/routes/admin-trust-policy.d.ts +49 -0
  212. package/dist/routes/admin.d.ts +15 -1
  213. package/dist/routes/github-webhook.d.ts +9 -3
  214. package/dist/routes/provenance-oidc.d.ts +38 -0
  215. package/dist/routes/verify-attestation.d.ts +21 -0
  216. package/dist/scaler/bare-metal-backend.d.ts +9 -2
  217. package/dist/scaler/config.d.ts +25 -4
  218. package/dist/scaler/container-backend.d.ts +9 -1
  219. package/dist/scaler/firecracker-backend.d.ts +29 -2
  220. package/dist/scaler/index.d.ts +1 -1
  221. package/dist/scaler/manager.d.ts +166 -8
  222. package/dist/scaler/pending-scale-sweeper.d.ts +35 -0
  223. package/dist/scaler/types.d.ts +75 -6
  224. package/dist/secrets/backend-registry.d.ts +32 -1
  225. package/dist/secrets/dashboard-encryption-key.d.ts +48 -0
  226. package/dist/secrets/ephemeral-keys.d.ts +16 -0
  227. package/dist/secrets/pg-secret-store.d.ts +10 -0
  228. package/dist/secrets/rbac.d.ts +5 -1
  229. package/dist/secrets/routing-key-scope.d.ts +6 -0
  230. package/dist/secrets/scope-routing.d.ts +126 -0
  231. package/dist/secrets/secret-resolver.d.ts +1 -14
  232. package/dist/secrets/token-manager.d.ts +5 -1
  233. package/dist/security/contributor-cache.d.ts +9 -1
  234. package/dist/security/trust-policy-gate.d.ts +117 -0
  235. package/dist/security/trust-policy-store.d.ts +78 -0
  236. package/dist/server.js +35769 -25052
  237. package/dist/sources/source-manager.d.ts +24 -0
  238. package/dist/stale-detector/stale-run-detector.d.ts +7 -0
  239. package/dist/standalone.js +34831 -25317
  240. package/dist/storage/filesystem.d.ts +17 -0
  241. package/dist/storage/key-discriminator.d.ts +20 -0
  242. package/dist/storage/s3.d.ts +2 -0
  243. package/dist/storage/types.d.ts +16 -0
  244. package/dist/webhook/dedup.d.ts +9 -1
  245. package/dist/webhook/event-log.d.ts +13 -2
  246. package/dist/webhook/generic-sources-listener.d.ts +4 -0
  247. package/dist/webhook/ingest-admission.d.ts +140 -0
  248. package/dist/webhook/ingest-overflow-buffer.d.ts +27 -0
  249. package/dist/webhook/ingest-overflow-replayer.d.ts +49 -0
  250. package/dist/webhook/ingest-overflow-types.d.ts +73 -0
  251. package/dist/webhook/loop-lag-source.d.ts +40 -0
  252. package/dist/webhook/observed-relay-guard.d.ts +40 -0
  253. package/dist/webhook/org-ingest-cap-reader.d.ts +24 -0
  254. package/dist/webhook/register-source-bundle.d.ts +3 -0
  255. package/dist/webhook/relay-reinject.d.ts +43 -0
  256. package/dist/worker/in-memory-job-queue.d.ts +8 -3
  257. package/dist/worker-core.d.ts +10 -0
  258. package/dist/ws/agent-api-registry.d.ts +20 -0
  259. package/dist/ws/agent-handler.d.ts +63 -7
  260. package/dist/ws/bringup-api.d.ts +99 -0
  261. package/dist/ws/dashboard-context-handler.d.ts +28 -10
  262. package/dist/ws/dashboard-run-state-handler.d.ts +31 -0
  263. package/dist/ws/failure-messages.d.ts +29 -0
  264. package/dist/ws/oidc-token-relay.d.ts +9 -0
  265. package/dist/ws/ownership-gate.d.ts +22 -0
  266. package/dist/ws/platform-client.d.ts +96 -1
  267. package/dist/ws/replay-chunker.d.ts +37 -0
  268. package/installer-image-digests.json +3 -3
  269. package/package.json +22 -21
  270. package/sbom.spdx.json +1240 -1788
@@ -1,6 +1,7 @@
1
1
  import { type Kysely } from 'kysely';
2
2
  import { type LabelMatcher, type ResourceRequest } from '@kici-dev/engine';
3
3
  import type { Database } from '../db/types.js';
4
+ import type { ClusterSettingsReader } from '../cluster/cluster-settings-reader.js';
4
5
  /** Info about an expired dispatch_queue entry, returned by markExpired(). */
5
6
  export interface ExpiredJobInfo {
6
7
  /** dispatch_queue row ID */
@@ -9,6 +10,16 @@ export interface ExpiredJobInfo {
9
10
  jobName: string;
10
11
  /** Most recent scaler spawn-failure detail, if any was recorded. */
11
12
  lastProvisioningError: string | null;
13
+ /**
14
+ * The job's routing selectors, carried so the expiry sweep can ask whether
15
+ * any agent could ever have run it. A job that expires with NO matching agent
16
+ * is `unroutable` (a fleet/label problem); one whose agent existed but never
17
+ * freed up is `timed_out_stale` (a capacity problem).
18
+ */
19
+ runsOnLabels: string[];
20
+ runsOnPatterns: LabelMatcher[];
21
+ excludeLabels: string[];
22
+ excludePatterns: LabelMatcher[];
12
23
  }
13
24
  /**
14
25
  * Point-in-time breakdown of dispatch_queue depth used for Prometheus gauges
@@ -167,8 +178,12 @@ export interface QueuedJob {
167
178
  */
168
179
  export declare class JobQueue {
169
180
  private readonly db;
170
- private readonly maxDepth;
181
+ /** Cluster-wide fallback for queue_max_depth when cluster_settings is null. */
182
+ private readonly defaultMaxDepth;
171
183
  private readonly defaultTimeoutMs;
184
+ private readonly clusterSettings?;
185
+ /** Per-job (per-org) queue-timeout resolver; falls back to defaultTimeoutMs. */
186
+ private readonly getQueueTimeoutMs?;
172
187
  /** 1-second TTL cache for pending depth count to avoid extra SELECT COUNT per enqueue. */
173
188
  private depthCache;
174
189
  /**
@@ -181,9 +196,16 @@ export declare class JobQueue {
181
196
  constructor(db: Kysely<Database>, options: {
182
197
  maxDepth: number;
183
198
  defaultTimeoutMs: number;
199
+ clusterSettings?: ClusterSettingsReader;
200
+ getQueueTimeoutMs?: (job: {
201
+ jobConfig?: Record<string, unknown>;
202
+ }) => Promise<number>;
184
203
  });
185
204
  /**
186
- * Enqueue a job. Checks depth first, rejects with 'queue full' if >= maxDepth.
205
+ * Enqueue a job. Checks depth first, rejects with 'queue full' if >= the
206
+ * fleet-wide `queue_max_depth` (cluster_settings, falling back to the config
207
+ * default). The per-job timeout resolves through the per-org
208
+ * `queue_timeout_ms` override.
187
209
  * @returns The generated job ID.
188
210
  */
189
211
  enqueue(job: QueuedJobInput): Promise<string>;
@@ -269,17 +291,38 @@ export declare class JobQueue {
269
291
  /**
270
292
  * Insert a job directly with status='dispatched' (bypasses the queue).
271
293
  * Used when an agent is immediately available and the job doesn't need to wait.
272
- * @returns The generated job ID.
294
+ *
295
+ * `agentId` is the durable owner, written here for the same reason
296
+ * {@link markDispatched} writes it on the queue-drain path: this row is
297
+ * dispatched the moment it is inserted, so it never passes through
298
+ * `markDispatched` and would otherwise carry a NULL owner for its whole life.
299
+ * A coordinator that never saw the dispatch resolves ownership from this
300
+ * column alone, so omitting it here would make {@link hasAgentOwnedJob} answer
301
+ * "not owned" for every directly-dispatched job after a failover.
302
+ *
303
+ * Idempotent on the primary key: a reroute re-dispatch reuses a preassigned
304
+ * jobId, so a concurrent reroute from a sibling coordinator (or a duplicate
305
+ * delivery) may target a row this instance already wrote. ON CONFLICT (id) DO
306
+ * NOTHING makes that a no-op instead of a dispatch_queue_pkey error; the
307
+ * returned `inserted` flag tells the caller whether a fresh row was created so
308
+ * it can avoid double-dispatching an already-present job. The conflicting row
309
+ * keeps the owner the winning writer recorded.
310
+ *
311
+ * @returns The job ID and whether a new row was inserted (false = row already existed).
273
312
  */
274
- insertDispatched(job: QueuedJobInput): Promise<string>;
313
+ insertDispatched(job: QueuedJobInput, agentId: string): Promise<{
314
+ id: string;
315
+ inserted: boolean;
316
+ }>;
275
317
  /**
276
- * Mark a job as dispatched.
318
+ * Mark a job as dispatched and record the agent it went to.
277
319
  *
278
- * Note: agentId is not persisted in the dispatch_queue table.
279
- * The dispatcher tracks agent-to-job mappings in memory (agentJobs Map).
280
- * The dispatch_queue is a transient routing table, not the execution record.
320
+ * `agent_id` is the durable owner: the dispatcher also tracks agent-to-job
321
+ * mappings in memory (agentJobs Map), but that map is per-coordinator, so a
322
+ * coordinator that never saw the dispatch has to read the owner back from the
323
+ * row to answer an ownership question.
281
324
  */
282
- markDispatched(jobId: string, _agentId: string): Promise<void>;
325
+ markDispatched(jobId: string, agentId: string): Promise<void>;
283
326
  /**
284
327
  * Mark a job as failed.
285
328
  *
@@ -329,6 +372,23 @@ export declare class JobQueue {
329
372
  * @returns Number of affected rows.
330
373
  */
331
374
  cancelByRunId(runId: string): Promise<number>;
375
+ /**
376
+ * Delete terminal dispatch_queue rows older than `retentionDays`.
377
+ *
378
+ * `dispatch_queue` is operational dispatch state; the durable run history
379
+ * lives in the cold-stored execution_runs/jobs/steps tables, so a terminal
380
+ * ({@link DispatchQueueStatus.Completed}/{@link DispatchQueueStatus.Failed}/
381
+ * {@link DispatchQueueStatus.Expired}) row has no archival value once it ages
382
+ * out. Non-terminal rows ({@link DispatchQueueStatus.Pending}/
383
+ * {@link DispatchQueueStatus.Dispatched}/{@link DispatchQueueStatus.Recovering})
384
+ * are never pruned — a still-active run keeps every one of its rows. Both the
385
+ * terminal-status filter and the age cutoff must hold for a row to be deleted.
386
+ *
387
+ * `retentionDays <= 0` disables pruning (returns 0 without a query).
388
+ *
389
+ * @returns Number of rows deleted.
390
+ */
391
+ pruneTerminalDispatchRows(retentionDays: number): Promise<number>;
332
392
  /**
333
393
  * Get the current number of pending jobs.
334
394
  * Uses a 1-second TTL cache to avoid extra SELECT COUNT per enqueue.
@@ -455,11 +515,12 @@ export declare class JobQueue {
455
515
  */
456
516
  getFullJobById(jobId: string): Promise<QueuedJob | null>;
457
517
  /**
458
- * Mark a job as dispatched only if it is still in 'recovering' state.
518
+ * Mark a job as dispatched only if it is still in 'recovering' state, and
519
+ * record `agentId` as the durable owner of the reclaimed job.
459
520
  * Used when an agent reconnects and claims a recovering job.
460
521
  * @returns true if the update affected a row (job was still recovering).
461
522
  */
462
- markDispatchedIfRecovering(jobId: string): Promise<boolean>;
523
+ markDispatchedIfRecovering(jobId: string, agentId: string): Promise<boolean>;
463
524
  /**
464
525
  * Get a single job by ID.
465
526
  * Used to look up runId during recovery timer setup.
@@ -471,10 +532,11 @@ export declare class JobQueue {
471
532
  } | null>;
472
533
  /**
473
534
  * HA-safe ownership check. Returns true if the DB shows that
474
- * `agentId` previously held `jobId` according to any of:
535
+ * `agentId` holds or previously held `jobId` according to any of:
475
536
  *
476
- * - `status='dispatched'` AND the registry-managed bookkeeping
477
- * records the agent assignment (caller-side `agentJobs` map),
537
+ * - `status='dispatched'` AND `agent_id = <agent>` — the live
538
+ * owner of an in-flight job, readable by any coordinator
539
+ * including one that never saw the dispatch,
478
540
  * - `status='recovering'` AND `recovery_agent_id = <agent>` (so a
479
541
  * replacement coord still recognises in-flight chunks), OR
480
542
  * - the row is already terminal (`completed` / `failed` /
@@ -495,11 +557,29 @@ export declare class JobQueue {
495
557
  id: string;
496
558
  runId: string;
497
559
  status: DispatchQueueStatus;
560
+ agentId: string | null;
498
561
  }>>;
562
+ /**
563
+ * Shared builder for the non-expired pending rows, oldest-first
564
+ * (`created_at ASC` — the same FIFO ordering as `dequeueForLabels` /
565
+ * `markExpired`). Read-only: no `FOR UPDATE`, no claim. Used by both the
566
+ * unbounded `getPendingJobs` drain and the capped `listPending` re-drive.
567
+ */
568
+ private pendingOldestFirstQuery;
499
569
  /**
500
570
  * Get all pending jobs in FIFO order (for queue drain on agent connect).
501
571
  */
502
572
  getPendingJobs(): Promise<QueuedJob[]>;
573
+ /**
574
+ * Read-only oldest-first listing of pending jobs, capped at `limit`.
575
+ *
576
+ * Powers the scaler capacity-freed re-drive (`Dispatcher.retryPendingScaleRequests`):
577
+ * when a scaler agent frees capacity, the oldest jobs that previously got an
578
+ * `at-capacity` verdict are the ones re-offered to `requestScale`. Unlike
579
+ * `dequeueForLabels`, this neither claims nor locks rows — it is a pure read;
580
+ * the re-drive re-runs the normal scale path, which reserves capacity itself.
581
+ */
582
+ listPending(limit: number): Promise<QueuedJob[]>;
503
583
  /**
504
584
  * Convert a DB row to a QueuedJob object.
505
585
  * Handles both auto-parsed JSONB arrays (from pg driver) and JSON strings (from tests).
@@ -25,10 +25,10 @@ import type { Database } from '../db/types.js';
25
25
  */
26
26
  export declare const OrchestratorScheduledJobName: z.ZodEnum<{
27
27
  cleanup: "cleanup";
28
- "orphan-secret-cleanup": "orphan-secret-cleanup";
29
- "token-cleanup": "token-cleanup";
30
28
  "cold-store-archive": "cold-store-archive";
31
29
  "cold-store-purge": "cold-store-purge";
30
+ "orphan-secret-cleanup": "orphan-secret-cleanup";
31
+ "token-cleanup": "token-cleanup";
32
32
  }>;
33
33
  export type OrchestratorScheduledJobName = z.infer<typeof OrchestratorScheduledJobName>;
34
34
  /** Access-log action for a manually triggered off-cadence tick. */
@@ -151,7 +151,7 @@ export declare class RegistrationIndex {
151
151
  *
152
152
  * Event type -> trigger type mapping:
153
153
  * - 'kici_event' -> 'kici_event'
154
- * - 'workflow_complete' -> 'workflow_complete' or 'lifecycle'
154
+ * - 'workflow_complete' -> 'workflow_complete', 'lifecycle', or 'workflows_failed_batch'
155
155
  * - 'job_complete' -> 'job_complete' or 'lifecycle'
156
156
  * - 'generic_webhook' -> 'generic_webhook'
157
157
  * - 'schedule' -> 'schedule'
@@ -13,7 +13,10 @@ export interface FailureSignals {
13
13
  hasInitFailure: boolean;
14
14
  /** The init-failure category (`InitFailureCategory`), if any. */
15
15
  initFailureCategory: string | null;
16
- /** Any job ended in `timed_out_stale` (or a workflow/job timeout fired). */
16
+ /**
17
+ * Any job ended in an infra-class verdict that means it never really ran —
18
+ * `timed_out_stale` or `unroutable` — or a workflow/job timeout fired.
19
+ */
17
20
  timedOut: boolean;
18
21
  /** Any step recorded a non-zero exit code. */
19
22
  anyStepNonZeroExit: boolean;
@@ -30,7 +30,7 @@ import type { ProviderRegistry } from '../provider-registry.js';
30
30
  import type { StepLogBuffer } from './step-log-buffer.js';
31
31
  import { type SourceLocationData } from './check-run-summary.js';
32
32
  import type { CheckRunTrackingStore } from './check-run-tracking-store.js';
33
- import { ExecutionJobStatus } from '@kici-dev/engine';
33
+ import { type TerminalJobStatus } from '@kici-dev/engine';
34
34
  /**
35
35
  * Dependencies for the CheckRunReporter.
36
36
  */
@@ -122,7 +122,7 @@ interface SetBuildCompleteOptions {
122
122
  repo: string;
123
123
  sha: string;
124
124
  workflowName: string;
125
- status: Extract<ExecutionJobStatus, 'success' | 'failed' | 'cancelled' | 'timed_out_stale'>;
125
+ status: TerminalJobStatus;
126
126
  installationId?: number;
127
127
  /** Routing key for per-app credential lookup (e.g., "github:12345"). */
128
128
  routingKey?: string;
@@ -142,7 +142,7 @@ interface UpdateJobStatusOptions {
142
142
  sha: string;
143
143
  workflowName: string;
144
144
  jobName: string;
145
- state: Extract<ExecutionJobStatus, 'success' | 'failed' | 'cancelled' | 'timed_out_stale'>;
145
+ state: TerminalJobStatus;
146
146
  installationId?: number;
147
147
  /** Routing key for per-app credential lookup (e.g., "github:12345"). */
148
148
  routingKey?: string;
@@ -167,7 +167,7 @@ interface UpdateWorkflowStatusOptions {
167
167
  repo: string;
168
168
  sha: string;
169
169
  workflowName: string;
170
- overallStatus: Extract<ExecutionJobStatus, 'success' | 'failed' | 'cancelled' | 'timed_out_stale'>;
170
+ overallStatus: TerminalJobStatus;
171
171
  installationId?: number;
172
172
  /** Routing key for per-app credential lookup (e.g., "github:12345"). */
173
173
  routingKey?: string;
@@ -238,6 +238,19 @@ export declare class CheckRunReporter {
238
238
  private readonly progressTimers;
239
239
  /** L1 cache: first in-progress sent flag (synced to `check_run_tracking.in_progress_sent_at`). */
240
240
  private readonly inProgressSent;
241
+ /**
242
+ * Keys whose job check run has already been completed.
243
+ *
244
+ * Makes the check run's status monotonic: once a `completed` update is
245
+ * issued, no later step-progress update may push it back to `in_progress`.
246
+ * Cancelling the pending debounce timer at completion time is not sufficient
247
+ * on its own — a step status that arrives after the completion schedules a
248
+ * FRESH timer, which then fires and leaves the check run showing
249
+ * `status: in_progress` with a terminal `conclusion` already attached. That
250
+ * is the permanently-unresolved state check-run completion exists to prevent,
251
+ * so the guard is on the write itself rather than on the timer.
252
+ */
253
+ private readonly terminalSent;
241
254
  /**
242
255
  * L1 cache: runId → set of check-run composite keys. Synced to the
243
256
  * indexed `check_run_tracking.run_id` column so a replacement coord can
@@ -334,21 +347,28 @@ export declare class CheckRunReporter {
334
347
  */
335
348
  setBuildComplete(opts: SetBuildCompleteOptions): void;
336
349
  /**
337
- * Clean up step-progress entries, debounce timers, and DB rows for a
338
- * completed run. Called when the execution tracker prunes the run.
350
+ * Clean up step-progress entries and debounce timers for a completed run.
351
+ * Called when the execution tracker prunes the run.
339
352
  *
340
- * In-memory cleanup is synchronous; the DB cleanup is fire-and-forget
341
- * because the caller (run-pruning hook) is on the response-shaping path
342
- * and shouldn't block on a network round-trip. Failure logs but does
343
- * not propagate.
353
+ * In-memory only. Database rows are owned by the retention sweep in
354
+ * `queue/cleanup.ts`, which deletes on inactivity age rather than on run
355
+ * completion. Deleting here would strand a late terminal update: a check-run
356
+ * status PATCH that arrives after the prune resolves its check-run ID by
357
+ * loading through to this row, and a deleted row makes that lookup fail.
344
358
  */
345
359
  cleanupRun(runId: string): void;
346
360
  /**
347
- * Hydrate the L1 caches from the DB after a leader switch (or any
348
- * boot-time recovery). Called once on coord become-leader so the
349
- * runIdToKeys reverse map is populated for any future cleanupRun calls
350
- * without requiring a DB round-trip per cleanup. If no store is wired,
361
+ * Mark the reporter as DB-backed after a leader switch (or any boot-time
362
+ * recovery). Called once on coord become-leader. If no store is wired,
351
363
  * this is a no-op.
364
+ *
365
+ * Nothing is hydrated up front — the table can be large across many shas —
366
+ * so check-run IDs load through on demand inside `resolveCheckRunId`. The
367
+ * `runIdToKeys` reverse map is rebuilt only from this coord's own writes,
368
+ * so a run whose keys all predate the switch leaves `cleanupRun` nothing to
369
+ * evict. That is harmless: the L1 caches it clears are equally empty on a
370
+ * fresh coord, and the DB rows belong to the retention sweep rather than to
371
+ * run prune.
352
372
  */
353
373
  recoverState(): Promise<void>;
354
374
  /** Track a check run key associated with a runId for later cleanup. */
@@ -29,7 +29,16 @@ export interface CheckRunTrackingState {
29
29
  stepProgress: StepProgressEntry[];
30
30
  /** Timestamp the first running-step transition was sent to GitHub. */
31
31
  inProgressSentAt?: Date;
32
- /** KiCI run this check-run belongs to. Used by `cleanupRun`. */
32
+ /**
33
+ * Timestamp the terminal (`completed`) update was accepted by the provider.
34
+ * Undefined means we have no record of sending it — not proof it failed.
35
+ */
36
+ terminalSentAt?: Date;
37
+ /**
38
+ * KiCI run this check-run belongs to. Written at create time so the row
39
+ * records its owning run; it is an attribution/lookup key, not a retention
40
+ * key — the sweep prunes on `updated_at` age alone.
41
+ */
33
42
  runId?: string;
34
43
  /** Last persisted update time; powers debounce-after-failover recovery. */
35
44
  updatedAt?: Date;
@@ -64,8 +73,13 @@ export declare class CheckRunTrackingStore {
64
73
  * Performed as an upsert so a re-issued setPending after a coord
65
74
  * failover replaces the prior ID rather than silently leaving a row
66
75
  * mismatched with the GitHub-side state.
76
+ *
77
+ * `runId` is written alongside so the row records which run owns it from
78
+ * the moment it is created. A row created without it carries a NULL
79
+ * `run_id`, which makes `listKeysByRunId` under-report and leaves the
80
+ * column useless to an operator asking which run posted a given check.
67
81
  */
68
- setCheckRunId(key: CheckRunTrackingKey, checkRunId: number): Promise<void>;
82
+ setCheckRunId(key: CheckRunTrackingKey, checkRunId: number, runId?: string): Promise<void>;
69
83
  /**
70
84
  * Lookup the check-run ID for a key. Returns undefined if no row exists
71
85
  * yet OR the row exists but the GitHub create has not finished
@@ -93,6 +107,14 @@ export declare class CheckRunTrackingStore {
93
107
  * cluster-wide.
94
108
  */
95
109
  markInProgressSent(key: CheckRunTrackingKey, runId?: string): Promise<void>;
110
+ /**
111
+ * Stamp that the terminal (`completed`) provider update was sent.
112
+ *
113
+ * Mirrors `markInProgressSent`. Best-effort like every write on this table —
114
+ * the caller swallows failures, because a tracking write must never break
115
+ * check-run reporting — so a null column is "no record", not "never sent".
116
+ */
117
+ markTerminalSent(key: CheckRunTrackingKey, runId?: string): Promise<void>;
96
118
  /**
97
119
  * Get the full state snapshot for a key. Used by the L1 cache to
98
120
  * hydrate on miss and by tests to verify the on-disk layout. Returns
@@ -104,17 +126,56 @@ export declare class CheckRunTrackingStore {
104
126
  */
105
127
  deleteRow(key: CheckRunTrackingKey): Promise<boolean>;
106
128
  /**
107
- * List every key currently tracked for a runId. Used by `cleanupRun`
108
- * to reproduce the runId keys reverse index that the in-memory map
109
- * provided. Index `idx_check_run_tracking_run_id` keeps this O(matches).
129
+ * List every key currently tracked for a runId the runId → keys reverse
130
+ * index that `CheckRunReporter` otherwise holds only in memory, so a
131
+ * replacement coord that never saw the run can still recover it. Index
132
+ * `idx_check_run_tracking_run_id` keeps this O(matches).
133
+ *
134
+ * No caller in tree: run-prune stopped consulting the store once row
135
+ * lifetime moved to {@link pruneStale}. Kept as the read half of the
136
+ * `run_id` column, beside {@link deleteByRunId}.
110
137
  */
111
138
  listKeysByRunId(runId: string): Promise<CheckRunTrackingKey[]>;
112
139
  /**
113
- * Delete every row for a runId. Mirrors the bulk-cleanup semantics of
114
- * `cleanupRun` so a single call from execution-tracker prune releases
115
- * all rows for the run.
140
+ * Delete every row for a runId.
141
+ *
142
+ * Not on the run-prune path: `cleanupRun` evicts only its in-memory state,
143
+ * because a row deleted at prune time strands a late terminal PATCH that
144
+ * still has to resolve its check-run ID. Routine reclamation is
145
+ * {@link pruneStale}. This remains as the targeted escape hatch for
146
+ * discarding one run's rows deliberately.
116
147
  */
117
148
  deleteByRunId(runId: string): Promise<number>;
149
+ /**
150
+ * Delete every row untouched for longer than `retentionDays`, and return
151
+ * how many were removed. `retentionDays <= 0` disables the sweep, matching
152
+ * the `JobQueue.pruneTerminalDispatchRows` convention.
153
+ *
154
+ * `updated_at` is the staleness signal because the table carries no status
155
+ * column, and the rows that most need reaping are precisely the ones with no
156
+ * `run_id` to join on — so the predicate is age alone, deliberately
157
+ * unfiltered by `run_id`. Every upsert bumps `updated_at`, so a run that is
158
+ * still emitting check-run traffic keeps its rows fresh; a workflow-level
159
+ * row, written once at create, ages from creation.
160
+ *
161
+ * Inactivity age rather than run completion is what keeps a reader safe: a
162
+ * row a diagnostic is polling for cannot disappear underneath it, because
163
+ * the window is days and the row is only removed once nothing has touched
164
+ * it for that long.
165
+ *
166
+ * The bound this trades for that safety: age is measured on check-run
167
+ * writes, not on run liveness, so a run that stays live while emitting no
168
+ * check-run traffic for longer than the window — a run parked on a manual
169
+ * approval gate, whose hold statuses go through `CheckStatusPoster` and
170
+ * never touch this table — has its rows swept while it is still running.
171
+ * The reporter's L1 cache still holds the ID, so its terminal update lands
172
+ * anyway on a coord that stayed up; it takes a restart or failover across
173
+ * that window to leave the update with no row to load through and no
174
+ * check-run ID to resolve.
175
+ *
176
+ * Called from the hourly cleanup tick.
177
+ */
178
+ pruneStale(retentionDays: number): Promise<number>;
118
179
  private selectRow;
119
180
  private upsertRow;
120
181
  }
@@ -127,6 +188,7 @@ export declare function rowToState(row: {
127
188
  build_creation_state: string | null;
128
189
  step_progress_json: unknown;
129
190
  in_progress_sent_at: Date | null;
191
+ terminal_sent_at: Date | null;
130
192
  run_id: string | null;
131
193
  updated_at: Date;
132
194
  }): CheckRunTrackingState;