INC-2026-04-07-002: Investigation

Root Cause

The Stow Architecture

~/.config/hypr is not a directory — it is a symlink to the stow package:

~/.config/hypr → ../atelier/_projects/personal/dots-quantum/hyprland/.config/hypr

This means every file Hyprland reads from ~/.config/hypr/ is actually read from the dots-quantum git repository. If a file is deleted from git, it disappears from the deployed config immediately.

The Breaking Change

Commit 64253e7 (fix(dotfiles): Guard .zshenv cargo source, harden gitignore, fix gitconfig portability) deleted the env-gpu.conf symlink from the hyprland stow package:

diff --git a/hyprland/.config/hypr/env-gpu.conf b/hyprland/.config/hypr/env-gpu.conf
deleted file mode 120000
--- a/hyprland/.config/hypr/env-gpu.conf
+++ /dev/null
@@ -1 +0,0 @@
-/home/evanusmodestus/atelier/_projects/personal/dots-quantum/hosts/razer/env-gpu.conf

The commit message says "Untrack env-gpu.conf (already gitignored, was tracked before gitignore entry)." The intent was cleanup — the file was gitignored AND tracked, which is contradictory. But deleting it from git also deleted it from the stow package, which deleted it from the deployed config.

The Cascade

  1. env-gpu.conf removed from stow package directory

  2. ~/.config/hypr/env-gpu.conf ceases to exist (directory symlink)

  3. hyprland.conf line 113: source = ~/.config/hypr/env-gpu.conf fails — file not found

  4. Hyprland starts without GPU environment variables:

    • No LIBVA_DRIVER_NAME=nvidia

    • No __GLX_VENDOR_LIBRARY_NAME=nvidia

    • No GBM_BACKEND=nvidia-drm

    • No WLR_NO_HARDWARE_CURSORS=0

    • No __NV_PRIME_RENDER_OFFLOAD=1

  5. Compositor initializes on Intel iGPU in degraded mode

  6. USB HID keyboard (Razer, on the NVIDIA GPU’s USB controller) does not deliver input events to the compositor

  7. Virtual HID keyboard (Kinesis, via uhid on the Intel USB controller) continues to work

Proof

At commit 34065dc (before the deletion): env-gpu.conf symlink existed in stow package. Hyprland sourced it. Source line errored because the symlink target (hosts/razer/) didn’t exist at that older commit, BUT the error caused Hyprland to skip GPU config entirely — and the built-in keyboard worked. This is because without GPU config, Hyprland defaulted to a working state.

At main (after the deletion): env-gpu.conf doesn’t exist in the stow package at all. Same source error. But when the symlink was manually recreated pointing to the correct hosts/razer/env-gpu.conf (which now exists at main), the GPU config loaded and the keyboard worked.

Empty config test (Hyprland -c /dev/null): Built-in keyboard did NOT work. This initially confused the investigation, but is consistent — with no config at all, Hyprland has no GPU env vars AND no input configuration, defaulting to a state where USB HID is not functional on this hybrid GPU machine.

Investigation Evidence Log

Phase 1: Configuration Comparison (Eliminated as Direct Cause)

md5sum ~/.config/hypr/hyprland.conf  # Both machines
Result
790a130e77df802bb6a980b7f09ffe78  (identical on P16g and Razer)
readlink -f ~/.config/hypr/env-gpu.conf  # Razer
Result (when symlink existed)
/home/evanusmodestus/atelier/_projects/personal/dots-quantum/hosts/razer/env-gpu.conf
pacman -Q hyprland aquamarine nvidia-utils seatd  # Both machines
Result
hyprland 0.54.3-2    aquamarine 0.10.0-4
nvidia-utils 595.58.03-1    seatd 0.9.3-1

Phase 2: Session State (Eliminated)

loginctl list-sessions --no-legend  # Pre-reboot
Result
5 accumulated sessions from crash/restart cycles

Two reboots performed. Problem persisted. Session state eliminated.

Phase 3: Device Visibility

hyprctl devices  # Initial check
Result
mice:
Keyboards:
# ZERO devices
ls -la /dev/input/event{4,5,6}
Result
event4: root:input     (Kinesis via uhid)
event5: root:openrazer (Razer keyboard)
event6: root:openrazer (Razer keyboard interface 2)
groups  # User group check
Result
# input group NOT present

Fixes Applied (Necessary but Not Sufficient)

