A 429 is the reMarkable cloud saying 'too many requests, slow down' — and for days in August your poller ignored it, logging 3,116 of them. The fix is backoff, cooldowns, and a timeout that outlasts the backoff.
The old rm_pull design fetched a FULL document archive per held doc every 20-minute poll. At 24 held docs on a device carrying 112, that hammered straight past the account's rate limit — 3,116 logged 429s that throttled the account for days. The rebuild you shipped 8-26 is a small master class in living inside someone else's rate limit.
A rate limit is a server's rule: 'no more than N requests per window.' Cross it and you get HTTP 429 Too Many Requests — not an error in your code, a request to back off. The wrong response is to retry immediately (that's more load on an already-overloaded door); the right one is exponential backoff — wait 1s, then 2s, then 4s, growing the gap so the server can drain. The reMarkable bridge does this internally, and a single archive fetch can now sit in a ~10.5-minute backoff before it succeeds.
The rebuilt rm_pull.py attacks the problem from three sides. First, cheap probes: instead of fetching an archive per held doc, one light `tags` call covers ALL due docs in a single bridge invocation — archives are paid for only on an actual release. Second, cooldowns: TAGCHECK_COOLDOWN_S = 1200 (20 min) between probes of the same doc, six hours for REFERENCE docs, so even the light traffic is bounded. Third, a self-expiring quiet window — writing an epoch into rm-quiet-until silences the poller with ZERO API calls while the rolling throttle drains, and it expires on its own so there's no restore step to forget.
The subtlest fix is one number. The bun call's timeout was raised to 780 seconds because it must EXCEED the bridge's ~10.5-minute 429-backoff window. The earlier 300s timeout was killing bun mid-backoff — so a fetch would consume rate-limit budget, get cut off before the backoff paid out, and return nothing, then try again. A timeout shorter than the backoff it's supposed to wait through doesn't cap the work; it just guarantees the work never finishes.
The rate-limit defenses are all readable in one file — and the device-count signal is one cat away.
grep -nE 'COOLDOWN|PROBE_CAP|429|quiet|timeout: int' /Users/tom/Claude/PDB/scripts/rm_pull.py
cat '/Users/tom/Claude/PDB/data/rm-device-count.json'
A 429 is an instruction, not a failure — obey it with backoff, bound it with cooldowns, and make every timeout longer than the wait it has to sit through.