Index, then ripgrep, then a pure scan. Git stays the only durable store on every rung.
Every reader stats the tree and re-parses only what changed, so the index heals itself after a hand edit, a branch switch, or a disabled hook.
Terms are AND-intersected. Over-selection is harmless because the Python scorer re-checks every candidate.
A missing rg is not an error. Deleting the index is always
valid recovery.