sudo usermod -aG input evanusmodestus
sudo tee /etc/udev/rules.d/99-openrazer-input-fix.rules << 'EOF'
SUBSYSTEM=="input", ATTRS{idVendor}=="1532", GROUP="input", MODE="0660"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger

These fixed device visibility (hyprctl devices showed keyboards after reboot) but did NOT fix the input issue.

Phase 4: openrazer Daemon and Kernel Module (Eliminated)

systemctl --user stop openrazer-daemon
systemctl --user disable openrazer-daemon
sudo rmmod razerkbd  # Rebind to hid-generic
dmesg | tail -5
Result
hid-generic 0003:1532:02C7.0004: input,hidraw2: USB HID v1.11 Keyboard
hid-generic 0003:1532:02C7.0005: input,hidraw3: USB HID v1.11 Mouse

Problem persisted after daemon stop AND module unload. Eliminated.

Phase 5: Raw Event Testing

timeout 3 cat /dev/input/event5 | od -A x -t x1 -N 192
Result
000000
# Zero bytes — Razer keyboard produced no evdev events
# EVIOCGRAB check
python3 -c "import fcntl,struct,os; [print(f'event{e}: NOT grabbed') for e in [4,5,6]]"

No exclusive grab on any device.

fuser -v /dev/input/event4 /dev/input/event5 /dev/input/event6
Result (after daemon stopped)
event4: Hyprland only
event5: Hyprland only
event6: Hyprland only

Phase 6: USB Device Identity

udevadm info /dev/input/event4
Result
DEVPATH=/devices/virtual/misc/uhid/0005:1D50:615E.0008  ← Kinesis (works)
udevadm info /dev/input/event5
Result
DEVPATH=/devices/pci.../1532:02C7.0003  ID_USB_DRIVER=usbhid  ← Razer (broken)

Phase 7: Empty Config Test

pkill -9 Hyprland
echo "" > /tmp/empty.conf
Hyprland -c /tmp/empty.conf
Result
Kinesis: works
Razer built-in: does NOT work

Phase 8: Git Bisect (The Breakthrough)

git -C ~/atelier/_projects/personal/dots-quantum checkout 34065dc
stow -R -t ~ hyprland
pkill -9 Hyprland && start-hyprland
Result
Source error: "globbing error: found no match" for env-gpu.conf
Built-in keyboard: WORKS
git -C ~/atelier/_projects/personal/dots-quantum checkout main
Result
env-gpu.conf: MISSING from stow package
Built-in keyboard: DOES NOT WORK
git -C ~/atelier/_projects/personal/dots-quantum diff 34065dc..main -- hyprland/
Result
diff --git a/hyprland/.config/hypr/env-gpu.conf b/hyprland/.config/hypr/env-gpu.conf
deleted file mode 120000
--- a/hyprland/.config/hypr/env-gpu.conf
+++ /dev/null
@@ -1 +0,0 @@
-/home/.../dots-quantum/hosts/razer/env-gpu.conf

Only change between working and broken: env-gpu.conf symlink deleted from git.

Phase 9: Confirmation

ln -sf /home/evanusmodestus/atelier/_projects/personal/dots-quantum/hosts/razer/env-gpu.conf \
  ~/atelier/_projects/personal/dots-quantum/hyprland/.config/hypr/env-gpu.conf
pkill -9 Hyprland && rm -rf /run/user/1000/hypr/* ~/.cache/hyprland/hyprlandCrash*
start-hyprland
Result
Built-in keyboard: WORKS
Super+D: WORKS
All keybinds: FUNCTIONAL

Investigation Rabbit Holes

Documented for learning. Each was investigated, evidence gathered, and eliminated.

Hypothesis Time Spent Why Eliminated

Stale logind sessions

30 min

Two reboots cleared sessions. Problem persisted.

XDG_SESSION_TYPE=tty

20 min

Identical on both machines. P16g works with same value.

Package version mismatch

15 min

All packages identical after upgrade.

openrazer daemon grabbing devices

20 min

Daemon stopped and disabled. Problem persisted.

razerkbd kernel module

30 min

Module unloaded, devices rebound to hid-generic. Problem persisted.

udev group permissions

30 min

Fixed (necessary) but not the root cause. Problem persisted after fix.

USB device reset

10 min

USB unbind/rebind performed. Problem persisted.

Empty config test

15 min

Keyboard didn’t work — misleading because no GPU config = same degraded state.

Total time in rabbit holes: ~2.5 hours. Root cause found in 15 minutes once the right question was asked (git diff between working and broken commit).