import { type LearningEntry } from "./learnings-contract.js";
import { LearningsBudgetError } from "./learnings-document.js";
/**
 * Derive the overflow path from a project's configured ledger path.
 *
 * Derived rather than separately configurable so a project that relocates its
 * ledger through `learnings.file` cannot end up with the two halves of one
 * mechanism in different directories — and so there is no second config key to
 * validate, contain, and keep in sync.
 * @param learningsFile - Project-relative ledger path
 * @returns Project-relative overflow path
 */
export declare function resolveLearningsOverflowFile(learningsFile: string): string;
/** Entries currently awaiting drain, and where they live. */
export interface LearningsOverflowContents {
    /** Absolute overflow path, whether or not the file exists yet. */
    readonly file: string;
    /** Validated entries awaiting drain. */
    readonly entries: readonly LearningEntry[];
}
/**
 * Read the overflow without modifying it.
 *
 * An absent file is the common, expected case and reads as empty — a project
 * that has never dropped a capture must not have to special-case its absence.
 * @param projectRoot - Absolute path to the host project root
 * @returns Overflow path and the entries awaiting drain
 */
export declare function readLearningsOverflow(projectRoot: string): Promise<LearningsOverflowContents>;
/** Outcome of draining entries the gardener has finished with. */
export interface LearningsOverflowDrain {
    /** Absolute overflow path. */
    readonly file: string;
    /** Ids that were present and have now been removed. */
    readonly drained: readonly string[];
    /** Requested ids that were not in the overflow — reported, never fatal. */
    readonly absent: readonly string[];
    /** How many entries still await drain. */
    readonly remaining: number;
}
/**
 * Remove entries the gardener has durably captured elsewhere.
 *
 * Drain is BY ID and never "empty the file", because the gardener's real
 * sequence is read → file a ticket per entry → drain. Clearing everything up
 * front would lose any entry whose ticket failed to file; removing only the ids
 * that already have a durable home makes a partial run safely resumable.
 *
 * An unknown id is reported rather than thrown, for the same reason an absent
 * supersede target is tolerated: on a re-run, an id another pass already drained
 * is indistinguishable from a bogus one, and failing the drain would strand
 * every other entry in the batch.
 * @param projectRoot - Absolute path to the host project root
 * @param ids - Entry ids to remove
 * @returns Which ids were drained, which were absent, and what remains
 */
export declare function drainLearningsOverflow(projectRoot: string, ids: readonly string[]): Promise<LearningsOverflowDrain>;
/**
 * Preserve a capture the ledger had no budget for, then re-raise the breach.
 *
 * Never returns normally: the capture genuinely did not land in the ledger, and
 * a caller that treated preservation as success would report a learning as
 * persisted when the projection will never serve it. The re-raised error names
 * the overflow file so the drop is actionable rather than merely fatal.
 *
 * If the overflow is itself full, the original ledger breach is re-raised with
 * both surfaces named. Nothing is evicted to make room — silently discarding an
 * older dropped learning to store a newer one is the exact data loss this whole
 * mechanism exists to prevent.
 * @param projectRoot - Absolute path to the host project root
 * @param entry - The validated entry the ledger rejected
 * @param breach - The budget breach the ledger write raised
 * @returns Never — always throws
 */
export declare function preserveDroppedLearning(projectRoot: string, entry: LearningEntry, breach: LearningsBudgetError): Promise<never>;
//# sourceMappingURL=learnings-overflow.d.ts.map