* test(asr): parse the guard, don't grep it
Two Majors CodeRabbit raised on #1523 — which I merged before reading
them, so this is the follow-up rather than a fix on the branch.
- Approved files were matched by BASENAME, so any future
`<anything>/asr_backend.py` was exempt from the guard it exists to
enforce. Matching is by relative path now; a decoy
`backend/engines/asr_backend.py` calling the selector is caught.
- Detection was a line regex, wrong in both directions: it missed
`import get_active_asr_backend as pick` and fired on the name inside
docstrings and comments. It walks the AST now, alias-aware, so only
real calls count.
Both verified by planting the exact bypasses: an aliased call in
services/tts_backend.py and the decoy module above. Neither was caught
before this change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(asr): resolve the selector's bindings before flagging a call
CodeRabbit, #1524: matching any call named get_active_asr_backend also
reported a local helper or an unrelated object's method that happens to
share the name. False positives are how a guard stops being believed —
people add allowlist entries for code that was never the bug.
Bindings are resolved first now: a bare call counts only if the name was
imported FROM services.asr_backend, an attribute call only if it hangs
off a module alias for it. Six shapes are pinned in the suite — direct,
aliased and module-attribute calls flagged; a same-named local function,
an unrelated method, and the name inside a docstring not.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>