import type { Board, LangfuseConnection } from "./model.js"; /** * staves — as run. * * Production observations read back in board vocabulary: how often a job ran, how long it took, * how often it failed, which exit the work took and where it went next. Measurement beside design: * nothing here claims a job is implemented, and nothing here carries a prompt, an input or an output. * Every number is returned with the window it covers and the bound of the scan that produced it. */ export type ObservationLevel = "DEBUG" | "DEFAULT" | "WARNING" | "ERROR"; /** One observation, reduced to what the board can say. Never a copy of trace contents. */ export interface RunObservation { id: string; traceId: string; /** staves.case when set, else the trace id: one unit of work. */ caseId: string; jobId: string; /** staves.exit: the id of the job the work went to next, or "stop". Exits have no ids of their own. */ exitId?: string; revision?: string; startTime: string; endTime?: string; latencyMs: number; level: ObservationLevel; statusMessage?: string; name?: string; type?: string; parentObservationId?: string; } export interface RunWindow { from: string; to: string; } export interface ObservationScan { observations: RunObservation[]; window: RunWindow; /** observations the filtered query returned: the bound on every number derived from this scan */ scanned: number; /** the scan hit its page limit with more still to read; older observations in the window were not read */ truncated: boolean; } export interface ReadObservationsRequest { boardId: string; fromStartTime?: string; toStartTime?: string; /** pages of 100; 20 pages = 2,000 observations */ maxPages?: number; fetchImpl?: typeof fetch; env?: Record; now?: () => Date; } /** Scan the window newest-first for observations instrumented to this board. * * The board filter is applied by the server. Verified by the controller against the live project on * 15 Sep 2026: 34 of the project's 35 observations came back for this board, and both "=" and * "contains" are accepted on this column. "=" is the one sent, because "contains" also matches a board * id that is merely a prefix of another, which would inflate `scanned` with another board's work. * The client-side board guard below stays as the safety net: a filter that silently matched nothing * would otherwise read as "this board never ran". Reuses the credential reader; adds no second fetch path. */ export declare function readObservations(connectionInput: LangfuseConnection, request: ReadObservationsRequest): Promise; export interface JobRuns { runs: number; failures: number; p50Ms: number; p95Ms: number; firstSeen: string; lastSeen: string; } export interface RunAggregate { window: RunWindow; scanned: number; truncated: boolean; jobs: Record; /** per job, how often each recorded exit was taken: a job id, or "stop" */ exits: Record>; handoffs: Record>; /** both directions: ids the board does not have, and jobs the board has that did not run */ drift: { unknownJobs: Record; neverRan: string[]; }; cases: number; } /** Read the board in run terms. Measurement beside design: a job with runs is not thereby * implemented as designed, and a job with none is not thereby missing — both are questions. */ export declare function aggregateRuns(scan: ObservationScan, board: Board): RunAggregate; /** The window a runs request asked for: whole days from 1 to 90, a week when unreadable. One rule for * the local daemon and the hosted gateway, so the same URL reads the same window on both. */ export declare function runDays(value: string | null): number; export interface RecentCase { caseId: string; startTime: string; endTime: string; steps: number; failures: number; totalMs: number; } /** The window's cases, newest first: one unit of work each, with the bound of what was scanned. * Ids only — a case carries no prompt, input or output back to the board. */ export declare function recentCases(observations: RunObservation[], limit?: number): RecentCase[]; export interface ReplayStep { jobId: string; /** the board has this job today; an unknown id is kept, never dropped, and never invented */ known: boolean; startTime: string; endTime?: string; latencyMs: number; level: ObservationLevel; exitId?: string; } export interface RunReplay { caseId: string; traceIds: string[]; steps: ReplayStep[]; /** first start to last end, or to the last start while it is still running */ totalMs: number; failures: number; } /** One unit of work, in the order it happened. The id is a staves.case or a trace id. */ export declare function replayRun(observations: RunObservation[], caseId: string, board: Board): RunReplay;