/**
 * vault — prune (protocol rev 40 §7.3; task 5.12a).
 *
 * The two-phase, ACYCLIC prune the client half owns:
 *
 *   1. plan     — walk the verified chain, compute the GC ROOT SET (what must
 *                 never be deleted) and the pruneable universe, and subtract.
 *   2. attest   — TWO `verifier_receipt`s over the SAME `intent_core_sha256`,
 *                 one per CLOSED implementation identity
 *                 (`run402-cli` | `r402s-verify`). This SDK is `run402-cli`
 *                 and produces exactly ONE of them; the other MUST come from
 *                 `r402s-verify`, which by spec shares no implementation code
 *                 with the SDK — differential verification is the whole point,
 *                 so this module will never synthesize the second receipt.
 *   3. submit   — sign the core, wrap it, sign the wrapper, and POST the
 *                 EXACT BYTES. The gateway reads this route through
 *                 `express.raw` and verifies the owner signature over the
 *                 bytes as sent, so a re-serialized object is a different
 *                 object. {@link pruneIntentBytes} is the one serializer.
 *   4. confirm  — poll the intent until its control-plane-signed
 *                 `prune_completion` appears, then believe ONLY that: per-object
 *                 outcomes are THREE-VALUED (`deleted` | `present_not_attempted`
 *                 | `present_after_attempt`) and only `deleted` means the bytes
 *                 are gone. `present_after_attempt` is NOT a deletion.
 *
 * What this module deliberately does NOT do:
 *   - decide retention eligibility. The ≥90-day schedule is measured against a
 *     control-plane-signed `retention_cutoff` ticket and the server's own
 *     admission times; a client cannot prove either. The plan is a PROPOSAL and
 *     the gateway is the authority — it refuses any candidate that is not
 *     retention-eligible against the bound ticket.
 *   - attest anything it did not check. A receipt this module builds carries
 *     `result: "failed"` (and both booleans as observed) whenever the chain
 *     cannot prove the property, rather than a convenient `true`.
 */
import { VAULT_FORMAT, VAULT_SUITE } from "../namespaces/vault.crypto.js";
import type { VaultCheckpointClaimSet, VaultCheckpointManifestReceipt, VaultCheckpointPackReceipt, VaultCheckpointClaimSetReceipt, VaultHead, VaultRefStateReceipt, VaultRetentionRootsReceipt, VaultWalPackReceipt } from "../namespaces/vault.types.js";
/** §7.3: at most 10 000 candidates per intent; larger prunes chunk into successive intents. */
export declare const VAULT_MAX_PRUNE_CANDIDATES = 10000;
/** The CLOSED V0 verifier identity set (`common.json#/$defs/implementation_id`). */
export declare const VAULT_VERIFIER_IMPLEMENTATIONS: readonly ["run402-cli", "r402s-verify"];
export type VaultVerifierImplementation = (typeof VAULT_VERIFIER_IMPLEMENTATIONS)[number];
/** This SDK's identity when it attests. The other half of the pair is never ours to produce. */
export declare const VAULT_SDK_VERIFIER_IMPLEMENTATION: VaultVerifierImplementation;
/**
 * What this lineage calls itself in a receipt's `implementation_version`.
 *
 * The LINEAGE and the PROTOCOL REVISION, not the npm version: a receipt records
 * which verifier produced it against which frozen wire, and the npm number
 * moves for reasons that have nothing to do with either. Bump this when the
 * verification logic or the revision it verifies changes.
 */
