import { type PathSpec } from '../types.ts';
export type Allowed = (virtual: string) => boolean;
/**
 * A remnant cascade met an entry the session can see.
 *
 * Thrown by `removeRemnants` before the visible entry is touched: the
 * caller's not-empty refusal is then simply true in the session's own
 * view, so every arm answers this by re-raising that original refusal
 * rather than deleting visible data.
 */
export declare class VisibleRemnant extends Error {
    readonly code = "ENOTEMPTY";
    readonly virtual: string;
    readonly virtualPath: string;
    constructor(virtual: string);
}
/**
 * The four ops a remnant cascade speaks, on one plane's own protected
 * channel.
 *
 * The channel carries every protection axis except visibility: a
 * deletion must still answer for its path's mode and rules exactly as
 * a first-class op would (the command plane binds its mode- and
 * rule-guarded slots, the dispatcher routes through its own fenced op
 * call), while the visibility filter stays off because the cascade
 * exists to see and destroy what the session cannot. The cascade never
 * sprinkles those checks itself; wiring a raw, unguarded channel here
 * is the bug this contract exists to prevent.
 */
export interface RemnantChannel {
    readdir(spec: PathSpec): Promise<string[]>;
    stat(spec: PathSpec): Promise<unknown>;
    unlink(spec: PathSpec): Promise<void>;
    rmdir(spec: PathSpec): Promise<void>;
}
/**
 * One listing entry's bare child name. Cold object-store listings mark
 * a directory with a trailing slash, and some backends report whole
 * paths rather than names; both normalize to the last component.
 */
export declare function entryName(entry: string): string;
/**
 * Whether any listed name is visible as a child of `base`.
 *
 * The one emptiness predicate every remnant arm judges with, fed every
 * name source its plane can enumerate (the backend listing, and on the
 * ops plane the namespace's merged children too), so "visibly empty"
 * cannot mean different things at different entry points.
 */
export declare function visibleBelow(base: string, names: Iterable<string>, allowed: Allowed): boolean;
/**
 * Remove one directory and everything under it, children first,
 * revalidating visibility at every step.
 *
 * The walk lists raw, but the moment any entry is visible the whole
 * cascade aborts with `VisibleRemnant` before that entry is touched:
 * between the caller's classification and each deletion another writer
 * may have created something visible, and destroying it would turn an
 * ostensibly empty rmdir into data loss. An entry that vanishes
 * mid-walk is a completed removal (a prefix-store directory disappears
 * with its last child), not an error. Every op goes through the
 * channel, so the plane's other protections refuse exactly as they
 * would a first-class op; the caller answers any cascade failure with
 * its original refusal.
 */
export declare function removeRemnants(channel: RemnantChannel, allowed: Allowed, spec: PathSpec): Promise<void>;
//# sourceMappingURL=remnants.d.ts.map