@kici-dev/orchestrator 0.5.0 → 0.6.1

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 (149) 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 +23 -0
  4. package/dist/agent/dispatcher.d.ts +81 -13
  5. package/dist/agent/host-roster.d.ts +37 -5
  6. package/dist/agent/registry.d.ts +2 -0
  7. package/dist/app.d.ts +33 -6
  8. package/dist/approvals/apply-decision.d.ts +67 -19
  9. package/dist/approvals/held-run-release-wiring.d.ts +45 -0
  10. package/dist/approvals/independent-wiring.d.ts +55 -0
  11. package/dist/approvals/resume-router.d.ts +9 -0
  12. package/dist/approvals/triggerer-subject.d.ts +37 -0
  13. package/dist/cache/dep-cache.d.ts +54 -10
  14. package/dist/cache/global-eval-round-cache.d.ts +7 -0
  15. package/dist/cli/api-client.d.ts +18 -0
  16. package/dist/cli/commands/cluster-settings.d.ts +11 -0
  17. package/dist/cli/commands/diagnose.d.ts +6 -0
  18. package/dist/cli/commands/held-run.d.ts +58 -0
  19. package/dist/cli/commands/trust-policy.d.ts +117 -12
  20. package/dist/cli/kici-admin.d.ts +10 -0
  21. package/dist/cli.js +2272 -1025
  22. package/dist/cluster/cluster-identity.d.ts +3 -3
  23. package/dist/cluster/cluster-settings-reader.d.ts +7 -1
  24. package/dist/cluster/coordinator.d.ts +44 -0
  25. package/dist/cluster/index.d.ts +4 -0
  26. package/dist/cluster/peer-handler.d.ts +19 -0
  27. package/dist/cluster/peer-registry.d.ts +17 -0
  28. package/dist/cluster/plan-headroom-store.d.ts +26 -0
  29. package/dist/cluster/worker-eviction.d.ts +69 -0
  30. package/dist/cold-store/load-event-log-range.d.ts +10 -3
  31. package/dist/cold-store/load-secret-audit-log-range.d.ts +4 -3
  32. package/dist/cold-store/tables/secret-audit-log.d.ts +4 -3
  33. package/dist/config.d.ts +21 -21
  34. package/dist/contexts/held-runs.d.ts +123 -16
  35. package/dist/contexts/protection/aggregate.d.ts +3 -2
  36. package/dist/contexts/protection/branch-gate.d.ts +15 -0
  37. package/dist/contexts/protection/concurrency-gate.d.ts +8 -2
  38. package/dist/contexts/protection/pipeline.d.ts +18 -0
  39. package/dist/contexts/release-queued-holds.d.ts +35 -0
  40. package/dist/dashboard/attestation-filters.d.ts +8 -0
  41. package/dist/dashboard/handler.d.ts +6 -24
  42. package/dist/db/migrations/116_org_plan_headroom.d.ts +4 -0
  43. package/dist/db/migrations/117_invoke_gate_proxy_jobs.d.ts +4 -0
  44. package/dist/db/migrations/118_invoke_gate_scheduling.d.ts +4 -0
  45. package/dist/db/migrations/119_scaler_ha_ownership.d.ts +4 -0
  46. package/dist/db/migrations/120_cluster_settings_scaler_reaper.d.ts +4 -0
  47. package/dist/db/migrations/121_org_settings_allow_untrusted_dockerfile_builds.d.ts +19 -0
  48. package/dist/db/migrations/122_host_roster_scaler_managed.d.ts +25 -0
  49. package/dist/db/migrations/123_workflow_registrations_default_branch.d.ts +24 -0
  50. package/dist/db/migrations/124_cluster_settings_provision_backoff.d.ts +4 -0
  51. package/dist/db/migrations/125_org_trust_directory.d.ts +30 -0
  52. package/dist/db/migrations/126_held_runs_posted_pending_check.d.ts +28 -0
  53. package/dist/db/migrations/127_org_trust_policy_approval_expiry_seconds.d.ts +26 -0
  54. package/dist/db/migrations/128_execution_runs_global_eval_round.d.ts +23 -0
  55. package/dist/db/migrations/129_execution_runs_dispatch_routing_key.d.ts +24 -0
  56. package/dist/db/migrations/130_scaler_provision_outcomes.d.ts +32 -0
  57. package/dist/db/types.d.ts +368 -10
  58. package/dist/entry-helpers.d.ts +28 -0
  59. package/dist/events/event-emitter.d.ts +22 -0
  60. package/dist/events/event-router.d.ts +87 -1
  61. package/dist/events/types.d.ts +2 -23
  62. package/dist/git/credential-broker.d.ts +94 -0
  63. package/dist/git/inherited-secret.d.ts +24 -0
  64. package/dist/git/installation-token.d.ts +38 -0
  65. package/dist/git/job-context.d.ts +13 -0
  66. package/dist/index.js +324 -84
  67. package/dist/metrics/agent-metrics-aggregator.d.ts +2 -2
  68. package/dist/metrics/prometheus.d.ts +111 -3
  69. package/dist/oidc/oidc-mint-registration.d.ts +7 -3
  70. package/dist/orchestrator-core.d.ts +79 -23
  71. package/dist/pipeline/direct-ingress-deps.d.ts +100 -0
  72. package/dist/pipeline/dispatch-matched-workflow.d.ts +302 -31
  73. package/dist/pipeline/global-eval-round.d.ts +14 -0
  74. package/dist/pipeline/internal-event-pipeline.d.ts +140 -0
  75. package/dist/pipeline/invoke-gate.d.ts +164 -0
  76. package/dist/pipeline/needs-scheduler.d.ts +13 -0
  77. package/dist/pipeline/process-webhook.d.ts +119 -31
  78. package/dist/pipeline/processor.d.ts +226 -21
  79. package/dist/pipeline/rerun.d.ts +21 -0
  80. package/dist/pipeline/resume-workflow.d.ts +40 -7
  81. package/dist/pipeline/route-or-dispatch-jobs.d.ts +9 -0
  82. package/dist/pipeline/security-hold-check.d.ts +217 -0
  83. package/dist/pipeline/undispatched-hold-checks.d.ts +23 -0
  84. package/dist/policy/dashboard-write-policy-listener.d.ts +62 -0
  85. package/dist/policy/dashboard-write-policy.d.ts +14 -0
  86. package/dist/provider-registry.d.ts +10 -2
  87. package/dist/providers/github/check-status-poster.d.ts +11 -0
  88. package/dist/providers/github/index.d.ts +0 -2
  89. package/dist/providers/github/normalizer.d.ts +3 -2
  90. package/dist/providers/local/normalizer.d.ts +3 -5
  91. package/dist/providers/universal-git/index.d.ts +11 -2
  92. package/dist/queue/job-queue.d.ts +43 -1
  93. package/dist/registration/extractor.d.ts +3 -3
  94. package/dist/registration/registration-index.d.ts +7 -0
  95. package/dist/registration/registration-store.d.ts +22 -0
  96. package/dist/reporting/check-run-reporter.d.ts +94 -1
  97. package/dist/reporting/check-run-summary.d.ts +25 -1
  98. package/dist/reporting/execution-tracker.d.ts +207 -2
  99. package/dist/reporting/run-aggregator.d.ts +4 -14
  100. package/dist/reporting/step-display-order.d.ts +43 -0
  101. package/dist/routes/admin-held-runs.d.ts +142 -0
  102. package/dist/routes/admin-trust-policy.d.ts +34 -6
  103. package/dist/routes/admin.d.ts +9 -0
  104. package/dist/scaler/backend-factory.d.ts +55 -0
  105. package/dist/scaler/bare-metal-backend.d.ts +43 -5
  106. package/dist/scaler/claim-store.d.ts +119 -0
  107. package/dist/scaler/config.d.ts +4 -0
  108. package/dist/scaler/container-backend.d.ts +18 -4
  109. package/dist/scaler/container-routing.d.ts +23 -0
  110. package/dist/scaler/container-spawn.d.ts +28 -0
  111. package/dist/scaler/event-backend.d.ts +124 -0
  112. package/dist/scaler/event-provision-reaper.d.ts +350 -0
  113. package/dist/scaler/failure-tracker.d.ts +1 -1
  114. package/dist/scaler/firecracker-backend.d.ts +33 -6
  115. package/dist/scaler/index.d.ts +11 -1
  116. package/dist/scaler/label-matcher.d.ts +4 -3
  117. package/dist/scaler/manager.d.ts +899 -72
  118. package/dist/scaler/resolve-container-auth.d.ts +45 -0
  119. package/dist/scaler/scaler-events.d.ts +11 -0
  120. package/dist/scaler/scaler-state-store.d.ts +294 -10
  121. package/dist/scaler/types.d.ts +131 -13
  122. package/dist/scaler/warm-pool.d.ts +132 -29
  123. package/dist/security/comment-handler.d.ts +50 -11
  124. package/dist/security/identity-link.d.ts +60 -0
  125. package/dist/security/lock-source.d.ts +11 -13
  126. package/dist/security/reduced-privilege-note.d.ts +59 -0
  127. package/dist/security/trust-directory-store.d.ts +233 -0
  128. package/dist/security/trust-policy-gate.d.ts +94 -59
  129. package/dist/security/trust-policy-store.d.ts +3 -0
  130. package/dist/security/trust-resolver.d.ts +14 -98
  131. package/dist/server.d.ts +11 -1
  132. package/dist/server.js +17684 -7351
  133. package/dist/stale-detector/gate-deadline-detector.d.ts +52 -0
  134. package/dist/stale-detector/stale-run-detector.d.ts +61 -3
  135. package/dist/standalone.js +24238 -13822
  136. package/dist/worker/in-memory-job-queue.d.ts +1 -1
  137. package/dist/ws/agent-handler.d.ts +28 -4
  138. package/dist/ws/dashboard-context-handler.d.ts +28 -4
  139. package/dist/ws/dashboard-global-workflows-handler.d.ts +6 -0
  140. package/dist/ws/failure-messages.d.ts +2 -0
  141. package/dist/ws/git-credential-relay.d.ts +39 -0
  142. package/dist/ws/oidc-token-relay.d.ts +6 -11
  143. package/dist/ws/platform-client.d.ts +54 -9
  144. package/installer-image-digests.json +3 -3
  145. package/package.json +24 -19
  146. package/sbom.spdx.json +864 -822
  147. package/dist/approvals/team-membership-lookup.d.ts +0 -13
  148. package/dist/providers/github/contributor-resolver.d.ts +0 -30
  149. package/dist/security/contributor-cache.d.ts +0 -83
