Skip to content

Non-git silent on staleness #1948

Description

@chaking22

Version

codebase-memory-mcp 0.10.8

Platform

Windows (x64)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

standard

What happened, and what did you expect?

I understand non-git repos aren't currently watched, just throwing this in there to be helpful:
A project indexed from a directory that is not a git repository is never refreshed again. It stays frozen at its first index for the life of the database, and nothing in the API indicates this.

and poll_project() has:

/* Skip non-git projects */
if (!s->is_git) {
    return;
}

The problem is not that these projects go stale. It is that going stale is invisible, and a stale graph produces confident wrong answers rather than obviously missing ones. A search_graph for a function that exists on disk returns:

total: 0
hint: "No nodes match this pattern. Check spelling or try a broader regex."

That is indistinguishable from a true negative, so a caller - especially an LLM agent - concludes the symbol does not exist and acts on it. Meanwhile index_status reports "status": "ready" with no last-indexed timestamp and no watched/unwatched flag.

Expected: either non-git roots get some refresh path (an mtime scan fallback), or - much cheaper - the API exposes the coverage, so a caller can decide whether to trust the answer and run an index or whatnot as needed.

Suggested fix:

  1. Surface it. Add a watched: true|false field and a last-indexed timestamp to index_status. Callers can then tell "no results" from "no results, and this project has not been checked since Tuesday." This is small and fixes the dangerous part — the silence.
  2. Fallback scan. For non-git roots, poll a stat-walk signature (path:size:mtime folded into a hash) on the same adaptive interval already used for git roots. git_dirty_signature() in watcher.c already does essentially this for dirty paths; the non-git case needs the same idea applied to the whole tree.

Additional Context:

Found while building an out-of-process freshness gate to work around this. Happy to test a patch — I have reproductions for both the git and non-git paths.

Reproduction

  1. Create a plain directory that is not a git repository:

    mkdir /tmp/nogit && cd /tmp/nogit
    cat > app.py <<'EOF'
    def alpha():
        return 1
    
    def beta():
        return alpha() + 1
    EOF

    (No git init - that is the whole point.)

  2. Index it:

    codebase-memory-mcp cli index_repository --repo-path /tmp/nogit
  3. Confirm the graph is populated:

    codebase-memory-mcp cli search_graph --project <name> --name-pattern '.*alpha.*'
    # -> 1 result
  4. Append a function to the file:

    printf '\ndef gamma_uniquename():\n    return beta() * 2\n' >> app.py
  5. Wait as long as you like — minutes, hours, a server restart — then:

    codebase-memory-mcp cli search_graph --project <name> --name-pattern '.*gamma.*'

Actual: total: 0, with the "check spelling" hint. Permanently — no poll interval ever covers this project.

Expected: the new function is found, or the response indicates the index may be stale.

Doing the same thing in a git init-ed directory behaves correctly: the
watcher notices and reindexes.

Logs


Diagnostics trajectory (memory / performance / leak issues)


Project scale (if relevant)

No response

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edgesux/behaviorDisplay bugs, docs, adoption UXwindowsWindows-specific issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions