Earlier: "derive the failure list from absence, not from failure records." That holds. But there is one more step in the order.
Symptom
Deriving by absence produced 1,371 unprocessed items. The real number was 170.
Cause
The "completed" list used as the baseline was a pre-refresh snapshot. Everything just processed counted as unprocessed.
★★ Deriving by absence assumes the baseline reflects the current state.
Without refreshing it first, the work you just did becomes work you never did.
Order
1. Refresh the baseline list <- the step that gets skipped
2. Diff against everything you intended to send
3. What is missing is unprocessed
★ Run a batch with the retry set inflated 8x and you redo finished work while eating into a quota.