@kici-dev/orchestrator 0.4.0 → 0.6.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 (183) hide show
  1. package/dist/__test-helpers__/fake-scaler-state-store.d.ts +24 -0
  2. package/dist/__test-helpers__/mock-db-query.d.ts +130 -0
  3. package/dist/__test-helpers__/mock-db.d.ts +27 -0
  4. package/dist/agent/agent-version.d.ts +34 -0
  5. package/dist/agent/dispatcher.d.ts +151 -13
  6. package/dist/agent/host-roster.d.ts +37 -5
  7. package/dist/agent/registry.d.ts +2 -0
  8. package/dist/app.d.ts +56 -7
  9. package/dist/approvals/apply-decision.d.ts +67 -19
  10. package/dist/approvals/held-run-release-wiring.d.ts +45 -0
  11. package/dist/approvals/independent-wiring.d.ts +55 -0
  12. package/dist/approvals/resume-router.d.ts +9 -0
  13. package/dist/approvals/triggerer-subject.d.ts +37 -0
  14. package/dist/cache/dep-cache.d.ts +54 -10
  15. package/dist/cache/global-eval-round-cache.d.ts +95 -0
  16. package/dist/cache/index.d.ts +3 -0
  17. package/dist/cache/pending-global-evals.d.ts +42 -0
  18. package/dist/cache/pending-inits.d.ts +10 -0
  19. package/dist/cli/api-client.d.ts +18 -0
  20. package/dist/cli/commands/cluster-settings.d.ts +52 -3
  21. package/dist/cli/commands/diagnose.d.ts +6 -0
  22. package/dist/cli/commands/held-run.d.ts +58 -0
  23. package/dist/cli/commands/runs.d.ts +1 -0
  24. package/dist/cli/commands/trust-policy.d.ts +117 -12
  25. package/dist/cli/kici-admin.d.ts +10 -0
  26. package/dist/cli.js +2770 -938
  27. package/dist/cluster/cluster-identity.d.ts +3 -3
  28. package/dist/cluster/cluster-settings-reader.d.ts +59 -1
  29. package/dist/cluster/coordinator.d.ts +44 -0
  30. package/dist/cluster/index.d.ts +4 -0
  31. package/dist/cluster/peer-handler.d.ts +19 -0
  32. package/dist/cluster/peer-registry.d.ts +17 -0
  33. package/dist/cluster/plan-headroom-store.d.ts +26 -0
  34. package/dist/cluster/worker-eviction.d.ts +69 -0
  35. package/dist/cold-store/load-event-log-range.d.ts +10 -3
  36. package/dist/cold-store/load-secret-audit-log-range.d.ts +4 -3
  37. package/dist/cold-store/tables/secret-audit-log.d.ts +4 -3
  38. package/dist/config.d.ts +48 -21
  39. package/dist/content-requirements-cache.d.ts +55 -0
  40. package/dist/contexts/held-runs.d.ts +123 -16
  41. package/dist/contexts/protection/aggregate.d.ts +3 -2
  42. package/dist/contexts/protection/branch-gate.d.ts +15 -0
  43. package/dist/contexts/protection/concurrency-gate.d.ts +8 -2
  44. package/dist/contexts/protection/pipeline.d.ts +18 -0
  45. package/dist/contexts/release-queued-holds.d.ts +35 -0
  46. package/dist/dashboard/attestation-filters.d.ts +8 -0
  47. package/dist/dashboard/handler.d.ts +6 -24
  48. package/dist/db/migrations/109_cluster_settings_cache_knobs.d.ts +4 -0
  49. package/dist/db/migrations/110_cluster_settings_global_eval_knobs.d.ts +4 -0
  50. package/dist/db/migrations/111_cluster_settings_global_eval_wait.d.ts +4 -0
  51. package/dist/db/migrations/112_execution_runs_workflow_repo.d.ts +4 -0
  52. package/dist/db/migrations/113_execution_runs_workflow_repo_index.d.ts +30 -0
  53. package/dist/db/migrations/114_ingest_queue_claim.d.ts +4 -0
  54. package/dist/db/migrations/115_global_workflows_cluster_switch.d.ts +9 -0
  55. package/dist/db/migrations/116_org_plan_headroom.d.ts +4 -0
  56. package/dist/db/migrations/117_invoke_gate_proxy_jobs.d.ts +4 -0
  57. package/dist/db/migrations/118_invoke_gate_scheduling.d.ts +4 -0
  58. package/dist/db/migrations/119_scaler_ha_ownership.d.ts +4 -0
  59. package/dist/db/migrations/120_cluster_settings_scaler_reaper.d.ts +4 -0
  60. package/dist/db/migrations/121_org_settings_allow_untrusted_dockerfile_builds.d.ts +19 -0
  61. package/dist/db/migrations/122_host_roster_scaler_managed.d.ts +25 -0
  62. package/dist/db/migrations/123_workflow_registrations_default_branch.d.ts +24 -0
  63. package/dist/db/migrations/124_cluster_settings_provision_backoff.d.ts +4 -0
  64. package/dist/db/migrations/125_org_trust_directory.d.ts +30 -0
  65. package/dist/db/migrations/126_held_runs_posted_pending_check.d.ts +28 -0
  66. package/dist/db/migrations/127_org_trust_policy_approval_expiry_seconds.d.ts +26 -0
  67. package/dist/db/migrations/128_execution_runs_global_eval_round.d.ts +23 -0
  68. package/dist/db/migrations/129_execution_runs_dispatch_routing_key.d.ts +24 -0
  69. package/dist/db/migrations/130_scaler_provision_outcomes.d.ts +32 -0
  70. package/dist/db/types.d.ts +428 -12
  71. package/dist/entry-helpers.d.ts +28 -0
  72. package/dist/events/event-emitter.d.ts +22 -0
  73. package/dist/events/event-router.d.ts +87 -1
  74. package/dist/events/types.d.ts +2 -23
  75. package/dist/git/credential-broker.d.ts +94 -0
  76. package/dist/git/inherited-secret.d.ts +24 -0
  77. package/dist/git/installation-token.d.ts +38 -0
  78. package/dist/git/job-context.d.ts +13 -0
  79. package/dist/index.js +324 -84
  80. package/dist/metrics/agent-metrics-aggregator.d.ts +4 -4
  81. package/dist/metrics/prometheus.d.ts +170 -3
  82. package/dist/oidc/oidc-mint-registration.d.ts +7 -3
  83. package/dist/orchestrator-core.d.ts +91 -24
  84. package/dist/pipeline/content-filter.d.ts +71 -0
  85. package/dist/pipeline/direct-ingress-deps.d.ts +100 -0
  86. package/dist/pipeline/dispatch-matched-workflow.d.ts +521 -11
  87. package/dist/pipeline/global-eval-round.d.ts +307 -0
  88. package/dist/pipeline/internal-event-pipeline.d.ts +140 -0
  89. package/dist/pipeline/invoke-gate.d.ts +164 -0
  90. package/dist/pipeline/job-contexts.d.ts +16 -17
  91. package/dist/pipeline/needs-scheduler.d.ts +13 -0
  92. package/dist/pipeline/process-webhook.d.ts +126 -31
  93. package/dist/pipeline/processor.d.ts +282 -23
  94. package/dist/pipeline/rerun.d.ts +21 -0
  95. package/dist/pipeline/resume-workflow.d.ts +40 -7
  96. package/dist/pipeline/route-or-dispatch-jobs.d.ts +15 -0
  97. package/dist/pipeline/security-hold-check.d.ts +217 -0
  98. package/dist/pipeline/test-pipeline.d.ts +12 -0
  99. package/dist/pipeline/undispatched-hold-checks.d.ts +23 -0
  100. package/dist/pipeline/webhook-payload-store.d.ts +20 -0
  101. package/dist/policy/dashboard-write-policy-listener.d.ts +62 -0
  102. package/dist/policy/dashboard-write-policy.d.ts +14 -0
  103. package/dist/provenance/backfill-run.d.ts +10 -1
  104. package/dist/provider-registry.d.ts +47 -4
  105. package/dist/providers/github/check-status-poster.d.ts +33 -3
  106. package/dist/providers/github/commit-message.d.ts +20 -0
  107. package/dist/providers/github/file-contents.d.ts +40 -0
  108. package/dist/providers/github/index.d.ts +2 -2
  109. package/dist/providers/github/normalizer.d.ts +3 -2
  110. package/dist/providers/local/normalizer.d.ts +3 -5
  111. package/dist/providers/universal-git/config.d.ts +2 -0
  112. package/dist/providers/universal-git/index.d.ts +11 -2
  113. package/dist/providers/universal-git/normalizer.d.ts +10 -0
  114. package/dist/queue/cleanup.d.ts +7 -1
  115. package/dist/queue/job-queue.d.ts +112 -7
  116. package/dist/queue/terminalize-unroutable.d.ts +13 -0
  117. package/dist/registration/extractor.d.ts +3 -3
  118. package/dist/registration/registration-index.d.ts +7 -0
  119. package/dist/registration/registration-run-match.d.ts +47 -0
  120. package/dist/registration/registration-store.d.ts +22 -0
  121. package/dist/reporting/check-run-reporter.d.ts +146 -2
  122. package/dist/reporting/check-run-summary.d.ts +25 -1
  123. package/dist/reporting/execution-tracker.d.ts +324 -9
  124. package/dist/reporting/log-chunk-sink.d.ts +8 -5
  125. package/dist/reporting/run-aggregator.d.ts +4 -14
  126. package/dist/reporting/step-display-order.d.ts +43 -0
  127. package/dist/routes/admin-held-runs.d.ts +142 -0
  128. package/dist/routes/admin-org-settings.d.ts +5 -0
  129. package/dist/routes/admin-trust-policy.d.ts +34 -6
  130. package/dist/routes/admin.d.ts +15 -0
  131. package/dist/scaler/backend-factory.d.ts +55 -0
  132. package/dist/scaler/bare-metal-backend.d.ts +43 -5
  133. package/dist/scaler/claim-store.d.ts +119 -0
  134. package/dist/scaler/config.d.ts +4 -0
  135. package/dist/scaler/container-backend.d.ts +18 -4
  136. package/dist/scaler/container-routing.d.ts +23 -0
  137. package/dist/scaler/container-spawn.d.ts +28 -0
  138. package/dist/scaler/event-backend.d.ts +124 -0
  139. package/dist/scaler/event-provision-reaper.d.ts +350 -0
  140. package/dist/scaler/failure-tracker.d.ts +1 -1
  141. package/dist/scaler/firecracker-backend.d.ts +33 -6
  142. package/dist/scaler/index.d.ts +11 -1
  143. package/dist/scaler/label-matcher.d.ts +4 -3
  144. package/dist/scaler/manager.d.ts +905 -76
  145. package/dist/scaler/resolve-container-auth.d.ts +45 -0
  146. package/dist/scaler/scaler-events.d.ts +11 -0
  147. package/dist/scaler/scaler-state-store.d.ts +294 -10
  148. package/dist/scaler/types.d.ts +131 -13
  149. package/dist/scaler/warm-pool.d.ts +132 -29
  150. package/dist/security/comment-handler.d.ts +50 -11
  151. package/dist/security/global-workflow-policy.d.ts +52 -12
  152. package/dist/security/identity-link.d.ts +60 -0
  153. package/dist/security/lock-source.d.ts +11 -13
  154. package/dist/security/reduced-privilege-note.d.ts +59 -0
  155. package/dist/security/trust-directory-store.d.ts +233 -0
  156. package/dist/security/trust-policy-gate.d.ts +94 -59
  157. package/dist/security/trust-policy-store.d.ts +3 -0
  158. package/dist/security/trust-resolver.d.ts +14 -98
  159. package/dist/server.d.ts +11 -1
  160. package/dist/server.js +56329 -42234
  161. package/dist/stale-detector/gate-deadline-detector.d.ts +52 -0
  162. package/dist/stale-detector/stale-run-detector.d.ts +61 -3
  163. package/dist/standalone.js +37619 -23570
  164. package/dist/webhook/ingest-accept.d.ts +70 -0
  165. package/dist/webhook/ingest-overflow-buffer.d.ts +35 -4
  166. package/dist/webhook/ingest-overflow-replayer.d.ts +50 -6
  167. package/dist/worker/in-memory-job-queue.d.ts +1 -1
  168. package/dist/ws/agent-handler.d.ts +31 -4
  169. package/dist/ws/dashboard-context-handler.d.ts +28 -4
  170. package/dist/ws/dashboard-global-workflows-handler.d.ts +36 -9
  171. package/dist/ws/execution-status-frame.d.ts +32 -0
  172. package/dist/ws/failure-messages.d.ts +2 -0
  173. package/dist/ws/git-credential-relay.d.ts +39 -0
  174. package/dist/ws/oidc-token-relay.d.ts +6 -11
  175. package/dist/ws/platform-client.d.ts +68 -9
  176. package/dist/ws/test-relay-handlers.d.ts +35 -10
  177. package/installer-image-digests.json +3 -3
  178. package/package.json +24 -19
  179. package/sbom.spdx.json +868 -821
  180. package/dist/approvals/team-membership-lookup.d.ts +0 -13
  181. package/dist/pipeline/inline-eval.d.ts +0 -44
  182. package/dist/providers/github/contributor-resolver.d.ts +0 -30
  183. package/dist/security/contributor-cache.d.ts +0 -83
