import { VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT, VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT } from "../namespaces/vault.crypto.js";
import type { VaultHead, VaultRecoveryReceipt, VaultGenesis } from "../namespaces/vault.types.js";
import type { VaultEncounteredRotation, VaultEpochDecryptFailure, VaultRetainedRefsReconcileResult } from "./vault-publication.js";
import { VaultKeystore, type VaultIdentityFile } from "./vault-keystore.js";
import { type VaultMemberBundleHint, type VaultMemberRecoveryBundle } from "./vault-member-bundle.js";
import type { VaultMirrorBackend } from "./vault-mirror-backend.js";
export interface VaultChainEntry {
    generation: string;
    head: VaultHead;
    head_sha256: string;
}
export interface VaultChainBreak {
    generation: string;
    reason: string;
}
export interface VaultDiscoveryResult {
    repo_id: string;
    genesis: VaultGenesis;
    genesis_sha256: string;
    /** How the genesis was authenticated. `unauthenticated_salvage` is a real, first-class outcome (protocol §5.1 vocabulary) — never silently upgraded to "trusted". */
    pin_trust: "receipt" | "unauthenticated_salvage";
    /** Every fully chain-verified head, genesis excluded, generation 1..N ascending. */
    chain: VaultChainEntry[];
    /** The newest fully-verified generation — `"0000000000000000"` (genesis) when the chain is empty. */
    newest_generation: string;
    newest_head_sha256: string;
    /** Non-null when the walk stopped because a head FAILED verification (a broken chain, not merely "nothing further is mirrored"). Recovery falls back to `newest_generation` either way — this field is what distinguishes an honest fallback from a quiet one. */
    chain_break: VaultChainBreak | null;
    /**
     * Every admitted `rotate_epoch` transition this KEYLESS chain walk saw,
     * oldest first (D193, rev 42 — `checkChainLink`/`assertNoTransition` admit
     * it structurally without ever opening an envelope; recovery's keyed
     * decrypt step, below, is the only place a rotation's envelope is opened).
     */
    rotations: VaultEncounteredRotation[];
}
export interface VaultDiscoverOptions {
    backend: VaultMirrorBackend;
    /** An explicit pin, overriding the keystore's stored receipt. */
    recovery_receipt?: VaultRecoveryReceipt;
    /** Consulted only when `recovery_receipt` is omitted, keyed by the genesis's OWN `repo_id` (read from the mirror first). */
    keystore?: VaultKeystore;
}
/**
 * List `head/`, pin-check the genesis, and walk `prev_sha256` from genesis to
 * the newest generation this mirror both HOLDS and can VERIFY. A signature or
 * chain-link failure at generation K stops the walk at K-1 (`chain_break`
 * names why); a generation simply absent from the mirror also stops the walk
 * there, with `chain_break: null` (nothing further was ever pushed here, or
 * hasn't been synced yet — not evidence of corruption).
 *
 * A PIN MISMATCH is the one hard, no-fallback refusal (`VAULT_CREATION_CONFLICT`):
 * a substituted vault must never be silently accepted at "whatever chain
 * verifies", because a substituted vault's own chain verifies perfectly
 * against ITS OWN (different) creator key.
 */
export declare function discoverAndVerifyChain(options: VaultDiscoverOptions): Promise<VaultDiscoveryResult>;
export interface VaultRequiredObject {
    key: string;
    object_id: string;
    kind: "ref_state" | "retention_roots" | "wal_pack" | "checkpoint_claim_set" | "checkpoint_manifest" | "checkpoint_pack";
}
export interface VaultAbsenceAdjudication {
    object_id: string;
    key: string;
    /** `intentionally_pruned` when a stored `prune_intent` names this object id — never corruption; `unexplained_absence` otherwise — a real loss, named rather than silently skipped. */
    adjudication: "intentionally_pruned" | "unexplained_absence";
    prune_intent_object_id: string | null;
}
/**
 * The required object set for one generation, resolved KEYLESSLY:
 * `checkpoint_claim_set` is plaintext-structured (never encrypted, protocol
 * §4.7) precisely so ITS ordered pack receipts enumerate every checkpoint
 * pack + manifest id without decryption — closure resolution never needs a
 * key. Walks back from `head` to the nearest checkpoint-bearing ancestor (or
 * genesis) collecting each head's own carriers + WAL entries along the way.
 */
