Skip to content

Mid-session drift refresh gate + embeddings cap#4

Merged
ReidenXerx merged 3 commits into
mainfrom
feat/mid-session-drift-refresh
Jul 12, 2026
Merged

Mid-session drift refresh gate + embeddings cap#4
ReidenXerx merged 3 commits into
mainfrom
feat/mid-session-drift-refresh

Conversation

@ReidenXerx

Copy link
Copy Markdown
Owner

Two agent-effectiveness fixes for the GitNexus enforcement layer.

1. Lift the embeddings cap on refresh (--embeddings 0)

Bare --embeddings applies GitNexus's default 50k-node cap, so on large repos embeddings get skipped → the kit's own missing_embeddings check then wedges a permanent stale loop. --embeddings 0 disables the cap (verified in the GitNexus CLI help: "pass 0 to disable the cap entirely"). Applied to all four analyze scripts.

2. Mid-session drift gate

Staleness was purely commit-based (indexedCommit === HEAD → fresh), so the agent's own uncommitted mid-session edits never marked the index stale — agents only refreshed at trigger events (session start / commit), never during routine work, and graph queries silently ran against a graph that ignored the edits.

  • check-staleness reports driftingFiles = git-dirty source files modified since the index build (mtime > indexedAt); cheap (stats only dirty files) and resets on refresh.
  • classifyMcpDrift blocks graph query tools (query/context/cypher/impact/pdg_query/trace/…) past driftRefreshThreshold (default 3, 0 disables) with a nudge to the fast incremental gitnexus:refresh. Non-query tools (detect_changes, rename, …) + edits/reads/greps are untouched.
  • Wired into the Claude + Cursor MCP guards, fresh phase only. Surfaced in gitnexus:status + a driftRefreshBlocks scorecard counter.

Microscope self-review (pass #1)

5 independent lenses. Fixed: drift wrongly firing in classical_fallback (overriding the escape hatch); a divergent source-ext regex (silently no-drift for .cts/.ex/.clj/…); the drift git status running on the whole hot path; non-ASCII paths, Cursor telemetry, "fast" overclaim. Verified against GitNexus source: --embeddings 0 = disable-cap, and incremental analyze re-hashes on-disk content (so it reindexes uncommitted edits + advances indexedAt).

Tests: 58/58.

🤖 Generated with Claude Code

ReidenXerx and others added 3 commits July 12, 2026 03:07
`--embeddings` with no arg keeps GitNexus's default embedding limit; `0` removes it so
the full symbol set gets vectors. Applied to all four analyze scripts (refresh / full /
pdg / full-pdg) — the ones agent-refresh and the pre-commit hook run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… index

Staleness was purely commit-based (indexedCommit === HEAD → "fresh"), so the uncommitted
edits an agent makes mid-session never marked the index stale. Agents only refreshed at
trigger events (session start / commit), never during routine work — so graph queries
silently ran against a graph that ignored the edits.

- check-staleness now reports `driftingFiles` = git-dirty SOURCE files modified since the
  index build (mtime > indexedAt). Cheap (stats only the dirty files) and RESETS on refresh
  because indexedAt advances — a plain `git status` count would nag forever.
- new shared `classifyMcpDrift`: graph QUERY tools (query/context/cypher/impact/pdg_query/
  trace/explain/api_impact/route_map/shape_check) hard-block past a drift threshold with a
  nudge to the FAST incremental `gitnexus:refresh`. Non-query tools (detect_changes, rename,
  check, tool_map…) pass; edits/reads/greps are untouched, so editing flow isn't interrupted.
- wired into the Claude + Cursor MCP guards, AFTER the must_refresh check (so it only applies
  when the index is otherwise commit-fresh).
- `driftRefreshThreshold` config (default 3; 0 disables). Surfaced in `gitnexus:status` +
  a `driftRefreshBlocks` scorecard counter. Contract now teaches proactive incremental refresh.

Tests: 58/58 — classifyMcpDrift logic + real check-staleness drift/reset in a temp git repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…m cost

Self-review (microscope waves, 5 independent lenses) of the drift gate — fixes:
- HIGH: the drift gate fired in classical_fallback too (the else-of-must_refresh covers it),
  overriding the classical-fallback escape hatch and telling the agent to run the refresh that
  just FAILED. classifyMcpDrift now enforces phase === "fresh" itself; both guards pass ctx.phase.
- MEDIUM: countDrift used a 3rd hand-rolled source-ext regex diverging from the kit's
  DEFAULT_SOURCE_EXT_RE (silently no-drift for .cts/.ex/.clj/.lua/…, and ignored the sourceExts
  config override). Now uses loadHookConfig(root).sourceExtRe.
- MEDIUM: countDrift's `git status` ran on EVERY tool call (grep/read/edit/shell/stale) though
  driftingFiles is consumed only by the MCP guards on the fresh path. Moved it into the
  commit-fresh branch + skip it entirely when the gate is disabled (threshold <= 0).
- LOW: non-ASCII paths undercounted (git octal-escaping) -> `-c core.quotePath=false`.
- LOW: Cursor never bumped the driftRefreshBlocks scorecard counter -> added.
- LOW: tempered the "fast" overclaim (uncapped embeddings make large batches / cold model slower).

Verified-correct by the review (no change): --embeddings 0 = "disable the cap" (traced in the
gitnexus CLI source; also a latent-bug fix vs bare --embeddings capping at 50k nodes), and the
core premise holds (incremental analyze hashes on-disk content -> reindexes uncommitted edits +
advances indexedAt). 58/58 (+ phase-gate regression test).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ReidenXerx
ReidenXerx merged commit 41baff0 into main Jul 12, 2026
1 check passed
@ReidenXerx
ReidenXerx deleted the feat/mid-session-drift-refresh branch July 12, 2026 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant