Change detection's git fast path (collectGitStatus) consumed `git status`
output with only an isSourceFile filter, on the assumption that git already
omits ignored paths. It doesn't: gitignore is a no-op for *tracked* files, and
the built-in default excludes (vendor/, node_modules/) aren't gitignore at all.
So a tracked file inside a committed dependency dir, or under a .gitignored
dir, surfaced as a change the full index never tracks — `codegraph status`
reported phantom pending changes that `sync` (a filtered filesystem reconcile)
never cleared, and the public getChangedFiles() API returned the same wrong
list.
Apply buildDefaultIgnore(repoDir) per recursion level, matching repo-relative
paths — structurally equivalent to the full-index path's ScopeIgnore (each
embedded repo judged by its own rules) with no extra git subprocess calls.
Deletions stay unfiltered: getChangedFiles acts on one only when the path is
already tracked in the DB, where removal is always correct, and that lets a
newly-excluded dir's stale rows clean themselves up.
Unblocks #699 (an .ignore overlay inherits this leak unless change detection
consults the same matcher as enumeration).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>