@@ -370,6 +370,7 @@ impl<'a> IncrementalTableScanBuilder<'a> {
370370 let plan_context = IncrementalPlanContext {
371371 snapshots,
372372 from_snapshot : snapshot_from,
373+ from_snapshot_id : self . from_snapshot_id ,
373374 table_metadata : self . table . metadata_ref ( ) ,
374375 to_snapshot_schema : schema,
375376 object_cache : self . table . object_cache ( ) . clone ( ) ,
@@ -504,8 +505,11 @@ impl IncrementalTableScan {
504505
505506 // Collect data files that were live at from_snapshot. These are needed to generate
506507 // equality delete tasks for files that predate the scan range.
507- // Runs in parallel with the rest of the planning.
508- let from_snapshot_collection = if all_deletes. iter ( ) . any ( is_equality_delete) {
508+ // Skipped when from=None because in that case all data files are treated as appends
509+ // (full-scan semantics), so equality deletes are handled via AppendedFileScanTask.
510+ let from_snapshot_collection = if self . plan_context . from_snapshot_id . is_some ( )
511+ && all_deletes. iter ( ) . any ( is_equality_delete)
512+ {
509513 Some ( Self :: spawn_manifest_entry_collection (
510514 self . plan_context . from_snapshot . clone ( ) ,
511515 self . plan_context . table_metadata . clone ( ) ,
@@ -536,6 +540,7 @@ impl IncrementalTableScan {
536540 // Process the data file [`ManifestEntry`] stream in parallel
537541 let filter = delete_filter. clone ( ) ;
538542 let table_metadata = self . plan_context . table_metadata . clone ( ) ;
543+ let from_snapshot_is_none = self . plan_context . from_snapshot_id . is_none ( ) ;
539544 spawn ( async move {
540545 let result = manifest_entry_data_ctx_rx
541546 . map ( |me_ctx| Ok ( ( me_ctx, file_scan_task_tx. clone ( ) ) ) )
@@ -545,8 +550,13 @@ impl IncrementalTableScan {
545550 let filter = filter. clone ( ) ;
546551 let table_metadata = table_metadata. clone ( ) ;
547552 async move {
548- if manifest_entry_context. manifest_entry . status ( )
549- == ManifestStatus :: Added
553+ let status = manifest_entry_context. manifest_entry . status ( ) ;
554+ // When from=None (full-scan semantics), treat both Added and Existing
555+ // entries as appends. Existing entries arise from expired snapshots or
556+ // manifest rewrites — they represent live files that must be included.
557+ // Deleted entries are skipped since they are not live.
558+ if status == ManifestStatus :: Added
559+ || ( from_snapshot_is_none && status == ManifestStatus :: Existing )
550560 {
551561 spawn ( async move {
552562 Self :: process_data_manifest_entry (
@@ -558,9 +568,7 @@ impl IncrementalTableScan {
558568 . await
559569 } )
560570 . await
561- } else if manifest_entry_context. manifest_entry . status ( )
562- == ManifestStatus :: Deleted
563- {
571+ } else if status == ManifestStatus :: Deleted && !from_snapshot_is_none {
564572 spawn ( async move {
565573 Self :: process_deleted_data_manifest_entry (
566574 tx,
0 commit comments