steam-backlog-enforcer/steam_backlog_enforcer
Krzysztof kuhy Rudnicki 401031602e Always allow games with zero achievements
Owned games Steam confirms have no achievements can never be assigned or
completed, so the enforcer no longer uninstalls, hides or kills them as
unauthorized. The gaming-time budget kill still applies to them.

Fail-closed: unknown status (no cache, other account, unreadable config
or snapshot, request error) keeps a game enforced. The set comes from
no_achievements_cache.json minus snapshot.json, so a game that gains
achievements is enforced again after the next scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWWAkVShjD2Bo6hM88B
2026-11-01 22:00:35 +01:00
..
docs pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
jobs pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
main fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
tests Always allow games with zero achievements 2026-11-01 22:00:35 +01:00
__init__.py feat: steam 100 percent extension 2026-03-02 20:29:32 +01:00
_achievement_skip.py Always allow games with zero achievements 2026-11-01 22:00:35 +01:00
_actions.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_allowed_games.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_assignment_progress.py Release a game after one new achievement instead of 100% completion 2026-09-26 16:46:03 +02:00
_attribution_labels.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_backups.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_bonus_incident.py Pay an hour of gaming budget for a LeetCode solve 2026-08-30 15:22:18 +02:00
_budget_games.py Show which games make up the gaming budget, and bill osu!lazer 2026-08-29 18:32:03 +02:00
_budget_log_tail.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_budget_resolve.py budget: price the enforced budget by the 06:00 gaming day's leisure switch 2026-10-19 17:09:33 +02:00
_budget_view.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_cdp.py Grade against 3.14 too, not just run on it 2026-08-29 11:44:25 +02:00
_cmd_done_finalize.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_cmd_done.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_cmd_playtime.py tests: block real kills/Steam spawns (a stale demo test killed the live game); enforce --demo is budget-only 2026-10-10 19:15:11 +02:00
_command_catalog.py tests: block real kills/Steam spawns (a stale demo test killed the live game); enforce --demo is budget-only 2026-10-10 19:15:11 +02:00
_command_gate.py total block: two-unit countdown (2w 2d … 45s), ticking every second 2026-10-23 20:59:41 +02:00
_command_help.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_command_locks.py tests: block real kills/Steam spawns (a stale demo test killed the live game); enforce --demo is budget-only 2026-10-10 19:15:11 +02:00
_command_params.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_config_setup.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_client.py fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
_ctl_context.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_control.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_gap.py tests: block real kills/Steam spawns (a stale demo test killed the live game); enforce --demo is budget-only 2026-10-10 19:15:11 +02:00
_ctl_ops.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_ctl_pending.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_protocol.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_reset.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_restart.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_server.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_ctl_types.py fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
_ctl_wire.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_desktop_env.py Pass SDL_JOYSTICK_HIDAPI_LG4FF=0 to Steam so the G29 keeps force feedback 2026-09-14 21:35:15 +02:00
_echo.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_enforce_demo.py total block: two-unit countdown (2w 2d … 45s), ticking every second 2026-10-23 20:59:41 +02:00
_enforce_guards.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_enforce_loop.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_enforce_steps.py Install games with steam-game-installer (depotdownloader) for speed, falling back to steam://install 2026-09-25 18:45:27 +02:00
_fast_install_cmd.py fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
_fast_install_failure.py fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
_fast_install_progress.py fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
_fast_install.py fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
_file_wake.py budget: wake on screen-locker's log.json; stat stamps drop stale earner answers 2026-10-09 18:52:58 +02:00
_friction.py buy-dlc: fixed-length phrase the daemon accepts (was an unfillable {minutes} slot) 2026-10-10 16:11:32 +02:00
_game_names.py pylint: clear the mechanical residue, the howlongtobeatpy 1.0.23 call, and three duplicate blocks 2026-09-12 20:31:27 +02:00
_gaming_days.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_gaming_reset.py playtime: drop the Fri-Mon carry-over; log budget on change only 2026-10-18 21:37:29 +02:00
_hltb_cached.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_hltb_comp_extract.py Grade against 3.14 too, not just run on it 2026-08-29 11:44:25 +02:00
_hltb_confidence.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_hltb_detail.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_hltb_matching.py pylint: clear the mechanical residue, the howlongtobeatpy 1.0.23 call, and three duplicate blocks 2026-09-12 20:31:27 +02:00
_hltb_page_parse.py Grade against 3.14 too, not just run on it 2026-08-29 11:44:25 +02:00
_hltb_search_api.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_hltb_search.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_hltb_types.py pylint: clear the mechanical residue, the howlongtobeatpy 1.0.23 call, and three duplicate blocks 2026-09-12 20:31:27 +02:00
_hosts_protection.py pylint: fold the remaining split-era duplicates back into single owners 2026-09-12 20:49:12 +02:00
_ledger_earners.py deps: earned_time 0.8.0 (per-minute tutor credit), fix stale 15-minute block comments 2026-10-10 18:22:04 +02:00
_leetcode_bonus.py LeetCode hour needs the day paid in full (earned_time 0.18.0); gate_off read live from leetcode-guard 2026-10-24 13:26:28 +02:00
_leetcode_ledger.py LeetCode hour needs the day paid in full (earned_time 0.18.0); gate_off read live from leetcode-guard 2026-10-24 13:26:28 +02:00
_leisure_kill.py leisure kill: a reason's start time pins the process (PID reuse) 2026-10-19 17:10:44 +02:00
_leisure_mode.py leisure Phase 2 (dormant): bill, warn and kill on the leisure budget from go-live 2026-10-19 16:40:49 +02:00
_leisure_never_kill.py leisure kill: never signal the desktop session, whatever now.json says 2026-10-19 17:03:09 +02:00
_leisure_procs.py leisure kill: wsg-grabber only as the program run; see through (deleted) exes 2026-10-19 17:01:21 +02:00
_manual_pick_lifecycle.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_mcp_actions.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_mcp_gaming_time.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_mcp_query.py Import split-out names from the modules that own them; drop the four lazy facades 2026-09-12 20:22:44 +02:00
_mcp_server.py Deduplicate snapshot loading, pick application and library hiding into shared helpers 2026-09-25 18:44:07 +02:00
_mcp.py Split total-block, playtime and MCP by responsibility 2026-08-23 20:52:08 +02:00
_own_pick.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_owned_apps_cache.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_pacman.py Grade against 3.14 too, not just run on it 2026-08-29 11:44:25 +02:00
_pick_completion.py Release a game after one new achievement instead of 100% completion 2026-09-26 16:46:03 +02:00
_pick_keep.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_playtime_block.py Split total-block, playtime and MCP by responsibility 2026-08-23 20:52:08 +02:00
_playtime_budget.py leisure Phase 2 (dormant): bill, warn and kill on the leisure budget from go-live 2026-10-19 16:40:49 +02:00
_playtime_cutoff.py leisure Phase 2 (dormant): bill, warn and kill on the leisure budget from go-live 2026-10-19 16:40:49 +02:00
_playtime_history_parse.py Show which games make up the gaming budget, and bill osu!lazer 2026-08-29 18:32:03 +02:00
_playtime_history.py Show which games make up the gaming budget, and bill osu!lazer 2026-08-29 18:32:03 +02:00
_playtime_kill.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_playtime_legacy.py playtime: drop the Fri-Mon carry-over; log budget on change only 2026-10-18 21:37:29 +02:00
_playtime_log.py playtime: drop the Fri-Mon carry-over; log budget on change only 2026-10-18 21:37:29 +02:00
_playtime_mountinfo.py Grade against 3.14 too, not just run on it 2026-08-29 11:44:25 +02:00
_playtime_notify.py Grade against 3.14 too, not just run on it 2026-08-29 11:44:25 +02:00
_playtime_record.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_playtime_run.py Grade against 3.14 too, not just run on it 2026-08-29 11:44:25 +02:00
_playtime_session.py leisure Phase 2 (dormant): bill, warn and kill on the leisure budget from go-live 2026-10-19 16:40:49 +02:00
_playtime_state.py leisure Phase 2 (dormant): bill, warn and kill on the leisure budget from go-live 2026-10-19 16:40:49 +02:00
_playtime.py leisure Phase 2 (dormant): bill, warn and kill on the leisure budget from go-live 2026-10-19 16:40:49 +02:00
_polls_reporting.py pylint: fold the remaining split-era duplicates back into single owners 2026-09-12 20:49:12 +02:00
_progress.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_prompter.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_protected_apps.py Stop the enforcer launching Steam and notifications as root 2026-08-24 13:55:44 +02:00
_reading_bonus.py budget: wake on screen-locker's log.json; stat stamps drop stale earner answers 2026-10-09 18:52:58 +02:00
_remaining.py total block: two-unit countdown (2w 2d … 45s), ticking every second 2026-10-23 20:59:41 +02:00
_scanning_assign.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_scanning_candidates.py pylint: clear the mechanical residue, the howlongtobeatpy 1.0.23 call, and three duplicate blocks 2026-09-12 20:31:27 +02:00
_scanning_confidence.py pylint: clear the mechanical residue, the howlongtobeatpy 1.0.23 call, and three duplicate blocks 2026-09-12 20:31:27 +02:00
_scanning_tampering.py Always allow games with zero achievements 2026-11-01 22:00:35 +01:00
_serve_guard.py Stop the web UI serving numbers the enforcer is not applying 2026-08-29 23:39:40 +02:00
_serve_stale.py Stop the web UI serving numbers the enforcer is not applying 2026-08-29 23:39:40 +02:00
_serve_startup.py Make serve re-runnable, and cover it to 100% 2026-08-29 18:52:11 +02:00
_shadow_log.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_shadow_view.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_shadow.py leisure Phase 2 (dormant): bill, warn and kill on the leisure budget from go-live 2026-10-19 16:40:49 +02:00
_snapshot.py Deduplicate snapshot loading, pick application and library hiding into shared helpers 2026-09-25 18:44:07 +02:00
_state_migrations.py Release a game after one new achievement instead of 100% completion 2026-09-26 16:46:03 +02:00
_stats_display.py Import split-out names from the modules that own them; drop the four lazy facades 2026-09-12 20:22:44 +02:00
_stats_gathering.py Import split-out names from the modules that own them; drop the four lazy facades 2026-09-12 20:22:44 +02:00
_stats_types.py Bring _stats.py and scanning.py under the 250-line cap 2026-08-24 16:00:54 +02:00
_stats.py Deduplicate snapshot loading, pick application and library hiding into shared helpers 2026-09-25 18:44:07 +02:00
_status_api.py budget: wake on screen-locker's log.json; stat stamps drop stale earner answers 2026-10-09 18:52:58 +02:00
_steam_api_client.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_steam_client.py Install games with steam-game-installer (depotdownloader) for speed, falling back to steam://install 2026-09-25 18:45:27 +02:00
_steam_errors.py Install games with steam-game-installer (depotdownloader) for speed, falling back to steam://install 2026-09-25 18:45:27 +02:00
_steam_launch.py Install games with steam-game-installer (depotdownloader) for speed, falling back to steam://install 2026-09-25 18:45:27 +02:00
_steam_models.py Split steam_api and _scanning_confidence under the cap 2026-08-24 14:25:43 +02:00
_steam_process.py restart safety: own scope for launched Steam, hold the day's budget, re-arm warnings after a raise 2026-10-04 19:14:20 +02:00
_steam_restart_guard.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_steam_state.py fix: fast install ignores other downloads; install offers any allowed game 2026-10-16 15:21:00 +02:00
_store_iptables.py Deduplicate snapshot loading, pick application and library hiding into shared helpers 2026-09-25 18:44:07 +02:00
_store_tools.py Timed store window that survives hosts reinstalls; whitelist exceptions stay visible 2026-10-03 13:43:32 +02:00
_store_window.py Timed store window that survives hosts reinstalls; whitelist exceptions stay visible 2026-10-03 13:43:32 +02:00
_total_block_domains.py Split total-block, playtime and MCP by responsibility 2026-08-23 20:52:08 +02:00
_total_block_hosts.py pylint: fold the remaining split-era duplicates back into single owners 2026-09-12 20:49:12 +02:00
_total_block_iptables.py Deduplicate snapshot loading, pick application and library hiding into shared helpers 2026-09-25 18:44:07 +02:00
_total_block_purge.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_total_block.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
_web_art.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_auth.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_build.py Make serve re-runnable, and cover it to 100% 2026-08-29 18:52:11 +02:00
_web_daemon.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_web_dataset.py Show which games make up the gaming budget, and bill osu!lazer 2026-08-29 18:32:03 +02:00
_web_errors.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_games.py Bring _web_dataset.py under the 250-line cap — cap campaign complete 2026-08-24 16:08:12 +02:00
_web_io.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_jobs.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_library.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_models.py Bring _web_dataset.py under the 250-line cap — cap campaign complete 2026-08-24 16:08:12 +02:00
_web_pace.py Bring _web_dataset.py under the 250-line cap — cap campaign complete 2026-08-24 16:08:12 +02:00
_web_privileged.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_process.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_routes.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_server.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_setup.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_sse.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
_web_views.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
_whitelist_locking.py pylint: fold the remaining split-era duplicates back into single owners 2026-09-12 20:49:12 +02:00
_whitelist.py pylint: fold the remaining split-era duplicates back into single owners 2026-09-12 20:49:12 +02:00
_workout_budget.py budget: wake on screen-locker's log.json; stat stamps drop stale earner answers 2026-10-09 18:52:58 +02:00
config.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
enforcer.py playtime: shadow leisure billing (C4); /proc scan from leisure_watch 2026-10-19 12:37:01 +02:00
game_install.py fast install: never report a failed run as success; queue the manifest first 2026-10-24 08:36:57 +02:00
game_uninstall.py Always allow games with zero achievements 2026-11-01 22:00:35 +01:00
hltb.py pylint: fold the remaining split-era duplicates back into single owners 2026-09-12 20:49:12 +02:00
library_hider.py Always allow games with zero achievements 2026-11-01 22:00:35 +01:00
protondb.py web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0 2026-10-10 16:07:42 +02:00
scanning.py pick keeps already-picked games; fast install reports progress 2026-10-23 20:14:12 +02:00
steam_api.py Split steam_api and _scanning_confidence under the cap 2026-08-24 14:25:43 +02:00
store_blocker.py Timed store window that survives hosts reinstalls; whitelist exceptions stay visible 2026-10-03 13:43:32 +02:00