diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index 3f3d476..2117ceb 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -271,6 +271,53 @@ bug, not the instance: nothing today asserts that a whole-swap's on-click survives Waybar's actual environment, so the next hand-written jsonc can reintroduce it silently. +### 142. A rebuild while docked undoes dock mode (the panel comes back, a workspace jumps to it) + +Bernardo 2026-07-16: every rebuild while docked lands in the undocked state — +laptop panel back on, a workspace moved onto it — and he re-picks **Dock mode** +in the Display menu by hand. Diagnosed statically on the dev box (no session +disruption needed; our own code already proves each step): + +1. **Dock mode is runtime-only.** `nomarchy-display-transition dock` ends with + `hyprctl keyword monitor , disable` (`hyprland.nix:205`) — a live + compositor command. Nothing writes it down: his `state.json` has no display + key at all, so dock mode is the one display setting outside the in-flake + state, which is exactly why it cannot survive anything. +2. **Any config reload re-enables everything.** The generated config's only + monitor line is the catch-all `monitor=,preferred,auto,1` (live + hyprland.conf:175 — he has no `displayProfiles`), so a reload turns every + output back on, `eDP-1` included, and Hyprland puts a workspace on the + output that just appeared. We do not have to guess that a reload does this: + the **undock** path uses `hyprctl reload` deliberately, as the hammer that + re-enables an inert disabled panel, hardware-proven 2026-07-14 + (`hyprland.nix:225`). A rebuild reloads the config and therefore *performs + an undock*, precisely and by construction. +3. **The watcher cannot see it happen.** `reconcile` diffs `outputs()` = + `hyprctl monitors all` (`:505`), which lists **disabled** monitors too. So + the connected set is byte-identical before and after the flip, `cur != + known_outputs` is false, and reconcile returns having done nothing. The + watcher tracks connect/disconnect and is structurally blind to + enable/disable — the blind spot in round 4/5's "the output set, not the + event, is the truth" (ROADMAP § Docking rounds 4–5). + +**Shape, and the trap in the obvious fix.** The tempting move is to bake the +disable into the config (state → `monitor=eDP-1,disable`) so a reload preserves +it. **Do not** without a guard: a persisted disable with no external attached +is a zero-output session at login — the black brick #100 and #127 are both +about. The config is evaluated with no knowledge of what is plugged in, so it +must keep defaulting to "everything on". Better: persist the *intent* +(`settings.display.dockMode`, in-flake, menu-writable — the philosophy this +currently violates) and let the **watcher** re-assert it, since only it knows +what is live. That needs reconcile to also track the *enabled* set, so +"internal came back on while an external is present and the state says docked" +becomes an event it can act on — which fixes the reload case and any other +path that silently re-enables the panel. Gate re-assertion on an external +actually being present, never on the state key alone. + +Pass = docked, `nomarchy-home` (and `nomarchy-rebuild`) → panel stays off, no +workspace moves, no menu trip; undocked rebuild unchanged; unplug while the +state says docked still restores the panel. + ### 120. A netinstall ISO, next to the fat offline one Bernardo 2026-07-14, after seeing the measured size: **keep the current ISO