/**
 * design/382 §4.3 / design/389 — the SESSION partition of the permission-rule store: where a
 * `{kind:"session"}` scoped allow rule lives.
 *
 * A session authorization's home is the session's own lifetime — never the durable CRDT partition. The
 * rows are ordinary {@link PersistedRule}s (scope `session`), and the unified store's ONE read
 * query (`PermissionRuleStore.effective({ sessionId })`) splices this partition's rows IN FRONT of the
 * durable partition's (the §4.1 narrowest-first reporting order: session > project > global), so every
 * read-side consumer — the gate's conjunction arm, the coverage table, the consent prepare — takes them
 * through the ONE eligibility predicate with zero second judges. The store's routing writer lands a
 * session-scope `redemption-add` here; the durable partition never sees one.
 *
 * ## The contract (design/382 §8-Q6, settled here)
 *
 * TWO verbs, and deliberately no third:
 *  · `read(sessionId)` — the live rows of ONE session, session-scoped, that session's only.
 *  · `apply(sessionId, add)` — land one redeemed authorization. Idempotent BY DOT (the redemption
 *    replay contract: `alreadyRedeemed` marks the dot as RECORDED, not the overlay as LANDED, so a
 *    replay must RE-APPLY, and this verb is what makes re-applying safe); refuses `session_ended`
 *    once the session's lifetime epoch is sealed — a late in-flight write after termination must not
 *    revive an authorization for a session that no longer exists.
 *
 * There is deliberately NO delete verb: a session row is not individually deletable — it dies with
 * its session (design/382 §10, ruled). Termination is the HOST's act on its own implementation (see
 * {@link InMemorySessionRulePartition.endSession}), not an engine verb.
 *
 * ## Lifecycle and durability
 *
 * The overlay lives WITH the session: a host that parks/checkpoints a session serializes its rows
 * beside it and rehydrates them on resume (`snapshotSession`/`restoreSession` on the reference
 * implementation) — that is how a session authorization survives a park without ever touching the
 * persisted store, and why it still ends when the session ends. `sessionId` uniqueness is the host's
 * duty (the `principal` posture): reusing an id declares "the same session".
 *
 * ## What this is NOT
 *
 * Not a durable backend: no dots are minted here (the redemption leg mints the audit dot exactly as the
 * store leg does), no tombstones exist here, nothing here syncs. Every durable entrance — write
 * deltas, sync in both directions, at-rest bytes — refuses or drops a session row
 * (`permission-rule-store.ts`, the durable two-member face); this module is the OTHER side of that
 * wall, and the wall is the design.
 */
import type { PersistedRule, RuleAdd, RuleBehavior, PersistedRuleMatch, PersistedRuleTool } from "./permission-rule-model.js";
/** One redeemed authorization landing in a session's overlay: the rule's canonical shape plus the
 *  redemption's own add (dot + provenance) — the same fields a `redemption-add` delta carries, minus
 *  the scope (the verb's `sessionId` IS the scope, constructed here so a caller cannot land a row
 *  whose scope names a different session than the one it addressed). */
export interface SessionRuleAdd {
    behavior: RuleBehavior;
    rule: string;
    tool: PersistedRuleTool;
    match: PersistedRuleMatch;
    command: string;
    add: RuleAdd;
}
/** What one overlay apply answered. `session_ended` is the epoch fence speaking: the write arrived at
 *  (or after) termination and landed nothing — the redemption reports the member `refused`. */
export type SessionRuleApplyResult = {
    landed: true;
} | {
    refused: "session_ended";
};
/**
 * The session partition a deployment hands to `createPermissionRuleStoreProvider({ session })`. See the
 * module doc for the contract; {@link InMemorySessionRulePartition} is the reference implementation and
 * the semantics. A backend that keeps a session's rows beside its own session record (a host whose
 * sessions are durable) may implement this over that storage — the law is LIFETIME-bound, not
 * medium-bound: no tombstones, no sync, nothing outlives the session.
 */
