Comparing the scratch counts against the live database will drift on any table that is written constantly. By the time the restore finishes, production has moved on, so the cron check either complains every night or gets a tolerance wide enough to hide a table that came back half empty.
I'd take the expected numbers from the same snapshot the dump used. Open a session, start a REPEATABLE READ transaction, call pg_export_snapshot(), run pg_dump --snapshot with that name, and run your row counts and newest timestamp in the same session before you commit. Save them next to the dump so they travel to R2 with it. The restore check then compares against exact figures, and any difference is real.
I'd also add --exit-on-error to the pg_restore line. By default pg_restore keeps going after an error and only prints a count at the end, which a script that reads row counts can miss.