aboutsummaryrefslogtreecommitdiff
path: root/working/hyprland-lua-port/README.org
diff options
context:
space:
mode:
Diffstat (limited to 'working/hyprland-lua-port/README.org')
-rw-r--r--working/hyprland-lua-port/README.org131
1 files changed, 131 insertions, 0 deletions
diff --git a/working/hyprland-lua-port/README.org b/working/hyprland-lua-port/README.org
new file mode 100644
index 0000000..42779e5
--- /dev/null
+++ b/working/hyprland-lua-port/README.org
@@ -0,0 +1,131 @@
+#+TITLE: Hyprland .conf → Lua port — staged, not deployed
+#+AUTHOR: Craig Jennings
+
+* Status
+
+Built and verified in a nested compositor. *Not deployed.* I deployed it to the
+dotfiles tree on 2026-08-24 and then rolled it back the same afternoon, because
+the switch had not been checked on real hardware and the machine needs to stay
+usable. The dotfiles repo is untouched at =8f692f5=; the live config is the
+original =hyprland.conf=.
+
+The port goes live only after the hardware check in =todo.org= under "Manual
+testing and validation" passes.
+
+* What is here
+
+| File | What it is |
+|----------------------------+---------------------------------------------------------------|
+| =hyprland.lua= | The deliverable, 788 lines. Shared config. |
+| =velox-local.lua= | velox host overrides, for =velox/.config/hypr/conf.d/=. |
+| =ratio-local.lua= | ratio host overrides, for =ratio/.config/hypr/conf.d/=. |
+| =reader-changes-for-lua.patch= | dotfiles-side: the four readers, ported and mutation-tested. |
+| =test-desktop-for-lua.patch= | archsetup-side: the post-install desktop checks. |
+| =hyprland.lua.generated= | Raw =hyprlang2lua= output, merging mode. Derivation evidence. |
+| =nomerge.lua= | Same converter with =--no-merge=. Derivation evidence. |
+
+The two patches are the part that is easy to lose and expensive to redo. Both
+were mutation-tested — every ported assertion was confirmed to go red when the
+property it guards was removed — so replay them rather than rewriting the
+assertions from scratch.
+
+* Redeploy, when the port is ready
+
+1. =cp hyprland.lua ~/.dotfiles/hyprland/.config/hypr/hyprland.lua=
+2. =cp velox-local.lua ~/.dotfiles/velox/.config/hypr/conf.d/local.lua=
+3. =cp ratio-local.lua ~/.dotfiles/ratio/.config/hypr/conf.d/local.lua=
+4. Move the three =.conf= files out of their stow packages. Do NOT merely leave
+ them beside the =.lua=: with both present Hyprland 0.56.2 loads the =.lua=
+ (proven — see below), so leaving the =.conf= in place buys no rollback and
+ only creates ambiguity about which file is live.
+5. =cd ~/.dotfiles && git apply <path>/reader-changes-for-lua.patch=
+6. =cd ~/code/archsetup && git apply <path>/test-desktop-for-lua.patch=
+7. Restow. Expect two traps, both hit on 2026-08-24 and both documented in
+ =todo.org=: =make restow hyprland= aborts on the pre-existing
+ =obsbot-wb-guard.service= conflict in =common= (restow =hyprland= and the host
+ package individually instead), and the running Hyprland rewrites a stub
+ =hyprland.conf= within a second of the symlink vanishing. Silence the stub with
+ =hyprctl keyword misc:disable_autoreload 1=, do the stow, then set it back to 0.
+8. *Push the dotfiles change before committing archsetup.* The installer clones
+ the dotfiles *remote* (=archsetup:1481=), so until the push lands a fresh VM
+ stows a tree with only =hyprland.conf= and the post-install checks fail.
+
+* Two things already proven, so nobody re-derives them
+
+*With both files present, the =.lua= wins.* Tested in a nested Hyprland 0.56.2
+with a fixture whose =.conf= set =gaps_in=11= and whose =.lua= set =77=. Result
+was 77, and the log read "[cfg] Using lua config found at ...hyprland.lua". This
+is why step 4 moves the =.conf= out rather than leaving it as a fallback.
+
+*The converter is a draft, not an answer.* =hyprlang2lua=
+(github.com/EIonTusk/hyprlang2lua) reported 100% coverage and still produced
+three functional defects, two of which would have broken the desktop. The two
+generated files are kept as evidence: both still carry the unfixed bind defect
+(="CTRL" .. mod .. " + S"=, which collapses to an unparseable =CTRLSUPER + S=),
+and the merging-mode file shows the source glob emitted mid-file where it silently
+reverses every per-host override. =--no-merge= fixed the ordering structurally;
+the rest were hand-fixed.
+
+* Review findings folded in (2026-08-24)
+
+An isolated review of the deployed diff, before the rollback. Four were fixed in
+the files here; the rest are gates on redeploying, not on the port's correctness.
+
+** Fixed here
+
+- =hl_source_glob= now surfaces all three failure modes and survives them. A
+ host override that fails to parse was warned about and skipped, which on velox
+ means coming up with no =force_zero_scaling= and no monitor scale — looking
+ like the whole port failed rather than one file. A runtime error inside the
+ chunk was unprotected and would have taken the entire config down over a single
+ host file. Now: parse failure says SKIPPED, runtime failure says PARTIAL and is
+ caught with =pcall=, and a glob matching nothing says NO MATCH. hyprlang did
+ none of this.
+- The =col.nogroup_border*= rationale sat *below* the =col= table, reading as a
+ preamble to =layout=. Moved above the two keys it explains — the same defect
+ the file header says was fixed for autostart.
+- =Generated by hyprlang2lua. Review TODOs before reloading Hyprland= removed
+ from all three files. No TODOs exist, and in =ratio-local.lua= it had landed
+ mid-paragraph, splitting the DP-4 rationale from the =hl.monitor= call it
+ explains.
+- =ratio-local.lua='s usage examples were still hyprlang syntax
+ (=monitor=DP-1,...=, =bind = $mod, L, ...=), which are syntax errors in a Lua
+ file, and the second named =$mod= — a variable a sourced chunk cannot see.
+ Rewritten in Lua, with a note on the scoping. Verified rather than assumed:
+ =loadfile= gives the chunk globals only, and both =mod= and =at_start= are
+ locals, so both read =nil= inside a sourced file.
+
+** Refuted by measurement
+
+- *Duplicate chords append; they do not replace.* The config binds Super+Z twice
+ on purpose (=exec pypr zoom= plus =submap zoom=), and the same for Escape
+ inside the submap — if the Lua API replaced rather than appended, Super+Z would
+ enter the submap without zooming and the pairing the config's own comment
+ relies on would be broken. Tested in a nested Hyprland 0.56.2 with exactly that
+ shape: both binds register. The live =.conf= session registers the same pair,
+ so behaviour matches. No action needed; recorded so nobody re-derives it.
+
+** Gates on redeploy — do these as part of the switch
+
+1. *Do not put the =.conf= files in a =retired/= directory inside the repo
+ without also excluding them from =dotfiles-validate=.* Its find uses
+ =-path '*/.config/hypr/*.conf'=, which globs across slashes and would match
+ the retired copies — 81 of 228 checked references came from the dead config
+ when this was tried. The validator would then fail pointing at a file kept
+ precisely because nothing loads it. Add =-not -path "$root/retired/*"= to both
+ finds, or park the =.conf= files outside the repo entirely.
+2. *Add tests for the new =dotfiles-validate= Lua branch.* The 25 new lines ship
+ with none. Proven vacuous: replacing both new awk regexes with =NEVERMATCHES=
+ still leaves =tests/dotfiles-validate/= reporting 15 tests OK. An extractor
+ that matches nothing prints nothing and exits 0 — the same false-pass shape
+ the three ported test suites got vacuity guards for. This one has no guard.
+3. *Guard the override ordering.* Nothing asserts =hl_source_glob= is the last
+ statement in =hyprland.lua=, and it is the single invariant the whole per-host
+ layer rests on. An edit that moves it above the =hl.config= blocks silently
+ reverses every host override — converter defect 1, the one that would have
+ reverted the Qt scaling fix. archsetup's VM suite structurally cannot catch
+ it, because the VM stows no host tier. The guard belongs in the dotfiles repo.
+4. *Sweep the prose comments that still name =hyprland.conf=.* About fifteen
+ across live scripts. =hyprland/.local/bin/waybar-reserve:12= is the one that
+ matters: it documents "Wired as =exec = waybar-reserve= in hyprland.conf",
+ which is exactly the mechanism the port replaces with =at_reload=.