Commit Graph

5 Commits

Author SHA1 Message Date
341bc784ac web control UI: all 24 commands in React, ctl.sock daemon, jobs, library browser; earned_time 0.7.0
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 16:07:42 +02:00
a5abb94d85 Keep Steam Runtime's logger out of the journal
Steam's srt-logger runs inside steam-backlog-enforcer.service's cgroup
and mirrors Steam's console into journald on its own — the DEVNULL
stderr the spawn already uses does not reach it, and the env carried
SRT_LOG_TO_JOURNAL=0, which is not the variable it reads. One boot on
2026-09-12 wrote 481k "joystick FFB effect status" lines (99% of the
journal) and evicted two weeks of history from a 300M journal, along
with the evidence for that night's curfew failure.

- desktop_env_args(): SRT_LOGGER_USE_JOURNAL=0, the variable srt-logger
  actually honours. Steam keeps its own logs/console-linux.txt.
- Unit: LogFilterPatterns for the two known flood patterns plus a
  per-unit rate limit, so a future Steam that ignores the variable still
  cannot take the journal with it.

The unit file is deployed and daemon-reloaded; the running service is
not restarted, because Steam is its child and a restart would kill a
live game. The env fix takes effect on the next enforcer start.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mLnUeoJ3mUwGRTowTUH6d
2026-09-13 10:51:50 +02:00
0c05d71008 Add a daily gaming-time budget with a binary-level cutoff
Accumulates time spent in Steam games and other launchers, and once the
daily budget (default 8h) is spent, shuts Steam down, kills the games, and
makes them unlaunchable until the next 06:00.

The gaming day starts at 06:00 local rather than midnight so a late session
counts against the day it began in; rollover is checked lazily against a
stored day key, so it survives suspend, reboot and daemon restarts with no
timer of its own. Elapsed time comes from wall-clock deltas clamped to two
tick intervals, which keeps suspends, missed ticks and NTP steps honest.

The block is a read-only bind mount of a refusal stub over all four launcher
entry points -- /usr/bin/steam is only a two-line exec wrapper, so masking it
alone leaves bin_steam.sh, Steam's own steam.sh and lutris live. A bind mount
mutates no bytes, umount restores exactly, and a reboot clears it
unconditionally; chmod/rename would leave Steam broken if the daemon died
mid-block. /proc/self/mountinfo is the authority on what is masked, never the
saved state, which is what makes a stale block release even if the state file
was deleted. The mount is deferred one tick past the cutoff so
`steam -shutdown` still works and games close cleanly.

Launchers are matched by cmdline, not comm: /usr/bin/lutris is a python3
script, so the kernel records its comm as "python3" and the existing scan
never sees it. The kill set is wider than the budget predicate, walking down
from each launcher, because a Lutris-launched Wine game carries no SteamAppId.

State is chattr +i'd -- ~/.config is user-writable, so root ownership alone
would not stop `rm` from resetting the counter -- and a missing state file
while mounts are live fails closed rather than lifting the block.

Also fixes a pre-existing bug: do_enforce returned when no game was assigned,
exiting the process. Since the budget is accounted for from inside that loop,
it silently stopped enforcing whenever a game was finished but not rescanned.

Verified on the desktop with a real game: AoE2 counted 18 processes, tripped
at the 60s demo budget, all processes killed, all four paths masked and
refusing, then gaming-unblock restored them byte-identical with
`pacman -Qkk steam lutris` reporting 0 altered files.

1322 tests pass at 100.00% branch coverage; pacman validated the ALPM hook.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbEaXapjMSkxyzgvbdkUFb
2026-08-04 20:00:08 +02:00
00a08de076 fix(enforcer): Steam CDP restart never worked (root+no-display, port collision)
Some checks are pending
pre-commit / pre-commit (push) Waiting to run
Tests / test (3.10) (push) Waiting to run
Tests / test (3.11) (push) Waiting to run
Tests / test (3.12) (push) Waiting to run
The systemd service runs as root with no User=, so _run_as_user() had no
SUDO_USER/USER to drop privileges to and launched Steam as bare root with
no DISPLAY/XAUTHORITY/DBUS session - its CDP port never opened. Add an
explicit STEAM_ENFORCER_DESKTOP_USER env var (set in the unit, substituted
by install.sh) so the enforcer always knows which desktop user owns the
Steam session, regardless of how it was launched.

Also fix a hardcoded _CDP_PORT=8080 colliding with an already-running
local service bound to 0.0.0.0:8080: requests to 127.0.0.1:8080 always
hit that service instead of steamwebhelper (which only bound
[::1]:8080), so CDP detection could never succeed even with the user
fix. Move to 9222, the conventional Chrome DevTools port.

Verified live: journalctl shows CDP ready and games hidden within ~7s
of a service restart, Steam running as the desktop user (not root).
2026-07-18 06:49:10 +02:00
551b8a4f95 chore: set up as standalone repo
Extracted from testsAndMisc monorepo. Changes:
- Rewrote imports from python_pkg.steam_backlog_enforcer.* → steam_backlog_enforcer.*
- Moved run.sh, install.sh, README.md, service file to repo root
- Added standalone pyproject.toml, requirements.txt, .pre-commit-config.yaml, .gitignore
- Added GitHub Actions CI workflows (tests + pre-commit)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 07:21:29 +02:00