diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index f270d5f..8e40bea 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -101,7 +101,7 @@ actually float once seen (regex tolerance for the `.…-wrapped` form). *Agents: append here with a one-paragraph pitch (what/why/cost). Do not implement. Bernardo moves accepted items into a tier.* - +### Pre-existing - **Battery charge-limit — make the toggle instant** `[blocked:hw]` (follow-up to the preset toggle shipped 2026-07-07, iteration #55). @@ -134,11 +134,388 @@ implement. Bernardo moves accepted items into a tier.* pairs with a hardware-queue session. Recommend (a) now, (b) investigated when the T14s is next available. +### Bugs / broken behavior (codebase exam 2026-07-09) +- **Installer: swap "none" still creates a 0G swap subvolume** + `nomarchy-install.sh` always passes `--argstr swapSize "${SWAP_GB}G"`. + When the user chooses 0 (no swap), disko gets `"0G"`, but + `disko-config.nix` only treats the exact string `"0"` as no-swap — + so it still creates `@swap` with size `0G`. Resume wiring correctly + skips (`SWAP_GB != "0"`), so layout and config disagree. Fix: pass + bare `"0"` (or teach disko to accept `"0G"`). Cheap pure check / + unit test for the swapSize contract would lock this. Cost: small + installer + disko-config change; high install-path impact. +- **Waybar doctor indicator never shows an icon** + `modules/home/waybar.nix` `nomarchy-doctor-status` prints + `"text":""` on failure. Waybar custom modules with empty `text` + self-hide, so the tripwire never becomes visible (tooltip-only if + it rendered at all). Intent in comments is opposite: appear only + when the sheet has a ✖. Fix: non-empty glyph (e.g. `󰒡` / `!`) + + `class: bad` when unhealthy; exit 0 / no output when healthy. + Cost: one-line script fix; V2 with existing `checks.doctor` if + extended, else V1. +- **neon-glass theme ships a broken Waybar whole-swap** + `themes/neon-glass/waybar.css` uses `@text` / `@base` / `@accent` / + etc. with **no** `@define-color` block. Whole-swap CSS replaces the + entire stylesheet with no palette prepend (`waybar.nix`), so + applying neon-glass yields undefined / broken bar colors (same + class as the purged stub CSS, JOURNAL #45). Also missing + `waybar.jsonc`, `preview.png`, `btop.theme`; CSS covers only a + subset of modules. Fix: either finish (self-contained colors + + layout parity + preview) **or** remove `waybar.css` until ready so + apply falls back to the generated bar. Cost: medium polish or + small quarantine delete; V2/V3 visual. +- **Control Center appearance toggles are no-ops without a rebuild** + `nomarchy-control-center.sh` `set_state` always uses `--no-switch`. + Blur / gaps (and similar appearance keys) only take effect after a + home switch, but the UI never runs one and never warns (unlike + Updates/Bluetooth which print "requires rebuild"). User flips look + identical until a later rebuild. Fix: run switch for appearance + keys, or refuse / warn clearly. Cost: small UX fix in one script. +- **Bluetooth menu row not self-gated** + System submenu always offers Bluetooth and `exec blueman-manager`. + If `nomarchy.system.bluetooth.enable = false`, blueman is not + installed → silent/broken launch. Printers / colorpicker / audio + gate correctly. Fix: gate on `command -v blueman-manager` (or the + settings flag). Cost: tiny; V0 + manual. + +- **summer-day workspace scroll dispatches differently from every other bar** + `themes/summer-day/waybar.jsonc` uses `workspace e+1` / `e-1` (next + **empty** workspace); summer-night, executive-slate, boreal use + `r+1` / `r-1` (relative). Likely leftover; behavior differs under + scroll. Fix: align to `r±1`. Cost: two lines. + +- **Battery charge-limit / powerprofile only match `BAT*` sysfs names** + `power.nix` oneshot and menu/waybar globs use + `/sys/class/power_supply/BAT*`. `nomarchy-battery-notify` correctly + treats any system battery (`type=Battery`, not `scope=Device`). + Machines with `CMB0` (and similar) get notify but not charge-cap / + inconsistent gating. Fix: name-agnostic scan aligned with + battery-notify. Cost: small multi-file; `[blocked:hw]` to confirm + on non-BAT* hardware. + +- **Unattended install silently disables LUKS if passphrase unset** + Interactive path defaults encrypt-on; unattended without + `NOMARCHY_LUKS_PASSPHRASE` installs **unencrypted** with only a log + line — no fail-closed. `test-install.sh` always sets a passphrase, + so the regression path is untested. Options: require the env var + when unattended, or an explicit `NOMARCHY_NO_LUKS=1`. Cost: small + policy change in install script + test matrix note. + +### Docs / option-surface drift (codebase exam 2026-07-09) + +- **`option-docs` would fail: undocumented `nomarchy.hardware.i2c.*`** + Live options `nomarchy.hardware.i2c.enable` and `.ddcci` in + `modules/nixos/hardware.nix`; distro default turns ddcci **on** + (`modules/nixos/default.nix` `mkDefault true`). No README table + rows, no template comments. Simulated `checks.option-docs` finds + exactly these two. Also: option default is false while module + default is true — document the effective default. Cost: docs + + optional template opt-in comments; would green option-docs. + +- **README / docs factual drift pack** (single docs pass or split): + (1) theme count still says **21** — repo has **24** presets + (`README.md`, `docs/TESTING.md`, `templates/downstream/README.md`); + (2) waybar whole-swap list still names catppuccin/lumon/nord/ + retro-82 — stubs purged; live CSS whole-swaps are summer-day, + summer-night, executive-slate, boreal, neon-glass; (3) idle table + still says "suspend **30**" — code is **15 min battery-only** + (`idle.nix`; ROADMAP already correct); (4) Tailscale row says + `sudo tailscale up` but module grants `--operator=` / template + says no sudo; (5) `hosts/live.nix` header still says "No installer + yet"; (6) CONVENTIONS parity list omits **boreal** (has full + waybar.jsonc). Cost: pure docs; high trust payoff. + +- **Keybind cheatsheet: Network still labeled nmtui** + `keybinds.nix` `desc = "Network (nmtui)"` but the module runs + `networkmanager_dmenu`. Cheatsheet inherits the wrong label. Cost: + one string. + +- **`nomarchy-menu` usage string incomplete** + Usage omits implemented modules (`doctor`, `controlcenter`, + `rollback`, …). Misleading for direct invocation / scripting. + Cost: one string in `rofi.nix`. + +- **Template / seed state drift** + (1) `templates/downstream/theme-state.json` lacks `border` and + `settings` keys present in repo root state (eval merges defaults — + not a break, but new installs ship a thinner shape); (2) no + commented `nomarchy.system.snapper.enable` or `hardware.i2c.*` in + `system.nix` despite opt-in convention; (3) installer-generated + `home.nix` is minimal (keyboard only) while `flake init` template + ships a fat default package suite — product divergence worth + documenting or aligning. Cost: small template/docs. + +- **Secondary docs polish** + README layout tree omits many real modules and pkgs + (doctor/control-center/battery-notify); `docs/MIGRATION.md` + unlinked from README nav and has a placeholder flake-init URL; + OVERRIDES.md example still pipes screenshots to **swappy** while + shipped annotator is **satty**. Cost: docs-only. + +### Theme polish / completeness (codebase exam 2026-07-09) + +- **Missing theme picker previews + hand btop for identity themes** + `boreal`, `executive-slate`, and `neon-glass` lack `preview.png` + (picker falls back to plain-name rows) and `btop.theme` (generated + btop only). CSS/jsonc for boreal/executive-slate are otherwise + solid. Capture previews after neon-glass is fixed/quarantined. + Cost: asset capture + optional hand btop; V3 visual. + +- **Generated Waybar missing identity-bar affordances** + Whole-swap bars ship `custom/powermenu` and a left logo → main menu; + the generated `waybar.nix` bar has neither. Optional parity add for + default-theme users. Cost: small waybar.nix + CSS; parity rule + says whole-swaps must get the same modules if added. + +- **summer-* CSS under-styles status module states** + summer-day/night include modules in selectors but largely lack + `.on` / `.available` / `.recording` polish that boreal, + executive-slate, and the generated style have. Functional OK; + visual hierarchy weak. Cost: CSS pass; V3. + +- **Optional CI: whole-swap CSS self-containment** + Contrast check does not require that a `waybar.css` defines every + `@color` it references, nor that every preset has preview + + backgrounds. A cheap gate would have caught neon-glass. Cost: + small tool + flake check. + +### Per-theme design audit (2026-07-09) + +*Method: `checks.theme-contrast` (all 24×7 pairings pass) + +`tools/audit-theme-design.py` + per-theme agent review of JSON roles, +ANSI, assets, whole-swaps, and fidelity to canonical sources. Gated +WCAG floors are green; items below are fidelity, hierarchy, btop +drift, identity semantics, and polish. Identity themes (white, +vantablack, lumon, hackerman, matte-black, miasma, neon-glass) are +flagged separately from fidelity bugs.* + +#### Broken / high-ROI fixes + +- **rose-pine btop is Main-on-Dawn (near-invisible hi_fg)** + JSON is **Rosé Pine Dawn** (`mode: light`, base `#faf4ed`, text + `#575279`) but `themes/rose-pine/btop.theme` mixes Dawn + `main_bg`/`main_fg` with **Main** accents: `hi_fg=#e0def4` on + `#faf4ed` ≈ invisible, `selected_bg=#524f67`, love `#eb6f92`, + foam/iris Main hexes. **Fix:** rewrite btop entirely to Dawn roles + (foam `#56949f`, iris `#907aa9`, love `#b4637a`, gold + `#ea9d34`/`#d68a16`, pine `#286983`). Also rename display name to + "Rosé Pine Dawn" (or ship a dark Main preset as a separate slug). + Cost: one btop rewrite + optional rename; V1 + visual V2. + +- **everforest + summer-night btop: inactive_fg == main_bg** + `themes/everforest/btop.theme` and `themes/summer-night/btop.theme` + set `inactive_fg` to `#2d353b` (= `main_bg`) → inactive/disabled + labels invisible. **Fix:** `inactive_fg` → grey1/muted range + (`#859289` / `#7a8478` / JSON muted). Cost: two lines; V1. + +- **vantablack role inversion breaks selection / muted** + `overlay` and `muted` are near-white `#fdfdfd` while base is + `#0d0d0d`. Generated consumers use `overlay` as selected_bg; + hand btop has `selected_bg=#fdfdfd` + `selected_fg=#ffffff` + (white-on-white) and `inactive_fg=#fdfdfd` (inactive rows scream). + Status greys are intentional monochrome identity. **Fix (keep void + identity):** `surface #1a1a1a`, `overlay #2a2a2a`, `muted #666666`; + btop `selected_bg #333` / `selected_fg #fff` / `inactive_fg` ≈ + muted. Cost: JSON + btop; re-run contrast; V1–V2. + +- **osaka-jade: warn≈good and text/subtext inverted** + `warn #459451` is green (same family as `good #549e6a`) → battery + warning reads as "ok". `subtext #F6F5DD` is brighter than `text + #C1C497` (secondary louder than primary). **Fix:** swap text↔subtext; + set `warn #E5C736` (from bright yellow ANSI, already in palette). + Keep jade accent + blossom accentAlt. Cost: small JSON retune; + contrast re-check; V1. + +- **catppuccin-latte: ANSI black/white axis inverted + mantle sludge** + Latte UI roles mostly match (base/text/accent/good/bad exact), but + `ansi[0]=#bcc0cc` (light) and `ansi[7]/[15]` are darkish → terminal + "black"/"white" slots misbehave; design-audit flags inverted slots. + `mantle #cbcdd0` is import-darken of light base (should be Latte + mantle `#e6e9ef`); `accentAlt #d260b5` is not Latte pink/mauve. + **Fix:** + ``` + mantle #e6e9ef; accentAlt #ea76cb (pink); + ansi[0] #5c5f77; ansi[7] #acb0be; ansi[8] #6c6f85; ansi[15] #bcc0cc + ``` + warn keep `#d6860a` if contrast requires, else `#df8e1d`. Cost: + JSON only; btop already Latte-correct. V0 contrast + V1. + +- **catppuccin (Mocha) btop is Frappé-on-Mocha** + JSON is exact Mocha; `btop.theme` uses Mocha `main_bg` but Frappé + fgs/boxes (`main_fg #c6d0f5`, `hi_fg #8caaee`, mauve/green/maroon + Frappé hexes). **Fix:** replace with official Mocha btop hexes + (`#cdd6f4`, `#89b4fa`, …). Optional: rename to "Catppuccin Mocha". + Cost: btop rewrite; V1. + +#### Whole-swap / identity themes + +- **neon-glass** — already queued above (broken waybar.css). JSON + palette itself is fine (high-chroma cyber). Finish or quarantine. + +- **summer-day / summer-night pair polish** + Structurally paired (inverted Everforest bar language) but: + (1) waybar CSS hexes drift from JSON (day warn/accentAlt; night + red/blue/yellow/purple vs JSON); bar follows legacy EF source, + Stylix/swaync follow JSON — dual sources of truth; + (2) night JSON collapses `subtext`=`muted`=`overlay` `#868d80` + (no secondary ladder for generated surfaces); + (3) day font 16px vs night 13px; day battery thresholds 30/15 vs + night 25/10; day missing `#custom-vpn` in pill selectors; + (4) day scroll `e±1` already queued. **Fix:** pick JSON as source + of truth and map waybar tokens to it (or document intentional EF + split); split night muted darker / subtext lighter; align font + + battery thresholds + VPN pill. Cost: CSS/JSON polish pass; V3. + +- **boreal / executive-slate** — whole-swaps self-define colors and + match JSON; best-in-class. Only gaps: `preview.png` + optional + `btop.theme` (already queued). + +- **white (monochrome light)** — identity-ok. Status good/warn/bad + are greys by design (audit hue/CVD noise expected). Optional: + widen L steps (`good #555`, `warn #777`, `bad #222`), raise + `surface #f0f0f0`, split `subtext #404040` while staying hueless. + Do not inject traffic-light hues. Cost: optional taste retune. + +- **lumon (Severance blue mono-status)** — identity-ok. good/warn/bad + all blue family by design; CVD collapse expected — rely on + glyph/shape (item 28). Optional: dim `subtext` one step + (`#9bb0c0`); increase L separation only among blues. Cost: + optional; document as identity exemption in audit tooling. + +- **hackerman** — matrix identity: warn cyan, bad green, ANSI reds + are greens. CVD collapse expected. **Keep identity** or optional + cyber-semantic UI only: `warn #e8d44f`, `bad #ff5a7a` while leaving + ANSI matrix. Raise `surface #1a1c2e` (flat base=surface). Cost: + product call + small JSON. + +- **matte-black** — identity: `good=#FFC107` amber, `warn=#b91c1c` + red (inverted traffic-light). Matches Omarchy matte-black. Minimal + fix: `subtext #9a9a9d` (text==subtext today). Full semantic remap + only if product wants conventional battery colors on this theme. + Cost: one-line hierarchy or deliberate status retune. + +- **miasma** — earthy `bad #685742` (brown, contrast ~2.3 audit-only) + is JOURNAL-exempt identity. Optional more readable brown-red + `#8b5a4a` / `#a65d4e` without leaving the forest. Cost: optional. + +#### Fidelity / hierarchy polish (popular ports) + +- **gruvbox is Material medium, not classic — name + btop split** + JSON hexes are Gruvbox **Material** (`text #d4be98`, material + green/yellow/red) while name says "Gruvbox" and `btop.theme` is + **classic** (`#ebdbb2`, `#d79921`, …). `surface`=`overlay`, + `text`=`subtext`. **Fix:** rename to "Gruvbox Material" **or** + retune JSON to classic; sync btop to the chosen lineage; + `overlay #504945`, `subtext #a89984`. Cost: naming + assets. + +- **nord** — clean Polar Night. Only nit: `subtext #e5e9f0` is + **brighter** than `text #d8dee9` (hierarchy inverted). **Fix:** + subtext → nord4-dim or bump text to nord6 `#eceff4`. Cost: one hex. + +- **tokyo-night** — Night (not Storm), JSON solid. btop + `main_fg`/`title` use warm `#cfc9c2` instead of Night + `#c0caf5`/`#a9b1d6`. Optional: `text #c0caf5`, `accentAlt + #bb9af7` (modern purple). Cost: btop + optional JSON. + +- **kanagawa** — Wave, clean. No action required; optional rename + "Kanagawa Wave"; optional brighter good `springGreen #98bb6c`. + +- **ethereal** — vibe solid; `surface`=`base`, `muted`=`overlay`. + **Fix:** `surface #1a2340` (or Omarchy color0 `#3C486D`); split + muted darker than overlay; optional richer good. Cost: small JSON. + +- **retro-82** — strong synthwave + excellent rofi whole-swap. + `surface #00172e` darker than `base #05182e` (inverted raise); + `good #028391` teal (reads info not ok). **Fix:** `surface + #0a2844`; optional `good #3f8f8a` or phosphor green. Cost: small + JSON; keep rofi. + +- **ristretto** — Monokai Pro Ristretto, ship-quality. Only + `subtext`=`text`; btop `main_bg` 1-step drift (`#2c2421` vs + `#2c2525`). **Fix:** `subtext #b5a9aa`; align btop bg. Cost: tiny. + +- **flexoki-light** — best of the Flexoki/import set post item-28. + Optional: distinct ANSI bright-black `#575653`; recapture preview + if terminal chrome still looks dark-on-paper. Cost: polish only. + +#### Systemic theme tooling + +- **Import pipeline collapses hierarchy when ANSI 0==8** + `tools/import-palettes.py` maps `surface←color0`, `overlay←color8`, + `good/warn/bad←color2/3/1`, `mantle←darken(base)`. When color0==8 + (gruvbox, everforest) surface=overlay; light themes get sludge + mantle. Long-term: allow explicit role overrides independent of + ANSI for identity themes; don't re-import without a hierarchy pass. + Cost: tool + convention doc. + +- **audit-theme-design identity exemptions** + Document expected noise for white/vantablack/lumon/hackerman/ + matte-black/miasma (hue-family + CVD) so future audits don't + "fix" identity into traffic lights. Optional: special-case in + the report script. Cost: docs or small script tweak. + +### Tooling / CI / installer hardening (codebase exam 2026-07-09) + +- **CI `py_compile` only covers theme-sync** + `.gitea/workflows/check.yml` compiles only + `pkgs/nomarchy-theme-sync/nomarchy-theme-sync.py`. Misses + `compose-lock.py`, `tools/*.py`, `tools/vm/*.py` — syntax errors + can ship. Expand to all tracked `*.py` (or at least installer + + tools). Cost: one workflow line; TESTING.md §1 should match. + +- **No automated check for installer pure contracts** + `compose-lock.py`, disko `swapSize`/`withLuks` arg contract, and + hardware-db module names vs `nixos-hardware.nixosModules` have no + `checks.*`. Lock bumps of nixos-hardware can rename modules and + break profiled installs only on matching hardware. Cost: medium + one-time check scaffolding; high long-term install safety. + +- **Installer soft gaps** + (1) fingerprint path prefers `lsusb` but package PATH has + `pciutils` not `usbutils` (sysfs fallback usually OK); (2) + `chown -R 1000:100` on the flake dir assumes first-user UID/GID; + (3) flake `packages` exports only theme-sync + install, not + doctor / control-center / battery-notify (runtime via overlay is + fine — discoverability only). Cost: small each. + +- **Control Center `/tmp/nomarchy-gens` for rollback list** + Predictable world-writable path for generation listing — multi-user + race / trash. Prefer `mktemp`. Cost: tiny. + +### Distro improvement ideas (codebase exam 2026-07-09) + +- **Fail-closed / friendlier theme-state errors in `mkFlake`** + Missing `theme-state.json` fails later at `readFile`; invalid JSON + fails at `fromJSON` before theme.nix's field-level validator. A + friendly "add theme-state.json" / schema pointer would help + downstream authors. Related: `settings.displayProfile*` not in + defaults block (consumers use `or`); unknown border role falls + through to raw string. Cost: medium lib/theme.nix UX. + +- **Look & Feel submenu (ROADMAP optional)** + Night-light, wallpaper cycle, blur/gaps (once CC appearance is + fixed) grouped with Theme once the root stays six entries. Cost: + menu structure only; product call. + +- **Export all overlay tools as flake packages** + `nix build .#nomarchy-doctor` etc. for maintainers and CI + convenience without going through modules. Cost: three lines in + flake.nix. + +- **Unattended-install test matrix** + `test-install.sh` always LUKS+swap; add (or document) no-swap and + no-LUKS paths once those contracts are fixed, so swap/LUKS-class + bugs cannot recur. Cost: script flags + time on KVM host. + +- **Document always-on home pieces** + easyeffects, udiskie, cliphist always on with no toggle (by + design) — optional README note so users know what ships and how to + override. Cost: docs only. ## Decisions `[human]`