Repository navigation
Description
Summary
Since 836c366 ("prune nested repositories from the parent source walk"), the source walker skips every non-root directory that contains a .git entry. That fixed a real problem (linked worktrees inside a checkout being indexed many times over), but it also drops git submodules from the parent project's index, with no setting to bring them back.
I'd like an opt-in way to index submodules as part of the parent, while still skipping linked worktrees and unrelated nested clones.
Use case
A "super repo" that pulls in the main application as a submodule:
super-repo/ <- where I start every agent session
.gitmodules
dev/ <- scripts that launch and wrap the app
docs/
app/ <- git submodule, ~1,000 tracked files
I always start agent sessions from super-repo/. Today:
- The
super-repoindex covers only its own files; nothing underapp/is indexed, and nothing reports that it was skipped. - To search the app I have to
tracedecay initit as a separate project and passproject_selectoron every call, or usemulti_root_*scope sets. - Even then there are no call or import edges between the two, so a path from
dev/intoapp/never appears as one chain incallers/impact/call_chain.
For this layout the submodule is effectively part of the project, and one index is what I want.
Telling submodules apart from worktrees
With current git, both a linked worktree and a checked-out submodule have a .git file, not a directory, so the presence check can't distinguish them. Some signals that do:
- The
gitdir:target. A linked worktree points to<common-dir>/worktrees/<name>; a submodule points to<parent>/.git/modules/<name>. - The parent's index. A submodule is a gitlink entry (mode
160000) at that path, and is usually listed in.gitmodules. - Linked worktrees also show up in
git worktree listfor the parent.
Possible shape
Something like an index setting (name up to you):
[index]
include_submodules = true # default false keeps today's behaviourWhen enabled, the walker would descend into a directory only if it is a registered submodule of the root (gitlink plus .gitmodules entry), and keep pruning linked worktrees and other nested repositories exactly as now.
Related
- Because grep, ast-grep, and unmounted-files share this walker, they also skip submodule contents today.
- It would help if
statusorunmounted_filesreported "skipped nested repository: app/", so users know why that code is missing.
Environment
- tracedecay 1.0.0-beta.91, macOS, Claude Code plugin install
- git 2.54
Activity
fix(index): withdraw incomplete submodule source admission
ScriptedAlchemy commentedon Nov 8, 2026
Implementation investigation (2026-11-08 UTC), Refs #4593 — issue remains open; no fix is claimed.
A walker-only
include_submodulesswitch cannot satisfy this issue without silently disagreeing with the indexed graph. I checkedmasterat91c72aba7750a398dd28e83d64bf0c6d6fef4172, rootAGENTS.md(no nested AGENTS entries in the complete tree), the issue (zero comments before this investigation), both currently open PRs, and prior closed/unmerged #4719 (which explicitly withdrew a walker-only implementation).The additional integration points that must change together are:
crates/tracedecay-code-index/src/source_walk.rs:167-176excludes every nonroot.gitdirectory; live grep, ast-grep, and unmounted-file auditing reuse this.crates/tracedecay-code-index-runtime/src/code_index_scheduler/classification.rsbuilds candidates from the parent Git index and explicitly selects.index_worktree_submodules(None). The parent indexes the gitlink path, not the child source files.crates/tracedecay-code-index-runtime/src/code_index_scheduler/git_tree_capture.rsexplicitly skipsentry.mode.is_commit(), so the clean-HEAD/exact-tree fast path drops gitlinks.reconcile.rs:4011+uses that fast path to publish clean generations; merely changing the filesystem walker cannot affect the index.freshness_witness.rs::source_candidatesderives its roster from the parent classification, andidentity.rs::GitMetadataFingerprintV1samples only the parent Git metadata. A changed child revision or same-size content rewrite could otherwise remain falsely fresh.An independent disposable native Git probe executed five nonvacuous assertions: the parent records
160000 ... appbut notapp/feature.rs; an initialized child has.git -> ../.git/modules/app; a linked worktree has a different.git -> .../worktrees/...target; and the child file really exists despite absence from the parent index. This is Git/filesystem behavior, not repository Rust/Bazel, CI, or native macOS validation.Acceptance needs a single explicit, restart-applied opt-in from the canonical project configuration; Git-index gitlink plus
.gitmodulesmembership and bound child repository/worktree identity; consistent nested-source admission, sanitized capture, sealed graph/retrieval, and both clean and dirty snapshot authorities; freshness invalidation on child changes and removals; fail-closed linked-worktree/untrusted clone/metadata substitution handling. Tests must exercise default-deny, opt-in parent→child call edges and grep/AST parity, commit/dirty change, restart/reuse, removal, denied/nested clone, and macOS/native behavior. No secondary walker-only authority.No production changes or PR were published: the environment providing this investigation has no repository checkout or Bazel/native macOS toolchain, so it cannot legitimately compile, run nonzero repository tests, or establish a safe completed implementation. The issue-specific owner remains active; this comment is a concrete implementation boundary, not a closure recommendation.
fix(code-index): report skipped nested repositories in unmounted audit
fix(code-index): bound repository audits and report walk failures
style(code-index): format nested repository regressions
fix(code-index): align nested checkout capture with source walks
style(code-index): format nested repository boundary tests
fix(code-index): invalidate cached rosters on nested Git markers
test(code-index): assert roster invalidation across marker removal
fix(code-index): refuse markerless parent gitlink directories
style(code-index): satisfy Bazel formatting for gitlink guard
fix(code-index): deny ignored admission beneath Git gitlinks
fix(code-index): preserve HEAD gitlink boundary on staged removal
fix(code-index): deny staged-removal gitlink in source admission
style(code-index): fix ignored gitlink regression formatting
fix(code-index): preserve HEAD gitlink boundaries in classification
fix(code-index): preserve clean registered gitlink state
fix(code-index): deny gitlink children in freshness roster
fix(code-index): refuse symlinked source leaf capture
fix(code-index): reject failed submodule freshness witnesses
fix(code-index): preserve authenticated child capture on Windows
fix(code-index): revalidate lazy submodule source walks
fix(code-index): require explicit sealed submodule policy
perf(code-index): restrict scoped Git boundary traversal
style(code-index): apply Bazel rustfmt to scoped Git boundaries
fix(code-index): revalidate parent submodule authority during reads
style(code-index): apply Bazel rustfmt to submodule authority test
fix(code-index): recheck child repository worktree binding