The proposer's reference basis, and every uses edge it writes, counted any
word-bounded mention of a canon's symbol. Three holes made that wrong at
scale (snippet #5448, symbol `file`, held 2,161 uses edges):
- Go, Rust, Kotlin, Swift, Dart, C, C#, Ruby and PHP were outside the
language-family maps, so their canons read as "unknown, no gate" and were
matched in every Python, TS and CSS body.
- Canons in other projects were matched by name, though one repo never
calls a function defined in another's.
- A plain word (`file`, `seen`) or a module's own helper (`_run`) matched
wherever it appeared.
names_canon is now the one by-name test, used by match_canon,
reference_canons and the write-path hint: same project, not a name the file
defines itself (unless the canon is recorded there), no generic verb with or
without a leading underscore, and a bare lowercase word only where it is
called. The write path keeps the payload's own names in play, since a
redefinition of a pulled canon is the copy it exists to flag.
Repair: record_uses only adds, so replace_reference_uses now makes a row's
machine-written reference edges exactly what the current rule finds,
leaving judged and hook edges alone. _PROPOSER_VERSION 7 re-reads every row
on its project's next refresh. Migration 0125 deletes the cross-project
reference edges already stored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>