The eval set under brain/eval/qa-2026-05.md showed BM25 top-1 at 20%
with 5 of the missing slugs being short focused knowledge entries
that lost to long aggregate docs on raw term-frequency. Tier weighting
addresses that without touching the BM25 algorithm itself.
How
- Result struct gains a Tier field, populated during the file walk
via extractTier (frontmatter wins, path prefix as fallback —
mirrors the graph.inferTierFromPath logic so the two callers stay
in lockstep).
- After the existing sort (and optional hybridMerge), do a final
stable re-sort by float64(Score) * tierWeight(Tier). Knowledge
×1.5, note ×1.0, inbox ×0.3, unknown ×1.0.
- hydrate() (vector-only hits) also fills Tier so re-ranking covers
the hybrid path.
Test covers the load-bearing case: a long note-tier doc with raw=10
loses to a short knowledge-tier doc with raw=8 after weighting
(8×1.5=12 vs 10×1.0=10).
Measurement gate is in infra#72: re-run brain/eval/score.py against
the live brain after this image lands; close the issue when top-1
hit rate lifts by ≥10 absolute points.