screen-locker/screen_locker/tests
Krzysztof kuhy Rudnicki c0aae7d05b Make the lock overlay's sport selector usable, and focus its form fields
The manual-workout sport selector was a `tk.OptionMenu`, and while the screen
was locked it could not be changed. A posted Tk menu is a separate
override-redirect toplevel that takes the Tk grab for itself, and gatelock's
1s recovery tick attacks it from both sides: `_surfaces.enforce()` lifts the
lock surface over the menu, and `_reassert_grab()` read the grab sitting on
the menu as "the grab was lost" and yanked it back. The menu opened on click
and died within a second. On 2026-07-26 that forced an hour-long walk to be
logged through the table-tennis form, with the reason typed into `racket`.

Radio buttons instead. They are ordinary children of the surface, so they
lift with it and live inside the root's grab tree -- neither mechanism can
reach them. That is a structural guarantee, not a tuned workaround; the
alternative, teaching gatelock to skip its lift while a popup is posted,
would open a window where something could cover the lock. They are also the
first version of this control styled from the shared palette, where the
OptionMenu was default grey on the dark overlay.

Nothing on a lock surface may open a popup, so two halves enforce it. The
static half walks each module's AST for popup-creating names -- AST rather
than a source regex because the modules explain this bug in prose that names
the very widgets being banned. Its module list is derived ("imports tkinter",
minus a short reasoned exemption list) rather than hardcoded, so a new lock
screen is in scope the day it is written; a hardcoded list drafted today
would already have missed `_sick_dialog`. The behavioural half is
`scripts/verify_lock_popup_safety.py`: it builds the real form with real Tk,
replays both hostile behaviours for five ticks, and re-runs the original
failure so the mechanism stays demonstrated rather than described. It
re-execs itself under Xvfb -- a global grab on the developer's own session
would freeze it -- and a CI job runs it, because the pytest suite replaces
the whole `tk` module and so cannot host it.

Separately, no field ever took keyboard focus. Under a global grab that means
typing goes nowhere with no other window on screen to reveal why. The
manual-workout and sick-justification forms now each name their own first
field via a `focus=` flag; `on_focus_ready` genuinely has nothing to focus
(it fires before those screens exist) and its docstring now says that instead
of claiming the lock window has no typed input at all.

