diff --git a/crates/kebab-core/src/search.rs b/crates/kebab-core/src/search.rs index bb66be9..38e41ad 100644 --- a/crates/kebab-core/src/search.rs +++ b/crates/kebab-core/src/search.rs @@ -158,6 +158,9 @@ pub struct TraceFusionInput { pub chunk_id: ChunkId, pub lexical_rank: Option, pub vector_rank: Option, + /// Hybrid mode: normalized RRF score in `[0, 1]`. + /// Lexical / Vector mode: equals the underlying retriever's score + /// (no fusion ran). 0.0 for chunks dropped past `target_k`. pub fusion_score: f32, } diff --git a/crates/kebab-search/src/hybrid.rs b/crates/kebab-search/src/hybrid.rs index 58b6678..7f415a9 100644 --- a/crates/kebab-search/src/hybrid.rs +++ b/crates/kebab-search/src/hybrid.rs @@ -391,6 +391,10 @@ impl HybridRetriever { } } + // total_ms is wall-clock from start; per-stage `lexical_ms` / + // `vector_ms` / `fusion_ms` each truncate to whole millis via + // `as_millis() as u64`, so their sum can drift below total + // (sub-ms losses) — DO NOT assert `total_ms >= sum(stages)`. tb.timing.total_ms = start_total.elapsed().as_millis() as u64; Ok((final_hits, tb.into_trace())) } diff --git a/crates/kebab-tui/src/search.rs b/crates/kebab-tui/src/search.rs index 9166fe3..13c9f43 100644 --- a/crates/kebab-tui/src/search.rs +++ b/crates/kebab-tui/src/search.rs @@ -227,6 +227,8 @@ pub fn handle_key_search(state: &mut App, key: KeyEvent) -> KeyOutcome { return KeyOutcome::Continue; } if let Some((q_text, q_mode)) = last_query { + // TODO: thread filters when TUI gains a filter UI (currently + // mirrors fire_search which also passes default filters). let q = kebab_core::SearchQuery { text: q_text, mode: q_mode,