Some checks failed
Check / eval (push) Has been cancelled
Policy: remove system generations older than 30 days only when they are also beyond the three most recent past gens, so rare rebuilds never lose rollback depth. Notes existing 14d nix.gc has no count floor.
90 KiB
90 KiB
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 3–5 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 (history, never edited).
Template:
## YYYY-MM-DD — <task title> (<commit sha, or "no commit">)
- **Task:** which BACKLOG item (or QA sweep / bootstrap / escalation)
- **Did:** what changed, in 2–4 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-15 — File #128 generation auto-prune policy (no code)
- Task: Bernardo: auto-clean NixOS gens older than 30 days but always keep ≥3 past generations.
- Did: NEXT #128. Policy restated; noted existing
nix.gcweekly--delete-older-than 14dhas no min-generation floor. - Verified: V0 (docs/agent only).
- Pending: implement when picked; optional HM gens scope.
- Next suggestion: implement #128, or human #115/#120.
2026-07-15 — #111 Recovery + #105 System IA + #110 retire Control Center
- Task: Scope-first Recovery, System submenu IA, retire Control Center.
- Did: System → Connectivity / Devices / Recovery / Preferences. Recovery:
Desktop gen (HM list+activate), System boot (toast + RECOVERY.md), Files
BTRFS, What changed. Migrated CC: blur/gaps presets in Look & Feel; update
checks + Bluetooth/Printing package toggles in Preferences (rebuild in
terminal). Removed
pkgs/nomarchy-control-center+ menu entry. Docs RECOVERY/HARDWARE/VISION updated. Closed #111 #105 #110 #117. - Verified: V0 menu-back; HM gen builds; flake check --no-build.
- Pending: V3 eyeball the new menu tree on a real session.
- Next suggestion: #115/#120 human decisions, or hardware queue.
2026-07-15 — V2 permanent checks for #104 / #122
- Task: V2 everything VM-checkable from the #104/#122 batch.
- Did: Extracted
pkgs/nomarchy-airplane(overlay). Addedchecks.airplane(session state machine + menu/keybind/whole-swap surfaces; mocked nmcli) andchecks.fastfetch-logo(sextant count + module flags). Host V2 artifacts stay under/tmp/nomarchy-v2-batch2and/tmp/nomarchy-v2-122/. - Verified: V2 — both new checks green; prior mock round-trip + kitty screenshots; #107 migrate re-checked; ecosystem keys in HM conf; flake check --no-build.
- Pending: V3 airplane radios (HARDWARE-QUEUE).
- Next suggestion: #111 Recovery menu, or #98 with screenshot.
2026-07-15 — #104 airplane mode + #122 fastfetch sextant logo
- Task: NEXT #104 (Airplane) + #122 (crisper fastfetch logo).
- Did: (104)
nomarchy-airplaneruntime Wi-Fi+BT kill-switch with prior restore; System menu row; SUPER+CTRL+R; Waybarcustom/airplane(signal 11, self-hides); whole-swap jsonc/css parity. (122) chafasextant24×12, rsvg 360px. - Verified: V1 airplane state machine (on/off/status empty when off);
bash -n; keybinds-cheatsheet; menu-back; flake check --no-build; HM gen.
V2 fastfetch: real kitty screenshots
/tmp/nomarchy-v2-122/{boreal-sextant,summer-kitty,boreal-block}.png— sextant clearly finer than block; no tofu; accents track. (Superseded by permanent checks entry above.) - Pending: V3 airplane on a machine with live radios (HARDWARE-QUEUE).
- Next suggestion: #111 Recovery menu, or #98 with screenshot.
2026-07-15 — #107 state.json + nomarchy-state-sync
- Task: BACKLOG #107 — rename misnamed system state file and CLI.
- Did:
theme-state.json→state.json(template, root, docs, modules); package/CLInomarchy-theme-sync→nomarchy-state-syncwith symlink alias;modules/state-read.nix; mkFlake/doctor/lifecycle read legacy name; writes always land onstate.jsonand remove the old file. - Verified: py_compile; legacy-file unit migrate (write removes theme-state.json); V0 flake check pending in same push.
- Pending: drop
nomarchy-theme-syncalias after release notes. - Next suggestion: #104 airplane, or #98 with a screenshot.
2026-07-15 — Close #94 installed chromium + kill Hyprland update-news
- Task: Residual #94 (chromium on installed path) + first-boot polish seen while probing.
- Did: Re-booted leftover offline install disk (
target.img). Probe: Chromium 150 on PATH, https/html →chromium-browser.desktop, Chromium window opens (about:blank+ keyring prompt). Closed #94. Addedecosystem.no_update_news+no_donation_nag(every first boot showed “Hyprland updated to 0.55.x!”). - Verified: V2 install re-boot screenshots
/tmp/nomarchy-v2-94/; V0nix flake check --no-build; HM gen conf contains ecosystem keys. - Pending: V3 optional on Acer (hardware already had no browser on live before #103; installed path is the one that mattered).
- Next suggestion: #107 state.json rename, or #98 if screenshot lands.
2026-07-15 — File #127 docked idle blackout (no code)
- Task: Bernardo: docked laptop idle → black screens; external KB/mouse no wake; unplug external did not restore panel; Caps Lock still worked. Explains the "session crash" (seat brick, not agent-only).
- Did: NOW #127 + HARDWARE-QUEUE capture steps. Code read: AC idle path is lock+DPMS not suspend; dock mode disables eDP; both wake and undock recovery failed on the incident.
- Verified: V0 (docs/agent only).
- Pending: hardware journal capture on next repro; then fix.
- Next suggestion: continue fix batches, or dig into #127 if Bernardo can leave SSH open for a controlled repro.
2026-07-15 — V2 verification of fix batches (doctor-float + test-install)
- Task: V2-test shipped items that admit VM harnesses (#95 doctor, #123 bake, #112/#124/#125 install path).
- Did / Verified:
- V2 doctor-float (boreal):
nix build --impure -f tools/doctor-float.nixPASS. Classcom.nomarchy.doctor, floating, centered; clienttitle=kitty. Screenshots:/tmp/nomarchy-v2-doctor/{desktop-before,doctor-float}.png. SoftGL window body is blank (known softGL terminal paint); float/class contract holds. - V2 test-install.sh (offline LUKS+swap): machine-checkable PASS
(~28 min). Artifacts
/tmp/nomarchy-v2-batch/:- ISO:
result/iso/nomarchy-live-….iso(#125) first-boot.png: themed Boreal desktop + Waybar, no red autogenerated banner, no login prompt → HM pre-activate (#123) succeeded (visual)- install completed poweroff; LUKS boot + passphrase works
- ISO:
- Disk filter fixture: fd0/loop excluded, vda/sda kept (#112 logic)
- V2 doctor-float (boreal):
- Pending: V3 on Acer/XPS; mount installed disk for log/flake-url strings needs root (skipped). Doctor softGL paint is not a product fail.
- Next suggestion: continue backlog or hardware V3.
2026-07-15 — #108 keybinds cheatsheet groups + completeness check
- Task: BACKLOG #108 — group SUPER+? as Window/Workspace/Menu/Media; automated completeness.
- Did: every bind/extra in keybinds.nix gets
group; cheatsheet renders section headers;checks.keybinds-cheatsheetasserts groups + every desc present (proved via assert). - Verified: V0 flake check; cheatsheet file shows ── Window ── etc.
- Pending: V3 eyeball SUPER+? on a real session (optional).
- Next suggestion: #94 residual or #107 state.json rename.
2026-07-15 — Fix batch #112 disk picker, #106 menu Back, #113 offline theme
- Task: Second fix-only batch from NEXT/NOW residuals.
- Did: (112)
list_installable_disksexcludes fd/loop/sr/zram/tiny (<8 GiB), sorts largest-first; installer-safety markers. (106)tools/check-menu-back.py+checks.menu-back(proved to fail when Back stripped). (113) offline theme contract: TESTING item 6 scoped to default/ current theme;run_switchprints clear offline-oriented message on network/build failures. - Verified: V0 flake check; installer-safety; menu-back prove-fail; py_compile theme-sync.
- Pending: V2 unattended install with OVMF fd0 present (optional).
- Next suggestion: #108 keybinds audit, or #94 test-install chromium.
2026-07-15 — Fix batch #123–#126 (install bake, flake ref, ISO name, display)
- Task: Fix-only NOW batch: #123 dconf pre-activate, #124 main flake seed, #125 ISO filename, #126 display mode list.
- Did: (123) pre-activate creates
/run/user/$UID+ prefersdbus-run-session -- activate. (124) seed?ref=main; patch-template rewritesinputs.nomarchy.urlfrom NOMARCHY_FLAKE_URL (was unused); template default main. (125)image.baseName→ nomarchy-live-….iso. (126) sort modes by pixel area; toast shows hyprctl size; TESTING QEMU note. - Verified: V0 flake check; installer-safety;
image.baseNameevalnomarchy-live-…; patch-template flakeUrl rewrite; mode sort unit fixture. - Pending: V3 reinstall on Acer/XPS (#123/#124); optional full
test-install.shV2 when time allows. - Next suggestion: #112 disk-picker fd0, or V2 test-install for #123.
2026-07-15 — File #125 ISO name + #126 display resolution invert (no code)
- Task: Bernardo: (1) installer ISO still named nixos; (2) live VM Display picker — higher modes made the screen look lower-res.
- Did: NOW #125 — artifact is
nixos-live-….isobecauseimage.baseNameis still the nixpkgs default; volumeID already NOMARCHY_LIVE. #126 — rofi display mode list/apply path; separate sort bug vs QEMU scaling before coding. - Verified: V0 (docs/agent only); confirmed
result/iso/nixos-live-…isoon tree. - Pending: implement when picked.
- Next suggestion: still #123 (HM pre-activate), or #125 if a one-liner.
2026-07-15 — #95 complete: Kitty is the only terminal (this commit)
- Task: Bernardo: make kitty default and only option — drop dual-terminal complexity (Ghostty failed on Acer OpenGL 4.2; fallback was more code).
- Did: Removed
ghostty.nixandnomarchy.ghostty.enable. Kitty always installed + themed; defaultnomarchy.terminal = "kitty". Doctor, calendar, what-changed →kitty --class=com.nomarchy.*. Dropped install-time GL probe + mesa-demos. Updated README/REQUIREMENTS/OVERRIDES/TESTING/tools. - Verified: V0 flake check; downstream-template-home builds with kitty, no ghostty; installer-safety green.
- Pending: V3 Acer SUPER+Return + doctor float (HARDWARE-QUEUE).
- Next suggestion: #123 (HM pre-activate dconf).
2026-07-15 — #95: themed Kitty when OpenGL < 4.3 (superseded above)
- Task: Bernardo: when GL < 4.3 automatically add kitty — and theme it.
- Did:
modules/home/kitty.nixthemes Kitty from theme-state (same palette/font/opacity as Ghostty); enables whennomarchy.terminalis kitty ornomarchy.kitty.enable. Installer runsglxinfo(mesa-demos on PATH) and, if OpenGL < 4.3, writessettings.terminal = "kitty"(+terminalReason) into theme-state. Docs/REQUIREMENTS + README rows. - Verified: V0 flake check; HM gen with
settings.terminal=kittybuilds — kitty.conf has Boreal colors,TERMINAL=kitty, Hyprland$terminal=kitty; default template HM has ghostty and no kitty package. - Pending: V3 Acer install; doctor/calendar still hardcode ghostty.
- Next suggestion: #123 (HM pre-activate dconf) — still highest install pain.
2026-07-15 — docs/REQUIREMENTS.md (OpenGL floor + disk planning)
- Task: Bernardo: why Acer lacks OpenGL 4.3; start documenting minimum system requirements including storage (Nix store + snapshots).
- Did: Answer is hardware generation (HD 4000 / Ivy Bridge tops at GL
4.2; Ghostty needs 4.3). New
docs/REQUIREMENTS.md— UEFI/x86_64, GPU table, RAM, disk floors (40/64/128 GiB) + swap≈RAM, why store+snapper grow; linked from README, docs map, HARDWARE.md; #95 notes the generation ceiling. - Verified: V0 (docs only).
- Pending: #95 still needs a runtime fallback; tighten disk numbers when
a fresh install is
df-measured end-to-end. - Next suggestion: #123 (installer bake).
2026-07-15 — File install findings from Acer + XPS photos (no code)
- Task: Bernardo: real installs on Acer Aspire M5-481T + Dell XPS 9350; photos of the install end screens and post-boot sessions. Figure out issues and queue them — do not implement in this iteration.
- Did: Read the six photos. Three distinct root causes (not one vague
"home didn't build"):
- #123 — HM pre-activate dies on both machines at dconf
(
/run/user/1001/dconf: Permission denied) → partial first boot (weird GTK + missing nm-applet are symptoms, not separate bugs). - #124 — seeded flake hardcodes
?ref=v1while installer writes main-eranomarchy.hardware.*; v1 lags (~hundreds of commits) →nomarchy.hardware does not existon Acer rebuild/pull. - #95 — Ghostty Acer-only (XPS is fine). Two photos = two
attempts on the Aspire: pre-HM explicit
OpenGLOutdated, post-HM quiet exit afterGDK_DISABLE(same machine; kitty used as the working shell). Primary blocker is GL ≥ 4.3. HARDWARE-QUEUE V3 rows. Photos stay local (not committed).
- #123 — HM pre-activate dies on both machines at dconf
(
- Verified: V0 (docs/agent only).
- Pending: implement #123 first; then #124; #95 independent (Acer GL).
- Next suggestion: #123 (installer bake) — highest blast radius.
2026-07-15 — #95 timeline: both Ghostty fails are Acer, pre/post HM
- Task: Bernardo corrected the Ghostty story again.
- Did: XPS works. Both fail photos are Aspire M5-481T: (1) before home
properly built → OpenGL 4.2/
OpenGLOutdated; (2) after home built → silent exit afterGDK_DISABLE=gles-api,vulkan. Kitty was the manual working terminal used to run those experiments. #95 + HARDWARE-QUEUE rewritten; not two machines. - Verified: V0 (docs only).
- Pending: —
- Next suggestion: still #123.
2026-07-15 — #119: mime defaults must name a present .desktop (this commit)
- Task: BACKLOG #119 —
text/plainnamed vscode, which the live ISO never ships (same GIO-skip trap as #94, one key over). - Did:
text/plainis now an ordered fallbackcode.desktop→org.gnome.TextEditor.desktop(HM tries the next when the preferred is missing). Live profile gainsmpvtoo — video mime defaults had the same hole and the package is free via the template pin. Extendedchecks.live-baseline-appsso every[Default Applications]key has at least one listed.desktopon live (HM path + system path for thunar) and on the default template install. - Verified: V2 — check green; mimeapps.list renders
text/plain=code.desktop;org.gnome.TextEditor.desktop; proved to fail whentext/plainis a vscode-only singleton. V0 flake check green. - Pending: V3 launch of a
.txton the Acer is covered by the existing #103 HARDWARE-QUEUE entry (now expects Text Editor for text files). Opting out of both vscode and Text Editor still leaves no handler — that is the delete-the-line convention, not a silent live-ISO bug. - Next suggestion: #95 (Ghostty does not open) or #94 residual (test-install chromium launch).
2026-07-14 — #118: smartd self-gates; the doctor was right all along (this commit)
- Task: BACKLOG #118 — Bernardo's live ISO showed a red Waybar health icon reporting smartd.
- Did: smartd's DEVICESCAN finds nothing where no drive answers SMART and
exits 17, so systemd marks it failed, the doctor honestly reports a
failed unit, and Waybar paints
@bad. Everything downstream was correct — smartd was the bug, not the doctor. Added anExecConditionrunningsmartctl --scan(empty exactly when smartd would find nothing), so the unit goes inactive rather than failed. NOTSuccessExitStatus = 17, which would also swallow exit 17 on a machine that has drives — the reason the daemon exists. - Scope was never live-only: smartd mkDefaults true everywhere and QEMU virtio has no SMART, so every VM install has been booting to a health warning, and every V2 run had been showing it as noise.
- Verified: V2 —
checks.smartd-gateboots the real distro module (not a restatement of it;nixpkgs.configneededmkForceto yield to the test's pkgs) and asserts both halves, since they pull opposite ways: a gate that never skips leaves the red icon, one that always skips silently kills drive-health monitoring — the failure nobody notices until a disk dies quietly. No-SMART node →ActiveState=inactive, not failed, absent fromsystemctl --failed(what the doctor actually reads); and the gate's logic driven against a scan that finds a device → exit 0, because QEMU cannot answer SMART honestly and pretending otherwise would test nothing. Proved to fail by unwiring the condition. flake check + doctor + hardware-toggles- live-baseline-apps + option-docs + state-bridges green.
- Pending: V3 — that smartd still RUNS on real drives (dev box, real NVMe). Queued with an explicit fail-condition: if it skips there, revert the gate rather than tune it.
- Next suggestion: #119 (
text/plainnames vscode — the last of #94's bug class), or #95 (Ghostty does not open) at the top of NOW.
2026-07-14 — #121 reverted: the fix worked, the gain didn't survive measuring (this commit)
- Task: Bernardo's call on #121 (shipped
0b464af, reverted here): "Let's leave it honestly. Sounds too much work for a negligible gain." - Did: removed the chromium overlay +
checks.chromium-single-closure; template HM closure back to 9.38 GiB and the duplicate unwrapped chromium is back, deliberately.overlays.defaultcarries a comment saying so, and the ROADMAP entry is now a ✗ decided-against record holding the measurement, the working approach, and the commit to recover it from. - Why this was right: the fix worked, but it substitutes into a
buildCommandnixpkgs owns — coupling us to wrapper internals with a silent no-op failure mode, which is why it needed a permanent check too. That standing cost buys ~195 MiB of download and ~19 MiB of disk. Boring beats clever at that exchange rate (CONVENTIONS). - The lesson that outlives it, and the real product of the last two items:
closure size is not disk size and is not image size — measure the
artifact. Removing a 687 MiB path moved the ISO by 8 KiB, because
mksquashfs dedupes duplicate files and
auto-optimise-storehardlinks them (the two paths share inodes —stat-verified;ducounts 639 MiB for the pair vs ~620 for one). Only the wire can't dedupe. This is stamped on #120, whose entire size table is closure arithmetic — without it, "drop the pin, save 4 GiB" would have evaporated at the squashfs exactly like this did. - Verified: V0 flake check green; revert confirmed by closure (the plain chromium is back, 9.38 GiB) rather than by reading the diff.
- Next suggestion: #118 (smartd self-gate).
2026-07-14 — #121: one chromium, not two — 687 MiB off every install (superseded by the revert above)
- Task: BACKLOG #121, found by measuring #103's ISO delta. Nothing was failing — that is the point; a duplicate browser breaks no build.
- Did: nixpkgs' chromium wrapper with
enableWideVine = true(what the template ships, for DRM) runs the-wvcopy but linksshare/*from the plain unwrapped build. A symlink is a store reference, so a second 687 MiB chromium rode along for a directory of.desktopfiles nothing executes — on every installed machine, not just the ISO.overlays.defaultnow moves the symlink source to the copy we already run; the template needs no change (lib.nix, the repo pkgs, and nixosModules all apply the overlay). - The check that decided the approach: whether the
-wvcopy itself references the plain build. It iscp -aof it, so it plausibly would — and if it did, no wrapper change could drop the duplicate and the whole item was dead. Verified self-contained first, then fixed. Also verified, not assumed:.override { enableWideVine = true; }composes with the overlay'soverrideAttrs(order usually matters — here it survives), so the template's existing line picks the fix up untouched. - Verified: V2 — only
-wv+ the tiny sandbox remain in the template closure. Equivalence proved, not hoped: the wrapper still execs the-wvbuild, WidevineCdm present there,share/{applications,icons,man}match stock with the.desktopbyte-identical. Newchecks.chromium-single-closureasserts the invariant (exactly one full unwrapped chromium — plain or-wv, never both), proved to fail by neutering the overlay's regex: reports "found 2", names both, and warns off the tempting "fix" of dropping enableWideVine (which silently kills DRM). - I overstated this, and measuring the artifact corrected it. I claimed
−687 MiB "on every install". True savings, all measured:
nominal closure −687 MiB (9.38→8.71 GiB), ISO −8 KiB of 8.078 GiB,
installed disk ~−19 MiB, cache-install download −195 MiB. Two
dedupes that closure arithmetic cannot see: mksquashfs detects duplicate
files (the
-wvcopy iscp -aof the plain build, so the ISO stored the blocks once), and auto-optimise-store hardlinks identical files — the two paths share inodes (verified bystat;ducounts 639 MiB for the pair vs ~620 for one). Only the wire can't dedupe: 195 MiB compressed NAR. - The rule this establishes: closure size is not disk size and is not image size. Measure the artifact. Directly relevant to #120, whose whole size table is closure arithmetic — noted there.
- So the fix is a download win (which is what #120's netinstall wants) and ~nothing for today's offline ISO. Whether that is worth coupling an overlay to nixpkgs' wrapper internals is Bernardo's call — raised, not assumed; it is guarded and no-ops if upstream moves. Worth an upstream patch regardless (the wrapper should take its desktop entry from the variant it wraps).
- Pending: nothing hardware-blocked. #120's size table updated (desktop is 13.34 GiB post-#121, not 14.01) and carries the closure-vs-artifact caveat.
- Next suggestion: #118 (smartd self-gate) — Bernardo's stated order.
2026-07-14 — #103: the live ISO gets a desktop, for +41 MiB (this commit)
- Task: BACKLOG #103 — Bernardo, live ISO 2026-07-14: still no browser, no office. "That makes a live iso useful."
- Did: the live HM user in
flake.nixnow names its own set — chromium, libreoffice-fresh, gnome-text-editor, amberol, snapshot. Firefox dropped (Bernardo's call): chromium owns the HTTP mime default and ships in the installed template, and it was the one item that would cost a real closure. - The finding that inverted the trade: I asked Bernardo to choose on a
~+2 GB premise. Wrong premise —
system.extraDependenciesalready pins the template's HM closure into the ISO for offline installs, so chromium/ libreoffice/amberol were already in the image's store, just absent from the live user's profile. Verified, not assumed: the live and template chromium resolve to the same store path, so reusing the template's exactchromium.override { enableWideVine = true; }costs zero — a plainchromiumwould have been a second 2.5 GiB closure. Only text-editor and snapshot are new: 9 paths, 133 MiB uncompressed (99 MiB is gst-plugins-rs). His Firefox call still held for the right reason — it was genuinely unpinned. - Verified: V2 — measured ISO delta (the item's pass condition), both
built from the same tree: 8.038 → 8.078 GiB = +41.2 MiB (+0.50%).
New
checks.live-baseline-appsasserts each app is on PATH and has a .desktop the launcher can see (a bin without one is invisible), that HTTPS resolves to a chromium entry that is actually present (#94's trap), and that Firefox has not crept back. Proved to fail: dropping snapshot makes it name the missing entry. flake check + live-install-entry + option-docs + template-sot green. - Pending: V3 — that the apps launch needs hardware (HARDWARE-QUEUE,
Acer M5-481T: from the launcher only, no terminal). New #119:
text/plainnames vscode, which the live ISO never ships — #94's bug one mime key over, and now the last of its kind. - Where the 8 GiB actually goes (Bernardo asked how Debian fits one in 4 GB;
I first blamed the offline-install pin and that was wrong — measured, the
pin is 4.02 of 18.03 GiB uncompressed, ~22%). The live desktop itself is
14.01 GiB: libreoffice 1457 MiB, initrd 1369, linux-firmware 770, mesa,
fonts, two chromiums (see #121). Debian fits ~4 GB by installing by copying
the live filesystem (no second closure) and by sharing one library version
archive-wide, where Nix pins exact deps per package. Compression is not the
gap — we already use
zstd -19(2.23:1). Bernardo's call: keep the offline ISO as is, add a netinstall variant → #120 (NEXT). Filed #121: the Widevine chromium wrapper drags a second 687 MiB unwrapped chromium in for itsshare/applicationsalone — pre-existing, on every installed machine. - Next suggestion: #118 (smartd self-gate) — Bernardo's stated order.
2026-07-14 — triage: #117 is not work, it's an input to #110 (this commit)
- Task: Bernardo's call on #117 (filed by the previous entry, which suggested it as the next item — it is not; that suggestion is stale).
- Did: Control Center is being retired (#110, NEXT,
[big]), so fixing its toggles builds on a condemned surface. #117 stays filed as a record feeding #110's migration matrix, marked not-standalone. Gave #110 the facts #116 turned up: its Bluetooth/Printing rows write state keys that only became live ina9f3a64, so those two toggles never worked for anyone — meaning there is no behavior to preserve, but the keys and their bridges are real now and must not be dropped with the rows, or a machine whose state saysbluetooth.enable = falsesilently flips back on at the next rebuild.checks.state-bridgeswill fail loudly if that happens. - Verified: V0 —
nix flake check --no-build. Backlog/journal only. - Next suggestion: #110 (the retirement itself, needs splitting first) or
#115 suspend-then-hibernate — both
[human]-gated on a design question.
2026-07-14 — #116: the state bridges that never were (a9f3a64)
- Task: BACKLOG #116 — NixOS options defaulting from
config.nomarchy.settings, an attribute that exists only on the HM side. - Did:
nomarchy.settingsis declared in exactly ONE place (modules/home/options.nix:412), soor <fallback>had been swallowing a missing-attribute error on the NixOS side forever. Options now declare a static default and the implementing module reads the state viastate-read.nix+lib.mkIf (state != null) (lib.mkDefault state)— done forbluetooth.enable(default.nix) andservices.printing.enable(services.nix).batteryChargeLimit's read is simply deleted: power.nix's oneshot reads the key withjqat runtime, which is why that menu worked. greeter.nix moved off a rawfromJSONonto the fail-closed reader. - The finding that mattered: the item said "three options … benign today"
and both halves were wrong. There were four (it grepped
options.nix, notmodules/nixos/— the same mistake in miniature as the bug it filed), and two were live user-facing bugs: Control Center's Bluetooth and Printing toggles wrote state nothing read and printed "requires rebuild", so they reported success and did nothing, for as long as they had existed. - Verified: V2. Before/after eval on the same flipped state proves
the bug was real: BEFORE
hardware.bluetooth.enable=true+printing=false(toggle inert); AFTER both flip, and a hand-set value still outranks the state. Permanent guards, since nothing in a build fails when a bridge dies:checks.state-bridges(11 eval assertions — absent key → default, state → config, hand-set → wins) andchecks.printing-from-state, a runNixOSTest whose node's ONLY input is the state file and which waits for a runningcups.service(+ avahi). The guard was proved to fail: re-breaking the bluetooth bridge made it throw, naming both broken assertions — a check that cannot fail is worse than none (625b7e3's lesson, applied). V0 flake check; option-docs, template-sot, downstream-template-{system,home}, installer-safety, hardware-toggles, battery-charge-limit all green. - Pending: no V3 — the mechanism is fully proved headlessly. New #117 (PROPOSED): the control-center toggles still leave the rebuild to the user, unlike every menu toggle since; a user can't tell "needs a rebuild" from "broken again", which is the symptom #116 just removed.
- Next suggestion: #117 (needs Bernardo's call: rebuild per-toggle vs one
apply-at-exit), or #115 suspend-then-hibernate — also
[human]-gated, and its state read now has a worked shape to copy.
The five entries below were reconstructed from the commits on 2026-07-14 after a session crash — the work was committed and pushed, and each commit did its own sync sweep (BACKLOG #115/#116, HARDWARE-QUEUE, docs); only the journal was missing. Written from the commit messages, not from memory.
2026-07-14 — one fingerprint switch, an auto-login toggle, the state bridge (eb38008)
- Task: Bernardo, post-reboot: "Use for login" was the wrong question — whether the finger works is one decision, and whether login prompts at all is a different one that was never in the menu.
- Did: System › Fingerprint is now a single on/off switch (enroll/list/
verify/delete demoted to plumbing behind it) writing the one
settings.fingerprint.pamkey;idle.nixdefaultsidle.fingerprintfrom that same key, so lock screen and login/sudo move together. New System › Auto-login (nomarchy-autologin), installer-seeded ON for LUKS machines. Making both state-owned surfaced two real bugs:greeter.autoLogindefaulted fromconfig.nomarchy.settings…, an attribute that exists ONLY on the HM side, andor nullswallowed it — the state path never worked on any machine ever built; andstate-sync getprinted Python'sNonefor a JSON null, so anycase … null)would miss. - Verified: V1 — flake check, installer-safety, option-docs pass.
Proved by eval/build: a state carrying autoLogin yields greetd
initial_session, template state yields none, a hand-set null beats the state;fingerprint.pam=truealone renders hyprlock's auth block; both tools bash -n clean and land in systemPackages; the get round trip printsnull. - Pending: V3 — HARDWARE-QUEUE "fingerprint + auto-login toggles on
hardware" (T14s, after unpinning the two system.nix lines). Filed #116
(two more NixOS options read the same phantom bridge — a grep for
config.nomarchy.settingsundermodules/nixos/should return nothing when done) and #115 (suspend-then-hibernate,[human]on delay/AC policy). - Next suggestion: #116 — the worked example is in the tree and the two remaining reads are known.
2026-07-14 — a real lock bind, and a lock screen that speaks in sentences (9792976)
- Task: two nits from the post-reboot hardware pass.
- Did: Super+Escape never locked anything — there was no lock bind at all,
only the power menu's Lock row and the idle timeout. Lock now lives at
Super+Ctrl+L (bare Super+L collides with common app binds), dispatching
loginctl lock-session— the power menu's path, so hypridle'slock_cmdstays the single place deciding what a lock looks like. The prompt's clipped fragments are sentences now, placeholder sentence-cased to match. - Verified: V1 — flake check; the built home generation carries the
bind, the new ready/present messages (built with
idle.fingerprintforced on, since the in-repo config leaves it off), and a cheatsheet row the generator produced on its own from the shared list. - Pending: V3 — the reader itself only exists on hardware.
- Next suggestion: the fingerprint/auto-login menu surface (became
eb38008).
2026-07-14 — put the fingerprint hint where it can be seen (fbbeac6)
- Task:
e2de906fixed the invisible reader and left an invisible message — Bernardo: "unlock worked, but still no message", same symptom as before the fix, completely different cause. - Did: the lock screen is deliberately clock-only — the input field fades
out while empty (hyprlock's
fade_on_emptydefault), so$FPRINTPROMPTin its placeholder rendered faithfully into a widget nobody sees until they had already given up on the finger and started typing. Moved to a label; the placeholder goes back to its exact previous string, so the non-fingerprint path is unchanged. - The lesson: I assumed the field was visible and reasoned from there. It
has never been visible — "it has always been like this" is what cracked it.
Both candidate surfaces (label vs
fade_on_empty=false) were tested on hardware rather than picked; Bernardo chose the label, which keeps the clock-only look instead of making opting into fingerprint mean permanently gaining a widget the design never had. - Verified: V2 — flake check; checks.theme-contrast + option-docs pass
(
subtext-on-baseis held to a 3.0 floor on all 21 themes by the guard that exists because two themes once shipped subtext == base — the same bug as this commit, one layer down). V3 — Bernardo confirms the line reads. - Next suggestion: the lock bind + prompt copy nits (became
9792976).
2026-07-14 — unlock by fingerprint; hyprlock never used the PAM flag (e2de906)
- Task: Bernardo tested the lock screen with
fingerprint.pamon — sudo took a finger, hyprlock did nothing. - Did: the PAM stack was never the problem (grosshack sits in
/etc/pam.d/hyprlockat order 11400 exactly like sudo's) — hyprlock just never asks it: its PAM conversation runs only on submit, so a module wanting to prompt while polling the reader never gets a turn. It has its own fprintd-over-D-Bus backend behindauth:fingerprint:enabled, which nothing in the distro ever set. Newnomarchy.idle.fingerprint(default false), mirroringhardware.fingerprint.pamthe waykeyboard.layoutmirrors the xkb option — hyprlock is configured in standalone HM, which has noosConfig. Opt-in, because with no reader hyprlock advertises a scan that cannot happen. - Verified: V2 — flake check; checks.option-docs passes (failed first with "undocumented option", the check doing its job).
- Pending: V3 — Bernardo applies and confirms both factors work.
- Next suggestion: confirm the prompt actually renders (it did not —
fbbeac6).
2026-07-14 — parallel fingerprint: 3 of 4 counts confirmed, 1 removed as a trap (625b7e3)
- Task: HARDWARE-QUEUE "parallel fingerprint-or-password on the real
reader" (Bernardo, AMD dev box, gen 422,
fingerprint.pam = true). - Did: confirmed on the real reader: one prompt, typed password works,
sensor works, wrong-finger ×3 falls back to password. The fourth count —
"password keeps working with fprintd stopped" — is removed rather than
checked off: fprintd is D-Bus activated, so
systemctl stopdoes not keep it down. Bernardo ran it and the fingerprint still worked, which is exactly the evidence the daemon came back and the dead-reader path was never exercised. A check that passes whether or not the property holds is worse than no check. The property needs no hardware anyway: password isauth sufficientat 11700, independent of the fprintd rule at 11400 — visible by eval, asserted by checks.hardware-toggles in a reader-less VM. - Verified: V3 (hardware, Bernardo) for the three counts; docs-only commit.
- Pending: still open on that item — hyprlock, the greeter (needs the
reboot), and
fingerprint.parallel = falserestoring sequential behavior. - Next suggestion: the hyprlock half (became
e2de906).
2026-07-14 — docking round 7 FAILED; the keyword was inert, not raced (this commit)
- Task: HARDWARE-QUEUE docking round 7 result (Bernardo, AMD dev box) — 5–6 consecutive unplugs, the panel never came back. Round 6's fix did nothing because round 6's diagnosis was wrong.
- Did: Probed it live instead of re-reading the journal. With ZERO enabled
outputs,
hyprctl keyword monitor eDP-1,preferred,auto,1is inert — accepted,ok, exit 0, and never flushed until a DRM event arrives. Not a race: inert across 4s and 5s in two runs.dispatch forcerendererreloadis inert too; onlyhyprctl reloadescapes (99ms / 289ms, cable out). So the transition issues the keyword, and escalates toreloadonly whenmonitorsproves it inert — then re-asserts the rule and callsnomarchy-keyboard-layout restoreper device, since a reload drops runtimedevice[…]:kb_layoutkeywords. Also made the menu'senableprove itself. - The lesson, worth more than the fix: round 6 built its race theory on
enable-timeout×2 +result=ok×1, and I extended it with a "phantom re-add" theory from theadded= DP-2lines. Both were the same artifact: everyresult=okwas Bernardo replugging the cable because the screen was black — his hotplug flushed the queued rule and the next poll claimed the win. A watcher whose success is indistinguishable from the user working around it will keep confirming whatever story you bring. The probe cost 10 minutes and killed two rounds of theory. - Verified: V3 (partial) — the fixed
nomarchy-display-transition undock eDP-1driven through two real unplugs on the dev box: panel on, workspaces 1–3 home, 1.8s,keyword=inert escalate=reload→enable=via-reload→result=ok. Keyboard-restore proven too, on a K400 whose receiver is in the laptop (so it survives the cable): kept its rememberedus, while a control barehyprctl reloaddropped it to the sessiongb— the clobber was an inference until measured, and it makesrestore_keyboardsload-bearing. Plus V2:nix flake check --no-buildall pass;checks.docking-ux+checks.dock-audio+monitor-fallback.nixpass; shellcheck clean on display-transition (profile-watch's lone SC2125 is pre-existing). - Pending: HARDWARE-QUEUE round 8 — the watcher-driven path needs a relogin (exec-once, baked store path) and repetition (5+ unplugs, one with the lid shut). New BACKLOG #114 (PROPOSED): tuigreet ignores per-device layouts.
- Next suggestion: #114, or the dock direction's unverified panel-off (it disables the panel trusting hyprctl's exit code — same class, latent).
2026-07-14 — docking round 6: undock left the laptop panel black (superseded by round 7 above)
- Task: HARDWARE-QUEUE docking round 6 result (Bernardo, AMD dev box). Plug side all passed (auto-dock, audio to the monitor, wallpaper on the external); unplugging left the panel black until re-docked.
- Did: Bernardo's journal was decisive — 3 undocks, 2×
result=enable-timeout+ 1×result=ok, so an intermittent race. Two fixes in modules/home/hyprland.nix: (1) the undockhyprctl keyword monitor eDP-1,preferred,auto,1exits 0 but is dropped when it lands mid-teardown of the departing external — now re-issued every poll for 5s, withmonitorslisting the panel as the only proof; (2) the watcher marked the departure handled via"$TRANSITION" undock … || true+awaiting_lid_open=1andknown_outputshad already moved, so nothing ever retried — one lost keyword = a dark panel. The undock is now a queued invariant driven on the 1s tick (6 attempts, thenresult=gave-up). - Verified: V2 —
nix flake check --no-buildall checks passed;nix build --impure -f tools/monitor-fallback.nixexit 0 in 57s (reaches the finallid-open transitioncheckpoint); shellcheck clean on both generated scripts (the lone SC2125 is pre-existing + intentional). Honest limit: the harness CANNOT reach this race — QEMU's headless backend aborts Hyprland if the last active output is deleted while the DRM output is disabled, so it must undock before removing DP-1 and never collides the two. The fix itself is V3 pending; comment added at tools/monitor-fallback.nix so a reader doesn't mistake a pass for coverage. - Pending: V3 → HARDWARE-QUEUE round 7 (unplug ≥5×; old failure was only ~2 in 3). Rounds 4–6 opened 5 counts: 4 are now confirmed fixed on hardware (wallpaper, auto-dock, monitor audio, keyboard prompting once — Bernardo), the undock is this commit, and headphone jack-follow is still untested — now its own entry, to fold into the round 7 session.
- Next suggestion: wait on round 7 before touching the dock path again.
2026-07-13 — #99 live-seed git-init; theme-switch failure filed as #113 (this commit)
- Task: BACKLOG #99 — false "state.json NOT git-tracked" doctor/ Waybar warning in the live session; resolve the held question from Fable.
- Did: hosts/live.nix
nomarchy-seed-flakenowgit init+add+commits the seeded~/.nomarchy(like nomarchy-install.sh:654), so the live checkout is a committed repo. Also committed #94's live-posture comment in flake.nix (separate commit). - Verified: V2 — focused serial-log VM run (
/tmp/nomarchy-v2-theme-99/): doctor prints✔ state.json is git-tracked+✔ flake checkout is clean,GIT_REPO_OK/TRACKED_OKmarkers. Held question RESOLVED: the same run's offline gruvbox switch failed with a 1176-drv source rebuild, but a local drv-equivalence test proved the failingbvl30ggn…home-manager-generation.drvis BYTE-IDENTICAL path-seeded vs git-seeded → the git-seed is exonerated; the failure is a pre-existing ISO-pinning gap (unpinned non-default-theme generation), now filed as #113. - Pending: #113 (offline theme-switch contract); #94 launch check; #97 V2 click; #96 V3 + #101 round 2 (HARDWARE-QUEUE).
- Next suggestion: #113 — decide pin-all-themes vs scope the offline promise.
2026-07-13 — #96+#97 menu gates explain instead of vanish/raw-fail (this commit)
- Task: BACKLOG #96 (battery-limit row silently absent on threshold-less firmware) and #97 (raw "Connection to BlueZ failed").
- Did: rofi.nix — Battery limit row now gates on
has_system_battery(like Power profile); the leaf explains a missingcharge_control_end_thresholdas a firmware capability. Bluetooth leaf checksbluetooth.servicebefore exec'ing blueman and explains the service-down vs no-adapter (/sys/class/bluetoothempty) cases with rfkill/firmware hints. - Verified: V1 — built nomarchy-menu, bash -n green, both new paths present in the generated script; V0 flake check green. VM can't fake a threshold-less battery or a BT adapter, so the behavioral checks are queued: #96 → HARDWARE-QUEUE (Acer + T14s row check); #97 → the no-adapter message is exercisable in the next QEMU run (planned with #94's test-install pass; VMs have no BT adapter).
- Pending: #97 V2 click-check in the next VM run; #96 V3 on the Acer.
- Next suggestion: #94 test-install run (chromium launch + BT click).
2026-07-13 — #107 direct System/Tools menu keybinds (this commit)
- Task: BACKLOG #107 — conflict-free direct bindings via keybinds.nix.
- Did:
SUPER+CTRL+I→nomarchy-menu system(Super+I settings muscle memory),SUPER+CTRL+T→nomarchy-menu toolsin keybinds.nix (single source: Hyprland + cheatsheet); root-menu Tools/System rows now carrymenuHintshortcut hints. - Verified: V2 — eval: 41 binds, zero duplicate mods+key; both binds in
the generated Hyprland config; built nomarchy-menu bash -n green with
cheatsheet rows + hints rendered. In-session on the live ISO: VIEWED
/tmp/nomarchy-v2-swap-93/40-system-menu.png+41-tools-menu.png— both submenus open directly from the binds. V0 flake check green. - Pending: nothing.
- Next suggestion: #99 pending the focused doctor/theme-switch VM run.
2026-07-13 — #93 installer swap prompt labeled + explained (this commit)
- Task: BACKLOG #93 — the swap field was a bare prefilled gum input (no visible section, label, or unit; the placeholder never shows once a value is prefilled).
- Did:
nomarchy-install.sh: visible "Swap & hibernation" section, two info lines (default = RAM ⇒ hibernation-ready; 0 = no swap), a labeled--headeron the input, and unambiguous info + Review lines ("N GiB swapfile (enables hibernation)" / "none (hibernation disabled)"). - Verified: V2 — full interactive KVM UI drive on the built ISO; VIEWED
/tmp/nomarchy-v2-swap-93/10-swap-prompt.png(section, both info lines, labeled prefilled input) and…/30-doctor.png(Review box: "Swap: 6 GiB swapfile (enables hibernation)"); wipe confirm aborted by mismatch, nothing touched. bash -n + V0 flake check green. - Pending: side-finding: QEMU exposed
/dev/fd0as the FIRST picker row — recorded as live repro evidence on #112. - Next suggestion: #99/#107 commits from the same evidence run.
2026-07-13 — charge-limit start-limit-hit on spaced AC storms (this commit)
- Task: Live V3 failure of #101 (TuringMachine doctor badge, 18:16): a
spaced dock/AC event storm → 5 successful starts in 10s →
start-limit-hit, unit marked failed though every run succeeded. - Did:
unitConfig.StartLimitIntervalSec = 0onnomarchy-battery-charge-limit(idempotent sub-second write — rate limiting only manufactures false failures); extendedchecks.battery-charge-limitwith the exemption assert + an 8× sequential start loop and a clean-state check. - Verified: V2 — the check passes under KVM (exit 0: exemption asserted, 8 spaced starts, not failed, no start-limit-hit; original coalescing phase still green). V0 flake check green.
- Pending: V3 round 2 re-queued in HARDWARE-QUEUE (#101 entry updated).
- Next suggestion: land the in-flight #93/#99/#107 evidence run.
2026-07-13 — #102 Nextcloud Desktop opt-in in the template (this commit)
- Task: BACKLOG #102 — document upstream HM
services.nextcloud-clientas a downstream-template opt-in; no Nomarchy wrapper. - Did: Commented
services.nextcloud-clientblock intemplates/downstream/home.nix(enable + startInBackground), and pointed the bare# nextcloud-clientpackage line at it (service = app + session lifecycle; re-comment removes both). - Verified: V1 — pinned HM 26.05 module confirmed
(enable/package/startInBackground); eval test on an uncommented template
copy via
lib.mkFlake: unit ExecStartnextcloud --background, WantedBy/PartOfgraphical-session.target.nix flake check --no-buildgreen (includes template-sot + downstream-template-home). - Pending: nothing — runtime lifecycle is the upstream module's contract.
- Next suggestion: #93/#99/#107 land next (shared live-VM evidence run).
2026-07-13 — User-promoted NEXT queue curation (#102–#112; this commit)
- Task: Audit Bernardo's live-ISO, application, menu, and device follow-ups against shipped behavior and curate the executable queue.
- Did: Promoted scoped work as NEXT #102–#112, with
[big]split gates for System-menu IA and Control Center retirement. Reused NOW #96 for the Acer threshold finding; #106/#108 start from shipped navigation/bind coverage. - Verified: V0 — read-only source/option/menu audit and
git diff --check. - Pending: #105 and #110 must be split before implementation; no runtime behavior changed.
- Next suggestion: #93 remains the NOW head; #102 is the first NEXT item.
2026-07-13 — #92 catalog-only installer keyboard selection (this commit)
- Task: Make installer layout/variant choices understandable without allowing arbitrary XKB values to break generated Nix.
- Did: Added a pinned human-readable XKB catalog, a one-step US/default path, strict searchable layout/variant pickers, shared exact validation for interactive and unattended input, and a resolved review summary.
- Verified: V2 — full flake eval; installer safety/keyboard/package builds; shell/Python/diff checks; real validator accepts valid layout-specific rows and rejects fabricated/prefix/wrong-layout values before installer setup. Exact-current-ISO KVM UI review captured catalog, variant, and review screens; strict unmatched input was rejected and the blank disk remained untouched.
- Pending: V3 real-hardware install remains; V2 artifacts are under
/tmp/nomarchy-v2-keyboard-92-current/. - Next suggestion: #93 swap-size prompt and explanation.
2026-07-13 — #91 installer no-variant normalization (this commit)
- Task: Stop the keyboard picker's display-only
(none)value from breaking generatedxkb-console-keymap.drvand the whole installation. - Did: Normalize at the shared input boundary and defensively in the real
template patcher. Added a
us+ sentinel fixture, actual console-keymap build, and made the offline installer VM carry the literal sentinel. - Verified: V2 — full flake eval; focused installer-keyboard/safety/
template builds; shell/Python/Nix syntax and diff checks; KVM
tools/test-install.shinstalled offline with LUKS + swap, powered off after ~400s, unlocked, and booted the themed desktop. Inspected install progress, LUKS, and first-boot captures under/tmp/nomarchy-vm/. - Pending: #92 now explicitly forbids free-form XKB values. Expanded the existing per-device keyboard hardware check for the connected-at-login menu.
- Next suggestion: #92 installer keyboard selection clarity/safety.
2026-07-13 — #101 charge-limit AC-event burst recovery (this commit)
- Task: Fix
nomarchy-battery-charge-limit.servicefailing when USB-C dock power events arrive while its settling write is still active. - Did: The oneshot now returns inactive after success; immediate and
delayed udev paths use coalescing
startjobs instead of interruptingrestartjobs. Strengthened the focused VM with a 12-event Mains burst during an extended active run and explicit failed/start-limit assertions. - Verified: V0
nix flake check --no-build, module parse, andgit diff --check; V2nix build .#checks.x86_64-linux.battery-charge-limit --no-link -Lunder KVM — the 12-event active-run burst finished inactive/success, changed InvocationID, and produced no failed/start-limit journal result. - Pending: V3 post-rebuild dock-power burst check in HARDWARE-QUEUE.
- Next suggestion: run V3 #101 alongside docking round 4, then #91.
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.
monitoraddednow 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; andnix build --impure -f tools/monitor-fallback.nix --no-link -Lall 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 --checkgreen. - Pending: implementation and item-specific V1–V3 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-uxand synced README/template/ROADMAP/hardware queue. - Verified: V1 —
nix flake check --no-build;checks.docking-uxbuilt 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 todocs/ROADMAP.md's known issues noting that certain Electron apps cannot be natively themed. Closed out #89 from the backlog without introducing brittleapp.asarrepacking 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-buildpeaks 6.0 GB RSS — that's the whole story. Newtools/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 — landed8fded63on 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 -Swith 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_blackoutin 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 → " 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 — state-sync's commit is pathspec-limited to state.json by design. - Did: New internal
nomarchy-autocommitin nomarchy-lifecycle: live-readssettings.autoCommit, commits everything dirty with messagenomarchy: auto-commit before <label>+ file list in the body; called (|| true, never blocks) at the top of nomarchy-pull / -rebuild / -home. Exposed aspassthru.autocommit; package exported. Docs/comments swept: README, RECOVERY, ROADMAP ✓ entry, rofi toggle text, control-center prompt, state-sync docstring. - Verified: V1+ —
nix flake check --no-buildgreen; new permanentchecks.lifecycle-autocommitbuilds (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-iconschild 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 viachecked.colors.text. iconTheme feeds stylix+rofi, both fine via Inherits. Fixed a slip:git add -Aswept 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 16–32px; 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
ac7e6bdbroke 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'sgtk-menu-imagesdefault-off: setgtk.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
@swapswapfile): 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-symbolicfine 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 towindow#waybarin 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: 0as 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-menuentry points (main, battery, power-profile, VPN) showed rofi's "Binding 'Left' is already bound" error dialog instead of a menu. - Did:
rofi.nix— releasekb-move-char-backtoControl+bbefore binding-kb-custom-1 Left, in bothrofi_menucopies (menu + vpn). rofi hard-fails on duplicate bindings, and reports it in a GUI dialog, not stderr — stub tests andbash -ncan 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-menurenders 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
05bab55session 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 menurofi_menuno-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
~/.nomarchylock still pinned the previous commit — the user's rebuild excluded this batch (mic LED "regression" was just that). Also: HMprograms.chromium.extensionsfrom the old config wasn't carried over, so Chromium externally-uninstalled all extensions and their data (wallets included); recovered from thepre-nomarchy-homebtrfs snapshot. MIGRATION.md browser note rewritten with the real mechanism. - Next suggestion: V3 sweep of the
05bab55items 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 invalidvar()CSS; now Boreal-style glass with@colors, cyan edge, soft selection). btop accent titles/selection; JSON ui rounding 14 + slight glass opacity;preview.pngfrom 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 iteration’s 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) viamodules/nixos/dock-audio-rules.nix+ default.nix pipewire.checks.dock-audiopure rule asserts + conf-file VM. V3 hotplug steps in HARDWARE-QUEUE. Closed #87. - Verified: V2 —
nix flake check --no-build;checks.dock-audiogreen (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=ignoreinmodules/nixos/power.nix(logind settings.Login). Undocked lid behaviour unchanged. idle.nix comment corrected.checks.clamshell-logindasserts conf + active logind. V3 steps in HARDWARE-QUEUE. Closed #86. - Verified: V2 —
nix flake check --no-build;checks.clamshell-logindgreen (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.logis present and no Home Manager generation exists → ✖ +home-manager switch --flake ~/.nomarchy -b bak. Skip/ok otherwise. Extendedchecks.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-changedwith 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.firstBootShownvia theme-sync--no-switch(in-checkout state). Skip live hostname. Optionnomarchy.firstBootWelcome.enable(default on).checks.first-boot. ROADMAP/VISION/README; closed #81.
- Doctor pointers; marker
- Verified: V2 —
nix flake check --no-build;checks.first-bootgreen (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/designorenergy_*) as% of design; system batteries only; soft warn <70% design; skip when attrs absent.NOMARCHY_POWER_SUPPLY_ROOTfor the VM fixture. Extendedchecks.doctor(fake BAT0 + Device-scope MOUSE0 ignore). HARDWARE §10, ROADMAP ✓, VISION ✓; closed #80. - Verified: V2 —
nix flake check --no-build;checks.doctorgreen; 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'sunit=and the live-state ExecCondition follow via oneunitlet-binding. Template example lines, README row, ROADMAP ✓. Newchecks.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-buildexit 0 (evals the new asserts + option-docs); builtdownstream-template-home(default hyprsunset path unregressed) + the check drv. Caught en route: HM rendersExecStartas a list (toStringneeded 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.mdentry (CLAUDE.md → symlink). Skill bodies moved toagent/: 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 frontmatter’d shim)..claude/is a thin adapter (shims route intoagent/). Maps updated (agent/, docs/, README tree). Stale:.gitignoreold_distro entry dropped; local result*/pycache removed. JOURNAL rotated (29 kept, 120 → JOURNAL-ARCHIVE.md). - Verified: V0 —
nix flake check --no-buildexit 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-computedresume_offsetcan't reach the boot cmdline (the genuine chicken-and-egg). First cut also had an unboundedwait_for_shutdownthat hung → killed it, bounded the wait in a thread (180s) + aCanHibernatepre-check, which is what surfaced the clean verdict. Pivotedchecks.hibernate-swapfileto what a VM can prove deterministically and the partition test can't: the installer swapfile build + offset — NOCOWmkswapfile, file-type swapon, validmap-swapfile -roffset accepted by/sys/power/resume_offset, zram above it. (Device fix:/dev/vdbonceuseNixStoreImagewas 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 thenot betweenshortcut with a real wrap-aroundmins >= sunrise or mins < sunset, so a cross-midnight day window switches both ways. (2)rofi.nixautotheme HH:MM guard tightened[0-2][0-9]→[01][0-9]|2[0-3]so 24–29 are rejected. Dismissed thebreezefinding (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 --whichnormal-case unchanged; menu bash -n; flake check green. Normal case unchanged sochecks.auto-themestill 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-themerunNixOSTest: installs nomarchy-state-sync, pointsNOMARCHY_DEFAULT_THEMESat presets, stubs the switch viaNOMARCHY_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-themefresh, 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 + anautotheme)submenu: toggle, pick day/night (fromnomarchy-state-sync list), set sunrise/sunset (HH:MM input, validated). Enable writes the flag + defaults the summer pair--no-switch, thenexec auto --force— one rebuild installs the timer AND applies the right theme. Disable is instant--no-switch(autoself-gates; the lingering timer no-ops). Day/night/times are live--no-switch. - Verified: V1 — HM generation builds (
writeShellScriptBinbash -n on nomarchy-menu passes) + bash -n on the built menu. Logic test (stubbed rofi/theme-sync/notify): selecting "Auto theme (off)" runs exactlyset day summer-day,set night summer-night,set enable true(all--no-switch), thenauto --force— the intended one-rebuild path. Disable path is static-clear (set false--no-switch, noauto); 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 onconfig.nomarchy.settings.autoTheme.enable or false(state-driven, like updates.nix gates on its enable). Service runsnomarchy-state-sync autowith a PATH forhome-manager; timerOnStartupSec=1min+OnCalendar=*:0/15+Persistent. Chose periodic over exact sunrise/sunset timers — robust to suspend/DST, andautois idempotent so ticks are cheap (rebuild only at the transition). - Verified: V1 — real-config eval (state temp-enabled, restored):
settings.autoTheme.enable→true, timerOnCalendar=*:0/15, service ExecStart=… nomarchy-state-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 untilgit add— flake eval only sees tracked files.) - Pending: live timer→
home-manager switchon 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-state-sync auto— readssettings.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).--whichprints the decision without switching;--force/--no-switchtoo. Factoredcmd_apply's core intoapply_namedsoautoreuses 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:00–00:01 window→night,
disabled→no-op, missing day/night→die,
auto --no-switchwrites state, re-run→"already on" no-op, plainapplystill writes (refactor intact). V0 py_compile + flake check +checks.state-sync-validategreen. - 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).