import type { RunnerDeps } from "../core/runner-deps.js";
import { type ArtifactVerifyCode, type PromptArtifact, type PublishedPromptArtifact } from "./artifact.js";
/** Why a copy a store holds could not be used: the verifier refused it (its code and reason — a retired schema's reason
 *  names the republish rewrite), or the store could not read it back (`unreadable`, the reason naming the read error). */
export interface StoredArtifactRefusal {
    readonly code: ArtifactVerifyCode | "unreadable";
    readonly reason: string;
}
/** What a read tells its caller when a copy was there and could not be used. */
export type OnArtifactRefused = (refusal: StoredArtifactRefusal) => void;
/** The clause every reader says of a copy that could not be used, by its cause — one wording, wherever it is said. */
export declare function refusalClause(refusal: StoredArtifactRefusal): string;
/**
 * The operator line for a stored center artifact that could not be read back: which copy, why — refused or unreadable
 * (the clause above), or no copy at all — and what follows from it. The one sentence a boot restore and a pinned resume
 * say.
 */
export declare function storedArtifactLine(artifactDigest: string, refusal: StoredArtifactRefusal | undefined, consequence: string): string;
export interface PromptArtifactStore {
    /**
     * Verified read by digest — undefined on a miss OR on a copy that cannot be used. When a copy was there and could not
     * be used — the verifier refused its bytes, or the store could not read them — `onRefused` is told once before the
     * read answers undefined, so a caller can tell a refused or unreadable copy (a retired schema, a corrupt file, a file
     * the process may not read) from a missing one. A store that holds a copy it cannot use calls it.
     */
    get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PublishedPromptArtifact | undefined>;
    /** Write by digest (the caller verified before putting). */
    put(artifact: PublishedPromptArtifact): Promise<void>;
}
export declare class MemoryPromptArtifactStore implements PromptArtifactStore {
    private readonly byDigest;
    get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PublishedPromptArtifact | undefined>;
    put(artifact: PublishedPromptArtifact): Promise<void>;
}
/** `artifacts/<hex>.json` under a caller-owned directory; atomic tmp+rename writes. */
export declare class FilePromptArtifactStore implements PromptArtifactStore {
    private readonly dir;
    constructor(dir: string);
    private fileFor;
    /** A file that is not there is a miss; one that is there and cannot be read (a directory in its place, a file the
     *  process may not open, too many open files) is told to `onRefused` as `unreadable`, by its error code. */
    get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PublishedPromptArtifact | undefined>;
    put(artifact: PublishedPromptArtifact): Promise<void>;
}
export type PromptSourceState = {
    state: "active";
    artifactDigest: string;
    sourceRevision: string;
} | {
    state: "disabled";
    sourceRevision: string;
};
export interface PromptSourceStateStore {
    load(): Promise<PromptSourceState | undefined>;
    save(state: PromptSourceState): Promise<void>;
}
export declare class MemoryPromptSourceStateStore implements PromptSourceStateStore {
    private state;
    load(): Promise<PromptSourceState | undefined>;
    save(state: PromptSourceState): Promise<void>;
}
/** `source-state.json` sibling of the artifact dir; atomic tmp+rename; malformed file = undefined
 *  (stateless boot — conservative: no candidate until the next verified response). */
export declare class FilePromptSourceStateStore implements PromptSourceStateStore {
    private readonly file;
    constructor(dir: string);
    load(): Promise<PromptSourceState | undefined>;
    save(state: PromptSourceState): Promise<void>;
}
/** The narrow face the Runner consumes (`RunnerDeps.promptSource`) — resolution only, no publish. */
export interface PromptArtifactSource {
    /** The current verified candidate new sessions (and every top-level session at a compaction) adopt; undefined = none. */
    current(): PublishedPromptArtifact | undefined;
    /** Resolve a PINNED digest (the resume path). Undefined = unavailable — the caller fails loud. `onRefused` is the
     *  store's (see {@link PromptArtifactStore.get}): told when a copy was there and could not be used, so the caller says
     *  why. */
    get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PromptArtifact | undefined>;
    /** The tri-state every adoption decision keys on: `"active"` = a verified candidate is live; `"disabled"` = an
     *  EXPLICIT verified revocation (`applyDisabled`) — the one state that empties a pinned center layer;
     *  `"unavailable"` = no verified state (never configured, or a store miss at boot) — an outage never strips policy,
     *  only an explicit revocation does. */
    sourceState(): "active" | "disabled" | "unavailable";
}
/**
 * The candidate state machine. Publish-side entry points:
 *   - `applySnapshot(raw)` — a fetched published artifact: verify → store.put → persist active state → atomic
 *     in-memory swap. Any verification failure leaves EVERYTHING unchanged.
 *   - `applyDisabled(sourceRevision)` — an explicit, successful disable/delete response: persist disabled state +
 *     drop the candidate. (Network failure/304 = simply don't call anything.)
 *   - `restore()` — boot: re-resolve the persisted active state through the verified store; a miss, an unreadable copy
 *     or a verify failure boots stateless (no candidate) without touching the persisted record, and says which on
 *     `onError` (a refused copy — a retired schema's reason names the republish rewrite — and an unreadable one are told
 *     apart from no copy at all).
 */
export declare class CenterPromptSource implements PromptArtifactSource {
    private readonly store;
    private readonly stateStore;
    private readonly onError;
    private readonly notifier;
    private candidate;
    private state;
    /** Serialization tail for the three STATE-MUTATING entry points. Each is a multi-await sequence ending in a
     *  synchronous swap of (candidate, state); with two in flight, an interleaving where B's `stateStore.save`
     *  resolves and swaps before A's would leave the persisted record naming B's digest while the in-memory candidate
     *  names A's. `CenterPromptSource` is driven by a caller's poll loop, so overlapping applies are an ordinary
     *  schedule. Serializing costs nothing (publish-rate operations) and makes the durable record and the in-memory
     *  candidate agree by construction. */
    private tail;
    /** Run `fn` after every previously-queued mutation settles (success OR failure — a failed apply must not wedge the queue). */
    private exclusive;
    /** `onError` is the operator channel of the source's own acts (a boot restore that finds its persisted artifact
     *  refused, unreadable or gone) — the Runner's sink, in its shape (`RunnerDeps.onError`): pass the Runner's. A boot
     *  restore belongs to no session: its context is `{ phase: "prompt-constitution", sessionId: "", classification:
     *  "center-source-restore" }`. Omitted = those acts are silent. */
    constructor(opts: {
        store: PromptArtifactStore;
        stateStore?: PromptSourceStateStore;
        onError?: RunnerDeps["onError"];
    });
    current(): PublishedPromptArtifact | undefined;
    get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PromptArtifact | undefined>;
    restore(): Promise<void>;
    sourceState(): "active" | "disabled" | "unavailable";
    applySnapshot(raw: unknown): Promise<{
        ok: true;
        artifactDigest: string;
    } | {
        ok: false;
        code: ArtifactVerifyCode;
        reason: string;
    }>;
    applyDisabled(sourceRevision: string): Promise<void>;
}