export declare const VAULT_SDK_VERIFIER_VERSION = "run402-sdk/r402s-v0-rev40";
/** `common.json#/$defs/receipt_pruneable` — the CLOSED union a delete set may name. */
export type VaultPruneableReceipt = VaultWalPackReceipt | VaultRefStateReceipt | VaultRetentionRootsReceipt | VaultCheckpointManifestReceipt | VaultCheckpointPackReceipt | VaultCheckpointClaimSetReceipt;
/** One verified chain link plus its resolved checkpoint claim set (null when the head bears no checkpoint). */
export interface VaultChainEntry {
    head: VaultHead;
    head_sha256: string;
    claim_set: VaultCheckpointClaimSet | null;
}
/** `common.json#/$defs/verifier_receipt_ref` — what the intent carries, not the receipt itself. */
export interface VaultVerifierReceiptRef {
    object_id: string;
    object_kind: "verifier_receipt";
    stored_bytes_sha256: string;
    size_bytes: string;
    implementation_id: VaultVerifierImplementation;
}
/** `verifier_receipt.json` — owner-signed, uploaded, then claimed at the intent's fence. */
export interface VaultVerifierReceipt {
    format: typeof VAULT_FORMAT;
    object_kind: "verifier_receipt";
    suite: typeof VAULT_SUITE;
    repo_id: string;
    object_id: string;
    intent_core_sha256: string;
    checkpoint_head_sha256: string;
    cutoff_ticket_sha256: string | null;
    restored_object_set_hmac: string;
    retention_evolution_ok: boolean;
    candidates_outside_roots_ok: boolean;
    implementation_id: VaultVerifierImplementation;
    implementation_version: string;
    result: "restored_and_verified" | "failed";
    signature: string;
}
/** `prune_intent_core.json` — owner-signed; the acyclic base BOTH receipts sign. */
export interface VaultPruneIntentCore {
    format: typeof VAULT_FORMAT;
    object_kind: "prune_intent_core";
    suite: typeof VAULT_SUITE;
    repo_id: string;
    object_id: string;
    gc_epoch: string;
    maintenance_cycle_id: string | null;
    maintenance_prune_role: "intermediate" | "final" | null;
    stage_claim_set_sha256: string | null;
    batch_index: string | null;
    batch_count: string | null;
    authorizing_head_sha256: string;
    checkpoint_claim_set_sha256: string;
    gc_root_set_hmac: string;
    retention_state_hmac: string;
    delete_set: VaultPruneableReceipt[];
    nonce: string;
    signature: string;
}
/** `prune_intent.json` — the wrapper the gateway publishes create-only under `prune/`. */
export interface VaultPruneIntent {
    format: typeof VAULT_FORMAT;
    object_kind: "prune_intent";
    suite: typeof VAULT_SUITE;
    repo_id: string;
    object_id: string;
    core: VaultPruneIntentCore;
    intent_core_sha256: string;
    verifier_receipts: VaultVerifierReceiptRef[];
    signature: string;
}
/** One entry of the completion's three-valued vector. */
export interface VaultPruneOutcome {
    object_id: string;
    result: "deleted" | "present_not_attempted" | "present_after_attempt";
}
/** `GET …/prune-intents/:id` — the gateway's secret-free public view (`toPublicIntent`). */
export interface VaultPruneIntentRecord {
    object_id: string;
    repo_id: string;
    state: string;
    gc_epoch: string;
    intent_sha256: string | null;
    intent_core_sha256: string | null;
    candidate_count: number;
    next_candidate_index: number;
    maintenance_cycle_id: string | null;
    maintenance_prune_role: string | null;
    stage_claim_set_sha256: string | null;
    batch_index: number | null;
    batch_count: number | null;
    completion: {
        object_id: string | null;
        sha256: string | null;
        per_object: VaultPruneOutcome[] | null;
        deleted_count: number;
        present_after_attempt_count: number;
        present_not_attempted_count: number;
        gc_epoch_at_completion: string;
        cycle_event_seq: string | null;
        completed_at: string | null;
    } | null;
    prepared_at: string | null;
    intent_put_issued_at: string | null;
    intent_stored_at: string | null;
    deleting_started_at: string | null;
}
/**
 * A checkpoint's FULL RECOVERY BUNDLE: the claim set, the manifest, every pack,
 * AND its `covers_through` head's `ref_state` + `retention_roots` carriers.
 * A bundle missing its carriers is not a recovery path, so the carriers are
 * part of the protection, not adjacent to it.
 */
