f8085f2e03
I added two more classifier unit tests for the attribute narrowing: a bare .code attribute that happens to be 401, and a bare .status attribute that happens to be 403, both must stay classified as transient since only .http_status is trustworthy. I also added a parametrized test for the five transient exception types the sync loop now short-circuits on. On top of that I added two tests that exercise _sync_loop directly instead of just the classifier function in isolation. One replays the real 502 Umbrel repro string through a mocked client.sync and confirms the loop retries with the 5s backoff. The other raises a genuine M_FORBIDDEN error and confirms the loop stops on the first call with no retry sleep. These catch a regression in how the loop wires the classifier in, not just a regression in the classifier itself. (cherry picked from commit f747bb4b5a6e6da1bb9136168f08d6e7af5ea64b)