<aside> π
This RFC is the scope-graph continuation of the Fuzzy Lookup Elimination RFC and implements the resolution-layer side of Ingestion Roadmap Phase 3 (Wire SemanticModel). It is triggered by PR #902 review feedback: "resolution must use the semantic model with O(1) lookups β that is the sole purpose of the semantic model."
</aside>
| Property | Value |
|---|---|
| Type | refactor (architecture) |
| Status | active β design locked, awaiting community review |
| Date | 2026-04-18 |
| Predecessor | RFC: From fuzzy lookups to a semantic model - language-agnostic resolution roadmap |
| Complements | πΊοΈ Ingestion Roadmap β Phase 3 (Wire SemanticModel) + Phase 4 (Import strategies) |
| Triggering feedback | GitNexus#902 β three CHANGES_REQUESTED reviews on the extraction/resolution phase split |
| Related issues | #429 centralize confidence constants Β· #884 gitnexus-shared consolidation |
| Live tracking | Meta issue #909 β 39 child tickets (Ring 1β5), progress checkboxes, dependency graph |
GitNexus already has a SemanticModel (SymbolTable + Type/Method/Field registries + HeritageMap) that resolves calls through a 5-stage DAG inside call-processor.ts. The DAG still reads AST fragments at resolution time and still uses a tiered TieredCandidates API where the caller has to reason about where a match was found. This RFC locks a design that:
ResolutionContext.resolve(name, file) + TieredCandidates with three scope-aware per-kind entry points: ClassRegistry.lookup(name, scope), MethodRegistry.lookup(name, scope), FieldRegistry.lookup(name, scope) β all returning Resolution[] with { def, confidence, evidence }.Registry.lookup(name, scope) call. TypeEnv becomes Scope.typeBindings; implicit-receiver inference becomes a strict resolveTypeRef path; dispatch-strategy selection becomes caller-side registry selection.SymbolTable and TypeRegistry as internal contributors β the resolver never calls them directly.REGISTRY_PRIMARY_<LANG> when β₯99% fixture + β₯98% corpus parity is reached. DAG retirement only when all production-classified languages are flipped and stable for a release cycle.The design preserves every public invariant of the knowledge graph: no changes to node/edge schema, no changes to MCP contracts, no changes to graph output. All delta lives inside the ingestion pipeline.
Two walls, one spine.
ββββββββββββββββββββββββ ββββββββββββββββββββββββ
β AST (tree-sitter β β Knowledge graph β
β + COBOL regex) β β (LadybugDB) β
ββββββββββββ¬ββββββββββββ ββββββββββββ²ββββββββββββ
β β
β extraction resolution β
β (AST-reading) (model-only) β
βΌ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ΄βββββββββββ
β Semantic Model β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β ScopeTree (spine) β β
β β β Scope nodes: {bindings, ownedDefs, imports, β β
β β typeBindings, range, parent} β β
β β β PositionIndex (O(log N) scope-at-position) β β
β β β Parent pointers (O(D) scope-chain walk) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Public API (resolver calls these; nothing else) β β
β β ClassRegistry.lookup(name, scope) β Resolution[] β β
β β MethodRegistry.lookup(name, scope) β Resolution[] β β
β β FieldRegistry.lookup(name, scope) β Resolution[] β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Internal contributors (feed into lookups; never called β β
β β directly by the resolver) β β
β β SymbolTable Β· TypeRegistry β β
β β DefIndex Β· ModuleScopeIndex Β· QualifiedNameIndex β β
β β MethodDispatchIndex Β· ExportMap Β· ImportGraph β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Wall 1 β Extraction β SemanticModel. Only extraction code reads the AST. It produces: scope tree, declarations attached to scopes, raw import edges on module-level scopes, type bindings, reference sites. No resolution happens here.
Wall 2 β SemanticModel β Resolver. Only the resolver calls Registry.lookup(name, scope). It never sees the AST. It emits one edge to the knowledge graph per call, tagged with confidence + evidence.
This matches the PR #902 review requirements verbatim: extraction is the sole AST-reader; resolution is the sole model-reader; the two phases talk through one well-typed spine and three well-typed queries.