Three of us approved the pull request. Three experienced engineers, all paying attention, all of whom would tell you they review carefully. The bug shipped anyway, and it was an off-by-one, which is the most embarrassing kind because it is the kind everyone claims to be vigilant about.
The code paged through results in batches. It fetched a window, processed it, advanced the offset, and stopped when a fetch came back short. The loop looked correct. It was correct, for every batch except the last, where it skipped the final record. One missing row per page of results. On a test fixture with a tidy multiple of the batch size, it passed every time, because the boundary never landed where the bug lived.
The reason it survived review is that we were all reading the same mental model. The code matched what we expected pagination to look like, so we confirmed our expectation rather than checking the edges. Nobody asked the awkward question: what happens when the total is not a clean multiple of the window? The one input that would have exposed it was the one input none of us pictured.
It surfaced in production as a slow reconciliation drift. A handful of records went unprocessed each run, the count was small enough to look like noise for a week, and then it wasn't. The fix was a one-character change to a comparison. The lesson was worth more than the fix: when you review a loop, do not check that it handles the obvious case. Check the empty input, the single element, and the one that does not divide evenly. The bug never lives in the middle. It lives at the ends, where nobody bothers to look.