Commit Graph

317 Commits

Author SHA1 Message Date
4c7a8c832e CI pins: shfmt v3.14.1, prettier 3.9.10 (newest stable)
The commit hook ran local shfmt 3.14.1 while CI pinned 3.13.1, and
prettier 3.9.5 trailed the 3.9.10 release. Bump both in pre-commit.yml
(shfmt SHA from a real download) and in common.sh's drift table;
local nvm prettier upgraded to match. shellcheck v0.11.0 is already the
newest stable and stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBScELfMUiieK9ManFbS3Y
2026-10-22 21:37:03 +02:00
213e16836d redeploy_agent_ready_sites: parallel checks with the checker's own budget
--verify-only flaked FAIL on all three sites: CHECK_TIMEOUT=10 killed
checks that take 2-22 s. The url checks now run concurrently, each with
--budget min(45, time left before a 55 s run deadline - 5 s grace); the
outer timeout is only a hang backstop. The redeploy steps run
concurrently too (systemctl restart now under a timeout), so a full run
fits 60 s worst case. --help prints only the header block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBScELfMUiieK9ManFbS3Y
2026-10-22 21:36:48 +02:00
2a76d05f9d Static-site Caddies: shared AgentReady site block, serve redeploy, verify
static_site_caddy.sh is the one site-block body for the personal website
and kcd2 dice Caddies: prerendered paths, real 404s and the ai-catalog Link
header instead of an SPA catch-all. Both setup scripts gain a sudo-free
`serve` that recreates only their container; kcd2's readiness wait needs a
200. redeploy_agent_ready_sites.sh serves both, restarts the popes site and
runs the AgentReady checker against all three public URLs. Tested by
test_static_site_serve.sh, test_redeploy_agent_ready_sites.sh and the
caddy:2.8 e2e_agent_ready_caddy.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBScELfMUiieK9ManFbS3Y
2026-10-22 21:23:59 +02:00
66321e555b i3blocks: 🛋 Leisure label and hidden SHADOW block once leisure is live
Phase 2 of the leisure rollout, dormant until daily-limits' cache says
"leisure_active": true. gaming_budget.sh then labels the block
"🛋 Leisure" (short "🛋", same colour logic, stale state keeps the label);
leisure_shadow.sh prints nothing so i3bar hides it. A missing, false or
non-boolean key keeps today's output.

