/** * The live depth: run one tick against real data, and say what it established. * * The harness is in Python, beside the loop production uses. This side builds its launch * configuration, runs it, and judges the outcome. * * ## The judgement that matters * * A tick returning nothing is ambiguous. It could be a healthy scanner with no setups, or one that * stopped before touching anything, or one whose every read failed. Those look identical from the * outside and mean completely different things, so the verdict keys on **successful reads** rather * than on the tick completing. * * A read that failed is not a read. Observed in practice: an authentication failure arrives as an * ordinary response carrying a false flag, raising nothing, so a scanner's own error handling never * fires and it computes a confidently wrong answer from missing input. Counting that as a read * would report the run clean. */ import { type ScannerTarget } from "./import-stage.js"; import { type SignalRecord } from "./signal-stage.js"; import type { Finding, FindingLocation } from "./types.js"; import type { ResolvedWallet } from "./wallet.js"; /** One recorded call, as the harness reports it. */ export interface ReadRecord { tool: string; ms: number; ok: boolean; error?: string; error_type?: string; response_keys?: string[]; cast_dropped?: boolean; /** * The instrument the call named, as its own arguments carried it. * * Recorded by the harness at the call site, so a finding can name the offending instrument * instead of the tool that was called with it. Absent when the call named none, and absent from * older harness output — never inferred from the error text, which is the server's prose. */ subject?: string; /** The call would have changed state and was refused rather than made. */ blocked?: boolean; /** The response came back and the scanner never looked inside it. */ unread?: boolean; } export interface TickOutcome { ok: boolean; reason?: string; detail?: string; status?: "ok" | "error" | "timeout"; failure?: { type: string; message: string; where?: { file: string; line: number; } | null; } | null; reads?: ReadRecord[]; reads_ok?: number; reads_failed?: number; signals?: SignalRecord[]; suppressed?: { file: string; line: number; type: string; message: string; }[]; last_return?: { file: string; line: number; function: string; } | null; stdout?: string; stderr?: string; } export interface LiveOptions { scanner: ScannerTarget; wallet: ResolvedWallet; /** Per-scanner budget. Defaults to what the recipe declares — never to the cadence. */ timeoutSeconds: number; intervalSeconds: number; defaultSignalValiditySeconds: number; inputs?: Record; signalDataSchema?: Record; stateHistoryMaxCount?: number; pythonBin?: string; } /** * Group failed reads by the service they belong to. * * One failed call among many is noise; every call to one service failing means a whole input is * missing and the scanner scored without it. The tool-name prefix is the service, which is enough * to tell those apart without knowing anything about the catalogue. */ export declare function groupFailuresByService(reads: ReadRecord[]): Map; /** What an earlier depth found that changes how this one reads its own result. */ export interface TickContext { /** * Places the import depth saw a data route the runtime cannot observe. * * Carried here because a tick that read nothing through the client, in a scanner that imports * `requests`, is a different situation from one that stopped early — and pointing the second * diagnosis at the first sends someone hunting a gate that does not exist. */ nonMcpSources?: FindingLocation[]; /** * What this run allowed a tick, and what production would allow it. * * They are not the same number. Validate caps at its own default so a six-hour-cadence scanner * does not make the command hang for six hours; production, when the recipe declares no * `timeout_seconds`, falls back to the interval (`scaffold.py`: `timeout_seconds = interval`). * Carried here because a timeout finding that says "this would time out in production too" is * simply false in that case, and a validator that states something untrue about production has * failed at the one job it has. */ budget?: TickBudget; } export interface TickBudget { /** The budget this run enforced. */ validateSeconds: number; /** The budget production would enforce for the same scanner. */ productionSeconds: number; /** Whether the recipe declared `timeout_seconds`. When it did, the two agree. */ declared: boolean; } /** * Production's tick budget for a scanner, mirroring the scaffold's own fallback. * * Kept beside the judgement that reports it, with the source named, because the whole point is * that this number is production's and not ours. */ export declare function productionBudgetSeconds(declaredTimeout: number | undefined, intervalSeconds: number): number; /** * Turn one tick into findings. * * Exported separately from running it so the judgement can be tested against recorded outcomes * without spawning anything or needing credentials. */ export declare function judgeTick(scanner: ScannerTarget, outcome: TickOutcome, context?: TickContext): Finding[]; /** Run one tick for one scanner. */ export declare function runTick(options: LiveOptions): Promise; //# sourceMappingURL=live-stage.d.ts.map