All checks were successful
Check / eval (push) Successful in 3m30s
The "blank + hypridle deadlock = the brick" cause published this morning is retracted everywhere it was asserted: ROADMAP, hyprland.nix's comment, #146, HARDWARE-QUEUE and two commit messages (a2151f4,321ccf7). It rested on two pieces of evidence and both were artifacts of how I measured: - "19 disconnects in 11 days": 18 of 19 are hypridle's noisy goodbye while systemd DELIBERATELY stops it — each bracketed by `Stopped hypridle` / `Started hypridle`, healthy replacement seconds later. - "Jul 14: CRITICAL at 13:08:17, then eleven hours of silence": an artifact of grepping ONE PID. systemd logged `Stopped hypridle` 13:08:17 and `Started hypridle` 13:09:00; PID 1678 ran fine all evening, invisible to the filter. Decisive: at the incident (before the 12:51:34 mitigation commit) hypridle had NO disconnect at all and had been healthy since Jul 14 13:09. It should have fired on-resume normally. The deadlock theory never had a case. The FIX stands on its own evidence and is untouched: the options really were off, hypridle's on-resume really was the only caller of `dpms on`, and input now wakes the screen with hypridle deliberately stopped (4s docked / 6s clamshell). Removing a proven single point of failure never needed a story about why the daemon might fail — which is exactly why it survived the story being wrong. #127 is RESTORED to NOW (deleted this morning as "shipped"; only the fix shipped). Its cause is open and the lead is the dead Ctrl+Alt+F3 — neither DPMS-off nor a dead hypridle can break VT switching, so something was wedged below the compositor holding DRM master. Every theory so far has been about the wake path, i.e. a symptom of the screen already being black. #146 → [watch], near-dead: one genuine zombie ever (verified by ps/ss, not grep); upstream #171 is real but its impact path closed when #147's stray linger went. Re-measure properly before building anything; close unbuilt if zero. Also closes the #127 hardware-queue entry: Bernardo ran the real 10-min idle — 19:27:58 dpms off (genuine timeout, shipped config, and it BLANKED = the revert working) -> mouse -> 19:32:14 `done enabled=1 first=DP-2`, clamshell, the incident geometry, one healthy hypridle throughout. All 4 steps pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1801 lines
116 KiB
Markdown
1801 lines
116 KiB
Markdown
# 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 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-16 — RETRACTION: the #127 diagnosis was as wrong as the test it replaced
|
||
- **Task:** Bernardo said "do #147 first, then #146". Both dissolved under
|
||
investigation, and taking them apart disproved the #127 *cause* I had shipped
|
||
hours earlier. The fix stands; the story around it did not. Sweep = retract.
|
||
- **The retraction, and it is the whole entry.** I published "blank + hypridle
|
||
deadlock = the brick" into ROADMAP, hyprland.nix's comment, #146 and two commit
|
||
messages, on two pieces of evidence: "19 disconnects in 11 days" and Jul 14's
|
||
"eleven hours of silence". **Both were artifacts of my own measurement.** 18 of
|
||
19 disconnects are hypridle's goodbye while systemd *deliberately stops it*
|
||
(each bracketed by `Stopped`/`Started`, healthy replacement seconds later). The
|
||
"silence" was a grep for **one PID** — systemd logged `Started hypridle` 43s
|
||
later and PID 1678 ran fine all evening, invisible to my filter. **Decisive:**
|
||
at the incident hypridle had **no disconnect at all**, healthy since Jul 14
|
||
13:09. The theory never had a case.
|
||
- **The irony is the lesson.** I spent the morning writing up "the invalid TEST B
|
||
measured its own scaffolding — put the mechanism inside the circuit", then did
|
||
exactly that twice more: inferred a lid position from an output list, inferred
|
||
"the session wiring is missing" from a grep that never covered HM's generated
|
||
conf. Three wrong claims, all from inferring where checking was cheap; Bernardo
|
||
caught all three. **Verify the instrument before believing the reading —
|
||
hardest when the reading agrees with you.**
|
||
- **#147 → not a distro bug.** The wiring exists (HM's `systemd.enable`, line 1 of
|
||
the generated conf) and fired; systemd *refused* the `graphical-session.target`
|
||
stop because portal-gtk had a start job queued ("destructive transaction"). It
|
||
needs `Linger=yes` to matter — an empty marker dated **2026-01-24, pre-dating
|
||
Bernardo's migration to Nomarchy**. Never shipped by us, ever. Removed. The item
|
||
is rewritten to the class that IS real: `/var/lib` survives a migration, so the
|
||
primary V3 box ran 6 months on a setting the distro never chose and cannot see.
|
||
- **#146 → `[watch]`, near-dead.** One genuine zombie ever (verified by `ps`/`ss`,
|
||
not grep); upstream #171 is real but its impact path closed with linger.
|
||
- **Did:** retracted the cause in place everywhere it was asserted; **restored
|
||
#127** (deleted this morning as "shipped" — only the fix shipped); rewrote #146
|
||
and #147; filed #148 (a reload re-lights the panel in a shut lid — found because
|
||
my own `hyprctl reload` did it to Bernardo, twice).
|
||
- **Verified: V3, the fix survives all of it.** The real 10-min idle, no
|
||
scaffolding: `19:27:58 Executing hyprctl dispatch dpms off` → blanked (the
|
||
revert working) → mouse → `19:32:14 done enabled=1 first=DP-2` — clamshell, the
|
||
incident geometry, from shipped config. Plus the brick condition on purpose
|
||
(hypridle stopped): keypress woke it 4s docked / 6s clamshell. **The fix needed
|
||
no story about why the daemon fails — which is why it survived the story being
|
||
wrong.** V1: flake check + option-docs/clamshell-logind/docking-ux green.
|
||
- **Next suggestion:** #127's **cause**, and start at the **dead Ctrl+Alt+F3** —
|
||
the one symptom no theory yet has touched. DPMS-off cannot break VT switching
|
||
and neither can a dead hypridle; a compositor wedged holding DRM master
|
||
explains the black screen and the dead TTY together. Every theory so far has
|
||
been about the wake path, i.e. a symptom of the screen already being black.
|
||
|
||
## 2026-07-16 — #127 SOLVED: the brick was never DPMS, and TEST B's first run lied
|
||
- **⚠ SUPERSEDED — read the entry above first.** Its headline ("SOLVED") and its
|
||
cause ("hypridle deadlock", "19× in 11 days") were **retracted the same day**:
|
||
the evidence was a measurement artifact and hypridle had no disconnect at the
|
||
incident. What survives: the invalid-TEST-B analysis, and the fix itself.
|
||
- **Task:** #127 TEST B (Bernardo ran it), then the whole sweep his result forced.
|
||
- **Read this if nothing else — the test measured nothing, and said so.** His run
|
||
reported "input never wakes it" **docked *and* undocked alike**, and that tie is
|
||
the tell: the theory demanded those differ. It ran `dpms off` **by hand**, which
|
||
no wake path watches, so "input didn't wake it" was guaranteed on any hardware
|
||
in any dock state. Re-run *through* hypridle so `on-resume` is actually armed:
|
||
input woke it in all 3 configs, **including clamshell on the sole live output**
|
||
(`done enabled=1 first=DP-2`) — the incident's exact geometry. Put the mechanism
|
||
under test inside the circuit, or you are measuring your own scaffolding.
|
||
- **Real cause:** Hyprland ships `misc:{key_press,mouse_move}_enables_dpms` **off**,
|
||
so hypridle's `on-resume` was the ONLY caller of `dpms on` anywhere in the session
|
||
— and hypridle deadlocks (hyprwm/hypridle#171, open since 2025-09, in neither
|
||
0.1.7 nor main) **without exiting**, so `Restart=always` never fires and systemd
|
||
still reports it active. Blank + deadlock = a black seat no key escapes. **19× in
|
||
11 days** on his box, incl. the incident day. Two mundane bugs, not one exotic one.
|
||
- **Did:** both options on — structural: the wake moves into the compositor where no
|
||
daemon can lose it, so a dead hypridle costs auto-lock, not the machine. Reverted
|
||
the clamshell skip; **#135 retired unbuilt**; ROADMAP § "#127 solved"; filed #146
|
||
(hypridle mortality) + #147 (relogin leaves session units dead) → PROPOSED.
|
||
- **Verified: V3 on the incident hardware.** Clamshell, hypridle **deliberately
|
||
stopped** (brick condition on purpose), `dpms off` → keypress woke it in **6s**;
|
||
the identical test before the options stayed black the full 45s. V1: `flake check`
|
||
+ `option-docs`/`clamshell-logind`/`docking-ux`/`display-profiles` pass, and I read
|
||
the **emitted** configs, not the source (`key_press_enables_dpms=true`;
|
||
`on-timeout=hyprctl dispatch dpms off`, skip script gone).
|
||
- **Pending:** V3 — proven via runtime `hyprctl keyword`, NOT from our Nix yet;
|
||
HARDWARE-QUEUE entry re-checks after `nomarchy-home` + relogin. Ctrl+Alt+F3 dead
|
||
during the incident is still unexplained (upstream co-symptom, hypridle#145).
|
||
- **Next suggestion:** #147 before #146 — a guard that restarts hypridle into a dead
|
||
compositor just fail-loops into `start-limit-hit` exactly like cliphist does. Both
|
||
are PROPOSED; Bernardo triages.
|
||
|
||
## 2026-07-16 — #129/#130 buttons; #133; #132; branding; and a latch bug from TEST A
|
||
- **Task:** Bernardo triaged the queue (#136 settled, #130 decided, #143 → wait,
|
||
#120 → PROPOSED), then #133, #132, the codename drop, and #129+#130.
|
||
- **The one to read: a latch bug, found by his TEST A.** He undocked, the panel
|
||
stayed dark, re-docking+undocking fixed it — *opening the lid* was the actual
|
||
cure. `awaiting_lid_open` is cleared only when the external is gone AND the
|
||
lid is open, so a clamshell undock latches it and the NEXT undock is silently
|
||
dropped. His journal proved it (first undock logged nothing). 1 of 3 undocks
|
||
ran; now 3 of 3. **This is very likely #127's second symptom, and it is not
|
||
DPMS** — so the brick may be two mundane bugs, not one exotic one. TEST B is
|
||
now the only thing between that and the truth.
|
||
- **#129/#130:** the planned fix ("darken the label") was **impossible** —
|
||
measuring all 24 palettes showed nothing clears 4.5 on a saturated mid-tone
|
||
accent (cream 2.72, dark text 1.65). The chip had to move: it is now the
|
||
accent pulled away from the label (white anchor for dark themes, black for
|
||
light), factor 0.70, worst 4.86/5.59. The old chip failed **seven** themes,
|
||
not the four the item assumed. #129 became arithmetic rather than a CSS lint:
|
||
pin both ends and the pair is checkable — the checker models GTK's real
|
||
`mix()` (read from gtkcsscolorvalue.c:234) and its negative test re-derives
|
||
the item's own 2.72/2.74 figures independently.
|
||
- **Verified:** every change negative-tested — the chip guard by reverting to
|
||
the old 0.90 chip (9 failures across 7 themes, matching the filed numbers),
|
||
#133's shim check by breaking lib.nix twice, the latch by replaying his
|
||
sequence. V0 green throughout; the branding by reading the built os-release.
|
||
- **Pending:** Bernardo runs TEST B tonight (**relogin first** — the latch fix
|
||
is exec-once). Buttons want an eyeball on a light theme at some point, but the
|
||
numbers are pinned and the render harness was declined on purpose.
|
||
- **Next suggestion:** whatever TEST B says. If input wakes the screen, revert
|
||
the #127 mitigation wholesale and #135 dies with it.
|
||
|
||
## 2026-07-16 — #137 + #145: the splash follows the canvas, and says your layout
|
||
- **Task:** #137 (splash off-centre docked) + #145 (keyboard layout on the LUKS
|
||
prompt, with Fedora's icon).
|
||
- **Did:** one `layout()`, re-run from the existing refresh callback on canvas
|
||
change; `@LAYOUT@` + `@FG_*@` baked by plymouth.nix like the palette already
|
||
is; plymouth's own `keyboard.png` copied at build time and recoloured.
|
||
- **The lesson, and it is the whole entry:** I was wrong twice, and only the
|
||
render rig caught it. Not head-0 geometry (`Window.GetWidth()` = `max_width`);
|
||
not per-head sprites (would have duplicated the logo — the plugin already
|
||
centres each display in the canvas). The bug was **time**: positions computed
|
||
once at parse time vs a canvas that resizes when a head arrives. And attempt 1
|
||
of the fix died on a plymouth-script trap: **a bare assignment inside a
|
||
function writes the global if that name exists globally**, so
|
||
`canvas_width = Window.GetWidth()` updated the very global its guard compared
|
||
against — always false, nothing drawn, **no error logged**. Isolated with a
|
||
20-line probe (`[after assign: global.canvas_width=800][guard SKIPPED]`).
|
||
Both facts are now comments in the script; do not re-derive them.
|
||
- **Verified:** V0 + V2 by render — `tools/plymouth-preview.sh` with the real
|
||
built theme: both heads centred, and the password dialog showing padlock,
|
||
entry, and ⌨ + `us`. Also caught, only because I read the build log: copying a
|
||
file from the store keeps it **444**, so `recolor` failed, the phase aborted,
|
||
and **every later sed silently did not run** — the theme shipped with `@BG_R@`
|
||
literals. `chmod +w`. Check build logs, not just exit codes.
|
||
- **Pending:** V3 queued — a real docked boot/shutdown is the only way to resize
|
||
a canvas (the rig's fake heads exist from the start). Recovery if the splash
|
||
is ever blank: the prompt is invisible but live (type blind), or boot the
|
||
previous generation.
|
||
- **Next suggestion:** #129/#130 (GTK contrast) or #133 (the #107 shim check).
|
||
|
||
## 2026-07-16 — "fix the rest": #140, #142, #144 shipped; #137 re-diagnosed
|
||
- **Task:** the T14s round's remainder. Bernardo picked configurable-provider +
|
||
drop-the-CLI for #140 (and asked for chatgpt/grok in the list).
|
||
- **Did:** **#140** Ask → web chat; `settings.ask.provider` read at run time
|
||
(switching needs no rebuild), claude-code + `pkgs.nodejs` deleted, query also
|
||
copied to the clipboard because vendor prefill is undocumented and fails
|
||
*silently*. **#142** dock mode is now an intent (`settings.display.dockMode`)
|
||
written at the transition choke point and re-asserted by the watcher as a
|
||
**tick invariant** — reconcile diffs `monitors all`, which lists disabled
|
||
outputs, so it is blind to a panel switching back on. **#144** MIGRATION.md
|
||
gets the Mozilla `profiles.ini` bullet.
|
||
- **Verified:** V0 on each. #140: drove the generated script — bad state values
|
||
all fall back, hostile query encodes right. #142: **9/9 gates** unit-tested by
|
||
extracting the real generated `enforce_dock_intent` and stubbing the session
|
||
(incl. *no external → never re-dock*, the #127 brick), plus the state
|
||
write/read round-trip on a scratch checkout so the live flake stayed clean.
|
||
- **#137 — read the entry before touching it.** My own first diagnosis was
|
||
**wrong** and is now corrected in place: `Window.GetWidth()` returns
|
||
`max_width`, not head 0, and the plugin *centres every display in the canvas*
|
||
— so per-head sprites (what I originally proposed) would duplicate the logo.
|
||
The real cause is that the script computes positions **once at parse time**,
|
||
so a display arriving/leaving mid-splash re-centres the displays while the
|
||
sprites keep their stale canvas coords. Fix = reposition on canvas change from
|
||
the existing refresh callback. Not shipped: it draws the **LUKS box** on an
|
||
encrypted machine, and the render rig (`x11.so` +
|
||
`PLY_CREATE_FAKE_MULTI_HEAD_SETUP`) needs root.
|
||
- **Pending:** V3 queue now holds #138 (dock audio), #139 (Acer sheets), #131
|
||
(Acer menu width), #142 (rebuild while docked — **relogin first**). Bernardo
|
||
must `nomarchy-home` + relogin to get any of today's session work.
|
||
- **Next suggestion:** #137 with a sudo session for the rig, or #143's upstream
|
||
(rofi#2317) — nothing to do there until they answer.
|
||
|
||
## 2026-07-16 — #139 + #141: the quick ones from the T14s round
|
||
- **Task:** #139 (terminal sheets open full-screen) and #141 (Waybar updates
|
||
click does nothing) — Bernardo: "let's do the quick ones first".
|
||
- **Did:** #139 was two faults: Hyprland 0.55.4 ignores **percentage** `size`
|
||
rules (clean matrix on hardware: both orders, Kitty memory off — px applies,
|
||
% never does, no configerror), and Kitty replays its remembered window size
|
||
into every float. Fix: `remember_window_size no` + a shared
|
||
`modules/home/term-sheet.nix` that reads the focused monitor and hands Kitty
|
||
the px, so the % intent survives without a rule; the size rules are gone.
|
||
#141: whole-swaps used `$TERMINAL`, which Waybar's env does not have →
|
||
`nomarchy-updates upgrade-window` opens its own window, all 5 call sites are
|
||
env-free, `checks.waybar-swap-env` guards the class. Bernardo asked mid-task
|
||
for the update window to float too → third caller of the sheet helper.
|
||
- **Verified:** V0 `nix flake check --no-build`. **V3 on the dev box:** built
|
||
the HM package with `--override-input`, drove the real launchers — calendar
|
||
1536×936 (=60%×65%), doctor 1408×1008 (=55%×70%), updates 1152×720
|
||
(=45%×50%), all floating + centred in the work area. #141 tested the way it
|
||
actually fails: `env -i` with no `TERMINAL` (matching Waybar's real env) →
|
||
window opens. Guard proven by reintroducing the bug: it fails with the
|
||
offending file/module/key named.
|
||
- **Pending:** Acer (1366×768) V3 queued — the sheets are monitor-relative now,
|
||
so it should hold by construction, which is exactly why it is worth one look.
|
||
#131 is **live on 2560** per Bernardo, so its "only at 1366" model is wrong —
|
||
next up.
|
||
- **Next suggestion:** #137 (plymouth per-head) or #142 (rebuild-while-docked).
|
||
- **Then #131 shipped too (same session):** the remodel found the real cause —
|
||
text menus are sized in % of the *monitor* while a label is a count of
|
||
*characters* in the *theme's* font, and the whole-swaps disagreed wildly
|
||
(620px fixed vs 40%; GeistMono 11 vs JetBrainsMono 14). Fixed with rofi's own
|
||
`ch` unit + a `min` cap: `width: calc( 84ch min 65% )` everywhere. Bernardo's
|
||
condition ("not ugly on a low-res monitor") is what the cap is for, and it is
|
||
measured, not hoped: 84ch = 756px/924px by font, `min 300px` → 300px. V3 by
|
||
screenshot at both ends, incl. the Acer's exact geometry reproduced on the dev
|
||
box. `checks.rofi-text-width` guards it.
|
||
|
||
## 2026-07-16 — #138 dock audio: the graph restart was the bug (44aac0f + this)
|
||
- **Task:** #138 — Meet "no mic or speakers" in Chromium; Zoom fine; no repro
|
||
on a fresh boot. Bernardo's hypothesis (pipewire restarts → Chromium never
|
||
reconnects) was right; the restarter turned out to be **us**.
|
||
- **Did:** `dock-audio.nix` `reprobe` restarted PipeWire/Pulse/WirePlumber on
|
||
every `monitoradded` (#100). Now escalates cheapest-first: select → repair a
|
||
parked card → restart. Added `wait_for_dock_sink` so a slow sink is not read
|
||
as "nothing to select" and cannot fall through to the restart. Filed #137/
|
||
#139/#140/#141 from the same T14s round in 44aac0f.
|
||
- **Verified:** V0 `nix flake check --no-build`. **V2/V3 on the dev box** (real
|
||
hardware, real graph): built the HM activation package with
|
||
`--override-input nomarchy path:…` and ran the real tool — rung 1 selects the
|
||
*same* sink the restart-first path picked (`selected=…HiFi__HDMI1__sink`) in
|
||
2.0s vs ~3.5s, with pipewire/pulse/wireplumber MainPIDs **unchanged**; rung 3
|
||
is reachable and restarts+retries as designed. Diagnosis proof: `Started
|
||
app-org.chromium.Chromium-*.scope` vs `reprobe-start` across 4 boots —
|
||
restart-after-Chromium in both broken sessions, 24s *before* in the healthy
|
||
one; Bernardo then reproduced on demand with a dock/undock (09:35:30).
|
||
- **Pending:** V3 queued (dev box): real plug with Chromium open on Meet —
|
||
**relogin first**, the watcher is `exec-once` (round 6's lesson). Bernardo
|
||
must `nomarchy-home` to pick this up; his Chromium needs one restart to
|
||
regain audio (his own 09:35 test killed it, not the fix).
|
||
- **Process note (mine, worth not repeating):** the rung-3 test was meant to be
|
||
safe via a stubbed `systemctl`, but the `sed` anchored on leading whitespace
|
||
that **Nix's indented strings strip**, so the stub never applied and the run
|
||
restarted his live graph for real. It came back clean (services active, dock
|
||
sink still default) and cost nothing extra only because Chromium was already
|
||
broken. Lesson: when a test's safety depends on a substitution, **assert the
|
||
substitution landed** before running the thing it protects you from.
|
||
- **Next suggestion:** #139 (terminal floats — two faults, both root-caused and
|
||
cheap) or #141 (4 jsonc lines, `$TERMINAL` absent from Waybar's env).
|
||
|
||
## 2026-07-15 — #107 upgrade path proven; state-read tip fixed
|
||
- **Task:** Bernardo feared rebuilding on the state.json rename ("what if it
|
||
doesn't boot"). Verify the real upgrade path from a legacy checkout.
|
||
- **Did:** Built a scratch downstream box shaped like his (~/.nomarchy: git
|
||
checkout, `theme-state.json`, input → local repo) and drove the whole path.
|
||
**The reassurance: the built derivations are byte-identical across the
|
||
rename** — HM `2yqqy8h…` and system `9qp9l3g…` from `theme-state.json` and
|
||
from `state.json` with identical content. The filename picks the read path
|
||
only; it cannot change the closure, so it cannot affect boot. Fixed the
|
||
footgun in `modules/state-read.nix`: the tip said "rename it to state.json",
|
||
which on a git flake yields an *untracked* (invisible) file and the very
|
||
"state file is missing" error the tip is attached to — now it points at the
|
||
menu write and names `git add state.json`.
|
||
- **Verified:** **V1 (strong)** — real eval of both `homeConfigurations` and
|
||
`nixosConfigurations` on the legacy name; migration write (content diff:
|
||
only the key I set, no drift); re-eval clean while dirty/intent-to-add via
|
||
both `.#` and `git+file://`; untracked-state failure is fail-closed at eval
|
||
with the new message (rendered, not assumed). No VM: identical drvPaths are
|
||
stronger evidence than booting the same closure twice.
|
||
- **Pending:** no permanent check asserts mkFlake accepts the legacy name —
|
||
the compat shim could rot silently before it's dropped. Filed #133.
|
||
- **Next suggestion:** #133, or #131 label call `[human]`.
|
||
|
||
## 2026-07-15 — V2 the menu IA (#105/#111/#110), no code change
|
||
- **Task:** close the V2 gap on 856a9d1 — it shipped at "V0 menu-back; HM
|
||
gen builds" for a user-visible menu restructure.
|
||
- **Did:** Rendered all 8 picker screens under the real HM session (scratch
|
||
menu-shot harness off `theme-shot.nix`, invoking each screen through the
|
||
same `$0 <arg>` dispatch). **IA verified**: six-entry root; System →
|
||
Connectivity/Devices/Recovery/Preferences; Recovery lists each scope once;
|
||
Preferences carries the migrated update-checks/Bluetooth/Printing toggles;
|
||
Control Center absent from the dispatch (asserted); no stderr on any screen.
|
||
- **Verified:** **V2 (content only)** — screenshots viewed, `v2-menu/`.
|
||
The VM renders menu *geometry* unfaithfully (icons 44→~10px, 6-row root
|
||
clips), so spacing/truncation is not judgeable there → filed #132 + a
|
||
docs/TESTING.md §5 gotcha so the next agent doesn't chase it.
|
||
- **Pending:** #131 — measured Inter 11 against the 40% picker width: the two
|
||
long Recovery labels fit at 1920 but ellipsize at 1366, cutting exactly the
|
||
cost hint #111 added. Live on the Acer (1366×768). Needs a design call.
|
||
BTRFS Files row is `command -v`-gated and absent in the guest — unexercised.
|
||
- **Next suggestion:** #131 label call `[human]`, or #107 state.json V2.
|
||
|
||
## 2026-07-15 — #98 follow-up: destructive buttons invisible (V2 sweep)
|
||
- **Task:** QA sweep of today's ship — V2 the batch that stopped at V1.
|
||
- **Did:** Rendered a real GTK3 GtkMessageDialog under the actual HM session
|
||
(scratch harness off `tools/theme-shot.nix`). Found e9dd3d1 **regressed
|
||
`destructive-action`**: adw-gtk3 derives ONLY the destructive background
|
||
from `currentColor` (`mix(@destructive_color, alpha(currentColor,…))`),
|
||
so pinning the label to base00 dragged the background dark too — "Delete"
|
||
rendered at **1.03:1** (invisible) on Boreal, and in light themes as well.
|
||
Fix: pin the destructive background to suggested-action's opaque pastel
|
||
ladder, enabled-only (`:not(.flat):not(:disabled)`).
|
||
- **Verified:** **V2** — boreal before/after, summer-night (whole-swap) and
|
||
summer-day (light) renders viewed; destructive 1.03→6.19:1 (boreal),
|
||
1.03→2.74:1 (summer-day, = upstream's white-on-accent convention).
|
||
`nix flake check --no-build` + check-theme-contrast green. Screenshots:
|
||
`scratchpad/v2-98/boreal-{BEFORE,AFTER}-zoom.png`, `sn-zoom.png`, `sd-zoom.png`.
|
||
Two CSS-derived hypotheses (`.default`, disabled suggested/destructive)
|
||
did NOT reproduce — rendering overruled the theory, both left alone.
|
||
- **Pending:** filed the permanent guard + light-mode ~2.7:1 button contrast
|
||
as BACKLOG items. #111/#105/#110 menu IA and #107 rename are still V1.
|
||
- **Next suggestion:** V2 the menu IA (#111/#105/#110), or human V3 #115/#127.
|
||
|
||
## 2026-07-15 — #127 skip DPMS-off when docked (mitigation)
|
||
- **Task:** Bernardo: no usable TTY on brick; prefer prevent over dump.
|
||
- **Did:** hypridle 10m listener skips `dpms off` when an internal
|
||
(eDP/LVDS/DSI) is present-but-disabled; lock still at 5m. Documented
|
||
LATER “DPMS when docked” revisit. Dump/wake tools remain.
|
||
- **Verified:** V0/V1 flake check. V3: HARDWARE-QUEUE mitigation check.
|
||
- **Pending:** human docked idle past 10m → external lit under lock.
|
||
- **Next suggestion:** V3 docked idle, or other queue.
|
||
|
||
## 2026-07-15 — #127 no-SSH dump + docked idle wake harden
|
||
- **Task:** Tackle docked idle blackout without needing SSH mid-brick.
|
||
- **Did:** `nomarchy-display-dump` / `nomarchy-display-wake`; undock always
|
||
`dpms on`; hypridle resume/after_sleep → wake rescue; SUPER+SHIFT+D;
|
||
HARDWARE-QUEUE #127 rewritten for Ctrl+Alt+F3 TTY path.
|
||
- **Verified:** V0/V1 flake check. V3: docked idle on AMD box.
|
||
- **Pending:** real repro; keep #127 open until V3 pass.
|
||
- **Next suggestion:** Bernardo runs forced DPMS dock test + TTY dump if needed.
|
||
|
||
## 2026-07-15 — #115 suspend-then-hibernate (1h, battery-only + menu)
|
||
- **Task:** Human settled delay=1h, battery only, menu enable/disable.
|
||
- **Did:** `nomarchy-suspend` + logind/sleep bridge from
|
||
`settings.power.suspendThenHibernate` (default on; needs resumeDevice).
|
||
Preferences toggle (rebuild). Unlock-before-encrypted-hibernate for s2h→disk.
|
||
HARDWARE-QUEUE: #115 steps + suggested-order sweep (top 8).
|
||
- **Verified:** V0/V1 `nix flake check --no-build` incl. state-bridges s2h cases.
|
||
- **Pending:** V3 bag-carry / 1h on battery (HARDWARE-QUEUE #115).
|
||
- **Next suggestion:** human runs HARDWARE-QUEUE suggested order, or #120.
|
||
|
||
## 2026-07-15 — #98 GTK dialog button black-on-dark (Boreal)
|
||
- **Task:** Bernardo: GTK dialog button labels black vs dark Boreal chrome.
|
||
- **Did:** Root cause — Stylix pins light `adw-gtk3` for all polarities.
|
||
Force `adw-gtk3-dark` when mode=dark, prefer-dark, and extraCss for
|
||
dialog/action button labels (suggested/destructive keep dark-on-pastel).
|
||
- **Verified:** V1 HM gen: settings.ini `gtk-theme-name=adw-gtk3-dark`,
|
||
prefer-dark=true, gtk.css button rules present. V3: open a GTK dialog
|
||
after nomarchy-home.
|
||
- **Pending:** V3 eyeball on real session.
|
||
- **Next suggestion:** hardware queue or human #115/#120.
|
||
|
||
## 2026-07-15 — Document generation prune for users (#128 docs)
|
||
- **Task:** User-facing docs for the 14d / keep-≥3-past policy.
|
||
- **Did:** RECOVERY §4 (how gens are kept); README generation section +
|
||
alias note; REQUIREMENTS hygiene points at the automatic prune.
|
||
- **Verified:** V0 (docs only).
|
||
- **Pending:** none.
|
||
- **Next suggestion:** hardware V3 or human #115/#120.
|
||
|
||
## 2026-07-15 — #128 generation prune (14d + keep ≥3 past, system+HM)
|
||
- **Task:** Implement auto-prune for system and Home Manager generations.
|
||
- **Did:** `pkgs/nomarchy-gen-prune` + `modules/nixos/gen-prune.nix` weekly
|
||
timer; pure select (current + 3 past always; else drop if age>14d); store
|
||
GC without `--delete-older-than`; bootloader refresh after system prune.
|
||
Doctor fix + RECOVERY note. Closed #128.
|
||
- **Verified:** V0/V1 — `checks.gen-prune` (self-test + dry-run + timer
|
||
assert + no age-only gc options). V3: run on a multi-gen box.
|
||
- **Pending:** V3 on real machine with many gens.
|
||
- **Next suggestion:** human #115/#120, or hardware queue.
|
||
|
||
## 2026-07-15 — File #128 generation auto-prune policy (no code)
|
||
- **Task:** Bernardo: auto-clean gens older than N days but always keep
|
||
≥3 past; include HM; prefer 14d over 30d.
|
||
- **Did:** NEXT **#128** — system **and** Home Manager; **14 days** + keep
|
||
≥3 past. Noted existing `nix.gc` weekly 14d has no min-generation floor.
|
||
- **Verified:** V0 (docs/agent only).
|
||
- **Pending:** implement when picked.
|
||
- **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). Added
|
||
`checks.airplane` (session state machine + menu/keybind/whole-swap
|
||
surfaces; mocked nmcli) and `checks.fastfetch-logo` (sextant count +
|
||
module flags). Host V2 artifacts stay under `/tmp/nomarchy-v2-batch2`
|
||
and `/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-airplane` runtime Wi-Fi+BT kill-switch with prior
|
||
restore; System menu row; SUPER+CTRL+R; Waybar `custom/airplane` (signal 11,
|
||
self-hides); whole-swap jsonc/css parity. (122) chafa `sextant` 24×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/CLI `nomarchy-theme-sync` → `nomarchy-state-sync` with symlink
|
||
alias; `modules/state-read.nix`; mkFlake/doctor/lifecycle read legacy
|
||
name; writes always land on `state.json` and 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-sync` alias 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. Added
|
||
`ecosystem.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/`;
|
||
V0 `nix 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.nix`
|
||
PASS. Class `com.nomarchy.doctor`, floating, centered; client
|
||
`title=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
|
||
- **Disk filter fixture:** fd0/loop excluded, vda/sda kept (#112 logic)
|
||
- **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-cheatsheet` asserts 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_disks` excludes 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_switch` prints 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` + prefers
|
||
`dbus-run-session -- activate`. (124) seed `?ref=main`; patch-template
|
||
rewrites `inputs.nomarchy.url` from 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.baseName` eval
|
||
`nomarchy-live-…`; patch-template flakeUrl rewrite; mode sort unit fixture.
|
||
- **Pending:** V3 reinstall on Acer/XPS (#123/#124); optional full
|
||
`test-install.sh` V2 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-….iso` because
|
||
`image.baseName` is 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-…iso`
|
||
on 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.nix` and `nomarchy.ghostty.enable`. Kitty always
|
||
installed + themed; default `nomarchy.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.nix` themes Kitty from theme-state (same
|
||
palette/font/opacity as Ghostty); enables when `nomarchy.terminal` is
|
||
kitty or `nomarchy.kitty.enable`. Installer runs `glxinfo` (mesa-demos on
|
||
PATH) and, if OpenGL < 4.3, writes `settings.terminal = "kitty"` (+
|
||
`terminalReason`) into theme-state. Docs/REQUIREMENTS + README rows.
|
||
- **Verified:** V0 flake check; HM gen with `settings.terminal=kitty` builds
|
||
— 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"):
|
||
1. **#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).
|
||
2. **#124** — seeded flake hardcodes `?ref=v1` while installer writes
|
||
main-era `nomarchy.hardware.*`; v1 lags (~hundreds of commits) →
|
||
`nomarchy.hardware does not exist` on Acer rebuild/pull.
|
||
3. **#95** — Ghostty **Acer-only** (XPS is fine). Two photos = two
|
||
attempts on the Aspire: pre-HM explicit `OpenGLOutdated`, post-HM
|
||
quiet exit after `GDK_DISABLE` (same machine; kitty used as the
|
||
working shell). Primary blocker is GL ≥ 4.3.
|
||
HARDWARE-QUEUE V3 rows. Photos stay local (not committed).
|
||
- **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 after `GDK_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/plain` named vscode, which the live ISO never
|
||
ships (same GIO-skip trap as #94, one key over).
|
||
- **Did:** `text/plain` is now an ordered fallback
|
||
`code.desktop` → `org.gnome.TextEditor.desktop` (HM tries the next when the
|
||
preferred is missing). Live profile gains `mpv` too — video mime defaults
|
||
had the same hole and the package is free via the template pin. Extended
|
||
`checks.live-baseline-apps` so every `[Default Applications]` key has at
|
||
least one listed `.desktop` on **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**
|
||
when `text/plain` is a vscode-only singleton. V0 flake check green.
|
||
- **Pending:** V3 launch of a `.txt` on 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 an `ExecCondition` running
|
||
`smartctl --scan` (empty exactly when smartd would find nothing), so the
|
||
unit goes **inactive** rather than failed. NOT `SuccessExitStatus = 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-gate` boots the **real** distro module
|
||
(not a restatement of it; `nixpkgs.config` needed `mkForce` to 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 from
|
||
`systemctl --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/plain` names 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.default` carries 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
|
||
`buildCommand` nixpkgs 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-store` hardlinks them
|
||
(the two paths share inodes — `stat`-verified; `du` counts 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 `-wv` copy but links `share/*` from the
|
||
**plain** unwrapped build. A symlink is a store reference, so a second
|
||
687 MiB chromium rode along for a directory of `.desktop` files nothing
|
||
executes — on every installed machine, not just the ISO. `overlays.default`
|
||
now 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 `-wv` copy itself
|
||
references the plain build. It is `cp -a` of 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's `overrideAttrs` (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 `-wv`
|
||
build, WidevineCdm present there, `share/{applications,icons,man}` match
|
||
stock with the `.desktop` **byte-identical**. New
|
||
`checks.chromium-single-closure` asserts 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 `-wv` copy is `cp -a` of the plain build, so the ISO stored the
|
||
blocks once), and **auto-optimise-store hardlinks** identical files — the
|
||
two paths share inodes (verified by `stat`; `du` counts 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.nix` now 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.extraDependencies` *already* 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 exact
|
||
`chromium.override { enableWideVine = true; }` costs zero — a plain
|
||
`chromium` would 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-apps` asserts 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/plain`
|
||
names 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
|
||
its `share/applications` alone — 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 in a9f3a64, 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
|
||
says `bluetooth.enable = false` silently flips back on at the next rebuild.
|
||
`checks.state-bridges` will 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.settings` is declared in exactly ONE place
|
||
(`modules/home/options.nix:412`), so `or <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 via
|
||
`state-read.nix` + `lib.mkIf (state != null) (lib.mkDefault state)` —
|
||
done for `bluetooth.enable` (default.nix) and `services.printing.enable`
|
||
(services.nix). `batteryChargeLimit`'s read is simply deleted: power.nix's
|
||
oneshot reads the key with `jq` at *runtime*, which is why that menu worked.
|
||
greeter.nix moved off a raw `fromJSON` onto 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`, not
|
||
`modules/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) and `checks.printing-from-state`, a runNixOSTest
|
||
whose node's ONLY input is the state file and which waits for a running
|
||
`cups.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.pam` key; `idle.nix` defaults `idle.fingerprint` from
|
||
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.autoLogin`
|
||
defaulted from `config.nomarchy.settings…`, an attribute that exists ONLY
|
||
on the HM side, and `or null` swallowed it — the state path never worked on
|
||
any machine ever built; and `state-sync get` printed Python's `None` for a
|
||
JSON null, so any `case … 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=true` alone renders hyprlock's auth block; both
|
||
tools bash -n clean and land in systemPackages; the get round trip prints
|
||
`null`.
|
||
- **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.settings` under `modules/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's `lock_cmd`
|
||
stays 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.fingerprint` forced
|
||
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:** e2de906 fixed 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_empty` default), so `$FPRINTPROMPT` in
|
||
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-base` is 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.pam` on — sudo
|
||
took a finger, hyprlock did nothing.
|
||
- **Did:** the PAM stack was never the problem (grosshack sits in
|
||
`/etc/pam.d/hyprlock` at 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 behind `auth:fingerprint:enabled`, which nothing
|
||
in the distro ever set. New `nomarchy.idle.fingerprint` (default false),
|
||
mirroring `hardware.fingerprint.pam` the way `keyboard.layout` mirrors the
|
||
xkb option — hyprlock is configured in standalone HM, which has no
|
||
`osConfig`. 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 stop` does 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 is `auth
|
||
sufficient` at 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 = false` restoring 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,1` is *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 forcerendererreload` is
|
||
inert too; only `hyprctl reload` escapes (99ms / 289ms, cable out). So the
|
||
transition issues the keyword, and escalates to `reload` only when
|
||
`monitors` proves it inert — then re-asserts the rule and calls
|
||
`nomarchy-keyboard-layout restore` per device, since a reload drops runtime
|
||
`device[…]:kb_layout` keywords. Also made the menu's `enable` prove 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 the `added= DP-2` lines. Both were the same artifact:
|
||
**every `result=ok` was 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-1` driven 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 remembered `us`, while a control
|
||
bare `hyprctl reload` dropped it to the session `gb` — the clobber was an
|
||
inference until measured, and it makes `restore_keyboards` load-bearing.
|
||
Plus V2: `nix flake check --no-build` all pass; `checks.docking-ux` +
|
||
`checks.dock-audio` + `monitor-fallback.nix` pass; 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 undock `hyprctl keyword monitor
|
||
eDP-1,preferred,auto,1` exits 0 but is dropped when it lands mid-teardown
|
||
of the departing external — now re-issued every poll for 5s, with
|
||
`monitors` listing the panel as the only proof; (2) the watcher marked the
|
||
departure handled via `"$TRANSITION" undock … || true` + `awaiting_lid_open=1`
|
||
and `known_outputs` had 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, then `result=gave-up`).
|
||
- **Verified:** V2 — `nix flake check --no-build` all checks passed;
|
||
`nix build --impure -f tools/monitor-fallback.nix` exit 0 in 57s (reaches
|
||
the final `lid-open transition` checkpoint); 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-flake` now `git init`+`add`+`commit`s
|
||
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_OK` markers. 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 failing
|
||
`bvl30ggn…home-manager-generation.drv` is 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 missing
|
||
`charge_control_end_threshold` as a firmware capability. Bluetooth leaf
|
||
checks `bluetooth.service` before exec'ing blueman and explains the
|
||
service-down vs no-adapter (`/sys/class/bluetooth` empty) 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 tools` in keybinds.nix (single
|
||
source: Hyprland + cheatsheet); root-menu Tools/System rows now carry
|
||
`menuHint` shortcut 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
|
||
`--header` on 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/fd0` as 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 = 0` on
|
||
`nomarchy-battery-charge-limit` (idempotent sub-second write — rate
|
||
limiting only manufactures false failures); extended
|
||
`checks.battery-charge-limit` with 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-client`
|
||
as a downstream-template opt-in; no Nomarchy wrapper.
|
||
- **Did:** Commented `services.nextcloud-client` block in
|
||
`templates/downstream/home.nix` (enable + startInBackground), and pointed
|
||
the bare `# nextcloud-client` package 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 ExecStart `nextcloud --background`,
|
||
WantedBy/PartOf `graphical-session.target`. `nix flake check --no-build`
|
||
green (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 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 → <dock sink>" row.
|
||
- **Verified:** V2-equivalent live on Newton — watcher: fake dock-named
|
||
null sink → default followed, unplug → fell back, EE links moved
|
||
mid-playback (pw-link); menu: generated script bash -n, dock-row jq
|
||
exercised against real pactl JSON, dispatchers probed on live
|
||
Hyprland. flake check green; option-docs green. Beware: kill the
|
||
subscribe pipe by PID — pkill -f self-matches the test shell.
|
||
- **Pending:** real-dock V3 ×2 in HARDWARE-QUEUE (watcher may miss
|
||
sinks that pre-exist and only flip route availability — capture pactl
|
||
subscribe + sink JSON if it fails again).
|
||
- **Next suggestion:** #89 slice 3 (Signal pixmap) or dock V3 feedback.
|
||
|
||
## 2026-07-12 — auto-commit sweep before pull/rebuild/home (interactive)
|
||
- **Task:** Bernardo's request (no BACKLOG item): with autoCommit on,
|
||
hand edits to `~/.nomarchy` (his had 4) stayed forever-dirty —
|
||
state-sync's commit is pathspec-limited to state.json by design.
|
||
- **Did:** New internal `nomarchy-autocommit` in nomarchy-lifecycle:
|
||
live-reads `settings.autoCommit`, commits *everything* dirty with
|
||
message `nomarchy: auto-commit before <label>` + file list in the
|
||
body; called (`|| true`, never blocks) at the top of nomarchy-pull /
|
||
-rebuild / -home. Exposed as `passthru.autocommit`; package exported.
|
||
Docs/comments swept: README, RECOVERY, ROADMAP ✓ entry, rofi toggle
|
||
text, control-center prompt, state-sync docstring.
|
||
- **Verified:** V1+ — `nix flake check --no-build` green; new permanent
|
||
`checks.lifecycle-autocommit` builds (real binary, sandbox repos:
|
||
sweep/clean/off/non-repo); end-to-end on a *copy* of the real
|
||
~/.nomarchy via built nomarchy-rebuild with stubbed sudo/rebuild —
|
||
the 4 real dirty files landed in one commit, tree clean. No VM boot:
|
||
no session-visible surface. Real-machine confirmation lands after the
|
||
next nomarchy-pull picks up this rev.
|
||
- **Pending:** nothing queued; Bernardo's actual ~/.nomarchy still has
|
||
its 4 uncommitted files until his next pull/rebuild with the new rev.
|
||
- **Next suggestion:** back to BACKLOG (#89 slice 3, Signal pixmap).
|
||
|
||
## 2026-07-12 — #89 slice 2: EasyEffects tray icon themed monochrome (b98248f)
|
||
- **Task:** BACKLOG #89 slice 2 — EasyEffects SNI shows Papirus' full-
|
||
colour blue equaliser, clashing with the monochrome tray.
|
||
- **Did:** Wrapped the resolved icon set in a `Nomarchy-icons` child
|
||
theme (theme.nix) that Inherits it + ships a scalable, palette-`text`-
|
||
coloured monochrome easyeffects glyph (the app's own -symbolic shape);
|
||
made it the session icon theme. Single shared layer, so it covers all
|
||
themes (all resolve to Papirus-*); colour tracks each theme via
|
||
`checked.colors.text`. iconTheme feeds stylix+rofi, both fine via
|
||
Inherits. Fixed a slip: `git add -A` swept a settings.local.json.tmp.*
|
||
into the commit → untracked + gitignored (f9d5e2c).
|
||
- **Verified:** **V3 in Boreal** (Bernardo confirmed live). Mechanism
|
||
pre-validated by GTK IconTheme lookup (override wins 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 ac7e6bd broke Boreal's bar + icons still missing.
|
||
- **Did:** Two lessons. (1) `window#waybar *` carries id specificity, so
|
||
the reset started *beating* the later class rules (pill radius/borders)
|
||
that plain `*` correctly lost to — reverted all three stylesheets;
|
||
arrows restored instead via stylix gtk.css (`menu menuitem arrow
|
||
{ min-width/height:16px }`) — USER priority (800) outranks waybar's
|
||
APPLICATION (600) regardless of specificity, same mechanism as the
|
||
existing check/radio rule. NB comments guard each `*` block.
|
||
(2) The "missing icons" were also GTK3's `gtk-menu-images` default-off:
|
||
set `gtk.gtk3.extraConfig.gtk-menu-images = 1`.
|
||
- **Verified:** **V3** — repro (no forced always-show-image): icon, check
|
||
and arrow all render even with Boreal's reset injected screen-wide;
|
||
bar screenshot shows pills restored. Flake check green.
|
||
- **Pending:** Bernardo eyeballs the real nm-applet menu (icons + arrow).
|
||
- **Next suggestion:** #89 slice 2 — the override-icon layer.
|
||
|
||
## 2026-07-12 — #76 closed: hibernate V3 PASSED on TuringMachine (this commit)
|
||
- **Task:** BACKLOG #76 `[human]` closure — Bernardo reports the V3 check.
|
||
- **Did:** Bernardo ran the real power-cycle on the T14s (LUKS + btrfs
|
||
`@swap` swapfile): hibernate → power off → single LUKS unlock →
|
||
session restored, "flawlessly". Deleted #76; HARDWARE-QUEUE resume
|
||
entry pruned (outcome recorded here + ROADMAP ✓-entry updated);
|
||
Decisions note marked shipped. The **no-swap Hibernate notify** check
|
||
stays open in HARDWARE-QUEUE as the one leftover.
|
||
- **Verified:** V3 (human, real hardware). Docs-only commit otherwise.
|
||
- **Pending:** no-swap notify check (needs a swapless session or
|
||
temporary `swapoff -a`).
|
||
- **Next suggestion:** #89 slice 2 — the override-icon layer.
|
||
|
||
## 2026-07-12 — #90 tray submenu arrows: root cause was waybar CSS (this commit)
|
||
- **Task:** BACKLOG #90 `[stuck]` (interactive, Bernardo driving on T14s).
|
||
- **Did:** Diagnosis was wrong — Papirus-Dark resolves `pan-end-symbolic`
|
||
fine via its breeze-dark inheritance (breeze ships inside the nixpkgs
|
||
papirus output). Real cause: Waybar's stylesheet applies process-wide,
|
||
and the `* { min-height: 0; }` block collapsed the arrow node in the
|
||
SNI tray menus Waybar hosts. Scoped the `*` block to `window#waybar`
|
||
in boreal + executive-slate waybar.css and waybar.nix generatedStyle
|
||
(tooltip rules restate the font — tooltips are separate toplevels);
|
||
removed the go-next-symbolic remap workaround from stylix.nix.
|
||
- **Verified:** **V3** — live GTK3 repro app popping a dbusmenu-shaped
|
||
menu, screenshotted via grim: arrow vanishes with old CSS injected
|
||
screen-wide, renders with fixed CSS; property bisect pinned
|
||
`min-height: 0` as the sole culprit. V1 flake check green.
|
||
- **Pending:** post-switch check that the real nm-applet menu shows the
|
||
arrow (needs a human click on the tray icon).
|
||
- **Next suggestion:** #89 slice 2 — the override-icon layer.
|
||
|
||
## 2026-07-11 — interactive T14s session: migration follow-ups (50a5586…6967d89)
|
||
- **Task:** Escalation — Bernardo driving, live on the migrated T14s
|
||
(first full session on real Nomarchy hardware; 7 commits).
|
||
- **Did:** autologin restored (migration missed the LUKS-machine line —
|
||
fixed downstream + MIGRATION.md example); SUPER+0 → workspace 10;
|
||
VPN tooltip names active VPNs (stuck-shield confusion was Tailscale);
|
||
battery "Not charging" hold-band tooltip (+ 4 whole-swap themes);
|
||
GTK submenu arrows (bundled SVG — Papirus lacks pan-end-symbolic and
|
||
inherits uninstalled breeze); xdg.userDirs.setSessionVariables pinned
|
||
(HM 26.05 flip); easyeffects gated on a live tray host (After=
|
||
waybar.service was inert — waybar is supervisor-run, not a unit);
|
||
#89 slice-1 SNI inventory recorded; #76 unblocked → `[human]`.
|
||
- **Verified:** **V3** throughout — live binds via `hyprctl binds`, GTK
|
||
menu screenshot (arrow + check render), SNI watcher registration,
|
||
deployed configs inspected; V1 flake check green on every commit.
|
||
- **Pending:** Bernardo: `nomarchy-rebuild` (autologin + new services),
|
||
then the #76 hibernate power-cycle. #89 targets narrowed to
|
||
EasyEffects (slice 2) + Signal (slice 3).
|
||
- **Next suggestion:** #89 slice 2 — the override-icon layer.
|
||
|
||
## 2026-07-11 — hotfix: Left=Back bound over rofi default → every menu dead
|
||
- **Task:** Escalation — V3 on the migrated T14s: all `nomarchy-menu`
|
||
entry points (main, battery, power-profile, VPN) showed rofi's
|
||
"Binding 'Left' is already bound" error dialog instead of a menu.
|
||
- **Did:** `rofi.nix` — release `kb-move-char-back` to `Control+b` before
|
||
binding `-kb-custom-1 Left`, in both `rofi_menu` copies (menu + vpn).
|
||
rofi hard-fails on duplicate bindings, and reports it in a GUI dialog,
|
||
not stderr — stub tests and `bash -n` can never catch this class.
|
||
Filed PROPOSED: EasyEffects 8 blue tray icon; parallel finger/password.
|
||
- **Verified:** **V3** — real rofi on the T14s: old flags reproduce the
|
||
error dialog (screenshot), fixed flags render the menu; after HM
|
||
switch, `nomarchy-menu` renders end-to-end. V0 flake check green.
|
||
- **Pending:** flatpak apps missing from drun = stale session env
|
||
(relogin), not a code bug. EasyEffects icon + pam items in PROPOSED.
|
||
- **Next suggestion:** V3 sweep of the remaining 05bab55 session items.
|
||
|
||
## 2026-07-11 — post-migration fix batch (05bab55; entry backfilled)
|
||
- **Task:** Escalation — first real-hardware migration (TuringMachine →
|
||
Nomarchy) surfaced a batch of annoyances; session crashed before
|
||
journaling, entry written by the follow-up session.
|
||
- **Did:** Force fprintAuth off unless `fingerprint.pam`; first-boot toast
|
||
waits for swaync + retries; night-light handles masked units; VPN menu
|
||
`rofi_menu` no-op fixed; ← = Back in list menus; GTK menu contrast;
|
||
mic-mute LED udev rule + sync; EasyEffects after tray; MIGRATION.md notes.
|
||
- **Verified:** V0 flake check; checks.first-boot; checks.hardware-toggles.
|
||
- **Pending:** V3 on the migrated machine. Follow-up found the downstream
|
||
`~/.nomarchy` lock still pinned the *previous* commit — the user's rebuild
|
||
excluded this batch (mic LED "regression" was just that). Also: HM
|
||
`programs.chromium.extensions` from the old config wasn't carried over, so
|
||
Chromium externally-uninstalled all extensions **and their data** (wallets
|
||
included); recovered from the `pre-nomarchy-home` btrfs snapshot.
|
||
MIGRATION.md browser note rewritten with the real mechanism.
|
||
- **Next suggestion:** V3 sweep of the 05bab55 items after a locked rebuild.
|
||
|
||
## 2026-07-11 — #88 neon-glass polish / finish
|
||
- **Task:** NEXT #88 — finish neon-glass (`VISION § D`), not quarantine.
|
||
- **Did:** Rewrote `themes/neon-glass/rofi.rasi` (was invalid `var()` CSS;
|
||
now Boreal-style glass with `@colors`, cyan edge, soft selection).
|
||
btop accent titles/selection; JSON ui rounding 14 + slight glass
|
||
opacity; `preview.png` from theme-shot desktop. No waybar.css.
|
||
- **Verified:** **V2** — contrast 24×7 pass; theme-wholeswap green;
|
||
theme-shot neon-glass desktop+menu viewed (cyan bar + glass menu);
|
||
boreal theme-shot regression green (menu/bar intact).
|
||
- **Pending:** —
|
||
- **Next suggestion:** post-install hardware hints PROPOSED, or human
|
||
HARDWARE-QUEUE.
|
||
|
||
## 2026-07-11 — Promote neon-glass → NEXT #88 (Bernardo)
|
||
- **Task:** human triage: promote neon-glass PROPOSED.
|
||
- **Did:** NEXT **#88** neon-glass polish/finish (`VISION § D`); path =
|
||
**finish** (not quarantine). Notes: no broken waybar.css reintro without
|
||
wholeswap parity; V2 theme-shot required. PROPOSED pitch removed;
|
||
VISION pointers updated. **No implementation** this commit.
|
||
- **Verified:** V0 (backlog/docs only).
|
||
- **Pending:** —
|
||
- **Next suggestion:** implement #88 (theme-shot V2).
|
||
|
||
## 2026-07-11 — VISION hygiene + PROPOSED (queue empty)
|
||
- **Task:** QA/docs loop — NEXT still only #76 `[blocked:hw]`; no product
|
||
item to implement without inventing work.
|
||
- **Did:** Marked Theme A/B/C shipped rows in `docs/VISION.md` (Firmware
|
||
#43, Fingerprint #55, doctor stack, rebuild errors #56, Boreal default,
|
||
hibernate confidence #77). Rewrote “Suggested agent slices” to open
|
||
work only. PROPOSED: post-install hardware hints; neon-glass
|
||
finish/quarantine `[human]`.
|
||
- **Verified:** **V0** — docs/backlog only (no module change). Prior
|
||
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) via `modules/nixos/dock-audio-rules.nix` + default.nix
|
||
pipewire. `checks.dock-audio` pure rule asserts + conf-file VM. V3
|
||
hotplug steps in HARDWARE-QUEUE. Closed #87.
|
||
- **Verified:** **V2** — `nix flake check --no-build`; `checks.dock-audio`
|
||
green (pure rule asserts + conf installed under wireplumber.conf.d).
|
||
- **Pending:** V3 real HDMI/USB-dock hotplug (HARDWARE-QUEUE).
|
||
- **Next suggestion:** QA sweep or LATER wallpapers split if promoted.
|
||
|
||
## 2026-07-11 — #86 clamshell HandleLidSwitchDocked
|
||
- **Task:** NEXT #86 — lid closed + external monitor must not suspend.
|
||
- **Did:** Explicit `HandleLidSwitchDocked=ignore` in
|
||
`modules/nixos/power.nix` (logind settings.Login). Undocked lid
|
||
behaviour unchanged. idle.nix comment corrected. `checks.clamshell-logind`
|
||
asserts conf + active logind. V3 steps in HARDWARE-QUEUE. Closed #86.
|
||
- **Verified:** **V2** — `nix flake check --no-build`;
|
||
`checks.clamshell-logind` green (`HandleLidSwitchDocked=ignore` +
|
||
logind active).
|
||
- **Pending:** V3 real lid+external on laptop (HARDWARE-QUEUE).
|
||
- **Next suggestion:** #87 dock audio sink follow.
|
||
|
||
## 2026-07-11 — #85 hardware hall of fame + split #84
|
||
- **Task:** NEXT #85 docs hall of fame; #84 was `[big]` → split.
|
||
- **Did:** HARDWARE.md §9 install-tested table (T14s Gen 4 AMD, Latitude
|
||
5410/5310) + DMI PR invite; renumbered following sections. #84 → #86
|
||
clamshell + #87 dock audio. VISION/ROADMAP; closed #85.
|
||
- **Verified:** V0 (docs only).
|
||
- **Pending:** —
|
||
- **Next suggestion:** #86 clamshell or #87 dock audio (both product).
|
||
|
||
## 2026-07-11 — #83 doctor first-boot pre-activate flag
|
||
- **Task:** NEXT #83 — doctor points at failed installer HM pre-activate.
|
||
- **Did:** doctor row: if `/var/log/nomarchy-hm-preactivate.log` is present
|
||
and no Home Manager generation exists → ✖ +
|
||
`home-manager switch --flake ~/.nomarchy -b bak`. Skip/ok otherwise.
|
||
Extended `checks.doctor` (fail arm + recovered gen). Closed #83.
|
||
- **Verified:** **V2** — checks.doctor green (fail arm + recovered gen);
|
||
local smoke with NOMARCHY_HM_PREACTIVATE_LOG / empty HOME.
|
||
- **Pending:** —
|
||
- **Next suggestion:** #85 docs hall of fame (cheap) or split #84 dock.
|
||
|
||
## 2026-07-11 — #82 generation readability
|
||
- **Task:** NEXT #82 — plain-language “what changed last rebuild”.
|
||
- **Did:** `pkgs/nomarchy-what-changed` (nvd → “N added, M removed, K
|
||
updated”); wired into lifecycle post-`nomarchy-rebuild` / `nomarchy-home`
|
||
(full nvd + notify toast); System › What changed? (toast + floating
|
||
full report). `checks.what-changed` with NOMARCHY_NVD fixture. Closed #82.
|
||
- **Verified:** **V2** — checks.what-changed green; local smoke on real
|
||
HM gens (“Desktop: 1 added, 1 removed”) + fixture counts.
|
||
- **Pending:** —
|
||
- **Next suggestion:** #83 doctor pre-activate fail flag or #85 docs.
|
||
|
||
## 2026-07-11 — #81 first-boot welcome toast
|
||
- **Task:** NEXT #81 — dismissible “you're set” card (`VISION § B`).
|
||
- **Did:** `pkgs/nomarchy-first-boot` + user oneshot
|
||
(`modules/home/first-boot.nix`): notify once with SUPER+M/T/? + Network
|
||
+ Doctor pointers; marker `settings.firstBootShown` via theme-sync
|
||
`--no-switch` (in-checkout state). Skip live hostname. Option
|
||
`nomarchy.firstBootWelcome.enable` (default on). `checks.first-boot`.
|
||
ROADMAP/VISION/README; closed #81.
|
||
- **Verified:** **V2** — `nix flake check --no-build`; `checks.first-boot`
|
||
green (toast + marker + silent re-run + live skip); local shim smoke;
|
||
downstream-template-home carries the user unit.
|
||
- **Pending:** V3 — real swaync rendering on first installed login
|
||
(toast body is pure text; not queued unless it misbehaves).
|
||
- **Next suggestion:** #82 generation readability or #85 docs hall of fame.
|
||
|
||
## 2026-07-11 — #80 doctor battery health readout
|
||
- **Task:** NEXT #80 — battery health in `nomarchy-doctor` (`VISION § C`).
|
||
- **Did:** Doctor row: `cycle_count` + retained capacity
|
||
(`charge_full`/`design` or `energy_*`) as `% of design`; system
|
||
batteries only; soft warn <70% design; skip when attrs absent.
|
||
`NOMARCHY_POWER_SUPPLY_ROOT` for the VM fixture. Extended
|
||
`checks.doctor` (fake BAT0 + Device-scope MOUSE0 ignore). HARDWARE §10,
|
||
ROADMAP ✓, VISION ✓; closed #80.
|
||
- **Verified:** **V2** — `nix flake check --no-build`; `checks.doctor`
|
||
green; local smoke on real BAT0 (342 cycles, 81% via energy_*) + fixture.
|
||
- **Pending:** Power-menu surface left optional/out of scope (doctor is
|
||
the product surface for report-only health).
|
||
- **Next suggestion:** #81 first-boot welcome card (highest product ROI)
|
||
or #85 docs-only hall of fame.
|
||
|
||
## 2026-07-11 — Triage: VISION-gap PROPOSED → NEXT #80–#85 (Bernardo)
|
||
- **Task:** Bernardo promoted five of the six fresh VISION-gap pitches
|
||
(all but the wallpapers split, which stays LATER).
|
||
- **Did:** NEXT gains #80 battery health readout, #81 first-boot welcome
|
||
card, #82 generation readability, #83 doctor pre-activate fail flag,
|
||
#84 dock life polish `[big]`, #85 hardware hall of fame. PROPOSED
|
||
placeholder left. **No implementation started** (explicit instruction).
|
||
- **Verified:** V0 (backlog only).
|
||
- **Pending:** —
|
||
- **Next suggestion:** #80 (smallest) or #81 (highest product ROI); #84
|
||
must be split first.
|
||
|
||
## 2026-07-11 — Quick wins: exit-node locations + geo tooltip
|
||
- **Task:** BACKLOG LATER "VPN exit-node richer display" + a geo-mode
|
||
tooltip nit from the previous iteration (human asked for quick wins).
|
||
- **Did:** Tailscale Exit node picker rows now "hostname — Country City",
|
||
sliced by the header's fixed-width column offsets (COUNTRY/CITY are
|
||
multi-word; never field-split), locationless nodes stay bare, pick strips
|
||
back to hostname at the first space. Nightlight Waybar tooltip says
|
||
"follows your location" in geo mode. Queue's VPN entry updated.
|
||
- **Verified:** V1 — awk proven against a fabricated 3-case fixture
|
||
(Mullvad 1-word + multi-word city + bare node); flake check exit 0;
|
||
downstream-template-home builds (writeShellScriptBin syntax-gates both
|
||
scripts). Real tailscale output is V3 (existing VPN queue entry).
|
||
- **Pending:** V3 VPN menu live paths (extended, not new).
|
||
- **Next suggestion:** wallpapers artifact split (LATER, decided).
|
||
|
||
## 2026-07-11 — Night-light geo mode (lat/long → wlsunset)
|
||
- **Task:** BACKLOG LATER "Night-light geo mode" (human-picked).
|
||
- **Did:** `nomarchy.nightlight.latitude`/`.longitude` (both set = geo mode):
|
||
`services.wlsunset` (location-computed sunrise/sunset, `.temperature` →
|
||
night temp) replaces hyprsunset; the toggle script's `unit=` and the
|
||
live-state ExecCondition follow via one `unit` let-binding. Template
|
||
example lines, README row, ROADMAP ✓. New `checks.nightlight-geo`:
|
||
pure-eval asserts on the rendered units (coords + temp in ExecStart,
|
||
ExecCondition present, hyprsunset off). Declarative-only (no menu writer —
|
||
coords are machine config like keyboard layout).
|
||
- **Verified:** V1 — `nix flake check --no-build` exit 0 (evals the new
|
||
asserts + option-docs); built `downstream-template-home` (default
|
||
hyprsunset path unregressed) + the check drv. Caught en route: HM renders
|
||
`ExecStart` as a list (`toString` needed in eval asserts).
|
||
- **Pending:** V3 queued (HARDWARE-QUEUE § Any machine): visible warm shift
|
||
at location night + toggle/persistence on the swapped unit.
|
||
- **Next suggestion:** wallpapers artifact split (LATER, decided).
|
||
|
||
## 2026-07-11 — Sync-sweep rule + grooming + zram user docs (human-requested)
|
||
- **Task:** Bernardo: groom stale items and codify the check so they don't
|
||
recur; close the zram user-doc gap.
|
||
- **Did:** LOOP.md §5 gains step 4 **Sync sweep** (grep item/feature across
|
||
agent/+docs/ on ship; prune recorded `[x]` queue entries) + an AGENTS.md
|
||
rule line. Applied it: BACKLOG PROPOSED pruned (auto-theme pitch was
|
||
stale — shipped as #79; shipped/promoted placeholders removed; v1.0
|
||
pointer rewritten; FUTURE promoted-stub dropped). HARDWARE-QUEUE pruned
|
||
29 checked `[x]` entries (363→~250 lines), dangling refs reworded,
|
||
prune rule in header. README §3 now documents the zram default +
|
||
hibernation out-of-the-box + MIGRATION pointer.
|
||
- **Verified:** V0 (docs/meta only) — grep sweep for dangling refs clean.
|
||
- **Pending:** night-light geo mode next (same session).
|
||
- **Next suggestion:** wallpapers artifact split (LATER, decided).
|
||
|
||
## 2026-07-11 — Vendor-neutral agent docs restructure (human-requested)
|
||
- **Task:** Bernardo: de-vendor the agent instructions (multi-model repo),
|
||
clean stale files, better docs/agent/.claude structure.
|
||
- **Did:** New root `AGENTS.md` entry (CLAUDE.md → symlink). Skill bodies
|
||
moved to `agent/`: VERIFICATION.md (enforcement, ex-nomarchy skill),
|
||
DELEGATION.md (tiers light/standard/frontier + scout/runner contracts +
|
||
fan-out; consolidates CLAUDE.md table + LOOP §economy + skill §6.5),
|
||
THEME-DESIGN.md (ex-theme skill, now with frontmatter’d shim). `.claude/`
|
||
is a thin adapter (shims route into `agent/`). Maps updated (agent/,
|
||
docs/, README tree). Stale: `.gitignore` old_distro entry dropped; local
|
||
result*/__pycache__ removed. JOURNAL rotated (29 kept, 120 →
|
||
JOURNAL-ARCHIVE.md).
|
||
- **Verified:** V0 — `nix flake check --no-build` exit 0 with the symlink
|
||
tracked; vendor-name grep clean outside DELEGATION's mapping table.
|
||
- **Pending:** nothing; other harnesses add their own adapter row when used.
|
||
- **Next suggestion:** #76/#79 remain [blocked:hw]; otherwise groom PROPOSED.
|
||
|
||
## 2026-07-11 — #76 checks.hibernate-swapfile (VM-verify the swapfile+offset)
|
||
- **Task:** Bernardo — push #76's swapfile-resume residual into a VM (like
|
||
the auto-theme sunset trick).
|
||
- **Did:** Tried a full runtime-swapfile hibernate→resume test; it hit a
|
||
bounded, definitive **`CanHibernate=no`** — systemd won't hibernate to a
|
||
swap that isn't declared in the boot config, and a runtime-computed
|
||
`resume_offset` can't reach the boot cmdline (the genuine chicken-and-egg).
|
||
First cut also had an **unbounded `wait_for_shutdown`** that hung → killed
|
||
it, bounded the wait in a thread (180s) + a `CanHibernate` pre-check, which
|
||
is what surfaced the clean verdict. Pivoted `checks.hibernate-swapfile` to
|
||
what a VM *can* prove deterministically and the partition test can't: the
|
||
installer swapfile **build + offset** — NOCOW `mkswapfile`, file-type
|
||
swapon, valid `map-swapfile -r` offset accepted by `/sys/power/resume_offset`,
|
||
zram above it. (Device fix: `/dev/vdb` once `useNixStoreImage` was dropped.)
|
||
- **Verified:** **V2 PASS** (fresh build, exit 0). BACKLOG/ROADMAP updated;
|
||
#76 residual narrowed to the literal encrypted power-cycle (dev box runs it).
|
||
- **Lesson:** the sunset-trick spirit applies but not always the full cycle —
|
||
when systemd/kernel gates the behaviour (CanHibernate), verify the
|
||
*construction* deterministically and leave only the physical cycle to HW.
|
||
Always bound `wait_for_shutdown` (no timeout param → thread + join).
|
||
- **Next suggestion:** #76/#79 both `[blocked:hw]`; QA / PROPOSED otherwise.
|
||
|
||
## 2026-07-11 — Code-review fixes (parallel review of the session batch)
|
||
- **Task:** Bernardo asked for parallel work; spawned a fresh-eyes opus
|
||
review of `2055842..HEAD` (static). It found the batch sound — 2 real LOW
|
||
edge bugs, 1 false positive, 1 cosmetic.
|
||
- **Did:** (1) `cmd_auto` — inverted sunrise/sunset (sunrise > sunset) went
|
||
perpetually day; replaced the `not between` shortcut with a real
|
||
wrap-around `mins >= sunrise or mins < sunset`, so a cross-midnight day
|
||
window switches both ways. (2) `rofi.nix` autotheme HH:MM guard tightened
|
||
`[0-2][0-9]` → `[01][0-9]|2[0-3]` so 24–29 are rejected. Dismissed the
|
||
`breeze` finding (papirus DOES ship breeze/breeze-dark — verified) and the
|
||
cosmetic doctor-RAM one.
|
||
- **Verified:** py_compile; boundary truth-table (normal + wrap-around);
|
||
HH:MM case table (23:00/19:59/20:00 accept, 24/25/30:00 reject); `auto
|
||
--which` normal-case unchanged; menu bash -n; flake check green. Normal
|
||
case unchanged so `checks.auto-theme` still holds.
|
||
- **Pending:** hibernate-swapfile VM test still running (uncommitted flake.nix).
|
||
- **Next suggestion:** land hibernate-swapfile once its VM test returns.
|
||
|
||
## 2026-07-10 — #79 V2: checks.auto-theme (simulated sunset) — was mis-framed V3
|
||
- **Task:** Bernardo challenged the "V3 real-session" framing — a simulated
|
||
sunset IS VM-testable. He's right; I'd conflated "needs a real desktop"
|
||
with "needs the generic home-manager switch."
|
||
- **Did:** Added `checks.auto-theme` runNixOSTest: installs nomarchy-state-sync,
|
||
points `NOMARCHY_DEFAULT_THEMES` at presets, stubs the switch via
|
||
`NOMARCHY_REBUILD` (a marker), configures the pair+schedule, then **walks
|
||
the VM clock** 19:55→20:05→20:06→next-day 07:30 asserting slug goes
|
||
summer-day → night (1 rebuild) → night (idempotent, still 1) → day (2). The
|
||
self-gating I relied on: presets via env, wallpaper/notify no-op headless,
|
||
run_switch honors NOMARCHY_REBUILD + waybar nudge is check=False.
|
||
- **Verified:** **V2 PASS** — `nix build .#checks…auto-theme` fresh, exit 0.
|
||
Dropped #79's `[blocked:hw]`; it's done (V2). Updated ROADMAP.
|
||
- **Lesson:** don't default "timer/session feature" to V3 — stub only the
|
||
generic step (the real HM switch, covered elsewhere) and simulate the rest
|
||
(clock) headlessly. Only the literal timer-fires-on-OnCalendar is on-HW,
|
||
and its schedule is systemd-analyze-validated.
|
||
- **Next suggestion:** NEXT head #76 `[blocked:hw]`; else QA / PROPOSED.
|
||
|
||
## 2026-07-10 — #79 slice 3: Look & Feel › Auto theme menu (#79 complete)
|
||
- **Task:** BACKLOG #79 slice 3 — the menu; completes the feature.
|
||
- **Did:** `rofi.nix` — "Auto theme (on/off)" row in Look & Feel + an
|
||
`autotheme)` submenu: toggle, pick day/night (from
|
||
`nomarchy-state-sync list`), set sunrise/sunset (HH:MM input, validated).
|
||
Enable writes the flag + defaults the summer pair `--no-switch`, then
|
||
`exec auto --force` — one rebuild installs the timer AND applies the right
|
||
theme. Disable is instant `--no-switch` (`auto` self-gates; the lingering
|
||
timer no-ops). Day/night/times are live `--no-switch`.
|
||
- **Verified:** **V1** — HM generation builds (`writeShellScriptBin` bash -n
|
||
on nomarchy-menu passes) + bash -n on the built menu. **Logic test**
|
||
(stubbed rofi/theme-sync/notify): selecting "Auto theme (off)" runs exactly
|
||
`set day summer-day`, `set night summer-night`, `set enable true`
|
||
(all `--no-switch`), then `auto --force` — the intended one-rebuild path.
|
||
Disable path is static-clear (set false `--no-switch`, no `auto`); a
|
||
stateful-stub dynamic test would loop (stub doesn't reflect the flip). V0
|
||
flake check green. **#79 collapsed to `[blocked:hw]`** (all 3 slices done;
|
||
only live-session switch remains, needs a Nomarchy machine).
|
||
- **Pending:** V3 real-session (timer switches day↔night across sunset).
|
||
- **Next suggestion:** NEXT head #76/#79 both `[blocked:hw]`; QA/PROPOSED.
|
||
|
||
## 2026-07-10 — #79 slice 2: auto-theme systemd timer
|
||
- **Task:** BACKLOG #79 slice 2 — the timer/hook.
|
||
- **Did:** `modules/home/autotheme.nix` (imported in home default.nix):
|
||
`systemd.user.{service,timer}.nomarchy-auto-theme`, install gated on
|
||
`config.nomarchy.settings.autoTheme.enable or false` (state-driven, like
|
||
updates.nix gates on its enable). Service runs `nomarchy-state-sync auto`
|
||
with a PATH for `home-manager`; timer `OnStartupSec=1min` +
|
||
`OnCalendar=*:0/15` + `Persistent`. Chose periodic over exact
|
||
sunrise/sunset timers — robust to suspend/DST, and `auto` is idempotent so
|
||
ticks are cheap (rebuild only at the transition).
|
||
- **Verified:** **V1** — real-config eval (state temp-enabled, restored):
|
||
`settings.autoTheme.enable`→true, timer `OnCalendar`=`*:0/15`, service
|
||
ExecStart=`… nomarchy-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 until
|
||
`git add` — flake eval only sees tracked files.)
|
||
- **Pending:** live timer→`home-manager switch` on a real Nomarchy session
|
||
(needs a Nomarchy machine, like #76). Slice 3 (menu) next.
|
||
- **Next suggestion:** #79 slice 3 — Look & Feel › Auto theme menu.
|
||
|
||
## 2026-07-10 — #79 slice 1: auto time-of-day theme CLI primitive
|
||
- **Task:** Split BACKLOG #79 (`VISION § D`, `[big]`) into 3 slices (CLI /
|
||
timer / menu); took slice 1.
|
||
- **Did:** `nomarchy-state-sync auto` — reads
|
||
`settings.autoTheme.{enable,day,night,sunrise,sunset}`, computes day/night
|
||
by the local clock, and applies the matching preset **only if different**
|
||
(idempotent → the slice-2 timer won't rebuild needlessly). `--which`
|
||
prints the decision without switching; `--force`/`--no-switch` too.
|
||
Factored `cmd_apply`'s core into `apply_named` so `auto` reuses the exact
|
||
same one engine (GOALS: no second pipeline).
|
||
- **Verified:** **V1** package builds; functional tests on the built bin
|
||
against scratch state: wide-day→day slug, 00:00–00:01 window→night,
|
||
disabled→no-op, missing day/night→die, `auto --no-switch` writes state,
|
||
re-run→"already on" no-op, plain `apply` still writes (refactor intact).
|
||
**V0** py_compile + flake check + `checks.state-sync-validate` green.
|
||
- **Pending:** slices 2 (systemd sunrise/sunset timers + login apply, V2)
|
||
and 3 (Look & Feel menu) remain under #79.
|
||
- **Next suggestion:** #79 slice 2 — the timer/hook (V2 runNixOSTest).
|