@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
@@ -9,8 +9,8 @@
9
9
  * make Mimir cardinality grow with the number of agents that have ever
10
10
  * existed (every ephemeral firecracker microVM minted a fresh ID), which
11
11
  * is unbounded. The caller-side dashboard filters by `scaler` instead,
12
- * which has a fixed enum of values (`stateful` / `container` /
13
- * `firecracker` / `bare-metal`).
12
+ * which has a fixed enum of values (`stateful`, plus every
13
+ * `ScalerBackendType`).
14
14
  *
15
15
  * Aggregation rules per metric kind:
16
16
  * - counter / upDownCounter / gauge → SUM across agents in the pool
@@ -34,14 +34,97 @@ interface ScalerUsageRow {
34
34
  * the on-disk ledger snapshot. Per-scaler rows omit `machinePool`.
35
35
  */
36
36
  export declare function setScalerUsageBreakdown(rows: ScalerUsageRow[]): void;
37
+ interface WarmPoolGaugeRow {
38
+ /** Operator-chosen scaler name that owns the pool. */
39
+ scaler: string;
40
+ /** Normalized label set the pool keeps agents ready for. */
41
+ labelSet: string;
42
+ target: number;
43
+ ready: number;
44
+ inFlight: number;
45
+ }
46
+ /**
47
+ * Replace the current warm-pool fill state.
48
+ *
49
+ * Called by ScalerManager after each warm-pool tick and after a config reload,
50
+ * so the gauges follow the pool rather than the scrape.
51
+ */
52
+ export declare function setWarmPoolGauges(rows: WarmPoolGaugeRow[]): void;
53
+ /**
54
+ * Total warm-pool spawns started.
55
+ * Labels:
56
+ * - scaler: operator-chosen scaler name that owns the pool.
57
+ */
58
+ export declare const scalerWarmPoolSpawnsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
59
+ /** Record a warm-pool spawn starting. */
60
+ export declare function incWarmPoolSpawns(scaler: string): void;
61
+ /**
62
+ * Total warm-pool agents destroyed as surplus to the pool's target — either
63
+ * past `idleTimeoutSeconds`, or immediately when a config reload lowers the
64
+ * target. Both paths run through the same destroy callback, so the counter
65
+ * covers both.
66
+ * Labels:
67
+ * - scaler: operator-chosen scaler name that owns the pool.
68
+ */
69
+ export declare const scalerWarmPoolReapedTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
70
+ /** Record a warm-pool agent being destroyed. */
71
+ export declare function incWarmPoolReaped(scaler: string): void;
37
72
  /** Increment the spawn-refusal counter (called by ScalerManager when a request fails the cap check). */
38
73
  export declare function incScalerSpawnRefusals(): void;
74
+ /**
75
+ * Why an event scaler's cluster-wide cap check failed.
76
+ *
77
+ * `reason` label for `kici_orch_scaler_cap_lock_failures_total`. The two are a
78
+ * different fault with a different operator response, so they must not share a
79
+ * series any more than either may share one with a plain capacity refusal.
80
+ * - `contended` — the advisory lock was still held when the wait budget
81
+ * expired. The database is healthy; several coordinators are scaling one hot
82
+ * scaler at once. Raise the scaler's cap, or the wait budget.
83
+ * - `unreachable` — the cap could not be evaluated at all (connection lost,
84
+ * statement timeout, schema error). Event autoscaling is stalled on the
85
+ * database and no cap arithmetic is happening anywhere.
86
+ */
87
+ export declare const ScalerCapLockFailureReason: {
88
+ readonly Contended: 'contended';
89
+ readonly Unreachable: 'unreachable';
90
+ };
91
+ export type ScalerCapLockFailureReason = (typeof ScalerCapLockFailureReason)[keyof typeof ScalerCapLockFailureReason];
92
+ /**
93
+ * Total event-scaler cluster-wide cap checks that failed, so their spawn was
94
+ * refused without the cap ever being evaluated.
95
+ *
96
+ * Deliberately NOT folded into `kici_orch_scaler_spawn_refusals_total`: that
97
+ * series means "the cluster is full", and the operator response is to add
98
+ * capacity or raise a cap. This one means the cap could not be evaluated, so
99
+ * event spawns fail closed for a reason that has nothing to do with capacity.
100
+ * Labels:
101
+ * - reason: contended (the lock wait budget expired) | unreachable (the cap could not be evaluated at all)
102
+ */
103
+ export declare const scalerCapLockFailuresTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
39
104
  /**
40
105
  * Record `count` pending jobs re-driven through the scaler by `trigger`
41
106
  * (`hook` = capacity-freed callback, `sweep` = leader-gated backstop).
42
107
  * Called by the dispatcher's metrics facade.
43
108
  */
44
109
  export declare function incScalerRedispatch(trigger: ScalerRedispatchTrigger, count: number): void;
110
+ /** Record a scale-up event emitted for `scaler`. */
111
+ export declare function incScalerScaleUpEmitted(scaler: string): void;
112
+ /** Record a scale-down event emitted for `scaler` with the teardown `reason`. */
113
+ export declare function incScalerScaleDownEmitted(scaler: string, reason: string): void;
114
+ /** Record an event-scaler provision that timed out before its agent registered. */
115
+ export declare function incScalerExternalProvisionTimeout(scaler: string): void;
116
+ /** Record an adoption lookup that could not reach its spawn record. */
117
+ export declare function incScalerAdoptionLookupFailure(): void;
118
+ /** Set the current count of in-flight (provisioning + active) external agents for `scaler`. */
119
+ export declare function setScalerExternalProvisioningActive(scaler: string, count: number): void;
120
+ /**
121
+ * Set how many event-scaler provisions the leader has been unable to see an
122
+ * agent for, for at least the flap grace. Zero on every non-leader, and on a
123
+ * leader whose sweep is blocked.
124
+ */
125
+ export declare function setScalerReapUnseenProvisions(count: number): void;
126
+ /** Set whether this coordinator's provision reaper is standing down (1) or sweeping (0). */
127
+ export declare function setScalerReapBlocked(blocked: boolean): void;
45
128
  /**
46
129
  * Merge current per-label counts with explicit `0`s for previously-seen labels
47
130
  * whose queue has drained. Mutates `everSeen` to include the current labels.
@@ -128,13 +211,27 @@ export declare const webhooksProcessedTotal: import("@opentelemetry/api").Counte
128
211
  /**
129
212
  * Org trust-policy gate decisions.
130
213
  * Labels:
131
- * - arm: which policy arm decided — workflow_modification | fork_pr | unknown_contributor | none (the PR passed)
132
- * - action: pass | hold | reject
214
+ * - arm: which policy arm decided — fork_pr | none (the verdict carried no reason)
215
+ * - action: pass | ignore | hold | reject
133
216
  *
134
217
  * Incremented once per evaluated PR event, including passes, so the ratio of
135
218
  * gated to ungated PRs is visible rather than only the gated ones.
136
219
  */
137
220
  export declare const trustPolicyDecisionsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
221
+ /**
222
+ * Fork pull-request events dropped by the org fork policy before any run row,
223
+ * check status, or job dispatch existed.
224
+ * Labels:
225
+ * - provider: the inbound delivery's provider (github, …)
226
+ *
227
+ * @conditionallyEmitted An org that does not ignore fork PRs emits no series.
228
+ *
229
+ * Distinct from `kici_orch_trust_policy_decisions_total{action="ignore"}`,
230
+ * which counts the verdict wherever it is reached: this counts the drop the
231
+ * ingest path actually performed, so a verdict that stopped being enforced
232
+ * shows as a divergence between the two rather than as silence.
233
+ */
234
+ export declare const forkEventsIgnoredTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
138
235
  /**
139
236
  * Duration of trigger matching operations (lock file evaluation).
140
237
  * Buckets: 1ms to 5s covering fast rejects through complex evaluations.
@@ -228,7 +325,7 @@ export type ScalerSpawnFailureBound = (typeof ScalerSpawnFailureBound)[keyof typ
228
325
  /**
229
326
  * Total scaler agent spawn failures.
230
327
  * Labels:
231
- * - backend: scaler backend type (bare-metal | container | firecracker | unknown)
328
+ * - backend: scaler backend type (bare-metal | container | event | firecracker | unknown)
232
329
  * - bound: true (job-bound spawn) | false (warm-pool/unbound)
233
330
  */
234
331
  export declare const scalerSpawnFailuresTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
@@ -371,6 +468,17 @@ export declare const eventRetryTotal: import("@opentelemetry/api").Counter<impor
371
468
  * - reason: why the event was DLQ'd (exhausted_retries)
372
469
  */
373
470
  export declare const eventDlqTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
471
+ /**
472
+ * Startup catch-up scans that threw. Emits no labels.
473
+ *
474
+ * The scan recovers the internal-event backlog a restart left behind, and it
475
+ * runs behind a boot latch that the composition root resolves after startup
476
+ * continues — so a failure cannot fail the bootstrap and is otherwise invisible
477
+ * until the backlog quietly ages into the DLQ. This counter is what an alert
478
+ * fires on; the accompanying `Deferred catch-up scan failed` log line carries
479
+ * the reason.
480
+ */
481
+ export declare const eventCatchUpFailuresTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
374
482
  /**
375
483
  * Dispatch leases that timed out before the holding node finalised them
376
484
  * (signals a node crash mid-dispatch). Emits no labels.
@@ -56,9 +56,13 @@ export interface OidcMintRegistrationInput {
56
56
  };
57
57
  db: Kysely<Database>;
58
58
  orchestratorId: string;
59
- testMode: boolean;
60
- testMintDeferAudience?: string;
61
- testMintRejectAudience?: string;
59
+ /**
60
+ * Test-only fault-injection predicate forwarded to the relay mint handler,
61
+ * supplied only by the build-time test double. Only ever defers — the
62
+ * anti-forgery choke point is preserved. Undefined (the shipped default) means
63
+ * no fault injection.
64
+ */
65
+ initialMintFault?: (audience: string) => boolean;
62
66
  }
