Two coverage gaps left by #2141 / #2157, both misses rather than fabrications.
1. Extensionless shebang scripts. _SHEBANG_DISPATCH already routes a
`#!/usr/bin/env bash` file with no extension to extract_bash, so its functions
are indexed, but the cross-file source-resolution pass picked participants by
filename suffix (`p.suffix in (".sh", ".bash")`). A sourced extensionless lib
was therefore excluded and calls into it never bound. Select by shape as well:
the bash extractor tags every node it emits with metadata.language == "bash".
The suffix check stays so an empty .sh file, which has no nodes to inspect,
still participates.
2. Bare `source lib.sh` (no ./ prefix). Only the `raw.startswith((".", "/"))`
branch recorded a bash_sources entry; a bare name fell through to the opaque
`imports` fallback, so neither the source edge nor calls into the lib resolved
even though the file usually sits beside the script. The else branch now binds
a sibling of that name when one exists.
The existence gate from the ./-prefixed branch carries over: a bare name that
resolves to no sibling keeps the old `imports` edge and records no bash_sources
entry, so nothing is invented. is_file() is wrapped against OSError so a name
that is invalid for the platform degrades instead of raising.
Transitive sources (a->b->c) remain unresolved, as the issue notes.