@kici-dev/orchestrator 0.4.0 → 0.5.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.
- package/dist/__test-helpers__/mock-db.d.ts +4 -0
- package/dist/agent/agent-version.d.ts +34 -0
- package/dist/agent/dispatcher.d.ts +70 -0
- package/dist/app.d.ts +23 -1
- package/dist/cache/global-eval-round-cache.d.ts +88 -0
- package/dist/cache/index.d.ts +3 -0
- package/dist/cache/pending-global-evals.d.ts +42 -0
- package/dist/cache/pending-inits.d.ts +10 -0
- package/dist/cli/commands/cluster-settings.d.ts +41 -3
- package/dist/cli/commands/runs.d.ts +1 -0
- package/dist/cli.js +1205 -620
- package/dist/cluster/cluster-settings-reader.d.ts +53 -1
- package/dist/config.d.ts +27 -0
- package/dist/content-requirements-cache.d.ts +55 -0
- package/dist/db/migrations/109_cluster_settings_cache_knobs.d.ts +4 -0
- package/dist/db/migrations/110_cluster_settings_global_eval_knobs.d.ts +4 -0
- package/dist/db/migrations/111_cluster_settings_global_eval_wait.d.ts +4 -0
- package/dist/db/migrations/112_execution_runs_workflow_repo.d.ts +4 -0
- package/dist/db/migrations/113_execution_runs_workflow_repo_index.d.ts +30 -0
- package/dist/db/migrations/114_ingest_queue_claim.d.ts +4 -0
- package/dist/db/migrations/115_global_workflows_cluster_switch.d.ts +9 -0
- package/dist/db/types.d.ts +60 -2
- package/dist/metrics/agent-metrics-aggregator.d.ts +2 -2
- package/dist/metrics/prometheus.d.ts +59 -0
- package/dist/orchestrator-core.d.ts +12 -1
- package/dist/pipeline/content-filter.d.ts +71 -0
- package/dist/pipeline/dispatch-matched-workflow.d.ts +247 -8
- package/dist/pipeline/global-eval-round.d.ts +293 -0
- package/dist/pipeline/job-contexts.d.ts +16 -17
- package/dist/pipeline/process-webhook.d.ts +7 -0
- package/dist/pipeline/processor.d.ts +56 -2
- package/dist/pipeline/route-or-dispatch-jobs.d.ts +6 -0
- package/dist/pipeline/test-pipeline.d.ts +12 -0
- package/dist/pipeline/webhook-payload-store.d.ts +20 -0
- package/dist/provenance/backfill-run.d.ts +10 -1
- package/dist/provider-registry.d.ts +38 -3
- package/dist/providers/github/check-status-poster.d.ts +22 -3
- package/dist/providers/github/commit-message.d.ts +20 -0
- package/dist/providers/github/file-contents.d.ts +40 -0
- package/dist/providers/github/index.d.ts +2 -0
- package/dist/providers/universal-git/config.d.ts +2 -0
- package/dist/providers/universal-git/normalizer.d.ts +10 -0
- package/dist/queue/cleanup.d.ts +7 -1
- package/dist/queue/job-queue.d.ts +69 -6
- package/dist/queue/terminalize-unroutable.d.ts +13 -0
- package/dist/registration/registration-run-match.d.ts +47 -0
- package/dist/reporting/check-run-reporter.d.ts +52 -1
- package/dist/reporting/execution-tracker.d.ts +117 -7
- package/dist/reporting/log-chunk-sink.d.ts +8 -5
- package/dist/routes/admin-org-settings.d.ts +5 -0
- package/dist/routes/admin.d.ts +6 -0
- package/dist/scaler/manager.d.ts +10 -8
- package/dist/security/global-workflow-policy.d.ts +52 -12
- package/dist/server.js +27553 -23779
- package/dist/standalone.js +5840 -2207
- package/dist/webhook/ingest-accept.d.ts +70 -0
- package/dist/webhook/ingest-overflow-buffer.d.ts +35 -4
- package/dist/webhook/ingest-overflow-replayer.d.ts +50 -6
- package/dist/ws/agent-handler.d.ts +3 -0
- package/dist/ws/dashboard-global-workflows-handler.d.ts +30 -9
- package/dist/ws/execution-status-frame.d.ts +32 -0
- package/dist/ws/platform-client.d.ts +14 -0
- package/dist/ws/test-relay-handlers.d.ts +35 -10
- package/installer-image-digests.json +3 -3
- package/package.json +4 -4
- package/sbom.spdx.json +57 -52
- package/dist/pipeline/inline-eval.d.ts +0 -44
|
@@ -1,9 +1,46 @@
|
|
|
1
1
|
import type { Kysely } from 'kysely';
|
|
2
2
|
import type { Database } from '../db/types.js';
|
|
3
3
|
/** Numeric columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
4
|
-
export type ClusterNumberColumn = 'max_github_payload_bytes' | 'event_log_max_payload_bytes' | 'lock_file_max_bytes' | 'webhook_dedup_ttl_ms' | 'contributor_cache_ttl_ms' | 'event_router_event_ttl_seconds' | 'event_router_max_dispatch_attempts' | 'queue_max_depth' | 'reroute_flap_grace_ms' | 'max_fanout_hosts' | 'event_router_rate_limit_per_workflow_per_minute' | 'cache_max_tarball_bytes' | 'cache_ttl_days' | 'check_run_tracking_ttl_days' | 'concurrency_wait_timeout_ms' | 'agent_token_ttl_ms' | 'ownership_db_check_timeout_ms' | 'unroutable_grace_ms';
|
|
4
|
+
export type ClusterNumberColumn = 'max_github_payload_bytes' | 'event_log_max_payload_bytes' | 'lock_file_max_bytes' | 'webhook_dedup_ttl_ms' | 'contributor_cache_ttl_ms' | 'event_router_event_ttl_seconds' | 'event_router_max_dispatch_attempts' | 'queue_max_depth' | 'reroute_flap_grace_ms' | 'max_fanout_hosts' | 'event_router_rate_limit_per_workflow_per_minute' | 'cache_max_tarball_bytes' | 'cache_ttl_days' | 'lockfile_cache_max' | 'lockfile_cache_max_bytes' | 'lockfile_cache_ttl_ms' | 'content_cache_max' | 'content_cache_max_bytes' | 'content_cache_ttl_ms' | 'global_eval_round_timeout_ms' | 'global_eval_candidate_timeout_ms' | 'global_eval_cache_max' | 'global_eval_wait_timeout_ms' | 'check_run_tracking_ttl_days' | 'concurrency_wait_timeout_ms' | 'agent_token_ttl_ms' | 'ownership_db_check_timeout_ms' | 'unroutable_grace_ms' | 'ingest_overflow_claim_timeout_ms';
|
|
5
5
|
/** Text columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
6
6
|
export type ClusterStringColumn = 'dashboard_verified_issuer';
|
|
7
|
+
/** Boolean columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
8
|
+
export type ClusterBooleanColumn = 'global_workflows_enabled';
|
|
9
|
+
/**
|
|
10
|
+
* Ceiling for the three LRU entry-count knobs — `lockfile_cache_max`,
|
|
11
|
+
* `content_cache_max`, and `global_eval_cache_max`.
|
|
12
|
+
*
|
|
13
|
+
* This is a boot-safety bound, not a policy preference. The underlying LRU
|
|
14
|
+
* allocates its index arrays eagerly from `max` — several typed arrays plus the
|
|
15
|
+
* TTL and size arrays the caches ask for — so the cost is paid at construction
|
|
16
|
+
* with zero entries cached. Measured on the shipped version: an empty cache at
|
|
17
|
+
* `max` 5,000,000 costs ~191 MB, and at 5,000,000,000 the constructor throws
|
|
18
|
+
* `RangeError: Invalid array length`.
|
|
19
|
+
*
|
|
20
|
+
* That throw is what makes an unbounded knob dangerous rather than merely
|
|
21
|
+
* wasteful. All three caches are built inside `bootstrapOrchestrator`, so a bad
|
|
22
|
+
* stored value crashes the orchestrator before its admin API is listening —
|
|
23
|
+
* and the admin API is the only way `kici-admin cluster-settings` can reach the
|
|
24
|
+
* stored value. The knob would brick the very tool needed to un-brick it.
|
|
25
|
+
*
|
|
26
|
+
* 100,000 is 200x the shipped default of 500 and costs ~4 MB per empty cache,
|
|
27
|
+
* so it is far above any plausible operator setting while keeping boot bounded.
|
|
28
|
+
*/
|
|
29
|
+
export declare const CACHE_MAX_ENTRIES_CEILING = 100000;
|
|
30
|
+
/**
|
|
31
|
+
* Bound a stored entry-count knob to something the LRU constructor survives.
|
|
32
|
+
*
|
|
33
|
+
* Applied at the read site rather than only at the write site, because the
|
|
34
|
+
* write-side validation cannot reach a value that is already in the database —
|
|
35
|
+
* set before the ceiling shipped, or written by any path other than the admin
|
|
36
|
+
* route. Clamping here is what actually guarantees a stored value cannot
|
|
37
|
+
* prevent boot.
|
|
38
|
+
*
|
|
39
|
+
* A value that is not a usable positive count (NaN, non-finite, below 1) falls
|
|
40
|
+
* back to the configured default rather than clamping to 1: a 1-entry cache
|
|
41
|
+
* thrashes silently, which is harder to diagnose than simply ignoring garbage.
|
|
42
|
+
*/
|
|
43
|
+
export declare function clampCacheMaxEntries(value: number, fallback: number): number;
|
|
7
44
|
/**
|
|
8
45
|
* A knob read that keeps "the operator never set this" separate from "we could
|
|
9
46
|
* not read it".
|
|
@@ -64,6 +101,21 @@ export declare class ClusterSettingsReader {
|
|
|
64
101
|
* An empty stored string is unset, matching {@link getString}.
|
|
65
102
|
*/
|
|
66
103
|
tryGetString(column: ClusterStringColumn): Promise<ClusterSettingRead<string>>;
|
|
104
|
+
/**
|
|
105
|
+
* Resolve a fleet-wide boolean knob without collapsing a read failure into a
|
|
106
|
+
* default.
|
|
107
|
+
*
|
|
108
|
+
* There is deliberately no `getBoolean(column, fallback)` companion. The
|
|
109
|
+
* security gate that consumes this must tell the reader's outcomes apart
|
|
110
|
+
* itself: a stored `false` and a NULL both deny today, but they deny for
|
|
111
|
+
* different reasons, and `{ ok: false }` must deny regardless of what the
|
|
112
|
+
* configured default happens to be. A convenience wrapper that folded the
|
|
113
|
+
* failure into the default would be safe only for as long as that default
|
|
114
|
+
* stayed `false`. A caller that only needs a display value (the dashboard
|
|
115
|
+
* status badge) folds `{ ok: false }` into the default explicitly at its own
|
|
116
|
+
* site, where getting it wrong misreports a badge rather than opening a gate.
|
|
117
|
+
*/
|
|
118
|
+
tryGetBoolean(column: ClusterBooleanColumn): Promise<ClusterSettingRead<boolean>>;
|
|
67
119
|
/**
|
|
68
120
|
* The cluster_settings row version last seen in the cache (0 if never loaded).
|
|
69
121
|
*
|
package/dist/config.d.ts
CHANGED
|
@@ -56,9 +56,17 @@ declare const configSchema: z.ZodObject<{
|
|
|
56
56
|
lockfileCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
57
57
|
lockfileCacheTtlMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
58
58
|
lockfileCacheMaxBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
59
|
+
contentCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
60
|
+
contentCacheTtlMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
61
|
+
contentCacheMaxBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
62
|
+
globalEvalRoundTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
63
|
+
globalEvalCandidateTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
64
|
+
globalEvalCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
65
|
+
globalEvalWaitTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
59
66
|
queueMaxDepth: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
60
67
|
queueTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
61
68
|
unroutableGraceMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
69
|
+
globalWorkflowsEnabled: z.ZodPipe<z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>, z.ZodTransform<boolean, string | boolean>>;
|
|
62
70
|
queueBackpressureThreshold: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
63
71
|
workerConcurrency: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
64
72
|
concurrencyWaitTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -81,6 +89,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
81
89
|
ingestOverflowReplayIntervalMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
82
90
|
ingestOverflowReplayBatch: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
83
91
|
ingestOverflowMaxAttempts: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
92
|
+
ingestOverflowClaimTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
84
93
|
rerouteSpawnWindowMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
85
94
|
rerouteAckTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
86
95
|
rerouteMaxHops: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -250,9 +259,17 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
250
259
|
lockfileCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
251
260
|
lockfileCacheTtlMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
252
261
|
lockfileCacheMaxBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
262
|
+
contentCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
263
|
+
contentCacheTtlMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
264
|
+
contentCacheMaxBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
265
|
+
globalEvalRoundTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
266
|
+
globalEvalCandidateTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
267
|
+
globalEvalCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
268
|
+
globalEvalWaitTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
253
269
|
queueMaxDepth: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
254
270
|
queueTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
255
271
|
unroutableGraceMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
272
|
+
globalWorkflowsEnabled: z.ZodPipe<z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>, z.ZodTransform<boolean, string | boolean>>;
|
|
256
273
|
queueBackpressureThreshold: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
257
274
|
workerConcurrency: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
258
275
|
concurrencyWaitTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -275,6 +292,7 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
275
292
|
ingestOverflowReplayIntervalMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
276
293
|
ingestOverflowReplayBatch: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
277
294
|
ingestOverflowMaxAttempts: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
295
|
+
ingestOverflowClaimTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
278
296
|
rerouteSpawnWindowMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
279
297
|
rerouteAckTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
280
298
|
rerouteMaxHops: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -477,9 +495,17 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
477
495
|
lockfileCacheMax: number;
|
|
478
496
|
lockfileCacheTtlMs: number;
|
|
479
497
|
lockfileCacheMaxBytes: number;
|
|
498
|
+
contentCacheMax: number;
|
|
499
|
+
contentCacheTtlMs: number;
|
|
500
|
+
contentCacheMaxBytes: number;
|
|
501
|
+
globalEvalRoundTimeoutMs: number;
|
|
502
|
+
globalEvalCandidateTimeoutMs: number;
|
|
503
|
+
globalEvalCacheMax: number;
|
|
504
|
+
globalEvalWaitTimeoutMs: number;
|
|
480
505
|
queueMaxDepth: number;
|
|
481
506
|
queueTimeoutMs: number;
|
|
482
507
|
unroutableGraceMs: number;
|
|
508
|
+
globalWorkflowsEnabled: boolean;
|
|
483
509
|
queueBackpressureThreshold: number;
|
|
484
510
|
workerConcurrency: number;
|
|
485
511
|
concurrencyWaitTimeoutMs: number;
|
|
@@ -499,6 +525,7 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
499
525
|
ingestOverflowReplayIntervalMs: number;
|
|
500
526
|
ingestOverflowReplayBatch: number;
|
|
501
527
|
ingestOverflowMaxAttempts: number;
|
|
528
|
+
ingestOverflowClaimTimeoutMs: number;
|
|
502
529
|
rerouteSpawnWindowMs: number;
|
|
503
530
|
rerouteAckTimeoutMs: number;
|
|
504
531
|
rerouteMaxHops: number;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-agnostic LRU cache for source-file contents fetched at a ref.
|
|
3
|
+
*
|
|
4
|
+
* Wraps any {@link FileContentsFetcher} with an in-memory LRU cache keyed by
|
|
5
|
+
* `(provider, repo, sha, path)`. The key is content-addressable by
|
|
6
|
+
* construction: a commit SHA pins immutable bytes, so a cached entry for a
|
|
7
|
+
* `(repo, sha, path)` triple can never go stale within the SHA. When the caller
|
|
8
|
+
* passes a mutable ref (a branch name) instead of a SHA, staleness is bounded by
|
|
9
|
+
* the TTL, exactly as the lock-file cache handles the same case.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors {@link ../lockfile-cache.ts LockFileCache}: same LRU + in-flight
|
|
12
|
+
* coalescing shape so N concurrent misses for one key run a single fetch.
|
|
13
|
+
*/
|
|
14
|
+
import type { FileContentsFetcher } from '@kici-dev/engine';
|
|
15
|
+
/**
|
|
16
|
+
* One fetched file's presence + bytes. `present: true` with `bytes: undefined`
|
|
17
|
+
* is the size-limit case (the file exists but the provider returned no inline
|
|
18
|
+
* content, e.g. a GitHub file over 1 MiB) — callers MUST treat it as
|
|
19
|
+
* "content unavailable for matching", never as an absent or empty file.
|
|
20
|
+
*/
|
|
21
|
+
export interface FileContentEntry {
|
|
22
|
+
readonly present: boolean;
|
|
23
|
+
readonly bytes?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare class ContentRequirementsCache {
|
|
26
|
+
private readonly cache;
|
|
27
|
+
private readonly inFlight;
|
|
28
|
+
private hits;
|
|
29
|
+
private misses;
|
|
30
|
+
constructor(options: {
|
|
31
|
+
max: number;
|
|
32
|
+
ttl: number;
|
|
33
|
+
maxBytes?: number;
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Fetch a file's contents at a ref, using the provided fetcher and LRU
|
|
37
|
+
* caching. Each distinct `(provider, repo, sha, path)` is fetched at most
|
|
38
|
+
* once; concurrent misses coalesce onto one fetch.
|
|
39
|
+
*
|
|
40
|
+
* @param fetcher - Provider-specific file-contents fetcher.
|
|
41
|
+
* @param repo - Provider repo identifier ("owner/repo").
|
|
42
|
+
* @param sha - Git ref (commit SHA, or a branch/tag name).
|
|
43
|
+
* @param path - Repo-relative file path.
|
|
44
|
+
*/
|
|
45
|
+
get(fetcher: FileContentsFetcher, repo: string, sha: string, path: string): Promise<FileContentEntry>;
|
|
46
|
+
private fetchAndCache;
|
|
47
|
+
/** Cache statistics for metrics/monitoring. */
|
|
48
|
+
getStats(): {
|
|
49
|
+
hits: number;
|
|
50
|
+
misses: number;
|
|
51
|
+
size: number;
|
|
52
|
+
calculatedSize: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=content-requirements-cache.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,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
|
package/dist/db/types.d.ts
CHANGED
|
@@ -352,6 +352,12 @@ export interface IngestOverflowBufferTable {
|
|
|
352
352
|
status: Generated<string>;
|
|
353
353
|
/** Last replay error, or null. */
|
|
354
354
|
last_error: string | null;
|
|
355
|
+
/**
|
|
356
|
+
* When the row moved `buffered` → `replaying`; null while it is buffered.
|
|
357
|
+
* Separate from `captured_at` (which orders the FIFO drain) so a long-buffered
|
|
358
|
+
* row is not reclaimed the instant a worker picks it up.
|
|
359
|
+
*/
|
|
360
|
+
claimed_at: ColumnType<Date | null, Date | null | undefined, Date | null>;
|
|
355
361
|
}
|
|
356
362
|
export type DispatchQueueItem = Selectable<DispatchQueueTable>;
|
|
357
363
|
export type NewDispatchQueueItem = Insertable<DispatchQueueTable>;
|
|
@@ -471,6 +477,20 @@ export interface ExecutionRunTable {
|
|
|
471
477
|
* when resolving the actor to a KiCI user.
|
|
472
478
|
*/
|
|
473
479
|
trigger_actor_user_id: string | null;
|
|
480
|
+
/**
|
|
481
|
+
* The repository that DEFINES this run's workflow, when that is not the
|
|
482
|
+
* repository the run acted on.
|
|
483
|
+
*
|
|
484
|
+
* `repo_identifier` is the repository the run acted on and whose code its
|
|
485
|
+
* jobs check out. For an organization-wide workflow dispatched against
|
|
486
|
+
* another repository, the workflow was authored somewhere else, and that
|
|
487
|
+
* authoring repository is recorded here. NULL means the two are the same —
|
|
488
|
+
* true of every per-repository run.
|
|
489
|
+
*
|
|
490
|
+
* Read by the rerun path, which must resolve the workflow from the
|
|
491
|
+
* repository that defines it rather than from the one it ran against.
|
|
492
|
+
*/
|
|
493
|
+
workflow_repo_identifier: string | null;
|
|
474
494
|
/** Human-readable reason why the run failed (null for non-failed runs). */
|
|
475
495
|
failure_reason: string | null;
|
|
476
496
|
/**
|
|
@@ -1514,8 +1534,6 @@ export interface OrgSettingsRepoPatternEntry {
|
|
|
1514
1534
|
export interface OrgSettingsTable {
|
|
1515
1535
|
/** Customer/org identifier (primary key) */
|
|
1516
1536
|
customer_id: string;
|
|
1517
|
-
/** Whether global workflows are enabled for this org */
|
|
1518
|
-
global_workflows_enabled: ColumnType<boolean, boolean | undefined, boolean>;
|
|
1519
1537
|
/** Repos allowed to author global workflows (null = any repo can author) */
|
|
1520
1538
|
global_workflow_allowed_repos: ColumnType<OrgSettingsRepoPatternEntry[] | null, OrgSettingsRepoPatternEntry[] | null | undefined | string, OrgSettingsRepoPatternEntry[] | null | string>;
|
|
1521
1539
|
/** Repos with elevated trust for global workflow execution (null = none) */
|
|
@@ -1710,6 +1728,32 @@ export interface ClusterSettingsTable {
|
|
|
1710
1728
|
event_router_rate_limit_per_workflow_per_minute: ColumnType<number | null, number | null | undefined, number | null>;
|
|
1711
1729
|
cache_max_tarball_bytes: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1712
1730
|
cache_ttl_days: ColumnType<number | null, number | null | undefined, number | null>;
|
|
1731
|
+
/** LRU entry ceiling for the lock-file cache. NULL ⇒ the configured default. Applies at next restart. */
|
|
1732
|
+
lockfile_cache_max: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1733
|
+
/** Byte ceiling for the lock-file cache. NULL ⇒ the configured default. Applies at next restart. */
|
|
1734
|
+
lockfile_cache_max_bytes: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1735
|
+
/** Entry TTL (ms) for the lock-file cache. NULL ⇒ the configured default. Applies at next restart. */
|
|
1736
|
+
lockfile_cache_ttl_ms: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1737
|
+
/** LRU entry ceiling for the Tier-1 content cache. NULL ⇒ the configured default. Applies at next restart. */
|
|
1738
|
+
content_cache_max: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1739
|
+
/** Byte ceiling for the Tier-1 content cache. NULL ⇒ the configured default. Applies at next restart. */
|
|
1740
|
+
content_cache_max_bytes: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1741
|
+
/** Entry TTL (ms) for the Tier-1 content cache. NULL ⇒ the configured default. Applies at next restart. */
|
|
1742
|
+
content_cache_ttl_ms: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1743
|
+
/** Wall-clock budget (ms) for a whole Tier-2 global eval round. NULL ⇒ the configured default. Read per round. */
|
|
1744
|
+
global_eval_round_timeout_ms: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1745
|
+
/** Wall-clock budget (ms) for one candidate inside a round. NULL ⇒ the configured default. Read per round. */
|
|
1746
|
+
global_eval_candidate_timeout_ms: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1747
|
+
/** LRU entry ceiling for the round-result cache. NULL ⇒ the configured default. Applies at next restart. */
|
|
1748
|
+
global_eval_cache_max: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1749
|
+
/**
|
|
1750
|
+
* Orchestrator-side ceiling (ms) on waiting for one eval round to settle.
|
|
1751
|
+
* Distinct from the two budgets above, which the agent enforces on itself: a
|
|
1752
|
+
* round that never reaches an agent — or an agent that wedges before its own
|
|
1753
|
+
* budget starts — is only bounded here. NULL ⇒ the configured default. Read
|
|
1754
|
+
* per round.
|
|
1755
|
+
*/
|
|
1756
|
+
global_eval_wait_timeout_ms: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1713
1757
|
/**
|
|
1714
1758
|
* Retention window in days for `check_run_tracking` rows. The hourly cleanup
|
|
1715
1759
|
* sweep deletes rows untouched for longer than this; 0 disables the sweep.
|
|
@@ -1722,6 +1766,20 @@ export interface ClusterSettingsTable {
|
|
|
1722
1766
|
* 0 disables fast-fail, leaving `queue_timeout_ms` as the only backstop.
|
|
1723
1767
|
*/
|
|
1724
1768
|
unroutable_grace_ms: ColumnType<number | null, number | null | undefined, number | null>;
|
|
1769
|
+
/**
|
|
1770
|
+
* Fleet-wide master switch for global workflows. NULL ⇒ the orchestrator's
|
|
1771
|
+
* configured default (`KICI_GLOBAL_WORKFLOWS_ENABLED`, default false). Read
|
|
1772
|
+
* per policy decision through `ClusterSettingsReader.tryGetBoolean`, which
|
|
1773
|
+
* reports an unreadable row separately so the gate can fail closed.
|
|
1774
|
+
*/
|
|
1775
|
+
global_workflows_enabled: ColumnType<boolean | null, boolean | null | undefined, boolean | null>;
|
|
1776
|
+
/**
|
|
1777
|
+
* How long a `replaying` claim on `ingest_overflow_buffer` may stand before
|
|
1778
|
+
* the drain pass reclaims the row for another worker. NULL ⇒ the
|
|
1779
|
+
* orchestrator's configured default. Must exceed the longest a single
|
|
1780
|
+
* delivery's pipeline can legitimately run.
|
|
1781
|
+
*/
|
|
1782
|
+
ingest_overflow_claim_timeout_ms: ColumnType<number | null, number | null | undefined, number | null>;
|
|
1725
1783
|
concurrency_wait_timeout_ms: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1726
1784
|
agent_token_ttl_ms: ColumnType<string | null, number | null | undefined, number | null>;
|
|
1727
1785
|
/**
|
|
@@ -47,10 +47,10 @@ export declare class AgentMetricsAggregator {
|
|
|
47
47
|
private store;
|
|
48
48
|
private defaultRetentionMs;
|
|
49
49
|
/**
|
|
50
|
-
* Optional lookup: agentId → scaler backend
|
|
50
|
+
* Optional lookup: agentId → scaler backend type (e.g. `container`,
|
|
51
51
|
* `firecracker`, `bare-metal`). Returning null marks the agent as
|
|
52
52
|
* static / stateful — we then stamp the `scaler` label as `'stateful'`.
|
|
53
|
-
* Wired from ScalerManager.
|
|
53
|
+
* Wired from ScalerManager.getBackendType in production. Tests can
|
|
54
54
|
* leave it undefined; in that case the `scaler` label is omitted.
|
|
55
55
|
*/
|
|
56
56
|
private readonly getScalerForAgent?;
|
|
@@ -93,6 +93,13 @@ export declare const ingestShedTotal: import("@opentelemetry/api").Counter<impor
|
|
|
93
93
|
export declare const stateReplayBreakerTripsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
94
94
|
/** Total webhook-ingest admissions granted. */
|
|
95
95
|
export declare const ingestAdmittedTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
96
|
+
/**
|
|
97
|
+
* Webhook pipelines that threw. Labels:
|
|
98
|
+
* - phase: post_ack — the delivery was already acknowledged, so the failure
|
|
99
|
+
* could not be reported in the response and is only visible here, in the
|
|
100
|
+
* event log, and in the queue row.
|
|
101
|
+
*/
|
|
102
|
+
export declare const webhookPipelineFailuresTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
96
103
|
/** Set the current buffered-row depth (called by the buffer + replayer). */
|
|
97
104
|
export declare function setIngestOverflowBuffered(value: number): void;
|
|
98
105
|
/** Current buffered-row depth (test helper). */
|
|
@@ -291,6 +298,58 @@ export declare const universalGitRegistrationErrorsTotal: import("@opentelemetry
|
|
|
291
298
|
* 'id_mismatch' (a username-matched link has a different provider_user_id)
|
|
292
299
|
*/
|
|
293
300
|
export declare const trustMatchRefusedNoIdTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
301
|
+
/**
|
|
302
|
+
* Candidates handed to a global eval round.
|
|
303
|
+
*
|
|
304
|
+
* Equal to `sum(kici_orch_global_eval_verdicts_total)` by construction: every
|
|
305
|
+
* candidate receives exactly one verdict, including on the fail-closed path
|
|
306
|
+
* where the round never runs. Kept as its own series because it is the natural
|
|
307
|
+
* top-line rate and the denominator the outcome breakdown divides — a
|
|
308
|
+
* divergence between the two would be a bug in the round, never a condition an
|
|
309
|
+
* operator should watch for.
|
|
310
|
+
*/
|
|
311
|
+
export declare const globalEvalCandidatesTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
312
|
+
/**
|
|
313
|
+
* Per-candidate verdicts a global eval round produced.
|
|
314
|
+
*
|
|
315
|
+
* Labels:
|
|
316
|
+
* - outcome: run (the filter admitted it) | filtered (the filter excluded it) | indeterminate (the round could not decide — a failed round, a budget breach, or a verdict that never arrived)
|
|
317
|
+
*/
|
|
318
|
+
export declare const globalEvalVerdictsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
319
|
+
/**
|
|
320
|
+
* Wall-clock duration of one dispatched global eval round, from dispatch to
|
|
321
|
+
* settled verdicts. A cache hit records nothing — it never dispatches a round.
|
|
322
|
+
*
|
|
323
|
+
* Buckets: 1s to 10min, covering a fast round through the default 120s agent
|
|
324
|
+
* budget and the 240s orchestrator wait ceiling.
|
|
325
|
+
*
|
|
326
|
+
* Labels:
|
|
327
|
+
* - result: success (the round settled) | error (dispatch rejected, the wait ceiling fired, or the round decided nothing)
|
|
328
|
+
*/
|
|
329
|
+
export declare const globalEvalRoundDurationSeconds: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
|
|
330
|
+
/**
|
|
331
|
+
* Jobs a round's `DynamicJobFn` generators produced, summed over the round's
|
|
332
|
+
* candidates. Recorded once per settled round, including zero.
|
|
333
|
+
*
|
|
334
|
+
* Buckets cover the common small fan-outs through a large matrix expansion.
|
|
335
|
+
*/
|
|
336
|
+
export declare const globalEvalJobsGenerated: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
|
|
337
|
+
/**
|
|
338
|
+
* Global eval round cache lookups by outcome.
|
|
339
|
+
*
|
|
340
|
+
* Three outcomes, not two. An input that cannot be serialized yields no cache
|
|
341
|
+
* key at all, so it never reaches the cache and registers neither a hit nor a
|
|
342
|
+
* miss — counting only hits and misses would drop those lookups from the
|
|
343
|
+
* denominator and make the hit rate read higher than it is.
|
|
344
|
+
*
|
|
345
|
+
* Expect a hit rate near zero on a healthy cluster: the key covers the whole
|
|
346
|
+
* event, so every real push is a miss by construction. This cache is a
|
|
347
|
+
* redelivery guard, not a steady-state optimization.
|
|
348
|
+
*
|
|
349
|
+
* Labels:
|
|
350
|
+
* - result: hit | miss | unkeyable (the round input could not be serialized)
|
|
351
|
+
*/
|
|
352
|
+
export declare const globalEvalCacheLookupsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
294
353
|
/**
|
|
295
354
|
* Internal events delivered to all matching workflows successfully (after the
|
|
296
355
|
* lease commits processed=true).
|
|
@@ -19,6 +19,7 @@ import { EventLogWriter } from './webhook/event-log.js';
|
|
|
19
19
|
import { AccessLogWriter } from './audit/access-log.js';
|
|
20
20
|
import { Dispatcher } from './agent/dispatcher.js';
|
|
21
21
|
import { LockFileCache } from './lockfile-cache.js';
|
|
22
|
+
import { ContentRequirementsCache } from './content-requirements-cache.js';
|
|
22
23
|
import { DedupCache } from './webhook/dedup.js';
|
|
23
24
|
import { ObserverRegistry } from './ws/observer-registry.js';
|
|
24
25
|
import { IngestAdmissionController } from './webhook/ingest-admission.js';
|
|
@@ -34,7 +35,7 @@ import type { ScalerConfig } from './scaler/index.js';
|
|
|
34
35
|
import type { CacheStorage } from './storage/index.js';
|
|
35
36
|
import { type ProvenanceTrustRoot } from './provenance/trust-root.js';
|
|
36
37
|
import { type ResolvedDashboardEncryptionKey } from './secrets/dashboard-encryption-key.js';
|
|
37
|
-
import { SourceCache, BuildCoordinator, DepCache, UserCache, DispatchCacheRefTracker, PendingBuildTracker, PendingInitTracker, PendingDynamicTracker } from './cache/index.js';
|
|
38
|
+
import { SourceCache, BuildCoordinator, DepCache, UserCache, DispatchCacheRefTracker, PendingBuildTracker, PendingInitTracker, PendingDynamicTracker, PendingGlobalEvalTracker, GlobalEvalRoundCache } from './cache/index.js';
|
|
38
39
|
import { ArtifactStore } from './artifacts/artifact-store.js';
|
|
39
40
|
import { CheckRunReporter } from './reporting/check-run-reporter.js';
|
|
40
41
|
import { StepLogBuffer } from './reporting/step-log-buffer.js';
|
|
@@ -98,6 +99,7 @@ export interface OrchestratorSubsystems {
|
|
|
98
99
|
pendingBuilds: PendingBuildTracker | undefined;
|
|
99
100
|
pendingInits: PendingInitTracker;
|
|
100
101
|
pendingDynamics: PendingDynamicTracker;
|
|
102
|
+
pendingGlobalEvals: PendingGlobalEvalTracker;
|
|
101
103
|
checkRunReporter: CheckRunReporter;
|
|
102
104
|
stepLogBuffer: StepLogBuffer;
|
|
103
105
|
sourceLocationStore: SourceLocationStore;
|
|
@@ -119,6 +121,8 @@ export interface OrchestratorSubsystems {
|
|
|
119
121
|
tokenStore: AgentTokenStore;
|
|
120
122
|
ownershipTracker: OwnershipTracker;
|
|
121
123
|
lockFileCache: LockFileCache;
|
|
124
|
+
contentRequirementsCache: ContentRequirementsCache;
|
|
125
|
+
globalEvalCache: GlobalEvalRoundCache;
|
|
122
126
|
dedup: DedupCache;
|
|
123
127
|
eventRouter: EventRouter;
|
|
124
128
|
/**
|
|
@@ -129,6 +133,13 @@ export interface OrchestratorSubsystems {
|
|
|
129
133
|
eventStore: EventStore;
|
|
130
134
|
eventEmitter: EventEmitter;
|
|
131
135
|
genericSourceManager: GenericSourceManager;
|
|
136
|
+
/**
|
|
137
|
+
* Re-register a generic source's provider bundle from its database row.
|
|
138
|
+
* The webhook pipeline calls it on an exact registry miss so the read side
|
|
139
|
+
* settles against server truth rather than a stand-in bundle. Shared by the
|
|
140
|
+
* relay path (server.ts) and the direct-ingress path (app.ts).
|
|
141
|
+
*/
|
|
142
|
+
ensureProviderBundle: (routingKey: string) => Promise<boolean>;
|
|
132
143
|
trustStore: TrustStore;
|
|
133
144
|
registrationStore: RegistrationStore;
|
|
134
145
|
registrationIndex: RegistrationIndex;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-1 declarative content-requirements filter (execution-purity model, Part B).
|
|
3
|
+
*
|
|
4
|
+
* After Tier-0 trigger matching selects candidate workflows, this step fetches
|
|
5
|
+
* the source files each candidate's `requires` names — once per distinct
|
|
6
|
+
* `(repo, sha, path)` via the LRU cache — evaluates the (pure DATA) requirements
|
|
7
|
+
* with the engine matcher, and drops any candidate that FAILS or is
|
|
8
|
+
* INDETERMINATE before dispatch. No author code is executed: `requires` is a
|
|
9
|
+
* declarative query the orchestrator interprets, which is what keeps content
|
|
10
|
+
* filtering inside the orchestrator under the purity model.
|
|
11
|
+
*
|
|
12
|
+
* Fail-visible: a dropped candidate (definite negative, oversize/unparseable
|
|
13
|
+
* content, a fetch error, or no fetcher/cache available) is logged with the
|
|
14
|
+
* concrete reason. An indeterminate file NEVER passes silently.
|
|
15
|
+
*/
|
|
16
|
+
import type { FileContentsFetcher, LockContentRequirement } from '@kici-dev/engine';
|
|
17
|
+
import type { ContentRequirementsCache } from '../content-requirements-cache.js';
|
|
18
|
+
/** A workflow candidate carrying the `requires` of the trigger that matched the event. */
|
|
19
|
+
export interface ContentFilterCandidate {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly requires?: readonly LockContentRequirement[];
|
|
22
|
+
}
|
|
23
|
+
/** The event the requirements are evaluated against: source repo + ref to fetch files at. */
|
|
24
|
+
export interface ContentFilterEvent {
|
|
25
|
+
/** Provider repo identifier ("owner/repo"). */
|
|
26
|
+
readonly repo: string;
|
|
27
|
+
/** Git ref (commit SHA, or branch/tag) at which files are read. */
|
|
28
|
+
readonly sha: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ContentFilterOptions {
|
|
31
|
+
/** Per-delivery file-contents fetcher; `undefined` when the provider has none. */
|
|
32
|
+
readonly fetcher: FileContentsFetcher | undefined;
|
|
33
|
+
/** Shared LRU cache; `undefined` when the deployment did not wire one. */
|
|
34
|
+
readonly cache: ContentRequirementsCache | undefined;
|
|
35
|
+
/** Delivery id for log correlation. */
|
|
36
|
+
readonly deliveryId?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* One dropped candidate.
|
|
40
|
+
*
|
|
41
|
+
* `indeterminate` separates the two reasons a drop happens, which mean opposite
|
|
42
|
+
* things to a workflow author: a definite content mismatch is the requirement
|
|
43
|
+
* doing its job, while an unreadable file, a fetch error, or a provider with no
|
|
44
|
+
* file-contents fetcher is the requirement never having been evaluated at all.
|
|
45
|
+
* Both drop the candidate — the filter is fail-visible, so an unevaluable file
|
|
46
|
+
* never passes — but a trace that renders the second as "excluded" tells an
|
|
47
|
+
* author their requirement said no when nothing ever read it.
|
|
48
|
+
*/
|
|
49
|
+
export interface DroppedCandidate {
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly reason: string;
|
|
52
|
+
/** True when the requirement could not be evaluated, rather than evaluating to false. */
|
|
53
|
+
readonly indeterminate?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface ContentFilterResult<C extends ContentFilterCandidate> {
|
|
56
|
+
readonly survivors: C[];
|
|
57
|
+
readonly dropped: DroppedCandidate[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Filter candidates by their declarative content requirements.
|
|
61
|
+
*
|
|
62
|
+
* Gathers each distinct `(repo, sha, path)` once via the cache, evaluates every
|
|
63
|
+
* candidate's `requires`, and returns the survivors (pass) split from the
|
|
64
|
+
* dropped (fail / indeterminate, each logged with its reason). A candidate with
|
|
65
|
+
* no `requires` always survives without any fetch (the fast path — like an empty
|
|
66
|
+
* `paths` filter). When a candidate has `requires` but no fetcher/cache is
|
|
67
|
+
* available, it is dropped as indeterminate (fail-visible), never dispatched
|
|
68
|
+
* unfiltered.
|
|
69
|
+
*/
|
|
70
|
+
export declare function filterByContentRequirements<C extends ContentFilterCandidate>(candidates: readonly C[], event: ContentFilterEvent, opts: ContentFilterOptions): Promise<ContentFilterResult<C>>;
|
|
71
|
+
//# sourceMappingURL=content-filter.d.ts.map
|