Extracts the near-identical "Sync settings" UI duplicated across 5 apps
(todo, diet_guard_app, workout_app, wake_alarm/phone_app, home_inventory)
into a single tested package. Firebase sync (primary) + optional local
backup slot; GitHub mirror UI was dropped per kuhy's explicit decision
mid-build in favor of Firebase-only, so existing apps keep their local
GitHub code untouched, just disconnected from this shared screen.
100% line coverage, flutter analyze clean under very_good_analysis.
Generalized check_no_crdt_sync_override.sh to guard any utils git
dependency (crdt_sync, sync_settings_ui), not just crdt_sync by name.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdSp6Nbrs9xvsWkCMDN9a1
Two changes to the shared sync credential path, both driven by devices
that reported "Connected" while every sync failed.
Google sign-in (signInWithGoogle, both languages) replaces typing the
sync account's password on a fresh install. The account is linked once
from the PC with tool/link_google.py, which asserts the pinned uid --
without that assertion an unlinked identity is *signed up* rather than
refused, and the new uid is then denied every read and write by the
security rules.
The second change is the one with teeth. hasSession() is a presence
check, so a refresh token the server had revoked still read as a live
session: the desktop todo build showed "Connected" and then failed every
sync with `HTTP 400 (TOKEN_EXPIRED)`. A refresh that fails for a terminal
reason now clears the stored session, so hasSession() answers honestly.
Deliberately narrow: only TOKEN_EXPIRED, USER_DISABLED, USER_NOT_FOUND,
INVALID_REFRESH_TOKEN, INVALID_GRANT_TYPE and MISSING_REFRESH_TOKEN
clear it. A network error or a 5xx must not -- a device that signs
itself out whenever the wifi drops needs a manual sign-in on every
device to recover, which is worse than the stale banner this fixes.
Verified against the live endpoint, not just mocks: has_session flips
True -> False on a real rejection.
crdt_sync_dart 0.9.0 -> 0.10.0; the five apps pin the matching tag.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0192EkoAyFBEWTvAN5vVgmSy