import type { Guard } from "./guard.js"; import type { StateStack } from "./state/stateStack.js"; /** * The Agency-level guard: the set of runtime guards one `guard(...)` call * pushed. `guard(cost: $1, time: 5m)` pushes a CostGuard AND a TimeGuard — * two objects, two guardIds — and everything user-facing (the trip * interrupt, the approve payload naming both dimensions, disarm lists, * the root-budget refusal) is about the PAIR. This class is the pair's * name. It is never stored: construct it on demand from a stack plus the * member ids, which ARE stored (`Guard.scopeIds`). * * Resolution is ALWAYS against a specific branch's stack, never a global * registry: fork time-clones carry the parent's guardId, so only the * raising branch's own stack knows which physical object answers to an * id there. That one rule is what makes approve routing correct across * fork, race, and the subprocess boundary (the answer is applied at the * raise site, in the process and branch that own the guard). */ export declare class GuardScope { private readonly members; private readonly stack; private constructor(); /** The scope a tripped guard belongs to, resolved on `stack`. Members * are matched innermost-first by id. A guard with an empty scopeIds * (root budgets, agency.withCostGuard) is its own single-member * scope. Returns null when no member is present on this stack — * callers treat that as a stale or foreign answer, a runtime error, * never a silent no-op. */ static resolve(stack: StateStack, tripped: Guard): GuardScope | null; memberFor(dimension: "cost" | "time"): Guard | null; /** User code cannot approve its way past the operator: a scope with a * root member refuses extension wholesale. */ containsRootBudget(): boolean; memberIds(): string[]; /** Apply a merged approve payload. Grants are ADDITIVE per named * dimension (negative deltas clamp to zero with a warning — see * clampGrant); an omitted dimension continues unchanged with its * remaining allowance; `disarm` names dimensions to stop metering. * Throws GuardApproveError on: a root scope, a payload naming a * dimension this scope does not have, or an answer that leaves the * TRIPPED dimension still over budget and armed — that answer would * re-trip forever (the handler-chain recursion guard cannot catch the * loop; its depth resets on every fresh trip). */ extend(payload: { maxCost?: number; maxTime?: number; disarm?: ("cost" | "time")[]; message?: string; }, tripped: "cost" | "time"): void; /** The interrupt-data fields describing this scope at raise time. */ snapshot(tripped: "cost" | "time"): { label: string | null; scopeIds: string[]; dimension: "cost" | "time"; limit: number; spent: number; maxCost: number | null; maxTime: number | null; }; /** Freeze the scope while its trip is being decided: the members and * every guard installed AFTER the innermost member stop gating, * charging, and ticking ON THIS BRANCH. Uses the stack's suspension * bracket (branch-scoped) — NOT object flags — for the same reason * handler suspension does: a shared CostGuard flagged object-wide * would blind sibling branches (see PR 1's deviation note in the * resumable-guards plan). Returns the token endSuspension needs. */ suspendForDecision(stack: StateStack): string[]; } /** A defective answer to a guard trip — attributed to the answering * handler by the chain machinery. Plain Error: this is the exception * domain (a bug in supervisory code), not an abort or a failure. */ export declare class GuardApproveError extends Error { constructor(message: string); }