@kici-dev/orchestrator 0.6.1 → 0.7.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 (178) hide show
  1. package/dist/agent/dispatcher.d.ts +10 -1
  2. package/dist/agent/host-roster.d.ts +8 -3
  3. package/dist/agent/registry.d.ts +60 -5
  4. package/dist/app.d.ts +10 -5
  5. package/dist/cache/dep-cache.d.ts +14 -6
  6. package/dist/cache/global-eval-round-cache.d.ts +1 -1
  7. package/dist/cache/index.d.ts +1 -1
  8. package/dist/cache/source-cache.d.ts +92 -15
  9. package/dist/cancel/cancel-run.d.ts +20 -2
  10. package/dist/cancel/sweep-stuck-cancelling.d.ts +30 -0
  11. package/dist/cli/api-client.d.ts +10 -0
  12. package/dist/cli/commands/agent-service/logs.d.ts +1 -1
  13. package/dist/cli/commands/agent-service/restart.d.ts +1 -1
  14. package/dist/cli/commands/agent-service/start.d.ts +1 -1
  15. package/dist/cli/commands/agent-service/status.d.ts +1 -1
  16. package/dist/cli/commands/agent-service/stop.d.ts +1 -1
  17. package/dist/cli/commands/agent-service/uninstall.d.ts +1 -1
  18. package/dist/cli/commands/agent.d.ts +25 -0
  19. package/dist/cli/commands/config.d.ts +16 -0
  20. package/dist/cli/commands/db-backup.d.ts +46 -0
  21. package/dist/cli/commands/held-run.d.ts +9 -0
  22. package/dist/cli/commands/orchestrator-service/drain.d.ts +2 -19
  23. package/dist/cli/commands/orchestrator-service/index.d.ts +9 -1
  24. package/dist/cli/commands/orchestrator-service/install-env.d.ts +43 -2
  25. package/dist/cli/commands/orchestrator-service/logs.d.ts +1 -1
  26. package/dist/cli/commands/orchestrator-service/restart.d.ts +1 -1
  27. package/dist/cli/commands/orchestrator-service/start.d.ts +1 -1
  28. package/dist/cli/commands/orchestrator-service/status.d.ts +17 -1
  29. package/dist/cli/commands/orchestrator-service/stop.d.ts +1 -1
  30. package/dist/cli/commands/orchestrator-service/uninstall.d.ts +1 -1
  31. package/dist/cli/commands/orchestrator-service/upgrade.d.ts +2 -1
  32. package/dist/cli/commands/rotate.d.ts +1 -1
  33. package/dist/cli/commands/shared/env-file-mode.d.ts +16 -0
  34. package/dist/cli/commands/shared/upgrade-hooks.d.ts +32 -0
  35. package/dist/cli/commands/shared/upgrade-safety.d.ts +81 -0
  36. package/dist/cli/commands/shared/versioned-upgrade.d.ts +67 -12
  37. package/dist/cli/commands/source.d.ts +1 -0
  38. package/dist/cli/commands/token.d.ts +4 -0
  39. package/dist/cli/commands/trust-policy.d.ts +57 -1
  40. package/dist/cli/join.d.ts +1 -1
  41. package/dist/cli/service/backup-timer.d.ts +108 -0
  42. package/dist/cli/service/compose-path.d.ts +11 -0
  43. package/dist/cli/service/compose.d.ts +22 -0
  44. package/dist/cli/service/deploy-env.d.ts +10 -11
  45. package/dist/cli/service/env-assignment.d.ts +24 -0
  46. package/dist/cli/service/index.d.ts +2 -2
  47. package/dist/cli/service/instance/resolve.d.ts +71 -7
  48. package/dist/cli/service/instance/types.d.ts +15 -0
  49. package/dist/cli/service/launchd.d.ts +7 -0
  50. package/dist/cli/service/systemd.d.ts +1 -0
  51. package/dist/cli/service/types.d.ts +36 -0
  52. package/dist/cli/service/windows.d.ts +16 -0
  53. package/dist/cli/wizard/orchestrator-wizard.d.ts +12 -3
  54. package/dist/cli/wizard/prompts.d.ts +7 -0
  55. package/dist/cli.js +12525 -9298
  56. package/dist/cluster/cluster-settings-reader.d.ts +2 -2
  57. package/dist/cluster/coordinator.d.ts +11 -0
  58. package/dist/cluster/instance-heartbeat.d.ts +96 -0
  59. package/dist/cluster/join-client.d.ts +55 -5
  60. package/dist/cluster/join-handler.d.ts +1 -0
  61. package/dist/cluster/orphan-recovery.d.ts +16 -0
  62. package/dist/cluster/peer-registry.d.ts +10 -0
  63. package/dist/concurrency/dispatch-next-queued.d.ts +1 -13
  64. package/dist/concurrency/index.d.ts +1 -2
  65. package/dist/concurrency/queue-manager.d.ts +63 -18
  66. package/dist/config/env-overlay.d.ts +3 -2
  67. package/dist/config.d.ts +24 -0
  68. package/dist/contexts/release-queued-holds.d.ts +23 -1
  69. package/dist/dashboard/attestation-filters.d.ts +2 -0
  70. package/dist/dashboard/handler.d.ts +22 -2
  71. package/dist/db/deferred-indexes.d.ts +72 -0
  72. package/dist/db/migration-test-harness.d.ts +22 -0
  73. package/dist/db/migrations/131_execution_jobs_git_credentials.d.ts +30 -0
  74. package/dist/db/migrations/132_execution_runs_trigger_event.d.ts +23 -0
  75. package/dist/db/migrations/133_dispatch_queue_source_tar_digest.d.ts +23 -0
  76. package/dist/db/migrations/134_dispatch_queue_ownership.d.ts +4 -0
  77. package/dist/db/migrations/135_cluster_settings_retention_days.d.ts +4 -0
  78. package/dist/db/migrations/136_master_key_wrapped_tables_key_version.d.ts +4 -0
  79. package/dist/db/migrations/137_execution_runs_pr_head_context.d.ts +4 -0
  80. package/dist/db/migrations/138_execution_runs_subject_trigger_event.d.ts +4 -0
  81. package/dist/db/migrations/139_admin_token_subject.d.ts +4 -0
  82. package/dist/db/migrations/140_dispatch_queue_canonical_labels.d.ts +54 -0
  83. package/dist/db/migrations/141_event_log_shed.d.ts +15 -0
  84. package/dist/db/migrator.d.ts +47 -0
  85. package/dist/db/notify-listener.d.ts +60 -0
  86. package/dist/db/synthetic-job-ids.d.ts +24 -0
  87. package/dist/db/types.d.ts +169 -4
  88. package/dist/deployment/deployment-identity.d.ts +31 -1
  89. package/dist/diagnostics/checks/index.d.ts +2 -1
  90. package/dist/diagnostics/checks/retention.d.ts +24 -0
  91. package/dist/diagnostics/types.d.ts +7 -0
  92. package/dist/events/event-router.d.ts +1 -1
  93. package/dist/fault-injection-types.d.ts +53 -0
  94. package/dist/firecracker/host-network.d.ts +63 -8
  95. package/dist/git/credential-broker.d.ts +35 -2
  96. package/dist/git/inherited-secret.d.ts +7 -2
  97. package/dist/git/job-context.d.ts +7 -4
  98. package/dist/helpers/secure-write.d.ts +35 -0
  99. package/dist/index.js +196 -67
  100. package/dist/metrics/prometheus.d.ts +116 -1
  101. package/dist/oidc/db-signer.d.ts +27 -5
  102. package/dist/oidc/id-token-claims.d.ts +33 -2
  103. package/dist/oidc/oidc-mint-registration.d.ts +6 -0
  104. package/dist/oidc/orchestrator-mint.d.ts +8 -0
  105. package/dist/oidc/reconcile-signing-key.d.ts +37 -0
  106. package/dist/orchestrator-core.d.ts +9 -3
  107. package/dist/pipeline/decorating-secret-resolver.d.ts +1 -1
  108. package/dist/pipeline/dispatch-matched-workflow.d.ts +65 -14
  109. package/dist/pipeline/manual-schedule.d.ts +1 -0
  110. package/dist/pipeline/process-webhook.d.ts +20 -2
  111. package/dist/pipeline/route-or-dispatch-jobs.d.ts +7 -0
  112. package/dist/pipeline/run-event-context.d.ts +39 -0
  113. package/dist/policy/dashboard-write-policy-listener.d.ts +1 -1
  114. package/dist/policy/dashboard-write-policy.d.ts +47 -1
  115. package/dist/provenance/dispatch-context.d.ts +46 -0
  116. package/dist/provenance/verify-deferred-capture.d.ts +39 -0
  117. package/dist/providers/github/auth.d.ts +9 -0
  118. package/dist/providers/github/deliveries.d.ts +118 -0
  119. package/dist/providers/universal-git/config.d.ts +1 -1
  120. package/dist/queue/cleanup.d.ts +13 -0
  121. package/dist/queue/job-queue.d.ts +162 -14
  122. package/dist/queue/retention.d.ts +105 -0
  123. package/dist/reporting/execution-tracker.d.ts +87 -36
  124. package/dist/routes/admin-db.d.ts +5 -0
  125. package/dist/routes/admin-events.d.ts +13 -0
  126. package/dist/routes/admin-held-runs.d.ts +11 -1
  127. package/dist/routes/admin-org-settings.d.ts +9 -0
  128. package/dist/routes/admin-runs.d.ts +7 -4
  129. package/dist/routes/admin-sources.d.ts +15 -0
  130. package/dist/routes/admin-trust-policy.d.ts +11 -0
  131. package/dist/routes/admin.d.ts +25 -0
  132. package/dist/scaler/backend-factory.d.ts +16 -0
  133. package/dist/scaler/bare-metal-backend.d.ts +22 -4
  134. package/dist/scaler/config.d.ts +6 -3
  135. package/dist/scaler/container-backend.d.ts +102 -3
  136. package/dist/scaler/container-hostconfig.d.ts +60 -0
  137. package/dist/scaler/file-tail.d.ts +25 -2
  138. package/dist/scaler/firecracker-api.d.ts +9 -1
  139. package/dist/scaler/firecracker-backend.d.ts +135 -2
  140. package/dist/scaler/host-access.d.ts +59 -0
  141. package/dist/scaler/index.d.ts +1 -0
  142. package/dist/scaler/manager.d.ts +33 -0
  143. package/dist/scaler/scaler-state-store.d.ts +6 -0
  144. package/dist/scaler/types.d.ts +5 -7
  145. package/dist/secrets/config.d.ts +48 -0
  146. package/dist/secrets/dashboard-encryption-key.d.ts +19 -0
  147. package/dist/secrets/ephemeral-keys.d.ts +9 -3
  148. package/dist/secrets/index.d.ts +3 -1
  149. package/dist/secrets/job-secret-gate.d.ts +76 -0
  150. package/dist/secrets/master-key-rotation.d.ts +65 -0
  151. package/dist/secrets/secret-output-crypto.d.ts +17 -0
  152. package/dist/secrets/secret-resolver.d.ts +23 -6
  153. package/dist/secrets/source-credentials.d.ts +1 -1
  154. package/dist/secrets/token-manager.d.ts +4 -1
  155. package/dist/security/reduced-privilege-note.d.ts +5 -0
  156. package/dist/security/trust-policy-gate.d.ts +70 -6
  157. package/dist/security/trust-tier.d.ts +31 -0
  158. package/dist/server.d.ts +1 -1
  159. package/dist/server.js +10661 -5282
  160. package/dist/sources/source-manager.d.ts +1 -1
  161. package/dist/stale-detector/stale-dispatch-candidates.d.ts +43 -0
  162. package/dist/standalone.js +9258 -4122
  163. package/dist/storage/loopback-guard.d.ts +53 -6
  164. package/dist/webhook/event-log.d.ts +14 -1
  165. package/dist/webhook/generic-sources-listener.d.ts +1 -1
  166. package/dist/webhook/ingest-admission.d.ts +24 -0
  167. package/dist/webhook/ingest-overflow-replayer.d.ts +78 -14
  168. package/dist/webhook/ingest-overflow-types.d.ts +13 -1
  169. package/dist/webhook/register-source-bundle.d.ts +23 -0
  170. package/dist/webhook/relay-reinject.d.ts +11 -12
  171. package/dist/webhook/shed-breadcrumb.d.ts +15 -0
  172. package/dist/ws/git-credential-relay.d.ts +41 -12
  173. package/dist/ws/platform-client.d.ts +28 -5
  174. package/installer-image-digests.json +3 -3
  175. package/package.json +4 -4
  176. package/sbom.spdx.json +53 -53
  177. package/dist/concurrency/group-tracker.d.ts +0 -51
  178. package/dist/scaler/nftables.d.ts +0 -111
