/** * Cyclic-seam resolution: deterministic cycle detection over module seam * obligations, plus a re-check helper that validates a proposed cycle-break * does not re-introduce a cycle. * * A "seam obligation" is any module that declares an interface obligation * (via neighbor_needs / inputs / outputs) that depends on a type or interface * owned by another module. For the purposes of this detector, a module M * is said to need module N when M lists N in its `needs` array. * * Detection algorithm: Kahn's iterative topological sort over the directed * graph of (module → modules it needs). Any node that remains after the * sort is part of a cycle. The resulting connected components are each * reported as one detected cycle. */ /** A module node in the seam-obligation graph. */ export interface SeamObligationNode { /** Unique module identifier. */ id: string; /** IDs of modules this module declares an interface obligation toward. */ needs: string[]; } /** One detected cycle (N ≥ 2 nodes). */ export interface DetectedCycle { /** Ordered list of module IDs that form the cycle (not necessarily in cycle order). */ members: string[]; } /** A proposed mediator module that breaks a cycle. */ export interface ProposedMediator { /** Module ID for the new mediator. */ id: string; /** Modules the mediator itself needs (must not form a new cycle). */ needs: string[]; } /** Result of a cycle-break re-check. */ export interface CycleBreakValidation { accepted: boolean; /** Present only when accepted === false. */ reason?: string; } /** * The break a worker ACTUALLY authored, read off the `cyclic_seam_resolution` * record rather than fabricated by the re-checker. * * Both sanctioned strategies designate a REAL node: `mediator` names a third * obligation that now owns the shared primitive, `single_authority` names the * one cycle member that keeps the interface. A record that designates nothing * cannot be validated against the real graph at all — see * {@link validateAuthoredCycleBreak}, which refuses it rather than inventing a * placeholder. */ export interface AuthoredCycleBreak { /** `break_strategy` from the resolution record. */ strategy: "mediator" | "single_authority"; /** The obligation id the record designates, when it named one. */ designatedId?: string; } /** * Detect cyclic seam obligations in a module graph. * * Uses Kahn's topological sort: build an in-degree map and a dependency → * dependent adjacency list, then drain the zero-in-degree queue. Any node * remaining in the graph after the drain is part of a cycle. Weakly * connected components among remaining nodes are grouped into cycles. * * Returns an empty array when no cycle is found. */ export declare function detectCyclicSeamObligations(nodes: SeamObligationNode[]): DetectedCycle[]; /** * Validate a proposed cycle-break by re-running cycle detection on the * graph after the break is applied. * * The break modifies the original graph as follows: * - Remove every `needs` edge between original cycle members that crossed the * cycle (both sides still appear in the graph with their original non-cycle * needs intact). * - Add the `proposedMediator` as a new node. * - For each original cycle member, replace any needs-edge that pointed to * another cycle member with a needs-edge to the mediator. * * If the resulting graph still contains a cycle, the proposed break is * rejected. */ export declare function validateCycleBreak(originalCycle: DetectedCycle, allNodes: SeamObligationNode[], proposedMediator: ProposedMediator): CycleBreakValidation; /** * Re-check a cycle-break AS AUTHORED, against the REAL obligation graph. * * The distinction from {@link validateCycleBreak} is the whole point: that * function asks a HYPOTHETICAL — "if the intra-cycle edges were redirected to * this proposed node, would the graph be acyclic?" — and its caller used to * answer it with a node it had fabricated itself (`{ id: "_mediator_A_B", * needs: [] }`) against the UNMODIFIED ledger. An edge-free sink absorbs every * redirected edge, so for a single detected cycle that question is acyclic BY * CONSTRUCTION and the re-check could never reject — a worker could claim * `status: "resolved"` while leaving the ledger's cycle edges exactly as they * were, and the pipeline advanced. * * This function asks the REAL question instead: does the graph the pipeline * will actually consume still carry the cycle? The break is accepted only when * * 1. the record designates a node (a break with no designated owner is not a * break, it is a claim), and that node EXISTS in the live graph; * 2. the strategy and the designated node agree — a mediator is a THIRD node * outside the cycle, a single authority is one of the cycle's own members; * 3. the live graph no longer contains a cycle touching the original members * — i.e. the break is reflected in the edges, not just asserted in prose; * 4. and, for the mediator strategy, redirecting the cycle's edges at the * mediator's REAL `needs` (never a fabricated empty set) stays acyclic, so * a mediator that itself depends back into the cycle is refused. * * `currentNodes` must be built from the obligation ledger as it stands NOW, on * this invocation, after ingestion and the staleness-archive pass — a stale * snapshot would reintroduce exactly the vacuity this closes. */ export declare function validateAuthoredCycleBreak(originalCycle: DetectedCycle, currentNodes: SeamObligationNode[], authored: AuthoredCycleBreak): CycleBreakValidation; //# sourceMappingURL=cyclicSeamResolution.d.ts.map