/**
 * Execution state tracker with write-through DB persistence.
 *
 * Aggregates job/step status updates from agents and persists execution
 * history to PostgreSQL. Maintains in-memory state for fast lookups
 * (job name resolution, run completion detection) with write-through
 * to the execution_runs/execution_jobs/execution_steps tables.
 *
 * Overall run status follows locked decision:
 * - success ONLY if ALL jobs succeed
 * - failed if ANY job fails
 * - cancelled if ANY job is cancelled (and none failed)
 */
import { type Kysely } from 'kysely';
import type { Database } from '../db/types.js';
import { ExecutionRunStatus, type InitFailure, ScalerEventType } from '@kici-dev/engine';
import type { ObserverRegistry } from '../ws/observer-registry.js';
import type { LogStorage } from './log-storage.js';
import type { JobQueue } from '../queue/job-queue.js';
/** Context passed to onExecutionComplete for commit status updates. */
export interface ExecutionContext {
    workflowName: string;
    provider: string;
    repoIdentifier: string;
    sha: string;
    installationId?: number;
    requestId?: string;
    routingKey?: string;
    /** Git branch or tag (e.g. "main", "feature/foo"). */
    ref?: string;
    /** Trigger event type (e.g. "push", "pr:open"). */
    triggerEvent?: string;
    /** First line of the commit message. */
    commitMessage?: string;
    /** Parent run ID for re-run lineage (null/undefined for original runs). */
    parentRunId?: string | null;
    /** Root ancestor run ID for re-run lineage (null/undefined for original runs). */
    originalRunId?: string | null;
    /** User identity that triggered this re-run (null/undefined for webhook-triggered). */
    triggeredBy?: string | null;
    /** Workflow-level concurrency config from the lock file. */
    concurrency?: {
        cancelInProgress?: boolean;
        max?: number;
    };
}
/** Data passed to the onWorkflowComplete callback. */
interface WorkflowCompleteCallbackData {
    runId: string;
    workflowName: string;
    status: string;
    duration: number;
    jobResults: Array<{
        name: string;
        status: string;
    }>;
    routingKey?: string;
    repo: string;
}
/** Data passed to the onJobComplete callback. */
interface JobCompleteCallbackData {
    runId: string;
    jobId: string;
    jobName: string;
    status: string;
    routingKey?: string;
    repo: string;
    workflowName: string;
}
export interface ExecutionTrackerDeps {
    db: Kysely<Database>;
    /** Optional observer registry for broadcasting status/step/log events to CLI observers. */
    observerRegistry?: ObserverRegistry;
    /** Optional callback when execution reaches terminal state. */
    onExecutionComplete?: (runId: string, status: Extract<ExecutionRunStatus, 'success' | 'failed' | 'cancelled'>, context: ExecutionContext, description?: string) => void;
    /** Optional callback to forward step status to Platform. */
    onStepStatusForward?: (runId: string, jobId: string, jobName: string, stepIndex: number, stepName: string, state: string, timestamp: number, data?: Record<string, unknown>, requestId?: string) => void;
    /** Optional callback when a completed run is pruned from memory. */
    onRunPruned?: (runId: string) => void;
    /** Optional callback when a workflow run reaches terminal state (for system event emission). */
    onWorkflowComplete?: (data: WorkflowCompleteCallbackData) => void;
    /** Optional callback when a job reaches terminal state (for system event emission). */
    onJobComplete?: (data: JobCompleteCallbackData) => void;
    /**
     * Optional callback to forward execution status changes to Platform.
     * Fires at run start (status=pending), on first job running, and run completion.
     * Used by Platform StaleOrchDetector to track active runs.
     */
    onExecutionStatusChange?: (runId: string, status: ExecutionRunStatus, context: ExecutionContext, jobCount: number, startedAt: number, completedAt?: number, durationMs?: number, failureReason?: string, 
    /**
     * Total raw log bytes accumulated across the run (sum of per-job totals).
     * Set on terminal run states only. Powers the operator-side
     * `kici_org_log_bytes` capacity-planning gauge on the Platform.
     */
    logBytes?: number, 
    /**
     * Structured init-failure signal. Set when the run never executed a step
     * because of an init-phase failure. Forwarded to Platform's execution.status
     * forward and persisted in execution_runs.init_failure on both sides.
     */
    initFailure?: InitFailure) => void;
    /** Optional callback to forward job status changes to Platform.
     *  Fires on every job state transition (pending->running, running->success, etc.).
     *  Used to populate Platform's execution_jobs projection table. */
    onJobStatusChange?: (runId: string, jobId: string, jobName: string, status: string, timestamp: number, startedAt?: number, completedAt?: number, durationMs?: number, errorMessage?: string, agentId?: string, runsOnLabels?: string[], 
    /**
     * Total raw log bytes accumulated across the job (sum of per-step totals).
     * Set on terminal job states only.
     */
    logBytes?: number, 
    /**
     * Structured init-failure signal. Set for synthetic rejected-* / init-failed-*
     * jobs that never started. Persisted in execution_jobs.init_failure.
     */
    initFailure?: InitFailure) => void;
    /**
     * Optional callback to emit run.event messages to Platform.
     * Fires at orchestrator lifecycle points (dispatch, agent assignment, job start/complete).
     *
     * SECURITY: this payload MUST NOT carry an `orgId` (or any tenant identifier).
     * The Platform always uses `authState.orgId` for tenant attribution; trusting
     * a wire-supplied field is a cross-tenant injection primitive. See
     * `docs/architecture/security/ws-tenant-isolation.md`.
     */
    onRunEventEmit?: (event: {
        runId: string;
        eventType: string;
        timestampMs: number;
        sourceService: 'orchestrator' | 'agent';
        jobId?: string | null;
        metadata?: Record<string, unknown>;
        durationMs?: number | null;
    }) => void;
    /** Optional log storage for writing per-job orchestration logs (JSONL). */
    logStorage?: LogStorage;
    /** Org ID for this orchestrator instance (used in run.event emission). */
    orgId?: string;
    /** Optional job queue for cascading run failures to dispatch_queue entries. */
    jobQueue?: JobQueue;
}
export declare class ExecutionTracker {
    private readonly db;
    private readonly observerRegistry?;
    private readonly onExecutionComplete?;
    private readonly onStepStatusForward?;
    private readonly onRunPruned?;
    private readonly onWorkflowComplete?;
    private readonly onJobComplete?;
    private readonly onExecutionStatusChange?;
    private readonly onJobStatusChange?;
    private readonly onRunEventEmit?;
    private readonly logStorage?;
    private readonly orgId?;
    private readonly jobQueue?;
    private readonly runs;
    /**
     * Per-run async-mutex chain. `onJobStatus` and `addJobsToRun` mutate the same
     * `run.jobs` Map / `execution_jobs` row; without serialization a job-status
     * reply that lands mid synthetic→real swap (`addJobsToRun`) clobbers the swap
     * and the run hangs in `running` forever (see `withRunLock`). The map value is
     * the tail of the chain for that runId; entries are GC'd when the last holder
     * releases.
     */
    private readonly runLockTails;
    /**
     * Tracks which runIds the current async context already holds in
     * `withRunLock`, so reentrant calls (e.g. onJobStatus → scheduler hook →
     * dispatchReadyJob → addJobsToRun, all the same runId) bypass re-acquisition
     * instead of deadlocking. Propagates across awaits via AsyncLocalStorage.
     */
    private readonly heldRunLocks;
    /** Tracks which runs are test runs for observer broadcasting. */
    private readonly testRunIds;
    /**
     * Per-(run, job) raw log byte accumulator.
     *
     * Populated from the agent-reported `logBytesStreamed` field on terminal
     * `step.status` messages and folded into `execution_jobs.log_bytes` when
     * the job reaches terminal state. The per-run total is then computed by
     * summing the per-job entries and written into `execution_runs.log_bytes`
     * at run completion. Deleted on run prune to avoid Map growth.
     *
     * Map shape: runId -> jobId -> bytes.
     */
    private readonly jobLogBytes;
    /** Callback fired when a job's needs are satisfied and it's ready for dispatch. */
    onJobReadyCallback?: (runId: string, jobName: string) => Promise<void>;
    constructor(deps: ExecutionTrackerDeps);
    /**
     * Register a callback fired when a job's needs become satisfied.
     * The processor sets this to dispatch newly-ready jobs to agents.
     */
    setOnJobReadyCallback(cb: (runId: string, jobName: string) => Promise<void>): void;
    /**
     * Record a new execution run with its initial jobs.
     *
     * Inserts execution_runs and execution_jobs rows in the DB and
     * sets up in-memory tracking state.
     */
    onExecutionStarted(runId: string, workflowName: string, provider: string, repoIdentifier: string, ref: string, sha: string, deliveryId: string | null, providerContext: Record<string, unknown>, triggerDecision: Record<string, unknown> | null, jobs: Array<{
        jobId: string;
        jobName: string;
        matrixValues?: Record<string, unknown>;
        runsOnLabels?: string[];
    }>, routingKey?: string, 
    /** Secret context names dispatched with jobs (for context-disable job lookup). */
    dispatchedContexts?: string[], 
    /** Trigger event type (e.g. "push", "pr:open") for dashboard display. */
    triggerEvent?: string, 
    /** First line of commit message for dashboard display. */
    commitMessage?: string, 
    /** Parent run ID for re-run lineage. */
    parentRunId?: string | null, 
    /** User identity that triggered this re-run. */
    triggeredBy?: string | null, 
    /** Root ancestor run ID for re-run lineage. */
    originalRunId?: string | null, 
    /** Workflow-level concurrency config from the lock file. */
    concurrency?: {
        cancelInProgress?: boolean;
        max?: number;
    }, 
    /** Workflow-level wall-clock timeout in ms from the lock file. Sets the run deadline. */
    workflowTimeoutMs?: number): Promise<void>;
    /**
     * Add additional jobs to an already-started execution run.
     * Used when build jobs are tracked early and regular jobs are dispatched later.
     */
    /**
     * Find the synthetic needs-pending job ID for a given job name in a run.
     * Used by dispatchReadyJob to locate the placeholder entry before replacing it.
     *
     * Cluster correctness: the synthetic row is inserted by the peer that
     * ingested the webhook. In an HA cluster `dispatchReadyJob` can fire on a
     * different peer whose in-memory map has no entry for this run. Fall back
     * to the DB so the leftover synthetic row gets cleaned up regardless of
     * which peer owns the downstream dispatch.
     */
    findSyntheticJobId(runId: string, jobName: string): Promise<string | undefined>;
    /**
     * Run `fn` while holding a per-run lock, serializing the run-mutating methods
     * (`onJobStatus`, `addJobsToRun`) so a status reply cannot interleave with the
     * synthetic→real job swap and wedge the run in `running`.
     *
     * The lock is **reentrant**: three paths re-enter a locked method within the
     * same async context for the same runId — onJobStatus → scheduler hook →
     * dispatchReadyJob → addJobsToRun; onJobStatus → enforceSchedulerInvariant →
     * onJobStatus; runSchedulerHook → onJobStatus (skip). A non-reentrant mutex
     * would deadlock on these, so a context that already holds the runId's lock
     * (tracked via `heldRunLocks`) runs `fn` inline. A genuinely concurrent caller
     * for the same runId (a separate WS message) is a different async context and
     * correctly waits. All reentrant paths are same-runId, so there is no
     * cross-run lock-ordering deadlock.
     */
    private withRunLock;
    addJobsToRun(runId: string, jobs: Array<{
        jobId: string;
        jobName: string;
        matrixValues?: Record<string, unknown>;
        runsOnLabels?: string[];
    }>, dispatchedContexts?: string[], 
    /** Synthetic job ID to replace (e.g. needs-pending-deploy-{uuid}). */
    replaceSyntheticId?: string): Promise<void>;
    private addJobsToRunImpl;
    /**
     * Mark a run as a test run for observer broadcasting.
     * Called by the test pipeline after creating the execution run.
     */
    markTestRun(runId: string): void;
    /**
     * Check if a run is a test run.
     */
    isTestRun(runId: string): boolean;
    /**
     * Update job status within a run.
     *
     * On terminal states (success/failed/cancelled), checks if ALL jobs
     * in the run are terminal. If so, computes overall run status and
     * fires the onExecutionComplete callback.
     */
    onJobStatus(runId: string, jobId: string, state: string, timestamp: number, agentId?: string, data?: Record<string, unknown>): Promise<void>;
    private onJobStatusImpl;
    /**
     * Phase 1a: recover run state from the DB when in-memory tracking is empty.
     * Returns the rehydrated RunState or null if the run is unknown to the DB
     * (in which case the caller skips this status update entirely).
     */
    private recoverRunFromDb;
    /**
     * Phase 1b: recover job state from the dispatch_queue and add it to the
     * run's in-memory map. Returns the freshly-inserted job entry.
     */
    private recoverJobFromDispatchQueue;
    /**
     * Phase 2: build the upsert payload for execution_jobs and execute it.
     * Returns the per-job log byte total when the job reached a terminal state
     * (used downstream by the run-completion phase to populate run.log_bytes).
     */
    private persistJobStatusUpdate;
    /**
     * Phase 3a: transition run from pending -> running when the first job
     * starts executing.
     */
    private maybeTransitionRunToRunning;
    /**
     * Phase 3b: when an agent reports 'cancelling', transition the run-level
     * status too. 'cancelling' means "graceful cancel in progress, hooks
     * running" — the run should reflect this intermediate state.
     */
    private maybeTransitionRunToCancelling;
    /**
     * Phase 4: emit run.event and orchestration log entries at job lifecycle
     * points (job started / agent assigned / job terminal).
     */
    private emitJobLifecycleEvents;
    /**
     * Phase 5: fire the onJobStatusChange callback for Platform forwarding.
     */
    private fireJobStatusChangeCallback;
    /**
     * Phase 6: reconcile orphaned steps. If a job reaches terminal state but
     * some steps are still 'running' (because a step.complete IPC message was
     * lost), mark them as the job's terminal state. Without this safety net,
     * the dashboard shows "running" with an ever-growing duration for the lost
     * step.
     */
    private reconcileOrphanedSteps;
    /**
     * Phase 7: drift report handling.
     * When an agent reports droppedJobs, transition those sibling jobs to
     * drift_dropped. drift_dropped is a terminal state, so the scheduler hook
     * (Phase 8) will propagate failures to any downstreams.
     */
    private handleDriftDroppedJobs;
    /**
     * Phase 8: needs-aware scheduler hook.
     * When a job reaches terminal state, evaluate its downstreams for dispatch.
     * The DAG is acyclic (validated at compile time L1 and eval time L2),
     * so recursive skip propagation terminates naturally.
     */
    private runSchedulerHook;
    /**
     * Phase 9: stuck-jobs invariant check ( Layer 3).
     * Before declaring a run complete, verify no stuck jobs exist. If any are
     * found, fail them via recursive onJobStatus calls and signal the caller to
     * stop (returns true) — the recursive calls will re-enter and re-check
     * completion with fresh state.
     */
    private enforceSchedulerInvariantOrFail;
    /**
     * Phase 10: finalize run completion. Computes overall status, writes the
     * execution_runs row, fires Platform-forwarding + workflow-complete +
     * observer callbacks, and schedules in-memory pruning.
     */
    private finalizeRunCompletion;
    /**
     * Mark a run as failed when its build fails (timeout or error).
     *
     * Called by the processor when a build job was tracked early via
     * onExecutionStarted but the build subsequently fails. Without this,
     * the execution_runs row would stay in a non-terminal state.
     */
    onBuildFailed(runId: string, initFailure?: InitFailure): Promise<void>;
    /**
     * Create a failed execution run when the build timed out before onExecutionStarted
     * had a chance to insert the row (buildJobTrackedEarly was false).
     *
     * Inserts a minimal execution_runs row with status='failed' directly so the E2E
     * test (and dashboard) can observe the failure instead of a missing run.
     */
    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): Promise<void>;
    /**
     * Insert a `failed` execution_runs row directly for an init failure that
     * occurred BEFORE onExecutionStarted ran (so no in-memory state exists
     * and no jobs were dispatched). Also writes the structured init_failure
     * signal and fires onExecutionStatusChange so Platform's projection picks
     * it up via the normal forward path. Idempotent: if a row already exists
     * for this runId, the insert is a no-op (ON CONFLICT DO NOTHING).
     *
     * Closes the silent pre-run-failure gap — without this helper, secret /
     * install-secret / all-jobs-rejected early-exits in dispatch-matched-workflow
     * leave no trace on the dashboard.
     */
    recordInitFailureRun(args: {
        runId: string;
        workflowName: string;
        provider: string;
        repoIdentifier: string;
        ref: string;
        sha: string;
        deliveryId: string | null;
        providerContext: Record<string, unknown>;
        routingKey: string;
        initFailure: InitFailure;
        triggerEvent?: string;
        commitMessage?: string;
    }): Promise<void>;
    /**
     * Mark a run as failed immediately with a reason message.
     *
     * Used when no agents are available to dispatch any jobs (e.g. cron-triggered
     * runs on a cluster leader without matching local agents and no reachable peers).
     * Instead of leaving the run in 'running' for OrphanRecovery to catch after 5 min,
     * this fails it right away.
     */
    failRun(runId: string, reason: string, initFailure?: InitFailure): Promise<void>;
    /**
     * Update step status within a job.
     *
     * Upserts execution_steps row with timing information. On 'running',
     * sets started_at. On terminal state, sets completed_at, duration_ms,
     * exit_code. Also constructs log_path and forwards to Platform.
     *
     * @param logBytesStreamed Raw byte total reported by the agent's
     *   LogStreamer at terminal step time. Accumulated into a per-(run, job)
     *   counter that lands in `execution_jobs.log_bytes` and
     *   `execution_runs.log_bytes` when the job and run reach terminal state,
     *   feeding the operator-side `kici_org_log_bytes` capacity-planning gauge
     *   on the Platform.
     */
    onStepStatus(runId: string, jobId: string, stepIndex: number, stepName: string, state: string, timestamp: number, data?: Record<string, unknown>, logBytesStreamed?: number): Promise<void>;
    /**
     * Check if all tracked jobs in a run have reached terminal state.
     */
    isRunComplete(runId: string): boolean;
    /**
     * Get the current overall status of a run.
     */
    getRunStatus(runId: string): Extract<ExecutionRunStatus, 'running' | 'success' | 'failed' | 'cancelled'>;
    /**
     * Look up a job name from in-memory state.
     * Used by LogWriter to construct log paths.
     */
    getJobName(runId: string, jobId: string): string | undefined;
    /**
     * Get execution context for a run from in-memory state.
     * Used by commit status reporting to access provider/repo/sha info.
     */
    getExecutionContext(runId: string): ExecutionContext | undefined;
    /**
     * Update the heartbeat timestamp for a running job.
     *
     * Uses optimistic WHERE status='running' so completed jobs are not updated.
     * Called when the agent sends a job.heartbeat message.
     */
    updateJobHeartbeat(runId: string, jobId: string): Promise<void>;
    /**
     * Get the count of active (non-completed) runs in memory.
     */
    getActiveRunCount(): number;
    /**
     * Get a summary of all active runs for the cluster health API.
     * Returns run ID, workflow name, status, and job routing counts.
     */
    getActiveRuns(): Array<{
        runId: string;
        workflowName: string;
        status: string;
        jobs: {
            total: number;
            completed: number;
            failed: number;
            running: number;
        };
    }>;
    /**
     * Get replay data for all in-memory runs (both active and recently completed).
     * Used to send a state.replay message to Platform on reconnection so the Platform
     * can reconcile its execution_runs and execution_jobs projection tables.
     */
    getReplayData(): Array<{
        runId: string;
        workflowName: string;
        status: ExecutionRunStatus;
        routingKey?: string;
        repoIdentifier?: string;
        sha?: string;
        ref?: string;
        triggerEvent?: string;
        commitMessage?: string;
        parentRunId?: string | null;
        originalRunId?: string | null;
        triggeredBy?: string | null;
        failureReason?: string;
        jobCount: number;
        startedAt: number;
        completedAt?: number;
        durationMs?: number;
        jobs: Array<{
            jobId: string;
            jobName: string;
            status: string;
            startedAt?: number;
            completedAt?: number;
            runsOnLabels?: string[];
        }>;
    }>;
    /**
     * Replay data merged with terminal runs read from the orchestrator's local DB.
     *
     * `getReplayData()` only sees runs still in memory. After an orchestrator
     * crash/restart, in-memory state is empty until new webhooks arrive — but
     * any run that completed before the crash still lives in `execution_runs`
     * on disk. Without re-emitting those, Platform's mirror table (and the
     * `kici_org_executions_count` operator-aggregate gauge) silently undercounts.
     *
     * This wrapper fills that gap: it returns the in-memory replay items first,
     * then unions in any terminal-state runs from the local DB completed within
     * `windowHours` (default 24h) that aren't already covered. Order is preserved
     * for in-memory entries (callers may rely on that for active-run metadata);
     * DB-backed entries are appended in `completed_at ASC` order.
     *
     * Idempotent: Platform's `state.replay` handler upserts on `run_id`, so
     * re-emitting an already-mirrored run is a no-op for billing and dashboard
     * state alike.
     */
    getReplayDataWithDb(windowHours?: number): Promise<ReturnType<ExecutionTracker['getReplayData']>>;
    /**
     * Update a job's in-memory status without touching the DB.
     * Used by StaleRunDetector which does direct DB updates and only needs
     * the in-memory state kept in sync for run completion detection.
     */
    updateInMemoryJob(runId: string, jobId: string, status: string): void;
    /**
     * Forward a terminal job status to Platform via the onJobStatusChange callback.
     * Used by StaleRunDetector and OrphanRecovery which update the DB directly
     * but need to notify Platform so its execution_jobs projection stays in sync.
     */
    forwardJobTerminalStatus(runId: string, jobId: string, jobName: string, status: string, errorMessage?: string): void;
    /**
     * Emit a run.event message via the onRunEventEmit callback.
     * Public wrapper for use by StaleRunDetector and OrphanRecovery.
     */
    emitInfraEvent(runId: string, eventType: string, opts?: {
        jobId?: string;
        metadata?: Record<string, unknown>;
        durationMs?: number;
    }): void;
    /**
     * Cancel all non-terminal steps for a job.
     *
     * When a job is terminated by infrastructure (stale detection, orphan recovery,
     * recovery timeout), any in-progress steps remain with status='running' in the DB.
     * This method marks them as 'cancelled' so the dashboard doesn't show stale
     * running indicators for steps that are no longer executing.
     */
    cancelStepsForJob(runId: string, jobId: string, reason: string): Promise<void>;
    /**
     * Check if all jobs for a run are terminal, and if so, complete the run.
     * Works with in-memory state (normal operation) or falls back to DB query
     * (crash recovery / pruned runs). Called by StaleRunDetector after marking
     * stale jobs.
     */
    completeRunIfAllJobsTerminal(runId: string): Promise<void>;
    /**
     * Path A helper: complete a run using in-memory state. Called by the
     * stale detector when memRun is still tracked locally — writes the
     * execution_runs terminal row, fires Platform-forwarding +
     * workflow-complete callbacks, and schedules in-memory pruning.
     */
    private completeRunFromMemoryState;
    /**
     * Path B helper: complete a run using DB rows only (crash recovery /
     * pruned runs). Loads jobs + run row from execution_jobs/execution_runs,
     * checks the all-terminal predicate + run-state guard, then writes the
     * terminal row and fires Platform-forwarding callbacks.
     */
    private completeRunFromDbFallback;
    /**
     * Emit a run.event message to Platform via the onRunEventEmit callback.
     * Called at orchestrator lifecycle points for infrastructure event tracking.
     */
    private emitRunEvent;
    /**
     * Emit a scaler lifecycle event for a job.
     * Stores the event in the event_log table via the existing run.event pipeline
     * and writes a log line to the provisioning JSONL file.
     *
     * @param runId - The run this event belongs to
     * @param jobId - The job this event belongs to
     * @param event - The scaler event with type, detail, and timestamp
     */
    emitScalerEvent(runId: string, jobId: string, event: {
        agentId: string;
        eventType: ScalerEventType;
        detail: string;
        timestampMs: number;
    }): void;
    /**
     * Append a line to a per-job orchestration log file via LogStorage.
     * Log format is JSONL for structured parsing on the frontend.
     * Path convention: executions/{runId}/jobs/{jobId}/orchestration.jsonl
     */
    private writeOrchLog;
    /**
     * Build a human-readable description for a completed run.
     * Lists failed job names for non-success outcomes.
     */
    private buildRunDescription;
    /**
     * Compute the overall run status from job statuses.
     *
     * Per locked decision:
     * - success ONLY if ALL jobs pass (skipped jobs count as success)
     * - failed if ANY job failed or timed_out_stale
     * - cancelled if ANY job cancelled (and none failed)
     */
    private computeRunStatus;
}
export {};
//# sourceMappingURL=execution-tracker.d.ts.map