63
67
  /** Decide which mint handler (if any) backs `OIDC_TOKEN_REQUEST_METHOD`. */
64
68
  export declare function selectOidcMintRegistration(input: OidcMintRegistrationInput): OidcMintRegistration | undefined;
@@ -29,7 +29,7 @@ import { IngestOverflowBuffer } from './webhook/ingest-overflow-buffer.js';
29
29
  import { IngestOverflowReplayer } from './webhook/ingest-overflow-replayer.js';
30
30
  import { AgentMetricsAggregator } from './metrics/agent-metrics-aggregator.js';
31
31
  import { SourceLocationStore } from './app.js';
32
- import { ExecutionJobStatus, type LabelMatcher, type PeerHeartbeat, type PeerLogsCollectRequest, type PeerToPeerMessage, type ResolvedSandboxGrant } from '@kici-dev/engine';
32
+ import { ExecutionJobStatus, type PeerHeartbeat, type PeerLogsCollectRequest, type PeerToPeerMessage, type InvokeResult } from '@kici-dev/engine';
33
33
  import { ScalerManager } from './scaler/index.js';
34
34
  import type { ScalerConfig } from './scaler/index.js';
35
35
  import type { CacheStorage } from './storage/index.js';
@@ -38,12 +38,14 @@ import { type ResolvedDashboardEncryptionKey } from './secrets/dashboard-encrypt
38
38
  import { SourceCache, BuildCoordinator, DepCache, UserCache, DispatchCacheRefTracker, PendingBuildTracker, PendingInitTracker, PendingDynamicTracker, PendingGlobalEvalTracker, GlobalEvalRoundCache } from './cache/index.js';
