mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
Capstone of Ring 2 SHARED. Implements RFC §4 — the shared, scope-aware
resolution surface the rest of the semantic model feeds into.
## Modules (`gitnexus-shared/src/scope-resolution/registries/`)
- `context.ts` — `RegistryContext` bundling ScopeTree / DefIndex
/ QualifiedNameIndex / ModuleScopeIndex /
MethodDispatchIndex + provider hooks.
Narrows Ring 1's opaque `RegistryContributor`
to concrete `OwnerScopedContributor`.
- `tie-breaks.ts` — `compareByConfidenceWithTiebreaks`, the RFC
Appendix B cascade: confidence DESC → scope
depth ASC → MRO depth ASC → ORIGIN_PRIORITY
ASC → DefId.localeCompare.
- `evidence.ts` — `composeEvidence(signals)` / `confidenceFromEvidence`.
Translates raw walk signals into the typed
`ResolutionEvidence[]` using authoritative
`EvidenceWeights`. No magic numbers.
- `lookup-qualified.ts`— RFC §4.5. Qualified-name fast path consumed
by `resolveTypeRef` dotted fallback and by
Step 6 of lookup-core.
- `lookup-core.ts` — The 7-step canonical algorithm. Pure. Param-
eterized by `CoreLookupParams`.
- `{class,method,field}-registry.ts`
— Thin wrappers over `lookupCore` that fix
`acceptedKinds` + `useReceiverTypeBinding` per
kind. `buildClassRegistry` / `buildMethodRegistry`
/ `buildFieldRegistry` factory functions.
## RFC §4.2 algorithm contract (honored verbatim)
1. Lexical scope-chain walk. Hard shadow on any `scope.bindings.has(name)`
regardless of kind survivorship.
2. Type-binding resolution (methods/fields only, opt-in via
`useReceiverTypeBinding`). MRO walk via `MethodDispatchIndex.mroFor`.
MRO-depth-decayed weight via `typeBindingWeightAtDepth`.
3. Owner-scoped contributor — when the caller knows the receiver owner,
its direct members merge in as `origin: 'local'`.
4. Kind filter — `acceptedKinds` per registry; `kind-match` evidence
at weight 0 is always emitted for debuggability.
5. Arity filter — `provider.arityCompatibility` per candidate. When at
least one compatible candidate exists, incompatibles are dropped;
otherwise the −0.15 penalty alone disambiguates (they stay in the
result, just ranked lower).
6. Global fallback — fires only when Steps 1-3 produced NO candidates
AND the name is dotted. Delegates to `lookupQualified`.
7. Rank + tie-break — evidence list sorted by the Appendix B cascade.
## §4.7 invariants asserted in tests
- No tier vocabulary in the return type (`Resolution`, not `TierXResult`).
- Confidence is per-candidate (not per-tier).
- Shadowing is a HARD filter; globals are consulted ONLY when lexically
empty.
- Caller can read `[0]` for one-shot answers.
- `Resolution.confidence` is capped at 1.0.
- `kind-match` is always emitted (weight 0).
## Unresolved-import + dynamic-unresolved evidence shape
- `BindingRef.via.linkStatus === 'unresolved'` applies the
`unlinkedImportMultiplier` (0.5×) to the where-found signal only.
Corroborators (`arity-match`, `owner-match`, `type-binding`) remain
unaffected — the RFC §4v2 capped-signal rule applies per-signal, not
per-candidate.
- `BindingRef.via.kind === 'dynamic-unresolved'` adds a degraded
`dynamic-import-unresolved` evidence signal at weight 0.02.
## Tests (28 in registries.test.ts, 259/259 combined)
Organized per RFC §4.2 step so a regression localizes to the step it broke:
- Step 1: local + walk-to-parent + hard-shadow + origin=import
- Step 2: explicit receiver type-binding + MRO depth decay on ancestor
- Step 3: owner-scoped contributor + owner-match
- Step 5: drop-incompatible-when-compatible-exists + soft-penalty-when-all-
incompatible + unknown-when-no-provider
- Step 6: global-qualified fires only when lexically empty + never for
non-dotted names + not consulted when lexical hit exists
- Step 7: tie-break cascade (inner shadows outer; defId.localeCompare
final)
- Corroborators: unresolved-import 0.5× cap per-signal + dynamic-
unresolved 0.02 degraded signal
- §4.5: lookupQualified kind filter + empty on miss + deterministic defId
order for partial classes
- §4.7: invariants — confidence per-candidate, capped at 1.0, kind-match
always present, [0]-for-one-shot
## Known follow-up optimizations
`collectOwnedMembers` in `lookup-core.ts` iterates `defs.byId.values()`
for each MRO hop — O(D) per call. Acceptable for Ring 2 fixtures; a
by-owner index should land before Ring 3 migrates large-workspace
languages. Tracked alongside the existing `findDefById` follow-up from
#915 review.
## Module placement
All under `gitnexus-shared/src/scope-resolution/registries/` — consistent
with the Ring 2 SHARED folder layout (#912/#913/#914/#915/#916/#918).
Slight deviation from the issue's `gitnexus-shared/src/registries/`
suggestion for consistency with siblings.
## Part of
- Parent: #909
- Depends on (code): #910, #911, #912, #913, #914, #915, #916, #918.
- Closes the Ring 2 SHARED delivery band. Unblocks Ring 2 PKG (#919–#925
bridges to the gitnexus/ CLI package) and Ring 3 language migrations.
|
||
|---|---|---|
| .. | ||
| src | ||
| package-lock.json | ||
| package.json | ||
| tsconfig.json | ||