Files
Nomarchy/agent/JOURNAL.md
Bernardo Magri 2a34c7398b
All checks were successful
Check / eval (push) Successful in 3m19s
fix(docking): make workspace and lid transitions atomic
Restore the old flake's external-only workspace handoff, protect closed-lid cable removal with a verified low-level logind inhibitor, and use monitor-added as the settled audio reprobe boundary.

Verified: V2 — nix flake check --no-build; docking-ux, option-docs, and template-sot checks; KVM tools/monitor-fallback.nix lifecycle test.

V3 pending: closed-lid BenQ round 4 in agent/HARDWARE-QUEUE.md.
2026-07-13 13:56:54 +01:00

664 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Journal — append-only iteration log
One entry per iteration, **newest first**. This is the loop's short-term
memory: the next session reads the last 35 entries to orient. Keep an
entry under ~15 lines; durable lessons go to MEMORY.md, not here. When
this file grows past ~25 entries, rotate the tail to
[JOURNAL-ARCHIVE.md](JOURNAL-ARCHIVE.md) (history, never edited).
Template:
```markdown
## YYYY-MM-DD — <task title> (<commit sha, or "no commit">)
- **Task:** which BACKLOG item (or QA sweep / bootstrap / escalation)
- **Did:** what changed, in 24 lines
- **Verified:** tier reached (V0/V1/V2) + the actual commands/checks run
- **Pending:** V3 queued? follow-ups filed? anything [stuck]?
- **Next suggestion:** what the following iteration should probably take
```
---
## 2026-07-13 — #100 dock transition recovery (this commit)
- **Task:** Fix the real T14s dangling workspace, closed-lid cable-removal
suspend/apparent crash, and BenQ audio miss after 7ebfab4.
- **Did:** Added one atomic dock/internal-first undock helper; the IPC watcher
owns a verified low-level lid inhibitor through physical lid-open, with
validated stale-process cleanup. `monitoradded` now debounces a settled
PipeWire/WirePlumber reprobe then picks an available dock sink; generic
audio events never override a manual choice. Named clamshell profiles share
the safe transition. Replaced the fallback VM tool with a bounded hotplug
workspace/output/inhibitor test and strengthened generated-artifact guards.
- **Verified:** V2 — `nix flake check --no-build`; targeted docking-UX,
option-docs, and template-SoT builds; and
`nix build --impure -f tools/monitor-fallback.nix --no-link -L` all green.
The KVM guest proved atomic workspace handoff, internal-first restoration,
inhibitor retention with the simulated lid closed, and release on lid-open.
The harness restores the DRM output before deleting QEMU's last synthetic
headless output because that backend-specific zero-output state aborts
Hyprland before a usable removal lifecycle is delivered.
- **Pending:** V3 exact closed-lid BenQ round 4 in HARDWARE-QUEUE. No
real-hardware or real monitor-audio claim.
- **Next suggestion:** run V3 round 4, then take installer #91.
## 2026-07-13 — Live ISO hardware findings queued (#91#99)
- **Task:** Transcribe Bernardo's Acer Aspire M5-481T install/session notes
and installer failure photo into the executable queue.
- **Did:** Added nine separate NOW items: literal `(none)` XKB install
failure, keyboard/swap installer clarity, missing browser, Ghostty launch,
charge-threshold discoverability, BlueZ failure, Boreal button contrast,
and the false-looking untracked-theme warning.
- **Verified:** V0 — exact backlog IDs/content reviewed; Nix failure's first
causal error preserved separately from cascading dependency failures;
`git diff --check` green.
- **Pending:** implementation and item-specific V1V3 verification.
- **Next suggestion:** #91 — fix the installation-blocking keyboard variant.
## 2026-07-13 — Docking hardware-QA corrections (interactive feedback)
- **Task:** Bernardo's real clamshell QA: menu on hidden eDP, no keyboard
layout route, audio stayed on speakers, laptop-off lost apps, abrupt
undock never restored eDP.
- **Did:** Rofi → focused output; replaced eDP disable with safe Dock mode
(move workspaces/focus, keep fallback); display watcher now unconditional,
reconnecting and race-tolerant. Keyboard watcher runs by default with all
XKB layouts + System Keyboard. Audio also reacts to card/port changes;
monitor-added re-applies the current awww wallpaper to the new output.
Corrected the fallback harness assumption; added `checks.docking-ux` and
synced README/template/ROADMAP/hardware queue.
- **Verified:** V1 — `nix flake check --no-build`; `checks.docking-ux`
built the real HM generation and passed syntax/invariant/layout-catalog
assertions; option docs 90/90, template SoT 4/4; Nix parse + Python
compile + diff check. V2 unavailable (no readable KVM).
- **Pending:** hardware retest in HARDWARE-QUEUE (docking correction round 3).
- **Next suggestion:** hardware retest this exact dock sequence.
## 2026-07-12 — #89 slice 3: Documented Signal tray icon limitation (no commit)
- **Task:** BACKLOG #89 slice 3 — Signal's tray icon is full-colour blue and doesn't match the monochrome bar.
- **Did:** Researched Signal's Linux tray icon behavior. Found it is a hardcoded, dynamically generated pixmap (`Signal_status_icon_1`) driven by its Electron wrapper with no built-in toggle for a monochrome icon. Added an entry to `docs/ROADMAP.md`'s known issues noting that certain Electron apps cannot be natively themed. Closed out #89 from the backlog without introducing brittle `app.asar` repacking hacks.
- **Verified:** N/A (Documentation only).
- **Pending:** #89 is fully closed.
- **Next suggestion:** Pick the next item from the BACKLOG.
## 2026-07-12 — CI OOM: memory-bounded eval for check.yml/bump.yml
- **Task:** Bernardo: check.yml always red since he capped the runner
container at 2 GB (uncapped it OOM'd the whole 4 GB VPS); bump.yml
status unknown.
- **Did:** Measured (GNU time, eval-cache off): one-process `nix flake
check --no-build` peaks **6.0 GB** RSS — that's the whole story. New
`tools/ci-eval.sh`: same coverage, ONE output per nix process (heap
freed between outputs); both workflows now call it. bump.yml also got
max-jobs=1/cores=2. Facts: bump.yml WORKS — landed 8fded63 on
2026-07-06, on schedule; ROADMAP's "no CI today" was stale → fixed.
- **Verified:** V1+ — ci-eval.sh ran green locally end-to-end (3:22);
per-output cold peaks measured: worst check 0.99 GB
(hardware-toggles), nomarchy toplevel 0.78 GB, HM 0.60 GB, **except
nomarchy-live 2.69 GB** (live ISO eval) — fits only with the
container's swap allowance (docker default --memory-swap = 2×memory);
if Bernardo set swap off, that one output still OOMs → server-side
one-liner (--memory=2g --memory-swap=6g) or a skip-hatch decision.
- **Pending:** real proof is the next push's Actions run on the VPS —
watch nomarchy-live's step; can't be verified from this machine.
- **Next suggestion:** confirm green run on the remote, then hardware
V3 batch.
## 2026-07-12 — parallel fingerprint-or-password (interactive, promoted)
- **Task:** Bernardo promoted the PROPOSED "fingerprint or password in
parallel" item live; wants it default-on for fingerprint-PAM users.
- **Did:** Packaged pam-fprint-grosshack v0.3.0 (pkgs/, source-reviewed
first: all failure paths → PAM_AUTHINFO_UNAVAIL, typed password only
ferried via AUTHTOK to pam_unix try_first_pass — can't lock out
password login). New `nomarchy.hardware.fingerprint.parallel`
(default true; false = stock sequential). Wiring swaps stock fprintd's
rule modulePath (mkForce) so ordering is inherited. README/template
rows; BACKLOG PROPOSED entry closed into ROADMAP ✓.
- **Verified:** V2 — checks.hardware-toggles extended to three nodes and
green: parallel node asserts grosshack line before pam_unix in
/etc/pam.d/sudo AND `sudo -S` with the right password succeeds /
wrong password fails with NO reader present (the lockout invariant);
seqpam node = stock pam_fprintd, no grosshack; nopam = neither.
Package builds (meson needed libpam-wrapper + python3). flake check
green.
- **Pending:** V3 on the AMD dev box (HARDWARE-QUEUE): the actual
type-or-touch race, fprintd-stopped fallback, hyprlock/greeter
behavior after a fingerprint win (pthread_cancel'd prompt quirk).
- **Next suggestion:** dock + fingerprint V3 batch on hardware, then
#89 slice 3.
## 2026-07-12 — undock blackout rescue (interactive follow-up)
- **Task:** Bernardo: "if I turn the laptop screen off and undock, does
the panel come back?" Answer had to be tested, not recalled.
- **Did:** Built tools/monitor-fallback.nix (softGL desktop VM, crib of
theme-shot): headless "external" + menu's exact disable + output
remove. Verdict: Hyprland 0.55.4 does NOT re-enable → shipped
`rescue_blackout` in the display hotplug watcher (immediate + retried
keyword re-enable of disabled outputs on zero-active, toast).
- **Verified:** V2 for the hazard (VM reproduced the dead state);
rescue itself is V1+components — the VM crashes before rescue can act
in 4/5 runs (aquamarine ABRT in dispatchIdle on the zero-output
state; control with panel active survives 5/5 — discriminator run).
Crash predates rescue (run with rescue provably inert also crashed).
Also fixed: `grep -c .` exit-1-at-zero disabling the rescue's own
trigger. flake check green.
- **Pending:** real-dock V3 (HARDWARE-QUEUE, "nothing important open"
warning); if real DRM crashes too → rework row (mirror) or wait for
Hyprland bump; consider reporting upstream with the coredump.
- **Next suggestion:** dock V3 results, then #89 slice 3.
## 2026-07-12 — dock audio auto-follow + docked menu rows (interactive)
- **Task:** Bernardo's dock test (= #87's V3): audio stayed on speakers,
had to hand-tweak EasyEffects; wants docked Display/Audio menu options.
- **Did:** Root-caused live on Newton: WirePlumber's stored default
(default-nodes) outranks the #87 priority rules (control test: new
sink, no watcher → default pinned), and the running gen lacked the
rules anyway; EE 8 follows the default fine (kcfg default true +
observed links move). Shipped `modules/home/dock-audio.nix`
(`nomarchy.dockAudio.enable`, on): pactl-subscribe watcher
set-default-sinks new dock-class sinks (regexes imported from
dock-audio-rules.nix) + toast + startup sweep. Menu: Display gains
laptop-off/screen-on/move-workspace/swap rows (live-only keywords);
Audio gains self-gated "Send output → <dock sink>" row.
- **Verified:** V2-equivalent live on Newton — watcher: fake dock-named
null sink → default followed, unplug → fell back, EE links moved
mid-playback (pw-link); menu: generated script bash -n, dock-row jq
exercised against real pactl JSON, dispatchers probed on live
Hyprland. flake check green; option-docs green. Beware: kill the
subscribe pipe by PID — pkill -f self-matches the test shell.
- **Pending:** real-dock V3 ×2 in HARDWARE-QUEUE (watcher may miss
sinks that pre-exist and only flip route availability — capture pactl
subscribe + sink JSON if it fails again).
- **Next suggestion:** #89 slice 3 (Signal pixmap) or dock V3 feedback.
## 2026-07-12 — auto-commit sweep before pull/rebuild/home (interactive)
- **Task:** Bernardo's request (no BACKLOG item): with autoCommit on,
hand edits to `~/.nomarchy` (his had 4) stayed forever-dirty —
theme-sync's commit is pathspec-limited to theme-state.json by design.
- **Did:** New internal `nomarchy-autocommit` in nomarchy-lifecycle:
live-reads `settings.autoCommit`, commits *everything* dirty with
message `nomarchy: auto-commit before <label>` + file list in the
body; called (`|| true`, never blocks) at the top of nomarchy-pull /
-rebuild / -home. Exposed as `passthru.autocommit`; package exported.
Docs/comments swept: README, RECOVERY, ROADMAP ✓ entry, rofi toggle
text, control-center prompt, theme-sync docstring.
- **Verified:** V1+ — `nix flake check --no-build` green; new permanent
`checks.lifecycle-autocommit` builds (real binary, sandbox repos:
sweep/clean/off/non-repo); end-to-end on a *copy* of the real
~/.nomarchy via built nomarchy-rebuild with stubbed sudo/rebuild —
the 4 real dirty files landed in one commit, tree clean. No VM boot:
no session-visible surface. Real-machine confirmation lands after the
next nomarchy-pull picks up this rev.
- **Pending:** nothing queued; Bernardo's actual ~/.nomarchy still has
its 4 uncommitted files until his next pull/rebuild with the new rev.
- **Next suggestion:** back to BACKLOG (#89 slice 3, Signal pixmap).
## 2026-07-12 — #89 slice 2: EasyEffects tray icon themed monochrome (b98248f)
- **Task:** BACKLOG #89 slice 2 — EasyEffects SNI shows Papirus' full-
colour blue equaliser, clashing with the monochrome tray.
- **Did:** Wrapped the resolved icon set in a `Nomarchy-icons` child
theme (theme.nix) that Inherits it + ships a scalable, palette-`text`-
coloured monochrome easyeffects glyph (the app's own -symbolic shape);
made it the session icon theme. Single shared layer, so it covers all
themes (all resolve to Papirus-*); colour tracks each theme via
`checked.colors.text`. iconTheme feeds stylix+rofi, both fine via
Inherits. Fixed a slip: `git add -A` swept a settings.local.json.tmp.*
into the commit → untracked + gitignored (f9d5e2c).
- **Verified:** **V3 in Boreal** (Bernardo confirmed live). Mechanism
pre-validated by GTK IconTheme lookup (override wins 1632px; udiskie/
nm/folder still Papirus). No theme uses a custom icon pack, so Boreal+
Papirus covers the set. NB: cursor-warp doesn't refresh the tray —
needs a waybar restart (new icon-theme cache).
- **Pending:** slice 3 — Signal (`:1.227`, generated pixmap, full-colour
blue round icon); pixmap apps can't be fixed by name override.
- **Next suggestion:** #89 slice 3 (Signal) or close #89 if pixmap apps
are accepted as documented-not-fixable.
## 2026-07-12 — tray menus truly fixed: counter-rules must live in waybar.css (8eb672b, 72e53e2)
- **Task:** Bernardo: icons still missing in the REAL nm-applet menu.
- **Did:** e8658fe's gtk.css cure worked in a plain GTK app but not in
Waybar: Waybar adds its provider at GTK_STYLE_PROVIDER_PRIORITY_USER
too (src/client.cpp) and wins the tie in practice (GTK 3.24) — proven
by repro at priority 900 matching the live menu exactly. Only rules in
the SAME stylesheet out-specify its `*`, so every waybar.css now
carries a menu block after the reset: arrow 16px, check/radio 14px,
separator 1px, `menu, menu *` font (labels are matched directly by
`*`, inheritance never applies). D-Bus GetLayout first proved
nm-applet exports per-network icon-data.
- **Verified:** **V3 on the real menu** — opened nm-applet's tray menu
via wlrctl virtual-pointer clicks, grim captures: arrows, checkmarks,
separators, Inter labels, Pica's icon, and every network's signal icon
in the Available-networks submenu. Bar pills intact. NB: cursor-warp
hover does not open GTK submenus (no motion events) — click the item.
- **Pending:** nothing for this item.
- **Next suggestion:** #89 slice 2 — the override-icon layer.
## 2026-07-12 — #90 correction: scoping regressed the bar; USER-priority cure (e8658fe)
- **Task:** Bernardo reports ac7e6bd broke Boreal's bar + icons still missing.
- **Did:** Two lessons. (1) `window#waybar *` carries id specificity, so
the reset started *beating* the later class rules (pill radius/borders)
that plain `*` correctly lost to — reverted all three stylesheets;
arrows restored instead via stylix gtk.css (`menu menuitem arrow
{ min-width/height:16px }`) — USER priority (800) outranks waybar's
APPLICATION (600) regardless of specificity, same mechanism as the
existing check/radio rule. NB comments guard each `*` block.
(2) The "missing icons" were also GTK3's `gtk-menu-images` default-off:
set `gtk.gtk3.extraConfig.gtk-menu-images = 1`.
- **Verified:** **V3** — repro (no forced always-show-image): icon, check
and arrow all render even with Boreal's reset injected screen-wide;
bar screenshot shows pills restored. Flake check green.
- **Pending:** Bernardo eyeballs the real nm-applet menu (icons + arrow).
- **Next suggestion:** #89 slice 2 — the override-icon layer.
## 2026-07-12 — #76 closed: hibernate V3 PASSED on TuringMachine (this commit)
- **Task:** BACKLOG #76 `[human]` closure — Bernardo reports the V3 check.
- **Did:** Bernardo ran the real power-cycle on the T14s (LUKS + btrfs
`@swap` swapfile): hibernate → power off → single LUKS unlock →
session restored, "flawlessly". Deleted #76; HARDWARE-QUEUE resume
entry pruned (outcome recorded here + ROADMAP ✓-entry updated);
Decisions note marked shipped. The **no-swap Hibernate notify** check
stays open in HARDWARE-QUEUE as the one leftover.
- **Verified:** V3 (human, real hardware). Docs-only commit otherwise.
- **Pending:** no-swap notify check (needs a swapless session or
temporary `swapoff -a`).
- **Next suggestion:** #89 slice 2 — the override-icon layer.
## 2026-07-12 — #90 tray submenu arrows: root cause was waybar CSS (this commit)
- **Task:** BACKLOG #90 `[stuck]` (interactive, Bernardo driving on T14s).
- **Did:** Diagnosis was wrong — Papirus-Dark resolves `pan-end-symbolic`
fine via its breeze-dark inheritance (breeze ships inside the nixpkgs
papirus output). Real cause: Waybar's stylesheet applies process-wide,
and the `* { min-height: 0; }` block collapsed the arrow node in the
SNI tray menus Waybar hosts. Scoped the `*` block to `window#waybar`
in boreal + executive-slate waybar.css and waybar.nix generatedStyle
(tooltip rules restate the font — tooltips are separate toplevels);
removed the go-next-symbolic remap workaround from stylix.nix.
- **Verified:** **V3** — live GTK3 repro app popping a dbusmenu-shaped
menu, screenshotted via grim: arrow vanishes with old CSS injected
screen-wide, renders with fixed CSS; property bisect pinned
`min-height: 0` as the sole culprit. V1 flake check green.
- **Pending:** post-switch check that the real nm-applet menu shows the
arrow (needs a human click on the tray icon).
- **Next suggestion:** #89 slice 2 — the override-icon layer.
## 2026-07-11 — interactive T14s session: migration follow-ups (50a5586…6967d89)
- **Task:** Escalation — Bernardo driving, live on the migrated T14s
(first full session on real Nomarchy hardware; 7 commits).
- **Did:** autologin restored (migration missed the LUKS-machine line —
fixed downstream + MIGRATION.md example); SUPER+0 → workspace 10;
VPN tooltip names active VPNs (stuck-shield confusion was Tailscale);
battery "Not charging" hold-band tooltip (+ 4 whole-swap themes);
GTK submenu arrows (bundled SVG — Papirus lacks pan-end-symbolic and
inherits uninstalled breeze); xdg.userDirs.setSessionVariables pinned
(HM 26.05 flip); easyeffects gated on a live tray host (After=
waybar.service was inert — waybar is supervisor-run, not a unit);
#89 slice-1 SNI inventory recorded; #76 unblocked → `[human]`.
- **Verified:** **V3** throughout — live binds via `hyprctl binds`, GTK
menu screenshot (arrow + check render), SNI watcher registration,
deployed configs inspected; V1 flake check green on every commit.
- **Pending:** Bernardo: `nomarchy-rebuild` (autologin + new services),
then the #76 hibernate power-cycle. #89 targets narrowed to
EasyEffects (slice 2) + Signal (slice 3).
- **Next suggestion:** #89 slice 2 — the override-icon layer.
## 2026-07-11 — hotfix: Left=Back bound over rofi default → every menu dead
- **Task:** Escalation — V3 on the migrated T14s: all `nomarchy-menu`
entry points (main, battery, power-profile, VPN) showed rofi's
"Binding 'Left' is already bound" error dialog instead of a menu.
- **Did:** `rofi.nix` — release `kb-move-char-back` to `Control+b` before
binding `-kb-custom-1 Left`, in both `rofi_menu` copies (menu + vpn).
rofi hard-fails on duplicate bindings, and reports it in a GUI dialog,
not stderr — stub tests and `bash -n` can never catch this class.
Filed PROPOSED: EasyEffects 8 blue tray icon; parallel finger/password.
- **Verified:** **V3** — real rofi on the T14s: old flags reproduce the
error dialog (screenshot), fixed flags render the menu; after HM
switch, `nomarchy-menu` renders end-to-end. V0 flake check green.
- **Pending:** flatpak apps missing from drun = stale session env
(relogin), not a code bug. EasyEffects icon + pam items in PROPOSED.
- **Next suggestion:** V3 sweep of the remaining 05bab55 session items.
## 2026-07-11 — post-migration fix batch (05bab55; entry backfilled)
- **Task:** Escalation — first real-hardware migration (TuringMachine →
Nomarchy) surfaced a batch of annoyances; session crashed before
journaling, entry written by the follow-up session.
- **Did:** Force fprintAuth off unless `fingerprint.pam`; first-boot toast
waits for swaync + retries; night-light handles masked units; VPN menu
`rofi_menu` no-op fixed; ← = Back in list menus; GTK menu contrast;
mic-mute LED udev rule + sync; EasyEffects after tray; MIGRATION.md notes.
- **Verified:** V0 flake check; checks.first-boot; checks.hardware-toggles.
- **Pending:** V3 on the migrated machine. Follow-up found the downstream
`~/.nomarchy` lock still pinned the *previous* commit — the user's rebuild
excluded this batch (mic LED "regression" was just that). Also: HM
`programs.chromium.extensions` from the old config wasn't carried over, so
Chromium externally-uninstalled all extensions **and their data** (wallets
included); recovered from the `pre-nomarchy-home` btrfs snapshot.
MIGRATION.md browser note rewritten with the real mechanism.
- **Next suggestion:** V3 sweep of the 05bab55 items after a locked rebuild.
## 2026-07-11 — #88 neon-glass polish / finish
- **Task:** NEXT #88 — finish neon-glass (`VISION § D`), not quarantine.
- **Did:** Rewrote `themes/neon-glass/rofi.rasi` (was invalid `var()` CSS;
now Boreal-style glass with `@colors`, cyan edge, soft selection).
btop accent titles/selection; JSON ui rounding 14 + slight glass
opacity; `preview.png` from theme-shot desktop. No waybar.css.
- **Verified:** **V2** — contrast 24×7 pass; theme-wholeswap green;
theme-shot neon-glass desktop+menu viewed (cyan bar + glass menu);
boreal theme-shot regression green (menu/bar intact).
- **Pending:** —
- **Next suggestion:** post-install hardware hints PROPOSED, or human
HARDWARE-QUEUE.
## 2026-07-11 — Promote neon-glass → NEXT #88 (Bernardo)
- **Task:** human triage: promote neon-glass PROPOSED.
- **Did:** NEXT **#88** neon-glass polish/finish (`VISION § D`); path =
**finish** (not quarantine). Notes: no broken waybar.css reintro without
wholeswap parity; V2 theme-shot required. PROPOSED pitch removed;
VISION pointers updated. **No implementation** this commit.
- **Verified:** V0 (backlog/docs only).
- **Pending:** —
- **Next suggestion:** implement #88 (theme-shot V2).
## 2026-07-11 — VISION hygiene + PROPOSED (queue empty)
- **Task:** QA/docs loop — NEXT still only #76 `[blocked:hw]`; no product
item to implement without inventing work.
- **Did:** Marked Theme A/B/C shipped rows in `docs/VISION.md` (Firmware
#43, Fingerprint #55, doctor stack, rebuild errors #56, Boreal default,
hibernate confidence #77). Rewrote “Suggested agent slices” to open
work only. PROPOSED: post-install hardware hints; neon-glass
finish/quarantine `[human]`.
- **Verified:** **V0** — docs/backlog only (no module change). Prior
iterations V2 suite still stands; no regression claimed here.
- **Pending:** human triage of PROPOSED; HARDWARE-QUEUE V3.
- **Next suggestion:** promote post-install hints → NEXT, or human
HARDWARE-QUEUE / neon-glass call.
## 2026-07-11 — QA sweep (queue empty but #76)
- **Task:** QA sweep — NEXT only has #76 `[blocked:hw]`; no other
actionable items.
- **Did:** option-docs (88 opts) + template-sot green; HM generation has
What changed? / doctor float / first-boot unit; rotated JOURNAL.md
41→18 entries (tail → JOURNAL-ARCHIVE). No product code change.
- **Verified:** **V2** — `nix flake check --no-build`; rebuilt green:
doctor, first-boot, what-changed, clamshell-logind, dock-audio,
windowrule-syntax, battery-notify, zram-swap, nightlight-geo.
- **Pending:** #76 V3 hibernate on Nomarchy hardware; #86/#87 V3 dock QA.
- **Next suggestion:** HARDWARE-QUEUE pass by human, or promote LATER
wallpapers split / triage PROPOSED.
## 2026-07-11 — #87 dock audio sink priority
- **Task:** NEXT #87 — default audio follows dock plug/unplug.
- **Did:** WirePlumber `90-nomarchy-dock-audio` (HDMI/DP session prio
1100, USB 1050) via `modules/nixos/dock-audio-rules.nix` + default.nix
pipewire. `checks.dock-audio` pure rule asserts + conf-file VM. V3
hotplug steps in HARDWARE-QUEUE. Closed #87.
- **Verified:** **V2** — `nix flake check --no-build`; `checks.dock-audio`
green (pure rule asserts + conf installed under wireplumber.conf.d).
- **Pending:** V3 real HDMI/USB-dock hotplug (HARDWARE-QUEUE).
- **Next suggestion:** QA sweep or LATER wallpapers split if promoted.
## 2026-07-11 — #86 clamshell HandleLidSwitchDocked
- **Task:** NEXT #86 — lid closed + external monitor must not suspend.
- **Did:** Explicit `HandleLidSwitchDocked=ignore` in
`modules/nixos/power.nix` (logind settings.Login). Undocked lid
behaviour unchanged. idle.nix comment corrected. `checks.clamshell-logind`
asserts conf + active logind. V3 steps in HARDWARE-QUEUE. Closed #86.
- **Verified:** **V2** — `nix flake check --no-build`;
`checks.clamshell-logind` green (`HandleLidSwitchDocked=ignore` +
logind active).
- **Pending:** V3 real lid+external on laptop (HARDWARE-QUEUE).
- **Next suggestion:** #87 dock audio sink follow.
## 2026-07-11 — #85 hardware hall of fame + split #84
- **Task:** NEXT #85 docs hall of fame; #84 was `[big]` → split.
- **Did:** HARDWARE.md §9 install-tested table (T14s Gen 4 AMD, Latitude
5410/5310) + DMI PR invite; renumbered following sections. #84 → #86
clamshell + #87 dock audio. VISION/ROADMAP; closed #85.
- **Verified:** V0 (docs only).
- **Pending:** —
- **Next suggestion:** #86 clamshell or #87 dock audio (both product).
## 2026-07-11 — #83 doctor first-boot pre-activate flag
- **Task:** NEXT #83 — doctor points at failed installer HM pre-activate.
- **Did:** doctor row: if `/var/log/nomarchy-hm-preactivate.log` is present
and no Home Manager generation exists → ✖ +
`home-manager switch --flake ~/.nomarchy -b bak`. Skip/ok otherwise.
Extended `checks.doctor` (fail arm + recovered gen). Closed #83.
- **Verified:** **V2** — checks.doctor green (fail arm + recovered gen);
local smoke with NOMARCHY_HM_PREACTIVATE_LOG / empty HOME.
- **Pending:** —
- **Next suggestion:** #85 docs hall of fame (cheap) or split #84 dock.
## 2026-07-11 — #82 generation readability
- **Task:** NEXT #82 — plain-language “what changed last rebuild”.
- **Did:** `pkgs/nomarchy-what-changed` (nvd → “N added, M removed, K
updated”); wired into lifecycle post-`nomarchy-rebuild` / `nomarchy-home`
(full nvd + notify toast); System What changed? (toast + floating
full report). `checks.what-changed` with NOMARCHY_NVD fixture. Closed #82.
- **Verified:** **V2** — checks.what-changed green; local smoke on real
HM gens (“Desktop: 1 added, 1 removed”) + fixture counts.
- **Pending:** —
- **Next suggestion:** #83 doctor pre-activate fail flag or #85 docs.
## 2026-07-11 — #81 first-boot welcome toast
- **Task:** NEXT #81 — dismissible “you're set” card (`VISION § B`).
- **Did:** `pkgs/nomarchy-first-boot` + user oneshot
(`modules/home/first-boot.nix`): notify once with SUPER+M/T/? + Network
+ Doctor pointers; marker `settings.firstBootShown` via theme-sync
`--no-switch` (in-checkout state). Skip live hostname. Option
`nomarchy.firstBootWelcome.enable` (default on). `checks.first-boot`.
ROADMAP/VISION/README; closed #81.
- **Verified:** **V2** — `nix flake check --no-build`; `checks.first-boot`
green (toast + marker + silent re-run + live skip); local shim smoke;
downstream-template-home carries the user unit.
- **Pending:** V3 — real swaync rendering on first installed login
(toast body is pure text; not queued unless it misbehaves).
- **Next suggestion:** #82 generation readability or #85 docs hall of fame.
## 2026-07-11 — #80 doctor battery health readout
- **Task:** NEXT #80 — battery health in `nomarchy-doctor` (`VISION § C`).
- **Did:** Doctor row: `cycle_count` + retained capacity
(`charge_full`/`design` or `energy_*`) as `% of design`; system
batteries only; soft warn &lt;70% design; skip when attrs absent.
`NOMARCHY_POWER_SUPPLY_ROOT` for the VM fixture. Extended
`checks.doctor` (fake BAT0 + Device-scope MOUSE0 ignore). HARDWARE §10,
ROADMAP ✓, VISION ✓; closed #80.
- **Verified:** **V2** — `nix flake check --no-build`; `checks.doctor`
green; local smoke on real BAT0 (342 cycles, 81% via energy_*) + fixture.
- **Pending:** Power-menu surface left optional/out of scope (doctor is
the product surface for report-only health).
- **Next suggestion:** #81 first-boot welcome card (highest product ROI)
or #85 docs-only hall of fame.
## 2026-07-11 — Triage: VISION-gap PROPOSED → NEXT #80#85 (Bernardo)
- **Task:** Bernardo promoted five of the six fresh VISION-gap pitches
(all but the wallpapers split, which stays LATER).
- **Did:** NEXT gains #80 battery health readout, #81 first-boot welcome
card, #82 generation readability, #83 doctor pre-activate fail flag,
#84 dock life polish `[big]`, #85 hardware hall of fame. PROPOSED
placeholder left. **No implementation started** (explicit instruction).
- **Verified:** V0 (backlog only).
- **Pending:** —
- **Next suggestion:** #80 (smallest) or #81 (highest product ROI); #84
must be split first.
## 2026-07-11 — Quick wins: exit-node locations + geo tooltip
- **Task:** BACKLOG LATER "VPN exit-node richer display" + a geo-mode
tooltip nit from the previous iteration (human asked for quick wins).
- **Did:** Tailscale Exit node picker rows now "hostname — Country City",
sliced by the header's fixed-width column offsets (COUNTRY/CITY are
multi-word; never field-split), locationless nodes stay bare, pick strips
back to hostname at the first space. Nightlight Waybar tooltip says
"follows your location" in geo mode. Queue's VPN entry updated.
- **Verified:** V1 — awk proven against a fabricated 3-case fixture
(Mullvad 1-word + multi-word city + bare node); flake check exit 0;
downstream-template-home builds (writeShellScriptBin syntax-gates both
scripts). Real tailscale output is V3 (existing VPN queue entry).
- **Pending:** V3 VPN menu live paths (extended, not new).
- **Next suggestion:** wallpapers artifact split (LATER, decided).
## 2026-07-11 — Night-light geo mode (lat/long → wlsunset)
- **Task:** BACKLOG LATER "Night-light geo mode" (human-picked).
- **Did:** `nomarchy.nightlight.latitude`/`.longitude` (both set = geo mode):
`services.wlsunset` (location-computed sunrise/sunset, `.temperature` →
night temp) replaces hyprsunset; the toggle script's `unit=` and the
live-state ExecCondition follow via one `unit` let-binding. Template
example lines, README row, ROADMAP ✓. New `checks.nightlight-geo`:
pure-eval asserts on the rendered units (coords + temp in ExecStart,
ExecCondition present, hyprsunset off). Declarative-only (no menu writer —
coords are machine config like keyboard layout).
- **Verified:** V1 — `nix flake check --no-build` exit 0 (evals the new
asserts + option-docs); built `downstream-template-home` (default
hyprsunset path unregressed) + the check drv. Caught en route: HM renders
`ExecStart` as a list (`toString` needed in eval asserts).
- **Pending:** V3 queued (HARDWARE-QUEUE § Any machine): visible warm shift
at location night + toggle/persistence on the swapped unit.
- **Next suggestion:** wallpapers artifact split (LATER, decided).
## 2026-07-11 — Sync-sweep rule + grooming + zram user docs (human-requested)
- **Task:** Bernardo: groom stale items and codify the check so they don't
recur; close the zram user-doc gap.
- **Did:** LOOP.md §5 gains step 4 **Sync sweep** (grep item/feature across
agent/+docs/ on ship; prune recorded `[x]` queue entries) + an AGENTS.md
rule line. Applied it: BACKLOG PROPOSED pruned (auto-theme pitch was
stale — shipped as #79; shipped/promoted placeholders removed; v1.0
pointer rewritten; FUTURE promoted-stub dropped). HARDWARE-QUEUE pruned
29 checked `[x]` entries (363→~250 lines), dangling refs reworded,
prune rule in header. README §3 now documents the zram default +
hibernation out-of-the-box + MIGRATION pointer.
- **Verified:** V0 (docs/meta only) — grep sweep for dangling refs clean.
- **Pending:** night-light geo mode next (same session).
- **Next suggestion:** wallpapers artifact split (LATER, decided).
## 2026-07-11 — Vendor-neutral agent docs restructure (human-requested)
- **Task:** Bernardo: de-vendor the agent instructions (multi-model repo),
clean stale files, better docs/agent/.claude structure.
- **Did:** New root `AGENTS.md` entry (CLAUDE.md → symlink). Skill bodies
moved to `agent/`: VERIFICATION.md (enforcement, ex-nomarchy skill),
DELEGATION.md (tiers light/standard/frontier + scout/runner contracts +
fan-out; consolidates CLAUDE.md table + LOOP §economy + skill §6.5),
THEME-DESIGN.md (ex-theme skill, now with frontmatterd shim). `.claude/`
is a thin adapter (shims route into `agent/`). Maps updated (agent/,
docs/, README tree). Stale: `.gitignore` old_distro entry dropped; local
result*/__pycache__ removed. JOURNAL rotated (29 kept, 120 →
JOURNAL-ARCHIVE.md).
- **Verified:** V0 — `nix flake check --no-build` exit 0 with the symlink
tracked; vendor-name grep clean outside DELEGATION's mapping table.
- **Pending:** nothing; other harnesses add their own adapter row when used.
- **Next suggestion:** #76/#79 remain [blocked:hw]; otherwise groom PROPOSED.
## 2026-07-11 — #76 checks.hibernate-swapfile (VM-verify the swapfile+offset)
- **Task:** Bernardo — push #76's swapfile-resume residual into a VM (like
the auto-theme sunset trick).
- **Did:** Tried a full runtime-swapfile hibernate→resume test; it hit a
bounded, definitive **`CanHibernate=no`** — systemd won't hibernate to a
swap that isn't declared in the boot config, and a runtime-computed
`resume_offset` can't reach the boot cmdline (the genuine chicken-and-egg).
First cut also had an **unbounded `wait_for_shutdown`** that hung → killed
it, bounded the wait in a thread (180s) + a `CanHibernate` pre-check, which
is what surfaced the clean verdict. Pivoted `checks.hibernate-swapfile` to
what a VM *can* prove deterministically and the partition test can't: the
installer swapfile **build + offset** — NOCOW `mkswapfile`, file-type
swapon, valid `map-swapfile -r` offset accepted by `/sys/power/resume_offset`,
zram above it. (Device fix: `/dev/vdb` once `useNixStoreImage` was dropped.)
- **Verified:** **V2 PASS** (fresh build, exit 0). BACKLOG/ROADMAP updated;
#76 residual narrowed to the literal encrypted power-cycle (dev box runs it).
- **Lesson:** the sunset-trick spirit applies but not always the full cycle —
when systemd/kernel gates the behaviour (CanHibernate), verify the
*construction* deterministically and leave only the physical cycle to HW.
Always bound `wait_for_shutdown` (no timeout param → thread + join).
- **Next suggestion:** #76/#79 both `[blocked:hw]`; QA / PROPOSED otherwise.
## 2026-07-11 — Code-review fixes (parallel review of the session batch)
- **Task:** Bernardo asked for parallel work; spawned a fresh-eyes opus
review of `2055842..HEAD` (static). It found the batch sound — 2 real LOW
edge bugs, 1 false positive, 1 cosmetic.
- **Did:** (1) `cmd_auto` — inverted sunrise/sunset (sunrise > sunset) went
perpetually day; replaced the `not between` shortcut with a real
wrap-around `mins >= sunrise or mins < sunset`, so a cross-midnight day
window switches both ways. (2) `rofi.nix` autotheme HH:MM guard tightened
`[0-2][0-9]` → `[01][0-9]|2[0-3]` so 2429 are rejected. Dismissed the
`breeze` finding (papirus DOES ship breeze/breeze-dark — verified) and the
cosmetic doctor-RAM one.
- **Verified:** py_compile; boundary truth-table (normal + wrap-around);
HH:MM case table (23:00/19:59/20:00 accept, 24/25/30:00 reject); `auto
--which` normal-case unchanged; menu bash -n; flake check green. Normal
case unchanged so `checks.auto-theme` still holds.
- **Pending:** hibernate-swapfile VM test still running (uncommitted flake.nix).
- **Next suggestion:** land hibernate-swapfile once its VM test returns.
## 2026-07-10 — #79 V2: checks.auto-theme (simulated sunset) — was mis-framed V3
- **Task:** Bernardo challenged the "V3 real-session" framing — a simulated
sunset IS VM-testable. He's right; I'd conflated "needs a real desktop"
with "needs the generic home-manager switch."
- **Did:** Added `checks.auto-theme` runNixOSTest: installs nomarchy-theme-sync,
points `NOMARCHY_DEFAULT_THEMES` at presets, stubs the switch via
`NOMARCHY_REBUILD` (a marker), configures the pair+schedule, then **walks
the VM clock** 19:55→20:05→20:06→next-day 07:30 asserting slug goes
summer-day → night (1 rebuild) → night (idempotent, still 1) → day (2). The
self-gating I relied on: presets via env, wallpaper/notify no-op headless,
run_switch honors NOMARCHY_REBUILD + waybar nudge is check=False.
- **Verified:** **V2 PASS** — `nix build .#checks…auto-theme` fresh, exit 0.
Dropped #79's `[blocked:hw]`; it's done (V2). Updated ROADMAP.
- **Lesson:** don't default "timer/session feature" to V3 — stub only the
generic step (the real HM switch, covered elsewhere) and simulate the rest
(clock) headlessly. Only the literal timer-fires-on-OnCalendar is on-HW,
and its schedule is systemd-analyze-validated.
- **Next suggestion:** NEXT head #76 `[blocked:hw]`; else QA / PROPOSED.
## 2026-07-10 — #79 slice 3: Look & Feel Auto theme menu (#79 complete)
- **Task:** BACKLOG #79 slice 3 — the menu; completes the feature.
- **Did:** `rofi.nix` — "Auto theme (on/off)" row in Look & Feel + an
`autotheme)` submenu: toggle, pick day/night (from
`nomarchy-theme-sync list`), set sunrise/sunset (HH:MM input, validated).
Enable writes the flag + defaults the summer pair `--no-switch`, then
`exec auto --force` — one rebuild installs the timer AND applies the right
theme. Disable is instant `--no-switch` (`auto` self-gates; the lingering
timer no-ops). Day/night/times are live `--no-switch`.
- **Verified:** **V1** — HM generation builds (`writeShellScriptBin` bash -n
on nomarchy-menu passes) + bash -n on the built menu. **Logic test**
(stubbed rofi/theme-sync/notify): selecting "Auto theme (off)" runs exactly
`set day summer-day`, `set night summer-night`, `set enable true`
(all `--no-switch`), then `auto --force` — the intended one-rebuild path.
Disable path is static-clear (set false `--no-switch`, no `auto`); a
stateful-stub dynamic test would loop (stub doesn't reflect the flip). V0
flake check green. **#79 collapsed to `[blocked:hw]`** (all 3 slices done;
only live-session switch remains, needs a Nomarchy machine).
- **Pending:** V3 real-session (timer switches day↔night across sunset).
- **Next suggestion:** NEXT head #76/#79 both `[blocked:hw]`; QA/PROPOSED.
## 2026-07-10 — #79 slice 2: auto-theme systemd timer
- **Task:** BACKLOG #79 slice 2 — the timer/hook.
- **Did:** `modules/home/autotheme.nix` (imported in home default.nix):
`systemd.user.{service,timer}.nomarchy-auto-theme`, install gated on
`config.nomarchy.settings.autoTheme.enable or false` (state-driven, like
updates.nix gates on its enable). Service runs `nomarchy-theme-sync auto`
with a PATH for `home-manager`; timer `OnStartupSec=1min` +
`OnCalendar=*:0/15` + `Persistent`. Chose periodic over exact
sunrise/sunset timers — robust to suspend/DST, and `auto` is idempotent so
ticks are cheap (rebuild only at the transition).
- **Verified:** **V1** — real-config eval (state temp-enabled, restored):
`settings.autoTheme.enable`→true, timer `OnCalendar`=`*:0/15`, service
ExecStart=`… nomarchy-theme-sync auto`; disabled→no units (isolation eval
condition=false). `systemd-analyze calendar '*:0/15'` valid. **V0** flake
check green. (Gotcha: a new .nix file is invisible to the flake until
`git add` — flake eval only sees tracked files.)
- **Pending:** live timer→`home-manager switch` on a real Nomarchy session
(needs a Nomarchy machine, like #76). Slice 3 (menu) next.
- **Next suggestion:** #79 slice 3 — Look & Feel Auto theme menu.
## 2026-07-10 — #79 slice 1: auto time-of-day theme CLI primitive
- **Task:** Split BACKLOG #79 (`VISION § D`, `[big]`) into 3 slices (CLI /
timer / menu); took slice 1.
- **Did:** `nomarchy-theme-sync auto` — reads
`settings.autoTheme.{enable,day,night,sunrise,sunset}`, computes day/night
by the local clock, and applies the matching preset **only if different**
(idempotent → the slice-2 timer won't rebuild needlessly). `--which`
prints the decision without switching; `--force`/`--no-switch` too.
Factored `cmd_apply`'s core into `apply_named` so `auto` reuses the exact
same one engine (GOALS: no second pipeline).
- **Verified:** **V1** package builds; functional tests on the built bin
against scratch state: wide-day→day slug, 00:0000:01 window→night,
disabled→no-op, missing day/night→die, `auto --no-switch` writes state,
re-run→"already on" no-op, plain `apply` still writes (refactor intact).
**V0** py_compile + flake check + `checks.theme-sync-validate` green.
- **Pending:** slices 2 (systemd sunrise/sunset timers + login apply, V2)
and 3 (Look & Feel menu) remain under #79.
- **Next suggestion:** #79 slice 2 — the timer/hook (V2 runNixOSTest).