mirror of
https://github.com/block/buzz.git
synced 2026-10-28 04:51:40 +00:00
`to_tsvector('simple', content)` over a kind-0 event tokenizes the whole
profile JSON, including an inline base64 avatar, so 111 agent profiles
sharing one `picture` matched `wes:*` and pushed the real Wes to row 121.
Add `profile_search_tsv(content)`, an IMMUTABLE SQL function that indexes
`name`/`display_name`/`displayName` at weight A, `nip05`/`lud16`/`website`
at B, and `about` at D, skipping `picture`, `banner`, `image`, and unknown
keys. `pg_input_is_valid` (PostgreSQL 16+) guards the `::jsonb` cast so
rows that predate ingest validation fall back to today's raw-text vector,
and `CASE` keeps the cast from ever being evaluated for invalid input; the
IMMUTABLE declaration is truthful because `jsonb_in` is immutable. The
`search_tsv` generated column gains a `kind = 0` arm ahead of the privacy
blocklist in `schema/schema.sql`, which stays intact.
Migration 0056 creates the function unconditionally and rewrites the
column only when `events` is empty, in 0008's shape, because replacing a
generated column copies every partition and rebuilds the partitioned GIN
under ACCESS EXCLUSIVE with no lock_timeout at relay startup. Populated
databases take the new out-of-band
`scripts/maintenance/profile_search_text_fields.sql`, which wraps the live
expression read through `pg_get_expr` so it is correct for both the
fresh-install allowlist and the brownfield blocklist, refuses to run before
0056 has created the function, is a no-op once applied, and recreates the
GIN index under a 5s lock_timeout. The older
`nip_rs_search_allowlist.sql` rewrite now emits the same kind-0 arm so
running it afterwards cannot undo this one. Docs in `buzz-search`,
CONTRIBUTING.md, and ARCHITECTURE.md describe the new expression.
Tests, each verified to fail when the seam it binds is removed:
`kind0_avatar_data_url_token_is_not_searchable` (desired-state lane; two
hits with the `kind = 0` arm removed from schema.sql) and, in the
migration lane, `fresh_install_profile_search_uses_text_fields`,
`maintenance_profile_search_rewrite_drops_avatar_tokens_on_populated_database`
(avatar row keeps matching with the wrap removed from the script; also
checks the GIN index and the idempotent rerun), and
`maintenance_profile_search_rewrite_wraps_fresh_install_allowlist` for the
post-0008 expression shape. `populated_upgrade_preserves_search_policy_
except_for_private_kinds` gains a kind-0 avatar row and asserts 0056
leaves a populated column untouched. The embedded migrator count moves to
56; the fresh-install allowlist assertion drops 0 from the array because
kind 0 now has its own arm. The two kind-0 tests from the earlier commits
and the display-name and short-prefix tests pass unchanged.
Verified against local PostgreSQL 17.9 with
`scripts/postgres-test-run.sh -p buzz-search --tests` (23 passed) and
`scripts/postgres-test-run.sh -p buzz-db --lib -E 'test(migration::postgres_tests)'`
(12 passed), `cargo test -p buzz-db --lib runtime::migration`,
`scripts/test-postgres-test-discovery.sh`, `cargo fmt`, and
`cargo clippy -p buzz-db -p buzz-search --all-targets -D warnings`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>