From 6a33d08aea09c515dccfc9411a2f8dfaa9836166 Mon Sep 17 00:00:00 2001
From: th-kim0823
Date: Sun, 10 May 2026 16:26:34 +0900
Subject: [PATCH] fix(fb-37): address PR #129 round 1 review
- doc TraceFusionInput.fusion_score semantics (single-mode vs hybrid)
- comment why total_ms vs stage sum can drift (millis truncation)
- TODO marker on TUI trace popup filter passthrough
Co-Authored-By: Claude Opus 4.7 (1M context)
---
crates/kebab-core/src/search.rs | 3 +++
crates/kebab-search/src/hybrid.rs | 4 ++++
crates/kebab-tui/src/search.rs | 2 ++
3 files changed, 9 insertions(+)
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,