@kici-dev/orchestrator 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__test-helpers__/fake-scaler-state-store.d.ts +24 -0
- package/dist/__test-helpers__/mock-db-query.d.ts +130 -0
- package/dist/__test-helpers__/mock-db.d.ts +27 -0
- package/dist/agent/agent-version.d.ts +34 -0
- package/dist/agent/dispatcher.d.ts +151 -13
- package/dist/agent/host-roster.d.ts +37 -5
- package/dist/agent/registry.d.ts +2 -0
- package/dist/app.d.ts +56 -7
- package/dist/approvals/apply-decision.d.ts +67 -19
- package/dist/approvals/held-run-release-wiring.d.ts +45 -0
- package/dist/approvals/independent-wiring.d.ts +55 -0
- package/dist/approvals/resume-router.d.ts +9 -0
- package/dist/approvals/triggerer-subject.d.ts +37 -0
- package/dist/cache/dep-cache.d.ts +54 -10
- package/dist/cache/global-eval-round-cache.d.ts +95 -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/api-client.d.ts +18 -0
- package/dist/cli/commands/cluster-settings.d.ts +52 -3
- package/dist/cli/commands/diagnose.d.ts +6 -0
- package/dist/cli/commands/held-run.d.ts +58 -0
- package/dist/cli/commands/runs.d.ts +1 -0
- package/dist/cli/commands/trust-policy.d.ts +117 -12
- package/dist/cli/kici-admin.d.ts +10 -0
- package/dist/cli.js +2770 -938
- package/dist/cluster/cluster-identity.d.ts +3 -3
- package/dist/cluster/cluster-settings-reader.d.ts +59 -1
- package/dist/cluster/coordinator.d.ts +44 -0
- package/dist/cluster/index.d.ts +4 -0
- package/dist/cluster/peer-handler.d.ts +19 -0
- package/dist/cluster/peer-registry.d.ts +17 -0
- package/dist/cluster/plan-headroom-store.d.ts +26 -0
- package/dist/cluster/worker-eviction.d.ts +69 -0
- package/dist/cold-store/load-event-log-range.d.ts +10 -3
- package/dist/cold-store/load-secret-audit-log-range.d.ts +4 -3
- package/dist/cold-store/tables/secret-audit-log.d.ts +4 -3
- package/dist/config.d.ts +48 -21
- package/dist/content-requirements-cache.d.ts +55 -0
- package/dist/contexts/held-runs.d.ts +123 -16
- package/dist/contexts/protection/aggregate.d.ts +3 -2
- package/dist/contexts/protection/branch-gate.d.ts +15 -0
- package/dist/contexts/protection/concurrency-gate.d.ts +8 -2
- package/dist/contexts/protection/pipeline.d.ts +18 -0
- package/dist/contexts/release-queued-holds.d.ts +35 -0
- package/dist/dashboard/attestation-filters.d.ts +8 -0
- package/dist/dashboard/handler.d.ts +6 -24
- 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/migrations/116_org_plan_headroom.d.ts +4 -0
- package/dist/db/migrations/117_invoke_gate_proxy_jobs.d.ts +4 -0
- package/dist/db/migrations/118_invoke_gate_scheduling.d.ts +4 -0
- package/dist/db/migrations/119_scaler_ha_ownership.d.ts +4 -0
- package/dist/db/migrations/120_cluster_settings_scaler_reaper.d.ts +4 -0
- package/dist/db/migrations/121_org_settings_allow_untrusted_dockerfile_builds.d.ts +19 -0
- package/dist/db/migrations/122_host_roster_scaler_managed.d.ts +25 -0
- package/dist/db/migrations/123_workflow_registrations_default_branch.d.ts +24 -0
- package/dist/db/migrations/124_cluster_settings_provision_backoff.d.ts +4 -0
- package/dist/db/migrations/125_org_trust_directory.d.ts +30 -0
- package/dist/db/migrations/126_held_runs_posted_pending_check.d.ts +28 -0
- package/dist/db/migrations/127_org_trust_policy_approval_expiry_seconds.d.ts +26 -0
- package/dist/db/migrations/128_execution_runs_global_eval_round.d.ts +23 -0
- package/dist/db/migrations/129_execution_runs_dispatch_routing_key.d.ts +24 -0
- package/dist/db/migrations/130_scaler_provision_outcomes.d.ts +32 -0
- package/dist/db/types.d.ts +428 -12
- package/dist/entry-helpers.d.ts +28 -0
- package/dist/events/event-emitter.d.ts +22 -0
- package/dist/events/event-router.d.ts +87 -1
- package/dist/events/types.d.ts +2 -23
- package/dist/git/credential-broker.d.ts +94 -0
- package/dist/git/inherited-secret.d.ts +24 -0
- package/dist/git/installation-token.d.ts +38 -0
- package/dist/git/job-context.d.ts +13 -0
- package/dist/index.js +324 -84
- package/dist/metrics/agent-metrics-aggregator.d.ts +4 -4
- package/dist/metrics/prometheus.d.ts +170 -3
- package/dist/oidc/oidc-mint-registration.d.ts +7 -3
- package/dist/orchestrator-core.d.ts +91 -24
- package/dist/pipeline/content-filter.d.ts +71 -0
- package/dist/pipeline/direct-ingress-deps.d.ts +100 -0
- package/dist/pipeline/dispatch-matched-workflow.d.ts +521 -11
- package/dist/pipeline/global-eval-round.d.ts +307 -0
- package/dist/pipeline/internal-event-pipeline.d.ts +140 -0
- package/dist/pipeline/invoke-gate.d.ts +164 -0
- package/dist/pipeline/job-contexts.d.ts +16 -17
- package/dist/pipeline/needs-scheduler.d.ts +13 -0
- package/dist/pipeline/process-webhook.d.ts +126 -31
- package/dist/pipeline/processor.d.ts +282 -23
- package/dist/pipeline/rerun.d.ts +21 -0
- package/dist/pipeline/resume-workflow.d.ts +40 -7
- package/dist/pipeline/route-or-dispatch-jobs.d.ts +15 -0
- package/dist/pipeline/security-hold-check.d.ts +217 -0
- package/dist/pipeline/test-pipeline.d.ts +12 -0
- package/dist/pipeline/undispatched-hold-checks.d.ts +23 -0
- package/dist/pipeline/webhook-payload-store.d.ts +20 -0
- package/dist/policy/dashboard-write-policy-listener.d.ts +62 -0
- package/dist/policy/dashboard-write-policy.d.ts +14 -0
- package/dist/provenance/backfill-run.d.ts +10 -1
- package/dist/provider-registry.d.ts +47 -4
- package/dist/providers/github/check-status-poster.d.ts +33 -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 -2
- package/dist/providers/github/normalizer.d.ts +3 -2
- package/dist/providers/local/normalizer.d.ts +3 -5
- package/dist/providers/universal-git/config.d.ts +2 -0
- package/dist/providers/universal-git/index.d.ts +11 -2
- 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 +112 -7
- package/dist/queue/terminalize-unroutable.d.ts +13 -0
- package/dist/registration/extractor.d.ts +3 -3
- package/dist/registration/registration-index.d.ts +7 -0
- package/dist/registration/registration-run-match.d.ts +47 -0
- package/dist/registration/registration-store.d.ts +22 -0
- package/dist/reporting/check-run-reporter.d.ts +146 -2
- package/dist/reporting/check-run-summary.d.ts +25 -1
- package/dist/reporting/execution-tracker.d.ts +324 -9
- package/dist/reporting/log-chunk-sink.d.ts +8 -5
- package/dist/reporting/run-aggregator.d.ts +4 -14
- package/dist/reporting/step-display-order.d.ts +43 -0
- package/dist/routes/admin-held-runs.d.ts +142 -0
- package/dist/routes/admin-org-settings.d.ts +5 -0
- package/dist/routes/admin-trust-policy.d.ts +34 -6
- package/dist/routes/admin.d.ts +15 -0
- package/dist/scaler/backend-factory.d.ts +55 -0
- package/dist/scaler/bare-metal-backend.d.ts +43 -5
- package/dist/scaler/claim-store.d.ts +119 -0
- package/dist/scaler/config.d.ts +4 -0
- package/dist/scaler/container-backend.d.ts +18 -4
- package/dist/scaler/container-routing.d.ts +23 -0
- package/dist/scaler/container-spawn.d.ts +28 -0
- package/dist/scaler/event-backend.d.ts +124 -0
- package/dist/scaler/event-provision-reaper.d.ts +350 -0
- package/dist/scaler/failure-tracker.d.ts +1 -1
- package/dist/scaler/firecracker-backend.d.ts +33 -6
- package/dist/scaler/index.d.ts +11 -1
- package/dist/scaler/label-matcher.d.ts +4 -3
- package/dist/scaler/manager.d.ts +905 -76
- package/dist/scaler/resolve-container-auth.d.ts +45 -0
- package/dist/scaler/scaler-events.d.ts +11 -0
- package/dist/scaler/scaler-state-store.d.ts +294 -10
- package/dist/scaler/types.d.ts +131 -13
- package/dist/scaler/warm-pool.d.ts +132 -29
- package/dist/security/comment-handler.d.ts +50 -11
- package/dist/security/global-workflow-policy.d.ts +52 -12
- package/dist/security/identity-link.d.ts +60 -0
- package/dist/security/lock-source.d.ts +11 -13
- package/dist/security/reduced-privilege-note.d.ts +59 -0
- package/dist/security/trust-directory-store.d.ts +233 -0
- package/dist/security/trust-policy-gate.d.ts +94 -59
- package/dist/security/trust-policy-store.d.ts +3 -0
- package/dist/security/trust-resolver.d.ts +14 -98
- package/dist/server.d.ts +11 -1
- package/dist/server.js +56329 -42234
- package/dist/stale-detector/gate-deadline-detector.d.ts +52 -0
- package/dist/stale-detector/stale-run-detector.d.ts +61 -3
- package/dist/standalone.js +37619 -23570
- 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/worker/in-memory-job-queue.d.ts +1 -1
- package/dist/ws/agent-handler.d.ts +31 -4
- package/dist/ws/dashboard-context-handler.d.ts +28 -4
- package/dist/ws/dashboard-global-workflows-handler.d.ts +36 -9
- package/dist/ws/execution-status-frame.d.ts +32 -0
- package/dist/ws/failure-messages.d.ts +2 -0
- package/dist/ws/git-credential-relay.d.ts +39 -0
- package/dist/ws/oidc-token-relay.d.ts +6 -11
- package/dist/ws/platform-client.d.ts +68 -9
- package/dist/ws/test-relay-handlers.d.ts +35 -10
- package/installer-image-digests.json +3 -3
- package/package.json +24 -19
- package/sbom.spdx.json +868 -821
- package/dist/approvals/team-membership-lookup.d.ts +0 -13
- package/dist/pipeline/inline-eval.d.ts +0 -44
- package/dist/providers/github/contributor-resolver.d.ts +0 -30
- package/dist/security/contributor-cache.d.ts +0 -83
|
@@ -58,6 +58,17 @@ interface BuildCheckRunSummaryOptions {
|
|
|
58
58
|
};
|
|
59
59
|
/** Total job duration in milliseconds. */
|
|
60
60
|
jobDurationMs?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Bytes a caller will add around the returned summary — the reduced-privilege
|
|
63
|
+
* note it prepends, the annotation-count line it appends — subtracted from
|
|
64
|
+
* the byte budget below.
|
|
65
|
+
*
|
|
66
|
+
* Without it the budget is spent in full here and the caller's own bytes push
|
|
67
|
+
* the final string over the API's cap, which rejects the entire update and
|
|
68
|
+
* leaves the check run unresolved. Reserving instead drops one more tier of
|
|
69
|
+
* log lines, which costs context rather than the whole report.
|
|
70
|
+
*/
|
|
71
|
+
reservedBytes?: number;
|
|
61
72
|
}
|
|
62
73
|
interface BuildAnnotationsOptions {
|
|
63
74
|
stepResults: StepResultData[];
|
|
@@ -71,12 +82,25 @@ interface BuildProgressTextOptions {
|
|
|
71
82
|
runId: string;
|
|
72
83
|
};
|
|
73
84
|
}
|
|
85
|
+
/** GitHub Checks API output.summary byte limit. */
|
|
86
|
+
export declare const SUMMARY_BYTE_LIMIT = 65535;
|
|
87
|
+
/**
|
|
88
|
+
* Cut `summary` so it fits the API's cap, whatever a caller wrapped around it.
|
|
89
|
+
*
|
|
90
|
+
* The last line of defence, not the primary mechanism: `reservedBytes` is what
|
|
91
|
+
* keeps a summary readable by dropping log tiers, and this only runs when the
|
|
92
|
+
* final string is still over. Truncating at a UTF-8 boundary matters — a cut
|
|
93
|
+
* through a multi-byte sequence produces a replacement character and can leave
|
|
94
|
+
* the string one byte over the cap it was cut to fit.
|
|
95
|
+
*/
|
|
96
|
+
export declare function clampSummaryToLimit(summary: string, limit?: number): string;
|
|
74
97
|
export { formatDuration } from '@kici-dev/shared';
|
|
75
98
|
/**
|
|
76
99
|
* Build a rich markdown summary for a GitHub Check run output.summary field.
|
|
77
100
|
*
|
|
78
101
|
* Includes: headline, step table, failure details with log context, trace footer.
|
|
79
|
-
* Respects the 65535 byte limit with progressive log truncation
|
|
102
|
+
* Respects the 65535 byte limit with progressive log truncation, minus whatever
|
|
103
|
+
* `reservedBytes` the caller will wrap around the result.
|
|
80
104
|
*/
|
|
81
105
|
export declare function buildCheckRunSummary(opts: BuildCheckRunSummaryOptions): string;
|
|
82
106
|
/**
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { type Kysely } from 'kysely';
|
|
15
15
|
import type { Database } from '../db/types.js';
|
|
16
|
+
import { JobKind } from '../db/types.js';
|
|
16
17
|
import { ExecutionRunStatus, type InitFailure, RunFailureClass, ScalerEventType, OrchLogPhase } from '@kici-dev/engine';
|
|
17
18
|
import type { ObserverRegistry } from '../ws/observer-registry.js';
|
|
18
19
|
import type { LogStorage } from './log-storage.js';
|
|
@@ -28,6 +29,20 @@ export interface ExecutionContext {
|
|
|
28
29
|
installationId?: number;
|
|
29
30
|
requestId?: string;
|
|
30
31
|
routingKey?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The repository that DEFINES the workflow, when that is not
|
|
34
|
+
* `repoIdentifier` — a global workflow authored in one repository and
|
|
35
|
+
* dispatched against another. Set only when the two differ, so "present"
|
|
36
|
+
* marks a cross-repository global run; forwarded to the Platform on
|
|
37
|
+
* `execution.status`.
|
|
38
|
+
*/
|
|
39
|
+
workflowRepoIdentifier?: string;
|
|
40
|
+
/**
|
|
41
|
+
* True when this run records a global evaluation round rather than a
|
|
42
|
+
* workflow. Forwarded to the Platform so its own re-run refusal can admit the
|
|
43
|
+
* round's re-evaluation.
|
|
44
|
+
*/
|
|
45
|
+
isGlobalEvalRound?: boolean;
|
|
31
46
|
/** Git branch or tag (e.g. "main", "feature/foo"). */
|
|
32
47
|
ref?: string;
|
|
33
48
|
/** Trigger event type (e.g. "push", "pr:open"). */
|
|
@@ -56,6 +71,15 @@ export interface ExecutionContext {
|
|
|
56
71
|
* subscriptions can match on it. Null/undefined for success or non-terminal.
|
|
57
72
|
*/
|
|
58
73
|
failureClass?: RunFailureClass | null;
|
|
74
|
+
/**
|
|
75
|
+
* Resolved trust tier of the run's ref, and which branch's lock file it was
|
|
76
|
+
* evaluated against. Mirror the `execution_runs.trust_tier` /
|
|
77
|
+
* `lock_file_source` columns; both absent for a run whose trust never
|
|
78
|
+
* resolved. Read by the check-run reporter to name the reduced-privilege
|
|
79
|
+
* posture on a job's completion summary.
|
|
80
|
+
*/
|
|
81
|
+
trustTier?: string;
|
|
82
|
+
lockFileSource?: string;
|
|
59
83
|
/** Workflow-level concurrency config from the lock file. */
|
|
60
84
|
concurrency?: {
|
|
61
85
|
cancelInProgress?: boolean;
|
|
@@ -71,6 +95,7 @@ interface WorkflowCompleteCallbackData {
|
|
|
71
95
|
jobResults: Array<{
|
|
72
96
|
name: string;
|
|
73
97
|
status: string;
|
|
98
|
+
outputs?: Record<string, unknown>;
|
|
74
99
|
}>;
|
|
75
100
|
routingKey?: string;
|
|
76
101
|
repo: string;
|
|
@@ -98,6 +123,24 @@ export interface ExecutionTrackerDeps {
|
|
|
98
123
|
observerRegistry?: ObserverRegistry;
|
|
99
124
|
/** Optional callback when execution reaches terminal state. */
|
|
100
125
|
onExecutionComplete?: (runId: string, status: Extract<ExecutionRunStatus, 'success' | 'failed' | 'cancelled'>, context: ExecutionContext, description?: string) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Drop the in-process state a run leaves behind — its pending job contexts
|
|
128
|
+
* and its still-open eval gates.
|
|
129
|
+
*
|
|
130
|
+
* Separate from {@link ExecutionTrackerDeps.onExecutionComplete} because that
|
|
131
|
+
* callback is NOT the terminalization chokepoint it reads as. It fires on the
|
|
132
|
+
* three paths that finish a run whose jobs ran (`completeRun`, and both
|
|
133
|
+
* stale-detector arms) and on none of the paths that terminalize a run whose
|
|
134
|
+
* jobs never did — `failRun` (the expired-approval sweep and every
|
|
135
|
+
* pre-dispatch abort) and `cancelHeldRun` (an install gate rejected). Those
|
|
136
|
+
* are exactly the runs most likely to be holding a pending job context, since
|
|
137
|
+
* a context is only stored for a job that was gated rather than dispatched.
|
|
138
|
+
*
|
|
139
|
+
* Synchronous by contract: the in-memory half of the cleanup must not be
|
|
140
|
+
* deferred behind an await the caller does not hold, and the DB half is
|
|
141
|
+
* fire-and-forget inside the callback.
|
|
142
|
+
*/
|
|
143
|
+
onRunTerminalCleanup?: (runId: string) => void;
|
|
101
144
|
/** Optional callback to forward step status to Platform. */
|
|
102
145
|
onStepStatusForward?: (runId: string, jobId: string, jobName: string, stepIndex: number, stepName: string, state: string, timestamp: number, data?: Record<string, unknown>, requestId?: string) => void;
|
|
103
146
|
/** Optional callback when a completed run is pruned from memory. */
|
|
@@ -194,6 +237,7 @@ export declare class ExecutionTracker {
|
|
|
194
237
|
private readonly db;
|
|
195
238
|
private readonly observerRegistry?;
|
|
196
239
|
private readonly onExecutionComplete?;
|
|
240
|
+
private readonly onRunTerminalCleanup?;
|
|
197
241
|
private readonly onStepStatusForward?;
|
|
198
242
|
private readonly onRunPruned?;
|
|
199
243
|
private readonly onWorkflowComplete?;
|
|
@@ -302,7 +346,14 @@ export declare class ExecutionTracker {
|
|
|
302
346
|
/** Agent provenance label when triggered through an agent credential. */
|
|
303
347
|
triggeredByAgentLabel?: string | null,
|
|
304
348
|
/** Pull-request number for PR-triggered runs; null/omitted for non-PR runs. */
|
|
305
|
-
prNumber?: number | null
|
|
349
|
+
prNumber?: number | null,
|
|
350
|
+
/**
|
|
351
|
+
* The repository that DEFINES the workflow, when that is not
|
|
352
|
+
* `repoIdentifier` — an organization-wide workflow authored in one
|
|
353
|
+
* repository and dispatched against another. Omitted/null for every
|
|
354
|
+
* per-repository run, where the two are the same repository.
|
|
355
|
+
*/
|
|
356
|
+
workflowRepoIdentifier?: string | null): Promise<void>;
|
|
306
357
|
/**
|
|
307
358
|
* Upsert one execution_jobs row per dispatched job (idempotent on
|
|
308
359
|
* (run_id, job_id) to tolerate a race with an early `onJobStatus`). The
|
|
@@ -335,6 +386,34 @@ export declare class ExecutionTracker {
|
|
|
335
386
|
* after a peer ACKs a reroute.
|
|
336
387
|
*/
|
|
337
388
|
markJobReroutedToPeer(runId: string, jobId: string, peerId: string): Promise<void>;
|
|
389
|
+
/**
|
|
390
|
+
* Whether a rerouted job has visibly started, read from the shared
|
|
391
|
+
* `execution_jobs` row rather than from a relayed progress frame.
|
|
392
|
+
*
|
|
393
|
+
* The coordinator's spawn-window backstop learns about progress from
|
|
394
|
+
* `job.progress`, which only a WORKER peer sends — a worker has no database,
|
|
395
|
+
* so relaying is its only channel. A peer COORDINATOR writes the job's status
|
|
396
|
+
* straight into this table instead, so silence on the wire says nothing about
|
|
397
|
+
* whether the job is running, and the backstop would cancel a healthy job.
|
|
398
|
+
*
|
|
399
|
+
* False when no row exists yet (the peer has not started the job) and when the
|
|
400
|
+
* row is still `pending`; the `started_at` half covers a status that has
|
|
401
|
+
* already moved on to a terminal value.
|
|
402
|
+
*/
|
|
403
|
+
hasJobStarted(runId: string, jobId: string): Promise<boolean>;
|
|
404
|
+
/**
|
|
405
|
+
* Whether a job has reached a terminal state in the shared `execution_jobs`
|
|
406
|
+
* row.
|
|
407
|
+
*
|
|
408
|
+
* The companion read to {@link hasJobStarted}: a peer COORDINATOR runs a
|
|
409
|
+
* rerouted job against this same table and relays no terminal `job.progress`,
|
|
410
|
+
* so the row is the only signal the routing coordinator gets that the job is
|
|
411
|
+
* over and its reroute tracking can be released.
|
|
412
|
+
*
|
|
413
|
+
* False when no row exists yet — an absent row is a job that has not started,
|
|
414
|
+
* never a finished one.
|
|
415
|
+
*/
|
|
416
|
+
isJobTerminal(runId: string, jobId: string): Promise<boolean>;
|
|
338
417
|
/**
|
|
339
418
|
* Run `fn` while holding a per-run lock, serializing the run-mutating methods
|
|
340
419
|
* (`onJobStatus`, `addJobsToRun`) so a status reply cannot interleave with the
|
|
@@ -362,6 +441,9 @@ export declare class ExecutionTracker {
|
|
|
362
441
|
contexts?: string[];
|
|
363
442
|
skippedContexts?: string[];
|
|
364
443
|
envWarning?: string;
|
|
444
|
+
jobKind?: JobKind;
|
|
445
|
+
summonedRunId?: string;
|
|
446
|
+
timeoutMs?: number;
|
|
365
447
|
}>, dispatchedContexts?: string[],
|
|
366
448
|
/** Synthetic job ID to replace (e.g. needs-pending-deploy-{uuid}). */
|
|
367
449
|
replaceSyntheticId?: string): Promise<void>;
|
|
@@ -455,6 +537,13 @@ export declare class ExecutionTracker {
|
|
|
455
537
|
* - `noop`: nothing — a later terminal will free the next slot.
|
|
456
538
|
*/
|
|
457
539
|
private runWaveSchedulerHook;
|
|
540
|
+
/**
|
|
541
|
+
* When a proxy job of an invoke gate reaches terminal, aggregate the gate once
|
|
542
|
+
* every sibling proxy is terminal: the gate is set `failed` if any proxy
|
|
543
|
+
* failed, else `success`. Setting the gate terminal drives its own downstream
|
|
544
|
+
* `needs` release via the scheduler hook. A no-op for any non-proxy job.
|
|
545
|
+
*/
|
|
546
|
+
private runInvokeGateAggregationHook;
|
|
458
547
|
/**
|
|
459
548
|
* Phase 9: stuck-jobs invariant check ( Layer 3).
|
|
460
549
|
* Before declaring a run complete, verify no stuck jobs exist. If any are
|
|
@@ -469,6 +558,51 @@ export declare class ExecutionTracker {
|
|
|
469
558
|
* observer callbacks, and schedules in-memory pruning.
|
|
470
559
|
*/
|
|
471
560
|
private finalizeRunCompletion;
|
|
561
|
+
/**
|
|
562
|
+
* Map a terminal run status to the terminal job status a proxy should carry.
|
|
563
|
+
* A failure class collapses to `failed`; a cancel to `cancelled`; everything
|
|
564
|
+
* else (success) to `success`.
|
|
565
|
+
*/
|
|
566
|
+
private mapRunStatusToProxyStatus;
|
|
567
|
+
/**
|
|
568
|
+
* Read a summoned run's non-secret declared outputs — the merged `outputs`
|
|
569
|
+
* JSONB of its jobs. Secret-masked outputs live in `run_secret_outputs` and
|
|
570
|
+
* are deliberately NOT read here, so a repo's secret output never crosses into
|
|
571
|
+
* the summoning global run.
|
|
572
|
+
*/
|
|
573
|
+
private readNonSecretRunOutputs;
|
|
574
|
+
/**
|
|
575
|
+
* Normalize an `outputs` JSONB cell to a plain object. The Postgres driver may
|
|
576
|
+
* return it already parsed (object) or as a JSON string; both are accepted. A
|
|
577
|
+
* null / empty / malformed cell yields `null`.
|
|
578
|
+
*/
|
|
579
|
+
private parseOutputsCell;
|
|
580
|
+
/**
|
|
581
|
+
* When `spawnedRunId` was summoned by an invoke gate, set the gate's proxy job
|
|
582
|
+
* to the run's mapped terminal status and attach its non-secret outputs. The
|
|
583
|
+
* proxy's terminal transition drives the summoning run's scheduler (release the
|
|
584
|
+
* next held proxy, and aggregate the gate once every proxy is terminal).
|
|
585
|
+
*/
|
|
586
|
+
private mirrorSummonedRunOntoProxy;
|
|
587
|
+
/**
|
|
588
|
+
* Set a proxy job's timeline span to the summoned run's own started_at /
|
|
589
|
+
* completed_at so its dashboard bar reflects the run it mirrors. A run rejected
|
|
590
|
+
* before executing any step has no start; fall back to its completion (and, for
|
|
591
|
+
* a run with no completion recorded, to the mirror timestamp) so the proxy
|
|
592
|
+
* still renders a point-width bar rather than a status-only placeholder.
|
|
593
|
+
*/
|
|
594
|
+
private mirrorSummonedRunSpanOntoProxy;
|
|
595
|
+
/**
|
|
596
|
+
* Reconcile a just-tagged summoned run against its proxy: if the run is already
|
|
597
|
+
* terminal, drive the mirror now. Closes the tag race — a run that finalizes
|
|
598
|
+
* before `summoned_by_run_id` lands (a synchronous all-jobs-rejected completion,
|
|
599
|
+
* or an HA peer finalizing it first) reads a null tag in `mirrorSummonedRunOntoProxy`
|
|
600
|
+
* and skips, so nothing else terminalizes its proxy and the gate hangs until
|
|
601
|
+
* its timeout. The invoke gate calls this after tagging each spawned run; the
|
|
602
|
+
* `onJobStatus` idempotency guard makes a double-fire with the normal finalize
|
|
603
|
+
* a no-op.
|
|
604
|
+
*/
|
|
605
|
+
reconcileSummonedRunIfTerminal(spawnedRunId: string): Promise<void>;
|
|
472
606
|
/**
|
|
473
607
|
* Mark a run as failed when its build fails (timeout or error).
|
|
474
608
|
*
|
|
@@ -483,8 +617,25 @@ export declare class ExecutionTracker {
|
|
|
483
617
|
*
|
|
484
618
|
* Inserts a minimal execution_runs row with status='failed' directly so the E2E
|
|
485
619
|
* test (and dashboard) can observe the failure instead of a missing run.
|
|
486
|
-
|
|
487
|
-
|
|
620
|
+
*
|
|
621
|
+
* The fifth pre-dispatch recording site, and the third that writes the row and
|
|
622
|
+
* returns. Its row is terminal with no resume path, so no invoke gate ever
|
|
623
|
+
* reads its `chain_depth` — the stamp is here for the same reason as on
|
|
624
|
+
* {@link ExecutionTracker.recordInitFailureRun}: this row is the run's ONLY
|
|
625
|
+
* record, and one that says `0` claims to have started the chain it actually
|
|
626
|
+
* died inside.
|
|
627
|
+
*/
|
|
628
|
+
onBuildFailedBeforeTracking(runId: string, workflowName: string, provider: string, repoIdentifier: string, ref: string, sha: string, deliveryId: string | null, providerContext: Record<string, unknown>, routingKey: string, triggerEvent?: string, commitMessage?: string, failureReason?: string, initFailure?: InitFailure,
|
|
629
|
+
/**
|
|
630
|
+
* Internal-trigger provenance, as one object rather than two more
|
|
631
|
+
* positional args on an already 13-wide signature. Shape matches
|
|
632
|
+
* `preDispatchRunProvenance` in `dispatch-matched-workflow.ts`, which is
|
|
633
|
+
* the only caller.
|
|
634
|
+
*/
|
|
635
|
+
provenance?: {
|
|
636
|
+
chainDepth?: number;
|
|
637
|
+
dispatchedByFailureLifecycle?: boolean;
|
|
638
|
+
}): Promise<void>;
|
|
488
639
|
/**
|
|
489
640
|
* Write a `failed` execution_runs row directly for an init failure, and drop
|
|
490
641
|
* any in-memory run so the recorded failure is the run's final word. Also
|
|
@@ -515,6 +666,91 @@ export declare class ExecutionTracker {
|
|
|
515
666
|
initFailure: InitFailure;
|
|
516
667
|
triggerEvent?: string;
|
|
517
668
|
commitMessage?: string;
|
|
669
|
+
/**
|
|
670
|
+
* The repository that DEFINES the workflow this run was about to execute.
|
|
671
|
+
* REQUIRED: every run has one, and a caller that does not state it must not
|
|
672
|
+
* compile. Left optional, a global dispatch path added later would record a
|
|
673
|
+
* null marker — and a null marker does not mean "unknown", it means "the
|
|
674
|
+
* workflow lives in this run's own repository", which the whole
|
|
675
|
+
* defining-repository predicate then reads as fact.
|
|
676
|
+
*
|
|
677
|
+
* Narrowed to the differing case here, exactly as `onExecutionStarted`
|
|
678
|
+
* does, so passing `repoIdentifier` (the per-repository case) is correct
|
|
679
|
+
* and records nothing.
|
|
680
|
+
*/
|
|
681
|
+
workflowRepoIdentifier: string;
|
|
682
|
+
/**
|
|
683
|
+
* Inherited invoke-chain depth for a run summoned by an invoke gate.
|
|
684
|
+
*
|
|
685
|
+
* An init failure is terminal, so unlike the hold on
|
|
686
|
+
* {@link ExecutionTracker.recordRunHeld} this run never fires a gate of its
|
|
687
|
+
* own and nothing reads the column back to bound recursion. It is recorded
|
|
688
|
+
* because this row is the run's ONLY record: one that says `0` claims to
|
|
689
|
+
* have started the chain it actually died inside.
|
|
690
|
+
*/
|
|
691
|
+
chainDepth?: number;
|
|
692
|
+
/**
|
|
693
|
+
* True when a failure-lifecycle trigger dispatched this run, recorded as
|
|
694
|
+
* the run's `trigger_decision` marker
|
|
695
|
+
* (`EventRouter.isFailureLifecycleRun`).
|
|
696
|
+
*
|
|
697
|
+
* Consistency rather than a live reader: this path emits no
|
|
698
|
+
* `__workflow_complete`, so no accumulator reads the marker back today. It
|
|
699
|
+
* is recorded so the row does not disagree with the one
|
|
700
|
+
* {@link ExecutionTracker.recordRunHeld} writes for the same dispatch, and
|
|
701
|
+
* so adding an emit here later cannot silently re-open the self-retrigger
|
|
702
|
+
* loop.
|
|
703
|
+
*/
|
|
704
|
+
dispatchedByFailureLifecycle?: boolean;
|
|
705
|
+
}): Promise<void>;
|
|
706
|
+
/**
|
|
707
|
+
* Write one `failed` execution_runs row for a global eval round that never
|
|
708
|
+
* produced verdicts.
|
|
709
|
+
*
|
|
710
|
+
* The round decides which organization-wide workflows apply to an event, so a
|
|
711
|
+
* round that fails suppresses every workflow it was deciding on. Without a row
|
|
712
|
+
* that outcome is invisible: no run was ever created for those workflows, so
|
|
713
|
+
* there is nothing on the dashboard to explain why they did not appear.
|
|
714
|
+
*
|
|
715
|
+
* **One row for the whole round, not one per workflow.** The round exists to
|
|
716
|
+
* collapse N candidate workflows into a single pre-run job; fanning its
|
|
717
|
+
* failure back out into N rows would undo exactly that. The reason names every
|
|
718
|
+
* affected workflow instead.
|
|
719
|
+
*
|
|
720
|
+
* Its `runId` is the round job's own — the last attempt's — so the row, the
|
|
721
|
+
* `dispatch_queue` row, and the attempt's logs all carry one id. No conflict
|
|
722
|
+
* guard is needed beyond `doNothing`: the id was minted for this round and
|
|
723
|
+
* belongs to no other run.
|
|
724
|
+
*/
|
|
725
|
+
recordGlobalEvalRoundFailureRun(args: {
|
|
726
|
+
runId: string;
|
|
727
|
+
workflowName: string;
|
|
728
|
+
provider: string;
|
|
729
|
+
repoIdentifier: string;
|
|
730
|
+
ref: string;
|
|
731
|
+
sha: string;
|
|
732
|
+
deliveryId: string | null;
|
|
733
|
+
providerContext: Record<string, unknown>;
|
|
734
|
+
routingKey: string;
|
|
735
|
+
/**
|
|
736
|
+
* The source `providerContext` was taken from, when a cross-provider
|
|
737
|
+
* lock-file fallback made it a different source from `routingKey`.
|
|
738
|
+
*
|
|
739
|
+
* Recorded because the two are a PAIR: a re-run of this round re-drives the
|
|
740
|
+
* organization-wide pass and must hand it the same bundle those credentials
|
|
741
|
+
* belong to. Pairing the stored context with the inbound routing key instead
|
|
742
|
+
* gives one source's credentials to another source's API client.
|
|
743
|
+
*/
|
|
744
|
+
dispatchRoutingKey?: string;
|
|
745
|
+
failureReason: string;
|
|
746
|
+
triggerEvent?: string;
|
|
747
|
+
/**
|
|
748
|
+
* The repository whose global workflows the round was deciding. A round is
|
|
749
|
+
* definitionally the cross-repository case, so this is normally a different
|
|
750
|
+
* repository from `repoIdentifier` — recorded, like everywhere else, only
|
|
751
|
+
* when the two actually differ.
|
|
752
|
+
*/
|
|
753
|
+
workflowRepoIdentifier: string;
|
|
518
754
|
}): Promise<void>;
|
|
519
755
|
/**
|
|
520
756
|
* Record a run paused at the workflow install gate (a `registries:` /
|
|
@@ -549,6 +785,27 @@ export declare class ExecutionTracker {
|
|
|
549
785
|
* security hold fail-closed unreachable by the comment path.
|
|
550
786
|
*/
|
|
551
787
|
prNumber?: number | null;
|
|
788
|
+
/**
|
|
789
|
+
* The repository that DEFINES the held workflow. REQUIRED for the same
|
|
790
|
+
* reason as on {@link ExecutionTracker.recordInitFailureRun}: a hold is a
|
|
791
|
+
* live, resumable run, so a null marker here would misattribute it for the
|
|
792
|
+
* whole time it sits in the queue and for the run it resumes into.
|
|
793
|
+
*/
|
|
794
|
+
workflowRepoIdentifier: string;
|
|
795
|
+
/**
|
|
796
|
+
* Inherited invoke-chain depth for a run summoned by an invoke gate.
|
|
797
|
+
* REQUIRED to be threaded by any caller that has one: a hold is resumable,
|
|
798
|
+
* so the resumed run can fire its own invoke gate, and the chain-depth
|
|
799
|
+
* circuit breaker reads this column back. Absent ⇒ the column's `0`
|
|
800
|
+
* default, which means "this run starts a chain".
|
|
801
|
+
*/
|
|
802
|
+
chainDepth?: number;
|
|
803
|
+
/**
|
|
804
|
+
* True when a failure-lifecycle trigger dispatched this run, recorded as
|
|
805
|
+
* the run's `trigger_decision` marker so its eventual completion is
|
|
806
|
+
* excluded from batch accumulation (`EventRouter.isFailureLifecycleRun`).
|
|
807
|
+
*/
|
|
808
|
+
dispatchedByFailureLifecycle?: boolean;
|
|
552
809
|
}): Promise<void>;
|
|
553
810
|
/**
|
|
554
811
|
* Flip a `held` run back to `pending` so the resumed dispatch can proceed
|
|
@@ -593,11 +850,13 @@ export declare class ExecutionTracker {
|
|
|
593
850
|
* registered. Returns true when a token was taken, false for an unknown or
|
|
594
851
|
* already-completed run (nothing to hold).
|
|
595
852
|
*
|
|
596
|
-
*
|
|
853
|
+
* Four registration windows need this. A run whose source-pack `__build__`
|
|
597
854
|
* job is dispatched first is registered with that job ALONE, and its real
|
|
598
|
-
* jobs are only dispatched once the build finishes
|
|
599
|
-
*
|
|
600
|
-
*
|
|
855
|
+
* jobs are only dispatched once the build finishes; a run without a build is
|
|
856
|
+
* registered with NO jobs before its dispatch loop, so its jobs land once
|
|
857
|
+
* every dispatch has returned. A deferred init job and a deferred dynamic
|
|
858
|
+
* entry each register their jobs from a fire-and-forget task that outlives
|
|
859
|
+
* the dispatch call. In every case, without a token the already
|
|
601
860
|
* -registered jobs reaching a terminal state satisfies {@link isRunComplete},
|
|
602
861
|
* so the run is finalized early: a terminal run status is written, the
|
|
603
862
|
* provider check is posted, and the status is forwarded to the Platform — all
|
|
@@ -612,9 +871,13 @@ export declare class ExecutionTracker {
|
|
|
612
871
|
* and an off-by-one job count for the length of the window. A counter holds
|
|
613
872
|
* the completion check open without being visible to any of them, and it
|
|
614
873
|
* writes no `execution_jobs` row, so it never surfaces as a phantom job.
|
|
615
|
-
* A token whose holder never settles keeps the run
|
|
874
|
+
* A token whose holder never settles keeps the run open until the stale
|
|
616
875
|
* detector reaps it — the same backstop that covers a job that never
|
|
617
|
-
* reports.
|
|
876
|
+
* reports. That backstop only reaches a run that has at least one job: every
|
|
877
|
+
* sub-scan of the stale detector starts from `execution_jobs` or
|
|
878
|
+
* `dispatch_queue`. So a holder that registers NO jobs must terminalize the
|
|
879
|
+
* run itself rather than rely on the sweep — which is what
|
|
880
|
+
* `dispatchMatchedWorkflow` does when its dispatch loop throws.
|
|
618
881
|
*
|
|
619
882
|
* Each token must be paired with exactly one {@link releasePendingJobsHold}.
|
|
620
883
|
*/
|
|
@@ -645,6 +908,35 @@ export declare class ExecutionTracker {
|
|
|
645
908
|
* Used by LogWriter to construct log paths.
|
|
646
909
|
*/
|
|
647
910
|
getJobName(runId: string, jobId: string): string | undefined;
|
|
911
|
+
/**
|
|
912
|
+
* Resolve the job name that names a step-log storage path, with a durable
|
|
913
|
+
* fallback. The step-log path is `executions/{runId}/job-{jobName}/…` and it
|
|
914
|
+
* is written from two sites — the chunk writer (`log-chunk-sink`) and the
|
|
915
|
+
* `execution_steps.log_path` upsert in `onStepStatus`. A purely in-memory
|
|
916
|
+
* lookup (`getJobName`) returns `undefined` during the brief window between
|
|
917
|
+
* dispatch and `addJobsToRun` populating `run.jobs`, so an early chunk would
|
|
918
|
+
* land under `job-{jobId}` while the reader later keys on `job-{realName}` —
|
|
919
|
+
* silently losing those lines. Both write sites go through this resolver so
|
|
920
|
+
* they cannot disagree: in-memory first, then the authoritative
|
|
921
|
+
* `dispatch_queue.job_name` (the same source `recoverJobFromDispatchQueue`
|
|
922
|
+
* trusts), and only `jobId` when the job is genuinely unknown.
|
|
923
|
+
*/
|
|
924
|
+
resolveJobName(runId: string, jobId: string): Promise<string>;
|
|
925
|
+
/**
|
|
926
|
+
* Seed the in-memory job name for a job the coordinator did not itself
|
|
927
|
+
* dispatch — a worker-rerouted job. Such a job is tracked in the cluster
|
|
928
|
+
* coordinator's own map, never enters this tracker's `run.jobs` via
|
|
929
|
+
* `addJobsToRun`, and has no coordinator-owned `dispatch_queue` row (the
|
|
930
|
+
* worker owns it under a fresh id), so `resolveJobName` would fall back to
|
|
931
|
+
* the bare `jobId` for its early log chunks while the reader keys on the real
|
|
932
|
+
* name — the same split-brain that loses lines. Seeding the name here, at
|
|
933
|
+
* reroute time, makes `resolveJobName`'s fast path correct from the first
|
|
934
|
+
* relayed chunk, independent of when the worker's `dispatch_queue` row becomes
|
|
935
|
+
* visible. In-memory only: the `execution_jobs` row is still created lazily by
|
|
936
|
+
* the worker's first status update. Guarded against clobbering an existing
|
|
937
|
+
* entry so a later terminal status is never overwritten.
|
|
938
|
+
*/
|
|
939
|
+
registerJobName(runId: string, jobId: string, jobName: string): void;
|
|
648
940
|
/**
|
|
649
941
|
* Find the runId of the in-memory run that owns a given dispatched jobId.
|
|
650
942
|
*
|
|
@@ -660,6 +952,28 @@ export declare class ExecutionTracker {
|
|
|
660
952
|
* Used by commit status reporting to access provider/repo/sha info.
|
|
661
953
|
*/
|
|
662
954
|
getExecutionContext(runId: string): ExecutionContext | undefined;
|
|
955
|
+
/**
|
|
956
|
+
* Stamp the run's resolved trust tier and lock-file branch onto the in-memory
|
|
957
|
+
* state, after `onExecutionStarted` recorded the row.
|
|
958
|
+
*
|
|
959
|
+
* Separate from the start call because trust resolves on its own path and is
|
|
960
|
+
* written to `execution_runs` by its own update. The dispatch site that
|
|
961
|
+
* writes those two columns calls this with the same values, but the two
|
|
962
|
+
* writes are independent and either can be lost: the DB update is
|
|
963
|
+
* fire-and-forget with its own `.catch()`, and this call is wrapped in a
|
|
964
|
+
* `try`/`catch` there. Both are deliberate — the note is worth less than the
|
|
965
|
+
* run — so the in-memory copy and the row CAN disagree, and neither is
|
|
966
|
+
* authoritative for the other. `recoverRunFromDb` reconciles by reading the
|
|
967
|
+
* row, so the durable value is the one that survives.
|
|
968
|
+
*
|
|
969
|
+
* A run this tracker does not know is a no-op: a missing run means the status
|
|
970
|
+
* updates that would read the fields are not coming either.
|
|
971
|
+
*
|
|
972
|
+
* Keep this synchronous. Its one caller wraps it in `try`/`catch`, which
|
|
973
|
+
* catches a throw but not a rejected promise, so an async body would put the
|
|
974
|
+
* failure back outside the guard.
|
|
975
|
+
*/
|
|
976
|
+
setRunTrustContext(runId: string, trustTier: string, lockFileSource?: string): void;
|
|
663
977
|
/**
|
|
664
978
|
* Update the heartbeat timestamp for a running job.
|
|
665
979
|
*
|
|
@@ -697,6 +1011,7 @@ export declare class ExecutionTracker {
|
|
|
697
1011
|
status: ExecutionRunStatus;
|
|
698
1012
|
routingKey?: string;
|
|
699
1013
|
repoIdentifier?: string;
|
|
1014
|
+
workflowRepoIdentifier?: string;
|
|
700
1015
|
sha?: string;
|
|
701
1016
|
ref?: string;
|
|
702
1017
|
triggerEvent?: string;
|
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
* behave identically — a worker-dispatched job's logs are persisted, counted
|
|
8
8
|
* and forwarded exactly like a locally-dispatched one's.
|
|
9
9
|
*
|
|
10
|
-
* The storage key is derived from `executionTracker.
|
|
11
|
-
* `ExecutionTracker.onStepStatus` uses to fill `execution_steps.log_path`,
|
|
12
|
-
* the reader and the writer cannot disagree about the naming rule
|
|
10
|
+
* The storage key is derived from `executionTracker.resolveJobName`, the same
|
|
11
|
+
* call `ExecutionTracker.onStepStatus` uses to fill `execution_steps.log_path`,
|
|
12
|
+
* so the reader and the writer cannot disagree about the naming rule — the
|
|
13
|
+
* resolver falls back to `dispatch_queue.job_name` during the dispatch window
|
|
14
|
+
* before in-memory job state is populated, which is what stops an early chunk
|
|
15
|
+
* from being persisted under an unreadable `job-{jobId}` path.
|
|
13
16
|
*/
|
|
14
17
|
import type { LogStream } from '@kici-dev/engine';
|
|
15
18
|
import type { LogWriter } from './log-writer.js';
|
|
@@ -32,9 +35,9 @@ export interface LogChunkSinkDeps {
|
|
|
32
35
|
stepLogBuffer?: StepLogBuffer;
|
|
33
36
|
/** Durable step-log persistence. Absent when the orchestrator has no database. */
|
|
34
37
|
logWriter?: LogWriter;
|
|
35
|
-
/** Resolves the job name that names the storage path. */
|
|
38
|
+
/** Resolves the job name that names the storage path (durable fallback). */
|
|
36
39
|
executionTracker?: {
|
|
37
|
-
|
|
40
|
+
resolveJobName(runId: string, jobId: string): Promise<string>;
|
|
38
41
|
};
|
|
39
42
|
/**
|
|
40
43
|
* Forward to the Platform for browser fan-out. Absent in independent mode.
|
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared run-detail aggregator.
|
|
3
|
-
*
|
|
4
|
-
* One source of truth for "DB rows → canonical nested run detail (jobs with
|
|
5
|
-
* nested steps + needs + outputs)". The dashboard handler and the agent-facing
|
|
6
|
-
* structured run-result route both build on the same `buildRunDetailJobs` /
|
|
7
|
-
* `mapRunDetailStep` mapping, so the row→jobs shape never diverges between the
|
|
8
|
-
* two read surfaces.
|
|
9
|
-
*
|
|
10
|
-
* `aggregateRunDetail` is the warm-path convenience used by the agent route: it
|
|
11
|
-
* runs the run-header + per-run batch queries and returns the canonical detail.
|
|
12
|
-
* (Cold-store fallback stays a dashboard-handler concern — the agent read path
|
|
13
|
-
* is warm-only in v1.)
|
|
14
|
-
*/
|
|
15
1
|
import type { Kysely } from 'kysely';
|
|
16
2
|
import { ExecutionJobStatus, type InitFailure } from '@kici-dev/engine';
|
|
17
3
|
import type { Database } from '../db/types.js';
|
|
@@ -58,6 +44,8 @@ export interface RunDetailJobRow {
|
|
|
58
44
|
base_job_name: string | null;
|
|
59
45
|
variant_kind: string | null;
|
|
60
46
|
variant_label: string | null;
|
|
47
|
+
job_kind: string | null;
|
|
48
|
+
summoned_run_id: string | null;
|
|
61
49
|
started_at: Date | null;
|
|
62
50
|
completed_at: Date | null;
|
|
63
51
|
duration_ms: number | null;
|
|
@@ -104,6 +92,8 @@ export declare function buildRunDetailJobs(jobs: RunDetailJobRow[], lookups: Run
|
|
|
104
92
|
baseJobName: string | null;
|
|
105
93
|
variantKind: string | null;
|
|
106
94
|
variantLabel: string | null;
|
|
95
|
+
jobKind: string | null;
|
|
96
|
+
summonedRunId: string | null;
|
|
107
97
|
startedAt: number | null;
|
|
108
98
|
completedAt: number | null;
|
|
109
99
|
durationMs: number | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The order a run's steps are shown in.
|
|
3
|
+
*
|
|
4
|
+
* Every reader of `execution_steps` sorted by `step_index` alone, which puts a
|
|
5
|
+
* pseudo-step wherever its index landed rather than where it ran. That is fine
|
|
6
|
+
* for the cache pseudo-steps, whose indices sit above the real steps and which
|
|
7
|
+
* mostly bracket the work — but a job's image build runs strictly FIRST, and
|
|
8
|
+
* rendering it last reads as though it happened last.
|
|
9
|
+
*
|
|
10
|
+
* The index cannot express this: `step.status` rejects a negative index (an
|
|
11
|
+
* agent sending one to an older orchestrator is disconnected mid-job), and two
|
|
12
|
+
* consumers treat a negative index as absent — the check-run reporter writes
|
|
13
|
+
* `steps[stepIndex]`, and the dashboard gates log fetching on `stepIndex >= 0`.
|
|
14
|
+
* So the ordering is expressed by TYPE, here, once, rather than by each reader
|
|
15
|
+
* inventing its own rule.
|
|
16
|
+
*/
|
|
17
|
+
import { type Expression } from 'kysely';
|
|
18
|
+
/**
|
|
19
|
+
* Sort key placing setup pseudo-steps (the ones that ran before the job's real
|
|
20
|
+
* steps) ahead of everything else. Apply BEFORE the `step_index` sort:
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* qb.orderBy(setupStepsFirst()).orderBy('step_index', 'asc')
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Steps with no type, and every real step, share the same key — so within each
|
|
27
|
+
* group `step_index` remains the only thing that orders them, exactly as before.
|
|
28
|
+
*/
|
|
29
|
+
export declare function setupStepsFirst(): Expression<number>;
|
|
30
|
+
/**
|
|
31
|
+
* In-memory equivalent, for a caller that already holds the rows.
|
|
32
|
+
*
|
|
33
|
+
* Kept beside the SQL so the two cannot drift into disagreeing about what
|
|
34
|
+
* "setup" means.
|
|
35
|
+
*/
|
|
36
|
+
export declare function compareStepsForDisplay(a: {
|
|
37
|
+
step_type?: string | null;
|
|
38
|
+
step_index: number;
|
|
39
|
+
}, b: {
|
|
40
|
+
step_type?: string | null;
|
|
41
|
+
step_index: number;
|
|
42
|
+
}): number;
|
|
43
|
+
//# sourceMappingURL=step-display-order.d.ts.map
|