aboutsummaryrefslogtreecommitdiff
path: root/working/hyprland-lua-port/README.org
blob: 42779e59d8388b409ac676f2c536a8b71807d471 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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=.