39
39
  import { ArtifactStore } from './artifacts/artifact-store.js';
40
40
  import { CheckRunReporter } from './reporting/check-run-reporter.js';
41
+ import type { ProcessingDeps } from './pipeline/processor.js';
42
+ import type { InvokeGateDeps, SummonArgs, SummonedRun } from './pipeline/invoke-gate.js';
41
43
  import { StepLogBuffer } from './reporting/step-log-buffer.js';
42
44
  import { type LogStorage } from './reporting/log-storage.js';
43
45
  import { ExecutionTracker, type ExecutionTrackerDeps } from './reporting/execution-tracker.js';
44
46
  import { LogWriter } from './reporting/log-writer.js';
45
47
  import { type NormalizedLogChunk } from './reporting/log-chunk-sink.js';
46
- import { PeerRegistry, PeerClient, createPeerHandler, RaftNode, OrphanRecovery, RunCoordinator } from './cluster/index.js';
48
+ import { PeerRegistry, PeerClient, createPeerHandler, RaftNode, OrphanRecovery, RunCoordinator, PlanHeadroomStore } from './cluster/index.js';
47
49
  import { SourceStore, SourceManager } from './sources/index.js';
48
50
  import { PgSecretStore, AuditLogger, SecretResolver } from './secrets/index.js';