@@ -1,5 +1,16 @@
1
1
  import type { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely';
2
2
  import type { ApprovalRequirement, ApproverClause, InitFailure, StepApprovalPayload } from '@kici-dev/engine';
3
+ /**
4
+ * Job kind stored in `execution_jobs.job_kind`. `Standard` runs steps on an
5
+ * agent; `Gate` is an invoke gate that summons source-repo runs; `Proxy`
6
+ * mirrors one summoned run's lifecycle. Mirrors the engine wire `JobKind` enum
7
+ * (`@kici-dev/engine`) — keep the two vocabularies in step.
8
+ */
9
+ export declare enum JobKind {
10
+ Standard = "standard",
11
+ Gate = "gate",
12
+ Proxy = "proxy"
13
+ }
3
14
  /**
4
15
  * PostgreSQL-only database types.
5
16
  * Column names use snake_case matching the actual database column names.
@@ -39,6 +50,8 @@ export interface Database {
39
50
  join_tokens: JoinTokenTable;
40
51
  org_settings: OrgSettingsTable;
41
52
  org_trust_policy: OrgTrustPolicyTable;
53
+ org_trust_directory: OrgTrustDirectoryTable;
54
+ org_plan_headroom: OrgPlanHeadroomTable;
42
55
  cluster_settings: ClusterSettingsTable;
43
56
  execution_job_needs: ExecutionJobNeedsTable;
44
57
  pending_job_contexts: PendingJobContextsTable;
@@ -51,6 +64,8 @@ export interface Database {
51
64
  scaler_spawning_agents: ScalerSpawningAgentsTable;
52
65
  scaler_agent_jobs: ScalerAgentJobsTable;
53
66
  scaler_reservations: ScalerReservationsTable;
67
+ scaler_pending_claims: ScalerPendingClaimsTable;
68
+ scaler_provision_outcomes: ScalerProvisionOutcomesTable;
54
69
  attestations: AttestationsTable;
55
70
  orchestrator_signing_keys: OrchestratorSigningKeysTable;
56
71
  dashboard_encryption_keys: DashboardEncryptionKeysTable;
@@ -406,7 +421,26 @@ export interface ExecutionRunTable {
406
421
  provider: string;
407
422
  /** Repository identifier (e.g. "owner/repo") */
408
423
  repo_identifier: string;
409
- /** Git ref (branch/tag) */
424
+ /**
425
+ * The branch (or tag) the run PRESENTS — `event.targetBranch`: the branch a
426
+ * push landed on, the base branch of a pull request, the default branch a
427
+ * schedule fire executes, the branch an internal trigger inherited.
428
+ *
429
+ * It is NOT a job's checkout ref. A pull-request job checks out the PR HEAD
430
+ * branch, and every `QueuedJobInput.ref` carries that value instead — the two
431
+ * are different facts and only one of them belongs here. The distinction is
432
+ * load-bearing: this column is what an internally-triggered run inherits as
433
+ * its branch claim before the context branch gate matches it against a
434
+ * context's `branchRestrictions`, and a fork contributor names the head
435
+ * branch freely. Every writer that CREATES the row uses the presented branch.
436
+ * The two reroute projections (`cluster/coordinator.ts`, `worker-core.ts`)
437
+ * are the exception: they insert from a `job.reroute` message, which carries
438
+ * only the job's ref. Their row is fail-safe by conflicting — the run is
439
+ * registered before the first job is handed to an agent
440
+ * (`startRunBeforeDispatch`), so a reroute is only possible once the
441
+ * authoritative row exists, and their insert is
442
+ * `ON CONFLICT (run_id) DO NOTHING`.
443
+ */
410
444
  ref: string;
411
445
  /** Git commit SHA */
412
446
  sha: string;
@@ -491,6 +525,35 @@ export interface ExecutionRunTable {
491
525
  * repository that defines it rather than from the one it ran against.
492
526
  */
493
527
  workflow_repo_identifier: string | null;
528
+ /**
529
+ * True when this row records a global evaluation round rather than a
530
+ * workflow.
531
+ *
532
+ * A round decides which organization-wide workflows apply to an event; a
533
+ * round that fails is recorded as one errored run so the suppression is
534
+ * visible. Re-running such a run re-executes the evaluation, not a workflow,
535
+ * so the re-run path branches on this column. It is structural on purpose:
536
+ * the round job's `__globaleval__` name prefix is a string a customer
537
+ * workflow may also carry, and a name a customer chooses must not decide
538
+ * which code path a re-run takes.
539
+ */
540
+ is_global_eval_round: Generated<boolean>;
541
+ /**
542
+ * The source whose credentials `provider_context` holds, when that is not the
543
+ * source the event arrived on.
544
+ *
545
+ * `routing_key` records the INBOUND source. For a cross-provider global
546
+ * workflow the lock file resolves through another source's bundle, and the
547
+ * context is written from that source's credentials — so anything pairing
548
+ * `routing_key` with `provider_context` hands one source's credentials to
549
+ * another source's API client. NULL means the two are the same, which is true
550
+ * of every ordinary run.
551
+ *
552
+ * Read by the rerun path of a failed evaluation round, which re-drives the
553
+ * organization-wide pass and has to hand it the same dispatch pair the
554
+ * delivery used.
555
+ */
556
+ dispatch_routing_key: string | null;
494
557
  /** Human-readable reason why the run failed (null for non-failed runs). */
495
558
  failure_reason: string | null;
496
559
  /**
@@ -529,6 +592,23 @@ export interface ExecutionRunTable {
529
592
  archived_at: Date | null;
530
593
  /** S3 object key of the chunk that carried this row; see `archived_at`. */
531
594
  archive_object_key: string | null;
595
+ /**
596
+ * For a run summoned by an invoke gate, the summoning (global) run's id. NULL
597
+ * for every run not summoned by a gate.
598
+ */
599
+ summoned_by_run_id: string | null;
600
+ /**
601
+ * For a summoned run, the proxy job name in the summoning run to update when
602
+ * this run completes. NULL for every run not summoned by a gate.
603
+ */
604
+ summoned_by_proxy_job: string | null;
605
+ /**
606
+ * How deep this run sits in an invoke chain. A webhook-triggered run is depth
607
+ * 0; a run summoned by an invoke gate carries its summoner's depth + 1. Read
608
+ * back when this run fires its own invoke gate so the chain-depth circuit
609
+ * breaker bounds recursion. Defaults to 0.
610
+ */
611
+ chain_depth: Generated<number>;
532
612
  }
533
613
  /**
534
614
  * Execution job table
@@ -552,8 +632,11 @@ export interface ExecutionJobTable {
552
632
  * or scaler backend appears. NULL whenever the job is routable.
553
633
  */
554
634
  routing_reason: ColumnType<string | null, string | null | undefined, string | null>;
555
- /** Matrix values JSON (e.g. {"node": "18"}) */
556
- matrix_values: string | null;
635
+ /**
636
+ * Matrix values JSON (e.g. {"node": "18"}). JSONB: the driver returns a parsed
637
+ * object on SELECT, while writers pass a `JSON.stringify` string.
638
+ */
639
+ matrix_values: ColumnType<Record<string, unknown> | null, string | null, string | null>;
557
640
  /** Agent ID that ran this job */
558
641
  agent_id: string | null;
559
642
  /** When the job started */
@@ -578,8 +661,12 @@ export interface ExecutionJobTable {
578
661
  * context, agent spawn). NULL for normal runs.
579
662
  */
580
663
  init_failure: ColumnType<InitFailure | null, unknown, unknown>;
581
- /** Labels used for agent routing (e.g. ["kici:os:linux", "kici:arch:x64"]). JSONB. */
582
- runs_on_labels: string | null;
664
+ /**
665
+ * Labels used for agent routing (e.g. ["kici:os:linux", "kici:arch:x64"]). JSONB:
666
+ * the driver returns a parsed array on SELECT, while writers pass a
667
+ * `JSON.stringify` string. Re-parsing it as a string yields null for every job.
668
+ */
669
+ runs_on_labels: ColumnType<string[] | null, string | null, string | null>;
583
670
  /** Last heartbeat received from agent (for stale run detection) */
584
671
  last_heartbeat_at: Date | null;
585
672
  /** JSON array of secret context names dispatched with this job */
@@ -637,6 +724,20 @@ export interface ExecutionJobTable {
637
724
  archived_at: Date | null;
638
725
  /** S3 object key of the chunk that carried this row. */
639
726
  archive_object_key: string | null;
727
+ /**
728
+ * Job kind (`JobKind`): `standard` runs steps on an agent, `gate` is an
729
+ * invoke gate, `proxy` mirrors a summoned run. Defaults to `standard`.
730
+ */
731
+ job_kind: Generated<string>;
732
+ /** For a `proxy` job, the summoned run it mirrors. NULL for every other kind. */
733
+ summoned_run_id: string | null;
734
+ /**
735
+ * For a `gate` job, its own wall-clock timeout in milliseconds (copied from the
736
+ * lock job). A gate runs no steps on an agent, so the agent-side job timeout
737
+ * cannot fire for it; the orchestrator sweeps this column and fails a gate whose
738
+ * proxies have not all terminalized in time. NULL = no gate timeout.
739
+ */
740
+ timeout_ms: number | null;
640
741
  }
641
742
  /**
642
743
  * Execution step table
@@ -963,6 +1064,17 @@ export interface HeldRunsTable {
963
1064
  * step-approval gate fires. Null for every non-drift hold.
964
1065
  */
965
1066
  payload: ColumnType<StepApprovalPayload | null, StepApprovalPayload | string | null | undefined, StepApprovalPayload | string | null>;
1067
+ /**
1068
+ * Whether this hold's pending `KiCI Security` check actually reached the
1069
+ * provider. `true` after a post returned; `false` when none was attempted or
1070
+ * one failed; `null` on a row written before the column existed, for which
1071
+ * the hold's shape is still the only available answer.
1072
+ *
1073
+ * Read through `postedPendingSecurityCheck`. It decides whether a hold has a
1074
+ * check to terminalize — and terminalizing one it never posted CREATES a
1075
+ * `KiCI Security` run on a commit that had none.
1076
+ */
1077
+ posted_pending_check: Generated<boolean | null>;
966
1078
  }
