Commit Graph

40 Commits

Author SHA1 Message Date
2e66502abc deps: newest stable web pins, node 26.13.0
Clears the dependency-freshness gate that blocked pushes (ci-mirror).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWxdzckyBH7fEbPywpr
2026-11-02 09:21:04 +01:00
d2a684ebf9 web deps: @tanstack/react-router 1.170.46; sync pnpm-lock.yaml
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
pnpm-lock.yaml had missed the previous bump (react-query 5.104.5,
typescript-eslint 8.72.0, vite 8.3.5); both lockfiles now match package.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYmCezqhUjUmMisF5YtM4F
2026-10-24 08:39:45 +02:00
dc22bd557c fast install: never report a failed run as success; queue the manifest first
The BG3 fast install of 2026-10-23 downloaded 160 GB, was refused by the
installer, and the web job still ended on a full bar, "Done!" and Succeeded
while Steam restarted the download from 0%.

- A failed run's reason is read from the installer's own run log (its ERROR
  lines). A waiting job prints "Failed: fast install of <game>: <reason>",
  which fails the job; `install` no longer says "Done!" after it.
- Daemon-started failures stay on the Dashboard's Fast install card (and in
  ctl status, `error`) until a new run starts or the game is installed.
- install_game writes Steam's "needs downloading" manifest before the
  installer runs: it only finishes a manifest it finds, so fresh installs
  were refused for want of one.
- Command building moved to _fast_install_cmd (250-line cap).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYmCezqhUjUmMisF5YtM4F
2026-10-24 08:36:57 +02:00
0d93539944 total block: two-unit countdown (2w 2d … 45s), ticking every second
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 20:59:41 +02:00
1bdf360193 pick keeps already-picked games; fast install reports progress
pick and pick-manual no longer uninstall games that are already allowed:
the outgoing assignment is kept as a released pick (installed, no lock)
until 'pick --replace', done/check, or abandon-pick. The allowed set is
capped at max_manual_picks + 1; a pick over it is refused before the
candidate list / confirmation, naming the games. status and the web
Picks card list kept games with an Abandon button.

Fast install now tracks the installer log from the spawn offset: web
jobs drive the progress bar (per-depot %, phase) and echo a line every
30 s; daemon-started runs are exposed via ctl status / /api/daemon and
shown on the Dashboard.

