Post-merge audit of #3272 found two regressions:
1. ListOAuthRefreshCandidates used "AND NOT (a AND b)" which, under PG
3-valued logic, evaluates to NULL when both temp_unschedulable_until
and temp_unschedulable_reason are NULL — i.e., the common healthy
account state. Such rows were silently excluded from the background
token refresh worker, so their OAuth access tokens would never get
refreshed and eventually start returning 401.
Verified empirically against PostgreSQL: only 3 of 5 test rows
matched before the fix; after switching to "(a AND b) IS NOT TRUE"
the expected 4 rows match.
2. The new ListOAuthRefreshCandidates method on AccountRepository was
not implemented on stubAccountRepo in api_contract_test.go (build
tag "unit"), breaking "make test-unit" which CI runs in
.github/workflows/backend-ci.yml.
Tests:
- Added IS NOT TRUE and "AND NOT (" assertions to the SQL-shape unit
test so the predicate can't regress to the broken form again.
- "go test -tags=unit ./internal/..." now passes cleanly.