docs(agent): file #137–#141 from the T14s round (three root-caused live)
All checks were successful
Check / eval (push) Successful in 4m12s

Bernardo's 2026-07-16 observations, filed with the diagnosis done on the
machine rather than as symptoms:

- #137 plymouth: unindexed Window.Get* → whole splash placed on head 0's
  geometry; off-centre on any second monitor (LUKS prompt included).
- #138 [human] Meet claims no mic/speakers: audio graph + Flatpak sandbox
  ruled out live; needs the browser named and the failure in front of us.
- #139 terminal floats full-screen: % size rules silently no-op on
  Hyprland 0.55.4 (absolute px applies), and Kitty replays its remembered
  window size — the second half is the Ghostty regression from #95.
- #141 waybar updates click dead: whole-swaps use $TERMINAL, which is
  absent from Waybar's env; 4 jsonc lines, a parity break not a bug.
- #140 PROPOSED: Ask Claude → web chat instead of the claude-code REPL.

Also gives #127 its "if diagnosis fails" branch: a screensaver while
docked, which is the panel-protection consolation prize, not a new item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 09:23:10 +01:00
parent 64f7379982
commit a40f99e417

View File

@@ -80,6 +80,15 @@ stays lit under hyprlock (journal: `dpms-off skipped: docked`); undocked
still blanks at 10 min and wakes on input. Full original pass (wake after still blanks at 10 min and wakes on input. Full original pass (wake after
DPMS-while-docked) deferred to the LATER revisit. DPMS-while-docked) deferred to the LATER revisit.
**Fallback if the cause resists (Bernardo 2026-07-16):** diagnosing stays the
preference — DPMS when docked is the outcome we want. But the mitigation as
shipped holds a near-static lock screen on the externals indefinitely, so if
the cause cannot be pinned down, a **screensaver while docked** is the
consolation prize: it protects the panels (burn-in — the same cost #135
names) without re-entering the blanking path that bricked the session. Not a
new item: it is the "if diagnosis fails" branch of this one, and #135's state
key is where it would land.
## NEXT ## NEXT
### 135. Give the #127 DPMS mitigation a state key (and a way back) ### 135. Give the #127 DPMS mitigation a state key (and a way back)
@@ -181,6 +190,111 @@ migration (state.json created + git-staged, legacy `git rm`'d). Proven by
hand 2026-07-15 (drvPaths identical across the rename) — this just keeps it hand 2026-07-15 (drvPaths identical across the rename) — this just keeps it
proven. Delete together with the shim + the `nomarchy-theme-sync` alias. proven. Delete together with the shim + the `nomarchy-theme-sync` alias.
### 137. Plymouth splash draws on head 0's geometry, so it is off-centre when docked
Bernardo 2026-07-16 (T14s, docked): the boot **and** shutdown logo is not
centred on the external monitor. Cause is in the theme script, not the
hardware: `modules/nixos/plymouth/nomarchy.script` calls `Window.GetWidth()`
/ `Window.GetHeight()` with **no head index**, which returns head 0, while
sprite coordinates live in a device-wide space spanning every head. So every
element is placed at "head 0's centre" measured from the union origin — right
on a single monitor, wrong the moment a second one exists, and wrong in a
different direction depending on which head is 0 and how they are arranged.
It is the whole splash, not just the logo: the same unindexed call places the
logo (`:9`, `:1516` — note the 15%-of-height *scale* also tracks the wrong
head), the password entry (`:129`), the lock, the bullets, and the progress
box/bar (`:210`, `:219`). Fix shape is the standard Plymouth one: loop
`Window.GetX(i)` / `GetY(i)` / `GetWidth(i)` / `GetHeight(i)` over the heads
and give each its own sprite set, so each monitor gets a centred, correctly
scaled splash — the LUKS prompt especially, since a passphrase box half off
the panel is the failure that matters. Pass = docked boot + shutdown centred
on both heads; undocked unchanged.
### 138. `[human]` Google Meet reports no mic or speakers; Zoom is fine
Bernardo 2026-07-16 (T14s, docked): Meet insists there is no microphone or
speaker even with the browser permission granted; Zoom calls work. What I
could rule out from the live session, so the fix pass does not re-tread it:
- The audio graph is healthy — PipeWire 1.6.5 with 4 sinks and 5 sources
(`wpctl status`), and a live `Chromium input` client was already attached.
- Not a Flatpak sandbox: Chromium is the **native** nixpkgs build from the
template's `home.packages`. (Zoom, the app that works, is the Flatpak.
Brave — also Flatpak — holds `pulseaudio` + `xdg-run/pipewire-0` +
`devices=all`, so it would not fail this way either.)
- One oddity worth checking first: the default source is **`OBSBOT Meet SE
Digital Stereo (IEC958)`** — an S/PDIF *passthrough* profile on the webcam,
a strange default for a mic. A device that enumerates but cannot open is a
plausible route to Meet's "no devices" wording.
`[human]` because it needs the failure in front of us: **which browser** were
you in (native Chromium, or the Brave Flatpak?), and with it open on Meet,
`chrome://media-internals` plus the device list under `chrome://settings/content/microphone`
would separate "Chromium enumerates nothing" from "Meet rejects what it is
offered". Until then there is no way to tell a Nomarchy defect from a
device-profile accident, and guessing costs more than asking.
### 139. Terminal floats open full-screen — % size rules are ignored, and Kitty remembers
Bernardo 2026-07-16: calcurse and nomarchy-doctor float but fill the screen —
the reduced size we had under Ghostty is gone. Reproduced and root-caused live
on the T14s (Hyprland 0.55.4, single 2560×1440 head), and it is **two** faults
stacked, which is why it looks like the float rules are dead when they are not:
1. **Percentage sizes silently no-op.** `com.nomarchy.calendar` came up
`floating=true` but `size=[2526,1360]` — the full work area, not the
`size 60% 65%` in `modules/home/hyprland.nix:1064`. A runtime rule with
**absolute** pixels (`size 1400 900`) applied perfectly and even centred
itself, so `size` works and the matcher works: it is the `%` form that this
Hyprland drops. No `hyprctl configerrors` — it fails silently, which is
how it survived the rule-syntax rewrite.
2. **Kitty remembers its last window size.** With the rule not applying,
nothing overrides Kitty's own request, and Kitty defaults to
`remember_window_size yes` — `~/.cache/kitty/main.json` literally holds
`{"window-size": [...]}` and is replayed into every new OS window. So the
float inherits whatever the last Kitty was, which after any tiled window is
~full-screen. **This is the Ghostty regression** (#95, Kitty-only): Ghostty
kept no such memory, so fault 1 was invisible — fault 2 exposed it.
Both need fixing, and fixing either alone is a trap: absolute pixels alone
stop being right on the 1366-wide Acer (#131's machine) or any scaled head,
and pinning Kitty alone leaves the `%` rules rotting for the next window we
float. Likely shape: `-o remember_window_size=no` (plus
`initial_window_width/height`) in the `nomarchy-calendar` / doctor launchers
so Kitty stops fighting us, and either the working syntax for `%` or a
documented note that this Hyprland wants absolute px. Affects every rule using
`%` — today calendar (`:1064`) and doctor (`:1070`). Pass = both sheets open
centred at their intended fraction on the dev box **and** on the Acer.
_(My probes wrote `{"window-size": [1400, 900]}` into your Kitty cache — it is
a self-updating cache, harmless, and any resize overwrites it.)_
### 141. Waybar's update module is dead in the whole-swap themes (`$TERMINAL` is unset)
Bernardo 2026-07-16: clicking the Waybar updates module does nothing.
Confirmed live and it is a **Waybar parity break** (CONVENTIONS § whole-swaps),
not an updates bug. The generated module bakes the terminal in —
`"${config.nomarchy.terminal} -e nomarchy-updates upgrade"`
(`modules/home/waybar.nix:356`) — but the four whole-swap themes hand-write
`"sh -c '$TERMINAL -e nomarchy-updates upgrade'"`, and **Waybar's environment
has no `TERMINAL`**: its 55 vars contain zero matches (pid 1688, `/proc/*/environ`).
`TERMINAL` is a `home.sessionVariables` entry (`modules/home/default.nix:104`),
so login shells get it and the Hyprland-spawned bar does not. The click expands
to `sh -c ' -e nomarchy-updates upgrade'` → nothing, no error, no toast. You
are on **boreal**, a whole-swap, which is why you see it.
Affected, one line each: `themes/{boreal,summer-day,summer-night,executive-slate}/waybar.jsonc`
(`custom/updates.on-click` — grep says this is the *only* `$TERMINAL` use left
in any whole-swap, so the blast radius is exactly these 4 lines). Fix = drop
the env dependency the way calendar/doctor already do — name `kitty` outright,
Kitty being sole supported since #95 — or, better and one place instead of
five, give `nomarchy-updates` a subcommand that opens its own terminal so
every caller stops needing `$TERMINAL`. Worth a check against the class of
bug, not the instance: nothing today asserts that a whole-swap's on-click
survives Waybar's actual environment, so the next hand-written jsonc can
reintroduce it silently.
### 120. A netinstall ISO, next to the fat offline one ### 120. A netinstall ISO, next to the fat offline one
Bernardo 2026-07-14, after seeing the measured size: **keep the current ISO Bernardo 2026-07-14, after seeing the measured size: **keep the current ISO
@@ -297,6 +411,36 @@ high-ROI, etc.) live in the journal + ROADMAP — not here.*
### Product / day-2 ### Product / day-2
### 140. Ask Claude should hand off to a web chat, not open a coding agent
Bernardo 2026-07-16: "opening claude-code is too disruptive" — he would prefer
the query go to a **web interface** (Gemini or Claude) instead. Today
SUPER+CTRL+A → `nomarchy-menu ask` (`modules/home/rofi.nix:899905`) takes the
free-text line and does `${cfg.terminal} -e npx --yes @anthropic-ai/claude-code@latest "$q"`:
a terminal window, an npm fetch on first run, and a REPL that stays open — a
coding agent answering "what's the syntax for…". The prompt surface is right;
the destination is wrong for the question the surface invites.
Cheap version: URL-encode `$q` and `xdg-open` a prefill URL
(`https://claude.ai/new?q=…`, `https://gemini.google.com/app?q=…`), landing in
the default browser (Chromium, per Decisions). That is a handful of lines and
deletes the `npx`/network/REPL cost — plus `pkgs.nodejs`, carried in
`home.packages` (`:1685`) **only** for this feature, so the closure shrinks
with it. To settle before building:
- **Which destination, and is it a choice?** Bernardo named Claude *or*
Gemini. A `settings.ask.provider` key keeps it in-flake and menu-writable
(the convention) and stops us hardcoding a vendor into a vendor-neutral
distro; a fixed default is cheaper. Prefill-URL support is per-vendor and
can be changed by them unilaterally — worth verifying each still prefills,
since a silently-ignored `?q=` degrades to "opens a blank chat", which is
survivable but should be a known cost, not a surprise.
- **Keep the CLI at all?** A second row (Ask ▸ web / Ask ▸ agent) preserves
today's behaviour for whoever wants it; deleting it is the simpler surface
and the one the complaint argues for. Bernardo's call.
- Renaming: "Ask Claude" is the keybind desc (`keybinds.nix:57`) and shows in
the generated cheatsheet — if the destination becomes configurable, the
label should stop naming one vendor.
### 134. `unstable.<pkg>` in the downstream — a newer app without a second flake ### 134. `unstable.<pkg>` in the downstream — a newer app without a second flake
Bernardo 2026-07-15, wanting a newer LM Studio (pinned 0.4.15-2 vs unstable Bernardo 2026-07-15, wanting a newer LM Studio (pinned 0.4.15-2 vs unstable