49
51
  import type { SecretStore } from '@kici-dev/engine';
@@ -51,11 +53,13 @@ import type { AdminRouteDeps } from './routes/admin.js';
51
53
  import { AgentTokenStore } from './agent/token-store.js';
52
54
  import { OwnershipTracker } from './agent/ownership-tracker.js';
53
55
  import { EventStore } from './events/event-store.js';
54
- import { EventRouter } from './events/event-router.js';
56
+ import { EventRouter, type EventMatchContext } from './events/event-router.js';
55
57
  import { EventEmitter } from './events/event-emitter.js';
56
58
  import { TrustStore } from './events/trust-store.js';
59
+ import type { OrchestratorFaultInjection } from './testing/fault-injection.js';
57
60
  import { GenericSourceManager } from './webhook/generic-sources.js';
58
61
  import { GenericSourcesChangeListener } from './webhook/generic-sources-listener.js';
62
+ import { DashboardWritePolicyChangeListener } from './policy/dashboard-write-policy-listener.js';
59
63
  import { RegistrationStore } from './registration/registration-store.js';
60
64
  import { RegistrationIndex } from './registration/registration-index.js';
61
65
  import { CronScheduler } from './cron/cron-scheduler.js';
@@ -125,6 +129,8 @@ export interface OrchestratorSubsystems {
125
129
  globalEvalCache: GlobalEvalRoundCache;
126
130
  dedup: DedupCache;
127
131
  eventRouter: EventRouter;
132
+ /** Invoke-gate dependencies (summon callback + chain-depth bound). */
133
+ invokeGateDeps: InvokeGateDeps;
128
134
  /**
129
135
  * Event store for custom internal events (system + custom). Exposed
130
136
  * here so the dashboard handler can serve the per-org DLQ surface
@@ -153,6 +159,10 @@ export interface OrchestratorSubsystems {
153
159
  getLocalInventory: () => Omit<PeerHeartbeat, 'type'>;
154
160
  broadcastHeartbeatToAllPeers: () => void;
155
161
  broadcastAgentTokenRevoke: (tokenId: string) => void;
162
+ /** Platform-owned worker-ceiling cache, read by the peer-handler admission gate. */
163
+ planHeadroomStore: PlanHeadroomStore;
164
+ /** Late-bind the coordinator's cluster.membership reporter (see ClusterInfra). */
165
+ setMembershipReporter: (report: () => void) => void;
156
166
  joinHandler: JoinHandler;
157
167
  configReloader: ConfigReloader;
158
168
  localConfigVersion: number;
@@ -164,6 +174,12 @@ export interface OrchestratorSubsystems {
164
174
  * Platform when a generic source is added/removed at runtime.
165
175
  */
166
176
  genericSourcesChangeListener: GenericSourcesChangeListener;
177
+ /**
178
+ * Dashboard-write policy hot-reload listener. Keeps every coordinator's
179
+ * cached policy map — and the capability snapshot it advertises to the
180
+ * control plane — in step with a `kici-admin` write served by any peer.
181
+ */
182
+ dashboardWritePolicyChangeListener: DashboardWritePolicyChangeListener;
167
183
  /** Inbound webhook delivery log writer (event_log table + object-storage payloads). */
168
184
  eventLogWriter: EventLogWriter;
169
185
  /** Access log writer (read + mutation attribution for dashboard + admin). */
@@ -204,6 +220,17 @@ export interface OrchestratorSubsystems {
204
220
  ingestOverflowBuffer: IngestOverflowBuffer;
205
221
  /** Background replayer draining the overflow buffer once capacity recovers. */
206
222
  ingestOverflowReplayer: IngestOverflowReplayer;
223
+ /**
224
+ * The live direct-ingress `ProcessingDeps` bag, assembled inside `createApp`.
225
+ *
226
+ * A mode hook that has to resume a held run needs the same bag the pipeline
227
+ * that created the hold used — otherwise the resume runs against a second,
228
+ * hand-assembled bag that can silently diverge from it. `createApp` runs
229
+ * AFTER `onSubsystemsReady`, so this throws until it has, which is why every
230
+ * caller must invoke it lazily (inside a release callback, never at wiring
231
+ * time).
232
+ */
233
+ buildProcessingDeps: () => ProcessingDeps;
207
234
  }
208
235
  /**
209
236
  * Mode-specific hooks injected by each entry point.
@@ -273,22 +300,6 @@ export interface OrchestratorHooks {
273
300
  * are skipped here — group fan-in is resolved separately by the scheduler.
274
301
  */
275
302
  export declare function upstreamBaseNamesFromNeeds(needs: unknown): string[];
276
- /**
277
- * Partition a lock job's `runsOn` / `excludeLabels` matchers into exact label
278
- * strings and regex patterns for internal-event (cron / `ctx.emit`) dispatch.
279
- * Lock jobs carry `runsOn` as `LabelMatcher[]`; the coordinator routing and the
280
- * direct dispatcher both need exact labels for the indexed/SQL fast path and
281
- * regex patterns as a separate JS post-filter — never the raw matcher objects.
282
- */
283
- export declare function internalJobRunsOnSelectors(job: {
284
- runsOn?: readonly LabelMatcher[];
285
- excludeLabels?: readonly LabelMatcher[];
286
- }): {
287
- runsOnLabels: string[];
288
- runsOnPatterns: LabelMatcher[];
289
- excludeLabels: string[];
290
- excludePatterns: LabelMatcher[];
291
- };
292
303
  /**
293
304
  * Parse an `execution_jobs.outputs` cell (string JSON or object) to a plain
294
305
  * object, or null when empty / unparseable.
@@ -319,6 +330,22 @@ export declare function buildUpstreamStatusesByBase(rows: Array<{
319
330
  job_name: string;
320
331
  status?: string | null;
321
332
  }>): Record<string, ExecutionJobStatus> | undefined;
333
+ /**
334
+ * For each declared need that names an invoke gate, gather its per-run results
335
+ * from the gate's proxy children — `{ repo, workflow, runId, status, outputs }`,
336
+ * one entry per proxy. `outputs` is the proxy's non-secret mirrored outputs (the
337
+ * same `execution_jobs.outputs` cell `mirrorSummonedRunOntoProxy` writes); a
338
+ * repo's secret outputs live in `run_secret_outputs` and are never read here.
339
+ * Keyed by gate name; a gate that summoned zero subscribers yields an empty
340
+ * array (so `.result` stays an `InvokeResult[]`), while a declared need that is
341
+ * a regular job (no gate row) yields no key.
342
+ *
343
+ * Shared by both `ctx.needs['<gate>'].result` construction paths: the
344
+ * DynamicJobFn generator (via `gatherUpstreamSnapshot`) and a standard
345
+ * `run:`/step job (via `mergeUpstreamOutputs` → the `upstreamInvokeResults`
346
+ * dispatch field).
347
+ */
348
+ export declare function gatherInvokeResults(db: Kysely<Database>, runId: string, gateNames: readonly string[]): Promise<Record<string, InvokeResult[]>>;
322
349
  /**
323
350
  * Fold a `runsOnAll` upstream's host children into the `byHost` envelope
324
351
  * `{ byHost: { '<host>': outputs }, summary: { succeededHosts, failedHosts, outputs } }`.
@@ -369,14 +396,43 @@ export declare function mergeUpstreamOutputs(db: Kysely<Database>, runId: string
369
396
  mergedSecrets: Record<string, string> | undefined;
370
397
  upstreamJobOutputs: Record<string, Record<string, unknown>> | undefined;
371
398
  upstreamJobStatuses: Record<string, ExecutionJobStatus> | undefined;
399
+ upstreamInvokeResults: Record<string, InvokeResult[]> | undefined;
372
400
  }>;
373
- export declare function buildInternalJobConfigForWorkflow(workflow: any, job: any, sandboxGrant?: ResolvedSandboxGrant, firedSchedule?: {
374
- cronExpression?: string;
375
- timezone?: string;
376
- }): Record<string, unknown>;
401
+ export declare function buildOnEventMatched(dispatcherRef: {
402
+ current: Dispatcher | null;
403
+ }, providerRegistryRef: {
404
+ current: ProviderRegistry;
405
+ }, processingDepsRef: {
406
+ current: (() => ProcessingDeps) | null;
407
+ }): (event: any, lockFile: any, matchedWorkflows: any[], context?: EventMatchContext) => Promise<void>;
408
+ /**
409
+ * Build the invoke-gate `summon` callback: match the source repo's own opt-in
410
+ * `kiciEvent({ name })` subscribers, dispatch each as a normal in-repo run, and
411
+ * return the spawned run ids so the gate can correlate a proxy job per run.
412
+ *
413
+ * This is the composition-root half of the invoke gate — it reuses the same
414
+ * in-process match + dispatch path the internal-event router uses
415
+ * (`matchKiciEventSubscribers` + `dispatchInternalEventViaPipeline`), scoped to
416
+ * the source repo. The gate executor (`runInvokeGate`) enforces the chain-depth
417
+ * bound and persists the summon↔spawn correlation.
418
+ */
419
+ export declare function buildSummonCallback(dispatcherRef: {
420
+ current: Dispatcher | null;
421
+ }, providerRegistryRef: {
422
+ current: ProviderRegistry;
423
+ }, eventRouter: EventRouter, processingDepsRef: {
424
+ current: (() => ProcessingDeps) | null;
425
+ }): (args: SummonArgs) => Promise<SummonedRun[]>;
377
426
  export declare function bootstrapOrchestrator(config: AppConfig, hooks: OrchestratorHooks, options?: {
378
427
  otelSdk?: {
379
428
  shutdown(): Promise<void>;
380
429
  };
430
+ /**
431
+ * Test-only fault-injection policy. Undefined in production (server.ts /
432
+ * standalone.ts pass nothing), so every seam sees an undefined policy and
433
+ * runs with no fault injection. A test-only entrypoint passes a policy to
434
+ * drive the seams directly.
435
+ */
436
+ faultInjection?: OrchestratorFaultInjection;
381
437
  }): Promise<void>;
382
438
  //# sourceMappingURL=orchestrator-core.d.ts.map
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The `ProcessingDeps` bag the DIRECT-INGRESS pipeline runs on.
3
+ *
4
+ * Two pipelines assemble this bag. `server.ts` builds the one the Platform WS
5
+ * relay hands to `processWebhook`; this module builds the one every HTTP
6
+ * ingress uses — the direct GitHub route, the generic webhook routes, and the
7
+ * internal-event dispatch adapter. On an independent orchestrator there is no
8
+ * relay, so this is the ONLY bag it ever has.
9
+ *
10
+ * It lives outside `app.ts` because it is the seam an approval defect hides in.
11
+ * A field the composition root forgets is invisible: the pipeline reads it as
12
+ * `undefined`, every guard downstream is written to degrade rather than throw,
13
+ * and the feature is silently inert. Assembling the bag in a function with a
14
+ * declared return type is what lets a test assert the wiring directly instead
15
+ * of asserting it through a 2,000-line composition root that no test
16
+ * constructs.
17
+ */
18
+ import type { ProcessingDeps } from './processor.js';
19
+ import { TrustDirectoryStore } from '../security/trust-directory-store.js';
20
+ import { TrustPolicyStore } from '../security/trust-policy-store.js';
21
+ import type { SourceLocationData } from '../reporting/check-run-summary.js';
22
+ /**
23
+ * Everything the bag reads that `AppDependencies` already carries.
24
+ *
25
+ * Declared structurally rather than as `AppDependencies` so this module does
26
+ * not import `app.ts` (which imports it) and so the fields the bag actually
27
+ * consumes are enumerated in one readable place. `AppDependencies` satisfies it
28
+ * by construction — the `createApp` call site is the compiler's check of that.
29
+ */
30
+ export interface DirectIngressDepsSource {
31
+ db: ProcessingDeps['db'] & {};
32
+ config: {
33
+ mode: NonNullable<ProcessingDeps['orchestratorMode']>;
34
+ secretKey?: string | undefined;
35
+ instanceId?: string | undefined;
36
+ rosterGraceMs?: number | undefined;
37
+ maxFanoutHosts?: number | undefined;
38
+ globalEvalRoundTimeoutMs?: number | undefined;
39
+ globalEvalCandidateTimeoutMs?: number | undefined;
40
+ globalEvalWaitTimeoutMs?: number | undefined;
41
+ };
42
+ dedup: ProcessingDeps['dedup'];
43
+ providerRegistry: ProcessingDeps['providerRegistry'];
44
+ ensureProviderBundle?: ProcessingDeps['ensureProviderBundle'];
45
+ lockFileCache: ProcessingDeps['lockFileCache'];
46
+ contentRequirementsCache?: ProcessingDeps['contentRequirementsCache'];
47
+ dispatcher: ProcessingDeps['dispatcher'];
48
+ platformClient?: ProcessingDeps['platformClient'];
49
+ sourceCache?: ProcessingDeps['sourceCache'];
50
+ buildCoordinator?: ProcessingDeps['buildCoordinator'];
51
+ depCache?: ProcessingDeps['depCache'];
52
+ pendingBuilds?: ProcessingDeps['pendingBuilds'];
53
+ pendingInits?: ProcessingDeps['pendingInits'];
54
+ pendingDynamics?: ProcessingDeps['pendingDynamics'];
55
+ pendingGlobalEvals?: ProcessingDeps['pendingGlobalEvals'];
56
+ globalEvalCache?: ProcessingDeps['globalEvalCache'];
57
+ checkRunReporter?: ProcessingDeps['checkRunReporter'];
58
+ executionTracker?: ProcessingDeps['executionTracker'];
59
+ eventRouter?: ProcessingDeps['eventRouter'];
60
+ invokeGateDeps?: ProcessingDeps['invokeGateDeps'];
61
+ registrationStore?: ProcessingDeps['registrationStore'];
62
+ registrationIndex?: ProcessingDeps['registrationIndex'];
63
+ secretResolver?: ProcessingDeps['secretResolver'];
64
+ sandboxAllowListReader?: ProcessingDeps['sandboxAllowListReader'];
65
+ logStorage?: ProcessingDeps['logStorage'];
66
+ contextStore?: ProcessingDeps['contextStore'];
67
+ variableStore?: ProcessingDeps['variableStore'];
68
+ heldRunStore?: ProcessingDeps['heldRunStore'];
69
+ coordinator?: ProcessingDeps['coordinator'];
70
+ cronScheduler?: ProcessingDeps['cronScheduler'];
71
+ globalWorkflowPolicy?: ProcessingDeps['globalWorkflowPolicy'];
72
+ eventLogWriter?: ProcessingDeps['eventLog'];
73
+ accessLogWriter?: ProcessingDeps['accessLogWriter'];
74
+ hostRosterStore?: ProcessingDeps['hostRosterStore'];
75
+ clusterSettings?: ProcessingDeps['clusterSettings'];
76
+ }
77
+ /** The per-process stores this factory owns, exposed so the caller can reuse them. */
78
+ export interface DirectIngressStores {
79
+ trustDirectoryStore: TrustDirectoryStore;
80
+ trustPolicyStore: TrustPolicyStore;
81
+ }
82
+ /**
83
+ * Build the direct-ingress `ProcessingDeps` factory.
84
+ *
85
+ * The returned function assembles a fresh bag per call, so every field reads
86
+ * the CURRENT subsystem instance — the provider registry is swapped wholesale
87
+ * on a source reload, and a bag captured once would keep dispatching through
88
+ * the replaced one.
89
+ *
90
+ * The two stores are constructed once here rather than per call: both are
91
+ * stateless over the database handle, and one of them is read on every PR
92
+ * delivery.
93
+ */
94
+ export declare function createDirectIngressProcessingDeps(deps: DirectIngressDepsSource, hooks: {
95
+ onSourceLocationsExtracted: (workflowName: string, jobName: string, locations: Array<SourceLocationData | undefined>) => void;
96
+ }): {
97
+ build: () => ProcessingDeps;
98
+ stores: DirectIngressStores;
99
+ };
100
+ //# sourceMappingURL=direct-ingress-deps.d.ts.map