feat(shared): DefIndex / ModuleScopeIndex / QualifiedNameIndex (#913, RFC #909 Ring 2 SHARED)#958
Conversation
… RFC #909 Ring 2 SHARED) Three flat O(1) indexes + pure build functions over per-file artifacts. Contract-only; no runtime behavior change yet — consumers (#917 Registry lookups, #915 SCC finalize, #919 ScopeExtractor) wire in later. Each index follows the same shape: - build function: flat input list → frozen immutable index - public interface: readonly Map + get/has/size accessors - first-write-wins on id/filePath collisions (upstream bug signal) - pure, side-effect-free, safe to call repeatedly DefIndex — the global "what is this id?" lookup gitnexus-shared/src/scope-resolution/def-index.ts buildDefIndex(defs: readonly SymbolDefinition[]): DefIndex byId: ReadonlyMap<DefId, SymbolDefinition> Consumed by Registry.lookup (#917) to materialize DefId[] hits back to full SymbolDefinition records. ModuleScopeIndex — `filePath → moduleScopeId` for cross-file hops gitnexus-shared/src/scope-resolution/module-scope-index.ts buildModuleScopeIndex(entries): ModuleScopeIndex byFilePath: ReadonlyMap<string, ScopeId> Consumed by the SCC finalize link pass (#915) to resolve ImportEdge.targetFile to a concrete module scope in constant time. QualifiedNameIndex — cross-kind qualified-name fast path gitnexus-shared/src/scope-resolution/qualified-name-index.ts buildQualifiedNameIndex(defs: readonly SymbolDefinition[]): QualifiedNameIndex byQualifiedName: ReadonlyMap<string, readonly DefId[]> Returns DefId[] (not a single DefId) because partial classes, method overloads, and cross-kind collisions can legitimately share a qualifiedName. Callers filter by acceptedKinds at the lookup site. Consumed by Registry.lookup qualified fast path + resolveTypeRef dotted fallback (#916, #917). Barrel re-exports added to gitnexus-shared/src/index.ts so consumers import from 'gitnexus-shared' rather than deep paths. Tests (gitnexus/test/unit/scope-resolution/, 23 total): def-index.test.ts (6): empty, single def, multiple distinct, first-write-wins collision, missing id returns undefined, byId direct iteration module-scope-index.test.ts (6): empty, single entry, multiple files, first-write-wins on duplicate filePath, missing returns undefined, byFilePath direct iteration qualified-name-index.test.ts (11): empty, single qnamed def, partial classes accumulate, input-order preservation, qname separation, skip undefined/empty qname, pair dedup, cross-kind indexing, frozen-empty-array on miss, direct iteration Verification: - gitnexus-shared + gitnexus build clean (tsc + scripts/build.js) - test/unit/scope-resolution: 23/23 pass - model + shadow + scope-resolution combined: 129/129 pass - No runtime consumer wiring yet — indexes are standalone library functions that #915, #917, #919 will import when ready Depends on #910 (SymbolDefinition, DefId, ScopeId types — already on main). Unblocks #915 (finalize algorithm), #917 (Registry.lookup), #919 (ScopeExtractor materialization).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
CI Report✅ All checks passed Pipeline Status
Test Results
✅ All 6560 tests passed 97 test(s) skipped — expand for details
Code CoverageTests
📋 View full run · Generated by CI |
|
@claude Act as a senior reviewer for GitNexus. Your job is to determine whether this PR is production-ready for this repo, not to give a generic code review. You are reviewing a PR in the GitNexus monorepo:
Your task has 2 phases, in this exact order: PHASE 1 — DEFINE THE BAR PHASE 2 — REVIEW THE PR AGAINST THAT BAR CONTEXT TO LOAD FIRST
Additional context:
PRIMARY OBJECTIVE Do not optimize for completeness at the expense of signal. REVIEW RULES
For each finding, assign one severity:
REPO-SPECIFIC REVIEW CHECKLIST 1. Correctness & functional completenessCheck:
2. Code clarity & clean codeCheck:
3. Test coverage & change safetyEvaluate against TESTING.md:
4. PerformanceInspect for:
5. Operational riskCheck:
6. MaintainabilityCheck:
NON-NEGOTIABLES TO VERIFY
OUTPUT FORMAT Production-ready bar for this PRGive a concise repo-specific definition in 5–10 bullets. FindingsFor each finding, use this structure exactly: [BLOCKING|NON-BLOCKING|NIT] Short title
Only include findings that are real and supported.
What I could not fully verifyList any behavior you could not prove from the diff, tests, or available context. Final verdictChoose exactly one:
If verdict is not ready, list the blocking items in priority order. IMPORTANT REVIEW BEHAVIOR
You must also ensure we are on track with the RFC plan! Check the issue tickets involved! |
|
Claude finished @magyargergo's task in 3m 15s —— View job PR Review: feat(shared): DefIndex / ModuleScopeIndex / QualifiedNameIndex (#913)Tasks
Production-ready bar for this PRThis PR ships pure shared-package index types + build functions in
Findings1. Correctness & functional completenessNo issues found in this area based on the diff and reviewed context. All three contracts verified:
2. Code clarity & clean codeNo issues found in this area based on the diff and reviewed context.
NIT —
|
| Check | Status |
|---|---|
| No secrets / machine paths | ✅ |
| No blind renames | ✅ (pure additions) |
| PR title: conventional commit | ✅ feat(shared): ... |
| PolyForm license untouched | ✅ |
| CI: tsc + tests | ✅ 6560/6560 pass |
| HIGH/CRITICAL impact addressed | ✅ (no shared symbol modifications) |
RFC #909 Ring plan check
| Ring | Issue | Status |
|---|---|---|
| Ring 1 | #910 scope types, #911 LanguageProvider hooks | ✅ merged |
| Ring 2 SHARED | #913 indexes (this PR) | ⏳ this PR |
| Ring 2 SHARED | #918 shadow diff/aggregate | ✅ merged |
| Ring 2 SHARED | #912 ScopeTree | pending (not blocking #913) |
| Ring 2 consumers | #915 SCC finalize, #917 Registry.lookup, #919 ScopeExtractor | pending (consume this PR) |
This PR correctly ships indexes independently of #912 (ScopeTree) by taking flat inputs rather than a tree — intentional and correctly stated in the PR description. Plan is on track.
What I could not fully verify
filePathnormalization contract — whether RING2-SHARED-4: SCC-aware finalize algorithm with bounded fixpoint #915's SCC finalize will feed paths with the same separator convention that callers ofModuleScopeIndex.get()will use. Unverifiable without RING2-SHARED-4: SCC-aware finalize algorithm with bounded fixpoint #915's diff.\0separator safety inQualifiedNameIndexpair keys —DefIdisstringwith no enforcement against null bytes in the type system. In practice nodeIds are constructed from file paths + identifiers + positions and would never contain\0, but this is an undocumented assumption (qualified-name-index.ts:54).- Downstream consumer behavior — whether RING2-SHARED-6: ClassRegistry / MethodRegistry / FieldRegistry + evidence composition #917, RING2-SHARED-4: SCC-aware finalize algorithm with bounded fixpoint #915, RING2-PKG-1: ScopeExtractor driver (tree-sitter + provider hooks → shared ScopeTree) #919 will filter
QualifiedNameIndexresults byacceptedKindsas expected. Only verifiable when those PRs land.
Final verdict
✅ Ready to merge — no blocking issues.
The implementation is correct, clean, well-tested, RFC-aligned, and purely additive. CI is green. Two NITs (rename freezeIndex or add Object.freeze, add hit-path frozen-bucket test) are valid but not merge-blocking. The filePath normalization concern should be documented before #915 lands.
…yanpatwari#913, RFC abhigyanpatwari#909 Ring 2 SHARED) (abhigyanpatwari#958) Three flat O(1) indexes + pure build functions over per-file artifacts. Contract-only; no runtime behavior change yet — consumers (abhigyanpatwari#917 Registry lookups, abhigyanpatwari#915 SCC finalize, abhigyanpatwari#919 ScopeExtractor) wire in later. Each index follows the same shape: - build function: flat input list → frozen immutable index - public interface: readonly Map + get/has/size accessors - first-write-wins on id/filePath collisions (upstream bug signal) - pure, side-effect-free, safe to call repeatedly DefIndex — the global "what is this id?" lookup gitnexus-shared/src/scope-resolution/def-index.ts buildDefIndex(defs: readonly SymbolDefinition[]): DefIndex byId: ReadonlyMap<DefId, SymbolDefinition> Consumed by Registry.lookup (abhigyanpatwari#917) to materialize DefId[] hits back to full SymbolDefinition records. ModuleScopeIndex — `filePath → moduleScopeId` for cross-file hops gitnexus-shared/src/scope-resolution/module-scope-index.ts buildModuleScopeIndex(entries): ModuleScopeIndex byFilePath: ReadonlyMap<string, ScopeId> Consumed by the SCC finalize link pass (abhigyanpatwari#915) to resolve ImportEdge.targetFile to a concrete module scope in constant time. QualifiedNameIndex — cross-kind qualified-name fast path gitnexus-shared/src/scope-resolution/qualified-name-index.ts buildQualifiedNameIndex(defs: readonly SymbolDefinition[]): QualifiedNameIndex byQualifiedName: ReadonlyMap<string, readonly DefId[]> Returns DefId[] (not a single DefId) because partial classes, method overloads, and cross-kind collisions can legitimately share a qualifiedName. Callers filter by acceptedKinds at the lookup site. Consumed by Registry.lookup qualified fast path + resolveTypeRef dotted fallback (abhigyanpatwari#916, abhigyanpatwari#917). Barrel re-exports added to gitnexus-shared/src/index.ts so consumers import from 'gitnexus-shared' rather than deep paths. Tests (gitnexus/test/unit/scope-resolution/, 23 total): def-index.test.ts (6): empty, single def, multiple distinct, first-write-wins collision, missing id returns undefined, byId direct iteration module-scope-index.test.ts (6): empty, single entry, multiple files, first-write-wins on duplicate filePath, missing returns undefined, byFilePath direct iteration qualified-name-index.test.ts (11): empty, single qnamed def, partial classes accumulate, input-order preservation, qname separation, skip undefined/empty qname, pair dedup, cross-kind indexing, frozen-empty-array on miss, direct iteration Verification: - gitnexus-shared + gitnexus build clean (tsc + scripts/build.js) - test/unit/scope-resolution: 23/23 pass - model + shadow + scope-resolution combined: 129/129 pass - No runtime consumer wiring yet — indexes are standalone library functions that abhigyanpatwari#915, abhigyanpatwari#917, abhigyanpatwari#919 will import when ready Depends on abhigyanpatwari#910 (SymbolDefinition, DefId, ScopeId types — already on main). Unblocks abhigyanpatwari#915 (finalize algorithm), abhigyanpatwari#917 (Registry.lookup), abhigyanpatwari#919 (ScopeExtractor materialization).
Closes #913. Part of RFC #909 Ring 2 SHARED.
Three flat O(1) indexes + pure build functions over per-file artifacts. Contract-only; no runtime wiring yet — consumers (#915 SCC finalize, #917 Registry lookups, #919 ScopeExtractor materialization) import when they land.
What ships
DefIndexDefId → SymbolDefinitionmaterializationModuleScopeIndexfilePath → moduleScopeIdfor cross-file hopsQualifiedNameIndexqualifiedName → DefId[]cross-kind fast pathresolveTypeRefdotted fallbackEach follows the same shape:
buildXIndex(flatInput): XIndex— pure function, side-effect-freereadonlyMap +get/has/sizeaccessorsDesign decisions
Decoupled from
ScopeTree(which doesn't exist yet — #912). Each index takes a flat input (SymbolDefinition[]or{ filePath, moduleScopeId }[]) rather than a scope tree. #919'sScopeExtractoror #915's finalize algorithm will flatten their state into these inputs when they're ready. #913 ships independently.QualifiedNameIndexstoresDefId[], not a singleDefId. Partial classes (C#), method overloads sharing a qname, and accidental cross-kind collisions can legitimately share a qualified name. Callers atRegistry.lookupfilter the returned array byacceptedKindsand rank the survivors.First-write-wins on collisions.
DefIdisnodeId(unique by construction), so a collision means upstream parsed the same symbol twice. Dropping the later record preserves the first-stable id the pipeline may already reference — easier to debug than silent overwrite.QualifiedNameIndexpair-dedup. Same(qname, DefId)appearing twice in the input contributes once. DistinctDefIds sharing aqnameaccumulate in input order for deterministic ranking.Tests — 23 in
gitnexus/test/unit/scope-resolution/def-index.test.ts (6): empty, single def, multiple distinct, first-write-wins collision, missing id → undefined, direct
byIditeration.module-scope-index.test.ts (6): empty, single entry, multiple files, first-write-wins on duplicate filePath, missing → undefined, direct iteration.
qualified-name-index.test.ts (11): empty, single qnamed def, partial classes accumulate, input-order preservation, qname separation, skip undefined/empty qname, pair dedup, cross-kind indexing, frozen-empty-array on miss, direct iteration.
Verification
gitnexus-shared+gitnexusbuild clean (tsc+scripts/build.js)test/unit/scope-resolution: 23/23 passtest/unit/model + test/unit/shadow + test/unit/scope-resolutioncombined: 129/129 pass — no regressionsUnblocks
Registry.lookupimplementations) — now hasDefIndex.getfor materializing DefId hits +QualifiedNameIndexfor the qualified fast pathModuleScopeIndexfor the O(1) file → moduleScope lookup in the link passScopeExtractordriver) — now has a target shape for its materialization outputTest plan
gitnexus-sharedbuild (cd gitnexus-shared && npm run build)gitnexusfull build (cd gitnexus && node scripts/build.js)vitest run test/unit/scope-resolution)