mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Implements Eva's blocker-2 fix: Postgres backend now orders search
results by relevance, and the e2e test that claims to verify this
actually discriminates rank from recency.
postgres.rs
- SELECT list now includes `ts_rank_cd(content_tsv,
plainto_tsquery('simple', $q)) AS rank` when the query has
searchable text. The same `$q` parameter slot is reused in WHERE.
- ORDER BY rank DESC, created_at DESC when has_text; empty/"*"
queries skip the rank column and fall back to created_at DESC
(no needless tsquery cost).
- SearchHit.score is populated from the rank column (f32 widened
to f64). Empty/"*" queries leave score at 0.0.
e2e_nostr_interop::test_nip50_search_relevance_order
- Redesigned to discriminate rank from recency. Previous fixture
used "alpha bravo charlie" with msg3="alpha bravo" — plainto_tsquery
ANDs all terms, so msg3 never matched the WHERE clause and the
test passed trivially with one candidate (Eva caught this).
- New fixture: query "{prefix} alpha bravo"; msg1 (oldest) has
terms adjacent (high rank); msg2 (middle) doesn't match at all;
msg3 (newest) has terms separated by filler (lower rank).
- Asserts both msg1 and msg3 are present, then asserts events[0].id
== id1 with no `||content.contains(...)` escape hatch.
- Discriminator is term proximity, not term frequency: Typesense's
default _text_match does NOT reward repeated query terms (verified
empirically — identical tm scores for "alpha bravo" vs
"alpha alpha bravo bravo"), but BOTH backends reward adjacency.
Proximity is the property both backends agree on.
- New `send_rest_message_at` helper pins created_at via
`custom_created_at`. Without explicit timestamps, three back-to-back
sends share one wall-clock second; PG falls to heap-scan order and
masquerades as rank ordering. Spreading by 30s each makes the
recency-only ordering deterministically put msg3 first, so a
passing test really means rank wins.
Validation
- buzz-search lib: 30/30. buzz-relay lib: 337/337.
- NIP-50 e2e on Postgres: 4/4 (incl. relevance_order) + isolation 1/1.
- NIP-50 e2e on Typesense: 4/4 + isolation 1/1.
- Proof of discrimination: with postgres.rs reverted to
`ORDER BY created_at DESC`, the new test FAILS on PG (msg3 first,
as predicted). Restored ts_rank_cd ordering after.
Pre-existing failure not introduced by this commit:
test_nip17_gift_wrap_not_searchable fails on both backends — it queries
Typesense directly at events-spike-{backend}; on the PG backend that
collection is never written to (structurally expected), and the
Typesense-backend failure is the same fixture coupling Eva already
acknowledged in the prior turn. No regression vs e5869ddd/4b7c8d12.
Co-authored-by: Tyler <109685178+tlongwell-block@users.noreply.github.com>
Signed-off-by: Tyler <109685178+tlongwell-block@users.noreply.github.com>