/** * Federation budget + hop counter (ADR-097 Phase 1). * * Carried in {@link FederationEnvelope} alongside the existing * sourceNodeId/targetNodeId/payload. Sender supplies the original limits; * each outbound hop increments hopCount and decrements remaining budget. * * Phase 1 enforces at the *send* side because there is no inbound * dispatcher today (sendToNode is a stub — see researcher report). * Phase 2 will move the decrement to receive once the inbound path lands. * * Security invariants pinned by the reviewer (audit_1776853149979 follow-up): * * 1. validateBudget rejects NaN, ±Infinity, negative numbers, and * non-integer hop counts. Returns a discriminated result so callers * cannot accidentally use a bad budget unchecked. * 2. enforceBudget runs check-then-decrement in a single synchronous * function with no awaits inside — two concurrent send calls cannot * both pass the pre-check. * 3. Errors return constant strings ("HOP_LIMIT_EXCEEDED" / * "BUDGET_EXCEEDED") with no remaining-budget echo so a caller can't * use the error response as an oracle for the threshold. */ /** Maximum hops a federation message may travel before the breaker opens. */ export declare const DEFAULT_MAX_HOPS = 8; /** * Caller-supplied budget. All fields are optional; omitted fields are * treated as Infinity for the corresponding axis. Created via validateBudget; * never construct directly. */ export interface Budget { readonly maxHops: number; readonly maxTokens: number; readonly maxUsd: number; } /** Discriminated result of validating raw user input into a Budget. */ export type BudgetValidationResult = { ok: true; budget: Budget; } | { ok: false; error: string; }; /** * Validate a raw budget object. Pure, no side effects. Caller obtains either * a guaranteed-safe Budget or a structured error suitable for logging. * * Accepts undefined/null and returns a default unbounded budget (maxHops = * DEFAULT_MAX_HOPS, tokens/usd = Infinity). This preserves backward * compatibility for callers that don't pass a budget at all. */ export declare function validateBudget(raw: unknown, overrideMaxHops?: unknown): BudgetValidationResult; /** * Enforcement decision returned by enforceBudget. Discriminated so the * caller can map directly to a constant-string error — no remaining-budget * echo on the failure side (anti-oracle). */ export type BudgetEnforcement = { ok: true; nextHopCount: number; remaining: Budget; } | { ok: false; reason: 'HOP_LIMIT_EXCEEDED' | 'BUDGET_EXCEEDED'; }; /** * Atomic (single synchronous function, no internal awaits) hop check. * * Returns the hopCount value the OUTBOUND envelope should carry plus the * remaining budget that downstream peers will see. Callers must use the * returned values; mutating the input Budget is forbidden (it's readonly). * * Contract: * - hopCount represents how many hops the message has already taken. * - The next outbound hop increments it: nextHopCount = hopCount + 1. * - The check fires AFTER increment: nextHopCount must be <= maxHops. * - This means maxHops=0 refuses to forward at all, which matches the * ADR's "no remote delegation allowed" semantic. * * tokensSpent / usdSpent are caller-reported actuals from the immediately * preceding leg (or 0 on the originator). The check fires on the * *post-spend* totals so a leg that overshoots is caught before the next * outbound dispatch. */ export declare function enforceBudget(budget: Budget, hopCount: number, spent?: { tokens: number; usd: number; }): BudgetEnforcement; //# sourceMappingURL=federation-budget.d.ts.map