967
1079
  export type HeldRun = Selectable<HeldRunsTable>;
968
1080
  export type NewHeldRun = Insertable<HeldRunsTable>;
@@ -1361,6 +1473,19 @@ export interface WorkflowRegistrationsTable {
1361
1473
  disabled: ColumnType<boolean, boolean | undefined, boolean>;
1362
1474
  /** Git commit SHA from the push that last updated this registration */
1363
1475
  commit_sha: ColumnType<string | null, string | null | undefined, string | null>;
1476
+ /**
1477
+ * The repository's default branch, captured from the push that last updated
1478
+ * this registration. A `__schedule_fire` run executes this branch's lock
1479
+ * file, so this IS that run's branch when a context evaluates branch
1480
+ * restrictions.
1481
+ *
1482
+ * NULL when the registration predates migration 123, or when the webhook
1483
+ * payload named no default branch. There is no backfill: the value is only
1484
+ * knowable from a payload, so a NULL row heals on its repo's next
1485
+ * default-branch push. NULL presents no branch, which keeps the honest
1486
+ * branch-gate rejection rather than inventing a branch.
1487
+ */
1488
+ default_branch: ColumnType<string | null, string | null | undefined, string | null>;
1364
1489
  /** Source file path for this workflow (e.g. ".kici/workflows/deploy.ts") */
1365
1490
  source_file: ColumnType<string | null, string | null | undefined, string | null>;
1366
1491
  /** Whether this is a global workflow (triggers across all repos under same routing key) */
@@ -1549,6 +1674,13 @@ export interface OrgSettingsTable {
1549
1674
  * URLs are accepted; arbitrary `http://` registries are rejected at dispatch.
1550
1675
  */
1551
1676
  allow_http_npm_registries: ColumnType<boolean, boolean | undefined, boolean>;
1677
+ /**
1678
+ * May an UNTRUSTED ref build its job's container image from a Dockerfile?
1679
+ *
1680
+ * Default false. The build runs outside the job's hardened sandbox, so this
1681
+ * is an opt-in, never inherited.
1682
+ */
1683
+ allow_untrusted_dockerfile_builds: ColumnType<boolean, boolean | undefined, boolean>;
1552
1684
  /**
1553
1685
  * Per-operation policy controlling which dashboard.* writes the orch
1554
1686
  * accepts when routed through Platform. JSONB shape:
@@ -1695,8 +1827,25 @@ export interface OrgTrustPolicyTable {
1695
1827
  unknown_contributor_policy: string;
1696
1828
  /** How to treat a PR that modifies workflow files: hold | reject | allow */
1697
1829
  workflow_change_policy: string;
1698
- /** How long a security hold stays approvable before it expires */
1830
+ /**
1831
+ * The coarse, hours-granularity view of the security-hold window.
1832
+ *
1833
+ * Retained and always written, because it is the only window an older peer or
1834
+ * CLI can read. This build derives it from `approval_expiry_seconds` on every
1835
+ * write (rounded up, never below 1), so the two columns cannot disagree.
1836
+ */
1699
1837
  approval_expiry_hours: number;
1838
+ /**
1839
+ * How long a security hold stays approvable before it expires, in seconds —
1840
+ * the authoritative window, and the only granularity that can express a
1841
+ * sub-hour hold.
1842
+ *
1843
+ * Nullable: NULL means no seconds value was ever written (a row predating the
1844
+ * column, or one written by an older build), and every reader falls back to
1845
+ * `approval_expiry_hours * 3600`. Same convention as
1846
+ * `contexts.hold_expiry_seconds`.
1847
+ */
1848
+ approval_expiry_seconds: ColumnType<number | null, number | null | undefined, number | null>;
1700
1849
  /** Which side last wrote this row: platform | local */
1701
1850
  source: string;
1702
1851
  /** When this policy was last written */
@@ -1705,6 +1854,57 @@ export interface OrgTrustPolicyTable {
1705
1854
  export type OrgTrustPolicy = Selectable<OrgTrustPolicyTable>;
1706
1855
  export type NewOrgTrustPolicy = Insertable<OrgTrustPolicyTable>;
1707
1856
  export type OrgTrustPolicyUpdate = Updateable<OrgTrustPolicyTable>;
1857
+ /**
1858
+ * Org trust directory (org_trust_directory) — the approval directory
1859
+ * `/kici approve` resolves a commenter against: identity links, per-member CI
1860
+ * trust levels, and team memberships. Sibling of `org_trust_policy`, same
1861
+ * ownership shape: wherever a Platform is attached it pushes this next to the
1862
+ * policy on `trust_policy.update` and the orchestrator only reads it back, so
1863
+ * approvals survive a restart. On an independent orchestrator there is no
1864
+ * Platform, so the operator writes it through
1865
+ * `kici-admin trust-policy directory-set` instead.
1866
+ *
1867
+ * The three JSONB columns are `unknown` on the select side because the pg
1868
+ * driver hands back whatever JSON the column holds; `TrustDirectoryStore`
1869
+ * validates each one against the wire schema before returning it. Inserts are
1870
+ * `JSON.stringify`d strings, matching every other JSONB column here.
1871
+ */
1872
+ export interface OrgTrustDirectoryTable {
1873
+ /** Customer/org identifier (primary key) */
1874
+ customer_id: string;
1875
+ /** JSONB array of `{ userId, provider, providerUsername, providerUserId? }` links */
1876
+ identity_links: ColumnType<unknown, string, string>;
1877
+ /** JSONB object mapping a KiCI user id to its `none | read | write | admin` CI trust level */
1878
+ member_ci_trust: ColumnType<unknown, string, string>;
1879
+ /** JSONB array of `{ teamName, memberUserIds }` entries */
1880
+ team_memberships: ColumnType<unknown, string, string>;
1881
+ /** When this directory was last written */
1882
+ updated_at: ColumnType<Date, Date | undefined, Date>;
1883
+ }
1884
+ export type OrgTrustDirectory = Selectable<OrgTrustDirectoryTable>;
1885
+ export type NewOrgTrustDirectory = Insertable<OrgTrustDirectoryTable>;
1886
+ export type OrgTrustDirectoryUpdate = Updateable<OrgTrustDirectoryTable>;
1887
+ /**
1888
+ * Org plan headroom (org_plan_headroom) — the orchestrator's cache of the
1889
+ * Platform-owned worker ceiling pushed on `plan.headroom`. Single row
1890
+ * (id='default'), because the orchestrator serves exactly one org. Same
1891
+ * ownership shape as org_trust_policy: the Platform writes it, the orchestrator
1892
+ * only reads it back, so it survives a Platform outage + a coordinator restart.
1893
+ */
1894
+ export interface OrgPlanHeadroomTable {
1895
+ /** Single-row sentinel id, always 'default'. */
1896
+ id: string;
1897
+ /** Absolute ceiling on this coordinator's connected worker peers. */
1898
+ max_worker_peers: number;
1899
+ /** The org's combined orchestrator limit, for the rejection reason. */
1900
+ org_limit: number;
1901
+ /** The org's combined orchestrator total at push time, for the rejection reason. */
1902
+ org_total: number;
1903
+ /** Whether the Platform asked the coordinator to drain its excess workers. */
1904
+ evict_excess: boolean;
1905
+ /** When this ceiling was last written. */
1906
+ updated_at: ColumnType<Date, Date, Date>;
1907
+ }
1708
1908
  /**
1709
1909
  * Cluster-global settings (cluster_settings) — a single row (id='default') of
1710
1910
  * fleet-wide operator tunables. Each knob is nullable; NULL = use the cluster
@@ -1782,6 +1982,52 @@ export interface ClusterSettingsTable {
1782
1982
  ingest_overflow_claim_timeout_ms: ColumnType<number | null, number | null | undefined, number | null>;
1783
1983
  concurrency_wait_timeout_ms: ColumnType<string | null, number | null | undefined, number | null>;
1784
1984
  agent_token_ttl_ms: ColumnType<string | null, number | null | undefined, number | null>;
1985
+ /**
1986
+ * How often the leader sweeps for stranded event-scaler provisions. Re-read
1987
+ * at the end of every sweep, so a change reschedules the timer on the next
1988
+ * tick rather than waiting for a leadership transition. NULL ⇒ the
1989
+ * orchestrator's configured default.
1990
+ */
1991
+ scaler_reap_interval_ms: ColumnType<string | null, number | null | undefined, number | null>;
1992
+ /**
1993
+ * How long an adopted event-scaler provision whose agent is registered on no
1994
+ * coordinator may sit before it is torn down. Set it well above the peer
1995
+ * heartbeat period: the "registered nowhere" signal is partly heartbeat
1996
+ * derived. NULL ⇒ the orchestrator's configured default. Read per sweep.
1997
+ */
1998
+ scaler_reap_stranded_timeout_ms: ColumnType<string | null, number | null | undefined, number | null>;
1999
+ /**
2000
+ * How long before the reaper retries a provision whose previous teardown left
2001
+ * the row in place. NULL ⇒ the orchestrator's configured default. Read per
2002
+ * sweep.
2003
+ */
2004
+ scaler_reap_reattempt_interval_ms: ColumnType<string | null, number | null | undefined, number | null>;
2005
+ /**
2006
+ * How long an expired scaler provisioning claim is kept before the reaper's
2007
+ * sweep deletes it. An expired claim can never be redeemed, so this only
2008
+ * controls how long a late redeemer is told "expired" rather than "unknown
2009
+ * code". NULL ⇒ the orchestrator's configured default. Read per sweep.
2010
+ */
2011
+ scaler_claim_retention_ms: ColumnType<string | null, number | null | undefined, number | null>;
2012
+ /**
2013
+ * First deferral applied to an external (event) scaler after one consecutive
2014
+ * provisioning failure. Each further consecutive failure doubles it, up to
2015
+ * `scaler_provision_backoff_max_ms`. NULL ⇒ the orchestrator's configured
2016
+ * default. Read per spawn request.
2017
+ */
2018
+ scaler_provision_backoff_base_ms: ColumnType<string | null, number | null | undefined, number | null>;
2019
+ /**
2020
+ * Ceiling on the doubling above, so a long provider outage settles into a
2021
+ * steady retry cadence instead of growing without bound. NULL ⇒ the
2022
+ * orchestrator's configured default. Read per spawn request.
2023
+ */
2024
+ scaler_provision_backoff_max_ms: ColumnType<string | null, number | null | undefined, number | null>;
2025
+ /**
2026
+ * How many consecutive provisioning failures a scaler may record before its
2027
+ * refusals name repeated failure as the cause rather than a single timeout.
2028
+ * NULL ⇒ the orchestrator's configured default. Read per spawn request.
2029
+ */
2030
+ scaler_provision_max_consecutive_failures: ColumnType<string | null, number | null | undefined, number | null>;
1785
2031
  /**
1786
2032
  * Deadline for one database-backed agent-ownership lookup. Past it the lookup
1787
2033
  * resolves as undecided and the frame is refused without counting a
@@ -1818,6 +2064,13 @@ export interface PendingJobContextsTable {
1818
2064
  job_input: ColumnType<Record<string, unknown>, string, string>;
1819
2065
  /** string[] of labels serialized as JSONB */
1820
2066
  runs_on_labels: ColumnType<string[], string, string>;
2067
+ /**
2068
+ * For an invoke-gate job, its invoke parameters (event, payload, optional,
2069
+ * maxParallel, failFast) serialized as JSON. Non-null marks this pending
2070
+ * context as a gate: when released it summons the source repo's subscribers
2071
+ * instead of dispatching to an agent. NULL for every ordinary job.
2072
+ */
2073
+ invoke_config: ColumnType<string | null, string | null | undefined, string | null>;
1821
2074
  /** When this context was stored */
1822
2075
  created_at: Generated<Date>;
1823
2076
  }
@@ -2247,6 +2500,17 @@ export interface HostRosterTable {
2247
2500
  token_id: string | null;
2248
2501
  /** Snapshot of the token's agent_type: 'static' | 'ephemeral'. */
2249
2502
  lifecycle_class: string;
2503
+ /**
2504
+ * True when an auto-scaler backend spawned this agent. Written from the
2505
+ * scaler manager's registration lookup (a spawn record exists for the agent
2506
+ * id), NOT from `lifecycle_class` — that column snapshots the auth TOKEN's
2507
+ * type and reads `ephemeral` for every agent when the auth mode is `none`.
2508
+ *
2509
+ * `runsOnAll` fan-out targets declared fleet members, so a true here keeps
2510
+ * the host out of the fan-out set. Defaults false, so a row predating the
2511
+ * column stays a fan-out target without re-registering.
2512
+ */
2513
+ scaler_managed: ColumnType<boolean, boolean | undefined, boolean>;
2250
2514
  /** JSON-encoded string[] of the post-Gate-1 validated labels. */
2251
2515
  labels: string;
2252
2516
  hostname: string | null;
@@ -2296,10 +2560,16 @@ export type HostRosterUpdate = Updateable<HostRosterTable>;
2296
2560
  * Scaler spawning-agents table (scaler_spawning_agents).
2297
2561
  *
2298
2562
  * One row per agent that has been spawned via a scaler backend
2299
- * (container / bare-metal / firecracker) but has not yet registered via
2300
- * WS. Persists `bound_job_id` so a replacement coord still issues the
2301
- * eager-dispatch hop when the agent eventually registers. GC'd by a
2302
- * leader-gated sweep that drops rows older than the spawn-timeout.
2563
+ * (container / bare-metal / firecracker / event) but has not yet registered
2564
+ * via WS. Persists `bound_job_id` so a replacement coord still issues the
2565
+ * eager-dispatch hop when the agent eventually registers, and `run_id`
2566
+ * alongside it so a coordinator that never spawned the agent the
2567
+ * leader-gated reaper routinely is not the spawner — can still attribute a
2568
+ * provisioning failure back to the job waiting on it. Reaped per
2569
+ * instance and adoption-aware: `listReapCandidates` narrows to event rows that
2570
+ * are either adopted or past their spawn deadline, and the reaper tears each
2571
+ * one down with `deleteSpawningAgent` — an adopted event agent legitimately
2572
+ * outlives the spawn timeout, so no blanket age-based sweep may drop it.
2303
2573
  */
2304
2574
  export interface ScalerSpawningAgentsTable {
2305
2575
  agent_id: string;
@@ -2309,9 +2579,68 @@ export interface ScalerSpawningAgentsTable {
2309
2579
  job_id: ColumnType<string | null, string | null | undefined, string | null>;
2310
2580
  bound_job_id: ColumnType<string | null, string | null | undefined, string | null>;
2311
2581
  spawned_at: Generated<Date>;
2582
+ /**
2583
+ * The coordinator instance that spawned this agent. Scopes recovery and the
2584
+ * per-instance reaper. NULL reads as "unknown owner" — never as "not mine".
2585
+ */
2586
+ owner_instance_id: ColumnType<string | null, string | null | undefined, string | null>;
2587
+ /** The coordinator the agent actually reached when it registered. */
2588
+ adopted_by: ColumnType<string | null, string | null | undefined, string | null>;
2589
+ /** When the adopting coordinator claimed the agent. */
2590
+ adopted_at: ColumnType<Date | null, Date | null | undefined, Date | null>;
2591
+ /**
2592
+ * The scaler's mandatory labels, copied onto the row so a coordinator with no
2593
+ * matching scaler entry can still stamp the taint and emit the teardown.
2594
+ */
2595
+ mandatory_labels: ColumnType<string[] | null, string | string[] | null | undefined, string | string[] | null>;
2596
+ /** The scaler's provisioning targets, copied onto the row for the same reason. */
2597
+ provisioning_targets: ColumnType<string[] | null, string | string[] | null | undefined, string | string[] | null>;
2598
+ /** The scaler's roles, copied onto the row for the same reason. */
2599
+ roles: ColumnType<string[] | null, string | string[] | null | undefined, string | string[] | null>;
2600
+ /**
2601
+ * The scaler backend that spawned the agent: `container`, `bare-metal`,
2602
+ * `firecracker`, or `event`. `event` is the value every adoption and reap
2603
+ * predicate matches on, so a row missing it can be adopted and reaped by
2604
+ * nobody. NULL means the row predates the column.
2605
+ */
2606
+ backend_type: ColumnType<string | null, string | null | undefined, string | null>;
2312
2607
  }
2313
2608
  export type ScalerSpawningAgentRow = Selectable<ScalerSpawningAgentsTable>;
2314
2609
  export type NewScalerSpawningAgentRow = Insertable<ScalerSpawningAgentsTable>;
2610
+ /**
2611
+ * Scaler provision-outcomes table (scaler_provision_outcomes).
2612
+ *
2613
+ * One row per provisioned agent id, recording what became of the provision.
2614
+ * Outlives `scaler_spawning_agents`, whose row is deleted on teardown — so the
2615
+ * stale-spawn prune can tell an adopted provision from one that was never
2616
+ * adopted, which the spawn row's absence cannot.
2617
+ *
2618
+ * `adopted_by` is written in the same transaction as
2619
+ * `scaler_spawning_agents.adopted_by`, inside `adoptSpawningAgent`, which is
2620
+ * the single writer of that column. Any future writer of `adopted_by` MUST
2621
+ * write this row too, or the prune loses the signal again.
2622
+ */
2623
+ export interface ScalerProvisionOutcomesTable {
2624
+ agent_id: string;
2625
+ scaler_name: string;
2626
+ /** The coordinator that adopted the provision. NULL means it never was. */
2627
+ adopted_by: ColumnType<string | null, string | null | undefined, string | null>;
2628
+ /** When it was first adopted. Never refreshed by a re-adopt. */
2629
+ adopted_at: ColumnType<Date | null, Date | null | undefined, Date | null>;
2630
+ /**
2631
+ * The reaper's teardown reason (`spawn-timeout` / `heartbeat-timeout`), set
2632
+ * only once the teardown was actually delivered. Independent of `adopted_by`:
2633
+ * a `heartbeat-timeout` condemns a provision that WAS adopted, and clearing
2634
+ * the adoption here would restore the misattribution this table removes.
2635
+ */
2636
+ condemned_reason: ColumnType<string | null, string | null | undefined, string | null>;
2637
+ /** When the reaper condemned it. */
2638
+ condemned_at: ColumnType<Date | null, Date | null | undefined, Date | null>;
2639
+ recorded_at: Generated<Date>;
2640
+ updated_at: ColumnType<Date, Date | string | undefined, Date | string>;
2641
+ }
2642
+ export type ScalerProvisionOutcomeRow = Selectable<ScalerProvisionOutcomesTable>;
2643
+ export type NewScalerProvisionOutcomeRow = Insertable<ScalerProvisionOutcomesTable>;
2315
2644
  /**
2316
2645
  * Scaler agent-jobs table (scaler_agent_jobs).
2317
2646
  *
@@ -2341,7 +2670,36 @@ export interface ScalerReservationsTable {
2341
2670
  cpu_units: number;
2342
2671
  mem_bytes: ColumnType<string, string | number, string | number>;
2343
2672
  reserved_at: Generated<Date>;
2673
+ /**
2674
+ * The coordinator instance holding the reservation. Scopes recovery and the
2675
+ * per-instance reaper. NULL reads as "unknown owner" — never as "not mine".
2676
+ */
2677
+ owner_instance_id: ColumnType<string | null, string | null | undefined, string | null>;
2344
2678
  }
2345
2679
  export type ScalerReservationRow = Selectable<ScalerReservationsTable>;
2346
2680
  export type NewScalerReservationRow = Insertable<ScalerReservationsTable>;
2681
+ /**
2682
+ * Pending provisioning claims (scaler_pending_claims).
2683
+ *
2684
+ * One row per outstanding event-scaler claim code, so any coordinator behind the
2685
+ * shared endpoint can redeem a code rather than only the process that minted it.
2686
+ * The code itself is never stored — only its sha256 — so a DB read cannot hand
2687
+ * back a redeemable secret. Single use is enforced by a conditional UPDATE on
2688
+ * `consumed_at`.
2689
+ */
2690
+ export interface ScalerPendingClaimsTable {
2691
+ claim_hash: string;
2692
+ claim_prefix: string;
2693
+ agent_id: string;
2694
+ scaler_name: string;
2695
+ labels: ColumnType<string[], string | string[], string | string[]>;
2696
+ /** BIGINT: node-pg returns it as a string, so callers coerce on read. */
2697
+ agent_token_ttl_ms: ColumnType<string, number | string, number | string>;
2698
+ orchestrator_url: string;
2699
+ expires_at: Date;
2700
+ consumed_at: ColumnType<Date | null, Date | null | undefined, Date | null>;
2701
+ created_at: Generated<Date>;
2702
+ }
2703
+ export type ScalerPendingClaimRow = Selectable<ScalerPendingClaimsTable>;
2704
+ export type NewScalerPendingClaimRow = Insertable<ScalerPendingClaimsTable>;
2347
2705
  //# sourceMappingURL=types.d.ts.map
@@ -5,6 +5,34 @@
5
5
  * Both entry points import these helpers instead of maintaining separate copies.
6
6
  */
7
7
  import { type SourceProvider, SourceSubtype } from '@kici-dev/engine';
8
+ /**
9
+ * Decide whether the current module load is the real production orchestrator
10
+ * process entry and should boot the server.
11
+ *
12
+ * `server.ts` is shipped under several output filenames depending on the build:
13
+ * `dist/server.js` (the native/full build and the container image) and
14
+ * `kici-orchestrator.cjs` / `.mjs` (the cross-platform "light" bundle customers
15
+ * download for macOS / Windows / ARM). All of them are real production entries
16
+ * and MUST boot when run directly, so the guard cannot key on one filename.
17
+ *
18
+ * The one entry that inlines `server.ts` yet must NOT boot from this guard is
19
+ * the dev-only `server-test.js`: it imports `runServer` and boots it itself with
20
+ * a fault-injection policy, so a second boot from the inlined guard would run
21
+ * two orchestrators in one process. That is the only exclusion, so the guard
22
+ * fires for every process entry EXCEPT `server-test.js`.
23
+ *
24
+ * Matching is by final path segment (see {@link entryFileName}) rather than full
25
+ * URL-string equality: the light bundle's `import.meta.url` is
26
+ * `` `file://${__filename}` ``, whose Windows form (`file://C:\...`) never equals
27
+ * the `pathToFileURL(argv[1]).href` form (`file:///C:/...`), which would leave the
28
+ * Windows orchestrator loading and exiting 0 without ever starting the server.
29
+ * On bare import (a unit test, or any non-entry importer) `argv[1]` is the
30
+ * importer, whose filename differs from this module's, so the guard stays silent.
31
+ *
32
+ * @param argvPath `process.argv[1]` — the path Node was invoked with.
33
+ * @param moduleUrl `import.meta.url` of the server module.
34
+ */
35
+ export declare function isProductionEntry(argvPath: string | undefined, moduleUrl: string): boolean;
8
36
  /**
9
37
  * A provider source for Platform registration.
10
38
  *
@@ -1,4 +1,5 @@
1
1
  import type { EventRouter } from './event-router.js';
2
+ import { type ScalerScaleUpPayload as ScalerScaleUpPayloadType, type ScalerScaleDownPayload as ScalerScaleDownPayloadType } from '../scaler/scaler-events.js';
2
3
  /**
3
4
  * Input data for emitting a workflow_complete system event.
4
5
  */
@@ -10,9 +11,15 @@ export interface WorkflowCompleteData {
10
11
  status: string;
11
12
  conclusion: string;
12
13
  duration: number;
14
+ /**
15
+ * Per-job results. `outputs` carries a job's non-secret declared outputs
16
+ * (additive/optional — an invoke gate reads them to surface an invoked run's
17
+ * outputs to downstream global jobs; older readers ignore the field).
18
+ */
13
19
  jobResults: Array<{
14
20
  name: string;
15
21
  status: string;
22
+ outputs?: Record<string, unknown>;
16
23
  }>;
17
24
  /** Why the run failed (`RunFailureClass`); carried on the event so Plane B can route on it. */
18
25
  failureClass?: string;
@@ -82,5 +89,20 @@ export declare class EventEmitter {
82
89
  * Returns the event ID as delivery receipt.
83
90
  */
84
91
  emitJobComplete(data: JobCompleteData): Promise<string>;
92
+ /**
93
+ * Emit a `kici.scaler.scale-up` system event. Delivered to the scaler's
94
+ * `provisioningTargets` (the workflow refs that provision cloud instances),
95
+ * carrying everything a provisioning workflow needs — including a single-use
96
+ * claim code. Root-level (chainDepth 0), rate-exempt via the reserved `kici.`
97
+ * prefix. Returns the event id as a delivery receipt.
98
+ */
99
+ emitScalerScaleUp(payload: ScalerScaleUpPayloadType, targets: string[]): Promise<string>;
100
+ /**
101
+ * Emit a `kici.scaler.scale-down` system event. Delivered to the scaler's
102
+ * `provisioningTargets` so a teardown workflow deletes the instance
103
+ * registered under `payload.agentId`. Root-level (chainDepth 0), rate-exempt.
104
+ * Returns the event id as a delivery receipt.
105
+ */
106
+ emitScalerScaleDown(payload: ScalerScaleDownPayloadType, targets: string[]): Promise<string>;
85
107
  }
86
108
  //# sourceMappingURL=event-emitter.d.ts.map