export declare function closureForGeneration(backend: VaultMirrorBackend, chain: readonly VaultChainEntry[], targetGeneration: string): Promise<VaultRequiredObject[]>;
/**
 * Check presence of every required object; for each ABSENT one, check the
 * mirror's OWN stored `prune_intent` objects (plaintext-structured, keyless)
 * for a delete-set entry naming it. Never a silent skip: every absence is
 * adjudicated one way or the other, and the caller decides what to do with an
 * `unexplained_absence` (typically: fall back one generation, see {@link
 * recoverWithFallback}).
 */
export declare function adjudicateAbsences(backend: VaultMirrorBackend, required: readonly VaultRequiredObject[]): Promise<VaultAbsenceAdjudication[]>;
export interface VaultRecoveryReport {
    repo_id: string;
    genesis_sha256: string;
    pin_trust: "receipt" | "unauthenticated_salvage";
    /**
     * The generation recovery actually landed on — may be BELOW
     * `chain_verified_to_generation` when either absence fallback (keyless or
     * keyed) OR — Request 4, D193-D203 rev 42 — an epoch this keystore cannot
     * open (`epoch_decrypt_failure`, non-null) capped it first, whichever is
     * more restrictive.
     */
    recovered_generation: string;
    /**
     * The newest generation the PURELY STRUCTURAL chain walk verified,
     * independent of any key material — this is `discoverAndVerifyChain`'s
     * own `newest_generation`, restated here under fsck's own vocabulary so a
     * caller can see, honestly, how far signature verification reached versus
     * how far `recovered_generation` actually materialized.
     */
    chain_verified_to_generation: string;
    /** Non-null iff the chain walk itself broke (see {@link VaultDiscoveryResult.chain_break}). */
    chain_break: VaultChainBreak | null;
    /**
     * Non-null iff an admitted `rotate_epoch` transition capped
     * `recovered_generation` below `chain_verified_to_generation` because this
     * keystore holds no envelope for the new epoch (or the envelope is absent/
     * altered on this mirror) — Request 4's named epoch boundary, never a bare
     * generic absence. Always `null` on {@link VaultVerifyReport} (mode
     * `keyless_verify` never opens a key).
     */
    epoch_decrypt_failure: VaultEpochDecryptFailure | null;
    /** Every absence encountered while resolving closures, across every generation tried, oldest attempt first. */
    absences: VaultAbsenceAdjudication[];
    /** True iff any absence was `unexplained_absence` — the loud, un-missable flag; never buried in a nested field. */
    data_loss_detected: boolean;
    validity_not_freshness: typeof VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT;
    keystore_still_required: typeof VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT;
}
export interface VaultVerifyReport extends VaultRecoveryReport {
    mode: "keyless_verify";
    /** Object kinds present + confirmed reachable for the recovered generation, counted (never bytes, never plaintext). */
    inventory: Record<string, number>;
    /**
     * Member recovery-bundle sidecars found under `member-recovery-bundles/` in
     * this prefix — UNVERIFIED availability hints (vault-recovery-custody):
     * nothing about them is authenticated by the chain; they only tell a human
     * holder "a bundle travels with this mirror, so bundle + source recovery
     * code can recover it with no server." Empty when the prefix carries none.
     */
    member_recovery_bundles: VaultMemberBundleHint[];
}
/**
 * Discovery + chain verification + closure/absence adjudication, WITHOUT
 * touching any key material — `run402 repos fsck --mirror`. Reports the
 * recoverable generation and an inventory; never decrypts, never
 * materializes. A genuinely keyless integrity probe (design D5) — useful as a
 * CI check that never needs a secret.
 */