@@ -1,6 +1,6 @@
1
1
  import { type Kysely } from 'kysely';
2
2
  import { type ColdStore } from '@kici-dev/shared';
3
- import type { DashboardRunDetailRequest, DashboardRunsListRequest, DashboardRunsListResponse, DashboardRunsFiltersRequest, DashboardRunsFiltersResponse, DashboardSourcesListRequest, DashboardSourcesListResponse, DashboardStepLogsRequest, DashboardAttestationsListRequest, DashboardAttestationsListAllRequest, DashboardAttestationGetRequest, DashboardAttestationRetryRequest, DashboardPayloadRequest, DashboardOrchLogsRequest, DashboardEventLogListRequest, DashboardEventLogActivityRequest, DashboardEventLogDetailRequest, DashboardEventLogPayloadStreamRequest, DashboardAccessLogListRequest, DashboardEventDlqListRequest, DashboardEventDlqCountRequest, DashboardEventDlqRetryRequest, DashboardEventDlqDiscardRequest, RunRerunRequest, RunCancelRequest, ManualScheduleRequest, DashboardRunStructuredRequest, DashboardArtifactsListRequest } from '@kici-dev/engine';
3
+ import type { DashboardRunDetailRequest, DashboardRunsListRequest, DashboardRunsListResponse, DashboardRunsFiltersRequest, DashboardRunsFiltersResponse, DashboardSourcesListRequest, DashboardSourcesListResponse, DashboardAdminTokensListRequest, DashboardAdminTokensListResponse, DashboardStepLogsRequest, DashboardAttestationsListRequest, DashboardAttestationsListAllRequest, DashboardAttestationGetRequest, DashboardAttestationRetryRequest, DashboardPayloadRequest, DashboardOrchLogsRequest, DashboardEventLogListRequest, DashboardEventLogActivityRequest, DashboardEventLogDetailRequest, DashboardEventLogPayloadStreamRequest, DashboardAccessLogListRequest, DashboardEventDlqListRequest, DashboardEventDlqCountRequest, DashboardEventDlqRetryRequest, DashboardEventDlqDiscardRequest, RunRerunRequest, RunCancelRequest, ManualScheduleRequest, DashboardRunStructuredRequest, DashboardArtifactsListRequest } from '@kici-dev/engine';
4
4
  import type { Database } from '../db/types.js';
