diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index a8e40ac..3d9a35b 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -94,24 +94,6 @@ Next slice: on hardware, run `hyprctl clients` while each is open, read the real `class`, then append rules. Also revisit whether blueman/s-c-p actually float once seen (regex tolerance for the `.…-wrapped` form). -### 51. Waybar/menu behaviour bugs — V2 render pending -Fixes shipped V1 (2026-07-09): doctor indicator emits `󰒡` + `class:bad` -when unhealthy (was empty text → self-hidden); CC appearance toggles print -"(requires rebuild)"; summer-day scroll `e±1`→`r±1`. **Remaining V2:** a -theme-shot render with an induced doctor failure to see the glyph (fold into -#44's `checks.doctor` extension); CC message + scroll are behavioural (V1 -+ self-evident). - -### 52. Theme fidelity bugs — btop V2 render pending -Six per-theme defects fixed 2026-07-09 (rose-pine btop→Dawn; everforest + -summer-night btop `inactive_fg`; vantablack role inversion; osaka-jade -text/subtext + warn; catppuccin-latte mantle/accentAlt/ANSI; catppuccin -Mocha btop). JSON fixes **V0-verified** (`check-theme-contrast` 24×7 all -pass — accentAlt retuned to Latte mauve `#8839ef`, not the audit's pink -`#ea76cb` which fails the 3.0 floor). **Remaining V2:** a theme-shot render -of the btop-changed themes (rose-pine, everforest, summer-night, vantablack, -catppuccin) — btop.theme isn't contrast-checked. - ### 54. Installer safety + polish — V2 scenarios pending Four guards shipped 2026-07-09 (V0/V1: bash -n, flake check, nomarchy-install builds): offline `compose-lock` failure now fail-closes instead of a network diff --git a/agent/HARDWARE-QUEUE.md b/agent/HARDWARE-QUEUE.md index 0d64f37..6eb308d 100644 --- a/agent/HARDWARE-QUEUE.md +++ b/agent/HARDWARE-QUEUE.md @@ -8,6 +8,14 @@ the failure as a NOW bug in BACKLOG.md. Machines: the **AMD dev box** QA machine), the **T14s** (webcam case). ## Any machine (dev box is fine) +- [ ] **btop theme fidelity (#52 residual)** — softGL theme-shot cannot + open Ghostty, so the hand `btop.theme` assets were only guest-file + asserted (main_bg / inactive_fg keys) + desktop/bar rendered for + rose-pine, everforest, summer-night, vantablack, catppuccin. On a + real session: `nomarchy-theme-sync apply ` then `btop` and + confirm backgrounds/text match the theme (esp. rose-pine Dawn light + bg `#faf4ed`, vantablack near-black `#0d0d0d`, catppuccin Mocha + `#1E1E2E`). One pass cycling those five is enough. - [ ] **Battery charge limit re-apply on unplug** — `sudo nixos-rebuild switch` with `power.batteryChargeLimit = 80`, physically unplug/replug AC, confirm `charge_control_end_threshold` re-reads 80. (udev trigger diff --git a/agent/JOURNAL.md b/agent/JOURNAL.md index 714278b..0df01ac 100644 --- a/agent/JOURNAL.md +++ b/agent/JOURNAL.md @@ -17,6 +17,24 @@ Template: --- +## 2026-07-09 — #51+#52 V2 batch: doctor glyph + btop bake +- **Task:** NEXT #51 (doctor Waybar glyph) + #52 (btop fidelity render). +- **Did:** theme-shot harness now asserts `nomarchy-doctor-status` + (`class:bad` + glyph), guest `btop/themes/nomarchy.theme`, pokes + waybar RTMIN+10, best-effort Ghostty+btop shot. Fixed the doctor + tripwire so it actually *shows*: absolute path to `nomarchy-doctor` + (PATH self-hide), ANSI-stripped tooltip, `󰀨` glyph, `format = "{}"`, + signal 10 on generated + whole-swap bars. +- **Verified:** **V2** — `THEME= nix build --impure -f tools/theme-shot.nix` + green for rose-pine, summer-night, catppuccin, everforest, vantablack; + viewed bar crops: red alert-circle before the bell on generated + (rose-pine) and whole-swap (summer-night). Scripted btop.theme key + checks (Dawn/inactive_fg/Mocha/vantablack) all OK. V0 flake check + + contrast 24×7 pass. Ghostty under softGL never opened → btop TUI + visual queued V3. +- **Pending:** HARDWARE-QUEUE btop TUI spot-check (five slugs). +- **Next suggestion:** #54 installer V2 scenarios, or #33 rofi scrollbar. + ## 2026-07-09 — #43 V2: System ▸ Firmware menu render - **Task:** V2 the shipped Firmware menu (#43). theme-shot render of `nomarchy-menu system`. diff --git a/agent/MEMORY.md b/agent/MEMORY.md index 6def52c..7815595 100644 --- a/agent/MEMORY.md +++ b/agent/MEMORY.md @@ -7,6 +7,16 @@ here the moment a debugging session teaches you something a future iteration would otherwise rediscover. ## Testing & VM recipes +- **theme-shot softGL cannot start Ghostty** — `btop.png` is best-effort + (usually identical to desktop). Guest asserts on + `~/.config/btop/themes/nomarchy.theme` prove baking; the TUI look is + hardware/GL tier (HARDWARE-QUEUE). +- **Waybar `custom/doctor` tripwire:** status helper must invoke + `nomarchy-doctor` by **absolute store path** (waybar's env can miss + system PATH → `command -v … || exit 0` self-hides forever); empty + `"text"` also self-hides; strip ANSI before packing the tooltip; use + signal 10 + `format = "{}"`. theme-shot asserts class:bad + glyph and + pokes RTMIN+10 before the desktop shot. - **tuigreet dies silently under runNixOSTest** (even bare, no theme flag: greetd sits as "(greetd)" with no child, nothing in the journal — its stderr goes to the VT) — nixpkgs' own greetd test uses diff --git a/modules/home/waybar.nix b/modules/home/waybar.nix index bbd68ef..f667834 100644 --- a/modules/home/waybar.nix +++ b/modules/home/waybar.nix @@ -115,12 +115,19 @@ let # exits 0, so the module only appears when the sheet has a ✖ (the # same self-hide discipline as vpn/nightlight/updates). The tooltip # carries the first failing lines; click opens the full sheet. + # Absolute path to the doctor binary: waybar's custom-module env can + # miss system PATH, and `command -v … || exit 0` then self-hides forever. doctorStatus = pkgs.writeShellScriptBin "nomarchy-doctor-status" '' - command -v nomarchy-doctor >/dev/null 2>&1 || exit 0 - out=$(nomarchy-doctor 2>/dev/null) && exit 0 - tip=$(printf '%s\n' "$out" | grep '✖' | head -5 \ + out=$(${pkgs.nomarchy-doctor}/bin/nomarchy-doctor 2>/dev/null) && exit 0 + # Strip ANSI so the tooltip is plain text (and waybar never chokes on + # control chars); keep only the ✖ lines. + tip=$(printf '%s\n' "$out" \ + | ${pkgs.gnused}/bin/sed 's/\x1b\[[0-9;]*m//g' \ + | grep '✖' | head -5 \ | ${pkgs.jq}/bin/jq -Rs 'rtrimstr("\n") + "\n(click for the full sheet)"') - printf '{"text":"󰒡","tooltip":%s,"class":"bad"}\n' "$tip" + # 󰀨 (md-alert-circle): alert shape that survives incomplete Nerd Font + # cuts better than 󰒡; class:bad still paints it @bad. + printf '{"text":"󰀨","tooltip":%s,"class":"bad"}\n' "$tip" ''; # Per-theme override probe. @@ -247,7 +254,11 @@ let "custom/doctor" = { exec = "nomarchy-doctor-status"; return-type = "json"; + format = "{}"; interval = 300; + # signal 10: poke after a fix (or from theme-shot) so the tripwire + # doesn't wait a full interval after a first-poll miss. + signal = 10; on-click = "nomarchy-menu doctor"; }; diff --git a/themes/boreal/waybar.jsonc b/themes/boreal/waybar.jsonc index 4cc3195..6280ef1 100644 --- a/themes/boreal/waybar.jsonc +++ b/themes/boreal/waybar.jsonc @@ -70,7 +70,9 @@ }, "custom/doctor": { "return-type": "json", + "format": "{}", "interval": 300, + "signal": 10, "exec": "nomarchy-doctor-status", "on-click": "nomarchy-menu doctor" }, diff --git a/themes/executive-slate/waybar.jsonc b/themes/executive-slate/waybar.jsonc index f7acfe9..7f5f94d 100644 --- a/themes/executive-slate/waybar.jsonc +++ b/themes/executive-slate/waybar.jsonc @@ -141,7 +141,9 @@ }, "custom/doctor": { "return-type": "json", + "format": "{}", "interval": 300, + "signal": 10, "exec": "nomarchy-doctor-status", "on-click": "nomarchy-menu doctor" }, diff --git a/themes/summer-day/waybar.jsonc b/themes/summer-day/waybar.jsonc index 2b5fee6..b3695e2 100644 --- a/themes/summer-day/waybar.jsonc +++ b/themes/summer-day/waybar.jsonc @@ -99,7 +99,9 @@ "custom/doctor": { "return-type": "json", + "format": "{}", "interval": 300, + "signal": 10, "exec": "nomarchy-doctor-status", "on-click": "nomarchy-menu doctor" }, diff --git a/themes/summer-night/waybar.jsonc b/themes/summer-night/waybar.jsonc index 78c3b32..07a0791 100644 --- a/themes/summer-night/waybar.jsonc +++ b/themes/summer-night/waybar.jsonc @@ -98,7 +98,9 @@ "custom/doctor": { "return-type": "json", + "format": "{}", "interval": 300, + "signal": 10, "exec": "nomarchy-doctor-status", "on-click": "nomarchy-menu doctor" }, diff --git a/tools/theme-shot.nix b/tools/theme-shot.nix index c88372d..2127eac 100644 --- a/tools/theme-shot.nix +++ b/tools/theme-shot.nix @@ -1,6 +1,9 @@ # Themed-desktop capture harness (item 28 slice c) — boots the full # desktop headlessly (software-GL Hyprland) at 1920x1080 and QMP-dumps -# two screenshots into $out: desktop.png and menu.png (rofi root open). +# screenshots into $out: desktop.png, menu.png (rofi root open), and +# btop.png (Ghostty running btop, when the terminal starts under softGL). +# Also asserts nomarchy-doctor-status JSON (class:bad) — the harness +# seeds an untracked theme-state.json, so doctor always reports ✖. # Maintainer tool, NOT a checks.* gate (a full-desktop VM is far too # heavy for CI). Impure: THEME env picks the theme slug. # THEME= nix build --impure -f tools/theme-shot.nix --no-link --print-out-paths @@ -66,6 +69,18 @@ pkgs.testers.runNixOSTest { # The session exec-once paints the wallpaper (softGL first paint at # 1920x1080 is slow) — give it a generous settle. machine.sleep(30) + # Doctor indicator contract: untracked theme-state → ✖ → status JSON + # with class:bad and the 󰒡 glyph (Waybar self-shows the module). + status = machine.succeed("su - nomarchy -c 'nomarchy-doctor-status'") + assert '"class":"bad"' in status, f"doctor-status not bad: {status!r}" + assert ("󰀨" in status or "󰒡" in status), f"doctor glyph missing: {status!r}" + # Baked btop theme must be present (asset or generated) for the slug. + machine.succeed("test -f /home/nomarchy/.config/btop/themes/nomarchy.theme") + machine.succeed("grep -q 'theme\\[main_bg\\]' /home/nomarchy/.config/btop/themes/nomarchy.theme") + # Poke custom/doctor (signal 10) so a first-poll miss at session start + # doesn't leave the tripwire blank for the full 300s interval. + machine.execute("su - nomarchy -c 'pkill -RTMIN+10 waybar' >/dev/null 2>&1 || true") + machine.sleep(3) # Park the cursor in the bottom-right corner so it doesn't sit in the # middle of the desktop shot (that frame doubles as the theme-picker # preview.png source). @@ -76,5 +91,15 @@ pkgs.testers.runNixOSTest { machine.execute(hy + " exec nomarchy-menu' >/dev/null 2>&1") machine.sleep(8) machine.screenshot("menu") + # Close menu, launch btop in Ghostty for the per-theme btop.theme shot. + # softGL may fail to start Ghostty — btop.png is best-effort then; the + # file assertions above still prove the theme is baked into the guest. + machine.execute("su - nomarchy -c 'pkill -x rofi' >/dev/null 2>&1 || true") + machine.sleep(1) + machine.execute( + hy + " exec ghostty --gtk-single-instance=false -e btop' >/dev/null 2>&1" + ) + machine.sleep(12) + machine.screenshot("btop") ''; }