You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An rrf(...) order silently ignores the order keys after it, on both engines. With four rows whose fused scores tie, order { rrf(bm25($d.body, "needle"), bm25($d.body, "needle")), $d.rank desc } limit 2 returns d1, d2 on engine v2; the keys ask for d4, d3. The same query with bm25 alone returns d4, d3, because v2 sorts a BM25 order by score, then the trailing keys, then every binding's id.
Reproduced on main (80406fee, v2) with a logic-test probe; schema Doc { slug @key, title, body @index, rank: I64 }, four rows with identical body and rank 1 to 4.
Mechanism
The planner plans no Sort over a fusion: optimizer.rssort_keys returns None for Ranking::Fused ("a fusion orders its own rows").
RankFuseExec (engine/graph.rsfuse_arms, a copy of v1's body) sorts entities by fused score only (partial_cmp, NaN compared equal), truncates to the limit in entities, and never reads the trailing keys. The fused score is not a column, so rrf(...) cannot be projected (T37).
The GQT runner already encodes the gap: ordered_refusal refuses expect ordered for an rrf-led order because "fusion sorts by score alone, with no tie-break".
Expected
One total order for every search order: the fused score as a per-row column, then the trailing keys, then the binding ids, then limit cuts rows. The fused score becomes projectable under the same rule as nearest and bm25 (T33). Tracked as RFC 0047's total-order work (#791, rollout step 5).
Activity
azimafroozeh commentedon Oct 1, 2026