`scripts/fix_2026_07_26_sport.py` re-files that walk as sport "other",
rebuilt through the form's own draft/validate/build path so it carries
exactly the writer's key set, and re-signed. `start_time` and the date are
untouched so `workout_id` stays stable and the phone converges instead of
gaining a duplicate. Kept as the audit trail for the edit; the walk's details
come from the entry and `--details`, so nothing personal lands in a tracked
file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 15:08:08 +02:00
..
__init__.py Add comprehensive tests for stockfish_analysis (100% coverage) 2025-12-02 22:58:06 +01:00
_gatelock_fixtures.py Migrate screen_locker to gatelock v0.2.0 per-output locking 2026-07-25 16:26:39 +02:00
_locker_factories.py Migrate screen_locker to gatelock v0.2.0 per-output locking 2026-07-25 16:26:39 +02:00
_status_view_helpers.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
conftest.py Migrate screen_locker to gatelock v0.2.0 per-output locking 2026-07-25 16:26:39 +02:00
test_adb_and_phone.py Restore consistency with WORKOUT_APP_JSON_REMOTES rename in _constants.py 2026-06-22 07:05:07 +02:00
test_compliance_state_part2.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_compliance_state.py Add manual (unverified) workout logging with evidence form 2026-07-05 20:08:52 +02:00
test_early_bird_part2.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
test_early_bird.py Add manual (unverified) workout logging with evidence form 2026-07-05 20:08:52 +02:00
test_extra_benefits.py Add manual (unverified) workout logging with evidence form 2026-07-05 20:08:52 +02:00
test_heat_skip.py Add manual (unverified) workout logging with evidence form 2026-07-05 20:08:52 +02:00
test_init_and_log_part2.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
test_init_and_log.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
test_log_io.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
test_log_mixin_chokepoint.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
test_manual_push.py Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
test_manual_sync.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_manual_workout_dialog.py Make the lock overlay's sport selector usable, and focus its form fields 2026-07-26 15:08:08 +02:00
test_manual_workout_features.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_manual_workout_status_view.py Wire gatelock.LockConfig into every window, not just the lock overlay 2026-07-21 21:45:59 +02:00
test_manual_workout.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_mcp.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
test_no_popup_widgets.py Make the lock overlay's sport selector usable, and focus its form fields 2026-07-26 15:08:08 +02:00
test_phone_check_unlock_part2.py chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
test_phone_check_unlock_part3.py Add auto-fill RunnerUp scan, carrot bonuses, and --status interface 2026-06-28 08:08:35 +02:00
test_phone_verification_part2.py chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
test_phone_verification_part3.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_phone_verification_part4.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_phone_verification_part5.py Pin the StrongLifts week-scan tests to a fixed Wednesday 2026-07-20 08:57:25 +02:00
test_runnerup_verification_part1.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_runnerup_verification_part2.py Make Check Phone week-aware; add RunnerUp GPS tolerance; fix CLI weekly count 2026-07-18 06:55:55 +02:00
test_runnerup_verification_part3.py Support multiple workouts per day; fix the dead sync; ban silent failures 2026-07-17 09:22:31 +02:00
test_runnerup_verification_part4.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_runnerup_verification_part5.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_scheduled_skip.py Add auto-fill RunnerUp scan, carrot bonuses, and --status interface 2026-06-28 08:08:35 +02:00
test_screen_lock_coverage_part1.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_screen_lock_coverage_part2.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_shutdown_base.py Add auto-fill RunnerUp scan, carrot bonuses, and --status interface 2026-06-28 08:08:35 +02:00
test_shutdown_part2.py refactor: enforce 400-line file limit with pre-commit hook and split outliers 2026-05-28 21:19:18 +02:00
test_shutdown_part3.py chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
test_shutdown_part4.py Add auto-fill RunnerUp scan, carrot bonuses, and --status interface 2026-06-28 08:08:35 +02:00
test_sick_features_part2.py refactor: enforce 400-line file limit with pre-commit hook and split outliers 2026-05-28 21:19:18 +02:00
test_sick_features.py Migrate screen_locker to gatelock v0.2.0 per-output locking 2026-07-25 16:26:39 +02:00
test_sick_tracker.py chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
test_status_data.py Fix CI-only failure: avoid dating a test entry "today" without HMAC 2026-07-19 13:56:44 +02:00
test_status_part2.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_status_view_part2.py Wire gatelock.LockConfig into every window, not just the lock overlay 2026-07-21 21:45:59 +02:00
test_status_view_part3.py Make Check Phone week-aware; add RunnerUp GPS tolerance; fix CLI weekly count 2026-07-18 06:55:55 +02:00
test_status_view.py Wire gatelock.LockConfig into every window, not just the lock overlay 2026-07-21 21:45:59 +02:00
test_status.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_surface_fanout.py Migrate screen_locker to gatelock v0.2.0 per-output locking 2026-07-25 16:26:39 +02:00
test_sync_fixtures.py Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
test_sync_retry.py Retry sync past the boot/resume network race, and stop blaming the token 2026-07-20 08:46:37 +02:00
test_temperature.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_time_check.py chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
test_ui_and_timers_part2.py chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
test_ui_and_timers.py Migrate screen_locker to gatelock v0.2.0 per-output locking 2026-07-25 16:26:39 +02:00
test_ui_flows_part2.py Add auto-fill RunnerUp scan, carrot bonuses, and --status interface 2026-06-28 08:08:35 +02:00
test_verify_workout.py Migrate screen_locker to gatelock v0.2.0 per-output locking 2026-07-25 16:26:39 +02:00
test_vt_switching.py Migrate to the shared gatelock backend 2026-06-21 20:11:16 +02:00
test_wake_shutdown.py chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
test_wake_skip.py Add auto-fill RunnerUp scan, carrot bonuses, and --status interface 2026-06-28 08:08:35 +02:00
test_wake_state.py fix: apply pre-commit formatting fixes to unblock CI 2026-05-28 20:59:35 +02:00
test_weekly_check.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_weekly_logic_part2.py Add phone-workout GitHub sync via shared crdt_sync (Workstream C) 2026-07-11 00:06:59 +02:00
test_weekly_logic.py Give manual workouts full effect parity; raise minimum to 5, double budget 2026-07-19 13:50:39 +02:00
test_workout_sync.py Manual-workout phone sync P2: PC ingestion (multi-record + manual branch) 2026-07-13 11:15:07 +02:00