screen-locker/screen_locker
Krzysztof kuhy Rudnicki b0d9165a79 Retry sync past the boot/resume network race, and stop blaming the token
The morning routine is started by systemd right after boot and right after
resume, so its sync ran seconds before DHCP/DNS were up. Every such run failed
outright — and said this:

    Workout sync push FAILED for 6 workout(s): network error reading
    screen-locker-sync/devices — a 403 here means the token lacks
    contents:write on kuhyx/syncs

Both halves of that were wrong. It was not a 403, and the token was fine: the
same six workouts pushed successfully by hand minutes later on the same token,
which reports push=true on the repo. The message cost a real investigation
chasing a permissions bug that did not exist.

- _sync_retry.with_sync_retry wraps the three sync call sites in a bounded
  retry (4 attempts, 2s/4s/8s backoff — ~14s, enough for the network to come
  up, short enough not to drag the routine). Verified offline in a network
  namespace: three retries, then an honest give-up.
- Any GitHubSyncError retries, deliberately including RepoNotFoundError.
  Classifying transient vs permanent would couple us to which exception
  crdt_sync chains where; a few wasted seconds on a genuinely bad token is the
  cheaper mistake.
- The push failure log now reports what actually happened. The contents:write
  hint survives only for RepoNotFoundError, which is the one error that
  actually implicates the repo or the token.

Retry at the application layer rather than ordering the unit after
network-online.target: the same race hits on resume, where boot ordering does
not apply, and these are user units that cannot depend on a system target.

The tests' autouse no-sleep fixture patches the module-local `sleep` name
rather than `_sync_retry.time.sleep` — the latter mutates the shared time
module object and silently disabled sleep for the whole suite, breaking an
unrelated temperature timeout test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 08:46:37 +02:00
..
tests Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
__init__.py Fix test discovery and coverage for python_pkg modules 2025-12-02 22:33:34 +01:00
_auto_upgrade.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_compliance_state.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_constants.py Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
_early_bird.py Add manual (unverified) workout logging with evidence form 2026-07-05 20:08:52 +02:00
_extra_benefits.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_heat_skip.py Fix pre-existing CI failures (crdt_sync dep, dead type:ignore, ruff) 2026-07-11 17:05:03 +02:00
_log_io.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_log_mixin.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_manual_push.py Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
_manual_sync.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
_manual_workout_dialog.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_manual_workout_widgets.py Redesign manual-workout form: two-column grid, drop phone-only fields 2026-07-13 10:09:18 +02:00
_manual_workout.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
_mcp.py Add read-only MCP server exposing workout/lock status 2026-07-10 21:28:09 +02:00
_phone_verification.py Make Check Phone week-aware; add RunnerUp GPS tolerance; fix CLI weekly count 2026-07-18 06:55:55 +02:00
_runnerup_db.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_runnerup_verification.py Make Check Phone week-aware; add RunnerUp GPS tolerance; fix CLI weekly count 2026-07-18 06:55:55 +02:00
_shutdown_base.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_shutdown.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_sick_dialog.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_sick_tracker.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_status_data.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_status_view_verify.py Make Check Phone week-aware; add RunnerUp GPS tolerance; fix CLI weekly count 2026-07-18 06:55:55 +02:00
_status.py Make Check Phone week-aware; add RunnerUp GPS tolerance; fix CLI weekly count 2026-07-18 06:55:55 +02:00
_sync_retry.py Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
_temperature_status_mixin.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
_temperature.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
_time_check.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
_ui_flows_relaxed.py refactor: enforce 400-line file limit with pre-commit hook and split outliers 2026-05-28 21:19:18 +02:00
_ui_flows.py Add manual (unverified) workout logging with evidence form 2026-07-05 20:08:52 +02:00
_ui_widgets.py Add manual (unverified) workout logging with evidence form 2026-07-05 20:08:52 +02:00
_wake_state.py Migrate to the shared gatelock backend 2026-06-21 20:11:16 +02:00
_weekly_check.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
_window_setup.py Migrate to the shared gatelock backend 2026-06-21 20:11:16 +02:00
_workout_credit.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
_workout_sync.py Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
adjust_shutdown_schedule.sh fix: resolve shutdown-schedule canonical path via guardctl dynamically 2026-07-04 11:48:39 +02:00
screen_lock.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
status_view.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00