import { type PathCtx } from '../config/paths.js'; import { type Ledger } from './ledger.schema.js'; export declare function ledgerFilePath(c?: PathCtx): string; export declare function loadLedger(c?: PathCtx): Ledger; export declare function saveLedger(ledger: Ledger, c?: PathCtx): void; /** * Is this account unusable at time `now`? * * Only an account-wide limit makes an account unusable. A limit on ONE model * leaves everything else about the account working, so it must not count here: * treating it as unusable is what stops a session starting on a model that is * perfectly available. */ export declare function isCapped(ledger: Ledger, account: string, now: number): boolean; /** The set of accounts that cannot run at all at time `now`. */ export declare function cappedNames(ledger: Ledger, now: number): Set; /** * Which (account, model) pairs are known spent right now, from limits recorded * EARLIER, including by other runs. * * Rotation plans from what it has measured plus what it has proven during the * run, and neither of those sees a limit an earlier run confirmed. Without * this, a fresh run offers a model back to the account it just ran out on, and * only rediscovers the limit by hitting it again. */ export declare function activeModelCaps(ledger: Ledger, now: number): Array<{ account: string; model: string; }>; export interface MarkCappedInput { account: string; now: number; reason?: string; /** Explicit reset time (epoch ms) if the signal provided one. */ resetAt?: number | null; /** Fallback window when no reset time is known. */ backoffMinutes?: number; /** Set when only ONE MODEL is out, rather than the whole account. */ model?: string; } /** * Record (or replace) a cap for an account. Returns a new Ledger. * * A model-scoped write replaces only the record for THAT model, so an account * can hold one per model. Replacing everything for the account was fine while * caps were only read as "can this account run at all", and wrong the moment * rotation started planning from them: capping Fable and then Opus on one * account erased the Fable record, and the next run offered Fable back to an * account whose Fable window was demonstrably closed. * * An account-wide write still replaces everything for the account, which is * right: nothing about that account is usable, so no per-model detail survives * as anything but noise. */ export declare function markCapped(ledger: Ledger, input: MarkCappedInput): Ledger; /** * When every current limit is about ONE MODEL rather than whole accounts, this * describes it: the model, and the soonest it frees up. * * This is the difference between "you cannot work" and "you cannot work on this * model". Treating the second as the first is how a Fable limit turns into an * apparently unusable setup, when switching models would have carried on fine. */ export declare function modelOnlyLimit(ledger: Ledger, now: number): { model: string; resetsAt: number | null; } | null; /** Drop caps whose window has passed. Returns a new Ledger. */ export declare function clearExpired(ledger: Ledger, now: number): Ledger; /** Remove any cap for an account (e.g. after a successful run). Returns a new Ledger. */ export declare function clearAccount(ledger: Ledger, account: string): Ledger;