mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-30 06:42:43 +00:00
12 KiB
12 KiB
Guardrails — GitNexus
Rules for human contributors and AI agents. Complements AGENTS.md (workflows) and CONTRIBUTING.md (PR process).
Scope (least privilege)
- Read: Source, tests, docs, public config as needed.
- Write: Only files required for the fix or feature; no unrelated formatting or refactors.
- Execute: Tests, typecheck, documented CLI commands. No destructive commands on user data without approval.
- Off-limits: Other people's machines, production deployments you don't own, credentials you lack permission to use.
Maintainer may widen scope per task.
Non-negotiables
- Never commit secrets — API keys, tokens, real
.envvalues, private URLs, session cookies. Use.env.examplewith placeholders. - Never rename with find-and-replace in GitNexus-indexed projects — use
renamewithdry_run: truefirst (omittingdry_runalso previews), review exact graph-backed semantic spans and coverage, then apply withrenameanddry_run: false. Unsupported targets fail closed; inspect and refactor them manually with language-aware tools. No separategitnexus renameCLI exists. - Run impact analysis before editing shared symbols —
impact(upstream) for functions/classes/methods others call. Do not ignore HIGH/CRITICAL without maintainer sign-off. - Run
detect_changesbefore commit — confirm diffs map to expected symbols/processes when the graph is available. - Preserve embeddings — plain
npx gitnexus analyzenow preserves any embeddings recorded in the index metadata (.gitnexus/gitnexus.json, mirrored to the legacymeta.json) — the previous behavior wiped them. Use--embeddingsto also generate vectors for new/changed nodes; use--drop-embeddingsonly when an explicit wipe is intended (e.g., model swap). - Never
terminate()a worker that may be inside a native call — killing a worker thread mid-N-API aborts the entire process (Napi::Error→std::terminate→ SIGABRT, #2432), so a timeout meant to trigger a graceful fallback takes the whole run down instead. Any worker running native code (tree-sitter grammars, LadybugDB, Icebug) must either reach a JS-visible safe point first — the parse pool'sshutdownDrainMshandshake insrc/core/ingestion/workers/worker-pool.ts— or be abandoned withunref()and left to exit on its own. A one-shot worker that ends after a singlepostMessageneeds noterminate()at all: it exits by itself. This bites hardest on the path you cannot test locally, because the abort only reproduces once the native module actually loads.
Signs (recurring failure patterns)
Format: Trigger → Instruction → Reason. Append new Signs when the same mistake repeats.
Stale graph after edits
- Trigger: MCP warns index is behind
HEAD, or search doesn't match latest commit. - Do:
npx gitnexus analyze(plus--embeddingsif used). Runs incrementally by default — the pipeline parses every file every run (cross-file resolution requires it), but tree-sitter dispatch is skipped for unchanged file chunks via the content-addressed cache, and only changed-file rows (plus their importers, transitively) are rewritten in LadybugDB. When the effective write set exceeds ~50% of the repo's files (minimum 50 files), the run transparently switches to the full wipe + bulk-COPY write plan and logs "switching to a full DB write" — expected behavior, not a bug, and file-level bookkeeping stays incremental. That same line also appears — regardless of write-set size, even for a one-file change — when a LadybugDB extension the existing index depends on cannot load on this machine (VECTOR, #2623; FTS, #2841), because a DB carrying those indexes refuses all row-level DML until the extension is loaded; rungitnexus doctorfor live extension status and re-run withGITNEXUS_LBUG_EXTENSION_INSTALL=auto(with network access) to allow one bounded install attempt. The rebuild is one-shot: it clears the indexes, so the next run goes back to the incremental plan. - Why: Tools query LadybugDB from last analyze; git changes are invisible until re-indexed.
Index seems corrupt or "incremental" is misbehaving
- Trigger:
analyzeproduces unexpected results, orincrementalInProgressis set in the index metadata (.gitnexus/gitnexus.json/ legacymeta.json), or the index is in a half-state after a crash. - Do:
npx gitnexus analyze --forceto rebuild the graph and FTS indexes. This may reuse unchanged parser output; when debugging parser/capture changes, usenpx gitnexus analyze --no-parse-cacheto rebuild that output too. The dirty-flag check forces the graph rebuild automatically when a previous incremental run didn't complete cleanly. A dirty-flag recovery rebuild parks the interrupted run's sidecars beside the DB aslbug.wal.dirty-recovery/lbug.shadow.dirty-recoveryfor post-mortem debugging — harmless, and removable withnpx gitnexus clean --lbug-sidecars. Safe to delete the.gitnexus/parse-cache/directory (and any legacy.gitnexus/parse-cache.json) at any time — content-addressed, will be regenerated. - Why: Incremental writeback is selective DB row replacement; if the on-disk state is inconsistent for any reason, a full rebuild is the cheapest path back to a known-good index.
Embeddings vanished after analyze
- Trigger: Semantic search quality drops;
stats.embeddingsin the index metadata (gitnexus.json/ legacymeta.json) is 0 after refresh. - Do: Re-run
npx gitnexus analyze --embeddingsto regenerate. Check the analyze log for aWarning: could not load cached embeddingsline — if present, the cache restore failed (corrupt DB / schema mismatch) and the rebuild had nothing to preserve. If you intentionally passed--drop-embeddings, this is expected. - Why: Plain
analyzepreserves prior vectors by re-inserting them after the rebuild; ways to end up at zero include an explicit--drop-embeddings, a cache-load failure (now logged), or a model/dimension change that invalidates the cache — but zero is no longer the only embedding-loss signature to watch for; see the Sign below for the non-zero, partial-failure case. A dirty-recovery run that cannot move the crashed WAL aside now either discards it (logged: forensics lost, embeddings still preserved) or fails fast with a lock error naming the holder — it never silently zeroes embeddings.
Analyze finishes but embeddings are incomplete (partial embedding index)
- Trigger:
npx gitnexus statusreportsincompleteReasons: ["embedding-checkpoint-pending"](or the human-readable "Index incomplete reasons" line);stats.embeddingsis honest and non-zero, and the preceding analyze log showed aWarning: N node(s) lost their embeddings to embedding-endpoint failuresline (#2790). - Do: Re-run plain
npx gitnexus analyze— no--embeddingsflag needed. A retainedembeddingCheckpointin the index metadata forces embedding generation for exactly the pending nodes regardless of flags, and clears once they succeed.--drop-embeddingsabandons the pending nodes instead of retrying them;--forcealso discards the checkpoint (with a warning) and rebuilds without resuming it. - Why: A long analyze run against a flaky HTTP embedding endpoint tolerates bounded sub-batch failures instead of aborting the whole run: it deletes the affected nodes' embedding rows (so they hold zero rows, never a partial set) and records those nodes as pending in
embeddingCheckpoint.stats.embeddingsstays an honest, non-zero count of everything that did succeed, so this state never trips the "Embeddings vanished" Sign above —embedding-checkpoint-pendingis the only reliable signal.
Scope extraction is incomplete
- Trigger:
npx gitnexus statusreportsincompleteReasons: ["scope-extraction-failed"]when files were omitted, orincompleteReasons: ["scope-extraction-unverified"]when the index predates the completeness receipt or its metadata is unreadable.impact/contextreports the same uncertainty asepistemic: "lower-bound"; confirmed omissions setcauses.scopeExtractionFiles > 0. - Do: Re-run
npx gitnexus analyze(--forcefor a full graph rebuild). If the reason persists, inspect the scope-extraction warnings and treat impact counts as floors until the affected source is supported or corrected. - Why: Parsing continued, but scope captures for the reported file count could not be produced even after the main-thread fallback. Calls, inheritance, imports, or accesses originating there may therefore be absent from the graph.
Analyze reports INCOMPLETE with a collapsed graph write
- Trigger: Analysis rejects a staged graph write with expected and persisted relationship counts, or an in-place run prints
Repository indexed INCOMPLETELY, exits nonzero, and recordsincompleteReasons: ["graph-write-collapsed"]. - Do: Inspect COPY errors, available memory, and free disk space on the volume holding
.gitnexus/; confirm no secondanalyzeis running against the same repo, then runnpx gitnexus doctor. For native buffer-pool exhaustion, see RUNBOOK.md forGITNEXUS_LBUG_BUFFER_POOL_SIZEand memory-budget guidance. Re-runnpx gitnexus analyze --forceafter addressing the cause. - Why: Far fewer relationships are readable back than the pipeline produced. A staged build throws before publication and preserves the previous index, if any. In-place writes cannot roll back, so the incomplete stamp and nonzero exit prevent a partial graph from being presented as successful. Recognized buffer exhaustion also throws immediately during COPY or fallback inserts. The collapse check compares in-memory totals (including streamed rows) against the post-write count, stays unmeasurable when the count cannot be read, and is skipped on incremental runs where whole-scope counts are not comparable.
MCP lists no repos
- Trigger: MCP stderr says no indexed repos.
- Do:
npx gitnexus analyzein the target repo; verifynpx gitnexus listshows it. - Why: MCP discovers repos via
~/.gitnexus/registry.json, populated by analyze.
Wrong repo in multi-repo setups
- Trigger: Query/impact results belong to another project.
- Do: Confirm an MCP default is configured or the GitNexus process was launched inside the intended registered path without crossing into an unindexed nested Git checkout. Otherwise call
list_repos, then passrepoon subsequent tools; pass it for mutating tools when multiple repos are registered and no MCP default exists. - Why: Read-only tools derive their default from MCP configuration or a process cwd that stays within one registered Git boundary. Outside those paths the target remains ambiguous, and mutating tools stay explicit unless configuration supplies the target.
LadybugDB lock / "database busy"
- Trigger: Errors opening
.gitnexus/lbugwhile MCP and analyze both run. - Do: Stop overlapping processes (one writer at a time). Retry analyze or restart MCP.
- Why: Embedded DB expects single-process ownership.
@ladybugdb/core0.18.0 also reports this contention as"Only one write transaction at a time is allowed in the system."— our busy/lock retry matcher (isDbBusyErrorinsrc/core/lbug/lbug-config.ts) recognizes this exact string too, so it's auto-retried the same as any other lock error. If you see that exact message, it's the same "one writer at a time" issue above, not a new failure mode.
Publishing & supply chain
- npm: Do not publish from unreviewed automation. Bump version intentionally; tag releases to match
package.json. - Dependencies: Minimal, auditable
package.jsonchanges; run tests and CI after lockfile updates. - License: PolyForm Noncommercial 1.0.0 — do not relicense without maintainer approval.
Escalation
Stop and ask a human maintainer when:
- Impact analysis shows HIGH/CRITICAL risk and the task still requires the change.
- You need to alter CI, release, or security-sensitive config.
- Requirements conflict (e.g. "speed up analyze" vs "must keep all embeddings on huge repo").
- You are unsure whether data loss is acceptable (
clean, forced migrations, schema changes).
Related docs
- ARCHITECTURE.md — components and data flow
- RUNBOOK.md — commands for recovery
- CONTRIBUTING.md — PR and commit expectations