aboutsummaryrefslogtreecommitdiff
path: root/todo.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-22 17:13:09 -0500
committerCraig Jennings <c@cjennings.net>2026-07-22 17:13:09 -0500
commit5fedecbd7a25e6357ccfa1b9fa587d36752492a4 (patch)
treec5de65996a987f8b1ff0d530f3ad77dbd4696c6c /todo.org
parentf1c661f50d6af2a115fc1430ae0478f2acef2dec (diff)
downloadarchsetup-5fedecbd7a25e6357ccfa1b9fa587d36752492a4.tar.gz
archsetup-5fedecbd7a25e6357ccfa1b9fa587d36752492a4.zip
feat(installer): enable the desktop-settings tick timer; close the panel buildHEADmain
The desktop-settings panel shipped in dotfiles (backings engine, presenters, GTK port of prototype 37, phase-4 integration, and a 17-point end-to-end suite). This repo's share: the installer now links desktop-settings-tick.timer alongside the maint timers so a fresh install gets the wallpaper tick, the spec flips to IMPLEMENTED naming the shipping commits, and the build tasks close with the drag-gesture and locked-path night-watch checks filed for manual validation.
Diffstat (limited to 'todo.org')
-rw-r--r--todo.org111
1 files changed, 76 insertions, 35 deletions
diff --git a/todo.org b/todo.org
index 717d8f4..bfe9e2e 100644
--- a/todo.org
+++ b/todo.org
@@ -45,24 +45,6 @@ below):
input-side-spec.org (DRAFT, four decisions open).
* Archsetup Open Work
-** DOING [#B] Build: desktop-settings panel :feature:hyprland:dotfiles:
-:PROPERTIES:
-:SPEC_ID: d6bb1e73-ec90-4327-85ee-bfa762da5bce
-:END:
-The GTK build of the desktop-settings panel per the spec (docs/specs/2026-07-02-desktop-settings-panel-spec.org, DOING; normative reference: prototype 37). Work happens in dotfiles settings/ — archsetup drives the lifecycle. Two non-blocking build-time picks live in the spec's Review findings (wallpaper setter tool; store location/format) — decide in phase 1 and record there.
-*** 2026-07-22 Wed @ 13:14:01 -0500 Built the backings engine (phase 1) — dotfiles 7a15237
-Landed as dotfiles settings/src/settings (10 modules) + tests/settings (118 tests against fake binaries, auto-discovered by make test — 81 suites green). Covers brightness/kbd (5% floor, x10 drum), toggles (dim, pointer cycle via toggle-touchpad, caffeine), DND class-split (dunst pause level 60, close-all before unpause, alarms punch through live), powerprofilesctl, nightlight (resident gammastep), hypridle.conf renderer + symlink-safe write + caffeine-respecting reload + hyprlock grace, suntimes (pure NOAA math), and the wallpaper engine (awww/mpvpaper/projector adapters, galleries, random draw, atomic JSON store). All three build-time picks recorded as DONE findings in the spec (setter=awww, store=state.json, nightlight=gammastep). Handoff note in ~/.dotfiles/inbox/.
-*** TODO Phase 2 — presenters :solo:
-GTK-free models at 100% unit coverage: program matrix (complete definitions, active-is-live surviving member writes, pin/letter/radio rows, slots 1-4), bench (drums, pointers, idle clamping/parking/bypass), wallpaper channels (mint/edit/delete/sort for pairs/sets/colors, per-mode sources, previews).
-*** TODO Phase 3 — GTK4/Blueprint UI
-Port prototype 37's instruments to GTK in family chrome: console keys, programmable matrix, drum roller, tripper dial (bottom legend, exact drag counter, bypass stamp), encircled groups, iconic channel cards, themed gallery wells, the three presses. Self-clocked instruments own their widget lifetime. Layer-shell chassis, sub-view navigation, AT-SPI smoke.
-*** TODO Phase 4 — integration and bar
-Bar consolidation LANDED EARLY (2026-07-22, live): gear module + Super+Shift+G wired; dim AND caffeine modules dropped (Craig amended decision A during the first drive — bar keeps only touchpad; dim/caffeine are panel-owned, keybinds stay). Remaining: watch/clock/world projected renderers (night watch as the hyprlock face); live hypridle rewrite; dunst pause-level config (alarm rules with override_pause_level 100); refresh-signal rewiring; end-to-end verify-everything.
-Backing tools: mpvpaper (AUR) + power-profiles-daemon installed on ratio 2026-07-22 and added to the installer (ppd service enable gated on no-battery, since TLP owns power on laptops). Remaining: velox wants mpvpaper (and optionally the ppd package, service off) by hand — one-time AUR install the sync doesn't carry.
-*** TODO Test surface — end-to-end pass
-A scripted end-to-end pass mirroring prototype 37's 17-point suite against the real panel, plus the per-phase suites called out above.
-*** TODO Flip the spec to IMPLEMENTED
-When the phases land: flip docs/specs/2026-07-02-desktop-settings-panel-spec.org DOING → IMPLEMENTED with a dated history line naming the shipping commits.
** TODO [#C] Timer module hero hierarchy :feature:waybar:timer:
From the roam inbox (Craig, claimed 2026-07-22). Which display ("hero") wins the waybar timer module when several timer modes run simultaneously: pomodoro wins over everything (the user is actively working; it's likely their main focus). The rest rank in chronological order of when they would ring. Worked example: with a just-started 15-min timer, a 1-hr timer at 10 minutes left, a pomodoro, and an alarm ringing in 12 minutes — show the pomodoro; when it completes, the 1-hr timer (rings first), then the alarm, then the 15-min timer. Feeds the timer-panel spec (docs/specs/2026-07-02-timer-panel-spec.org).
** TODO [#C] Timer module: drop RING message, persistent notifications :bug:waybar:timer:
@@ -101,13 +83,6 @@ Post-mortem for the 2026-07-15 velox no-kernel boot failure, from the archsetup/
- Sanoid-vs-actual dataset drift: configure_zfs_snapshots configures zroot/var/log + zroot/var/lib/pacman as separate datasets; velox's actual layout has neither separate (/var/log sits inside zroot/var). Reconcile.
- CONFIRMED (2026-07-21): the pre-pacman snapshot hook fired on velox — the 2026-07-15 no-kernel boot was recovered via the pre-pacman ZFS snapshot rollback, and velox is back on the tailnet running linux-lts 6.18.38 with initramfs present (2026-07-19 session). Root-cause hook-ordering fix shipped separately. Still open: the post-upgrade /boot assertion in guard.py and the sanoid-vs-actual dataset drift reconcile (the two bullets above).
-** CANCELLED [#B] Hyprland layoutmsg crash — bad_variant_access (upstream) :bug:hyprland:
-CLOSED: [2026-07-21 Tue]
-Dropped 2026-07-21 (Craig's call) — not tracking the upstream report. The crash evidence (both reports + tmpfs log excerpts) and the voice-passed issue draft stay preserved in [[file:working/hyprland-layoutmsg-crash/][working/hyprland-layoutmsg-crash/]] if it recurs and is worth reviving.
-Grading: Critical severity (SIGSEGV kills the whole desktop session; every GUI app's unsaved state lost) x rare edge case (twice in ~4.5 months: 2026-03-07 on v0.54.1, 2026-07-20 on v0.55.4) = P2 = [#B]. Upstream Hyprland bug, not this repo's code — the task tracks reporting it and picking up the fix.
-A layoutmsg mfact dispatch (layout-resize, mod+H/L) throws std::bad_variant_access inside Layout::CAlgorithm::layoutMsg, uncaught, SIGSEGV. Both crashes fired from the layout-resize mfact path (keycode 104 shrink today, 108 grow in March). Layout at crash was master and the identical mfact had worked seconds earlier; the pre-crash window held monocle<->master toggles, two window closes dropping focus to "[Window nullptr]", and togglefloating x2. Monocle is a registered v0.55 layout (log shows graceful "Unknown monocle layoutmsg" rejects), so the config is not at fault; related edges are guarded ("mfact -> no window") while this path misses its variant guard. Repo has no newer build (0.55.4-1 installed and repo).
-Evidence preserved in [[file:working/hyprland-layoutmsg-crash/][working/hyprland-layoutmsg-crash/]] (both crash reports + excerpts from the tmpfs session log, extracted before reboot loses it).
-Next: Craig posts the issue himself (2026-07-20 decision) — the voice-passed draft is [[file:working/hyprland-layoutmsg-crash/issue-draft.md][issue-draft.md]], with both crash reports and the log excerpts beside it for attaching. Watch the repo for a fixed release and close on confirmation. The layout-resize script guard was declined (a script can't observe the internal desync).
** TODO [#B] Assess a Hyprland left-drag window gesture :feature:hyprland:
:PROPERTIES:
:LAST_REVIEWED: 2026-07-21
@@ -884,6 +859,47 @@ Craig's standing checklist of everything that isn't agent-verifiable. Each child
Priority and type tag added by that audit: the task carried neither, which kept the project's largest live container out of the agenda entirely.
+*** Settings panel: brightness drum drags
+What we're verifying: the paper drums' drag gesture (a Cairo hit-test the e2e suite can't drive) maps drag distance to backing percent with the floor rules. On ratio (no backlight) the drums render dimmed and refuse the drag — that's expected, so the drag half of this test needs velox.
+- Open the settings panel (Super+Shift+G).
+- Drag the SCREEN drum downward well past the bottom.
+- Drag the KBD drum the same way.
+#+begin_src sh :results output
+brightnessctl -m info; brightnessctl -m -c kbd_backlight info
+#+end_src
+Expected: the screen backing floors at 5% (drum never shows 0); the kbd backing reaches 0. On ratio both drums are dimmed and undraggable instead.
+
+*** Settings panel: tripper dial tab drags
+What we're verifying: the dial's drag gestures — clamping between enabled neighbors, the exact-minutes counter during a drag, the OFF-notch park, and unparking (the e2e suite covers this commit path only at the backing layer).
+- Open the settings panel.
+- Drag the LOCK tab counterclockwise toward 0; watch the minutes counter during the drag.
+- Drag the SUSPEND tab out of the OFF notch onto the scale.
+- Drag SUSPEND back down into the bottom OFF notch.
+#+begin_src sh :results output
+cat ~/.config/hypr/hypridle.conf
+#+end_src
+Expected: LOCK refuses to land below DIM's minutes (clamps, doesn't cross); the counter shows exact minutes while dragging; SUSPEND leaves/rejoins the conf as it unparks/parks. Finish by restoring the rail to DIM 5 / LOCK 7 / WATCH 8 / SCREEN OFF 10 / SUSPEND parked.
+
+*** Settings panel: matrix pin clicks and letter wheels
+What we're verifying: the program matrix's pin and wheel hit-tests (Cairo; the e2e suite drives only the backing calls) — seat/unseat pins, cycle a CPU POWER letter, and the active-is-live rule.
+- Open the settings panel.
+- Activate FOCUS (its head key).
+- Click FOCUS's NIGHT LIGHT pin to seat it.
+- Click the pin again to unseat it.
+- Click FOCUS's CPU POWER letter wheel a few times.
+- Move a control that belongs to no program (e.g. flip TOUCHPAD).
+Expected: seating the pin starts the night light immediately (screen warms) and FOCUS stays active; unseating stops it; each wheel click steps P→B→S and applies live; the manual TOUCHPAD change deactivates the scene (no head stays lit).
+
+*** Settings panel: locked-path night-watch swap
+What we're verifying: the WATCH stage under a locked session — the kiosk face reveals only after its window maps (no desktop flash), and first input restores hyprlock. The e2e/live checks so far only exercised the unlocked lifecycle. Note: caffeine was found engaged on 2026-07-22 (hypridle deliberately left stopped); release caffeine first or this never fires.
+- Release caffeine so hypridle runs with the five-stage conf.
+- In the panel, temporarily drag the rail tight: DIM 1 / LOCK 2 / WATCH 3.
+- Lock the session (Super+Shift+Q → lock, or wait for the LOCK stage).
+- Leave the machine untouched past the WATCH minute mark.
+- Watch the transition carefully for any flash of the desktop between hyprlock and the night-watch face.
+- Press a key or move the mouse.
+Expected: the night-watch board replaces the lock face with no desktop flash between them; first input drops the face and hyprlock is back (password prompt, not the desktop). If the face fails to start, the plain hyprlock stays — never a bare desktop. Restore the rail to DIM 5 / LOCK 7 / WATCH 8 afterward.
+
*** Net panel: sticky error toast dismisses on the next click
What we're verifying: the stuck enterprise-error banner (dotfiles a157bed) now clears when you click anywhere else in the panel — the fix is a pointer-level gesture that AT-SPI can't drive.
- Open the net panel from the bar.
@@ -1521,10 +1537,6 @@ Specced 2026-07-10 after discussion with Craig, and the design grew past the ori
Parent spec: [[file:docs/specs/2026-07-09-audio-doctor-spec.org][docs/specs/2026-07-09-audio-doctor-spec.org]] (IMPLEMENTED). This is a v1 gap found after the fact, not a phase of it.
-** DONE [#C] WireGuard import is now config-less — decide feature fate :feature:network:
-CLOSED: [2026-07-21 Tue]
-Decided 2026-07-21 (Craig): KEEP the import feature. The out-of-band flow is already in place — =assets/wireguard-config/= carries a README documenting "drop plaintext =*.conf= locally at install time (gitignored); ship encrypted =*.conf.gpg= to track", and its =.gitignore= enforces it (=*.conf= blocked, =!*.conf.gpg= allowed). The script also already no-ops gracefully on an empty dir (=shopt -s nullglob= + a =found= flag), so nothing ships and nothing errors when no configs are present. Nothing to build; the fate decision was the whole task.
-scripts/import-wireguard-configs.sh reads assets/wireguard-config/*.conf, but no configs ship in the repo anymore (removed as a public-leak fix; .gitignore blocks plaintext).
** TODO [#C] Waybar modules run together — need subtle separators :bug:dotfiles:waybar:
Craig misreads where one module ends and the next begins — the wind (weather) value runs straight into the date with no visual stop, so he reads the wind figure as the start of the date. Add a light, subtle separator or spacing between adjacent Waybar modules.
Grading: Minor severity (legibility, nothing broken) x frequent (every glance at the bar) = P3 = [#C].
@@ -1539,12 +1551,6 @@ From the roam inbox (2026-07-20): the shipped Waybar weather chip's comfort colo
- Bad conditions — red number: temp over 90 → the temp number is red; wind over a comfort level → the wind glyph displays and its number is red.
Open design question (Craig): which other conditions/combinations to signal, and how a forecasted severe event (e.g. an upcoming hurricane) should display.
Grading: Minor severity (legibility on a shipped chip, nothing broken) × frequent (every glance at the bar) = P3 = [#C]. Mostly buildable from the rules above; the severe-event display needs Craig's call. Waybar is archsetup-owned per the dotfiles standing rule.
-** DONE [#C] Dupre theme waybar.css drifted from live style.css :bug:dotfiles:waybar:
-CLOSED: [2026-07-21 Tue]
-Fixed in dotfiles 3e4e7ff (2026-07-20, "fix(theme): sync dupre waybar.css with the live weather rules") — dupre/waybar.css is byte-identical to live again, restoring the =#custom-weather= selectors/hover/gold divider, so =tests/theme-css= is green.
-Grading: Minor severity (cosmetic, reverts only on a theme switch) × rare edge case (dupre is already the active theme) = P4 = [#D] on user impact, bumped to [#C] because the dotfiles =make test= stays RED until synced, poisoning the green baseline for every future commit.
-The weather-kit work added =#custom-weather= selectors to =hyprland/.config/waybar/style.css= but never mirrored them into =hyprland/.config/themes/dupre/waybar.css=. =tests/theme-css= asserts the two files are identical (set-theme copies the theme file over the live one), so switching to dupre would silently revert the weather chip styling. Fix: sync the theme file to live. Pre-existing; found 2026-07-19 during an unrelated commit's green-baseline run.
-
** TODO [#C] Add a time selector to the timer panel :feature:timer:
Offer a period-appropriate selector for timer duration, likely drawing on the
tape-counter idiom, while preserving the existing direct-entry path.
@@ -2008,3 +2014,38 @@ archsetup:3054 rewrites the whole GRUB_CMDLINE_LINUX_DEFAULT line with a fixed s
CLOSED: [2026-07-21 Tue]
Shipped in dotfiles 8bc79ba per Craig's calls (one global button, rendered text): COPY on the doctor row serializes every category band via the same card_spec the GUI renders, through panelkit clipboard. TDD tests/maint/test_status_copy.py, full dotfiles make test green, inbox note sent. Live check pending: open the maint panel, press COPY, paste.
Craig's roam capture 2026-07-20, routed via .emacs.d sentry inbox-zero as archsetup-owned UI work. Dotfiles maint panel work; archsetup drives it end-to-end per the standing rule.
+** DONE [#B] Build: desktop-settings panel :feature:hyprland:dotfiles:
+CLOSED: [2026-07-22 Wed]
+:PROPERTIES:
+:SPEC_ID: d6bb1e73-ec90-4327-85ee-bfa762da5bce
+:END:
+The GTK build of the desktop-settings panel per the spec (docs/specs/2026-07-02-desktop-settings-panel-spec.org, DOING; normative reference: prototype 37). Work happens in dotfiles settings/ — archsetup drives the lifecycle. Two non-blocking build-time picks live in the spec's Review findings (wallpaper setter tool; store location/format) — decide in phase 1 and record there.
+*** 2026-07-22 Wed @ 13:14:01 -0500 Built the backings engine (phase 1) — dotfiles 7a15237
+Landed as dotfiles settings/src/settings (10 modules) + tests/settings (118 tests against fake binaries, auto-discovered by make test — 81 suites green). Covers brightness/kbd (5% floor, x10 drum), toggles (dim, pointer cycle via toggle-touchpad, caffeine), DND class-split (dunst pause level 60, close-all before unpause, alarms punch through live), powerprofilesctl, nightlight (resident gammastep), hypridle.conf renderer + symlink-safe write + caffeine-respecting reload + hyprlock grace, suntimes (pure NOAA math), and the wallpaper engine (awww/mpvpaper/projector adapters, galleries, random draw, atomic JSON store). All three build-time picks recorded as DONE findings in the spec (setter=awww, store=state.json, nightlight=gammastep). Handoff note in ~/.dotfiles/inbox/.
+*** 2026-07-22 Wed @ 15:26:44 -0500 Built the presenters (phase 2) — dotfiles 5172289
+Three GTK-free models per prototype 37, all at 100% line coverage (tests/settings/test_presenters.py, 100 tests; full repo suite green before and after). programs.py: the matrix — eight complete programs (Craig's four factory scenes drafted here per the pre-flight pick, slots 1-4 first-class), pin rows + power radio row, activate returns the full sets, member writes return apply/updated with active-is-live surviving. bench.py: drum mapping (screen never reads 0, floor 5%; kbd floors at 0), idle rail order clamping between enabled neighbors, park/unpark with re-clamp, caffeine bypass, view-state builder tolerant of no-backlight None. channels.py: the eight-channel bank, per-mode sources visibility, alpha/recency sort (unlabeled last), the shared mint/edit/delete grammar for pairs/sets/colors (press arm-cycle, two-picture set minimum, dup rejection, selection clamping), sources guardrails, interval wheel, previews. Handoff note in ~/.dotfiles/inbox/.
+*** 2026-07-22 Wed @ 16:03:52 -0500 Ported prototype 37's instruments to GTK (phase 3) — dotfiles 33d82eb
+The panel renders P37 end to end. New instruments.py carries the three Cairo instruments as clock-free humble objects: ProgramMatrix (glyph/numbered heads over jewel pins + CPU POWER paper letter wheels), DrumRoller (paper drums, drag-to-set, dimmed n/a on no-backlight machines), TripDial (sqrt 300° scale, colored stage tabs, OFF-notch parking, exact-minutes drag counter, BYPASSED · CAFFEINE stamp, bottom legend). gui.py rebuilt to P37's layout with the wallpaper sub-view: channel bank with drawn faces, minted pair/color/set trays (alpha/time sort, edit/delete chip feet), the three presses (pair arm-cycle, color picker, set press + interval wheel), sources with a folder picker. New GTK-free glue all unit-tested (test_panel_glue.py, 33 tests): dial geometry in bench, matrix/idle/wallpaper wiring in panel, presenter-vocabulary channels (pair/solid/random-from-set) in wallpaper.apply. AT-SPI smoke (make test-panel-settings) drives the real wiring against faked backings + a sandboxed store, pinned to its own child pid so it can never fire a live panel's backings. Visually verified on a headless output against P37 captures (main + pair/single/solid/random). Adaptations recorded in the handoff: five-stage dial (WATCH gets its own green — the engine runs watch separately, P37 merged the label), DESKTOP_SETTINGS_START_VIEW test seam. Full suite 84 suites green; window rule widened for the 540px panel. Handoff note in ~/.dotfiles/inbox/.
+*** 2026-07-22 Wed @ 16:47:54 -0500 Integrated phase 4 — dotfiles 680b50d
+Bar consolidation had landed early (74f723e); this pass shipped the rest. settings-project hosts the watch/clock/world channels as HTML faces (settings/faces/) on a gtk-layer-shell background window over WebKit2 — all three visually verified on a headless output, world reading the waybar worldclock roster via query param. settings-watch is the hypridle watch-stage host: throwaway-profile chrome kiosk that reveals only after its window maps behind the lock and relocks before teardown — a failed face degrades to the plain lock, never a bare desktop (unlocked lifecycle verified live; the locked swap goes to the manual checklist). Sun-pair location reads whereami live per transition with last-good cache in state.json (verified live: 9.5s first beat, New Orleans coords, Gogh day side applied); desktop-settings-tick.timer (2 min, enabled on ratio, added to the installer) drives flips and random draws — 23ms no-op beats. dunstrc history_length 100 protects held alarms (full DND cycle verified against live dunst; wtimer alarms already CRITICAL via the notify wrapper, no promotion rule needed). Live hypridle rewrite verified — five-stage regime rendered through the stow symlink, caffeine respected (found engaged, daemon correctly left stopped). Refresh signals needed no rewiring (touchpad signals itself via toggle-touchpad). 45 new tests; suite 84 suites green; smoke 13/13. Handoff note in ~/.dotfiles/inbox/.
+Velox one-time steps (sync doesn't carry): mpvpaper (AUR), optionally power-profiles-daemon (service off), and systemctl --user enable --now desktop-settings-tick.timer.
+*** 2026-07-22 Wed @ 17:05:58 -0500 Landed the 17-point end-to-end pass — dotfiles 9038eee
+Prototype 37's 17-point suite re-derived against the real panel (the original Playwright script wasn't preserved; the functional surface in the spec's Final prototype section is the source). tests/settings/panel_e2e.py + run-panel-e2e.sh + =make test-panel-e2e=: points 1-14 drive the running panel over AT-SPI (program recall with per-backing verification across FOCUS/BATTERY/slot1, pointer console keys, all eight wallpaper channels including projected watch/world stop/start ordering, close); points 15-17 cover the Cairo instruments (drums, tripper dial clamp/park/render/reload, matrix pins + letter wheels with active-is-live) at the backing layer, since AT-SPI can't reach a DrawingArea's hit-tests. Same safety posture as the smoke: sandboxed store, faked backings, pid-pinned a11y node. 17/17 green on ratio's live compositor; full suite 85 green; smoke 13/13; ruff clean. The drag gestures go to the manual checklist below. Handoff note in ~/.dotfiles/inbox/.
+*** 2026-07-22 Wed @ 17:05:58 -0500 Flipped the spec to IMPLEMENTED
+docs/specs/2026-07-02-desktop-settings-panel-spec.org DOING → IMPLEMENTED with a dated history line naming the shipping commits (dotfiles 7a15237 / 74f723e / 5172289 / 33d82eb / 680b50d / 9038eee) and the verification evidence (85 suites, smoke 13/13, e2e 17/17). The four panel drag-gesture checks and the locked-path night-watch swap live under "Manual testing and validation" — human-eye checks, not implementation blockers.
+** CANCELLED [#B] Hyprland layoutmsg crash — bad_variant_access (upstream) :bug:hyprland:
+CLOSED: [2026-07-21 Tue]
+Dropped 2026-07-21 (Craig's call) — not tracking the upstream report. The crash evidence (both reports + tmpfs log excerpts) and the voice-passed issue draft stay preserved in [[file:working/hyprland-layoutmsg-crash/][working/hyprland-layoutmsg-crash/]] if it recurs and is worth reviving.
+Grading: Critical severity (SIGSEGV kills the whole desktop session; every GUI app's unsaved state lost) x rare edge case (twice in ~4.5 months: 2026-03-07 on v0.54.1, 2026-07-20 on v0.55.4) = P2 = [#B]. Upstream Hyprland bug, not this repo's code — the task tracks reporting it and picking up the fix.
+A layoutmsg mfact dispatch (layout-resize, mod+H/L) throws std::bad_variant_access inside Layout::CAlgorithm::layoutMsg, uncaught, SIGSEGV. Both crashes fired from the layout-resize mfact path (keycode 104 shrink today, 108 grow in March). Layout at crash was master and the identical mfact had worked seconds earlier; the pre-crash window held monocle<->master toggles, two window closes dropping focus to "[Window nullptr]", and togglefloating x2. Monocle is a registered v0.55 layout (log shows graceful "Unknown monocle layoutmsg" rejects), so the config is not at fault; related edges are guarded ("mfact -> no window") while this path misses its variant guard. Repo has no newer build (0.55.4-1 installed and repo).
+Evidence preserved in [[file:working/hyprland-layoutmsg-crash/][working/hyprland-layoutmsg-crash/]] (both crash reports + excerpts from the tmpfs session log, extracted before reboot loses it).
+Next: Craig posts the issue himself (2026-07-20 decision) — the voice-passed draft is [[file:working/hyprland-layoutmsg-crash/issue-draft.md][issue-draft.md]], with both crash reports and the log excerpts beside it for attaching. Watch the repo for a fixed release and close on confirmation. The layout-resize script guard was declined (a script can't observe the internal desync).
+** DONE [#C] WireGuard import is now config-less — decide feature fate :feature:network:
+CLOSED: [2026-07-21 Tue]
+Decided 2026-07-21 (Craig): KEEP the import feature. The out-of-band flow is already in place — =assets/wireguard-config/= carries a README documenting "drop plaintext =*.conf= locally at install time (gitignored); ship encrypted =*.conf.gpg= to track", and its =.gitignore= enforces it (=*.conf= blocked, =!*.conf.gpg= allowed). The script also already no-ops gracefully on an empty dir (=shopt -s nullglob= + a =found= flag), so nothing ships and nothing errors when no configs are present. Nothing to build; the fate decision was the whole task.
+scripts/import-wireguard-configs.sh reads assets/wireguard-config/*.conf, but no configs ship in the repo anymore (removed as a public-leak fix; .gitignore blocks plaintext).
+** DONE [#C] Dupre theme waybar.css drifted from live style.css :bug:dotfiles:waybar:
+CLOSED: [2026-07-21 Tue]
+Fixed in dotfiles 3e4e7ff (2026-07-20, "fix(theme): sync dupre waybar.css with the live weather rules") — dupre/waybar.css is byte-identical to live again, restoring the =#custom-weather= selectors/hover/gold divider, so =tests/theme-css= is green.
+Grading: Minor severity (cosmetic, reverts only on a theme switch) × rare edge case (dupre is already the active theme) = P4 = [#D] on user impact, bumped to [#C] because the dotfiles =make test= stays RED until synced, poisoning the green baseline for every future commit.
+The weather-kit work added =#custom-weather= selectors to =hyprland/.config/waybar/style.css= but never mirrored them into =hyprland/.config/themes/dupre/waybar.css=. =tests/theme-css= asserts the two files are identical (set-theme copies the theme file over the live one), so switching to dupre would silently revert the weather chip styling. Fix: sync the theme file to live. Pre-existing; found 2026-07-19 during an unrelated commit's green-baseline run.