BatchProgress.eta is computed from an overall-average rate (loaded / elapsedSinceFirstByte). A long stall or a slow tail therefore drags the average down and inflates the ETA for the whole batch, even while healthy items are streaming fast.
Proposal
Compute the rate over a moving window (or an EWMA) so the ETA reflects recent throughput. Keep it deterministic under the injected Clock — ProgressAggregator already takes one, so the manualClock unit tests in download-batch-progress.spec.ts extend cleanly.
Note: aggregate total also under-counts while items are still queued (sizes unknown until they start), so early ETAs are optimistic — a caller-supplied or HEAD-probed size could firm that up (larger, separate scope).
Introduced alongside #451; P8 / P17 in the rig spec.
BatchProgress.etais computed from an overall-average rate (loaded / elapsedSinceFirstByte). A long stall or a slow tail therefore drags the average down and inflates the ETA for the whole batch, even while healthy items are streaming fast.Proposal
Compute the rate over a moving window (or an EWMA) so the ETA reflects recent throughput. Keep it deterministic under the injected
Clock—ProgressAggregatoralready takes one, so themanualClockunit tests indownload-batch-progress.spec.tsextend cleanly.Note: aggregate
totalalso under-counts while items are still queued (sizes unknown until they start), so early ETAs are optimistic — a caller-supplied or HEAD-probed size could firm that up (larger, separate scope).Introduced alongside #451; P8 / P17 in the rig spec.