export type LoopStatus = 'running' | 'halted' | 'completed' | 'dead'; /** A running loop is presumed dead when it has not heartbeat for this long. */ export declare const SILENT_DEATH_MS: number; export interface LoopEntry { id: string; repo: string; contractPath: string; goal: string; autonomyLevel: string; status: LoopStatus; lastHeartbeat: string; iteration: number; gateVerdict: string; tokenEstimate: number; killRequested: boolean; registeredAt: string; /** Brakes mirrored from the contract at registration (Cortex enforces them). */ maxIterations?: number; tokenBudget?: number; /** LP-07: estimated tokens per iteration (contract `token_per_iteration`). */ tokenPerIteration?: number; /** LP-07: worst-case total tokens = tokenPerIteration × maxIterations (pre-flight). */ worstCaseTokens?: number; /** * LP-07 cost-per-accepted-change accounting, set by loop_report: * `accepted` = changes accepted this run, `tokensUsed` = tokens actually spent. */ accepted?: number; tokensUsed?: number; } /** * Load the registry. A torn/corrupt file is quarantined (moved to * loops.json.corrupt-) and reported LOUD on stderr rather than silently * resetting to [] — an empty registry means the kill switch and brakes go blind. */ export declare function loadLoops(): LoopEntry[]; export declare function saveLoops(entries: LoopEntry[]): void; /** Cost aggregates preserved when terminal loops leave the live registry. */ export interface RepoArchiveAgg { archived: number; attempts: number; accepted: number; tokensUsed: number; verdicts: Record; } export interface ArchiveSummary { archivedCount: number; lastArchivedAt: string | null; byRepo: Record; } /** Read the archive cost summary (a corrupt file is quarantined, not silently reset). */ export declare function loadArchiveSummary(): ArchiveSummary; /** * LP-07: cumulative token ceiling for a whole repo. Per-repo override in * ~/.genius-cortex/config.json (`repoTokenBudgets`) wins; otherwise the generous * `repoTokenBudget` default. Enforced against the SUM of every loop's * tokenEstimate in the repo at heartbeat time. */ export declare function getRepoBudget(repo: string): number; /** Parse "200k" / "1.5M" / "200000" into a number of tokens. */ export declare function parseTokenBudget(raw: string | undefined): number | undefined; interface ContractInfo { goal: string; autonomyLevel: string; maxIterations?: number; tokenBudget?: number; tokenPerIteration?: number; } export interface ContractValidation { ok: boolean; errors: string[]; info?: ContractInfo; } /** * Validate that a CONTRACT.md is registrable: goal / gate / brakes / * blast_radius sections present. Also extracts goal, autonomy level and the * brakes Cortex enforces at heartbeat time. */ export declare function validateContract(contractPath: string): ContractValidation; export interface RegisterParams { repo: string; contractPath: string; goal?: string; autonomyLevel?: string; id?: string; } export interface RegisterResult { ok: boolean; entry?: LoopEntry; errors?: string[]; /** Non-fatal advisories surfaced at registration (e.g. worst-case > budget). */ warnings?: string[]; } export declare function registerLoop(params: RegisterParams): RegisterResult; export interface HeartbeatParams { id: string; iteration?: number; gateVerdict?: string; tokenEstimate?: number; } export interface HeartbeatResult { ok: boolean; kill: boolean; reason?: string; entry?: LoopEntry; error?: string; } export declare function heartbeatLoop(params: HeartbeatParams): HeartbeatResult; export interface ReportParams { id: string; status: 'completed' | 'halted' | 'dead'; verdict?: string; /** LP-07: number of changes accepted this run (for cost-per-accepted-change). */ accepted?: number; /** LP-07: tokens actually spent this run. */ tokensUsed?: number; } export interface ReportResult { ok: boolean; entry?: LoopEntry; error?: string; } export declare function reportLoop(params: ReportParams): ReportResult; export interface KillParams { id?: string; repo?: string; all?: boolean; } export interface KillResult { ok: boolean; killed?: string[]; error?: string; } export declare function killLoops(params: KillParams): KillResult; /** status as stored, or 'suspected-dead' for a running loop gone silent. */ export type EffectiveStatus = LoopStatus | 'suspected-dead'; export interface LoopView extends LoopEntry { effectiveStatus: EffectiveStatus; } export declare function listLoops(now?: Date): LoopView[]; /** A loop "loses money" when fewer than this fraction of its changes are accepted. */ export declare const LOSING_MONEY_THRESHOLD = 0.5; export interface LoopStat { id: string; repo: string; status: LoopStatus; attempts: number; accepted: number | null; tokensUsed: number; acceptanceRate: number | null; tokensPerAccepted: number | null; losingMoney: boolean; } export interface RepoStat { repo: string; loops: number; attempts: number; accepted: number; tokensUsed: number; tokenEstimate: number; budget: number; acceptanceRate: number | null; tokensPerAccepted: number | null; losingMoney: boolean; } export interface StatsView { loops: LoopStat[]; repos: RepoStat[]; } /** * Compute cost-per-accepted-change metrics per loop and per repo. Acceptance * rate = accepted / attempts (iterations); cost-per-accepted = tokensUsed / * accepted. A loop/repo with a known acceptance rate below LOSING_MONEY_THRESHOLD * is flagged `losingMoney` ("this loop is losing money"). */ export declare function loopStats(): StatsView; export {};