/** * federation/budget.ts — FederationBudget: per-peer reserved → * committed → released state machine for token / USD spend. * * F-038 — ported from ruflo * `v3/@claude-flow/plugin-agent-federation/src/domain/value-objects/federation-budget.ts` * (validateBudget + enforceBudget shape) and folded into a class * that tracks actual spend per peer across calls. * * State machine (per peer): * reserved: amount is held back (the peer is going to spend ≤ N). * committed: amount was actually spent (the call completed and we * know the real cost). * released: amount returned to the peer (call failed before * commit; we give the hold back). * * Persistence: optional JSON snapshot at * `.harness/federation-budget.json` so the budget survives a * Claude Code session restart. The file is gitignored. */ /** Default budget JSON path. */ export declare const DEFAULT_BUDGET_PATH = ".harness/federation-budget.json"; /** Hard ceilings — matches ruflo's MAX_*_CEILING values, kept here * so callers can't ask for absurdly large budgets. */ export declare const MAX_USD_CEILING = 1000000; export declare const MAX_TOKENS_CEILING = 1000000000; export type ReserveResult = { ok: true; reservationId: string; } | { ok: false; reason: "peer_over_budget" | "invalid_amount"; }; export interface PerPeerBudget { readonly nodeId: string; readonly maxTokens: number; readonly maxUsd: number; readonly maxHops: number; readonly spentTokens: number; readonly spentUsd: number; } export interface PersistedBudget { readonly version: 1; readonly updatedAt: string; readonly perPeer: PerPeerBudget[]; } interface Reservation { readonly id: string; readonly nodeId: string; readonly tokens: number; readonly usd: number; readonly atMs: number; } /** Pure validator — borrowed from ruflo's `validateBudget` and * simplified. Returns a discriminated result. */ export declare function validateBudgetInput(raw: unknown): { ok: true; maxTokens: number; maxUsd: number; maxHops: number; } | { ok: false; error: string; }; export interface FederationBudgetOpts { /** Override the JSON persistence path. */ readonly path?: string; /** Default per-peer limits applied when a peer is first seen. */ readonly defaultMaxTokens?: number; readonly defaultMaxUsd?: number; readonly defaultMaxHops?: number; } export declare class FederationBudget { private readonly path; private readonly perPeer; private readonly reservations; private readonly defaults; constructor(opts?: FederationBudgetOpts); /** Get or lazily-create the per-peer budget record. */ getOrCreate(nodeId: string): PerPeerBudget; /** Override the limits for a specific peer. */ setLimits(nodeId: string, limits: { maxTokens?: number; maxUsd?: number; maxHops?: number; }): void; /** Reserve `tokens` + `usd` against a peer's budget. The caller * MUST eventually `commit()` or `release()` — un-released * reservations are surfaced via `outstanding()`. */ reserve(nodeId: string, tokens: number, usd: number): ReserveResult; /** Commit a reservation — caller reports the ACTUAL spend which * may be less than the reserved amount. Difference is refunded. */ commit(reservationId: string, actual?: { tokens?: number; usd?: number; }): boolean; /** Release a reservation — full refund. */ release(reservationId: string): boolean; /** List outstanding reservations. */ outstanding(): Reservation[]; /** Snapshot every per-peer budget — for the status MCP tool. */ snapshot(): PerPeerBudget[]; /** Serialize to the persisted JSON shape. */ toJSON(): PersistedBudget; /** Write to disk (atomic tmp + rename). */ saveToDisk(): void; /** Re-read from disk, replacing in-memory state. */ loadFromDisk(): void; } export {}; //# sourceMappingURL=budget.d.ts.map