import type { EpCaller } from "./endpoint-subjects.js"; import { type AnchorResolver } from "./endpoint-signing.js"; import { type CheckpointSettleFact } from "./endpoint-checkpoint.js"; import { type ActionContext, type GoalRef, type GoalStatusValue, type GoalResultFact } from "./endpoint-action.js"; /** A signed guard OBLIGATION (§13.6/§13.10): attenuations the effecting endpoint MUST apply, * bound to its goal/request id, reusable within it. Verified against the anchor registry * (role `obligations`, scope = the endpoints the key may attest for). */ export interface GuardObligation { v: 1; space: string; /** The guarded goal/request id this obligation binds to (§13.10: bound to its goal/request). */ requestId: string; signer: { keyId: string; }; /** The monotonic attenuations the endpoint MUST apply; opaque to this wiring (the effecting * handler interprets them), validated as non-empty structured entries and signed. */ attenuations: unknown[]; iat: number; exp: number; sig: string; } /** The guard endpoint's parsed answer (closed per decision): `hold` carries the checkpoint * coordinates; `deny` carries an optional reason; obligations ride `allow`/`hold` only. */ export type GuardAnswer = { decision: "allow"; obligations: GuardObligation[]; } | { decision: "deny"; reason?: string; } | { decision: "hold"; token: string; holdDeadlineMs: number; obligations: GuardObligation[]; }; /** The injected class-call seam: invoke the guard endpoint's decision command and return its * raw answer body PLUS the broker-authenticated responder identity (derived from the reply * subject by the caller's transport layer, never from the body). The seam receives the * guarded request's coordinates so the guard knows WHAT it is deciding; the GATE owns all * parsing and verification of the answer, so no wiring can surface an unverified obligation. */ export type GuardCallSeam = (q: { /** The guard endpoint the VERIFIED trait value names. */ guardEndpoint: string; /** The guarded request's broker-authenticated coordinates. */ endpoint: string; command?: string; requestId: string; caller: EpCaller; }) => Promise<{ answer: unknown; responder: { id: string; lifecycleUid: string; }; }>; /** The gate's verdict for the effecting handler. */ export type GuardVerdict = { decision: "allow"; obligations: GuardObligation[]; } | { decision: "hold"; token: string; holdDeadlineMs: number; obligations: GuardObligation[]; responder: { id: string; lifecycleUid: string; }; }; /** Run the §13.6 guard gate for one guarded request: call the guard endpoint (via the injected * seam) within `deadlineMs`, and classify FAIL-CLOSED — the ONLY outcomes are a verified * ALLOW, a verified HOLD (the caller then wires the pause via {@link holdGuardedGoal}), or a * `permission-denied` throw. A timeout, transport failure, garbled answer, cross-variant * fields, or an obligation that does not verify (signature, scope, window, request binding) * all DENY. Ordering is guard-then-effect: call this BEFORE any effect. */ export declare function runGuardGate(opts: { /** The guard endpoint named by the VERIFIED `ai.cotal.guarded` trait value (the D6 governed * attachment verification is the caller's step; this seam trusts its output only). */ guardEndpoint: string; /** The guarded request's coordinates (broker-authenticated at the serve boundary). */ request: { endpoint: string; command?: string; id: string; caller: EpCaller; }; callGuard: GuardCallSeam; /** The guard budget: past it the gate DENIES (never hangs, never allows). */ deadlineMs: number; now: number; space: string; resolveAnchor: AnchorResolver; }): Promise; /** The ACTION composite's guard gate (§13.6): run by the OWNING instance for a guarded goal * BEFORE any execution effect — the counterpart of the ephemeral rail's * `assertGovernedPreEffect`, with hold ROUTED instead of refused. {@link runGuardGate} does * the calling, parsing, and obligation verification; this seam projects the verdict onto the * goal: * - ALLOW: the goal transitions accepted → running under the owner's construction-bound * proof (this projection is the owner's admission to execute) and the VERIFIED * obligations return for the executor, which MUST apply them; * - HOLD: {@link holdGuardedGoal} mints the guard-holder-bound checkpoint and projects * `waiting`; * - DENY (or ANY fail-closed gate refusal: timeout, garble, unverifiable obligation): the * goal commits terminal `failed` at the shared commit point under the OWNER's * construction-bound proof — the owner runs this gate, so the deny predicate is the * owner's own refusal to execute, carrying the gate's reason in the terminal payload. * Obligations bind to the GOAL id (§13.10: bound to its goal/request, reusable within it). */ export declare function gateGoalExecution(ctx: ActionContext, args: { goal: GoalRef; /** The guard endpoint named by the goal's VERIFIED `ai.cotal.guarded` trait value. */ guardEndpoint: string; callGuard: GuardCallSeam; resolveAnchor: AnchorResolver; deadlineMs: number; now: number; /** The OWNING instance arming a hold's timer (its identity/epoch subject, §13.12). */ instanceId: string; epoch: number; }): Promise<{ outcome: "running"; obligations: GuardObligation[]; status: GoalStatusValue; } | { outcome: "waiting"; hold: { token: string; holdDeadlineMs: number; }; obligations: GuardObligation[]; status: GoalStatusValue; } | { outcome: "denied"; won: boolean; fact: GoalResultFact; status: GoalStatusValue; }>; /** The durable HOLD reconciler (§13.6): converge a goal whose guard-hold checkpoint SETTLED * while the goal projection lags (a release or expiry crashed mid-flight, or the timer fire * settled the checkpoint and the owner's projection is still owed). For a goal `waiting` on * checkpoint T whose spec binds THIS goal: * - settle RESUMED: finish the projection to `running` (idempotent); * - settle EXPIRED: drive the terminal deny via {@link expireGuardHold} (idempotent); * - still live: nothing to do — the timer plane owns the deadline. * A goal not waiting, or waiting on a token whose checkpoint does not bind it, is left * untouched: this reconciler converges exactly the holds this module minted. (The * mint-then-no-wait partial state is recovered by RETRYING the gate — the mint is * idempotent-if-identical and the transition completes; a dedicated repair arm was * panel-adjudicated as insurance ahead of composition and deliberately not built.) * A converged `running` carries the hold's RECORDED verified obligations (§13.6/§13.10: * MUST-apply, reusable within the goal — the pause never launders them away). */ export declare function reconcileGuardHold(ctx: ActionContext, args: { goal: GoalRef; now: number; }): Promise<{ converged: "running" | "denied" | "none"; obligations?: GuardObligation[]; }>; /** Convert a HELD action to `waiting` on a checkpoint OWNED BY THE GUARD DECISION (§13.6): the * checkpoint's holder is the guard's authenticated responder (only IT may resume), the * deadline is the hold's (mandatory), and the goal's status projects `waiting` carrying the * checkpoint coordinate. The mint is idempotent and the timer is armed through the mediated * plane by the checkpoint module. */ export declare function holdGuardedGoal(ctx: ActionContext, args: { goal: GoalRef; hold: { token: string; holdDeadlineMs: number; responder: { id: string; lifecycleUid: string; }; obligations?: GuardObligation[]; }; /** The OWNING instance arming the hold's timer (its identity/epoch subject, §13.12). */ instanceId: string; epoch: number; now: number; }): Promise; /** Release a guard hold: the GUARD (the checkpoint's holder, presenting as itself) resumes the * one-use checkpoint, and the goal leaves `waiting` back to `running`. The token is first bound * to THIS goal (a valid token for another goal never releases it), THEN the resume seam * enforces holder binding, one-use, and the deadline fence (a hold past its deadline drives * the EXPIRED settlement there and refuses; an expired hold never releases). * * CRASH CONVERGENCE (the checkpoint settlement is the arbiter; the goal transition is its * derived projection): a crash between the one-use resume and the goal transition leaves the * checkpoint `resumed` and the goal `waiting` — the RETRY's resume loses `conflict`, so it * OBSERVES the recorded settlement, requires it to be THIS presenter's own `resumed` (a * foreign or expired settlement rethrows), and finishes the projection idempotently (a goal * already `running` is the converged state, not an error). */ export declare function releaseGuardHold(ctx: ActionContext, args: { goal: GoalRef; token: string; presenter: { id: string; lifecycleUid: string; }; now: number; }): Promise<{ settle: CheckpointSettleFact; status: GoalStatusValue; obligations: GuardObligation[]; }>; /** Settle an EXPIRED guard hold onto the goal: an expired hold is DENY (fail closed). The token * is first bound to THIS goal (an arbitrary token never terminal-fails an unrelated goal), then * the CHECKPOINT is owner-expired (settling its status and stopping its timers, so no orphaned * schedule lingers until the checkpoint's own deadline), and finally the goal commits terminal * `failed` (permission-denied) at the shared commit point — where a racing completion or cancel * may lawfully have won first (the caller observes the winner; the projection converges either * way). Idempotent: an already-terminal goal returns its winner. */ export declare function expireGuardHold(ctx: ActionContext, args: { goal: GoalRef; token: string; now: number; }): Promise<{ won: boolean; fact: GoalResultFact; status: GoalStatusValue; }>; //# sourceMappingURL=endpoint-guard.d.ts.map