export declare function checkpointRecoveryBundle(entry: VaultChainEntry): VaultPruneableReceipt[];
/** Every pruneable object the chain has ever named, sorted by `object_id`, deduplicated. */
export declare function collectPruneUniverse(entries: readonly VaultChainEntry[]): VaultPruneableReceipt[];
/** Pairwise-distinct, sorted by `object_id` — the schema's canonical order, not an incidental one. */
export declare function sortPruneReceipts(receipts: readonly VaultPruneableReceipt[]): VaultPruneableReceipt[];
export interface VaultGcRootSet {
    /** The protected receipts, sorted — the `gcrootset` commitment's preimage content. */
    receipts: VaultPruneableReceipt[];
    /** The newest checkpoint-bearing entry, or `null` when the chain has none. */
    latest_checkpoint: VaultChainEntry | null;
    /** The one before it, or `null`. */
    prior_checkpoint: VaultChainEntry | null;
    /**
     * Why nothing may be pruned yet, or `null` when a prune is structurally
     * possible. Stated rather than left to be inferred from an empty candidate
     * list, which would read as "already clean".
     */
    blocked_reason: string | null;
}
/**
 * The GC root set: the latest checkpoint's recovery bundle + its WAL suffix +
 * the immediately-prior checkpoint's recovery bundle + every carrier at or
 * after the prior checkpoint.
 *
 * DELIBERATELY conservative in two places, because under-protecting deletes
 * history and over-protecting only costs storage:
 *
 *   - with FEWER THAN TWO checkpoints nothing is prunable at all. The
 *     protection rule exists so a bad latest checkpoint still has a second
 *     recovery path; with a single checkpoint that second path IS the
 *     pre-checkpoint WAL chain, so pruning it would leave exactly one.
 *   - every `ref_state` / `retention_roots` carrier at or after the PRIOR
 *     checkpoint is protected, not just the unexpired-root carriers. Root
 *     expiry is measured against a server-signed ticket this client cannot
 *     evaluate, so it never guesses a carrier is dead.
 */
export declare function computeGcRootSet(entries: readonly VaultChainEntry[]): VaultGcRootSet;
export interface VaultPrunePlan {
    /** Candidates in canonical order, capped at {@link VAULT_MAX_PRUNE_CANDIDATES}. */
    candidates: VaultPruneableReceipt[];
    /** How many pruneable objects were left out by the per-intent cap (chunk into a later intent). */
    deferred_count: number;
    root_set: VaultGcRootSet;
    universe_count: number;
}
/** universe − GC root set, canonical order, capped. Never mutates its inputs. */
export declare function planPruneCandidates(entries: readonly VaultChainEntry[]): VaultPrunePlan;
export interface VaultRetentionEvolutionCheck {
    ok: boolean;
    /** Every departure this client could not justify from the chain alone. */
    unproven: Array<{
        generation: string;
        ref: string;
        oid: string;
        reason: string;
    }>;
}
/**
 * Verify that every retention root which LEFT the map left legally: only at a
 * checkpoint-bearing generation carrying a cutoff ticket, and only when its
 * `effective_admitted_at + retentionDays < cutoff_at` strictly.
 *
 * `effectiveAdmittedAt` returning `null` is not a failure of the vault — it is
 * a failure of THIS CLIENT to prove the departure, and the check reports `ok:
 * false` so the receipt attests `false` rather than a convenient `true`.
 */
export declare function checkRetentionEvolution(entries: readonly VaultChainEntry[], roots: (entry: VaultChainEntry) => Array<{
    ref: string;
    oid: string;
    dropped_at_generation: string;
}>, effectiveAdmittedAt: (droppedAtGeneration: string) => string | null, isEligible: (effectiveAdmittedAtIso: string, cutoffAtIso: string) => boolean): VaultRetentionEvolutionCheck;
export interface VaultBuildPruneCoreInput {
    repo_id: string;
    gc_epoch: string;
    authorizing_head_sha256: string;
    checkpoint_claim_set_sha256: string;
    gc_root_set_hmac: string;
    retention_state_hmac: string;
    delete_set: readonly VaultPruneableReceipt[];
    /** All five cycle fields are non-null together iff the prune advances a maintenance cycle (§7.2). */
    cycle?: {
        maintenance_cycle_id: string;
        maintenance_prune_role: "intermediate" | "final";
        stage_claim_set_sha256: string;
        batch_index: string;
        batch_count: string;
    } | null;
    object_id?: string;
    nonce?: string;
}
/**
 * Build + sign `prune_intent_core`. The core is signed on its own AND embedded
 * in a signed wrapper (the double signature of §7.3) — `intent_core_sha256` is
 * the stored-bytes hash of the COMPLETE signed core, which is why the core must
 * be finished before either verifier can attest anything about it.
 */
