import type { MeshLedgerEntry } from './mesh-ledger.js';
import type { PendingMeshCoordinatorEvent } from './mesh-events.js';
import type { MeshAsyncJobLifecycle } from '../repo-mesh-types.js';
export type MeshAsyncRefineJobStatus = 'accepted' | 'running' | 'completed' | 'failed';
export interface MeshAsyncRefineJobSummary extends MeshAsyncJobLifecycle {
    jobId: string;
    interactionId?: string;
    status: MeshAsyncRefineJobStatus;
    meshId?: string;
    nodeId?: string;
    targetNodeId?: string;
    targetDaemonId?: string;
    workspace?: string;
    branch?: string;
    into?: string;
    retryOfJobId?: string;
    lastEvent?: string;
    lastLedgerKind?: string;
    lastUpdatedAt?: string;
    instruction: string;
}
export declare function buildMeshAsyncRefineJobs(args: {
    meshId?: string;
    ledgerEntries?: MeshLedgerEntry[];
    pendingEvents?: PendingMeshCoordinatorEvent[];
}): MeshAsyncRefineJobSummary[];
/** Terminal refine jobs older than this (relative to the newest job in the set) are
 * "stale" — already-resolved historical refinery rejections/successes that should not
 * keep inflating the status counts in mesh_status. 6h covers a long working session
 * while still folding multi-day-old residue. */
export declare const STALE_TERMINAL_REFINE_WINDOW_MS: number;
/** Cap on how many recent terminal jobs are counted even if all fall inside the freshness
 * window — prevents a burst of refines from dominating the summary. */
export declare const RECENT_TERMINAL_REFINE_CAP = 8;
export interface MeshAsyncRefineJobsSummary {
    /** Count of jobs reflected in `byStatus` (active jobs + recent terminal jobs). */
    total: number;
    byStatus: Record<string, number>;
    /** Terminal jobs dropped from the counts because they are stale residue. */
    staleTerminal: number;
    /** Non-terminal (accepted/running) jobs still in flight. */
    activeJobs: MeshAsyncRefineJobSummary[];
}
/**
 * Build a compact summary of refine jobs that folds stale terminal jobs.
 *
 * The full job list (from `buildMeshAsyncRefineJobs`) is derived from a recent ledger
 * window and deduped by jobId, but it still includes every terminal (completed/failed)
 * job that happens to fall in that window — including multi-day-old refinery rejections
 * that have long since been resolved. Those stale terminals inflate `byStatus.failed`
 * and read as "current breakage" when they are historical noise.
 *
 * Active (accepted/running) jobs are always counted. Terminal jobs are counted only when
 * they are recent: within `STALE_TERMINAL_REFINE_WINDOW_MS` of the newest job's activity
 * time AND among the `RECENT_TERMINAL_REFINE_CAP` most-recent terminals. Everything else
 * is folded into `staleTerminal` and excluded from `byStatus`.
 *
 * Freshness is measured relative to the newest job in the set (not wall-clock), so the
 * result is deterministic for a given input — important for tests and for stale-clock
 * environments.
 */
export declare function summarizeMeshAsyncRefineJobs(jobs: MeshAsyncRefineJobSummary[]): MeshAsyncRefineJobsSummary;
