import { type FileCacheMixin } from '../../cache/file/mixin.ts';
import { type CallerDispatchFn } from '../../context/session_context.ts';
import type { LostPaths, OpRecord } from '../../observe/record.ts';
import type { Decisions } from '../../policy/decisions.ts';
import { Policies } from '../../policy/index.ts';
import { type CacheFacts } from '../../types.ts';
import type { BaseVFS } from '../../vfs/base.ts';
import type { SessionAccess } from '../../view/types.ts';
import type { Namespace } from '../mount/namespace/namespace.ts';
import { Reconciler } from '../reconcile.ts';
import type { DriftQueue } from '../snapshot/drift.ts';
/** Runs a write once the workspace admits it. */
type AdmitWrite = <T>(write: () => Promise<T>) => Promise<T>;
export declare class Dispatcher {
    private readonly namespace;
    private readonly cache;
    private readonly policies;
    private readonly drift;
    private readonly admitWrite;
    private readonly decisions;
    private access;
    private caller;
    private state;
    private static readonly stores;
    private static storeCount;
    readonly reconciler: Reconciler;
    constructor(namespace: Namespace, cache: FileCacheMixin & BaseVFS, policies?: Policies, drift?: DriftQueue, admitWrite?: AdmitWrite, decisions?: Decisions);
    forSession(session: SessionAccess | null): Dispatcher;
    /**
     * This dispatcher run as `caller`: its checks read that caller's
     * session, line, dry run and call, not the async context's. A session
     * a `forSession` view already bound stays its own. Mirrors Python's
     * `caller` keyword on Dispatcher.dispatch.
     */
    private forCaller;
    private sessionId;
    /** The dry run the op is part of: the caller's, else the async context's. */
    private explaining;
    /**
     * The namespace's own answer for a path no backend serves.
     *
     * Child mounts and symlinks are structure the dispatcher owns, so a
     * directory that exists only because a mount or link sits below it
     * still lists and stats. Null for any other op, or when the
     * namespace knows nothing at `virtual`.
     */
    private namespaceResult;
    dispatch: CallerDispatchFn;
    /** The observation owner known before this call can suspend. */
    private readCaller;
    private dispatchAdmitted;
    /** Publish only this admitted read's records for its captured caller. */
    private observeReads;
    /** Publish delivered chunks and normal empty completion, retaining stream cleanup. */
    private observeStream;
    /**
     * A read that refuses a directory with GNU's EISDIR, at the path it was
     * handed.
     *
     * A store answers a read of a directory in its own voice: ENOENT from a
     * keyed store, whose directory is a set of keys rather than an object, an
     * opaque error from sftp, no bytes from some drivers. So a read that fails
     * or answers no bytes asks whether its path is a directory (`readHitADir`),
     * and any other answer stands. A stream is judged as it is pulled; a live
     * pipe is no directory. Mirrors Python's Dispatcher._read_refusing_dirs.
     */
    private readRefusingDirs;
    /**
     * A streamed read that refuses a directory once it fails or ends with no
     * bytes. Run to its empty first step before it is handed on, as `primed`
     * runs a stream, so a caller that closes it before pulling still closes the
     * read. Mirrors Python's Dispatcher._drain_refusing_dirs.
     */
    private drainRefusingDirs;
    /**
     * Whether a read of `path` that failed or answered no bytes reached a
     * directory, probed as this dispatcher's caller. The probes are the
     * dispatcher's own, no call of the command's, so its path rules do not
     * judge them; the caller's hides do. A policy's refusal is the dispatcher's
     * own answer rather than a store's, so it stands, and a dry run asks the
     * gates only, so it probes nothing. Mirrors Python's
     * Dispatcher._read_hit_a_dir.
     */
    private readHitADir;
    /** The entry at `path` itself, as lstat answers; throws when nothing is there. */
    private lstat;
    /** The entries of the directory at `path`. */
    private listing;
    /**
     * Whether the file cache holds a copy of the call's path, asked of the store
     * without fetching the bytes or checking the copy against the backend: a
     * read of a held file is checked as it is served. Mirrors Python's
     * Dispatcher._held.
     */
    private held;
    /**
     * Rank several scopes as one query, as a store's `searchMany` does. One
     * call answers for them all where one mount serves every scope and its VFS
     * ranks a batch, past the same checks each scope's own search meets: each
     * is walked and followed, a path rule or a coded preVfs policy reaching
     * below any of them declines the batch (null), and every hit the session
     * hides is dropped. Otherwise, and while a postVfs policy speaks for the
     * session (it judges each scope's answer on its own), each scope is
     * searched on its own and the hits joined in scope order. Mirrors Python's
     * Dispatcher._search_together.
     */
    private searchTogether;
    /**
     * Keep the small files `typed` names in the read cache, for the reads a
     * command is about to make of them; nothing is answered. Each read that
     * follows still meets every check of its own and is served what this kept,
     * so nothing is fetched where a check could refuse that read before its
     * backend is asked: nothing in a dry run or while a coded preVfs policy
     * speaks for the session (the rule a one-call walk meets in `declines`),
     * and no path the session hides or a path rule reaches. A file already
     * kept, one a renderer answers, one pinned to a revision and one on a mount
     * that keeps no reads or holds its data locally (read as fast when asked)
     * is passed over. A store that reads a batch
     * (`readMany`) is asked once for the rest of its files; any other is asked
     * for each file its listing sizes within READ_AHEAD_BYTES. A failure is
     * logged and dropped: the read that follows meets it itself. Mirrors
     * Python's Dispatcher._read_many.
     */
    private readMany;
    /**
     * Load the namespace and run what a snapshot restore left owed.
     *
     * Pending fingerprint checks from a strict snapshot restore run before
     * the op can touch a mount, whichever surface called: FUSE and `ws.vfs`
     * come straight here, so a drain that lived any higher would let a
     * first write clobber drifted state. drain() clears pending before it
     * stats, so its own probes cannot recurse into it. A dry run leaves them
     * pending, its policies' reads included: the check is no policy's
     * answer, and the op that does run still owes it. Mirrors Python's
     * Dispatcher._prepare.
     */
    private prepare;
    /**
     * Walk the op's path, as the kernel does before a call sees it.
     *
     * Hidden paths answer before anything else can: the typed path is
     * checked so a link inside hidden space cannot be followed out of it,
     * the followed path is re-checked (`follow`) so a visible link cannot
     * lead in, and a rename's or a copy's destination is a create. Every link
     * above the
     * final name is then followed, whatever the op does with the name:
     * command dispatch walks the operands it classifies, and this is the
     * same walk for every other caller (a relative word ln resolves itself,
     * `ws.vfs`, a runtime's os.symlink), so a link made, read or
     * removed under a linked directory lands in the directory the link
     * names. Mirrors Python's Dispatcher._walk.
     */
    private walk;
    /**
     * Refuse a rename the namespace forbids before any backend runs.
     *
     * A rename re-anchors everything below its source while the hides stay
     * where they are written, so hidden content would land at paths the
     * session can see. Destroying hidden content is silent (rmR, the remnant
     * rmdir); relocating it into view is refused. Only a directory has
     * anything below it to re-anchor, so a file source passes. rename(2)
     * also replaces a destination directory only when it is empty, and the
     * node table is half of what empty means here: a link is invisible to
     * every backend, so a destination the backend reads as empty can still
     * hold one. Left to the backend the rename succeeded and the purge then
     * deleted the link with it, losing namespace state silently where POSIX
     * promises ENOTEMPTY. Mirrors Python's Dispatcher._refuse_rename.
     */
    private refuseRename;
    /**
     * Follow the final name, unless the op acts on the name itself.
     *
     * `nofollow` is the caller's AT_SYMLINK_NOFOLLOW: an op that acts on a
     * link entry itself (chown -h writing the link's own attrs) keeps the
     * typed path. Consumed here, never forwarded. A copy writes its
     * destination as a write does, through a link at the final name; a
     * rename moves the name itself. A copy whose two ends then name one file
     * is refused: a backend that replaces its destination would delete the
     * source first. Mirrors Python's Dispatcher._follow.
     */
    private follow;
    /**
     * Walk and follow each other path argument the way the path is: the same
     * hides, spelling checks and rule gate apply, and the followed spelling
     * replaces it. Mirrors Python's Dispatcher._walk_operands.
     */
    private walkOperands;
    /**
     * The mount a copy's destination is on, when that is another mount whose
     * store may copy from this one's; null otherwise. Mirrors Python's
     * Dispatcher._copy_target.
     */
    private copyTarget;
    /**
     * Copy a file onto another mount, store to store.
     *
     * Admission judged the source as a read and the destination as a create
     * under its own mount's mode, as for a copy within one mount. The
     * destination's store copies from the source's where it can (one bucket to
     * another under one set of credentials); otherwise it answers EXDEV, as a
     * copy between two mounts always did, and the caller moves the bytes
     * itself. The destination's name is held, and its caches settled, on its
     * own mount; a copy past its timeout keeps the name until the store
     * answers. Mirrors Python's Dispatcher._copy_across.
     */
    private copyAcross;
    /**
     * Answer EXDEV for a rename or a copy between two mounts.
     *
     * A mount is a filesystem boundary: rename(2) moves a name within one and
     * answers EXDEV across two, before any permission is weighed, so `mv`
     * falls back to copy and unlink instead of the source's backend taking
     * the destination for one of its keys; a backend copies only within
     * itself, the same way. It resolves both parent directories first, so a
     * missing one is ENOENT (ENOTDIR through a file) ahead of EXDEV. Mirrors
     * Python's Dispatcher._refuse_cross_mount.
     */
    private refuseCrossMount;
    /**
     * Whether a one-call walk gives way to the caller's own walk.
     *
     * A backend's find, du, search, tree copy or tree removal answers for
     * every entry under its path in one call, past the checks each entry would
     * meet on its own. Path rules and file policies decline that shortcut so
     * the caller walks through calls that are each judged, including inside
     * commands. A path rule declines no `files_containing` on its own: its
     * answer only rules files out of a walk that still
     * lists every one, and each file it rules out meets the rule as a warm read,
     * so one the rule refuses reports `Permission denied` as its read would. A
     * hide declines the copies and the removal, which would reach hidden
     * entries; a read in HIDE_FILTERED_OPS
     * runs and `filter` drops what the session hides from its answer. A file
     * copy is declined the same way: the bytes it moves never pass through a
     * read. A tree copy is declined too when a link stands below its
     * destination: the backend writes each child name as it is, where the
     * walk's copies follow the link. Mirrors Python's Dispatcher._declines.
     */
    private declines;
    /**
     * Run admission for an op on a mounted path.
     *
     * Admission policies fire at the dispatcher, before the warm-cache early
     * return: a cached read must be refused exactly like a cold one, or the
     * cache becomes a policy bypass. This dispatcher is the one dispatcher in
     * TypeScript: shell internals, programmatic access, `ws.vfs`, and
     * FUSE all end up here. A rename's or a copy's destination is a create
     * there: it passes the same gate as the source, so a path rule holds
     * against moving or copying into a protected scope (or onto the directory
     * that holds one) the way it holds against writing there, under the mode
     * of the mount that owns it. A copy only reads its source. Mirrors
     * Python's Dispatcher._admit.
     */
    private admit;
    /**
     * Answer an op on a path no mount serves.
     *
     * The namespace may still know a directory there (a deeper mount, a
     * link). No mount means no cache to keep straight and no owning prefix
     * (the gates see ''), but admission still fires: a policy that bounds
     * readdir or stat by path must cover the synthetic answer too. A real but
     * ungranted mount is the same case: a granted mount below it already put
     * this path's name in a listing, so walking down to the grant must
     * answer, and the merged names are session-filtered individually, so
     * nothing of the mount's own content leaks. A setattr with no owning
     * mount lands in the overlay (a link above every mount still takes
     * chown -h), gated exactly like the mounted overlay write; an ungranted
     * mount is not that case and keeps the canonical denial. Mirrors Python's
     * Dispatcher._answer_unmounted.
     */
    private answerUnmounted;
    /**
     * Whether a read is answered as it is pulled. A whole read of stored bytes
     * streams as the VFS's `read` answers it, a stream as it is pulled and bytes
     * as one chunk. A window, a rendering, a VFS with no `read` of its own and a
     * postVfs policy that may read the result each get the whole bytes instead,
     * which are a stream of one chunk, including inside commands and runtimes. Mirrors
     * Python's Dispatcher._streams.
     */
    private streams;
    /**
     * Open a streamed read, its first chunk pulled before it returns. A cold
     * read fills the cache as it is pulled. A live pipe's read is neither
     * pulled nor cached: it answers as a `PipeStream`. Mirrors Python's
     * Dispatcher._open_stream.
     */
    private openStream;
    /** Whether a filetype renderer answers this read on `vfs`; asked each
     * time, since a renderer can land while the read runs. */
    private rendersRead;
    /**
     * Judge bytes or a row its caller already holds, as a cache hit. A runtime
     * descriptor and a kernel mount's handle keep what they fetched; each later
     * read or stat of it meets the hides, the rules and the file policies in
     * force now, through the boundary a fetch and the file cache answer
     * through, and nothing is fetched. The bytes were recorded when they were
     * fetched, so this is not. Mirrors Python's Dispatcher._judge_held.
     */
    private judgeHeld;
    /**
     * Answer a read from the file cache, or null to read the backend.
     *
     * The file cache holds what commands read, keyed on the path alone: the
     * stored bytes, which are the rendering for a VFS with no `read` of its
     * own. A read through a filetype renderer (whoever registered it) asks
     * for a different value under the same key, so it is neither served
     * from that cache nor kept in it, and neither is a direct read
     * (`direct: true`), which asks for what the backend holds now: a
     * follow's poll for bytes the cached copy cannot have yet. The cache
     * holds the whole object, so a ranged read is answered by slicing it,
     * never by handing back the whole file: the window is what the caller
     * asked for instead of the file, and git reads pack indexes this way.
     * sliceWindow is the same helper the ranged read op falls back to, so
     * warm and cold agree.
     * Mirrors Python's Dispatcher._serve_cached.
     */
    private serveCached;
    /**
     * The cache manager a cold read fills, or null to keep nothing.
     *
     * A cold read keeps the whole file it fetched for the next reader,
     * through the mount's own manager, the one a command's read fills: a
     * write racing the fetch retires its generation, so the bytes it read
     * are not kept. A ranged read comes from the store only where the store
     * can serve one; elsewhere the read op would fetch the whole file and
     * slice it for every range, so the whole file is read once, kept, and
     * each range sliced from it. The op is resolved only once the mount is
     * ready, so a renderer can land after this check; the fill asks again
     * before it keeps anything. Mirrors Python's Dispatcher._filler.
     */
    private filler;
    /**
     * The running command's `walkLimit` on `mount` (walkBound): its entry,
     * its declared limit and the session's profile over the mount's and the
     * workspace's. Mirrors Python's Dispatcher._walk_bound.
     */
    private walkBoundOf;
    /**
     * The files a walk guard's path holds, once the command's own `walkLimit`
     * lets the walk run: past it the walk is refused before any backend rule
     * is asked. Mirrors Python's Dispatcher._full_walk_files.
     */
    private fullWalkFiles;
    /**
     * How many files the session sees under a walk guard's path, counted off
     * the mount's `readTree` with every hidden file dropped, and every file a
     * nested mount covers, so a guard's refusal never counts what the command
     * would not read. Without one, or where
     * it cannot read the whole tree, a mount with a `walkLimit` is walked
     * listing by listing, hidden entries skipped, until one file past the
     * limit; a folder below the path it cannot open counts nothing, as the
     * command reports it itself. null otherwise. Mirrors Python's
     * Dispatcher._visible_files.
     */
    private visibleFiles;
    /**
     * Run a fresh stat under its path's writer hold, so no local write to the
     * path lands between the backend's answer and its reconcile; the reconcile
     * runs to its end under the hold. Mirrors Python's Dispatcher._fresh_call.
     */
    private freshCall;
    /**
     * Run the op on its mount and stamp what it moved.
     *
     * Returns the op's answer with the rename destination and the arguments
     * the backend received, which the write's settling reads. Mirrors
     * Python's Dispatcher._call.
     */
    private callBackend;
    /**
     * Keep a whole write's bytes for the next read, under its name's hold.
     *
     * The write's own record labels them with the token the backend
     * answered, so a `fresh` mount does not refetch what it just wrote; a
     * record moving another length than was sent keeps nothing, and so does a
     * name another mount took while the write ran, read under the cache's lock.
     * The bytes kept are a copy, so a caller reusing its buffer cannot change
     * them. Mirrors Python's Dispatcher._keep_written.
     */
    /**
     * The cached copy an append may extend, read under its name's hold before
     * the append runs: its bytes and their token. Mirrors Python's
     * Dispatcher._cached_before.
     */
    private cachedBefore;
    /** Drop content without losing the conditional-write baseline. */
    private invalidateStream;
    /**
     * Keep a write's bytes for the next read, under its name's hold. The
     * write's own record labels them with the token the backend answered, so
     * a `fresh` mount does not refetch what it just wrote; a record moving
     * another length than was sent keeps nothing. An append extends the cached
     * copy only where the file is proven to have been that copy: the backend
     * rewrote it whole, its read saw the copy's token, and its write moved the
     * copy's length plus the appended bytes. A store with no tokens, or one
     * that appends by itself, proves nothing, so the copy stays dropped. An
     * append of nothing that wrote nothing (`cmd >> f` opening `f`) leaves the
     * copy as it was; one that made the file anew drops it, and so does a
     * streamed one, whose name another writer could take while it waited.
     * Mirrors Python's Dispatcher._keep_written.
     */
    private keepWritten;
    /**
     * Merge the namespace into a backend answer and drop hidden names.
     *
     * A listing gains the child mounts and links the namespace holds below
     * it and loses every name the session hides; a stat gains the attribute
     * overlay recorded at its path. Mirrors Python's Dispatcher._filter.
     */
    private filter;
    /**
     * A stat, or a subtree's stats, on the device of the mount serving
     * `virtual`. The device is the id a runtime reports as a guest's st_dev,
     * so `stat %d` and `fs.stat` name one device, and a walk tells a mount
     * boundary by it. A path no mount serves is on the namespace's own, the
     * one a root mount would have. Anything but a stat or a subtree's stats
     * passes unchanged.
     */
    /**
     * A custom function's answer as the session may see it. A list of paths,
     * or of records with a `path`, loses what the session hides, as a
     * `files_containing` answer does. Any other answer cannot be told apart
     * from what it names, so it is declined while the session hides anything
     * under the call's path. No answer reveals nothing. Mirrors Python's
     * Dispatcher._custom_answer.
     */
    private customAnswer;
    private onDevice;
    /**
     * A subtree read with the links the namespace holds below `path` on the
     * same mount, each as the link it is. No backend stores a link, so a walk
     * that reads the subtree in one call meets them only here, as a listing
     * meets them in `readdir`; a link that leads where the session cannot see
     * is left out, as a listing leaves it out. A link shadows what the backend
     * holds at its name and below it, as a stat of the name answers the link.
     * Mirrors Python's Dispatcher._with_links.
     */
    /** A subtree read with the attributes the overlay holds for each entry, the
     * ones a stat of that entry carries. */
    private overlaid;
    private withLinks;
    /**
     * Run one write with its names held, one writer at a time per name.
     *
     * The caller's abort covers only its wait for the hold: a writer the
     * abort finds queued lets go of any name it already holds and never
     * runs. One that comes after the abort (a stopped run landing what its
     * guest left open, within the stop's grace) waits its turn. One holding
     * its names runs to the end and the caller waits for it and for `after`
     * (the bookkeeping), since an abort cannot stop a store's call under way,
     * as Python's cancelled line is joined whole; an abort that lands during
     * that call still makes it late, since the line may have gone on past its
     * grace. `after` runs for a caller still waiting, and for a late call that
     * succeeded while every name is still on the mount that ran it (`owners`),
     * so a rename still moves its links; any other late call runs `landed`,
     * which drops what the landing made stale where its names still belong to
     * that mount (a read between the abort and the landing may have cached
     * the old bytes); a failure nobody waits for any more is reported.
     *
     * Args:
     *   keys: the names to hold, in the one order every writer takes them.
     *   label: the op and path, for a late failure's report.
     *   call: runs the op, handing over the store's own call once it starts.
     *   after: the bookkeeping, run while the caller still waits.
     *   landed: run once a call that outlived its timeout settles.
     *   owners: the mount each name was on when the call started.
     */
    private holdWrite;
    /**
     * What a write changes beside the store: the caches above the path, and
     * the node table's links and attributes at its names. Mirrors Python's
     * Dispatcher._settle_write.
     */
    /**
     * What a write changes beside the store: the caches above the path, and the
     * node table's links and attributes at its names. A copy reads its path, so
     * only its destination changes. A create that answers its new entry's stat
     * (`created`) has it kept where its parent's listing names it, in place of
     * dropping that listing for a re-list: the create is the one change to it,
     * and the next level of a nested create finds its parent there. Mirrors
     * Python's Dispatcher._settle_write.
     */
    private settleWrite;
    /**
     * The mount serving each of a write's names as it starts, keyed by the
     * name, for the cleanup after a call that lands past its timeout.
     */
    /** Whether each name is still on the mount it was on in `owners`. */
    private stillOwned;
    private owners;
    /**
     * Drop what a write that threw may have made stale.
     *
     * A write that fails partway may already have changed the store (a
     * paginated delete, a copy that merged some children), so the caches at
     * and below every name it reaches go either way; the node table moves only
     * with a write that landed. The version the line held for each name is
     * kept, so the next write there stays conditioned on what the agent read,
     * and so is each version `lost` marks under them, which a refused
     * conditional write kept: a retry without a read is refused again.
     * Over-dropping costs a refetch. An eviction error is logged, not thrown,
     * so the caller still learns why the write failed. `owners`, for a call
     * that landed after its timeout, holds the mount each name was on when the
     * call started: a name another mount has taken since is that mount's now,
     * so nothing at or under it is touched. Mirrors Python's
     * Dispatcher._evict_failed_write, whose timed-out call is cancelled and
     * never lands late.
     */
    private evictFailedWrite;
    /**
     * What a tree copy changed under `dst`: each entry it wrote. The copy
     * merges into what `dst` already held, so a file it left keeps its cached
     * copy and the version a conditional write needs; the files and
     * directories it wrote are the source's, listed after the copy, so an
     * empty directory it made drops its folder's listing too. Mirrors Python's
     * Dispatcher._settle_tree_copy.
     */
    private settleTreeCopy;
    /**
     * Every file and directory at any depth under `root`, through the mount's
     * own listing.
     */
    private entriesBelow;
    /**
     * A number naming one store object, the same for every mount of it in every
     * workspace, as Python's id() of the store is.
     */
    private storeId;
    /**
     * Whether the node table answers this op instead of a backend.
     *
     * `symlink` and `readlink` always, because a link exists nowhere else.
     * The rest only when the path itself is a link, and then for the same
     * reason the create and the read are the dispatcher's: forwarding reaches a
     * backend that has never heard of the name. A no-follow stat is the
     * read half of that fact (lstat asks for the link's own row, which
     * only the table holds); a following stat never arrives here, since
     * the follow below rewrote it to the target. Mirrors Python's
     * Dispatcher._table_answers.
     */
    /**
     * The index kwargs normal dispatch stamps on every registered op, for
     * the dispatcher's own raw registry calls: an indexed backend cannot
     * resolve a nested path without it.
     */
    private indexKwargs;
    /** The policy boundary for an op on a path `mount` owns: the mount's
     * prefix and mode, or for a path above every mount an empty prefix and
     * full write, governed by `/` (`MountModePolicy`). Mirrors Python's
     * Dispatcher._boundary. */
    private boundary;
    /**
     * The dispatcher's own channel for internal walks: the TS twin of Python's
     * Mount.call plus the dispatcher-side duties around it. The
     * same mode fence, index stamping and mount-prefix context normal
     * dispatch applies, plus the boundary's admission and completion for
     * writes (Python's `_MountChannel` holds the same `Boundary`) and the
     * dispatcher's own write invalidation, because a raw mount call
     * runs outside the cache context dispatch establishes, so the cores'
     * invalidation cannot land. Invalidation runs even when the op
     * fails: a missing-path failure means the tree changed under the
     * walk, and the walk's own earlier listing is exactly the entry that
     * must not survive. Only the visibility filter stays off, which is
     * what lets a remnant walk see hidden entries. Every internal
     * backend call in this class routes through here; a bare
     * `callKeyed` outside dispatch is a bug.
     */
    private fencedCall;
    /**
     * Whether a rename's source stats as a directory.
     *
     * Only a directory can carry hidden content into view, so the reveal
     * refusal probes the source before it fires and lets a file rename
     * pass. An absent source moves nothing (the rename itself reports
     * it); a source the mount cannot classify fails toward refusal, the
     * same stance the pattern arm takes. Mirrors Python's
     * Dispatcher._moved_source_is_dir.
     */
    private movedSourceIsDir;
    /**
     * Take a visibly-empty directory's hidden remnants with it.
     *
     * The backend refused the rmdir because entries remain, but when the
     * session's view of the directory is empty the refusal would leak
     * that something invisible exists. A session's mutation may destroy
     * what it cannot see, never learn of it, so the remnants go with the
     * directory through the shared removeRemnants walk; a visible child,
     * or any cascade failure (a mode-protected entry, a visible entry
     * appearing mid-walk), re-raises the backend's refusal. Emptiness is
     * the dispatcher's own readdir pipeline: backend entries merged with the
     * namespace's children (nested mounts, links) and judged by
     * visibility, so a visible child no backend can see keeps the
     * refusal instead of reporting a successful rmdir while the mounted
     * child remains. The namespace's own hidden nodes under the subtree
     * (links, attr overlays) are purged with it, so the removed tree
     * cannot resurface from the node table once the hide lifts.
     */
    private rmdirRemnants;
    /**
     * `path` with the links above its final name followed.
     *
     * The walked path answers to the session's hides as the typed one did,
     * the rule the follow of the final name applies too: a visible link must
     * not lead into hidden space. Throws `eloop` when a link above the name
     * loops (ELOOP), as the coded error every caller's per-operand catch
     * words. Mirrors Python's Dispatcher._walked.
     */
    private walked;
    private tableAnswers;
    /**
     * Answer a node-table op at the dispatcher itself, gated like a backend.
     *
     * A symlink is namespace state with no backend behind it, so the dispatcher
     * owns every verb that names one. Admission still fires exactly as for
     * a backend write: the link's turf is the longest mount prefix above it
     * (the same ownership rule the link read filter uses), session grants
     * and both gates run, and the write leaves an OpRecord — a scoped
     * kernel mount refuses exactly like a scoped shell. The turf's mode
     * gates the write too (`MountModePolicy` at the `Boundary`), so a
     * read-only mount or grant answers EROFS for a link exactly as for a
     * file; a link above every mount is bare namespace structure, gated
     * with an empty prefix and governed by `/`. A rename's
     * destination is judged on its own turf, since the endpoints need not
     * share one. Also answers the `unlink`, `rename` and no-follow
     * `stat` of a path the node table holds a link for. Mirrors Python's
     * Dispatcher._namespace_table_op.
     */
    private tableCall;
    /**
     * The error a readlink of something that is not a link answers.
     *
     * readlink(2) splits the two misses and callers read them differently:
     * a path that is there but is not a link is EINVAL, and one that is
     * not there at all is ENOENT, which is the code a guest's
     * `except FileNotFoundError` catches. The node table only knows the
     * first half, so absence is probed here and only here, on the failure
     * path, where one extra round trip buys the right errno. Mirrors
     * Python's Dispatcher._readlink_miss.
     */
    private readlinkMiss;
    /**
     * Whether anything at all is at `path`, and the parent's listing.
     *
     * Four channels, asked in the order of what they prove. The namespace
     * goes first: a link, and a directory that exists only because a
     * mount or a link sits below it, are structure no backend can see,
     * and a mount root is the deployment's own configuration. Then the
     * backend's row, which settles a file. A directory row settles
     * nothing, because an API tree synthesizes its directories: a
     * postgres schema lists `tables/` and `views/` before anything has
     * asked whether that schema is there, and a grouping mount stats
     * every path under a live collection as a directory. So a directory
     * is proven the way the hierarchy kit itself proves one, by appearing
     * in its parent's listing, which is also the only way a prefix store
     * can answer for a directory that is nothing but a set of keys.
     * Cannot reuse `resolvePathStat`: that dispatches, and the dispatcher is
     * what dispatch is inside of.
     *
     * The parent's listing comes back beside the answer, null when no probe
     * reached it or it gave none, because a listing with entries in it also
     * proves the parent a directory: a create in a directory that holds
     * anything costs no round trip beyond this one. Mirrors Python's
     * Dispatcher._occupancy.
     */
    private occupancy;
    /**
     * What symlink(2) answers instead of making a link at `path`.
     *
     * Null when the link can be made. The name must be free (EEXIST) and
     * its parent a directory (`parentRefusal`), both read off the probes
     * `occupancy` makes: a parent whose listing answered with entries is a
     * directory, so only an empty or silent parent is walked, which is the
     * failure path nearly always. Mirrors Python's
     * Dispatcher._symlink_refusal.
     */
    private symlinkRefusal;
    /**
     * The errno the parent chain of a name being created answers.
     *
     * symlink(2) and rename(2) resolve the directory a name goes in before
     * they look at the name: ENOENT when it is absent and ENOTDIR when a
     * non-directory stands anywhere in the chain. The chain is walked
     * upward until something is there, as `destKind` walks a copy's
     * destination, because a store answers a path under a plain file with
     * the same miss as an absent one: the parent itself being a directory
     * is the one clean answer, a directory higher up means the components
     * below it are absent, and anything else is ENOTDIR. Null when the
     * parent is a directory, and when a policy closes a channel, which
     * proves nothing either way. Mirrors Python's
     * Dispatcher._parent_refusal.
     */
    private parentRefusal;
    /**
     * The type of what stands at `virtual`, null when nothing does.
     *
     * The channels `occupancy` asks, for a path the walk above a new name
     * reaches: namespace structure and a mount root are directories, then
     * the backend's row, then the path's own entry in its parent's
     * listing, which is how a prefix store holds a directory that is
     * nothing but a set of keys. Mirrors Python's Dispatcher._entry_type.
     */
    private entryType;
    /**
     * The backend listing of the directory `virtual` sits in: null when no
     * mount serves that directory, its backend lists nothing there, or the
     * path has no name to sit in one. Mirrors Python's
     * Dispatcher._parent_listing.
     */
    private parentListing;
    /**
     * Run one read op for a probe, or null when it found nothing.
     *
     * The probe reads on the caller's behalf but not at its request, so it
     * meets what the op would at the dispatcher: a path the caller cannot
     * see answers as the walk answers it (`sees`), and a policy that denies
     * `stat` must not be reachable through a readlink. That refusal is
     * raised, not swallowed, because only the caller knows what to answer
     * when a channel goes dark.
     *
     * The index and the path's filetype are the two kwargs that decide
     * which registered op answers, so a probe that omitted them would ask
     * a different question than the dispatcher does and report a rendered path
     * as absent. Python needs no twin of that half: its dispatcher routes
     * through `Mount.call`, which stamps both itself.
     *
     * Args:
     *   name: the function to run, `stat` or `readdir`.
     *   resolved: what the namespace resolved the path to.
     *   issuer: the mark on the op being served, carried to the probe's
     *     gate so the probe is judged as its caller's.
     */
    private probeRead;
    /**
     * Answer an extended-attribute op from the node table.
     *
     * The attributes a caller sets live on the path's node, so they
     * survive on a backend that has no such slot and move with a rename;
     * the backend's own facts are read off its stat on every call and
     * refused to writers with EPERM, the answer for an attribute the
     * filesystem keeps for itself. The listing is sorted, so both hosts
     * and every backend agree on its order. Gated like a setattr: both
     * admission gates fire on the path's turf, and a write needs a
     * writable turf. Mirrors Python's Dispatcher._xattr_op.
     *
     * Args:
     *   name: `getxattr`, `listxattr`, `setxattr` or `removexattr`.
     *   path: the path, already followed unless the caller asked for its
     *     link node itself.
     *   kwargs: `name` for all but listxattr, `value` and the
     *     `create`/`replace` flags for setxattr.
     *   report: the caller's report.
     *   issuer: the mark on the op being served.
     */
    private answerXattr;
    /**
     * Answer statfs(2) for a path: the type name and the capacity of the
     * mount that holds it, which is what df reports for that mount. The path
     * must exist, as statfs's own walk requires. The namespace above every
     * mount has no file system behind it, so its type is `-` and its
     * capacity unknown. Mirrors Python's Dispatcher._statfs.
     *
     * Args:
     *   path: the path, already followed.
     *   issuer: the mark on the op being served.
     */
    private statfs;
    /**
     * Settle that an attribute op's path exists, which it answers first. A
     * link node's own attributes and a directory that exists only in the
     * namespace have no backend behind them; anything else the backend's
     * stat must find, or the op is ENOENT. Mirrors Python's
     * Dispatcher._xattr_target.
     */
    private xattrTarget;
    /**
     * Apply attributes natively where the backend can, overlay the rest.
     *
     * A VFS with a registered setattr op applies what it can and
     * returns the residual; residual fields go to the overlay and
     * natively applied ones are dropped from it, so a stale overlay never
     * shadows a fresh backend value. A VFS without the op, and a
     * link path (which has no backend inode), overlay everything. The
     * overlay half is the dispatcher's own write, so it runs inside the same
     * gates as the native half. Mirrors Python's Dispatcher._apply_setattr.
     */
    private applySetattr;
    /** Store every requested field in the namespace overlay. */
    private overlaySetattr;
    /** Write one overlay entry, converting an ISO mtime to epoch seconds. */
    private writeOverlay;
    /**
     * Drop what a change to `rawPath` made stale above the store.
     *
     * The mount's caches take it under every mount of its store
     * (`CacheManager.invalidate`); a removal through the dispatcher knows
     * nothing was below the name, so its index is not asked. The overlay times
     * a content write moves go too, under each name: `observed` is the epoch
     * seconds of a content write to record, null for a removal, and `times`
     * false keeps them, for a change that moved no times. `row` is a CREATE's
     * new entry, kept in its parent's listing; null drops that entry. Mirrors
     * Python's Dispatcher._changed.
     */
    /**
     * Time the directories a `mkdir -p` made above its path, as the path
     * itself is timed. After a failure only those that now exist are: a chain
     * is made outermost first, so the first one missing ends it. Mirrors
     * Python's `_date_made`.
     */
    private dateMade;
    private changed;
    /**
     * Bind the end of a line to the mounts it started with.
     *
     * The mount table is pinned at the line's start, so a version kept when it
     * ends is judged by the mount that produced it rather than whatever holds
     * the prefix by then. Mirrors Python's Dispatcher.capture_cache_facts.
     */
    captureCacheFacts(): (path: string) => CacheFacts;
    /**
     * Keep the version each path last had on a line that ended; a nested
     * line's keeps only the versions of paths still lost. Mirrors Python's
     * Dispatcher.keep_versions.
     */
    keepVersions(records: readonly OpRecord[], cacheFacts: (path: string) => CacheFacts, lost: LostPaths | null, nested?: boolean): Promise<void>;
}
export {};
//# sourceMappingURL=dispatcher.d.ts.map