@@ -526,22 +526,35 @@ async fn handle_explain(
526526 let corrections = execute_plan ( & state, & plan_corr) . await ;
527527
528528 // Segment provenance from the manifest. Filtering by bucket here
529- // matches the executor's pruning — the same segments the query would
530- // open are the ones we report.
531- let ( watermark_ms, rollup_segments, raw_segments) = {
529+ // matches the executor's pruning. For each overlapping rollup
530+ // segment we also surface its `input_segment_ids` so an operator
531+ // can name every raw segment that contributed to a rollup line —
532+ // spec §19.10 (invoice snapshots reference a watermark + source
533+ // segment set).
534+ let ( watermark_ms, rollup_segments, rollup_inputs, raw_segments) = {
532535 let manifest = state. manifest . read ( ) . await ;
533536 let bucket_count = manifest. bucket_count . max ( 1 ) ;
534537 let target_bucket = bucket_for_account ( & AccountId ( account_id. clone ( ) ) , bucket_count) ;
535- let rollups: Vec < String > = manifest
536- . rollup_segments
537- . iter ( )
538- . filter ( |s| {
539- s. bucket == target_bucket
540- && s. min_timestamp_ms < to_ms
541- && s. max_timestamp_ms >= from_ms
542- } )
543- . map ( |s| s. segment_id . clone ( ) )
544- . collect ( ) ;
538+ let mut rollup_ids = Vec :: new ( ) ;
539+ let mut inputs_map = serde_json:: Map :: new ( ) ;
540+ for s in & manifest. rollup_segments {
541+ if s. bucket != target_bucket
542+ || s. min_timestamp_ms >= to_ms
543+ || s. max_timestamp_ms < from_ms
544+ {
545+ continue ;
546+ }
547+ rollup_ids. push ( s. segment_id . clone ( ) ) ;
548+ inputs_map. insert (
549+ s. segment_id . clone ( ) ,
550+ serde_json:: Value :: Array (
551+ s. input_segment_ids
552+ . iter ( )
553+ . map ( |id| serde_json:: Value :: String ( id. clone ( ) ) )
554+ . collect ( ) ,
555+ ) ,
556+ ) ;
557+ }
545558 let raws: Vec < String > = manifest
546559 . raw_segments
547560 . iter ( )
@@ -552,7 +565,12 @@ async fn handle_explain(
552565 } )
553566 . map ( |s| s. segment_id . clone ( ) )
554567 . collect ( ) ;
555- ( manifest. watermarks . hourly_rollup_ms , rollups, raws)
568+ (
569+ manifest. watermarks . hourly_rollup_ms ,
570+ rollup_ids,
571+ inputs_map,
572+ raws,
573+ )
556574 } ;
557575
558576 Ok ( Json ( serde_json:: json!( {
@@ -562,6 +580,7 @@ async fn handle_explain(
562580 "watermark_ms" : watermark_ms,
563581 "lines" : lines,
564582 "rollup_segments" : rollup_segments,
583+ "rollup_inputs" : rollup_inputs,
565584 "raw_segments" : raw_segments,
566585 "corrections" : corrections,
567586 } ) ) )
0 commit comments