# 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](JOURNAL-ARCHIVE.md) (history, never edited). Template: ```markdown ## YYYY-MM-DD — () - **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-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:** V1 — 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. KVM boot of the exact current ISO proved the packaged installer contains the new flow; interactive screenshot pass was still running at commit time. - **Pending:** Complete the already-running pre-destructive KVM UI review. - **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 generated `xkb-console-keymap.drv` and 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.sh` installed 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.service` failing 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 `start` jobs instead of interrupting `restart` jobs. 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, and `git diff --check`; V2 `nix build .#checks.x86_64-linux.battery-charge-limit --no-link -L` under 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. `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 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-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 → " 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