export declare function buildPruneIntentCore(input: VaultBuildPruneCoreInput, signingSeed: Uint8Array): VaultPruneIntentCore;
/** The stored-bytes hash of the complete signed core — what BOTH verifier receipts sign. */
export declare function pruneIntentCoreSha256(core: VaultPruneIntentCore): string;
export interface VaultBuildVerifierReceiptInput {
    repo_id: string;
    intent_core_sha256: string;
    checkpoint_head_sha256: string;
    cutoff_ticket_sha256: string | null;
    restored_object_set_hmac: string;
    retention_evolution_ok: boolean;
    candidates_outside_roots_ok: boolean;
    implementation_id: VaultVerifierImplementation;
    implementation_version: string;
    object_id?: string;
}
/**
 * Build + sign a `verifier_receipt`.
 *
 * `result` is DERIVED, never passed in: a receipt is `restored_and_verified`
 * exactly when both attestation booleans are true, and `failed` otherwise. A
 * caller cannot hand this function `failed` booleans and a passing result.
 */
export declare function buildVerifierReceipt(input: VaultBuildVerifierReceiptInput, signingSeed: Uint8Array): VaultVerifierReceipt;
/** The `verifier_receipt_ref` an intent carries for an uploaded receipt. */
export declare function verifierReceiptRef(receipt: VaultVerifierReceipt): VaultVerifierReceiptRef;
/**
 * Wrap + sign the intent.
 *
 * Every gate the gateway applies to the pair is applied here first, so a
 * malformed pair never reaches the wire as a wasted round trip: exactly two
 * refs, one per CLOSED implementation identity, distinct ids AND distinct
 * hashes, each attesting `restored_and_verified` with both booleans true, and
 * each signing THIS core.
 */
export declare function buildPruneIntent(core: VaultPruneIntentCore, receipts: readonly VaultVerifierReceipt[], signingSeed: Uint8Array): VaultPruneIntent;
/**
 * Refuse a supplied core that the chain has moved past — BEFORE the receipts
 * are uploaded.
 *
 * A prune is planned, verified out-of-band by a second implementation, and only
 * then submitted, so there is a real window in which a push or a compaction
 * lands underneath it. The gateway would refuse such an intent at its fence,
 * but by then both receipts are stored objects the fence CLAIMS, so a stale
 * submission burns evidence for nothing. Same registry codes the gateway uses,
 * raised one step earlier.
 */
export declare function assertPruneCoreStillCurrent(core: VaultPruneIntentCore, current: {
    repo_id: string;
    gc_epoch: string;
    checkpoint_claim_set_sha256: string;
}): void;
/**
 * THE serializer for the submit route.
 *
 * `POST …/prune-intents` is parsed with `express.raw`: the service strict-parses
 * these bytes and verifies the owner signature over them. Anything that
 * re-serializes the object between here and the socket — a JSON body helper, a
 * proxy that reformats — changes what was signed. Send exactly this.
 */
export declare function pruneIntentBytes(intent: VaultPruneIntent): Uint8Array;
export interface VaultPruneConfirmation {
    /** `null` until the control-plane-signed completion exists. */
    outcome: "completed" | "superseded_no_delete" | "superseded_partial_delete" | null;
    /** Object ids the completion confirms are GONE. Only `deleted` qualifies. */
    deleted: string[];
    /** Still present — attempted or not. Never reported as removed. */
    present: VaultPruneOutcome[];
    /** Candidates the completion did not adjudicate at all (a defect; reported, never assumed deleted). */
    unadjudicated: string[];
}
/**
 * Read the completion's three-valued vector against the intent's canonical
 * candidate order.
 *
 * The one rule this function exists to enforce: **only `deleted` means gone.**
 * `present_after_attempt` looks like a deletion in the logs and is not one —
 * treating it as one is how a client reports history removed that is still
 * there. A candidate with no entry is `unadjudicated`, never inferred.
 */
export declare function summarizePruneCompletion(candidateIds: readonly string[], record: VaultPruneIntentRecord | null): VaultPruneConfirmation;
/** Run `fn` in a fresh temp directory and always remove it, even on refusal. */
export declare function withScratchDir<T>(prefix: string, fn: (dir: string) => Promise<T>): Promise<T>;
//# sourceMappingURL=vault-prune.d.ts.map