5
5
  import type { LogStorage } from '../reporting/log-storage.js';
6
6
  import type { CacheStorage } from '../storage/types.js';
@@ -233,7 +233,7 @@ export declare class DashboardHandler {
233
233
  * unioning both source tables. Uses the identical name/subtype/provider
234
234
  * derivation as `handleSourcesList` so a run summary's `source` block
235
235
  * matches what the sources page shows for the same routing key. Routing
236
- * keys with no live source row are simply absent from the map (the caller
236
+ * keys with no live source row are absent from the map (the caller
237
237
  * falls back to the run's own provider).
238
238
  */
239
239
  private resolveSourceIdentities;
@@ -303,6 +303,26 @@ export declare class DashboardHandler {
303
303
  * carries the wire actor so the customer can audit any operator read.
304
304
  */
305
305
  handleSourcesList(msg: DashboardSourcesListRequest): Promise<DashboardSourcesListResponse>;
306
+ /**
307
+ * Handle a dashboard.admin-tokens.list request.
308
+ *
309
+ * Returns the orchestrator's live admin-token inventory for the Platform's
310
+ * RBAC drift report. `admin_tokens` is orchestrator-wide — an orchestrator
311
+ * serves exactly one org — so the projection is not filtered by `orgId`; the
312
+ * handler-bound `orgId` / `routingKey` attribute the access_log row, the same
313
+ * inline-ctx pattern `handleSourcesList` uses.
314
+ *
315
+ * Only live tokens are returned: a revoked or already-expired token is not a
316
+ * finding, so reporting one would be noise the operator learns to ignore.
317
+ *
318
+ * `token_hash` is never selected. The report has no use for it, and a hash is
319
+ * a credential verifier — relaying one would put an offline-crackable value
320
+ * on the dashboard plane.
321
+ *
322
+ * Reading who holds admin tokens is itself privileged, so every read writes
323
+ * an access_log row carrying the wire actor.
324
+ */
325
+ handleAdminTokensList(msg: DashboardAdminTokensListRequest): Promise<DashboardAdminTokensListResponse>;
306
326
  /**
307
327
  * Handle a dashboard.step.logs request.
308
328
  * Looks up the step's log_path and reads content from LogStorage.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Indexes built after boot, outside the migration set.
3
+ *
4
+ * A migration cannot build an index without locking the table it indexes.
5
+ * Kysely runs the whole pending batch inside one transaction and offers no
6
+ * per-migration opt-out, and PostgreSQL rejects `CREATE INDEX CONCURRENTLY`
7
+ * inside a transaction block outright — so a migration's only option is a
8
+ * plain `CREATE INDEX`, which holds an exclusive lock for the whole build. On
9
+ * a table holding millions of rows that is a multi-minute outage bolted onto
10
+ * an upgrade.
11
+ *
12
+ * So an index on a table that scales with run volume goes here instead. Each
13
+ * entry is built `CONCURRENTLY` on its own connection with no statement
14
+ * timeout, under an advisory lock distinct from the migration lock, after the
15
+ * server is already serving. `IF NOT EXISTS` makes every build idempotent, and
16
+ * a failed build retries on the next boot.
17
+ *
18
+ * `hack/check-migration-safety.ts` enforces that new indexes on those tables
19
+ * land here rather than in a migration.
20
+ */
21
+ import type pg from 'pg';
22
+ import { type Logger } from '@kici-dev/shared';
23
+ /**
24
+ * Distinct from the migrator's `543210001`: an index build must not block, or
25
+ * be blocked by, a peer applying migrations.
26
+ */
27
+ export declare const DEFERRED_INDEX_LOCK_KEY = 543210002;
28
+ export interface DeferredIndex {
29
+ /** Index name, matching the one the SQL creates. */
30
+ name: string;
31
+ /** A single `CREATE INDEX CONCURRENTLY IF NOT EXISTS` statement. */
32
+ sql: string;
33
+ }
34
+ /**
35
+ * Every index the retention sweep and the age-based readers depend on.
36
+ *
37
+ * Each one supports a `... < cutoff` scan that would otherwise walk the whole
38
+ * table on every cleanup tick. The tables already carry indexes for their
39
+ * serving-path queries; these cover the aging path, whose predicate is not
40
+ * prefixed by an organization or routing key.
41
+ */
42
+ export declare const DEFERRED_INDEXES: ReadonlyArray<DeferredIndex>;
43
+ /**
44
+ * Drop a leftover invalid index before rebuilding it.
45
+ *
46
+ * An interrupted `CREATE INDEX CONCURRENTLY` leaves the index in place marked
47
+ * invalid: it is not used by the planner, and `IF NOT EXISTS` sees it and
48
+ * skips. Without this, the very first failed build would make the retry a
49
+ * permanent no-op — the opposite of the "retries on the next boot" contract.
50
+ */
51
+ export declare function dropIfInvalid(client: Pick<pg.Client, 'query'>, name: string, logger: Logger): Promise<void>;
52
+ export interface BuildDeferredIndexesResult {
53
+ built: string[];
54
+ failed: string[];
55
+ }
56
+ /**
57
+ * Build every deferred index on one dedicated connection.
58
+ *
59
+ * The connection is taken straight from `pg` rather than from the serving
60
+ * pool: `CREATE INDEX CONCURRENTLY` must run outside a transaction and must
61
+ * not inherit a statement timeout, and a concurrent build on a large table
62
+ * would otherwise hold a serving connection for its whole duration.
63
+ *
64
+ * The advisory lock is `pg_try_advisory_lock`, not the blocking form: when a
65
+ * peer is already building, this instance has nothing to wait for.
66
+ */
67
+ export declare function buildDeferredIndexes(databaseUrl: string, opts?: {
68
+ logger?: Logger;
69
+ indexes?: ReadonlyArray<DeferredIndex>;
70
+ pg?: typeof import('pg');
71
+ }): Promise<BuildDeferredIndexesResult>;
72
+ //# sourceMappingURL=deferred-indexes.d.ts.map
@@ -13,6 +13,11 @@
13
13
  * test can neither name the wrong migration nor drift when a file is renamed.
14
14
  * It has no fallback to the whole set: an unknown or no-op target throws.
15
15
  *
16
+ * A DATA migration needs the state one step earlier as well, so it can insert
17
+ * the rows it is supposed to rewrite: `migrateToPreviousMigration()` provides
18
+ * it, deriving that target from the migration list rather than from a name the
19
+ * test spells out.
20
+ *
16
21
  * Repo/store tests outside `migrations/` (host roster, artifact store, the repo
17
22
  * suites) legitimately want head-of-list schema and use `migrateToLatest()`
18
23
  * directly instead.
@@ -38,4 +43,21 @@ export declare function migrationNameFromTestUrl(testUrl: string): string;
38
43
  * "the whole migration set ran".
39
44
  */
40
45
  export declare function migrateToOwnMigration<DB>(db: Kysely<DB>, testUrl: string): Promise<MigrationResultSet>;
46
+ /**
47
+ * Apply migrations `001..NNN-1` — everything up to, but NOT including, the
48
+ * migration the calling test file is named after. Pass `import.meta.url`.
49
+ *
50
+ * This is the pre-migration state a DATA migration has to be tested from. A
51
+ * data migration rewrites rows that already exist, so its test has to straddle
52
+ * it: migrate here, insert the rows an upgraded database actually holds, then
53
+ * call {@link migrateToOwnMigration} and assert what moved. Going straight to
54
+ * `migrateToOwnMigration` leaves no window to insert anything, so the
55
+ * assertions would run against rows the migration never saw — a check that
56
+ * passes identically with the migration body deleted.
57
+ *
58
+ * The target is derived from the migration list, so the caller never names the
59
+ * previous migration and cannot drift when one is inserted before it. A test
60
+ * for the very first migration throws, since there is no earlier state.
61
+ */
62
+ export declare function migrateToPreviousMigration<DB>(db: Kysely<DB>, testUrl: string): Promise<MigrationResultSet>;
41
63
  //# sourceMappingURL=migration-test-harness.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `execution_jobs.git_credentials JSONB NULL` — the `gitCredentials` map the
4
+ * job's lock entry declared, as server truth the credential relay can read on
5
+ * the hot path.
6
+ *
7
+ * The relay is called on every git network operation, so it must not re-fetch
8
+ * or re-parse a lock file to learn what a job is allowed to ask for. The
9
+ * orchestrator persists no per-job lock entry (`execution_jobs` carries no
10
+ * config column), so the declaration is written at dispatch and read back here.
11
+ *
12
+ * Values follow `LockJob.gitCredentials`: a `<name>Secret` field is a secret
13
+ * NAME in qualified `<context>:<key>` form, while its `<name>Value` sibling
14
+ * carries material for a credential with no store entry to name. The column
15
+ * stores whichever the lock declared, verbatim — it is the declaration the
16
+ * relay compares a request against, not a secret store of its own.
17
+ *
18
+ * Nullable, with no default: NULL means "this job declared no git credentials",
19
+ * which is true of nearly every job and of every row written before this column
20
+ * existed. A default would have to name a declaration nobody made. The row is
21
+ * written after the dispatch loop, so NULL also covers "not written yet" — the
22
+ * relay resolves that ambiguity against the job's dispatch record rather than
23
+ * reading it as a declaration (`git/job-context.ts`).
24
+ *
25
+ * Idempotent: the add is guarded on existence and the drop uses IF EXISTS, so a
26
+ * re-run is a no-op.
27
+ */
28
+ export declare function up(db: Kysely<unknown>): Promise<void>;
29
+ export declare function down(db: Kysely<unknown>): Promise<void>;
30
+ //# sourceMappingURL=131_execution_jobs_git_credentials.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `execution_runs.trigger_event TEXT NULL` — the event type that started
4
+ * the run (`push`, `pr:open`, `schedule`, …).
5
+ *
6
+ * The tracker has always carried this value in memory and relayed it to the
7
+ * dashboard, but never persisted it. The git credential relay needs it: it
8
+ * evaluates a named context's protection rules against the run, and a context
9
+ * may restrict which trigger types may use it (`triggerTypeFilters`). Without
10
+ * the recorded value that rule cannot be evaluated at all.
11
+ *
12
+ * Nullable, with no default: a row written before this column existed has no
13
+ * recorded trigger, and no cluster-wide value could stand in for one. A run
14
+ * whose trigger is unknown fails a `triggerTypeFilters` rule closed, which is
15
+ * the correct direction — a credential is withheld rather than granted on a
16
+ * rule nobody could check.
17
+ *
18
+ * Idempotent: the add is guarded on existence and the drop uses IF EXISTS, so a
19
+ * re-run is a no-op.
20
+ */
21
+ export declare function up(db: Kysely<unknown>): Promise<void>;
22
+ export declare function down(db: Kysely<unknown>): Promise<void>;
23
+ //# sourceMappingURL=132_execution_runs_trigger_event.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `dispatch_queue.source_tar_digest TEXT NULL` — the SHA-256 of the source
4
+ * tarball's own bytes, so the agent can verify what it downloaded before
5
+ * extracting it.
6
+ *
7
+ * The neighbouring `source_tar_hash` column carries the workflow `contentHash`
8
+ * despite its name, which is why the agent's restore path verified nothing: it
9
+ * had no value to compare the bytes against. `deps_hash` next door has always
10
+ * held its tarball's real digest, and this column is its source-side sibling.
11
+ *
12
+ * Nullable, with no default: NULL means "no digest known for this row", which
13
+ * is true of every row written before the column existed and of any dispatch
14
+ * whose source came from somewhere other than the content-addressed cache. The
15
+ * agent treats NULL as "nothing to verify against" and restores unverified,
16
+ * exactly as it did before — so an in-flight queue survives the upgrade.
17
+ *
18
+ * Idempotent: the add is guarded on existence and the drop uses IF EXISTS, so a
19
+ * re-run is a no-op.
20
+ */
21
+ export declare function up(db: Kysely<unknown>): Promise<void>;
22
+ export declare function down(db: Kysely<unknown>): Promise<void>;
23
+ //# sourceMappingURL=133_dispatch_queue_source_tar_digest.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=134_dispatch_queue_ownership.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=135_cluster_settings_retention_days.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=136_master_key_wrapped_tables_key_version.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=137_execution_runs_pr_head_context.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=138_execution_runs_subject_trigger_event.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ export declare function down(db: Kysely<unknown>): Promise<void>;
4
+ //# sourceMappingURL=139_admin_token_subject.d.ts.map
@@ -0,0 +1,54 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Fold `dispatch_queue` label arrays to their canonical (trimmed, lowercase)
4
+ * form.
5
+ *
6
+ * Label matching folds case, and every other label store folds on read.
7
+ * `dispatch_queue` cannot: its comparison happens in SQL — the `@>` containment
8
+ * prefilter and the `jsonb_array_elements_text` exclude check — so the SQL
9
+ * filters rows before any JavaScript sees them. A row enqueued before labels
10
+ * became case-insensitive carries whatever case the workflow author wrote, so
11
+ * it would never again match a folded agent label set, and no read-side fold
12
+ * could rescue it because the row is never selected in the first place. This
13
+ * migration is what makes those rows reachable.
14
+ *
15
+ * The fold mirrors `canonicalizeLabel` in `@kici-dev/engine` —
16
+ * `btrim(lower(...))` against `raw.trim().toLowerCase()` — so a row this
17
+ * migration rewrites holds the same bytes as the same labels enqueued today.
18
+ * Lowercasing alone would strand a padded legacy label the same way a
19
+ * mixed-case one is stranded, because the agent side trims.
20
+ *
21
+ * `runs_on_patterns` / `exclude_patterns` are deliberately untouched: they hold
22
+ * regex SOURCES, which cannot be lowercased without corrupting the pattern.
23
+ * Those fold via the forced `i` flag applied when they are read.
24
+ *
25
+ * The GIN index `idx_dispatch_queue_labels_gin` needs no change — the query
26
+ * shape is identical, only the values move.
27
+ *
28
+ * `COALESCE(jsonb_agg(...), '[]'::jsonb)` is defence in depth against the
29
+ * `EXISTS` guard below being loosened, and is unreachable as the statement
30
+ * stands. `jsonb_agg` over zero rows does return NULL, and a NULL would violate
31
+ * `runs_on_labels NOT NULL` and leave the drain's `jsonb_array_elements_text`
32
+ * with nothing to walk on `exclude_labels` — but zero rows requires an empty
33
+ * array, and an empty array can never satisfy a guard that demands an element
34
+ * differing from its own folded form. Removing the guard, or replacing it with
35
+ * one that admits an empty array, makes the COALESCE load-bearing immediately,
36
+ * so it stays.
37
+ *
38
+ * Idempotent: each `UPDATE` selects only rows holding an element that is not
39
+ * already its own canonical form, so a re-run touches nothing.
40
+ */
41
+ export declare function up(db: Kysely<unknown>): Promise<void>;
42
+ /**
43
+ * Irreversible by design: the original case is destroyed, so there is nothing
44
+ * to restore. This is a data migration, not a schema change, so `down` leaves
45
+ * the schema exactly as `up` found it and the no-op is the honest outcome
46
+ * rather than a missing implementation.
47
+ *
48
+ * Rolling the orchestrator back is briefly worse than never having migrated:
49
+ * an old orchestrator compares an agent's labels verbatim against rows this
50
+ * migration canonicalized, so a fleet whose configured labels are not already
51
+ * lowercase strands those rows until they expire, drain, or are re-enqueued.
52
+ */
53
+ export declare function down(): Promise<void>;
54
+ //# sourceMappingURL=140_dispatch_queue_canonical_labels.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Extend the event_log.status CHECK constraint with 'shed' so the orchestrator
4
+ * can record a breadcrumb for a delivery the ingest admission controller
5
+ * refused under load. Without the row a shed delivery is indistinguishable
6
+ * from one that never arrived, because the shed happens before the pipeline
7
+ * that writes every other status.
8
+ *
9
+ * Orchestrator-only: the Platform event_log uses a separate, narrower status set.
10
+ *
11
+ * Idempotent: the DROP ... IF EXISTS / re-ADD pair re-runs cleanly.
12
+ */
13
+ export declare function up(db: Kysely<unknown>): Promise<void>;
14
+ export declare function down(db: Kysely<unknown>): Promise<void>;
15
+ //# sourceMappingURL=141_event_log_shed.d.ts.map
@@ -11,6 +11,31 @@ interface MigrateOptions {
11
11
  db: Kysely<any>;
12
12
  pool: pg.Pool;
13
13
  }
14
+ /**
15
+ * Build a pool reserved for schema work.
16
+ *
17
+ * Migrations run DDL and backfills that legitimately take minutes on a
18
+ * database holding real history, so they must not inherit the hot path's
19
+ * `statement_timeout`. pg treats `0` as "no limit". Kysely's `Migrator`
20
+ * acquires its own connections from whatever pool backs the `Kysely` instance
21
+ * it is given, so the exemption has to be set on the pool — a `SET` issued on
22
+ * one client would not reach the connections that run the migrations.
23
+ *
24
+ * `max: 2` covers the advisory-lock client plus the one Kysely checks out.
25
+ */
26
+ export declare function createMigrationPool(databaseUrl: string): pg.Pool;
27
+ /**
28
+ * Run `fn` against a short-lived timeout-free migration pool, then close it.
29
+ */
30
+ export declare function withMigrationPool<T>(databaseUrl: string, fn: (opts: MigrateOptions) => Promise<T>): Promise<T>;
31
+ /** True when a driver error is a cancelled statement rather than bad SQL. */
32
+ export declare function isStatementTimeoutError(message: string): boolean;
33
+ /**
34
+ * Restate a migration failure so the log names the migration that failed and,
35
+ * on a cancelled statement, the way out. The bare driver message names
36
+ * neither, which is what left an operator with a boot loop and no next step.
37
+ */
38
+ export declare function describeMigrationFailure(message: string, migrationName?: string): string;
14
39
  interface MigrationStatusEntry {
15
40
  name: string;
16
41
  status: 'applied' | 'pending';
@@ -28,5 +53,27 @@ export declare function runMigrations(opts: MigrateOptions): Promise<MigrationRe
28
53
  * Get migration status (applied/pending) without running anything.
29
54
  */
30
55
  export declare function getMigrationStatus(opts: MigrateOptions): Promise<MigrationStatusEntry[]>;
56
+ /** What a `migrateTo` run did. */
57
+ export interface MigrateToResult {
58
+ /** The migration the ledger now sits at. */
59
+ target: string;
60
+ /** Migrations applied to reach it (empty when moving backwards). */
61
+ applied: string[];
62
+ /** Migrations reverted to reach it (empty when moving forwards). */
63
+ reverted: string[];
64
+ }
65
+ /**
66
+ * Migrate the ledger to a named migration, in either direction.
67
+ *
68
+ * The point of this is rollback: a previous release's static provider does not
69
+ * carry the newer migrations' names, so Kysely refuses to start against a
70
+ * ledger that records them (`corrupted migrations: previously executed
71
+ * migration <name> is missing`). Reverting to the head that release was
72
+ * running at is what makes the old binary bootable again.
73
+ *
74
+ * It runs under the same advisory lock as {@link runMigrations}, so a peer
75
+ * cannot be applying migrations while this reverts them.
76
+ */
77
+ export declare function migrateTo(opts: MigrateOptions, name: string): Promise<MigrateToResult>;
31
78
  export {};
32
79
  //# sourceMappingURL=migrator.d.ts.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * A LISTEN subscription that survives losing its connection.
3
+ *
4
+ * A `LISTEN` session is a single checked-out client sitting idle. A Postgres
5
+ * failover, a restart, or an idle-backend sweep terminates it, and the pool's
6
+ * own error handler discards the broken connection without re-acquiring — so
7
+ * the subscription is silently gone while `/health` and `/ready` stay 200. The
8
+ * process keeps running and never hears another NOTIFY on that channel.
9
+ *
10
+ * This wraps the pattern once: acquire, subscribe, `LISTEN`, and on `error` or
11
+ * `end` release the dead client and reconnect with jittered exponential
12
+ * backoff until `stop()`. NOTIFY has no durable log, so nothing can be
13
+ * replayed — instead, after a successful re-`LISTEN` the consumer's
14
+ * `onReconnect` re-derives whatever it missed from the database, which is
15
+ * exactly what that consumer already does at cold boot.
16
+ */
17
+ import type pg from 'pg';
18
+ import { type Logger } from '@kici-dev/shared';
19
+ export interface NotifyListenerOptions {
20
+ pool: pg.Pool;
21
+ /** Channel name. Interpolated into `LISTEN`, so it must be an identifier. */
22
+ channel: string;
23
+ onNotification: (msg: pg.Notification) => void;
24
+ /**
25
+ * Re-derive what the subscription missed while it was disconnected. Awaited
26
+ * after a successful re-`LISTEN`, never on the first connect — a cold start
27
+ * has its own load path.
28
+ */
29
+ onReconnect?: () => Promise<void> | void;
30
+ logger?: Logger;
31
+ /** First backoff step. Doubles up to {@link MAX_BACKOFF_MS}. */
32
+ baseBackoffMs?: number;
33
+ }
34
+ export declare const MAX_BACKOFF_MS = 30000;
35
+ export declare class NotifyListener {
36
+ private readonly opts;
37
+ private client;
38
+ private stopped;
39
+ private reconnecting;
40
+ private timer;
41
+ private attempt;
42
+ private readonly logger;
43
+ private readonly baseBackoffMs;
44
+ constructor(opts: NotifyListenerOptions);
45
+ /** Acquire a client and subscribe. Throws if the first connect fails. */
46
+ start(): Promise<void>;
47
+ /**
48
+ * Best-effort `UNLISTEN`, then release. Cancels any pending reconnect, so a
49
+ * shutdown mid-backoff does not resurrect the subscription.
50
+ */
51
+ stop(): Promise<void>;
52
+ /** True while a live client holds the subscription. */
53
+ get connected(): boolean;
54
+ private connect;
55
+ private scheduleReconnect;
56
+ /** Exponential backoff with full jitter, capped at {@link MAX_BACKOFF_MS}. */
57
+ private backoffMs;
58
+ private reconnect;
59
+ }
60
+ //# sourceMappingURL=notify-listener.d.ts.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The `execution_jobs.job_id` prefix that marks a PLACEHOLDER row.
3
+ *
4
+ * A placeholder stands for a job the dispatch pass registered but did not hand
5
+ * to the dispatcher — one waiting on a `needs` edge, on a rolling-wave slot, on
6
+ * an invoke-gate summon, or on a protection-rule hold. It exists so the run is
7
+ * not considered complete without it (`isRunComplete` iterates only registered
8
+ * jobs), and it is swapped for the real job id the moment the job actually
9
+ * dispatches (`dispatchReadyJob` → `findSyntheticJobId` → `addJobsToRun`).
10
+ *
11
+ * Lives here, beside the table it describes, because both the writers
12
+ * (`pipeline/`) and the readers that must exclude these rows from an occupancy
13
+ * count (`contexts/`) key on it, and neither layer imports the other.
14
+ */
15
+ export declare const NEEDS_PENDING_JOB_ID_PREFIX = "needs-pending-";
16
+ /**
17
+ * SQL `LIKE` pattern matching every placeholder `job_id`.
18
+ *
19
+ * `_` is a single-character wildcard in `LIKE`, so the literal underscore-free
20
+ * prefix above needs no escaping — kept as one constant anyway so a caller can
21
+ * never spell the pattern and the prefix differently.
22
+ */
23
+ export declare const NEEDS_PENDING_JOB_ID_LIKE = "needs-pending-%";
24
+ //# sourceMappingURL=synthetic-job-ids.d.ts.map