Repository navigation
Description
Summary
detect_changes correctly returns changed_files but always returns impacted_symbols: [] / impacted_count: 0 when the indexed project lives inside a git worktree (not the worktree root itself).
The root cause is that canonical_root is computed one level too high, causing a path prefix mismatch between git diff output and graph file paths.
Environment
- codebase-memory-mcp: v0.8.1
- OS: macOS 25.5.0 (Darwin)
- Project layout: git monorepo at
/workspace/, with sub-projects indexed from subdirectories (e.g.,/workspace/scripts/,/workspace/runtime/solar-monitor/)
Repository Structure
/workspace/ ← actual git root (.git lives here)
├── scripts/
│ └── solar_daily_report_v1.py ← indexed as project "workspace-scripts"
├── runtime/
│ └── solar-monitor/ ← indexed as project "workspace-runtime-solar-monitor"
Steps to Reproduce
- Index a project whose
root_pathis a subdirectory of the git worktree root (e.g.,workspace/scripts/) - Call
detect_changeswithscope: "impact"andsince: "HEAD~1"
{
"project": "Users-openclaw-.openclaw-workspace-scripts",
"since": "HEAD~1",
"scope": "impact",
"depth": 2
}- Observe:
changed_filesis correctly populated;impacted_symbolsis[]
Expected Behavior
impacted_symbols should list all symbols in the changed files plus their transitive callers.
Actual Behavior
{
"changed_files": ["scripts/solar_daily_report_v1.py", ...],
"changed_count": 120,
"impacted_symbols": [],
"impacted_count": 0,
"depth": 2
}Root Cause
list_projects reveals the miscalculation:
{
"name": "Users-openclaw-.openclaw-workspace-scripts",
"root_path": "/Users/openclaw/.openclaw/workspace/scripts",
"git": {
"worktree_root": "/Users/openclaw/.openclaw/workspace",
"git_common_dir": "../.git",
"canonical_root": "/Users/openclaw/.openclaw/workspace/.."
}
}| Field | Value | Notes |
|---|---|---|
| Actual git root | /Users/openclaw/.openclaw/workspace/ |
confirmed via git rev-parse --show-toplevel |
canonical_root |
/Users/openclaw/.openclaw/ |
one .. too many |
| git diff path | scripts/solar_daily_report_v1.py |
relative to actual git root |
| Expected path for matching | workspace/scripts/solar_daily_report_v1.py |
relative to wrong canonical_root |
The path prefix that detect_changes strips from git diff paths (workspace/scripts/) does not match what the graph stored (solar_daily_report_v1.py relative to root_path), so no symbols are ever matched.
The symbol is present in the graph (verified via search_graph):
{
"name": "solar_daily_report_v1.py",
"qualified_name": "Users-openclaw-.openclaw-workspace-scripts.solar_daily_report_v1",
"label": "Module",
"file_path": "solar_daily_report_v1.py",
"out_degree": 81
}The canonical_root appears to be computed as worktree_root + "/" + git_common_dir + "/.." which for git_common_dir = "../.git" resolves to workspace/../.git/.. = .openclaw/ instead of the correct workspace/.
Workaround
Currently falling back to manual trace_path + search_graph to assess blast radius for shared library changes.
Additional Notes
changed_filesdetection works correctly in all cases- Projects indexed from the worktree root directly are unaffected
- Standalone git repos (not worktrees) are unaffected —
detect_changesworks correctly there - This affects all
Users-openclaw-.openclaw-workspace-*projects (anything inside the workspace)
Activity
fix(git): fix canonical_root for worktrees and subdirectory projects
fix(git): resolve canonical_root '..' components in worktree git_comm…
DeusData commentedon Jun 29, 2026
Thanks for the detailed worktree root analysis. I’ve triaged this under #398. This is distinct from #682 but in the same gitdir/worktree family; the regression should index a subdirectory inside a linked worktree and assert
changed_filesandimpacted_symbolsuse the same normalized root.fix(git): resolve canonical_root '..' components in worktree git_comm…
fix(git): resolve canonical_root '..' components in worktree git_comm…
fix(git): derive canonical_root from git's own absolute common-dir
fix(git): correct canonical_root for worktrees and subdirectory projects