@@ -197,6 +197,7 @@ export async function ingestDependencies(opts: {
197197 let exportResult : { jobId : number ; gcsPrefix : string ; rowCount : number }
198198 // Files already loaded into staging by the prior (resumed) job, and rows it had already merged.
199199 let resumeProgressDone = 0
200+ let resumeProgressTotal = 0
200201 let resumeRowCountPg = 0
201202 if ( opts . resumeJobId != null ) {
202203 // Reuse the prior job's exact export by id — bypasses reuse-by-kind (which excludes 'failed'
@@ -234,6 +235,7 @@ export async function ingestDependencies(opts: {
234235 }
235236 exportResult = { jobId : prior . jobId , gcsPrefix : prior . gcsPrefix , rowCount : 0 }
236237 resumeProgressDone = prior . progressDone
238+ resumeProgressTotal = prior . progressTotal
237239 resumeRowCountPg = prior . rowCountPg
238240 // Reprocess the export with its ORIGINAL settings, not the current CLI opts. A narrower
239241 // ecosystems list would drop versions-lookup rows (deps silently unmerged); the wrong fill flag
@@ -313,6 +315,20 @@ export async function ingestDependencies(opts: {
313315 )
314316 }
315317
318+ // The stored progress:done maps to chunk boundaries computed from the file count the prior run
319+ // saw (progress:total). If the re-listed count differs (objects deleted, prefix re-exported), the
320+ // boundaries no longer align: startChunk can clamp past the un-merged files and the loop marks the
321+ // job 'done' having skipped them. Fail loudly instead. Only when the prior run actually recorded
322+ // progress (>0) — a fresh 'exported' resume has progress:total 0 and restarts from chunk 0 safely.
323+ if ( resume && resumeProgressTotal > 0 && totalFiles !== resumeProgressTotal ) {
324+ throw ApplicationFailure . nonRetryable (
325+ `resume job ${ opts . resumeJobId } : parquet file count changed since the prior run ` +
326+ `(recorded ${ resumeProgressTotal } , now ${ totalFiles } at ${ exportResult . gcsPrefix } ) — ` +
327+ `the export was modified or re-exported; run a fresh export instead of --resume-job` ,
328+ 'RESUME_INVALID' ,
329+ )
330+ }
331+
316332 if ( totalFiles === 0 || totalRows === 0 ) {
317333 await mergeStagingToTable ( {
318334 jobId : exportResult . jobId ,
0 commit comments