@@ -3,10 +3,12 @@
3
3
  *
4
4
  * Manages the lifecycle: pending -> approved/rejected/expired.
5
5
  */
6
- import { Kysely } from 'kysely';
6
+ import { Kysely, type Transaction } from 'kysely';
7
7
  import { z } from 'zod';
8
8
  import { type ApprovalRequirement, type ApproverClause, type StepApprovalPayload, ApprovalDecision, HoldScope, TriggerSource } from '@kici-dev/engine';
9
9
  import type { Database, HeldRun, HeldRunApproval } from '../db/types.js';
10
+ /** A Kysely root handle or an in-flight transaction — query builders accept either. */
11
+ type Executor = Kysely<Database> | Transaction<Database>;
10
12
  /** Status values for held runs (held_runs table). */
11
13
  export declare enum HeldRunStatus {
12
14
  Pending = "pending",
@@ -17,7 +19,25 @@ export declare enum HeldRunStatus {
17
19
  }
18
20
  /**
19
21
  * Reason a run was held in the security queue. Persisted verbatim in
20
- * `held_runs.reason` and switched on by `buildSecurityHoldSummary`.
22
+ * `held_runs.reason` and whose vocabulary `buildSecurityHoldSummary` switches
23
+ * on.
24
+ *
25
+ * Each value names why a run sits in the queue. The enum stays whole because
26
+ * compiling code still names all four: `buildSecurityHoldSummary` renders one
27
+ * branch per value. Dropping a member breaks that, and breaks the parity test
28
+ * that pins `SECURITY_HOLD_JOB_IDS`' three policy-reason keys to this enum's
29
+ * options — the engine constant cannot import the enum, so that coupling lives
30
+ * only in the orchestrator's test. Nothing validates `held_runs.reason` against
31
+ * this enum, so a stored value is not rejected anywhere.
32
+ *
33
+ * - `fork_pr` — the org trust policy's fork switch held the run.
34
+ * - `context_trust` — a context's minimum-trust gate held the run.
35
+ * - `workflow_modification` — deprecated; no longer raised. Modifications to
36
+ * `.kici/` are surfaced on their own informational check and no longer feed
37
+ * a policy arm. Removed at v1.0.0.
38
+ * - `unknown_contributor` — deprecated; no longer raised. The policy turns on
39
+ * whether the pull request came from a fork, not on who opened it. Removed
40
+ * at v1.0.0.
21
41
  */
22
42
  export declare const SecurityHoldReason: z.ZodEnum<{
23
43
  context_trust: "context_trust";
@@ -37,6 +57,20 @@ export interface CreateHeldRunData {
37
57
  expiresAt: Date;
38
58
  /** Queue type: 'context' (default) or 'security'. */
39
59
  queueType?: 'context' | 'security';
60
+ /**
61
+ * Granularity of the held element. Omit to leave the column at its `'job'`
62
+ * default. The org trust policy's PR-wide hold passes `'workflow'`: it fires
63
+ * before any job is materialized and resumes by rebuilding the whole workflow
64
+ * dispatch, so `routeRelease` must send it to the workflow resume path.
65
+ */
66
+ scope?: HoldScope;
67
+ /**
68
+ * What triggered the hold. Omit to leave the column at its `'context'`
69
+ * default. Written explicitly by the trust-policy hold so its release signal
70
+ * carries the pair `routeRelease` discriminates on rather than relying on a
71
+ * column default to supply half of it.
72
+ */
73
+ triggerSource?: TriggerSource;
40
74
  }
41
75
  /**
42
76
  * Data required to create a generalized approval hold. Unlike the legacy
@@ -109,14 +143,57 @@ export interface ListHeldRunsOptions {
109
143
  export declare class HeldRunStore {
110
144
  private readonly db;
111
145
  constructor(db: Kysely<Database>);
112
- /** Create a new held run with pending status. */
113
- create(orgId: string, data: CreateHeldRunData): Promise<HeldRun>;
146
+ /**
147
+ * Create a new held run with pending status.
148
+ *
149
+ * `exec` is the executor the INSERT runs through, defaulting to the store's
150
+ * own connection. A caller that writes something the row cannot exist without
151
+ * — the job's pending dispatch context, without which the hold can never be
152
+ * resumed — passes its enclosing transaction, so the two land or roll back
153
+ * together. Handed in rather than taken from an ambient scope: Kysely has no
154
+ * such scope, so a `this.db` insert inside a `db.transaction()` callback runs
155
+ * on a different connection and commits on its own.
156
+ */
157
+ create(orgId: string, data: CreateHeldRunData, exec?: Executor): Promise<HeldRun>;
114
158
  /**
115
159
  * Create a generalized approval hold (workflow/job/step scope, explicit or
116
160
  * context trigger) carrying a normalized `ApprovalRequirement`. Returns
117
161
  * the created row.
162
+ *
163
+ * `exec` carries the same meaning it does on {@link create}.
164
+ */
165
+ createHold(orgId: string, data: CreateHoldData, exec?: Executor): Promise<HeldRun>;
166
+ /**
167
+ * Record that the pending `KiCI Security` check reached the provider, for
168
+ * every hold that gates it, so the settle that ends one knows it has a check
169
+ * to terminalize.
170
+ *
171
+ * Written AFTER the post returns, never before. The two orders fail
172
+ * differently and the failures are not equivalent: recording first and dying
173
+ * before the post leaves a row claiming a check the commit does not have, and
174
+ * the settle then CREATES one — a completed `KiCI Security` run appearing on a
175
+ * commit nothing ever held. Recording second leaves the opposite residue, a
176
+ * real pending check the settle declines to close, which is the same stuck
177
+ * check the fire-and-forget post could already produce. A fabricated failing
178
+ * check on a pull request is worse than a stuck one, so the write goes last.
179
+ *
180
+ * **One statement for all of them, not one per hold.** A commit's check run is
181
+ * shared by every hold on it, and the settle asks the contention query which
182
+ * of them still owns it. Marking them in a loop admits a PARTIAL mark: mark
183
+ * the reviewer hold, fail on the security hold, and the security row keeps
184
+ * `posted_pending_check: false` — so it is not counted as a contender, and
185
+ * approving the reviewer hold terminalizes the shared check `success` while
186
+ * the trust hold still gates the job. That is a fabricated PASSING check,
187
+ * which is the worse direction, reached without any process dying: a
188
+ * deadlock, a statement timeout or a lost connection between the two UPDATEs
189
+ * is enough. A single `WHERE id IN (…)` either marks every hold or none.
190
+ *
191
+ * The residual window is therefore one statement issued immediately after the
192
+ * provider call returns — narrow, and not only reachable by a process death,
193
+ * which is why the caller logs its failure rather than treating it as
194
+ * impossible.
118
195
  */
119
- createHold(orgId: string, data: CreateHoldData): Promise<HeldRun>;
196
+ markPendingCheckPosted(orgId: string, heldRunIds: readonly string[]): Promise<void>;
120
197
  /** INSERT one decision row using the given executor (root or transaction). */
121
198
  private insertDecisionRow;
122
199
  /** Flip a pending hold to 'approved' using the given executor. Undefined if not pending. */
@@ -190,20 +267,49 @@ export declare class HeldRunStore {
190
267
  */
191
268
  listOverdue(): Promise<HeldRun[]>;
192
269
  /**
193
- * Release overdue workflow timer holds. The install-gate wait action pauses
194
- * the workflow as a held run; on timer expiry it must RESUME (not fail like
195
- * a reviewer-hold expiry). Flips each overdue pending `hold_type` timer,
196
- * `hold_scope='workflow'` row to `released` and returns a `ReleaseSignal`
197
- * per row so the caller can resume the workflow. Runs BEFORE
198
- * `expireOverdue()` so these rows leave the pending pool before the
199
- * expire-and-fail sweep sees them.
270
+ * Release overdue timer holds at ANY scope. A wait action pauses its element
271
+ * as a held run; on timer expiry it must RESUME (not fail like a reviewer-hold
272
+ * expiry). Flips each overdue pending timer row to `released` and returns a
273
+ * `ReleaseSignal` per row, carrying the row's own scope so the caller can
274
+ * route it `routeRelease` sends a workflow-scoped one to the install-gate
275
+ * rebuild and a job-scoped one to the job re-dispatch path.
276
+ *
277
+ * Runs BEFORE `expireOverdue()` so these rows leave the pending pool before
278
+ * the expire-and-fail sweep sees them. That ordering is load-bearing, not
279
+ * incidental: `expireOverdue` is not scope-filtered, so a released-but-not-yet-
280
+ * resumed row would otherwise be expired out from under its resume.
200
281
  *
201
- * The filter matches every persisted spelling of the timer hold type, so a
202
- * row an un-upgraded orchestrator wrote as `wait_timer` still resumes rather
203
- * than falling through to the expire-and-fail sweep. `hold_scope` is what
204
- * keeps job-scoped dispatch-gate timer holds out of this sweep.
282
+ * The filter matches every persisted spelling of the timer hold type, so a row
283
+ * an un-upgraded orchestrator wrote as `wait_timer` still resumes rather than
284
+ * falling through to the expire-and-fail sweep. It deliberately does NOT
285
+ * filter on `hold_scope`: a job-scoped timer hold used to be excluded here,
286
+ * which left it with no release path at all — created, never released,
287
+ * eventually expired, its job never dispatched.
205
288
  */
206
289
  releaseDueWaitHolds(): Promise<ReleaseSignal[]>;
290
+ /**
291
+ * Every pending queued (concurrency) hold, with the org and concurrency group
292
+ * it belongs to — the input to the periodic release sweep, which needs to know
293
+ * WHICH groups have someone waiting before it looks up any limits.
294
+ *
295
+ * Returns the pair rather than full rows: the sweep only groups by it, and
296
+ * `listQueuedHoldsForContext` fetches the rows it actually releases.
297
+ */
298
+ listAllQueuedHolds(): Promise<Array<{
299
+ orgId: string | null;
300
+ concurrencyGroup: string | null;
301
+ }>>;
302
+ /**
303
+ * List the pending queued (concurrency) holds for one context's concurrency
304
+ * group, oldest first.
305
+ *
306
+ * Joined to `execution_runs` and filtered by `customer_id` as well as
307
+ * `context`: a context NAME is not unique across tenants, so without the org
308
+ * predicate one org's completing job could release another org's queued hold.
309
+ * Oldest-first is the release order — a queue that released newest-first would
310
+ * starve whoever waited longest.
311
+ */
312
+ listQueuedHoldsForContext(orgId: string, concurrencyGroup: string): Promise<HeldRun[]>;
207
313
  /**
208
314
  * Expire overdue pending runs. Called by the stale detector.
209
315
  * Sets status to 'expired' and resolved_at to now() for all
@@ -224,4 +330,5 @@ export declare function createHeldRunStoreFromUrl(databaseUrl: string, opts?: {
224
330
  store: HeldRunStore;
225
331
  dispose: () => Promise<void>;
226
332
  };
333
+ export {};
227
334
  //# sourceMappingURL=held-runs.d.ts.map
@@ -26,8 +26,9 @@ export declare function evaluateMultiContextGates(envs: ReadonlyArray<{
26
26
  }>, ctx: JobDispatchContext): ContextGateRejection[];
27
27
  /**
28
28
  * Aggregate hold/wait/queue parameters across all bound contexts, most
29
- * restrictive wins: trust = max tier, reviewers = sorted dedup union, wait timer
30
- * = max, hold expiry = min, concurrency limit = min (tightest). The concurrency
29
+ * restrictive wins: trust = strictest declared floor (see `TRUST_RANK` a
30
+ * wording choice, not a verdict), reviewers = sorted dedup union, wait timer =
31
+ * max, hold expiry = min, concurrency limit = min (tightest). The concurrency
31
32
  * strategy follows the primary (first) context.
32
33
  */
33
34
  export declare function aggregateProtectionParams(envs: ReadonlyArray<Context>): EffectiveProtection;
@@ -1,5 +1,20 @@
1
1
  import type { Context, ProtectionGateResult } from '@kici-dev/engine';
2
2
  import type { JobDispatchContext } from './pipeline.js';
3
+ /**
4
+ * The reason phrase for a branch-restricted context bound by an
5
+ * internally-triggered run that carries NO branch. Shared with the multi-context
6
+ * aggregator so the two reject paths cannot describe the same cause
7
+ * differently, and context-free because each caller names the context itself.
8
+ *
9
+ * An internally-triggered run usually does have a branch: a scheduled run
10
+ * presents its registration's default branch, and every other internal trigger
11
+ * inherits the branch of the run that emitted its event. Those runs are matched
12
+ * against the restriction patterns like any other. This phrase covers only the
13
+ * runs where neither source produced one — a registration whose default branch
14
+ * has never been captured, or an emitting run that is gone — so it names the
15
+ * remedy for that case rather than telling an operator to drop the restriction.
16
+ */
17
+ export declare const INTERNAL_TRIGGER_NO_BRANCH_DETAIL: string;
3
18
  /** Evaluate branch restrictions, trigger type filters, and repo patterns. */
4
19
  export declare function evaluateBranchGate(env: Context, ctx: JobDispatchContext): ProtectionGateResult;
5
20
  //# sourceMappingURL=branch-gate.d.ts.map
@@ -1,4 +1,10 @@
1
1
  import type { Context, ProtectionGateResult } from '@kici-dev/engine';
2
- /** Evaluate concurrency limits for the context. */
3
- export declare function evaluateConcurrencyGate(env: Context, currentRunningCount: number, _concurrencyGroup: string): ProtectionGateResult;
2
+ /**
3
+ * Evaluate concurrency limits for the context.
4
+ *
5
+ * Takes only the two fields it reads rather than a whole `Context`, so the
6
+ * ready-dispatch re-gate can call it with the limit and strategy it resolved
7
+ * from a run's bound context row. Every full `Context` still satisfies it.
8
+ */
9
+ export declare function evaluateConcurrencyGate(env: Pick<Context, 'concurrencyLimit' | 'concurrencyStrategy'>, currentRunningCount: number, _concurrencyGroup: string): ProtectionGateResult;
4
10
  //# sourceMappingURL=concurrency-gate.d.ts.map
@@ -12,6 +12,24 @@ export interface JobDispatchContext {
12
12
  repository: string;
13
13
  runId: string;
14
14
  jobId: string;
15
+ /**
16
+ * True when the run was triggered by the orchestrator itself (a schedule
17
+ * fire, a workflow/job completion, a failure batch, a `kiciEvent()`, an
18
+ * invoke-gate summon) rather than by a provider webhook.
19
+ *
20
+ * Such a run usually DOES carry a branch, and `branch` is then matched
21
+ * against the restriction patterns like any other run's: a schedule fire
22
+ * presents its registration's default branch, and every other internal
23
+ * trigger inherits the branch of the run that emitted its event.
24
+ *
25
+ * The flag matters only when `branch` is EMPTY — a failure batch or a scaler
26
+ * event (many runs behind it, or none), a registration whose default branch
27
+ * has never been captured, an emitting run that is gone. The branch gate then
28
+ * rejects naming that cause, instead of quoting the empty value as a branch
29
+ * name an operator could add to the restriction list. It never weakens the
30
+ * gate: a run with no branch cannot satisfy a restriction, `*` included.
31
+ */
32
+ internallyTriggered?: boolean;
15
33
  }
16
34
  /** Evaluate all protection rules for a context. */
17
35
  export declare function evaluateProtectionRules(env: Context, ctx: JobDispatchContext, currentRunningCount: number, concurrencyGroup: string, trustTier?: TrustTier): Promise<ProtectionGateResult>;
@@ -0,0 +1,35 @@
1
+ import type { Kysely } from 'kysely';
2
+ import type { Database } from '../db/types.js';
3
+ import type { HeldRunStore, ReleaseSignal } from './held-runs.js';
4
+ export interface ReleaseQueuedHoldsArgs {
5
+ db: Kysely<Database>;
6
+ heldRunStore: Pick<HeldRunStore, 'listQueuedHoldsForContext' | 'release'>;
7
+ orgId: string;
8
+ /** The context's concurrency group — `execution_runs.context`. */
9
+ concurrencyGroup: string;
10
+ /** The context's configured limit; `null`/`undefined` means unlimited. */
11
+ concurrencyLimit: number | null | undefined;
12
+ /** Resume a released hold by re-dispatching its job. */
13
+ onJobRelease: (signal: ReleaseSignal) => Promise<void>;
14
+ }
15
+ /**
16
+ * Count the jobs OCCUPYING a slot in a concurrency group, scoped to one org.
17
+ *
18
+ * A job occupies its slot from the moment it is dispatched until it reaches a
19
+ * terminal status — not merely while its status is `running`. Counting only
20
+ * `running` missed every job that had been dispatched but had not yet reported
21
+ * back, so the sweep read a full group as empty and released queued holds while
22
+ * their slots were still taken. That is a real over-admission, not a cosmetic
23
+ * one: the release path re-checks the limit precisely so the bound holds
24
+ * whenever the sweep happens to run, and an undercount defeats that re-check.
25
+ *
26
+ * The `customer_id` predicate is not optional: a context name shared across
27
+ * tenants would otherwise leak concurrency between them.
28
+ */
29
+ export declare function countOccupyingJobs(db: Kysely<Database>, orgId: string, concurrencyGroup: string): Promise<number>;
30
+ /**
31
+ * Release up to `limit - running` queued holds for a group, oldest first.
32
+ * Returns how many actually resumed.
33
+ */
34
+ export declare function releaseQueuedHolds(args: ReleaseQueuedHoldsArgs): Promise<number>;
35
+ //# sourceMappingURL=release-queued-holds.d.ts.map
@@ -50,7 +50,9 @@ export declare function baseAttestationsQuery(db: Kysely<Database>): import("kys
50
50
  join_tokens: import("../db/types.js").JoinTokenTable;
51
51
  kici_events: import("../db/types.js").KiciEventTable;
52
52
  orchestrator_signing_keys: import("../db/types.js").OrchestratorSigningKeysTable;
53
+ org_plan_headroom: import("../db/types.js").OrgPlanHeadroomTable;
53
54
  org_settings: import("../db/types.js").OrgSettingsTable;
55
+ org_trust_directory: import("../db/types.js").OrgTrustDirectoryTable;
54
56
  org_trust_policy: import("../db/types.js").OrgTrustPolicyTable;
55
57
  pending_attestations: import("../db/types.js").PendingAttestationsTable;
56
58
  pending_job_contexts: import("../db/types.js").PendingJobContextsTable;
@@ -62,6 +64,8 @@ export declare function baseAttestationsQuery(db: Kysely<Database>): import("kys
62
64
  run_ephemeral_keys: import("../db/types.js").RunEphemeralKeysTable;
63
65
  run_secret_outputs: import("../db/types.js").RunSecretOutputsTable;
64
66
  scaler_agent_jobs: import("../db/types.js").ScalerAgentJobsTable;
67
+ scaler_pending_claims: import("../db/types.js").ScalerPendingClaimsTable;
68
+ scaler_provision_outcomes: import("../db/types.js").ScalerProvisionOutcomesTable;
65
69
  scaler_reservations: import("../db/types.js").ScalerReservationsTable;
66
70
  scaler_spawning_agents: import("../db/types.js").ScalerSpawningAgentsTable;
67
71
  scoped_secrets: import("../db/types.js").ScopedSecretsTable;
@@ -121,7 +125,9 @@ export declare function basePendingAttestationsQuery(db: Kysely<Database>): impo
121
125
  join_tokens: import("../db/types.js").JoinTokenTable;
122
126
  kici_events: import("../db/types.js").KiciEventTable;
123
127
  orchestrator_signing_keys: import("../db/types.js").OrchestratorSigningKeysTable;
128
+ org_plan_headroom: import("../db/types.js").OrgPlanHeadroomTable;
124
129
  org_settings: import("../db/types.js").OrgSettingsTable;
130
+ org_trust_directory: import("../db/types.js").OrgTrustDirectoryTable;
125
131
  org_trust_policy: import("../db/types.js").OrgTrustPolicyTable;
126
132
  pending_attestations: import("../db/types.js").PendingAttestationsTable;
127
133
  pending_job_contexts: import("../db/types.js").PendingJobContextsTable;
@@ -133,6 +139,8 @@ export declare function basePendingAttestationsQuery(db: Kysely<Database>): impo
133
139
  run_ephemeral_keys: import("../db/types.js").RunEphemeralKeysTable;
134
140
  run_secret_outputs: import("../db/types.js").RunSecretOutputsTable;
135
141
  scaler_agent_jobs: import("../db/types.js").ScalerAgentJobsTable;
142
+ scaler_pending_claims: import("../db/types.js").ScalerPendingClaimsTable;
143
+ scaler_provision_outcomes: import("../db/types.js").ScalerProvisionOutcomesTable;
136
144
  scaler_reservations: import("../db/types.js").ScalerReservationsTable;
137
145
  scaler_spawning_agents: import("../db/types.js").ScalerSpawningAgentsTable;
138
146
  scoped_secrets: import("../db/types.js").ScopedSecretsTable;
@@ -1,16 +1,3 @@
1
- /**
2
- * Dashboard handler for the orchestrator.
3
- *
4
- * Responds to dashboard.* and run.* WS messages from Platform by querying the local
5
- * execution_jobs and execution_steps tables and reading logs from LogStorage.
6
- *
7
- * Supported messages:
8
- * - dashboard.run.detail: returns jobs with nested steps for a run
9
- * - dashboard.step.logs: returns log lines for a specific step
10
- * - dashboard.payload: returns the original webhook payload for a run
11
- * - run.rerun.request: re-runs a completed workflow run
12
- * - run.cancel.request: cancels a running workflow run
13
- */
14
1
  import { type Kysely } from 'kysely';
15
2
  import { type ColdStore } from '@kici-dev/shared';
16
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';
@@ -125,16 +112,12 @@ interface DashboardHandlerDeps {
125
112
  */
126
113
  eventStore?: EventStore | null;
127
114
  /**
128
- * **Test-only.** Master switch for fault-injection knobs. When false the
129
- * handler ignores every test-only knob below even if it is set.
115
+ * **Test-only fault injection**, supplied only by the build-time test double:
116
+ * `handleRerunRequest` awaits this hook before invoking `onRerun`, so an HA
117
+ * E2E can force a slow first coordinator and trigger a relay failover.
118
+ * Undefined (the shipped default) means no delay.
130
119
  */
131
- testMode?: boolean;
132
- /**
133
- * **Test-only.** When set (and `testMode` is true), `handleRerunRequest`
134
- * sleeps this many ms before invoking `onRerun`, so an HA E2E can force a
135
- * slow first coordinator and trigger a relay failover. Ignored in production.
136
- */
137
- testRerunDelayMs?: number;
120
+ beforeRerun?: () => Promise<void>;
138
121
  }
139
122
  export declare class DashboardHandler {
140
123
  private readonly db;
@@ -153,8 +136,7 @@ export declare class DashboardHandler {
153
136
  private readonly eventStore;
154
137
  private readonly retryAttestations;
155
138
  private readonly provenanceSigningIssuer;
156
- private readonly testMode;
157
- private readonly testRerunDelayMs;
139
+ private readonly beforeRerun;
158
140
  constructor(deps: DashboardHandlerDeps);
159
141
  /**
160
142
  * Update the bound orgId + routingKey. Called from server.ts after resolving
@@ -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=109_cluster_settings_cache_knobs.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=110_cluster_settings_global_eval_knobs.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=111_cluster_settings_global_eval_wait.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=112_execution_runs_workflow_repo.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add the partial index `idx_execution_runs_workflow_repo` on
4
+ * `execution_runs (workflow_repo_identifier) WHERE workflow_repo_identifier IS NOT NULL`.
5
+ *
6
+ * Matching a workflow registration to its runs keys on the repository that
7
+ * DEFINES the workflow — `workflow_repo_identifier ?? repo_identifier` — which
8
+ * the orchestrator expresses as
9
+ * `workflow_repo_identifier IN (…) OR (workflow_repo_identifier IS NULL AND repo_identifier IN (…))`
10
+ * (`registration/registration-run-match.ts`). The second arm rides
11
+ * `idx_execution_runs_repo` from migration 001; the first arm had no index at
12
+ * all, because migration 112 added the column without one. A planner cannot
13
+ * use an index for only half a disjunction, so the whole predicate degraded to
14
+ * a sequential scan over a table that grows with every run — on
15
+ * `dashboard.registrations.list`, which runs its grouped MAX on every list
16
+ * request.
17
+ *
18
+ * With both arms indexed the planner can BitmapOr them.
19
+ *
20
+ * Partial by design, and the partiality is what makes it cheap: the column is
21
+ * non-null only for a cross-repository organization-wide run, a small minority
22
+ * of rows, so the index stays a fraction of the table's size and skips every
23
+ * per-repository run. It also matches the predicate exactly — the first arm
24
+ * can never match a NULL row, since `NULL IN (…)` is never true.
25
+ *
26
+ * Idempotent: `IF NOT EXISTS` makes a re-run 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=113_execution_runs_workflow_repo_index.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=114_ingest_queue_claim.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<unknown>): Promise<void>;
3
+ /**
4
+ * Restores the org column with its original NOT NULL DEFAULT false. A rollback
5
+ * cannot recover the per-org values the up-migration dropped — they are gone —
6
+ * so every org comes back at the opt-in default.
7
+ */
8
+ export declare function down(db: Kysely<unknown>): Promise<void>;
9
+ //# sourceMappingURL=115_global_workflows_cluster_switch.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ export declare function up(db: Kysely<any>): Promise<void>;
3
+ export declare function down(db: Kysely<any>): Promise<void>;
4
+ //# sourceMappingURL=116_org_plan_headroom.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=117_invoke_gate_proxy_jobs.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=118_invoke_gate_scheduling.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=119_scaler_ha_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=120_cluster_settings_scaler_reaper.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `org_settings.allow_untrusted_dockerfile_builds boolean NOT NULL DEFAULT false`.
4
+ *
5
+ * A job may build its container image from a Dockerfile in the repository. That
6
+ * build runs arbitrary `RUN` commands on the agent host's daemon, OUTSIDE the
7
+ * hardened posture the job's own steps get (`CapDrop: ALL`, no-new-privileges,
8
+ * pids/memory/CPU caps) — a build cannot be capability-restricted the way a
9
+ * container run can.
10
+ *
11
+ * So the default is deny for an untrusted ref (a fork PR, an unresolved
12
+ * contributor — the same classification the cache write scope uses). An operator
13
+ * who wants fork PRs building their own images turns it on per org, deliberately.
14
+ *
15
+ * Idempotent: a re-run on a DB that already has the column is a no-op.
16
+ */
17
+ export declare function up(db: Kysely<unknown>): Promise<void>;
18
+ export declare function down(db: Kysely<unknown>): Promise<void>;
19
+ //# sourceMappingURL=121_org_settings_allow_untrusted_dockerfile_builds.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `host_roster.scaler_managed boolean NOT NULL DEFAULT false`.
4
+ *
5
+ * `runsOnAll` fans a job out across the declared fleet. Every registering agent
6
+ * upserts a roster row, auto-scaler-spawned ones included, so a pre-spawned
7
+ * warm agent was a valid fan-out target — and a child pinned to it runs at the
8
+ * pool's fixed shape rather than its own. This column records the one fact that
9
+ * separates the two populations: whether a scaler backend spawned the agent.
10
+ *
11
+ * It is written from the scaler manager's registration lookup (a spawn record
12
+ * exists for the agent id), NOT from `lifecycle_class`. `lifecycle_class`
13
+ * snapshots the auth TOKEN's type and is `ephemeral` for every agent when the
14
+ * auth mode is `none`, so it cannot distinguish a fleet host from a scaler
15
+ * agent in that mode.
16
+ *
17
+ * DEFAULT false is load-bearing: a row written before this migration must read
18
+ * as not-scaler-managed so an existing fleet host stays a fan-out target
19
+ * immediately, without waiting to re-register.
20
+ *
21
+ * Idempotent: a re-run on a DB that already has the column is a no-op.
22
+ */
23
+ export declare function up(db: Kysely<unknown>): Promise<void>;
24
+ export declare function down(db: Kysely<unknown>): Promise<void>;
25
+ //# sourceMappingURL=122_host_roster_scaler_managed.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `workflow_registrations.default_branch text` (nullable).
4
+ *
5
+ * A `__schedule_fire` run executes the default branch's lock file, so the
6
+ * default branch IS that run's branch — which is what a branch-restricted
7
+ * context needs in order to accept it. The value is already computed at
8
+ * registration time from the webhook payload (the default-branch-push check),
9
+ * it was simply never persisted, so a scheduled run had no branch to present.
10
+ *
11
+ * NULLABLE with no default, deliberately. The default branch is knowable only
12
+ * from a webhook payload, so there is nothing to backfill a pre-existing row
13
+ * with: a registration written before this migration reads NULL until its
14
+ * repo's next default-branch push re-registers it. The dispatch path reads NULL
15
+ * as "no branch" and the context branch gate then rejects with its honest
16
+ * named-cause verdict — a DEFAULT would instead invent a branch the
17
+ * registration never proved, which is exactly the confusion this whole column
18
+ * exists to end.
19
+ *
20
+ * Idempotent: a re-run on a DB that already has the column is a no-op.
21
+ */
22
+ export declare function up(db: Kysely<unknown>): Promise<void>;
23
+ export declare function down(db: Kysely<unknown>): Promise<void>;
24
+ //# sourceMappingURL=123_workflow_registrations_default_branch.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=124_cluster_settings_provision_backoff.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Create `org_trust_directory` — the orchestrator's cache of the Platform-owned
4
+ * approval directory pushed alongside the policy on `trust_policy.update`:
5
+ * identity links, per-member CI trust levels, and team memberships.
6
+ *
7
+ * A sibling of `org_trust_policy` rather than more columns on it: the policy is
8
+ * four scalar switches, while these three are structured documents the Platform
9
+ * replaces wholesale on every push — `identity_links` and `team_memberships`
10
+ * are arrays, `member_ci_trust` is a user-id-keyed map — so they are stored as
11
+ * JSONB.
12
+ *
13
+ * Persisting rather than holding them only in memory is what lets
14
+ * `/kici approve` authorize a commenter after a restart. Without a cached
15
+ * directory the orchestrator cannot map a comment author onto a KiCI user at
16
+ * all until the Platform's next push lands, so every approval is refused in the
17
+ * meantime.
18
+ *
19
+ * Wherever a Platform is attached it is the only writer of this row. An
20
+ * independent orchestrator has no Platform, so there the operator writes it
21
+ * through `kici-admin trust-policy directory-set`. The two are mutually
22
+ * exclusive — the admin route refuses the local write on any Platform-attached
23
+ * orchestrator — so a deployment still only ever has one writer, and there is
24
+ * no counterpart to `org_trust_policy.source` to record which it was.
25
+ *
26
+ * Idempotent: guarded by IF NOT EXISTS, so a 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=125_org_trust_directory.d.ts.map
@@ -0,0 +1,28 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Add `held_runs.posted_pending_check boolean` — whether this hold's pending
4
+ * `KiCI Security` check actually reached the provider.
5
+ *
6
+ * `postCheckStatus` CREATES the named check run when it finds none, so
7
+ * terminalizing a check the hold never posted does not close anything: it puts
8
+ * a completed `KiCI Security` run on a commit that had none. Whether a hold
9
+ * posted one was derived from the row's SHAPE, which answers what the code
10
+ * INTENDED — a post that the provider refused, or that no check poster was in
11
+ * reach to attempt, leaves a shape that says "posted" and a commit that has
12
+ * nothing. The column records what happened instead of what was meant.
13
+ *
14
+ * Nullable, with no default, and the three values are distinct:
15
+ *
16
+ * - `true` — the post returned successfully. The hold owns the check.
17
+ * - `false` — no post was attempted, or one was attempted and failed. Nothing
18
+ * to terminalize; a settle would fabricate.
19
+ * - `null` — the row predates this column, so nothing recorded either way. The
20
+ * shape derivation still answers for it. A `false` DEFAULT would instead
21
+ * declare every hold pending at deploy time un-posted and strand the checks
22
+ * they really do have.
23
+ *
24
+ * Idempotent: a re-run on a DB that already has the column is a no-op.
25
+ */
26
+ export declare function up(db: Kysely<unknown>): Promise<void>;
27
+ export declare function down(db: Kysely<unknown>): Promise<void>;
28
+ //# sourceMappingURL=126_held_runs_posted_pending_check.d.ts.map