garminconnect_backend gains web-friendly auth: resume() (token restore with
API validation), begin_login()/complete_mfa() (two-step MFA handshake via
return_on_mfa), user_label(), and patch_garth() split out of activate().
5_Sync.py drops the garth login flow (Cloudflare-blocked) for the new
backend; the authenticated client is cached in st.session_state. Verified
headlessly with streamlit AppTest: token restore, sync-button click, full
incremental sync, no exceptions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
garth's SSO login is Cloudflare-rate-limited (429) and garth is now
deprecated upstream. New openrun.ingest.garminconnect_backend authenticates
via python-garminconnect 0.3.5 DI Bearer tokens and shims garth's client
surface (connectapi/download/username), so the existing sync pipeline runs
unchanged. openrun-sync gains --backend {auto,garth,garminconnect}; auto
prefers garminconnect when .secrets/garmin_tokens.json exists.
Login: uv run python -m openrun.ingest.garminconnect_backend
Synced: 7 activities (-> 2026-06-02) + splits + FITs, wellness through
2026-06-12, time-in-zone recomputed (364 activities).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- .gitignore now excludes the Garmin Takeout dump (0debd9f2-*/, personal
health data), ruvector.db / agentdb.rvf scratch files, data/fit/ and
data/backups/; untracked 23,673 files (kept on disk)
- .gitlab-ci.yml runs pytest via uv on every push
- scripts/backup_db.sh snapshots data/garmin.db (keeps last 14)
- canonical DB is garmin/data/garmin.db; the stray vault-root copy
(Takeout ingest run from wrong cwd on 2026-06-08) is preserved at
data/backups/vault-root-takeout-ingest-2026-06-08.db
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>