export interface SessionRulePartition {
    /** The live session-scoped rows of ONE session. An ended (or never-written) session reads as `[]`. */
    read(sessionId: string): Promise<readonly PersistedRule[]>;
    /** Land one redeemed authorization — idempotent by dot, refused once the session ended. */
    apply(sessionId: string, add: SessionRuleAdd): Promise<SessionRuleApplyResult>;
}
/**
 * The reference overlay — in-memory, per-process, the semantics every host implementation must keep:
 *
 *  · APPLY is idempotent by dot identity (a replayed redemption re-submits its recorded dot and
 *    changes nothing — the store's `foldDelta` discipline, verbatim);
 *  · TERMINATION seals FIRST, clears SECOND ({@link endSession}): the sealed-set membership is the
 *    session's lifetime epoch, flipped atomically before any state is dropped, so an in-flight write
 *    that lost the race lands on the seal and answers `session_ended` — never on a half-cleared
 *    session, and never as a row that outlives its session (design/382 §4.3, the r2-⑥ fence);
 *  · a sealed session never reopens — `apply` and `restoreSession` both refuse it, so "session ended"
 *    is a one-way fact exactly like a quarantined dot's;
 *  · SNAPSHOT/RESTORE ({@link snapshotSession}/{@link restoreSession}) are the park/resume carriage:
 *    the host serializes a session's rows into its checkpoint and rehydrates them on resume. Restore
 *    is fail-closed on shape — every row must be a session row of THE session being restored (a
 *    checkpoint is host-owned bytes, and a global row smuggled through this door would ride the
 *    merge point straight into adjudication).
 */
export declare class InMemorySessionRulePartition implements SessionRulePartition {
    private readonly rows;
    private readonly sealed;
    /** How many times one session's row set has CHANGED. Reading a caller-owned value runs caller code,
     *  so a verb that reads its argument and then replaces a session's rows wholesale must be able to
     *  tell that something landed in between — otherwise it overwrites a grant that was already answered
     *  `landed:true`, and a consent nobody withdrew stops existing. Bumped by every landing, restore and
     *  termination; read across `restoreSession`'s snapshot. */
    private readonly epochs;
    private bumpEpoch;
    read(sessionId: string): Promise<readonly PersistedRule[]>;
    apply(sessionId: string, add: SessionRuleAdd): Promise<SessionRuleApplyResult>;
    /**
     * The termination transfer: SEAL the lifetime epoch first (one atomic membership flip — after this
     * line every in-flight `apply` holding this id answers `session_ended`), THEN drop the rows. The
     * order is the whole fence: clear-then-seal would leave a window in which a late write re-grows a
     * rule set for a session that is already gone. Idempotent; a never-seen id seals to the same place.
     */
    endSession(sessionId: string): void;
    /** The park half of the checkpoint carriage: this session's rows, serializable as-is. */
    snapshotSession(sessionId: string): Promise<readonly PersistedRule[]>;
    /**
     * The resume half. Fail-closed on every axis: a sealed session never rehydrates (termination is
     * one-way), and every row must be a well-formed SESSION row of exactly this session — anything else
     * in the checkpoint bytes is refused whole, loudly, because the merge point trusts this overlay to
     * serve only what its contract says it holds.
     *
     * The rows also pass the SAME `normalizePersistedRule` re-projection the sync face runs on store
     * rows (rule text parses, canonical spelling, stored tool/match/command agree with the text): this
     * door takes host-owned checkpoint bytes with no redemption validator in front of them, and a row
     * the engine could not re-project would otherwise sit one merge away from adjudication. Rows this
     * overlay landed itself always pass — {@link InMemorySessionRulePartition.apply} runs the same screen,
     * so the two doors agree on what a session row is and a snapshot of this overlay always restores —
     * which is what makes a refusal here foreign damage, refused whole.
     */
    restoreSession(sessionId: string, rows: readonly PersistedRule[]): Promise<void>;
}
