From ffb9978ec6ea59716f690dc08d447b9b8fa6ee55 Mon Sep 17 00:00:00 2001 From: Zaki Manian Date: Fri, 6 Mar 2026 15:27:45 -0800 Subject: [PATCH] test(workspace): regression test for document_path in search results (#509) * test(workspace): add regression test for document_path propagation through RRF Verifies that search results carry the source document's file path through the RRF fusion pipeline, not the document UUID. Covers the bug fixed in PR #503 / issue #481. Co-Authored-By: Claude Opus 4.6 * Update src/workspace/search.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * chore: merge main and fix formatting Co-Authored-By: Claude Opus 4.6 [skip-regression-check] --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/workspace/search.rs | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/workspace/search.rs b/src/workspace/search.rs index d25dda09..29e21c33 100644 --- a/src/workspace/search.rs +++ b/src/workspace/search.rs @@ -249,6 +249,67 @@ mod tests { } } + fn make_result_with_path(chunk_id: Uuid, doc_id: Uuid, path: &str, rank: u32) -> RankedResult { + RankedResult { + chunk_id, + document_id: doc_id, + document_path: path.to_string(), + content: format!("content for chunk {}", chunk_id), + rank, + } + } + + #[test] + fn test_rrf_propagates_document_path() { + // Regression test: search results must carry the source document's + // file path, not the document UUID. See PR #503 / issue #481. + let config = SearchConfig::default().with_limit(10); + + let doc_a = Uuid::new_v4(); + let doc_b = Uuid::new_v4(); + let chunk1 = Uuid::new_v4(); + let chunk2 = Uuid::new_v4(); + let chunk3 = Uuid::new_v4(); + + let fts_results = vec![ + make_result_with_path(chunk1, doc_a, "notes/todo.md", 1), + make_result_with_path(chunk2, doc_b, "journal/2024-01-15.md", 2), + ]; + let vector_results = vec![ + make_result_with_path(chunk1, doc_a, "notes/todo.md", 1), + make_result_with_path(chunk3, doc_b, "journal/2024-01-15.md", 2), + ]; + + let results = reciprocal_rank_fusion(fts_results, vector_results, &config); + + for result in &results { + // The path must be a real file path, never a UUID string + assert!( + Uuid::parse_str(&result.document_path).is_err(), + "document_path looks like a UUID ('{}'), expected a file path", + result.document_path + ); + } + + // Verify exact paths are preserved + let paths: Vec<&str> = results.iter().map(|r| r.document_path.as_str()).collect(); + assert!( + paths.contains(&"notes/todo.md"), + "missing notes/todo.md in {:?}", + paths + ); + assert!( + paths.contains(&"journal/2024-01-15.md"), + "missing journal/2024-01-15.md in {:?}", + paths + ); + + // Hybrid match (chunk1) should preserve the correct path + let hybrid = results.iter().find(|r| r.chunk_id == chunk1).unwrap(); + assert_eq!(hybrid.document_path, "notes/todo.md"); + assert!(hybrid.is_hybrid()); + } + #[test] fn test_rrf_single_method() { let config = SearchConfig::default().with_limit(10);