/** * Transitive-closure FK walker. Computes the set of * (collection, id) tuples reachable from seed predicates, so a * partition extraction ships a referentially-complete subset. * * Two-phase, plaintext, read-only (runs inside the unlocked vault * session — see foundation §13.4 / spec invariant 7): * 1. INBOUND expansion: from selected records, pull every record * that references them (children travel with parents), to a * fixed point. * 2. OUTBOUND completion: pull every VISIBLE parent the selected set * references, transitively, WITHOUT re-expanding inbound from those * parents (bounds the closure). A tier-elevated (or missing) parent is * excluded rather than admitted — see `danglingRefs` on the result. * * The FK graph is auto-derived from the vault's existing RefRegistry * (the `ref('target')` declarations on collections) — no hand-written * edge list. * * @module */ import type { Vault } from '../kernel/vault.js'; /** Seed predicate per collection. Records that return true become roots. */ export interface WalkClosureOptions { readonly seeds: Record) => boolean | Promise>; /** Max fixed-point iterations before throwing. Default 16. */ readonly maxDepth?: number; } /** * #759: an outbound FK edge whose referenced parent was excluded from the * closure — either because it doesn't exist, or because it is tier-elevated * and therefore invisible (same "elevated ≡ missing" semantics as root * selection / inbound expansion). The child keeps its FK value; the parent * does not travel. Callers (extract-partition) surface this as a residue * notice rather than silently dropping it. */ export interface DanglingRefNotice { /** Collection of the child record that holds the dangling FK. */ readonly collection: string; /** Id of the child record. */ readonly id: string; /** FK field on the child that references the missing/elevated parent. */ readonly field: string; /** Target collection the FK points at. */ readonly target: string; /** Id of the missing/elevated parent. */ readonly targetId: string; /** * #772: distinguishes an intentional tier boundary (`'elevated'` — the * parent exists but is above the caller's readable tier) from a genuine * data-integrity gap (`'missing'` — no envelope for `targetId` at all). */ readonly reason: 'missing' | 'elevated'; } export interface ClosureResult { /** collection → set of record ids that travel together. */ readonly closure: Map>; readonly graph: { /** Fixed-point iterations the walk needed to converge. */ readonly depth: number; /** True if an edge pointed back to an already-selected node. */ readonly cyclesDetected: boolean; }; /** #759: outbound FK edges whose parent was excluded (missing or elevated). */ readonly danglingRefs: ReadonlyArray; } export declare function walkClosure(vault: Vault, opts: WalkClosureOptions): Promise;