* Initial plan * refactor: move language-specific container node logic into LanguageProvider - Add resolveEnclosingOwner hook to LanguageProviderConfig - Add staticOwnerTypes to MethodExtractionConfig - Implement Ruby resolveEnclosingOwner (singleton_class → class/module) - Replace hardcoded STATIC_OWNER_TYPES with config.staticOwnerTypes - Move Ruby static types to rubyMethodConfig - Move Kotlin static types to kotlinMethodConfig - Remove Ruby singleton_class branch from findEnclosingClassInfo - Collapse seqFindEnclosingClassNode/seqFindRawEnclosingContainerNode into single provider-aware seqFindEnclosingOwnerNode - Update worker path to pass provider.resolveEnclosingOwner Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/bc9f9d4d-f749-4872-9ff2-17fc86e08787 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * test: add regression tests for config-driven staticOwnerTypes and resolveEnclosingOwner hook Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/bc9f9d4d-f749-4872-9ff2-17fc86e08787 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * refactor: implement DAG-based pipeline architecture with phase extraction Restructure the ingestion pipeline from a ~1800-line monolithic orchestrator into a DAG (Directed Acyclic Graph) of named phases with explicit dependencies. New files under pipeline-phases/: - types.ts: PipelinePhase, PipelineContext, PhaseResult contracts - runner.ts: DAG runner with topological sort validation - scan.ts, structure.ts, markdown.ts, cobol.ts: early phases - parse.ts + parse-impl.ts: chunked parse + resolve (the core) - routes.ts, tools.ts, orm.ts: post-parse enrichment phases - cross-file.ts + cross-file-impl.ts: cross-file binding propagation - mro.ts, communities.ts, processes.ts: graph analysis phases - index.ts: barrel export pipeline.ts reduced from ~1960 lines to ~184 lines: - DAG phase array declaration - runPipelineFromRepo as thin orchestrator - topologicalLevelSort retained for backward compat Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/136bf9c3-2f4f-449b-9fff-001332c8371c * test: add DAG runner unit tests, update ARCHITECTURE.md with phase DAG docs Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/136bf9c3-2f4f-449b-9fff-001332c8371c * fix: address code review - pass resolutionContext through parse output, fix worker URL path Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/136bf9c3-2f4f-449b-9fff-001332c8371c * fix: declare transitive parse dependency explicitly in mro/communities/processes phases Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/136bf9c3-2f4f-449b-9fff-001332c8371c * refactor: improve pipeline-phases clean code and folder structure - Extract synthesizeWildcardImportBindings to wildcard-synthesis.ts - Extract extractORMQueriesInline to orm-extraction.ts - Create shared constants.ts for AST_CACHE_CAP - Fix inline type import in orm.ts (use proper top-level import) - Add comprehensive JSDoc to getPhaseOutput explaining type safety - Move isDev to module level in cross-file.ts (consistency) - Improve module-level documentation across files - Organize barrel exports in index.ts with section comments Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/2bd6d4aa-6271-4009-8dd2-332ea8ec73ab Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * address review feedback: fix circular dep, allFetchCalls mutation, progress bugs, remove DAG naming, extract isDev, fix _item naming, fix O(n²) line calc Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/6cf53c9b-d55d-4c6f-bf3d-7bfb82d512b6 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * improve JSDoc on lineNumberAtOffset binary search Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/6cf53c9b-d55d-4c6f-bf3d-7bfb82d512b6 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * address review: filter deps in runner, move totalFiles to ctx, fix cycle JSDoc, centralize isDev, remove DAG naming Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/b388424f-b939-4a94-97de-3855f9465564 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * fix doc consistency in graph-sort.ts module-level and function-level JSDoc Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/b388424f-b939-4a94-97de-3855f9465564 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * fix(pipeline): wrap phase errors with phase name and emit terminal error progress event Restores phase diagnostics at CLI/MCP boundary. runPipeline now wraps phase.execute() in try/catch and rethrows with 'Phase <name> failed: ...' preserving the original via { cause }. Also emits a terminal { phase: 'error' } progress event so subscribers see the failure before the rejection propagates. Handler errors during error reporting are swallowed to keep the original cause authoritative. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U1) * fix(pipeline): move bindingAccumulator dispose into crossFile try/finally; make single-use crossFile.execute() now wraps its body in try/finally so the accumulator is released on both the happy path and when runCrossFileBindingPropagation throws. Dev-mode telemetry stays inside the try block before dispose (all three counters return 0 after dispose clears internal maps). BindingAccumulator becomes single-use: appendFile after dispose now throws 'BindingAccumulator: use after dispose' instead of silently re-animating via the old _disposed auto-clear. Docs updated; the only production construction site (parse-impl) always creates a fresh instance per run, so no caller relied on the re-use contract. Residual risk documented in crossFile module JSDoc: a future phase inserted between parse and crossFile that throws would still leak the accumulator. Any such phase must manage accumulator lifetime explicitly. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U2) * docs(pipeline): explain why importCtx teardown is safe before crossFile Investigation (plan U3) confirms: `importCtx` (ImportResolutionContext) is a scratch workspace with no downstream consumer after parse. `resolutionContext` (returned to crossFile) is a distinct object that owns importMap / namedImportMap / packageMap / moduleAliasMap / model, and never closes over importCtx. cross-file-impl consumes only that ctx via processCalls. The two confusingly-similar "context" names were the root of the adversarial reviewer's concern — comment locks in the invariant so the next reader sees it. No behavioral change. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U3) * refactor(pipeline): remove ctx.totalFiles side-channel; promote to ParseOutput totalFiles was a hidden mutable field on PipelineContext written by parse and read by mro/communities/processes — five reviewers flagged this as a violation of the immutable-context invariant. Removed from PipelineContext, which is now fully readonly, and made the implicit temporal dep explicit: mro/communities/processes now declare 'parse' as a dep and read totalFiles via getPhaseOutput<ParseOutput>(...). No behavior change. Topo-sort unchanged because parse was already a transitive dep through crossFile. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U4) * feat(method-extractor): runtime staticOwnerTypes guard at factory chokepoint createMethodExtractor now rejects MethodExtractionConfigs that list companion_object / singleton_class / object_declaration in typeDeclarationNodes but omit the matching entry from staticOwnerTypes. Fails loudly at provider construction time instead of producing silent isStatic=false on the 50000th file analyzed. Opt-out convention preserved: an explicit `new Set()` (empty Set) signals intentional exclusion and passes the guard (memory obs #30588). All 13 existing language configs pass the guard; the new negative test fails without it. Test-first. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U5) * fix(pipeline): wrap sequential-fallback in try/finally so cleanup survives throws The sequential-fallback block in runChunkedParseAndResolve now runs inside a try/finally that guarantees astCache.clear(), accumulator finalize, and enrichExportedTypeMap execute even if readFileContents or processCalls throws mid-fallback. Cleanup failures are caught inside the finally so they can't mask the original error. Accumulator disposal ownership remains with crossFile (U2) — U6 only adds astCache cleanup and preserves finalize ordering on the error path. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U6) * test(pipeline): direct unit coverage for wildcard-synthesis and cross-file-impl Both modules previously had zero direct unit coverage — branches were exercised only through integration tests' happy paths. wildcard-synthesis.test.ts covers: Go graph-IMPORTS fallback, Python moduleAliasMap build, MAX_SYNTHETIC_BINDINGS_PER_FILE cap, dedup against existing namedImportMap entries, and empty-exportedSymbols early return. cross-file-impl.test.ts covers: gapRatio below threshold no-op, MAX_CROSS_FILE_REPROCESS cap, graph-only exportedTypeMap fallback, and empty namedImportMap short-circuit. Tests assert current behavior — any future regression flips them. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U7) * test(pipeline): golden-file graph-parity regression guard on mini-repo fixture Pins the current post-P1/P2 graph output (57 symbols, 92 relationships, 4 processes, deterministic edge digest) so future silent refactors cannot drift behavior unnoticed. If any count changes or any edge rewires, the test fails with a readable diff listing what changed and a copy-pasteable UPDATE_GOLDEN=1 regen command. Edge digest keyed by symbolic (label, name, filePath) triples rather than raw generateId output — stays meaningful across id-encoding refactors while still catching real semantic rewiring. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U8) * fix(pipeline): minimal cycle reporting + resolveEnclosingOwner loop safeguards U9: runner cycle detection now reports only the SCC members via DFS back-edge trace ('Cycle detected: A -> B -> C -> A') rather than everything with inDegree > 0 (which mixed cycle members with blocked dependents). Also emits the 'error' progress event for graph- validation failures, symmetric with U1's runtime-error path. U16: findEnclosingClassInfo now defends against language-provider hooks that return non-container nodes — visitedContainers Set breaks repeat-visit loops, MAX_ENCLOSING_WALK_ITERATIONS is belt-and-braces. Documented the hook contract invariant so future provider authors know the walk-continues-upward expectation. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U9, U16) * refactor(pipeline): type hygiene, dead code cleanup, shared allPathSet, graph-sort naming Bundles plan units U10, U11, U12, U14, U15: U10 — Type hygiene: readonly ParseOutput arrays (allExtractedRoutes, allDecoratorRoutes, allToolDefs, allORMQueries, allPaths); removed redundant 'as string[] | undefined' cast in routes.ts and 'as URL' in parse-impl.ts; WorkerPool is now 'import type'. Readonly contract propagated into processORMQueries (only iterates). U11 — Dead code & shims: deleted constants.ts shim (AST_CACHE_CAP inlined into its sole real consumer cross-file-impl.ts; isDev consumers now import directly from ../utils/env.js). Removed internal utility re-exports from pipeline-phases/index.ts (no external consumers). Removed topologicalLevelSort re-export from pipeline.ts; updated topological-sort.test.ts to import from the canonical utils/graph-sort.js. Stripped 'Phase 3+4:' stale JSDoc from parse-impl.ts. U12 — Perf: StructureOutput now carries allPathSet (ReadonlySet<string>) built once; cobol, markdown, and cross-file-impl consume the shared set instead of allocating their own. Parse forwards it via ParseOutput.allPathSet; processCobol/processMarkdown widened to ReadonlySet<string>. U14 — graph-sort.ts: renamed local 'inDegree' to 'pendingImportsPerFile' with expanded JSDoc explaining the reverse- graph Kahn's formulation and warning future maintainers not to 'correct' it to standard in-degree semantics. Added self-edge test. U15 — Unconditional worker-fallback logging: removed isDev guard on the worker-pool-creation-failure console.warn so operators can diagnose perf degradations in production. No behavior change. U8 golden-file test confirms pipeline output is byte-identical. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U10, U11, U12, U14, U15) * docs: fix ARCHITECTURE.md table integrity; bump AGENTS.md/CLAUDE.md to 1.3.0 U13 — documentation fixes: ARCHITECTURE.md: the prior insertion of the 'Pipeline Phase DAG' section orphaned 7 rows from the 'Where to change what' header. Moved those 7 rows back up under their header so the table reads contiguously; DAG section now follows the completed table. AGENTS.md + CLAUDE.md: bumped version 1.2.0 -> 1.3.0, updated Last reviewed to 2026-04-13, added matching Changelog row documenting the GitNexus index stats refresh after the DAG refactor. Stat bumps (symbols/relationships/execution flows) that were sitting uncommitted in the working tree are now landed under a proper changelog entry per each file's own documented schema. Plan: docs/plans/2026-04-13-001-fix-pipeline-dag-refactor-review-findings-plan.md (U13) * refactor(pipeline): drop spurious parse deps, true-readonly ParseOutput.exportedTypeMap, skip redundant wildcard synth - mro/communities/processes: switch redundant `parse` dep to `structure` — totalFiles originates in structure, so depending on parse for it was a spurious data dep that obscured the real DAG. - ParseOutput.exportedTypeMap: typed as truly ReadonlyMap<...,ReadonlyMap>>; graph→exports enrichment moved into parse-impl so the snapshot is fully populated at parse return. crossFile builds its own local mutable working copy for per-file re-resolution writes — no cast at the boundary. - parse-impl: hasSynthesized flag guards the unconditional final synthesizeWildcardImportBindings call when per-chunk/fallback synthesis already ran (graph-global + idempotent across chunks). - cross-file-impl: documented the intentional `phase: 'parsing'` progress label so telemetry bucketing stays consistent with the parse phase. - cross-file-impl test: replaced the now-moved fallback-enrichment assertion with a stronger one — crossFile must not mutate the parse-supplied map. Addresses PR #809 review pass 5 carry-overs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
10 KiB
Architecture — GitNexus
This repository is a monorepo with two main products: the CLI / MCP package (gitnexus/) and the browser UI (gitnexus-web/). Supporting folders ship editor integrations and plugins without changing the core graph engine.
Repository layout
| Path | Role |
|---|---|
gitnexus/ |
Published npm package gitnexus: CLI, MCP server (stdio), local HTTP API for bridge mode, ingestion pipeline, LadybugDB graph, embeddings (optional). |
gitnexus-web/ |
Vite + React UI: in-browser indexing (WASM), graph visualization, optional connection to gitnexus serve. |
.claude/, gitnexus-claude-plugin/, gitnexus-cursor-integration/ |
Packaged skills and plugin metadata so agents discover the same workflows as documented in AGENTS.md. |
eval/ |
Evaluation harnesses and docs for benchmarking tool usage. |
.github/ |
CI workflows (quality, unit, integration, E2E) and composite actions. |
End-to-end flow: index → graph → tools
-
Ingestion (
gitnexus analyze)- Entry:
gitnexus/src/cli/analyze.ts→runPipelineFromRepoingitnexus/src/core/ingestion/pipeline.ts. - The pipeline is structured as a DAG (Directed Acyclic Graph) of named phases (see Pipeline Phase DAG below).
- Output is loaded into LadybugDB under
.gitnexus/at the repo root (lbug/,meta.json, etc.). Optional FTS indexes and embeddings attach to the same store. - The repo is registered in
~/.gitnexus/registry.jsonso MCP can find it from any working directory.
- Entry:
-
Persistence & metadata
gitnexus/src/storage/repo-manager.ts— paths, registry, cleanup of legacy Kuzu artifacts.gitnexus/src/core/lbug/lbug-adapter.ts— graph load, queries, embedding restore batches.
-
Query & agents
- MCP (stdio):
gitnexus/src/cli/mcp.ts→startMCPServer→LocalBackend(gitnexus/src/mcp/local/local-backend.ts) opens registered repos and serves tools fromgitnexus/src/mcp/tools.tsand resources fromgitnexus/src/mcp/resources.ts. - Bridge HTTP:
gitnexus/src/cli/serve.ts→ Express app ingitnexus/src/server/api.ts(CORS-limited) exposes REST + MCP-over-HTTP for the web UI. - CLI tools (no MCP):
gitnexus query,context,impact,cypheringitnexus/src/cli/tool.tscall the same backend for scripts and CI.
- MCP (stdio):
-
Staleness
gitnexus/src/mcp/staleness.tscompares indexedlastCommittoHEADand surfaces hints when the graph is behind git.
MCP tools (summary)
| Tool | Purpose |
|---|---|
list_repos |
Discover indexed repositories when more than one is registered. |
query |
Natural-language / keyword search over the graph (hybrid BM25 + optional vectors). |
cypher |
Ad hoc Cypher against the schema (see resource gitnexus://repo/{name}/schema). |
context |
Callers, callees, processes for one symbol (with disambiguation). |
impact |
Blast radius (upstream/downstream) with depth and risk summary. |
detect_changes |
Map git diffs to affected symbols and processes. |
rename |
Graph-assisted rename with dry_run preview (graph vs text_search confidence). |
Where to change what
| If you are changing… | Start in… |
|---|---|
| CLI commands / flags | gitnexus/src/cli/ (index.ts, per-command modules). |
| Parsing or graph construction | gitnexus/src/core/ingestion/pipeline-phases/ (individual phase files), pipeline.ts (orchestrator). |
| Graph schema / DB access | gitnexus/src/core/lbug/ (schema.ts, lbug-adapter.ts), gitnexus/src/mcp/core/lbug-adapter.ts if MCP-specific. |
| MCP protocol, tools, resources | gitnexus/src/mcp/server.ts, tools.ts, resources.ts. |
| Search ranking | gitnexus/src/core/search/ (BM25, hybrid fusion). |
| Embeddings | gitnexus/src/core/embeddings/, phases in analyze.ts. |
| Wiki generation | gitnexus/src/core/wiki/. |
| Web UI behavior | gitnexus-web/src/ (components, workers, graph client). |
| CI | .github/workflows/*.yml, .github/actions/setup-gitnexus/. |
Pipeline Phase DAG
The ingestion pipeline is a DAG of named phases. Each phase is defined in its own file under gitnexus/src/core/ingestion/pipeline-phases/ with explicit dependencies, typed inputs, and typed outputs.
scan → structure → [markdown, cobol] → parse → [routes, tools, orm]
→ crossFile → mro → communities → processes
Phase files
| Phase | File | Dependencies | What it does |
|---|---|---|---|
scan |
scan.ts |
(root) | Walk repo filesystem, collect paths + sizes |
structure |
structure.ts |
scan |
Build File/Folder nodes + CONTAINS edges |
markdown |
markdown.ts |
structure |
Extract headings and cross-links from .md/.mdx |
cobol |
cobol.ts |
structure |
Regex-based COBOL/JCL extraction |
parse |
parse.ts + parse-impl.ts |
structure, markdown, cobol |
Chunked tree-sitter parse, import/call/heritage resolution |
routes |
routes.ts |
parse |
Route registry (Next.js, Expo, PHP, decorator-based) |
tools |
tools.ts |
parse |
MCP/RPC tool detection |
orm |
orm.ts |
parse |
Prisma/Supabase ORM query edges |
crossFile |
cross-file.ts + cross-file-impl.ts |
parse, routes, tools, orm |
Cross-file type propagation in topological order |
mro |
mro.ts |
crossFile |
Method Resolution Order, METHOD_OVERRIDES edges |
communities |
communities.ts |
mro |
Leiden community detection |
processes |
processes.ts |
communities, routes, tools |
Execution flow detection, Route/Tool → Process links |
How to add a new phase
- Create a new file in
pipeline-phases/(e.g.my-phase.ts) - Define a
PipelinePhase<MyOutput>object withname,deps, andexecute(ctx, deps) - Export it from
pipeline-phases/index.ts - Add it to the
buildPhaseList()function inpipeline.ts
// pipeline-phases/my-phase.ts
import type { PipelinePhase, PipelineContext, PhaseResult } from './types.js';
import { getPhaseOutput } from './types.js';
import type { ParseOutput } from './parse.js';
export interface MyPhaseOutput { /* ... */ }
export const myPhase: PipelinePhase<MyPhaseOutput> = {
name: 'myPhase',
deps: ['parse'], // runs after parse completes
async execute(ctx, deps) {
const { allPaths } = getPhaseOutput<ParseOutput>(deps, 'parse');
// ... do work, write to ctx.graph ...
return { /* typed output */ };
},
};
DAG runner
The runner (pipeline-phases/runner.ts) validates the DAG at startup (detects cycles and missing deps via topological sort), then executes phases in dependency order. Each phase receives:
ctx: PipelineContext— shared graph, repoPath, progress callbackdeps: Map<string, PhaseResult>— outputs from all upstream phases
Known limitations
Overloaded method resolution
Method and Constructor node IDs include an arity suffix (#<paramCount>) to
disambiguate overloaded methods. Two overloads with different parameter counts
produce distinct graph nodes: Method:file:Class.method#1 vs
Method:file:Class.method#2.
Same-arity overload disambiguation: When two overloads share the same
parameter count but differ in types (e.g. save(int) vs save(String)), a
type-hash suffix ~type1,type2 is appended to produce distinct node IDs:
Method:file:Class.save#1~int vs Method:file:Class.save#1~String. The suffix
is only added when a same-arity collision is detected within a class and all
parameters have non-null type annotations. Languages without type info (Python,
Ruby, JS) fall back to arity-only IDs. TypeScript/JavaScript overload signatures
are intentionally excluded from type-hashing because they are declaration-only
contracts that should collapse to the implementation body's node ID. See issue
#651.
C++ const-qualified overload disambiguation: Methods overloaded by const
qualification (e.g. begin() vs begin() const) are disambiguated via an
isConst property and a $const ID suffix appended to the const-qualified
variant when a non-const collision exists. The $const suffix appears after the
type-hash suffix: e.g. Method:file:Container.begin#0$const.
Generic/template type preservation in type-hash: The type-hash suffix uses
rawType (full AST text including generic/template args) rather than the
simplified type from extractSimpleTypeName. This means C++ template overloads
like process(vector<int>) vs process(vector<string>) produce distinct IDs:
~vector<int> vs ~vector<std::string>. Java generic overloads like
process(List<String>) vs process(List<Integer>) are a compile error due to
type erasure, so this gap is theoretical for Java.
ID stability on first overload: Type and const tags are collision-only. When
a class has save(int) as its only save method, the ID is save#1 (no tag).
Adding save(String) changes the original to save#1~int. This is correct for
fresh analysis but means IDs are not stable across overload additions. Future
incremental re-analysis should account for this.
Variadic method matching: When one side is variadic (parameterCount
undefined) and the other has a fixed count, METHOD_IMPLEMENTS edges are
emitted with confidence 0.7 instead of 1.0. Variadic methods like
foo(String... args) may superficially match foo(String s) by type but
are not guaranteed to be interchangeable across all languages (Java/Kotlin
accept this via varargs sugar; TypeScript, C#, Rust do not).
Confidence tiering for METHOD_IMPLEMENTS edges:
| Match quality | Confidence | When |
|---|---|---|
| Exact parameter types match | 1.0 | Both sides have parameterTypes arrays and they match |
| Arity (count) matches | 1.0 | Both sides have parameterCount, types unavailable |
| Variadic vs fixed | 0.7 | One side is variadic, other has fixed count |
| Lenient (insufficient info) | 0.7 | One or both sides lack type and count data |
Related docs
- MIGRATION.md — breaking changes and migration guidance.
- RUNBOOK.md — operational commands and recovery.
- GUARDRAILS.md — safety boundaries for humans and agents.
- TESTING.md — how to run tests.
AGENTS.md/CLAUDE.md— agent workflows and tool usage expectations for this repo when indexed by GitNexus.