This is the pgvector footgun I've watched bite the most people, exactly because it fails quiet. The model that made it click for me: HNSW hands you ef_search candidates from the unfiltered graph, then the WHERE runs. If tenant 42 is a small slice, the true filtered-nearest may never have been in that candidate pool, so you silently get fewer than ten — or ten worse ones — and the plan says nothing.
Worth adding to the mitigation list, in rough order of cost: bump hnsw.ef_search first (widens the pool, buys margin, no schema change); then reach for iterative scan (hnsw.iterative_scan = strict_order/relaxed_order in 0.8+), which keeps walking the graph until it has enough rows that pass the filter — the closest thing to an actual fix. For a handful of large tenants, a partial HNSW index per tenant restores in-filter recall outright, at the cost of index proliferation. And the cheapest detector for anyone who can't adopt a tool yet: when the tenant has ≥LIMIT rows, assert you got LIMIT back — a short result set is the alarm the query plan won't raise.
The reproducible-from-fresh-checkout benchmark is what makes this land; most "recall collapsed" posts hand-wave exactly the part you measured.