GUARDRAILS.md
Rules for human contributors and AI agents. Complements AGENTS.md (workflows) and CONTRIBUTING.md (PR process).
Maintainer may widen scope per task.
.env values, private URLs, session cookies. Use .env.example with placeholders.rename MCP tool with dry_run: true first, review graph vs text_search edits. No separate gitnexus rename CLI exists.impact (upstream) for functions/classes/methods others call. Do not ignore HIGH/CRITICAL without maintainer sign-off.detect_changes before commit — confirm diffs map to expected symbols/processes when the graph is available.npx gitnexus analyze now preserves any embeddings recorded in the index metadata (.gitnexus/gitnexus.json, mirrored to the legacy meta.json) — the previous behavior wiped them. Use --embeddings to also generate vectors for new/changed nodes; use --drop-embeddings only when an explicit wipe is intended (e.g., model swap).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's shutdownDrainMs handshake in src/core/ingestion/workers/worker-pool.ts — or be abandoned with unref() and left to exit on its own. A one-shot worker that ends after a single postMessage needs no terminate() 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.Format: Trigger → Instruction → Reason. Append new Signs when the same mistake repeats.
HEAD, or search doesn't match latest commit.npx gitnexus analyze (plus --embeddings if 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; run gitnexus doctor for live extension status and re-run with GITNEXUS_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.analyze produces unexpected results, or incrementalInProgress is set in the index metadata (.gitnexus/gitnexus.json / legacy meta.json), or the index is in a half-state after a crash.npx gitnexus analyze --force to rebuild from scratch. The dirty-flag check forces this automatically when a previous incremental run didn't complete cleanly, but --force is the manual escape hatch. A dirty-flag recovery rebuild parks the interrupted run's sidecars beside the DB as lbug.wal.dirty-recovery / lbug.shadow.dirty-recovery for post-mortem debugging — harmless, and removable with npx 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.stats.embeddings in the index metadata (gitnexus.json / legacy meta.json) is 0 after refresh.npx gitnexus analyze --embeddings to regenerate. Check the analyze log for a Warning: could not load cached embeddings line — 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.analyze preserves 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.npx gitnexus status reports incompleteReasons: ["embedding-checkpoint-pending"] (or the human-readable "Index incomplete reasons" line); stats.embeddings is honest and non-zero, and the preceding analyze log showed a Warning: N node(s) lost their embeddings to embedding-endpoint failures line (#2790).npx gitnexus analyze — no --embeddings flag needed. A retained embeddingCheckpoint in the index metadata forces embedding generation for exactly the pending nodes regardless of flags, and clears once they succeed. --drop-embeddings abandons the pending nodes instead of retrying them; --force also discards the checkpoint (with a warning) and rebuilds without resuming it.embeddingCheckpoint. stats.embeddings stays an honest, non-zero count of everything that did succeed, so this state never trips the "Embeddings vanished" Sign above — embedding-checkpoint-pending is the only reliable signal.npx gitnexus status reports incompleteReasons: ["graph-write-collapsed"]; the analyze summary printed Repository indexed INCOMPLETELY naming an expected and a persisted relationship count, and the CLI exited non-zero.npx gitnexus analyze --force. If it recurs, check free disk space on the volume holding .gitnexus/, confirm no second analyze is running against the same repo (both stage through .gitnexus/csv), then run npx gitnexus doctor.incremental-in-progress and embedding-checkpoint-pending, which describe a run that did what it said and left work for next time, this one means most of your edges are gone, so it is the one incomplete reason that also fails the exit code. The check compares in-memory totals (including rows streamed out of the heap) against the post-write count, refuses to answer when the count cannot be read, and is skipped on incremental runs where whole-scope counts are not comparable.npx gitnexus analyze in the target repo; verify npx gitnexus list shows it.~/.gitnexus/registry.json, populated by analyze.list_repos, then pass repo on subsequent tools..gitnexus/lbug while MCP and analyze both run.@ladybugdb/core 0.18.0 also reports this contention as "Only one write transaction at a time is allowed in the system." — our busy/lock retry matcher (isDbBusyError in src/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.package.json.package.json changes; run tests and CI after lockfile updates.Stop and ask a human maintainer when:
clean, forced migrations, schema changes).