import { type PolicyDoc } from './evaluate.js'; export declare const POLICY_ROTATION_SCHEMA = "flows-policy-rotation-v1"; export type PolicyRotationStatus = 'active' | 'pending'; /** The canonical body the rotate action signs (EIP-191 over JCS). */ export interface PolicyRotationAttestationBody { schema: typeof POLICY_ROTATION_SCHEMA; walletRef: string; /** sha256(JCS(newDoc)) — the policy hash now in force (or pending). */ contentHash: string; /** The contentHash this rotation supersedes; null for first registration. */ previousHash: string | null; /** newDoc.version — strictly increments previousVersion. */ version: number; status: PolicyRotationStatus; /** ISO time a pending (timelock) rotation becomes active; omitted when active. */ activatesAt?: string; /** * The signing action's declared ACTION_VERSION — metadata stamped (and therefore * signed) so every persisted attestation records WHICH version of the seat minted * it. The trust root is still the CID-derived signer address, never this label; * this drives the live-attestation-count-per-version "safe to disable vN?" query. * Omitted when the seat declares no version (e.g. legacy / unversioned callers). */ actionVersion?: number; } /** The signed attestation envelope the action returns and the app stores. */ export interface PolicyRotationAttestation { body: PolicyRotationAttestationBody; /** EIP-191 personal_sign over canonicalize(body). */ signature: string; /** The action's CID-derived signer address (verified against the registry). */ signerAddress: string; /** The rotate action's IPFS CID (selects the registry entry to verify against). */ actionCid: string; } /** The trusted prior-attestation facts (caller verified the prior self-signature). */ export interface PriorPolicy { contentHash: string; version: number; } export interface AuthorizeRotationInput { walletRef: string; previousDoc: PolicyDoc | null; newDoc: PolicyDoc; /** The verified current policy this rotation supersedes; null for first registration. */ prior: PriorPolicy | null; /** Authorization facts the caller already cryptographically verified. */ authorization: { /** verifyGovernanceQuorum returned ok (quorum + on-chain owners + doc binding). */ quorumVerified?: boolean; /** The approval attestation's signature verified against the trusted signer. */ approvalVerified?: boolean; /** The boundHash carried in the approval attestation. */ approvalBoundHash?: string; /** The policy-edit intent the approval must bind (its JCS hash is recomputed here). */ policyEditIntent?: unknown; }; nowMs: number; /** * The seat's declared ACTION_VERSION, stamped into the signed attestation body * (ops/legibility metadata — NOT the trust root). Omitted ⇒ no actionVersion in * the body (back-compat with callers that don't declare one). */ actionVersion?: number; } export type RotationDecision = 'register' | 'pending'; export type RotationReason = 'first_registration_not_null_prev' | 'first_registration_unsafe_circuit' | 'stale_or_forged_previous' | 'non_monotonic_version' | 'loosening_unauthorized' | 'timelock_invalid' | 'approval_unbound'; export interface AuthorizeRotationResult { ok: boolean; decision?: RotationDecision; reason?: RotationReason; /** Present when ok — the attestation body to sign (status reflects pending vs active). */ body?: PolicyRotationAttestationBody; } /** * Decide whether a policy-hash rotation is authorized and produce the attestation * body to sign. Fail-closed: any unmet condition → { ok:false, reason }. */ export declare function authorizePolicyRotation(input: AuthorizeRotationInput): AuthorizeRotationResult;