Also: web deps bumped for dependency freshness (react-query 5.104.5,
typescript-eslint 8.72.0, vite 8.3.5, node 24.22.1 in CI).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUaX4zAa6H4sMu3jd6RFdb
2026-10-23 20:14:12 +02:00
4cf77b61c6 web deps: @tanstack/react-query 5.104.4, @tanstack/react-router 1.170.45
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsh4Znwh2KnC7q6vbGpX1N
2026-10-19 12:44:33 +02:00
a09f08701a playtime: drop the Fri-Mon carry-over; log budget on change only
A Sunday ran past the 6.0h the i3 bar showed: 2h47m of Saturday's
leftover was carried into the budget the cutoff used, and the 3-second
"Gaming budget" journal line omitted it. Unspent time is now dropped at
06:00 every day; load_state takes a legacy ledger's share back out of
today's high-water mark. The budget line logs only on change (was 25k
lines/day), fired warnings are logged, and budget.jsonl records carry
budget_seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015PrwCnQouKTF4EUMENMxnG
2026-10-18 21:37:29 +02:00
4745dca0d2 web: sync package-lock.json with the vitest/eslint bump (CI uses npm ci)
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 17:04:12 +02:00
a7c0c32417 web deps: vitest 5.0.5, @vitest/coverage-v8 5.0.5, eslint 10.13.0
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 17:01:30 +02:00
d6287295f5 deps: bump node 24.22.0, ruff 0.17.1, pre-commit 4.7.0, web deps (freshness gate)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 15:24:36 +02:00
2735c00716 deps: bump @tanstack/react-query 5.104.2 (freshness gate)
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / web-coverage (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Claude-Session: https://claude.ai/code/session_01E57caQF4KXwEvqEnKtJiHM

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 21:48:48 +02:00
76e8592225 deps: bump @tanstack/react-router 1.170.42, @types/node 26.6.5 (freshness gate)
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 21:39:57 +02:00
f75dcd09e2 tests: block real kills/Steam spawns (a stale demo test killed the live game); enforce --demo is budget-only
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 19:15:11 +02:00
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
405f3f3d94 deps: vite 8.3.4, typescript-eslint 8.71.1, @vitejs/plugin-react 6.1.2
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RHwVPyiiQMPh4M3JQwQku
2026-10-09 18:56:08 +02:00
25dc49363b deps: earned-time-v0.2.0 in requirements.txt and pre-commit (CI was on 0.1.0), jsdom 30.1.2
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-05 14:08:55 +02:00
19c9f8d24f deps: regenerate package-lock.json for the eslint bump (npm ci was red)
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 18:15:32 +02:00
152f1bfc1f deps: websockets 17.2, eslint 10.12.0
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 17:51:42 +02:00
b0dfdd70c2 Stable bumps: mcp 2.3.0, pylint 4.1.2, @types/node 26.6.4
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 13:46:34 +02:00
6afa2b88cd Today's stable bumps: coverage, howlongtobeatpy, mypy, pylint, ruff and the web dev deps
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-02 21:12:06 +02:00
9586128163 Carry unspent Fri-Sun gaming time to the rest of the Fri-Mon block
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-02 21:07:49 +02:00
d99e87f5b1 Bump vitest and @vitest/coverage-v8 to 5.0.2
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
Released today; the dependency-freshness gate blocked the push without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhzaTAWtRfJk8gre6NLSka
2026-09-26 16:48:16 +02:00
bbc3853c67 Today's stable bumps: pylint, ruff and the web dev deps (jsdom, vite)
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
Tests / web-coverage (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 18:49:25 +02:00
0b4e571eb0 Today's stable bumps: ruff and the web dev deps
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 21:26:57 +02:00
230706d686 Bump @testing-library/dom to 10.4.2
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SS8M5wk88nJTXxDWz61KKk
2026-09-14 21:36:36 +02:00
f383325276 Bump @types/node to 26.5.1
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Tests / test (push) Has been cancelled
The pre-push CI mirror refused the previous push on this one pin.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mLnUeoJ3mUwGRTowTUH6d
2026-09-13 10:57:02 +02:00
4783753b3f Re-point paths for the ~ reorganisation (home-tidy)
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
Also bumps mcp 2.2.0, ruff 0.16.7, types-requests 2.33.0.20260906 and, in
web/, react 19.3.0, vitest 5.0.0 (+ coverage-v8), eslint 10.10.0,
typescript-eslint 8.70.0, vite 8.3.0 and the small ones, so the freshness
gate lets this through. Web lint/build/tests/coverage (100 %) unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
2026-09-11 19:55:43 +02:00
94ddb6fa72 Bump globals and typescript-eslint to latest stable
Keeps the dependency-freshness gate green; unrelated to the engagement
gating removal in the previous commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 18:15:46 +02:00
445ad011bb Remove engagement gating from the gaming budget
A qualifying game process running is now sufficient on its own to bill
the budget. Previously a tick only counted if the screen wasn't locked,
the game's window was X11-focused, and input hadn't gone idle for 5
minutes — with an idle-grace refund on top. That leniency is gone
entirely: no focus check, no idle check, no screen-lock check, no
refund. Deletes the engagement-probing modules (_playtime_engagement,
_engagement_probes, _engagement_types, _x_focus, _x_probe, _screen_hold,
_controller_input) and their config fields, simplifies the audit log
and budget-view/web session schema accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 18:14:27 +02:00
47f77f5f1e Make serve re-runnable, and cover it to 100%
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
The serve rework was sitting untracked: a /proc-based port guard, the
start-or-defer decision, and a stale-bundle rebuild. It had no tests, and it
changed cmd_serve(_config, state) to cmd_serve(argv) without updating the one
test that called it, so the suite was red and coverage was 251 lines short.

Tests, all against fakes:
- _fake_proc builds a synthetic /proc. _NET_TCP is derived from _PROC at
  import time, so patch_proc redirects both; patching _PROC alone would have
  had these tests parse the host's real process table.
- _serve_guard is split across two test files to stay under the 250-line cap.
  os is replaced wholesale in every termination test, so no signal can reach a
  real process even if the guard's self-protection were removed.
- _web_build mocks subprocess entirely and redirects every path constant into
  tmp_path. _no_subprocess now blocks _web_build.subprocess.run too: an
  unguarded test would fire a real `npm run build`, rewriting web/dist and
  perturbing frontend_is_stale() for every later test in the run.

Source changes, both required rather than incidental:
- _serve_guard's wildcard match was a `# noqa: S104` on a "0.0.0.0" literal,
  which the no-noqa hook rejects outright. It is now the all-zero hex column
  /proc actually prints, so the dotted-quad literal never appears.
- main/__init__.py's serve dispatch arm was itself uncovered; it now has a
  test asserting the raw argv passes through unparsed.

Also drops the document.hidden guard from useBudgetPoll: it skipped the very
first load, so the budget panel sat on "Reading budget state…" forever in a
background tab, which is every tab under browser automation.

Verified: 1712 python tests, 100% branch coverage; 128 vitest, 100%. The
guard's /proc parser was checked read-only against a real listener on :8000
and resolved the same pid as `ss`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MKFzwzwRU1JD7SFLHtQBsz
2026-08-29 18:52:11 +02:00
1faf211767 Show which games make up the gaming budget, and bill osu!lazer
The budget tab answered "how much did I play" but not "what did I play":
playtime_state.json and playtime_history.json each stored one aggregate
seconds figure per gaming day, so the 14-day chart was a row of featureless
bars. Separately, qualifying_pids had exactly two sources — the SteamAppId
env var and a hardcoded 16-launcher frozenset — so osu!lazer, which sets no
SteamAppId and matches no launcher name, was never billed at all.

qualifying_pids now returns pid -> attribution key instead of a bare pid set.
The app id was already in hand and thrown away on its first line; it now
survives into PlaytimeState.per_game, alongside a user-editable
counted_processes list in config.json seeded with osu!lazer.

Two things the parts/whole relationship forces:

  - per_game only ever sums to AT MOST seconds, never equals it. backdate
    refunds the idle grace on every engaged-to-paused edge, and
    _state_or_recover synthesises a full budget with no breakdown. The
    refund is debited from last_credited_key, and the remainder is rendered
    as "Unattributed" rather than stored — one path then covers legacy days,
    focus-probe failures and drift alike.

  - counted_processes is kept apart from LAUNCHER_PROCESS_NAMES. That
    frozenset is also the total-block kill list, and it routes through
    kill_and_uninstall_launchers, which pacman -R's the owning package.
    Counted entries are killed on total block, never uninstalled.

Both storage formats stay at schema 1: load_state already filters to
dataclass fields, so a record without per_game migrates for free, and the
history reader has to accept both a bare float and an object regardless, so
a version bump would distinguish nothing.

Chart segments use the shared design system's categorical ramp (--cat-1..6),
capped at six games plus "Other" because a seventh distinguishable hue does
not exist under simulated CVD. The red over-budget fill is gone: colour now
encodes which game, and the dashed budget line alone says over or under.

Snapshot persistence moves to _snapshot.py to keep config.py under the
250-line cap. Three modules bound config paths at import time, which
bypasses the conftest redirect — they now reach them through the module.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MKFzwzwRU1JD7SFLHtQBsz
2026-08-29 18:32:03 +02:00
08aa5c42f8 Say "masked" only when launchers really are
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
The cutoff badge asserted "launchers are masked" from `blocked` alone, but
the two can disagree: the total-block branch of `playtime_tick` calls
`reconcile(should_block=False)` and leaves `blocked_at` set, so the mounts
are gone while the day still reads blocked. The panel already fetches
`rules.masked_launchers` for its "Masked now" row, so the badge now reads
the same live count instead of inferring one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 07:36:13 +02:00
f0f14ebf49 Bump coverage and @vitejs/plugin-react to latest stable
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 07:19:01 +02:00
fcae46faf1 Show the gaming budget in the web UI
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 07:17:42 +02:00
39de18042f Bump @testing-library/react to 16.3.3
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 20:52:22 +02:00
9e0f75a5a0 Latest stable dependencies, mcp 2.x, and the gate
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
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
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 17:29:14 +02:00
ba412ca04f test(web): cover the 3 pre-existing branch-coverage gaps in SummaryCards
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
Fast-vs-slow rush-ratio class, the STYLE_LABELS raw-key fallback, and the
non-positive estimated-total preset row were all unexercised, failing the
100% branch-coverage pre-push gate independently of the palette change in
the prior commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 17:40:25 +02:00
6202db54a0 web: warm-tint the unified-design-system palette, fix DESIGN_AUDIT_TODO violations
Fixes every finding in the repo's own audit: spacing/radius scale, letter-
spacing compensation on <=13px text, --on-fill for filled segmented-control/
badge/button surfaces, 12-col .cards grid, mis-nested corner radius,
box-shadow -> outline on the dark-UI selection ring, and completes the
phantom --accent-bg token.

Verified: lint + 84/84 tests clean, build succeeds, re-verified identical
in an isolated worktree at HEAD, and pixel-checked against the real `serve`
command's output via headless-Chrome screenshot.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 17:35:40 +02:00
7ac07c4b7a feat: add pick-manual command with 2-week enforcement lock
User can now pick any owned game by Steam app_id via `pick-manual <id>`.
The script resolves the game name, asks for YES confirmation, then locks
all other commands for 14 days or until the game is 100% complete.
Post-assignment steps (uninstall others, install, hide library) mirror
the automatic pick flow. Lock is checked before every command including
add-exception. Also fixes pre-existing test failures in hltb, stats,
and web_dataset modules and adds 100% coverage for all changed code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 17:15:37 +02:00
41deb90324 feat: add interactive web UI for backlog completion planning
Adds a React/TypeScript frontend (web/) with a Python stdlib HTTP server
backend.  The UI mirrors the CLI `stats` command in the browser, with
real-time sliders for ProtonDB rating, HLTB confidence thresholds, daily
play time, per-game time cap, playtime mode, no-HLTB-data fallback, and a
target-date planner.  A parity badge confirms the client-side totals
reproduce the CLI defaults exactly (786 / 67031.1h / 143017.2h / 238447.9h).

Python side:
- `_web_dataset.py`: offline projection of HLTB/ProtonDB/snapshot caches
  into a compact, secret-free JSON payload; 100% branch coverage
- `_web_server.py`: zero-dependency stdlib HTTP server serving the built
  Vite bundle and the /api/dataset endpoint; 100% branch coverage
- `main.py`: new `serve` command wiring

Frontend (Vitest + RTL, 100% branch coverage enforced):
- TypeScript port of ProtonDB compound rating rule with full parity
- Pure client-side filtering via estimate.ts (no server round-trips)
- SVG completion timeline chart, sortable/searchable game table
- Steam dark theme; responsive layout

Pre-commit: adds `vitest-coverage` hook at pre-push stage requiring 100%
branch coverage on the React codebase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:35:45 +02:00