feat(enforcer): raise manual pick cap from 2 to 3 concurrent games
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.12) (push) Has been cancelled

Config.max_manual_picks is the single source of truth for how many
games may be locked in at once; enforcement, CLI, and MCP tooling all
already read it dynamically. Updates docs referencing the old default.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Krzysztof Rudnicki 2026-07-23 18:05:29 +02:00
parent ba412ca04f
commit cdc453bdf4
3 changed files with 12 additions and 12 deletions

View File

@ -113,7 +113,7 @@
<body> <body>
<h1>Manual picks: a way out, and a second slot</h1> <h1>Manual picks: a way out, and a second slot</h1>
<p class="sub">Two changes to the Steam Backlog Enforcer — a 4-day window to undo a manual pick, and support for two locked-in games at once. Commits <code>eb1472a</code> and <code>05e070c</code>, 19 July 2026.</p> <p class="sub">Two changes to the Steam Backlog Enforcer — a 4-day window to undo a manual pick, and support for up to three locked-in games at once. Commits <code>eb1472a</code> and <code>05e070c</code>, 19 July 2026.</p>
<nav class="toc"> <nav class="toc">
<strong>Contents</strong> <strong>Contents</strong>
@ -227,9 +227,9 @@ abandon that one. Each new pick stamps a fresh <code>started_at</code>, so the g
forever and the enforcer enforces nothing.</p> forever and the enforcer enforces nothing.</p>
<p>The chosen answer was not to forbid re-picking, but to make a second concurrent pick a <p>The chosen answer was not to forbid re-picking, but to make a second concurrent pick a
first-class, <em>capped</em> feature. If you may legitimately have two games locked in, correcting first-class, <em>capped</em> feature. If you may legitimately have several games locked in, correcting
a pick no longer requires a pick→abandon→pick cycle, and the cap is what bounds the whole thing. a pick no longer requires a pick→abandon→pick cycle, and the cap is what bounds the whole thing.
<code>Config.max_manual_picks</code> defaults to 2.</p> <code>Config.max_manual_picks</code> defaults to 3.</p>
<p>That turns the enforcer's central question from "which game?" into "which <em>set</em> of <p>That turns the enforcer's central question from "which game?" into "which <em>set</em> of
games?" — and that is the real substance of the diff:</p> games?" — and that is the real substance of the diff:</p>

View File

@ -60,7 +60,7 @@ class Config:
kill_unauthorized_games: bool = True kill_unauthorized_games: bool = True
uninstall_other_games: bool = True uninstall_other_games: bool = True
desktop_notifications: bool = True desktop_notifications: bool = True
max_manual_picks: int = 2 max_manual_picks: int = 3
"""How many games may be manually locked in at once. """How many games may be manually locked in at once.
All active picks stay installed and visible; the enforcer treats them as All active picks stay installed and visible; the enforcer treats them as

View File

@ -39,11 +39,11 @@ full 2 weeks. There is now a short mistake-correction window:
The lock-active message advertises `abandon-pick` only while the window is The lock-active message advertises `abandon-pick` only while the window is
still open, and the `pick-manual` warning mentions it up front. still open, and the `pick-manual` warning mentions it up front.
## Two concurrent manual picks (added 2026-07-19) ## Concurrent manual picks (added 2026-07-19)
`Config.max_manual_picks` (default 2) is how many games may be locked in at `Config.max_manual_picks` (default 3) is how many games may be locked in at
once. Both stay installed, visible and un-killed; the lock releases only when once. All active picks stay installed, visible and un-killed; the lock
every pick is finished or past its own 14-day deadline. releases only when every pick is finished or past its own 14-day deadline.
- `State.manual_picks` is the list of `{app_id, game_name, started_at}` - `State.manual_picks` is the list of `{app_id, game_name, started_at}`
entries. The old single-slot `manual_pick_*` fields are still read on load, entries. The old single-slot `manual_pick_*` fields are still read on load,
@ -52,15 +52,15 @@ every pick is finished or past its own 14-day deadline.
source of truth for "may exist". `uninstall_other_games`, source of truth for "may exist". `uninstall_other_games`,
`hide_other_games`, `enforce_allowed_game` and `_guard_installed_games` all `hide_other_games`, `enforce_allowed_game` and `_guard_installed_games` all
take that set instead of one app id. take that set instead of one app id.
- `pick-manual` is in `_MANUAL_LOCK_EXEMPT_COMMANDS` so a second game can be - `pick-manual` is in `_MANUAL_LOCK_EXEMPT_COMMANDS` so another game can be
added while the first holds the lock; the cap is what limits it. Its added while earlier picks hold the lock; the cap is what limits it. Its
post-pick cascade operates on the whole allowed set, so adding a pick never post-pick cascade operates on the whole allowed set, so adding a pick never
tears down an earlier one. tears down an earlier one.
- `abandon-pick <app_id>` drops only that pick; a survivor inherits the - `abandon-pick <app_id>` drops only that pick; a survivor inherits the
assignment and keeps the lock. assignment and keeps the lock.
- `cmd_done` still finishes `current_app_id` and auto-picks a replacement, so - `cmd_done` still finishes `current_app_id` and auto-picks a replacement, so
two games stay queued. A finished pick leaves the active set automatically the remaining picks stay queued. A finished pick leaves the active set
via `finished_app_ids` — no pruning needed. automatically via `finished_app_ids` — no pruning needed.
**Deployment note:** the enforce daemon holds the allowed set in code, so **Deployment note:** the enforce daemon holds the allowed set in code, so
`sudo systemctl restart steam-backlog-enforcer` is required after upgrading. `sudo systemctl restart steam-backlog-enforcer` is required after upgrading.