/**
 * E2 decision first-class object (docs/plans/2026-05-28-e2-decision-object.md).
 *
 * `hippo decide` used to write only a tagged memory (tags ['decision'], source
 * 'decision') with a 90-day half-life, so an in-force decision decayed out of
 * recall even though it was never reversed. The `decisions` table is now the
 * source of truth: a decision stays `active` regardless of memory decay, and
 * `hippo decide list --status active` is authoritative. A memory row still
 * mirrors the decision for recall surfaces but is NOT canonical — memory_id is
 * NULLABLE with ON DELETE SET NULL so forget/consolidate/archive gracefully
 * orphans the decision row.
 *
 * Lifecycle: active -> superseded (a newer decision replaces it; superseded_by
 * points to the successor) or active -> closed (retired with no successor).
 *
 * Tenant scoping: every helper requires tenantId. BEFORE INSERT/UPDATE triggers
 * enforce decisions.tenant_id == the referenced memory's tenant_id, and a
 * superseded_by same-tenant trigger makes cross-tenant supersession
 * unrepresentable. Mirrors the v0.31 predictions pattern (src/predictions.ts).
 *
 * Dual-write atomicity: `saveDecision` writes the memory + decisions row (and,
 * when superseding, the old row's UPDATE) inside writeEntry's SAVEPOINT
 * 'write_entry' (store.ts:1196) via the afterWrite hook, so a failure in any
 * step rolls all of them back. Pattern matches savePrediction (predictions.ts).
 */
export type DecisionStatus = 'active' | 'superseded' | 'closed';
export declare const VALID_DECISION_STATES: ReadonlySet<DecisionStatus>;
export interface Decision {
    id: number;
    /** Nullable: ON DELETE SET NULL lets memory deletion (forget / consolidate /
     *  archive) proceed without breaking the decision row. */
    memoryId: string | null;
    tenantId: string;
    decisionText: string;
    context: string | null;
    status: DecisionStatus;
    /** Successor decision id; set only when status === 'superseded'. */
    supersededBy: number | null;
    supersededAt: string | null;
    closedAt: string | null;
    createdAt: string;
}
export interface SaveDecisionOpts {
    decisionText: string;
    context?: string;
    /** Table id of an ACTIVE decision this one supersedes. The CLI resolves it
     *  from a `--supersedes <memory-id>` via resolveActiveDecisionIdByMemory;
     *  HTTP/SDK pass the table id directly. */
    supersedesDecisionId?: number;
    /** Extra memory tags merged after ['decision'] (the CLI passes path-context
     *  tags; HTTP/SDK pass none). */
    extraTags?: string[];
}
export interface ListDecisionsOpts {
    status?: DecisionStatus;
    limit?: number;
}
/**
 * Create a decision. Writes the memory mirror + the decisions row atomically
 * inside writeEntry's SAVEPOINT 'write_entry'. When supersedesDecisionId is
 * given, the referenced ACTIVE row is UPDATEd -> superseded in the SAME
 * SAVEPOINT (CAS: WHERE status='active'; throws on changes===0 so a duplicate
 * supersede aborts the whole write rather than orphaning a successor).
 *
 * The memory mirror preserves the legacy `hippo decide` shape: tags
 * ['decision', ...extraTags], source 'decision', confidence 'verified',
 * half_life DECISION_HALF_LIFE_DAYS, content = "<text>\n\nContext: <context>"
 * when context is given (so existing recall output is unchanged).
 */
export declare function saveDecision(hippoRoot: string, tenantId: string, opts: SaveDecisionOpts, actor?: string): Decision;
/**
 * Close (retire) an active decision with no successor. Updates the decisions
 * row only; the memory mirror is not mutated. CAS guard mirrors closePrediction
 * (predictions.ts): WHERE status='active'; 0 changes distinguishes not-found
 * from not-active so callers surface the right error.
 */
export declare function closeDecision(hippoRoot: string, tenantId: string, id: number, actor?: string): Decision;
export declare function loadDecisionById(hippoRoot: string, tenantId: string, id: number): Decision | null;
export declare function loadDecisions(hippoRoot: string, tenantId: string, opts?: ListDecisionsOpts): Decision[];
export declare function loadActiveDecisions(hippoRoot: string, tenantId: string, opts?: {
    limit?: number;
}): Decision[];
/**
 * Resolve a `--supersedes <memory-id>` (the legacy CLI contract) to the table id
 * of the ACTIVE decision backed by that memory, or null when the memory has no
 * active decision row (a legacy pre-episode decision-tagged memory). Extracted
 * so the CLI's backward-compat path is unit-testable at the store layer without
 * exporting cmdDecide.
 */
export declare function resolveActiveDecisionIdByMemory(hippoRoot: string, tenantId: string, memoryId: string): number | null;
//# sourceMappingURL=decisions.d.ts.map