Skip to content

Expose index freshness in MCP results and prevent silently stale graph queries #48

Description

@WinterQuant

Problem

A persistent code graph can temporarily become stale after:

Switching branches
Rebasing or resetting
Bulk file changes
Saving uncommitted edits
Restarting the MCP server or watcher

Infigraph’s watcher incrementally reindexes changed files and re-resolves affected cross-file relationships. However, graph-backed MCP results do not currently indicate whether the graph has caught up with the working tree.

This means tools such as trace_callers, find_all_references or transitive_impact can potentially return a confident-looking result while an update is still pending.

An active watcher is not, by itself, proof that the graph is current.

Current behavior
Source content hashes are stored on indexed modules.
Git HEAD is recorded when a repository is explicitly indexed and registered.
The watcher processes created, modified and deleted files.
Cross-file changes trigger targeted reindexing and call-edge resolution.
Search warns when no watcher is running.
MCP results do not include the indexed HEAD, current HEAD, pending update state or a caught_up indicator.
Branch changes are detected indirectly through working-tree file events rather than explicitly through Git HEAD changes.

Relevant areas:

crates/infigraph-core/src/watch/mod.rs
crates/infigraph-mcp/src/tools/watch.rs
crates/infigraph-mcp/src/tools/search.rs
crates/infigraph-core/src/multi/mod.rs
Example reproduction
Index a repository and start the MCP watcher.
Run trace_callers for a function.
Switch to another branch where its callers are different, or add a new uncommitted caller.
Immediately run trace_callers again.
The result may reflect the previous graph state, with no metadata indicating that reindexing is pending.
Expected behavior

Graph-backed MCP results should expose a compact freshness state, for example:

freshness:
status: fresh | updating | stale | unknown
indexed_head: abc123
current_head: def456
working_tree_dirty: true
pending_changes: 3
indexed_generation: 42
stale_reason: branch_changed

When freshness cannot be guaranteed, the result should contain a visible warning instead of silently returning potentially stale structural information.

An optional strict mode could refuse to return graph results until the index has caught up.

Proposed direction
Maintain per-project pending and in-progress update counts.
Mark the graph as updating as soon as filesystem changes are received.
Mark it fresh only after indexing and cross-file re-resolution complete successfully.
Compare the current Git HEAD with the last successfully indexed HEAD.
Reconcile stored content hashes with the working tree when a watcher starts or restarts.
Add freshness metadata through a common response wrapper or compact footer used by all graph-backed MCP tools.
Consider a strict_freshness option that waits or fails visibly when the graph is behind.

Acceptance criteria

Branch switches and rebases are detected.
Saved uncommitted changes are reflected in freshness state.
Pending and in-progress watcher updates are distinguishable from a fresh graph.
Graph-backed MCP responses expose freshness information consistently.
Stale or unknown state produces a visible warning.
Watcher restart performs reconciliation before reporting the graph as fresh.
Tests cover branch switches, uncommitted edits, deleted files and queries issued during reindexing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions