import type { MemoryEntryOrigin } from "./types.js";
export declare const ORIGIN_CLEARANCES_FILE = "origin-clearances.json";
/** One clearance's terminal event (appended, never rewritten). */
export interface OriginClearanceEvent {
    eventId: string;
    at: number;
    to: "done" | "failed";
    /** The resolver of THIS event (the opener on the normal path; a later resumer on a crash path). */
    requestId: string;
    /** Mechanical detail (landing slug, refusal reason) — engine-composed, bounded by the writer. */
    detail?: string;
}
export interface OriginClearanceRow {
    clearanceId: string;
    /** The entry whose marker was cleared. The re-record keeps the SAME id (§2.3-2's later-batch
     *  arm), so this key joins the clearance to the entry across its whole life. */
    entryId: string;
    scope: string;
    slug: string;
    /** The committed rev the clearance was judged against (the tombstone's CAS anchor). */
    baseRev: string;
    /** The cleared marker, verbatim (audit: what the host vouched away). */
    origin: MemoryEntryOrigin;
    /** WHO cleared — the mandatory audit attribution (never defaulted). */
    requestId: string;
    /** WHY — the host's stated ground (never defaulted). */
    reason: string;
    at: number;
    status: "pending" | "done" | "failed";
    /** CUSTODY: the full serialized cleared-entry file text. A crash between the tombstone batch and
     *  the re-record batch leaves this as the only copy — the pending row is the loud recovery seat
     *  (a later clearEntryOrigin call for the same entry resumes from it). */
    entryText: string;
    /** Set the moment THIS clearance's tombstone commits ({@link markOriginClearanceTombstoned}) —
     *  the resume arm's arbiter for an absent entry: with it, absence is the known crash window
     *  (tombstone landed, re-record owed — replay from custody); without it, the absence is an
     *  INDEPENDENT deletion this clearance never made, and replaying the add would silently undo a
     *  deliberate delete. Absent on rows recorded before this member existed — such a row's resume
     *  refuses conservatively (custody stays disclosed on the row; the refusal states it). */
    tombstonedAt?: number;
    events: OriginClearanceEvent[];
}
/**
 * #468② — the ACCOUNT SHADOW a `memory.origin_clear_not_marked` refusal carries when the engine already
 * held the answer: the entry's most recent COMPLETED clearance, as who asked for it and when it settled.
 *
 * It exists to discriminate the refusal's two very different causes without a second full read of the
 * account: an entry that was NEVER marked (no shadow — nothing to clear, and nothing ever cleared) versus a
 * RE-SEND of a clear that already succeeded (shadow present — the caller's own earlier call, or another
 * host's, already did this). Absence is honest absence: the engine never opens an extra read to fill it, so
 * a refusal raised on a path that did not need the ledger simply omits it.
 *
 * `requestId` is the OPENER's attribution (the `clearEntryOrigin` caller's own key — what a re-sending
 * caller compares against), while `settledAt` is the row's terminal `done` event, which on a crash-resumed
 * row is a LATER moment than the opening. The full row (reason, origin, custody, every event) stays one
 * {@link OriginClearanceRow} lookup away — this shadow is a discriminator, never a replacement for it.
 *
 * AS-OF SEMANTICS (codex r3): the account is read ONCE per `clearEntryOrigin` call, by the probe that looks
 * for a resumable pending row, and the committed entry is read after it. A clearance opened AND settled by
 * ANOTHER caller inside that window is therefore not in the snapshot this shadow is derived from, so its
 * absence means "no settled clearance as of this call's own read of the account", never "none exists" — and
 * a fresh call answers with the newer account. The caller's OWN earlier clear (the re-send case this exists
 * for) settled long before and is always in the snapshot. Deliberately not closed by a second read: the
 * shadow is a convenience over the authoritative `listOriginClearances`, and buying strictness with an extra
 * ledger read on a refusal path would cost every caller what only a concurrent third party could observe.
 */
export interface OriginClearanceShadow {
    requestId: string;
    settledAt: number;
}
/** Lock-free strict read of the whole account (host audit face; journal-aware, corrupt = throw). */
export declare function readOriginClearances(controlDir: string): OriginClearanceRow[];
/**
 * WRITE-AHEAD open: append the pending row (custody included) before any store mutation. Refuses a
 * second OPEN while a pending row for the same entry stands — the pending row is a resume seat,
 * not a queue (the caller resumes it instead).
 */
export declare function openOriginClearance(controlDir: string, row: Omit<OriginClearanceRow, "status" | "events">): void;
/**
 * Record that THIS clearance's tombstone leg committed (called between the delete's success and
 * the re-record attempt). The record is what lets a later resume read an ABSENT entry as "the
 * known crash window — replay the add from custody" instead of guessing: absence alone is
 * un-attributable (an independent, deliberate deletion through the ordinary tombstone lane leaves
 * the identical committed state). Idempotent (first write wins); non-pending rows are a no-op
 * (a settled row's history never rewrites).
 */
export declare function markOriginClearanceTombstoned(controlDir: string, input: {
    clearanceId: string;
    now: () => number;
}): void;
/**
 * Terminal event append + status flip. Unknown clearanceId is a corrupt-caller refusal.
 *
 * SINGLE-WINNER terminal: a row already terminal ignores a late contradictory
 * settlement — two concurrent resumers race the store legs (the store's own CAS decides those),
 * and the loser's stale verdict must not overwrite the winner's audit state (a successfully
 * cleared entry reading `failed` with contradictory events). The loser's own thrown refusal is
 * its loud channel; a re-call then answers off the CURRENT committed state.
 *
 * `keepPending: true` appends the event WITHOUT flipping the status: the resume-seat form for a
 * refused re-record leg — the tombstone has committed and the custody row is the ONLY copy of the
 * bytes, so the row must stay resumable (a `failed` flip would strand them: the resume arm only
 * completes pending rows).
 */
export declare function settleOriginClearance(controlDir: string, input: {
    clearanceId: string;
    to: "done" | "failed";
    requestId: string;
    eventId: string;
    now: () => number;
    detail?: string;
    keepPending?: boolean;
}): void;
