DL-346
Compass global search is a SERVER-side corpus reached over the wire, not a client-held index: a persistent center-of-top-bar input coexists with the D5-frozen Cmd+K palette (both feed one provider set), issues/PRs search the WHOLE board rather than the caller’s assigned slice, and chat search reaches the already-shipped-but-UI-unreachable rpc SearchMessages. Issue search is new server work — an issues.search_tsv GENERATED ALWAYS … STORED column + GIN index + SearchIssues RPC, mirroring the messages pipeline. Two schema constraints are load-bearing and measured on PostgreSQL 18.4. (1) The labels term MUST route through a compass_labels_text SQL wrapper declared IMMUTABLE with a pinned search_path: bare array_to_string (and labels::text) is only STABLE and fails the migration with “generation expression is not immutable”, while the IMMUTABLE array_to_tsvector alternative compiles but bypasses the parser so label search silently matches nothing. (2) The column labels its four fields with setweight (title A, body/summary B, labels C) and queries pass the matching {0.1,0.2,0.4,1.0} weights array to ts_rank — a flat concatenation ranks a short-title hit and a hit buried in a 10 KB body EXACTLY equal (0.06079 vs 0.06079 measured; weighted 0.60793 vs 0.24317), so relevance ordering is unachievable without it, and the column is STORED so this cannot be deferred without a table rewrite. PR results stay a client-side prRows() derivation over Issue.prs and are FIXTURE-ONLY at v1 — the field has zero Go writers — so no live-mode PR assertion may gate the release
Status: Active (Matt, 2026-09-07)