- Guard enforce_allowed_game() and _guard_installed_games() against
current_app_id=None so they never treat all games as unauthorized
- Add early return in _enforce_loop_iteration when no game is assigned
- Wrap State.load() in enforce loop with error handling for corrupt files
- Switch all config/cache file writes to atomic (tmpfile + rename)
- Add robust error handling to State.load() for corrupt JSON
- Update tests for new behavior and add coverage for atomic writes
- Add comprehensive tests for all packages (3572 tests, 100% branch coverage)
- Split oversized test files to stay under 500-line limit
- Add per-file ruff ignores for test-appropriate suppressions
- Fix _cache_decks.py to properly convert JSON lists to tuples
- Add session-scoped conftest fixture for logging handler cleanup (Python 3.14)
- Update ruff pre-commit hook to v0.15.2
- Add codespell ignore words for test data
- Add generated output files to .gitignore
The enforce daemon loaded state once at startup and never reloaded it.
When the CLI reassigned a game (e.g. via 'done'), the daemon kept
enforcing the old assignment and deleted the newly assigned game every
3 seconds as 'unauthorized'.
Fix: reload state from disk at the top of each enforce loop iteration
so CLI changes take effect within one cycle.
Also add steam://install protocol handler for interactive installs
(via xdg-open) so Steam determines the correct installdir from its
own metadata, avoiding 'Missing game executable' errors from guessed
directory names in fabricated appmanifests.