export declare function verifyVaultMirror(backend: VaultMirrorBackend, options?: {
    recovery_receipt?: VaultRecoveryReceipt;
    keystore?: VaultKeystore;
}): Promise<VaultVerifyReport>;
export interface VaultRecoverResult extends VaultRecoveryReport {
    mode: "recovered";
    out_dir: string;
    refs: Record<string, string>;
    head_target: {
        kind: "symref";
        ref: string;
    } | {
        kind: "detached";
        oid: string;
    };
    /**
     * Non-null iff this recovery decrypted via the human-member path (a member
     * recovery bundle opened with the source recovery code) rather than a
     * keystore — names WHICH bundle sidecar (`bundle_key`, null when supplied
     * directly), which wrapper opened, and the rp_id the context was built
     * with. Faithful: a keystore recovery and a bundle recovery produce the
     * same repository, but the caller can always tell which happened.
     */
    member_recovery: {
        bundle_key: string | null;
        wrapper_id: string;
        rp_id_used: string;
        ek_fingerprint: string;
    } | null;
    /**
     * clone-installs-retained-refs (D2): the same `refs/r402/retain/<oid>`
     * bookkeeping `restoreObjectsInto` (clone/fetch) and `fsck` install, applied
     * here so a recovered bare repo's `git fsck` is silent too — a disaster
     * drill should never see dangling-commit noise for tips this recovery
     * itself just proved are retained. D3: a bookkeeping failure degrades to a
     * `warning` on this field; recovery itself never fails on it.
     */
    retained_refs: VaultRetainedRefsReconcileResult;
    /**
     * `out_dir` is a BARE repository (`git init --bare`) — objects/refs/HEAD
     * directly in `out_dir`, no working files. This is deliberate and matches
     * every other on-disk vault layout; it is named explicitly here (rather
     * than left for the reader to discover via `ls`) because a bare directory
     * with no working tree reads as a failed or empty recovery otherwise
     * (dogfood item 3). See `next_actions` for how to get working files.
     */
    layout: "bare";
    /** `git clone <out_dir> <out_dir>-worktree` — materializes working files from the bare recovery above. */
    next_actions: {
        action: string;
        command: string;
    }[];
}
export interface VaultRecoverOptions {
    backend: VaultMirrorBackend;
    out_dir: string;
    recovery_receipt?: VaultRecoveryReceipt;
    keystore?: VaultKeystore;
    /**
     * vault-recovery-custody — the human-member path: a member recovery
     * bundle (exported wrapper ciphertexts + key identity) opened with
     * `source_recovery_code` substitutes for the keystore's encryption
     * identity. When `source_recovery_code` is supplied WITHOUT a bundle, the
     * mirror's own `member-recovery-bundles/` sidecars are tried; none found
     * is the truthful `RECOVERY_BUNDLE_MISSING` refusal (a server-side
     * wrapper row that was never exported is not an offline backup). The
     * recovery-receipt pin is still required for trusted recovery — key
     * material never substitutes for the trust anchor.
     */
    member_bundle?: VaultMemberRecoveryBundle;
    source_recovery_code?: string;
    /** Seal-time ceremony host for the wrapper context; default = bundle's own `rp_id`, then `console.run402.com`. */
    rp_id?: string;
}
/** The two identity fields recovery actually decrypts with — a keystore's `identity.json` or a member bundle opened by the source recovery code both project onto this. */
export type VaultRecoveryIdentity = Pick<VaultIdentityFile, "encryption_private_key_hex" | "encryption_fingerprint">;
/**
 * Materialize the resolved generation into `out_dir` and run §4.7 restorer
 * acceptance: scratch restore, every covered ref at its EXACT oid, `git fsck`
 * full connectivity, recompute the three keyed commitments against the
 * checkpoint manifest when one covers this generation. Acceptance failure is
 * a typed non-zero exit (throws) — never a partial, silently-accepted repo.
 */
export declare function recoverVaultMirror(options: VaultRecoverOptions): Promise<VaultRecoverResult>;
//# sourceMappingURL=vault-recover.d.ts.map