Skip to content

Incremental re-index names File nodes by relative path; full build uses basename — same tree yields diverging graphs #994

Description

@spde

Summary

An incremental re-index (index_repository on an already-indexed project) names File nodes by their repo-relative path, while a full build names them by basename. Node upserts match by qualified name, so re-indexing a touched file renames its File node in place — the same working tree yields two different graphs depending on whether it was indexed fresh or incrementally, and the divergence grows with every edited file (both added and modified files are affected).

Because File nodes are USAGE-edge sources, this breaks name-based traversal: walking inbound USAGE transitively dead-ends at any touched file's node, silently dropping everything that reaches a target through a recently added/modified class.

Reproduction (v0.9.0, macOS arm64; also present on current main)

BIN=./codebase-memory-mcp; T=$(mktemp -d); I=$(mktemp -d); F=$(mktemp -d)
mkdir -p "$T/src"
printf 'public class Bee { public void buzz() {} }\n' > "$T/src/Bee.java"
printf 'public class Aye { private final Bee bee = new Bee(); }\n' > "$T/src/Aye.java"
CBM_CACHE_DIR="$I" "$BIN" cli index_repository "{\"repo_path\":\"$T\"}"     # initial
printf 'public class Cee { private final Bee bee = new Bee(); }\n' > "$T/src/Cee.java"   # ADD
printf '// touched\n' >> "$T/src/Aye.java"                                                # MODIFY
CBM_CACHE_DIR="$I" "$BIN" cli index_repository "{\"repo_path\":\"$T\"}"     # incremental
CBM_CACHE_DIR="$F" "$BIN" cli index_repository "{\"repo_path\":\"$T\"}"     # full, same tree
# then per cache: query_graph "MATCH (n:File) RETURN n.name"

Result:

cache File node names
incremental Bee.java, src/Cee.java, src/Aye.java
full (same tree) Cee.java, Aye.java, Bee.java

USAGE edges into Bee correspondingly come from src/Cee.java (incremental) vs Cee.java (full).

Root cause

pipeline_incremental.c ("Create File nodes for changed files (purge deleted them)") passes changed_files[i].rel_path as the name argument of cbm_gbuf_upsert_node, whereas pipeline.c ("Create File node") computes the basename first. The incremental site also loses the {"extension": ...} props the full build sets. Introduced with the RAM-first incremental rework (80680ea); given the comment says it re-creates what purge deleted, this looks like an argument slip rather than intent.

Fix

PR to follow: mirror the full pipeline's node shape at the incremental call site (basename + extension props), plus a regression test in the incremental suite (incr_file_node_name_stays_basename) — red without the fix, green with it; full incremental suite passes (162/162).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions