/** * Cross-shard merge & semantic boundary linking (plan #2, Phase 2). * * After the shard workers return per-shard fragments + cross-boundary * call descriptors, this module: * 1. merges the fragments into one unified catalog (union of occurrences, * each keeping its already-resolved intra-shard edges); * 2. LINKS the boundary calls semantically against the export symbol table * ({@link ExportIndex}) + package manifest index ({@link PackageManifestIndex}) * built from the merged catalog and the resolved shard set, then stitches * the recovered edges onto their owner occurrences as * `resolution: 'semantic'`, `crossShard: true`, `confidence: 'high'`. * * The linker emits a cross-package edge ONLY when the import specifier + * imported source name resolve to a UNIQUE exported occurrence in the imported * module — exactly what the TypeScript type checker would conclude. Relative * module barrels are followed through a bounded, cycle-safe re-export walk. On * ANY ambiguity (a name with multiple matching exports the subpath can't * disambiguate, a name the module does not export, a specifier pointing at an * external npm package) it DECLINES and emits an unresolved (`to: []`) edge. A * missing edge is safe; a phantom cross-package edge would fail the gate. This * replaces the old name-only syntactic fallback, which fabricated impossible * coupling edges by matching a globally-unique simple name into a package the * caller never imported. * * Intra-shard edges retain their original (semantic, in exact mode) fidelity; * relative imports are still path-pinned (already exact for same-package * imports). Engine-layer and language-agnostic: it operates on plain catalog * data + the descriptors' callee names / import specifiers + each package's * `package.json` — no parser, no TypeScript assumptions. */ import type { ShardBuildResult } from './shard-model.js'; import type { PackageManifestIndex } from '../../cross-package/export-index.js'; import type { Catalog, CrossBoundaryCall, ResolutionStats } from '../../types.js'; /** Output of the cross-shard pass: the unified catalog + boundary-resolution stats. */ export interface CrossShardOutput { readonly catalog: Catalog; readonly boundaryStats: ResolutionStats; } /** * Merge per-shard fragments and recover cross-package edges. The single * Phase-2 entry the orchestrator calls. */ export declare function mergeAndResolveShards(fragments: readonly ShardBuildResult[], allFiles: readonly string[], manifestIndex: PackageManifestIndex): CrossShardOutput; /** * Finalize cross-package edges on a merged catalog: stamp each occurrence's * owning package (`assignPackages`) then drop name-guessed cross-package edges * that contradict the import graph (`constrainCrossPackageEdges`). These two * pipeline steps are always applied as a pair on the post-resolve catalog — by * both the sharded build (`runShardedGraph`) and the cached single-program * recovery path (`cache-orchestrator`) — so they live here, the cross-package * resolution module, as one helper rather than duplicated import pairs. */ export declare function stampAndConstrainPackages(catalog: Catalog, projectRoot: string): Catalog; /** * Union every fragment's `functions` map into one catalog. Each * occurrence keeps its already-resolved intra-shard `calls`. Shards are * disjoint by construction (distinct files), so occurrences don't * conflict; a defensive dedup by occurrence IDENTITY — (bodyHash, * filePath, line, column) — drops any accidental duplicate rather than * double-counting. * * The dedup key MUST include `column`: two distinct callables can share a * `(bodyHash, filePath, line)` triple when they sit on the SAME source line * with BYTE-IDENTICAL bodies — e.g. `a.some((p) => p.test(x)) || b.some((p) => * p.test(x))` (two body-twin arrows on one line). `bodyHash` is a CONTENT hash, * so both twins hash equally; a column-less key collapsed them into one, * dropping the second occurrence the single-program engine keeps. Keying on the * full occurrence identity (filePath:line:column — the same tuple the SCC graph * uses as its node id) makes the merged function set byte-identical to exact * (Phase 3 closed the residual 2-occurrence delta this way). */ /** * Fill a declaration-target dependency edge's `resolvedPackage` using the * COMPLETE merged manifest index (P2 Phase 0 Task 0.2). A single shard worker * sees only its own packages, so a cross-shard workspace `.d.ts` import it could * not attribute — `workspace-declaration-unmapped`, or `external-declaration` * when the workspace package resolved through a `node_modules` symlink — is * re-attributed here to a unique workspace package, matching the single-program * exact catalog byte-for-byte. Ambiguous names (tombstoned duplicates) stay * unresolved. Pure: returns the SAME catalog reference when nothing changes. * * Scope: this parity holds when workspace imports resolve to DECLARATION files — * the norm for built `dist/*.d.ts` packages, where a worker emits * `workspace-declaration-unmapped` / `external-declaration` and this patch upgrades * both to `workspace-declaration-entry`. A workspace that exports raw source `.ts` * would resolve to `catalog-source` (a real `to:[hash]`) in the exact build; this * classification-only patch cannot reconstruct that target hash, so such a repo is * a fidelity boundary rather than byte-identical. (Not reachable in this repo.) */ export declare function reattributeDeclarationDependencies(catalog: Catalog, manifestIndex: PackageManifestIndex): Catalog; export declare function mergeShardFragments(fragments: readonly Catalog[], allFiles: readonly string[]): Catalog; /** * Resolve each cross-boundary call against the merged global catalog and * stitch the recovered edge onto its owner. A recovered edge is `'semantic'`, * `crossShard: true`, `confidence: 'high'` — the import specifier + callee name * linked to a UNIQUE target occurrence (relative imports pin by path; bare / * workspace imports pin by the imported package's export symbol table). On any * ambiguity the resolver DECLINES (`to: []`) — a missing edge is safe, a phantom * cross-package edge is not. Declined / external boundary calls stay unresolved * but are counted (attributable). */ export declare function resolveCrossBoundaryCalls(merged: Catalog, boundaryCalls: readonly CrossBoundaryCall[], manifestIndex: PackageManifestIndex): CrossShardOutput; /** * The full sharded≡exact equivalence verdict — the Phase-4 gate's currency. * Five partitions, ALL of which MUST be empty for the sharded build to be * byte-equivalent to the single-program build: * * - `functionsOnlyInA` / `functionsOnlyInB` — symmetric difference of the * occurrence IDENTITY sets (the function set itself). A non-empty side means * one engine discovered a function the other did not — a discovery/merge * divergence, NOT an edge difference. (This is the partition that caught the * two body-twin arrows the column-less merge dedup dropped; see * `mergeShardFragments`.) * - `intraMismatches` / `crossDifferences` — edges whose target set differs, * partitioned by whether either side is a cross-shard (boundary-linked) edge * (see {@link CatalogEdgeDiff}). * - `sccDifferences` — strongly-connected components present in one catalog's * occId-keyed SCC graph but not the other (by sorted-member signature). SCCs * drive the `cycle` rule's findings, so an SCC divergence is a gate-visible * divergence even when every individual edge matches (e.g. a dropped function * that was a cycle member changes the component). * * `equivalence` ⇔ every partition empty. */ export interface CatalogEquivalence { readonly functionsOnlyInA: readonly string[]; readonly functionsOnlyInB: readonly string[]; readonly intraMismatches: readonly string[]; readonly crossDifferences: readonly string[]; readonly sccDifferences: readonly string[]; /** * Owner-attributed detail for every differing edge (the union of * `intraMismatches` + `crossDifferences`). Additive: it carries the owner file * path + position the real-repo equivalence guardrail classifies on (and * prints on a budget breach). The five partition arrays above are the * authoritative equivalence verdict (`isEquivalent` ignores this field). */ readonly edgeDifferences: readonly EdgeDifference[]; } /** * Full structural diff of two catalogs: function set + edges + SCCs. The * Phase-4 equivalence gate runs this over (sharded, exact) and asserts every * partition empty. Composes the three orthogonal diffs: * - `diffFunctionSets` — occurrence-identity symmetric difference; * - `diffCatalogsByEdge` — the per-edge target diff (intra / cross); * - `diffSccs` — occId-keyed SCC membership diff (reusing the engine's own * `computeSccs` over `buildIndexes`, so the gate measures the SAME SCCs the * `cycle` rule consumes). */ export declare function diffCatalogs(a: Catalog, b: Catalog): CatalogEquivalence; /** True when every partition of a {@link CatalogEquivalence} is empty. */ export declare function isEquivalent(eq: CatalogEquivalence): boolean; export interface CatalogEdgeDiff { /** Intra-shard edges whose target differs between the two catalogs. MUST be * empty for a correct sharded build vs single-program build. */ readonly intraMismatches: readonly string[]; /** * Cross-package (boundary-linked) edges whose target differs between the two * catalogs. MUST ALSO be empty. * * With semantic linking (Phase 2), the sharded build's cross-package edges * are no longer an approximation of the single-program build's — they are the * SAME edges, recovered by linking each import specifier + callee name to the * UNIQUE exported occurrence the type checker would pick. A non-empty * `crossDifferences` is therefore a correctness REGRESSION (e.g. a name-only * fallback fabricating a phantom edge into a package the caller never * imported, or the linker declining an edge the single program resolves), NOT * an accepted fidelity gap. The Phase 4 equivalence guardrail asserts this * partition empty. */ readonly crossDifferences: readonly string[]; readonly differences: readonly EdgeDifference[]; } /** * One owner-attributed edge difference. `key` is the same * `filePath:line:column@line:col` (owner OCCURRENCE identity + call-site * position) the partition arrays use. The explicit `owner*` fields carry the * complete owner occurrence identity alongside that display key so downstream * diagnostics never need to parse the key or mistake it for a body hash. * `ownerFilePath` is project-relative; `ownerLine` / `ownerColumn` are the * declaration position, while `line` / `column` remain the call-site position. * `toA` / `toB` are the sorted-joined target sets on each side (one is `''` when * the edge is present only on one side). `cross` mirrors the partition split. */ export interface EdgeDifference { readonly key: string; readonly ownerBodyHash: string; readonly ownerFilePath: string; readonly ownerLine: number; readonly ownerColumn: number; readonly line: number; readonly column: number; readonly toA: string; readonly toB: string; readonly cross: boolean; } /** * Diff two catalogs by edge, partitioned into intra-shard mismatches and * cross-package (boundary-linked) differences. An edge is keyed by * `filePath:line:column@line:col → sorted(to)` — the owner OCCURRENCE identity * (ADR-0136), NOT `ownerHash`, so two same-file body-twins' differing edges are * no longer collapsed last-writer-wins; a key is a difference when the two * catalogs disagree on its target set. Both partitions MUST be empty for a * correct sharded build vs single-program build: intra-package edges are exact * in both, and semantic boundary linking reproduces the single-program build's * cross-package edges verbatim (Phase 2). The partition only records WHICH side * a difference falls on (cross when either edge is `crossShard`), so a * regression is attributable to the linker vs a local resolver. The Phase 4 * equivalence guardrail (`__tests__/equivalence.test.ts`) is the live gate. * * `differences` additionally carries the OWNER FILE PATH + call-site line/column * of every differing edge, so the real-repo equivalence guardrail can classify a * divergence by owner file (test/fixture-owned ⇒ gate-invisible; production ⇒ * meaningful) and print the offending `file:line → target` on a budget breach. * The legacy key arrays are unchanged. */ export declare function diffCatalogsByEdge(a: Catalog, b: Catalog): CatalogEdgeDiff; //# sourceMappingURL=cross-shard-resolve.d.ts.map