@@ -201,7 +201,37 @@ pub fn search_with_intelligence(
201201 let fts_results = dedup_by_file ( all_fts) ;
202202
203203 // --- Graph lane from combined seeds ---
204- let combined_seeds = merge_seeds ( & semantic_results, & fts_results) ;
204+ let mut combined_seeds = merge_seeds ( & semantic_results, & fts_results) ;
205+
206+ // Inject temporal candidates as graph seeds when date_range is present
207+ let temporal_seeds: Vec < RankedResult > = if let Some ( range) = & orchestration. date_range {
208+ config
209+ . store
210+ . get_files_in_date_range ( range. 0 , range. 1 )
211+ . unwrap_or_default ( )
212+ . iter ( )
213+ . map ( |f| RankedResult {
214+ file_path : f. path . clone ( ) ,
215+ file_id : f. id ,
216+ score : 1.0 ,
217+ heading : None ,
218+ snippet : String :: new ( ) ,
219+ docid : f. docid . clone ( ) ,
220+ } )
221+ . collect ( )
222+ } else {
223+ vec ! [ ]
224+ } ;
225+ for ts in & temporal_seeds {
226+ let dominated = combined_seeds
227+ . iter ( )
228+ . any ( |s| s. file_path == ts. file_path && s. score >= ts. score ) ;
229+ if !dominated {
230+ combined_seeds. retain ( |s| s. file_path != ts. file_path ) ;
231+ combined_seeds. push ( ts. clone ( ) ) ;
232+ }
233+ }
234+
205235 let graph_results =
206236 graph:: graph_expand ( config. store , & combined_seeds, query, 2 , 20 ) . unwrap_or_default ( ) ;
207237
@@ -217,8 +247,8 @@ pub fn search_with_intelligence(
217247 ) ;
218248
219249 // --- Step 4: Reranker (4th lane) if available ---
220- let final_fused = if let Some ( reranker ) = & mut config . reranker {
221- let mut rerank_results : Vec < RankedResult > = Vec :: new ( ) ;
250+ let mut rerank_results : Vec < RankedResult > = Vec :: new ( ) ;
251+ let reranker_used = if let Some ( reranker ) = & mut config . reranker {
222252 for candidate in fused_pass1. iter ( ) . take ( config. rerank_candidates ) {
223253 let score = reranker
224254 . rerank_score ( query, & candidate. snippet )
@@ -237,8 +267,63 @@ pub fn search_with_intelligence(
237267 . partial_cmp ( & a. score )
238268 . unwrap_or ( std:: cmp:: Ordering :: Equal )
239269 } ) ;
270+ true
271+ } else {
272+ false
273+ } ;
274+
275+ // --- Step 5: Temporal lane (5th lane) when date_range is present ---
276+ let final_fused = if let Some ( range) = & orchestration. date_range {
277+ // Build temporal lane: score ALL candidates from pass1/reranked by date proximity
278+ let base_fused = if reranker_used {
279+ fusion:: rrf_fuse (
280+ & [
281+ ( "semantic" , & semantic_results, weights. semantic ) ,
282+ ( "fts" , & fts_results, weights. fts ) ,
283+ ( "graph" , & graph_results, weights. graph ) ,
284+ ( "rerank" , & rerank_results, weights. rerank ) ,
285+ ] ,
286+ RRF_K ,
287+ )
288+ } else {
289+ // Use pass1 as the candidate source; avoid clone by re-referencing
290+ fused_pass1
291+ } ;
292+ let mut temporal_results: Vec < RankedResult > = base_fused
293+ . iter ( )
294+ . filter_map ( |c| {
295+ let file = config. store . get_file ( & c. file_path ) . ok ( ) ??;
296+ let nd = file. note_date ?;
297+ let score = crate :: temporal:: temporal_score ( nd, range. 0 , range. 1 ) ;
298+ Some ( RankedResult {
299+ file_path : c. file_path . clone ( ) ,
300+ file_id : c. file_id ,
301+ score,
302+ heading : c. heading . clone ( ) ,
303+ snippet : c. snippet . clone ( ) ,
304+ docid : c. docid . clone ( ) ,
305+ } )
306+ } )
307+ . collect ( ) ;
308+ temporal_results. sort_by ( |a, b| {
309+ b. score
310+ . partial_cmp ( & a. score )
311+ . unwrap_or ( std:: cmp:: Ordering :: Equal )
312+ } ) ;
240313
241- // RRF Pass 2 (4-lane)
314+ // 5-lane RRF (rerank_results is empty when reranker absent, weight 0)
315+ fusion:: rrf_fuse (
316+ & [
317+ ( "semantic" , & semantic_results, weights. semantic ) ,
318+ ( "fts" , & fts_results, weights. fts ) ,
319+ ( "graph" , & graph_results, weights. graph ) ,
320+ ( "rerank" , & rerank_results, weights. rerank ) ,
321+ ( "temporal" , & temporal_results, weights. temporal ) ,
322+ ] ,
323+ RRF_K ,
324+ )
325+ } else if reranker_used {
326+ // Non-temporal with reranker: 4-lane (existing behavior)
242327 fusion:: rrf_fuse (
243328 & [
244329 ( "semantic" , & semantic_results, weights. semantic ) ,
@@ -249,6 +334,7 @@ pub fn search_with_intelligence(
249334 RRF_K ,
250335 )
251336 } else {
337+ // Non-temporal without reranker: 3-lane (existing behavior)
252338 fused_pass1
253339 } ;
254340
0 commit comments