NCI
Architecture · Re-exports

Re-export and dependency resolution

Almost no real package’s entry file declares its own surface — most just re-export from internal modules. The resolver replays those rewrites until every public symbol points at its terminal declaration. The behaviour visible through the CLI is documented here; the implementation lives in resolver.rs and is internal.

Hops and max_hops

Each follow is one hop. max_hops = 0 parses the entry only and stops. -1 is unlimited. The nci-engine constant DEFAULT_MAX_HOPS is what nci init writes into nci.config.json and what nci index uses when neither the file nor --max-hops says otherwise.

Dependency resolution policy: nci-dep-v1

symbol_dependencies (resolved “uses” edges) follow a fixed precedence — strongest first:

LayerResolution rule
1Explicit module specifier on the import statement.
2Same file as the using declaration.
3Import alias visible in that file.
4Files reachable via /// <reference path="…" /> closure.
5Weakest: package-wide bare-name fallback. Can tie homonyms — known limitation.

is_internal does not block an edge — internal symbols still participate in symbol_dependencies.

Two separate edge tables

  • symbol_dependencies — the resolved graph above, suitable for “what does this declaration reference?”.
  • symbol_surface_dependencies — namespace/module-surface rollup. Don’t use it as a substitute on arbitrary member rows; it answers a different question.

Source package vs. exporting package

When a re-export crosses package boundaries, the resulting symbols row records both ownership layers:

  • package_id is the indexed install the user typed into the import.
  • source_package_name (and source_package_version when in-tree) is the package that authored the declaration.

Use source_package_name for nci query --source-package to scope hits to the right ownership layer.

Merge provenance

When the resolver emits two declarations that the dedupe stage decides are “the same”, the row records why:

  • merge_scope — same merge key as another contribution.
  • identical_fold — same name, kind, normalised signature across external files.
  • overload_key — overload-style merge keyed by normalised signature.

Read these from merge_provenance_json together with signature and kind_name when an overload count looks wrong — overload rows can either fuse into one row or stay distinct depending on normalisation.

Where to go next