import type { MeshIdentity, MeshStore } from "../mesh/store.js"; export type DecisionKind = "approval" | "question" | "escalation"; export type DecisionInput = "text" | "confirm" | "select" | "editor"; export type DecisionStatus = "open" | "answered" | "expired" | "cancelled"; export type DecisionHolder = "root" | "user" | `supervisor:${string}`; export interface DecisionOption { id: string; label: string; } export interface DecisionAnswer { optionId?: string; text?: string; answeredBy: string; via: string; at: number; } export type DecisionOnExpire = "cancel" | "default" | "escalate"; export interface DecisionEscalation { /** Holders in order, frozen at raise time; `chain[0]` is the first holder. */ chain: DecisionHolder[]; /** Index of the current holder in `chain`. */ hop: number; hopTimeoutMs: number; onFinal: "cancel" | "default"; } export interface DecisionHistoryEntry { holder: DecisionHolder; until: number; reason: "expired" | "escalated"; text?: string; by?: string; } export interface DecisionRecord { id: string; kind: DecisionKind; title: string; body?: string; options?: DecisionOption[]; input?: DecisionInput; raisedBy: { participantId: string; runId?: string; sessionId?: string; }; holder: DecisionHolder; createdAt: number; deadline?: number; onExpire: DecisionOnExpire; defaultOptionId?: string; escalation?: DecisionEscalation; history?: DecisionHistoryEntry[]; status: DecisionStatus; answer?: DecisionAnswer; } export interface DecisionRaiseInput { kind?: unknown; title?: unknown; body?: unknown; options?: unknown; input?: unknown; holder?: unknown; deadline?: unknown; timeoutMs?: unknown; onExpire?: unknown; defaultOptionId?: unknown; escalation?: unknown; } export declare const DECISION_PREFIX = "decisions/"; export declare const DECISIONS_TOPIC = "fabric.decisions"; export declare const MAX_DECISION_TITLE_CHARS = 200; export declare const MAX_DECISION_BODY_CHARS = 4000; export declare const MAX_DECISION_TEXT_CHARS = 4000; export declare const MAX_DECISION_OPTIONS = 12; export declare const MAX_DECISION_DEADLINE_MS: number; export declare const MIN_DECISION_TIMEOUT_MS = 1000; export declare const MAX_OPEN_DECISIONS = 200; export declare const MAX_ESCALATION_HOPS = 8; export declare const MIN_ESCALATION_HOP_MS = 1000; export declare const MAX_ESCALATION_HOP_MS: number; export declare const DEFAULT_ESCALATION_HOP_MS: number; export declare const MAX_ESCALATION_REASON_CHARS = 500; export declare const assertDecisionId: (value: unknown) => string; export declare const decisionHolderValue: (value: unknown) => DecisionHolder; /** The default chain climbs from the given holder: supervisor -> root -> user. */ export declare const defaultEscalationChain: (holder: DecisionHolder) => DecisionHolder[]; /** Validate raise arguments into an open record; throws on any malformed field. */ export declare const buildDecisionRecord: (input: DecisionRaiseInput, raisedBy: DecisionRecord["raisedBy"], now?: number) => DecisionRecord; export interface DecisionAnswerInput { optionId?: unknown; text?: unknown; } /** Validate an answer against an open record; returns the answer payload. */ export declare const validateDecisionAnswer: (record: DecisionRecord, input: DecisionAnswerInput) => { optionId?: string; text?: string; }; /** The stored chain when it is well formed; a malformed one escalates nowhere. */ export declare const decisionEscalation: (record: DecisionRecord) => DecisionEscalation | undefined; /** * Apply every deadline that has passed by `now`. Each elapsed hop hands the * decision to the next holder with a deadline one hopTimeoutMs after the * previous one, so a late reader lands where a punctual one would have. Past * the last hop, `onFinal` resolves it like a plain cancel/default expiry. */ export declare const applyDecisionDeadline: (record: DecisionRecord, now: number) => DecisionRecord; /** `hop 2/3` for an escalating decision, undefined otherwise. */ export declare const decisionHopLabel: (record: DecisionRecord) => string | undefined; type DecisionAuthorize = (record: DecisionRecord) => void; export declare class DecisionStore { #private; readonly mesh: MeshStore; readonly identity: MeshIdentity; readonly now: () => number; constructor(mesh: MeshStore, identity: MeshIdentity, now?: () => number); raise(input: DecisionRaiseInput, raisedBy?: Partial): Promise; get(id: string): Promise; list(filter?: { status?: DecisionStatus; holder?: string; limit?: number; }): Promise; /** * Open decisions that this store's identity raised, across processes that * share the identity. Fabric rewrites an open record only to move it along an * escalation chain, so the last writer of a non-escalating open record is its * raiser; escalating records are left out. */ listOwnOpen(): Promise; /** CAS open -> answered. Fails when the decision is missing or no longer open. */ answer(id: string, input: DecisionAnswerInput, by: { answeredBy: string; via: string; }, authorize?: DecisionAuthorize): Promise; cancel(id: string, by: { answeredBy: string; via: string; }, authorize?: DecisionAuthorize): Promise; /** CAS the current holder's decision to the next holder in its chain now. */ escalate(id: string, input: { reason?: unknown; }, by: { escalatedBy: string; }, authorize?: DecisionAuthorize): Promise; /** * Resolve when the decision leaves `open` (answer, expiry, cancel) or the * wait times out; a timed-out wait returns the still-open record. */ wait(id: string, options?: { timeoutMs?: number; signal?: AbortSignal; pollMs?: number; }): Promise; } export {}; //# sourceMappingURL=store.d.ts.map