diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-28 21:37:55 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-28 21:37:55 -0500 |
| commit | 2d9dcc942fc16b8e5bcbe0a6eced5a71f639ae29 (patch) | |
| tree | 1ec391b1d950bd0be6f922b5b02aa92c9694b727 /todo.org | |
| parent | 8342b74a696addf631bad5d811cfdac8ca722035 (diff) | |
| download | archsetup-2d9dcc942fc16b8e5bcbe0a6eced5a71f639ae29.tar.gz archsetup-2d9dcc942fc16b8e5bcbe0a6eced5a71f639ae29.zip | |
docs(todo): close the reboot and caffeine fixes, file four findings
The 2026-07-28 reboot cut the session short before two finished tasks could be closed. amdgpu.runpm=0 is confirmed live in /proc/cmdline, and the caffeine readability work shipped, so both close now.
Four new entries. Desktop settings didn't survive a session restart. Timer presets should start in one click. hyprlock still exits mid-lock, and its watchdog relaunch left no durable trace. The wireguard gpg convention is inert: the importer globs *.conf only and carries no gpg call, so the stated promise that it decrypts at import is false. That last one is why the newly encrypted wolf config stays untracked for now.
The hyprlock grading first read "some users sometimes", which the matrix maps to P3 rather than the [#B] written beside it. The frequency row was the wrong input. On a one-user machine, twice in three days is frequent, so I corrected the input rather than the letter.
Also corrected an earlier claim that night light "has likely never worked" from the config. It launches fine by hand and survives. It loses a race against compositor readiness at session start, and nothing relaunches it.
Diffstat (limited to 'todo.org')
| -rw-r--r-- | todo.org | 160 |
1 files changed, 160 insertions, 0 deletions
@@ -45,6 +45,166 @@ below): input-side-spec.org (DRAFT, four decisions open). * Archsetup Open Work +** DONE [#A] Reboot ratio to activate amdgpu.runpm=0 :bug:hyprland:ratio: +CLOSED: [2026-07-28 Tue] DEADLINE: <2026-07-28 Tue> +:PROPERTIES: +:CREATED: [2026-07-28 Tue] +:LAST_REVIEWED: 2026-07-28 +:END: +Craig's plan: close everything down, run topgrade, then reboot. Alarm set for 08:00 (=at= job 56, persistent desktop notify). + +=amdgpu.runpm=0= sits in =/etc/default/grub= and in the generated =/boot/grub/grub.cfg= (5 occurrences, so the reboot will actually apply it) but is absent from =/proc/cmdline=. The box has been up since 2026-07-22 21:10 and the fix landed 2026-07-24, so the running kernel predates it. The GPU is AMD Strix Halo (Radeon 8060S, =1002:1586=), exactly what the parameter targets: runtime power management invalidates the GPU resources hyprlock holds across a display power-cycle, so hyprlock exits without unlocking. + +That is the root cause under the 2026-07-27 lockdead screen. The screen-lock flock fix (dotfiles =ec18fd7=) stops one dead client from becoming a lockdead screen, but it treats the symptom -- this reboot treats the cause. + +Not :solo: — Craig closes his own session and runs topgrade first. + +Rebooted 2026-07-28 08:59. =amdgpu.runpm=0= confirmed present in =/proc/cmdline= afterward, so the parameter is finally live and the root-cause fix for the hyprlock lockout is in effect. + +** DONE [#B] Caffeine state is unreadable on both surfaces :bug:dotfiles:design:solo: +CLOSED: [2026-07-28 Tue] +:PROPERTIES: +:CREATED: [2026-07-28 Tue] +:LAST_REVIEWED: 2026-07-28 +:END: +Neither surface that reports caffeine tells the truth reliably, so there is no way to know at a glance whether the screen will lock. Found while investigating the 2026-07-27 lockout, where Craig believed caffeine was on and the screen locked anyway. + +Defect 1 — the settings panel shows a frozen value. =gui.py= calls =_refresh_async()= once during window construction (line 454) and again only after the user's own actions (=_after_matrix=, line 663). The only two =GLib.timeout_add= calls are one-shots (the 2400ms toast hide and a 350ms fire), so nothing re-reads state on a timer. An open panel therefore displays the caffeine value from the moment it opened, forever. Any external flip -- the waybar click, Super+I, the =caffeine-toggle= script -- leaves it stale with no self-correction. The panel is the only surface in the repo carrying a caffeine control (=panel.py:25=); maint has none and does not embed these toggles, so this is the display Craig read. + +Defect 2 — there is no caffeine indicator on the bar at all. =custom/caffeine= appears in neither the stowed =hyprland/.config/waybar/config= nor the live generated =/run/user/1000/waybar/config=, and no =custom/caffeine= block is defined anywhere in the waybar config dir. The =waybar-caffeine= script exists, works, and has its own passing test suite, but nothing displays it. So the bar has never been a source of caffeine state, and the keybind and script have been signalling (=pkill -RTMIN+8 waybar=) a module that isn't there. + +(An earlier read of this task said the bar showed two near-identical glyphs. That was wrong: the module is absent, not merely unstyled. The script's class names are still backwards -- =active= when caffeine is OFF, =inhibited= when ON -- and neither class is styled, but both points are moot until the module is actually in the bar.) + +Grading: Major severity (the panel reports state wrongly while it is open, and the only other surface does not exist, so there is no reliable source for a setting Craig actively manages) x most-of-the-time (any external toggle while the panel is open; the bar never shows it) = P2 = [#B]. + +Fix all three. Wire =custom/caffeine= into the bar, rename its classes so they describe caffeine rather than idle, and style them from the existing palette. Give the panel's toggle row a re-read on a timer or on focus-in. Solo -- buildable and testable, and the direction is settled by the defects rather than a taste call, though the bar color is worth a glance from Craig once it renders. + +All three shipped as dotfiles =033076c=, pushed. =custom/caffeine= now sits in the bar between DND and settings on =interval: 2=; classes renamed =on=/=off= and both styled, caffeine-ON in the theme's gold =#dab53d=; the panel re-reads live state every 3s while visible. Verified live in the stowed config and the generated =/run/user/1000/waybar/config=. The full suite caught a theme-copy regression (=themes/dupre/waybar.css= out of sync with =waybar/style.css=) that the focused suites missed. + +** TODO [#B] Desktop settings don't survive a session restart :bug:dotfiles:hyprland: +:PROPERTIES: +:CREATED: [2026-07-28 Tue] +:LAST_REVIEWED: 2026-07-28 +:END: +Craig, from the roam inbox 2026-07-28: "launching into wayland doesn't honor previous caffeine settings ...or I expect any other settings in the desktop settings module." Captured right after the 08:59 reboot. + +Confirmed, and it generalizes past caffeine. The settings module splits cleanly into two halves, and only one of them persists. + +Persisted, in =~/.config/desktop-settings/state.json= (=store.py= =DEFAULTS=): program slots, idle-tripper stages, wallpaper. These come back correctly. + +Not persisted — every one is derived live from a process or a compositor runtime option, so a session restart resets it to whatever =hyprland.conf= establishes: +- Caffeine — =caffeine_state()= is =pgrep -x hypridle= inverted, and =hyprland.conf:73= runs =exec-once = pkill -x hypridle; hypridle=. So every launch unconditionally starts hypridle, which means caffeine is *always* OFF after login. There is no code path that could restore it ON. +- Auto-dim — =dim_state()= reads =hyprctl getoption decoration:dim_inactive=, a compositor runtime value that resets to the config default on restart. +- Night light — =state()= is =pgrep -x gammastep=; the process dies with the session. +- DND — =dunstctl=; dunst restarts fresh from =exec-once=. +- Power profile / brightness — owned by powerprofilesctl and systemd-backlight, outside this module's scope. + +Verified live 10 minutes after the reboot: hypridle running (caffeine OFF), dim =false=, gammastep not running, dnd =false=, power =balanced=. Every toggle sat at its factory position. + +The failure is silent, which is what makes it bite: nothing tells you the value you set was discarded. That is the mechanism behind the 2026-07-27 lockout, where Craig believed caffeine was on and the screen locked anyway. + +Grading: Major severity (the panel's core promise is holding these values, and the reset is silent and total across all four toggles) x most users frequently (every session start resets them, though it only harms when a deliberate non-default was set) = P2 = [#B]. + +Not :solo: — the fix needs Craig's call on *which* toggles should persist and whether persistence is per-toggle opt-in. Restoring night light at 3pm or caffeine on a laptop are both plausibly wrong, so this is a preference question, not a derivable one. The mechanism itself (extend =store.py= with a =toggles= block, restore on session start) is mechanical once that's settled. + +Related: =[#B] Caffeine state is unreadable on both surfaces= covers display accuracy — whether the surfaces report the truth. This covers whether the value survives at all. Distinct bugs, same subsystem. + +*** Side finding — gammastep loses a startup race and nothing relaunches it +=hyprland.conf:75= runs =exec-once = gammastep=, but no gammastep process is alive. Today's three launch logs tell the story: =gammastep-2026-07-28-090034.log= carries "Wayland connection experienced a fatal error: -1 / Temperature adjustment failed", and the other two are empty. + +Launched by hand afterward it runs fine and survives, so gammastep is not broken — it loses a race against compositor readiness at session start. Nothing relaunches it, so night light is simply off for the whole session, silently. (An earlier read of this said night light "has likely never worked from the config". That was wrong: the failure is a startup race, not a permanent break.) + +Worth its own task — the fix is a readiness wait or a retry around that exec-once, not a persistence change. Filed here for now because it surfaced during this investigation. + +** TODO [#B] hyprlock still exits mid-lock; the watchdog relaunch is silent :bug:hyprland:dotfiles: +:PROPERTIES: +:CREATED: [2026-07-28 Tue] +:LAST_REVIEWED: 2026-07-28 +:END: +Craig, 2026-07-28 ~15:00: saw the Hyprland lockdead/error text blurred *behind* a working lock screen; it vanished when he authenticated. + +That ordering is the diagnosis. hyprlock's blur samples what the compositor is currently rendering, so the compositor was already showing lockdead when the new hyprlock attached. Sequence: hyprlock exits non-zero (no coredump, so it exits rather than crashing), Hyprland renders lockdead because the client is gone while the session stays locked, =screen-lock='s watchdog relaunches within =LOCK_RELAUNCH_DELAY= (0.5s), and the new client draws over the lockdead frame and blurs it. + +*The recovery worked.* On 2026-07-27 this same hyprlock exit produced two contending clients and a session recoverable only from another console. It now self-heals in half a second, and the residue is cosmetic. Both the flock guard (dotfiles =ec18fd7=) and the watchdog did their jobs — verified in this session's compositor log, where all four lock events created exactly one =sessionLock= and one =sessionLockSurface= each, against two of each on 2026-07-27. + +Two things remain. + +*Why hyprlock exits.* The wrapper's header blames GPU-resource invalidation across a display power-cycle (hyprlock#953), which =amdgpu.runpm=0= targets — and that parameter is live as of the 2026-07-28 08:59 reboot, confirmed in =/proc/cmdline=. There is also no DPMS idle rule any more (=e900903=), so idling never power-cycles the display. Yet hyprlock still exited. Strongest untested candidate: a screen recording (=wf-recorder= into =~/sync/recordings/2026-07-28-12-53-57.mkv=, running 12:53 until Craig killed it) held screencopy sessions on DP-4 across the lock. The compositor log carries 2454 screenshare sessions and a =CScreencopyProtocol= bind in the window between the last two locks. A screencopy client churning dmabufs alongside hyprlock's own is a plausible way to invalidate them, and it was the one large new variable that day. + +*The relaunch is silent.* The watchdog loop re-runs hyprlock and logs nothing, so there is no record of how often this fires, when, or with what exit code — which is exactly why the frequency couldn't be established from the logs. Log the exit code and a timestamp on each relaunch. + +Grading: Major severity (the lock client dies mid-lock, and the pre-fix version of this wedged a session unrecoverably) x most users frequently (twice in three days, and this is a single-user machine, so every occurrence lands on the only user) = P2 = [#B]. Downgraded from the 2026-07-27 [#A] because the wedge is fixed and the failure now self-heals. + +An earlier draft of this grading said "some users sometimes", which the matrix maps to P3 = [#C], not the [#B] written beside it. The frequency row was the wrong input rather than the letter: on a one-user machine a fault hitting twice in three days is frequent, not occasional. Corrected the input per the rule that a disputed grade is fixed at its inputs. + +Solo for the instrumentation half only: adding the relaunch logging is buildable, testable against the existing =tests/screen-lock= suite, and needs no decision. Diagnosing the exit is not solo — it needs a reproduction, and the likely trigger is Craig recording his screen. + +Next step when picked up: land the relaunch logging first so the next occurrence produces evidence, then try to reproduce by locking with =wf-recorder= running. + +** TODO [#B] The wireguard gpg convention is inert; the installer can't read it :bug:security:network: +:PROPERTIES: +:CREATED: [2026-07-28 Tue] +:LAST_REVIEWED: 2026-07-28 +:END: +Found 2026-07-28 by an independent review, while deciding whether to commit a newly-encrypted =wolf.conf.gpg=. + +=assets/wireguard-config/.gitignore:3= states: "Ship configs gpg-encrypted (*.conf.gpg) only; the installer decrypts at import." That is false. =scripts/import-wireguard-configs.sh:43= globs =$dir/*.conf= and nothing else, there is no =gpg= call anywhere in it, and line 67 hard-errors "no .conf files in $dir". A =.conf.gpg= in that directory is invisible to the importer. + +So the post-leak convention has a hole in the middle. The =.gitignore= permits tracking =*.conf.gpg= and tells you the installer will handle it, which invites committing encrypted secrets into a repo that cgit still serves anonymously, in exchange for a capability that does not exist. The encryption is real; the payoff is not. + +=README.org:12= disagrees with the =.gitignore= too: "Nothing here is tracked except this note and the .gitignore." Written 13 minutes after the =.gitignore= on 2026-07-20, so the stricter line is the later one. Three sources, two positions, no resolution. + +Grading: Major severity (the stated policy actively invites putting live key material into a world-cloneable repo on a false premise, and a leak here is unrecallable once cloned) x some users sometimes (only fires when someone adds a config) = P3 = [#C]... except this is the security carve-out, graded on severity alone because one occurrence with the right consequences is a showstopper. = [#B]. + +Not :solo: — the fix is a decision, not a build. Three options, and they interact with the open cgit move: +1. Teach the importer to decrypt =*.conf.gpg= (needs a passphrase or agent at install time, which on a fresh-install path may not exist — that is the likely reason it was never written). +2. Drop the =!*.conf.gpg= exception and keep the directory genuinely empty of secrets, tracked or not, until archsetup is off the public host. +3. Do the cgit move first, then revisit. + +Until it is resolved, do not commit any =*.conf.gpg=. The encrypted =wolf.conf.gpg= is deliberately left untracked in the working tree. + +Related: =[#B] Move archsetup off cgit= and =[#B] Audit cgit-published repos for secrets and privacy=. Both are still open, and both argue for keeping new secrets out of this repo until they land. + +** TODO [#B] Timer presets should start in one click :feature:dotfiles:timer: +:PROPERTIES: +:CREATED: [2026-07-28 Tue] +:LAST_REVIEWED: 2026-07-28 +:END: +Craig, captured 2026-07-28, routed here by home's inbox-zero pass from the shared roam inbox. + +Verbatim: "timer/alarm: timer preset buttons should be one click. we will have to adjust so the user knows to name the timer first (have the label on top of the timer buttons), have the text field on the same row, and add below. if the user adds the time value in the text field and presses enter, that should also start the timer." + +Two changes in one. A preset button should start its timer on a single click rather than needing the name step first, and the input area gets rearranged so the naming flow is obvious: label above the preset buttons, text field on the same row, add below. Enter in the text field starts the timer too. + +Panel source is =~/.dotfiles/timer/src/timer/= (=gui.py= for the view, =panel.py= for the presenter, =viewmodel.py= for state). + +Not :solo: — the rearrangement is described but not settled, and the result is a visual judgment Craig has to see. The one-click behaviour is buildable on its own; the layout wants a pass in front of him. Per the UI-prototyping rule, sketch the arrangement before touching production code. + +Related: =[#C] Add a time selector to the timer panel= covers a duration picker for the same input area. Design them together when either is picked up. + +** TODO [#A] Comet KVM setup for truenas :feature:infra:truenas: +DEADLINE: <2026-08-02 Sun> +:PROPERTIES: +:CREATED: [2026-07-27 Mon] +:LAST_REVIEWED: 2026-07-27 +:END: +Wire up the GL.iNet Comet (GL-RM1) IP KVM against truenas. It was bought 2026-01-14 for exactly this job and its KB node still reads "Arrived, not yet set up." + +Why now: truenas went dark 2026-07-24 and stayed unreachable. Diagnosis from ratio on 2026-07-27 — no tailnet contact for 3 days, 100% packet loss on 192.168.86.5, ARP entry FAILED (nothing answers ARP for the address, so the NIC is down at layer 2), every service port closed, while the gateway and a dozen other LAN hosts stayed reachable. Wake-on-LAN to 70:85:c2:db:9d:94 drew no response. With no console and no out-of-band power control there was no remote remedy at all, so recovery needed hands on the box. The Comet closes exactly that gap: BIOS/UEFI console, Wake-on-LAN, and browser access over its native Tailscale integration. + +Not :solo: — the physical cabling is Craig's, and the Tailscale enrollment needs his account. + +Steps, from the KB node ([[id:67bc5994-a763-48e2-926f-4ac0d1bad3db][GL.iNet Comet (GL-RM1) - KVM]]): +1. HDMI from truenas video out to the Comet's HD IN. +2. USB-A-to-USB-C from the Comet to a truenas USB port (keyboard/mouse emulation). +3. Ethernet to the network. +4. Power via USB-C (5V/2A). +5. Reach the web interface and enroll it in Tailscale, so it's usable when the LAN side of truenas is the thing that's broken. + +Then verify while truenas is healthy, rather than discovering the gaps during the next outage: confirm the console shows POST and the BIOS, that keyboard input reaches the box, and that Wake-on-LAN from the Comet actually powers it on. Enable WOL in the truenas BIOS if that last check fails — this outage never established whether it was on. + +Worth considering as a follow-up: the ATX power board accessory gives hard power-cycle control for a truly wedged box, which the KVM alone can't do. + ** TODO [#C] Post-upgrade hooks: compositor restart reminder + font cache rebuild :feature:infra:ratio:solo: :PROPERTIES: :CREATED: [2026-07-25 Sat] |