Also: gaming_budget.sh floors generated_at and says "no data" for a
non-numeric one; a fractional timestamp used to make it exit 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsh4Znwh2KnC7q6vbGpX1N
2026-10-19 16:22:02 +02:00
5e6aee64cf i3blocks: leisure_shadow says "no data" when generated_at is missing
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
A daily-limits cache without a numeric generated_at made the age
arithmetic hit "null: unbound variable" under set -u: exit 1 and an empty
block. The render now floors a numeric generated_at and the script emits
the orange "SHADOW no data" fallback for anything else, still exiting 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsh4Znwh2KnC7q6vbGpX1N
2026-10-19 13:17:59 +02:00
e190d9a4bd i3blocks: shadow-week leisure block (leisure_shadow.sh)
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Renders daily-limits' `leisure_shadow` cache (contract C5): `🛋 SHADOW
3h12 left · 1h48 used`, yellow under 30 min, red `WOULD BLOCK` at 0,
never urgent; `⏱? no data` while the enforcer has no C4 fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsh4Znwh2KnC7q6vbGpX1N
2026-10-19 12:27:15 +02:00
ad46fc85a5 pacman wrapper: drop list-file checks and docs after list retirement
digital-wellbeing e2a7176 removed the blocked-keyword, white and grey
lists. check_pacman_wrapper no longer looks for them, the VirtualBox note
stops citing pacman policy, and the docs drop the lists and greylist
challenge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Lhzv7c391mTKWfwU17V7Z
2026-10-17 18:46:17 +02:00
70df11f306 i3blocks/tutor: target follows earned_time 0.10.0 weekday quota (15/30/50)
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / lib-tests (push) Has been cancelled
Shell tests / arch-tests (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:24:48 +02:00
66160cd6da i3blocks/tutor: count credited minutes (cap 60), not ledger rows vs 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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Since earned_time 0.8.0 each tutor credit row carries detail.minutes, so
counting rows against 4 hid the block after 4 credited minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YADHKXzZhhePzQ2rNoXFcK
2026-10-12 16:55:37 +02:00
a511403e0f i3blocks: automation_tutor block -> tutor (ledger ~/.local/share/tutor, click ~/src/tutor/run.sh)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YADHKXzZhhePzQ2rNoXFcK
2026-10-12 16:47:45 +02:00
cf55091e95 fix(webcam): keep Logitech C270 at 30 fps in low light via udev rule
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 13:49:17 +02:00
3ea0359748 i3blocks: XDG_RUNTIME_DIR falls back to /run/user/$UID, not /tmp
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
A session started while logind was off the system bus had no
XDG_RUNTIME_DIR, so the gaming and shutdown blocks looked for
daily-limits' cache in /tmp and showed '⏱? no data'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHsV8jzhhX162EcxxEXbca
2026-10-12 08:22:43 +02:00
7b06fc3c4a refactor(dot-resolver): install the tracked sync-dot-cert.sh instead of generating it
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Every script under /usr/local/bin must be a repo file. install_cert_sync
wrote /usr/local/bin/sync-dot-cert.sh from a heredoc with the domain,
Caddy container and cert dir baked in. The script now lives at
linux_configuration/scripts/sync-dot-cert.sh, takes those three as
arguments (defaults = the installer's constants), and is installed with
install -m 755. dot-cert-sync.service and the first sync pass the
arguments, so --domain reaches the timer too. Test asserts the installed
file is the tracked one byte for byte and runs the script itself against
a docker shim (reload only on change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014yhTkYV6ZeuAbQYvykFGFc

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:32:54 +02:00
2dc4081dc9 fix(services): report and remove a stale compulsive-block <app>.orig
check_compulsive_blocker said "<app> wrapper installed (original backed
up)" whenever /usr/bin/<app>.orig existed, even after the package was
removed. A .orig whose /usr/bin/<app> no package owns (read from
${SYSROOT}/var/lib/pacman/local, not pacman -Qqo) is now a warning,
"stale <app>.orig left after package removal", and the repair deletes
it (plus a dangling wrapper) via run, honouring --status/--dry-run.
Unreadable db: never prunes. Pairs with digital-wellbeing 6867f29.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014yhTkYV6ZeuAbQYvykFGFc

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:24:12 +02:00
8be1fac8f9 linux_configuration: track ~/.local/bin wrapper scripts in repo, symlink instead of generating
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Moves 7 loose ~/.local/bin scripts into linux_configuration/scripts/ and
tracks the flutter/dart git-env wrapper; fix_flutter_git_env.sh and
unreal_mcp_repo.sh now symlink to the tracked files instead of writing
heredocs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014yhTkYV6ZeuAbQYvykFGFc

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 18:49:56 +02:00
698fdd5c8e i3blocks: automation_tutor block (today's tutor credits, click runs plc-lab run.sh)
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 15:06:05 +02:00
b8d0b215e1 wg firewall: the workout poke moves to tcp/8774 (8773 is book-guard's desktop wrapper); applied on the host 2026-10-10, phone reaches 8774 over the LAN
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KrBEzjPRdx5oyp8NtTLW5F
2026-10-10 09:57:29 +02:00
20e05f021f wg firewall: allow-workout-poke opens tcp/8773 from the LAN only (ALLOW_WORKOUT_POKE)
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
screen-locker's workout-poke.service takes the phone's POST of a finished
workout on tcp/8773. The flag is persisted like ALLOW_DOT so every re-apply
keeps it, and there is deliberately no wg0 rule: off the home LAN the poke
fails fast and the normal sync credits the workout instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RHwVPyiiQMPh4M3JQwQku
2026-10-09 18:47:21 +02:00
5f14add664 i3blocks: daily-limits click works under i3blocks' PATH; deps: anthropic 1.12.1, pyflakes 4.0.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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
i3blocks' environment has no ~/.local/bin, so `command -v daily-limits`
failed and every left-click on ⏻/🎮 was silently dropped. Call the launcher
by path (DAILY_LIMITS_BIN), detach with setsid, and notify when it is
missing. Also bumps the two pins behind latest stable that turned the
freshness gate red on 433cec27.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QrjUTo1yhgAsUUasdw4bpG
2026-10-09 11:53:37 +02:00
433cec278e i3blocks: shutdown and gaming blocks render from the daily-limits cache
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Both blocks read $XDG_RUNTIME_DIR/daily-limits.json (kuhyx/daily-limits,
refreshed every 60 s by a user timer) instead of curling the enforcer and
duplicating the earner table. Stale or missing cache shows ⏱? rather than
old numbers; unknown earners are shown with '?'; left-click opens
daily-limits --gui. Steady-state tick: bash only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QrjUTo1yhgAsUUasdw4bpG
2026-10-09 10:46:19 +02:00
c5aa20a085 i3blocks shutdown: list unearned earners (+🧩1h ... →max 23:00)
The shutdown block now shows what can still push shutdown later, like the
gaming-budget block: earners with earned_seconds == 0 from the enforcer's
/api/budget, with a ceiling note once they overflow 23:00. No hint in the
override/SHUTDOWN states or when the server is down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014qWnrvoCawLZWUpTLJxHue
2026-10-06 20:42:50 +02:00
27be07db48 i3blocks gaming_budget: automation earner icon ⚙ (earned-time 0.3.0)
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Has been cancelled
Python tests / test (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / lib-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-05 15:15:50 +02:00
856866e8b8 i3blocks gaming_budget: list every earner from .rules.earners (anki 🗂), sub-hour bonuses as minutes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-05 14:27:43 +02:00
038017d9eb wg firewall: replace only inet filter (no docker restart), persist DoT 853 via ALLOW_DOT
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cqv4ckcaStUFpUkcJKmmNz
2026-10-04 21:16:16 +02:00
83c7bf9664 i3blocks shutdown countdown: minute-precision schedule (*_MINUTES keys)
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 19:38:24 +02:00
f0d50d7375 i3blocks: issue_dashboard shows merged issues awaiting their opener
The issue dashboard now keeps merged-but-open issues (Merge only tags the
opener, kado-no-akari #21) out of `todo` and writes them as `awaiting` in
status.json. The block shows them as "· ⏳ N" between "✓" and "✗", only when
N > 0, without changing the colour (they wait on the opener, not kuhy).
`awaiting` is optional, so the old server's status.json still renders
numbers rather than grey. Still zero forks on the hot path. Prunes the oldest
evidence artifact to stay at the 60-file cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WXd5qap8DWqZCS9mjh3CzH
2026-10-02 20:59:36 +02:00
deaf3ba80a DNS: dnsmasq bind-dynamic, no ordering cycle, stunnel Wants=; retire pc_startup check; repo paths under ~/src
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-02 18:02:44 +02:00
63465cffac i3blocks: issue_dashboard block
Some checks failed
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Python tests / test (push) Has been cancelled
[issue_dashboard] shows what the local issue dashboard (~/src/issue-dashboard)
knows, from the status.json its server rewrites on every refresh:
"📋 <to do> · ⚙ <agents working> · ✓ <ready to merge>", green when something
is ready to merge, red with "· ✗ <n>" when an agent or a proof failed, grey
"📋 dashboard" when the file is missing or stale (server not running). Zero
forks on the hot path; a click opens issue-dashboard-desktop, which reuses or
starts the server and opens its window. Behaviour + fork-count test in
tests/test_i3blocks_issue_dashboard.sh. Prunes the oldest evidence artifact
to stay at the 60-file cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WXd5qap8DWqZCS9mjh3CzH
2026-10-02 17:03:47 +02:00
a3728824a1 i3blocks: book_guard block; gatelock 0.9.0 and newest-stable pins
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 checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
[book_guard] shows this month's paper-book pace from the state.json
book-guard publishes (green on pace, yellow behind but unlocked, red when
locked or the timer is disarmed, orange when missing/stale); a click opens
book-guard-desktop -- the same way [screen_locker] opens its UI. Behaviour
test in tests/test_i3blocks_book_guard.sh.

meta/requirements.txt: gatelock 0.9.0 (the shared morning-session reader),
plus today's newest stable for anthropic, cryptography, flake8-bugbear,
geopandas, howlongtobeatpy, pyflakes, selenium, mypy, pylint and ruff.
Prunes the oldest evidence artifact to stay at the 60-file cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FBbkN4ZB4aUPJPzR2prRan
2026-10-02 14:22:43 +02:00
07810fb270 Home Assistant setup + allow-homeassistant firewall option (Viomi V3 LAN control)
setup_homeassistant.sh runs a digest-pinned Home Assistant container with
host networking and installs hass-xiaomi-miot v1.1.5, so the Viomi V3
(viomi.vacuum.v13) is controllable over the LAN from the HA companion app.
setup_wireguard_ssh.sh gains a persisted ALLOW_HOMEASSISTANT flag that opens
tcp/8123 to the LAN subnet and wg0 only. Prunes the oldest evidence file to
stay under the 60-file cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGnk48tUeJteJWEQ7UhKDd
2026-09-27 17:12:22 +02:00
ae99698d5b i3blocks: gaming budget block (time left, used/total, unearned bonuses)
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 checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
New [gaming_budget] block reads steam-backlog-enforcer's /api/budget every
30s: "🎮 2h00 left · 6h00/8h00 +📖1h". Colours follow the enforcer warn_at
(1h/30m/10m), blocked is red, a dead server shows the cached value as stale.
Unearned bonus sizes come from the enforcer config via jq --slurpfile.

Prunes the oldest evidence artifact to stay under the 60-file cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CD7nSVE2dKvByG8hdSi3gm
2026-09-26 17:22:54 +02:00
ec2da0b575 helium: unlock the keyring through secretstorage; anchor the running-browser check
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 checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
`secret-tool lookup` is non-interactive — on a locked keyring it returns
nothing and shows no dialog — and a busctl Unlock+Prompt pair cannot work
either, because Secret Service prompt objects die with the D-Bus
connection that created them. secretstorage keeps one connection:
get_default_collection().unlock() pops the gcr dialog and blocks until it
is answered. Verified on the real profile: 5 v11 rows -> v10, then with
the keyring re-locked Helium (through the wrapper, so the flags file and
LeechBlock apply) lists all 5 logins and keeps every row.

`pgrep -f /opt/helium-browser-bin` also matched the invoking shell when
its argv mentioned the path, so the guard refused on an idle machine;
now anchored to `^/opt/helium-browser-bin/`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8YGXVZdNUG79q5DGsdMm3
2026-09-20 18:29:49 +02:00
c193408ccd helium: full uBlock Origin (MV2) via Helium, profile cloned, keyring prompt fix
Chromium 151 removed the last Manifest V2 code paths and the Web Store
purged uBlock Origin on 2026-08-31, so ungoogled-chromium 153 cannot load
the full blocker any more. Helium (GPL-3, ungoogled-chromium base) bundles
uBO 1.75.0 as a component extension and keeps MV2 alive.

- installers/install_helium.sh: pacman deps, AUR via yay or makepkg
  (+validpgpkeys import), /usr/local/bin/helium-browser ->
  browser-preexec-wrapper so LeechBlock NG and the hosts refresh still
  apply, --clone-profile with a downgrade check and running-browser
  refusal, then the verifier. Passed in vmbox from scratch, then host.
- installers/verify_helium.py: Xvfb + DevTools exit-code gate — uBO
  background_page + manifest_version 2, every /etc/chromium/policies key
  on chrome://policy (Helium reads that dir natively), adblock-tester >= 95.
- installers/migrate_helium_passwords_to_basic.py: lightdm autologin
  leaves gnome-keyring locked, so the 5 v11 logins make Helium prompt on
  every launch; this re-encrypts them as v10 and only then enables
  --password-store=basic.
- register helium-browser in aur_packages.txt and the periodic browser
  wrapper/service lists; pylint hook gets websockets + cryptography;
  codespell learns the vendor name; anthropic 1.6.0 -> 1.7.0 (gate red);
  oldest evidence artifact pruned to stay under the 60-file cap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8YGXVZdNUG79q5DGsdMm3
2026-09-20 18:07:34 +02:00
cce6e2c048 g29 shifter: no notification, no retry loop -- fail visibly and stop
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (push) Has been cancelled
Python tests / test (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
kuhy: "I do not want it to work like this, I want it to just work
normally." PS4 mode (046D:C260) cannot be supported on this PC (no kernel
driver, SDL lg4ff has no c260 either, so FFB is dead there too) and the
selector is physical. Keep the mode detection so the journal and --status
name PS4 mode instead of "not found"; drop the desktop notification and
the 5-minute Restart loop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NVfC2T6DyvCFqse9A99zef
2026-09-18 10:56:52 +02:00
3ae53499e6 g29 shifter: detect PS4 mode (046D:C260) instead of failing silently
On the 2026-09-15 and 2026-09-17 boots the wheel enumerated as 046D:C260
(PS3/PS4 selector in PS4 position, bound by hid-generic). The BPF udev
rule, the ensure unit and its hotplug rule all keyed on C24F, so the unit
failed once with "no G29 found" and nothing was said; 1st/3rd stayed on
the firmware's bad decode until the selector was flipped a day later.

- fixes/g29_wheel_mode.sh (new, sourced): classify the HID bus as
  native/ps4/compat/absent; root-safe desktop notification via
  /run/user/*/bus + sudo -u.
- --ensure: absent -> exit 0; ps4/compat -> exit 1 + critical
  notification; native -> attach. --status prints the mode first.
- g29-shifter-bpf.service: Restart=on-failure, RestartSec=5min so a
  notification lost before the session bus exists at boot is re-sent.
- 99-g29-shifter-ensure.rules: also fires on C260.
- tests/test_fix_g29_shifter.bats: 13 tests against a fake sysfs tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NVfC2T6DyvCFqse9A99zef
2026-09-18 10:47:18 +02:00
b3f3f55863 install_new_lg4ff: regenerate the initramfs only when it carries the other copy
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (push) Has been cancelled
Python tests / test (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
The dkms pacman hook already rebuilds every preset on install and remove,
so the unconditional mkinitcpio -P cost 20 s twice per run on the host.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SS8M5wk88nJTXxDWz61KKk
2026-09-14 22:15:43 +02:00
7e2d78c7db Add the G29 shifter HID-BPF fix (1st/3rd engage reliably)
Live on this host since 2026-09-11 but never committed. The wheel firmware
decodes the shifter's hall sensor itself and this unit's top row rests at
Y 180-193, below the ~195 engage threshold, so 1st/3rd often did not
register. g29_shifter.bpf.c re-decodes those two gates from the raw X/Y
bytes with hysteresis (engage >= 160, release <= 140) and ORs the bit in
before hid-logitech parses the report; it never clears a bit, so the
firmware's working gates cannot regress. fix_g29_shifter.sh builds,
attaches and installs it persistently (udev-hid-bpf rule + a systemd
safety-net unit pulled in on every re-enumeration); g29_shifter_capture.py
records and grades raw captures per gate.

Two files were over the 250-line cap: the test file is split at the
record/CLI boundary with the report builders moved into a conftest fixture
(the naming hook allows only test_*.py in tests/), and the grader's
docstrings are tightened. No behaviour change to the installed fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SS8M5wk88nJTXxDWz61KKk
2026-09-14 22:12:31 +02:00
2d54765f6f Read the load average through LOADAVG_FILE so the probe tests are host-independent
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 checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
The "flags nothing on a quiet machine" case read the real /proc/loadavg and
went red whenever a game was running on the host (22/16 during a BeamNG
session), and the "flags a load at/above thread count" case had to SKIP
whenever the host was idle. Same override pattern as JOURNALD_CONF_DIR: the
harness writes a fixture, both cases now assert deterministically, and a
missing file degrades to 0 as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SS8M5wk88nJTXxDWz61KKk
2026-09-14 21:55:06 +02:00
c81e4a9446 Add G29 force-feedback doc and a new-lg4ff installer
BeamNG.drive 0.39 native lost G29 FFB because SDL3's HIDAPI lg4ff driver
advertises an effect-status query it cannot answer (12,201 failures per
session in beamng.log). DOCS-g29-ffb.md records the diagnosis, the narrow
SDL_JOYSTICK_HIDAPI_LG4FF=0 hint vs the broad one, and the launch-option
%command% bug that had gamemoderun passed as a game argument.

install_new_lg4ff.sh swaps the in-tree hid-logitech for new-lg4ff via DKMS
(dkms.conf installs it under the same name in updates/dkms/), regenerates
initramfs presets that bundle the module, and offers --status/--revert.
Passed install/status/revert in vmbox; host run pending.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SS8M5wk88nJTXxDWz61KKk
2026-09-14 21:43:28 +02:00
ce3c4213b0 Arch journal cap: 300M -> 4G, vacuum only past the cap
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 checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
300M held about two days on kuhy's desktop: one Steam boot wrote 480k
journal lines and the evidence for a curfew failure two weeks earlier was
already gone when it was needed (2026-09-13). The three Arch copies of
the journal tweak (arch_hardware, arch_perf_fixes, arch_perf_report) move
to a 4G cap, and "large"/vacuum now mean past that cap — a 2G journal is
deliberate retention, not a finding. Tests follow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mLnUeoJ3mUwGRTowTUH6d
2026-09-13 10:55:43 +02:00
db243fe02e Cache prettier's verdict so a push stops paying Node startup
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (push) Has been cancelled
Python tests / test (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
A push took ~13s. prettier is a pre-push hook precisely because Node's
startup dominates its runtime, and pre-commit chunks a large file list into
several invocations -- a 106-file push paid ten cold Node starts. ci-mirror,
the hook that looks expensive, was already 0.02s once its green-tree cache
hit.

A file whose content, prettier version and prettier config are all unchanged
since its last clean check cannot have become unformatted, so the verdict is
now cached and the file never reaches Node. Only clean verdicts are recorded,
so a formatting regression is always re-checked; the key includes
`prettier --version` and every config file, so an upgrade or a config edit
invalidates the cache wholesale. The systemd-run memory cap is unchanged.

Measured on the same push range: 13.0s -> 3.3s total, of which ~0.6s is
hooks and the rest is git's own network negotiation. On a 40-file list the
runner itself goes 0.652s -> 0.057s, starting no prettier process at all.

endurain/README.md and copilot-instructions.md are reflowed: the ~
reorganisation lengthened paths inside them, which changed prettier's
markdown table alignment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
2026-09-11 21:03:57 +02:00
f15f00f3fe Re-point paths for the ~ reorganisation (home-tidy)
Also bumps the 16 meta/requirements pins the freshness gate flagged
(anthropic 1.5.0, numpy 2.5.3, pytest-randomly 5, flake8-bugbear 26.9.9,
ruff 0.16.7, pyright 1.1.414, selenium 4.49.0, hypothesis 6.168.0, lxml
6.1.3, pipdeptree 4.2.5, the two types-* stubs) and Flutter 3.47.3 in
meta/.fvmrc. One test still expected the pre-move ~/mcp-servers path.

The pre-commit hook fed .zsh files to shfmt and shellcheck, neither of
which parses zsh (SC2148/SC1071), so no zsh file could be committed since
the hook was tightened on 2026-08-22; those now get `zsh -n` instead. The
hook's own shfmt pass also staged its reformat of 8 shell files.

CI_GREEN_SKIP because main is red on exactly the dependency-freshness
finding this commit fixes, which is the documented use of that flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
2026-09-11 20:50:19 +02:00
0cea82cab5 feat: the nftables drift check now runs itself at boot
`verify` gated on the two invariants whose breach cut every bridged
container off the internet on 2026-08-29 and again after the 2026-08-30
reboot -- but nothing invoked it, so it reported drift only when a human
thought to ask, and the outage it exists for is exactly the one nobody
thinks to ask about.

nftables-drift.service now runs it after nftables.service, docker.service
and network-online.target at every boot, plus a daily Persistent timer. A
breach is a failed unit in `systemctl --failed`, not a log line: a
self-check that detects a failure has to gate, not warn.

Proven in ~/utils/vmbox across two real reboots -- drifted /etc leaves the
unit failed with the diff and the missing docker0 accept in its journal,
matching /etc leaves it active with no false positive -- then installed and
run green on the host. Not yet observed across a host reboot.

Also bumps the gatelock pin to v0.7.3, which is what turned main's
dependency-freshness job red; CI_GREEN_SKIP is set because this commit is
that fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d48t4qsQLBJnDwDeo2Nom
2026-08-30 15:49:12 +02:00
89a44b58b2 feat: gate on nftables drift so the docker cut-off cannot come back silently
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 checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
The forward-chain fix from 334c0cd9 only ever reached the live ruleset by
hand; /etc/nftables.conf kept the bare default-drop chain, so the next
reboot cut every bridged container off again and the Signal bot went deaf
a second time. Nothing compared generated against persisted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:56:24 +02:00
2713ae9d66 Put the screen-locker status back on the i3 bar
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 checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
The GTK tray icon was the only status surface, and it had been commented out
of ~/.config/i3/config since 2026-08-21. With nothing in the bar, the locker
miscounted the week for a fortnight and the machine never said so.

Shows "<count>/<minimum> · <gaming budget>", read from the local status API
(screen-locker-web.service on 127.0.0.1:8770); clicking opens the full UI.

Three things it deliberately will not do quietly:
- a dead status server renders "status server down" in red, or the last known
  value marked (stale) in orange -- never a blank block. That server is what
  the gaming budget reads, so its absence costs two hours;
- a disarmed or unscheduled timer overrides the compliance colour entirely
  and shows "DISARMED" in red. A locker that cannot fire is the worse
  problem and the one that hides;
- clicking only opens the UI. There is no bar action that can clear a lock.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fcwu78wk17FWMHbbfbyicc
2026-08-29 22:55:24 +02:00
334c0cd904 fix: stop the wireguard firewall from silently cutting every container off
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 checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
`write_nftables_ruleset` emitted a forward chain with `policy drop` and no
rules at all. That chain runs at the same netfilter hook as Docker's own
DOCKER-USER/DOCKER-FORWARD chains, so it vetoed them: every bridged
container lost outbound networking while the host itself stayed online, so
nothing looked broken.

It cost the Signal bot three silent hours today. signal-cli lost its
connection to Signal at 15:32:50 and looped on reconnect for 2.5h, while
the bot kept answering /healthz with 200 -- `/v1/groups` still served from
local state, so every surface said healthy.

`flush ruleset` also deletes Docker's own tables, and dockerd only rebuilds
them on its next network event, so restore_docker_rules() now restarts
docker right after a successful apply.

Verified in vmbox (Arch guest, docker installed, alpine probe):
BASELINE=reachable -> OLD=blocked -> NEW=reachable, sshd active throughout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbjfWdAyHbCubac7wJKJZW
2026-08-29 18:34:25 +02:00
ce33c935e4 Run the website's post editor as a loopback unit, no Caddy route
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 checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
2026-08-29 17:50:03 +02:00
61abbf8cf9 Force-recreate the website container so config and dist changes apply
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 checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Two failure modes compose cannot see, both of which report a healthy
container while it serves 404s:

  1. The Caddyfile is a bind mount, so its contents are not in the config
     hash compose compares. Editing it changes nothing observable, compose
     says Running, and the new directives never load.
  2. A bind mount resolves once, at start. Replacing dist/ rather than
     emptying it leaves the container on the old unlinked inode: /srv reads
     empty and every request 404s.

Hit both at once on a real deploy today -- the container was Up 6 hours,
Caddy logs clean, /srv empty, curl 404. Reproduced by rm -rf dist (inode
84695030 -> 84695031) and fixed by the patched function in one run.

wait_for_website also stops using curl -sf, which collapses every non-2xx
into the same "did not become reachable". It now reports the status it saw,
because unreachable and answering-404 are different bugs and the message
named only the first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7BaCSV8FEtcNgVDVsRAJj
2026-08-29 16:35:30 +02:00
516acc243f Serve prerendered blog posts, not the SPA shell, from the website container
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 checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
The personal-website repo now prerenders each post to
dist/blog/<slug>/index.html. Caddy try_files does not resolve a directory
to its index on its own, so with the single-term directive every post URL
fell through to the SPA shell: right content once React booted, wrong
<title>, and no link preview. Verified against caddy:2.8 in Docker both
ways before and after.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7BaCSV8FEtcNgVDVsRAJj
2026-08-29 16:19:28 +02:00
adf2e402df Grade against 3.14 too, not just run on it
`requires-python` and the CI pin already said 3.14, but ruff, mypy and pylint
were still grading `meta/` against 3.10 -- three tools judging an interpreter
nothing runs any more, and ruff withholding the pyupgrade fixes that only
become safe at the newer target. `pin_ci_python.py` rewrites these three knobs.

What the stale target was hiding: `datetime.timezone.utc` where `datetime.UTC`
is now correct (UP017), and ruff's stable formatter applying PEP 758 --
`except (A, B):` becomes `except A, B:`. That makes the source 3.14-only at the
syntax level, which is what `requires-python = ">=3.14"` already promised; kuhy
chose it deliberately over holding ruff a release back (2026-08-29).

Also drops a comment in `wsg_grabber/models.py` that the bump makes false: it
explained why the file used ``str, Enum`` instead of ``StrEnum`` under mypy at
3.10, sitting directly above a ``class Verdict(StrEnum)`` that had already
stopped obeying it.

ruff, ruff-format, mypy --strict and pylint all clean at the new target.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr
2026-08-29 11:50:39 +02:00