Commit Graph

43 Commits

Author SHA1 Message Date
e6ac7b433e remove stupid comment from optiscalar config 2026-05-03 00:44:08 -04:00
774d748bfe yarn: drop GE-Proton compat-tool pin from steam-config-nix
nixpkgs' proton-ge-bin (the package wired into programs.steam.extra-
CompatPackages via modules/desktop-steam.nix) registers in Steam's
compat-tool list under its versioned id, currently GE-Proton10-34.
steam-config-nix's README example uses the unversioned string
"GE-Proton", which on a fresh boot wrote that literal value into
localconfig.vdf — Steam resolved it to no installed tool and silently
fell back to bundled Proton 10. FH5 then launched on stock Proton,
which doesn't pick up PROTON_FSR4_UPGRADE the way GE does.

Drop both `compatTool` (per-app) and `defaultCompatTool` (global).
The wrapper-based launchOptions.env path is unaffected — env vars
still pass through to whatever Proton Steam ends up using. Tool
selection goes back to manual Steam UI > Properties > Compatibility.

A versioned pin (`compatTool = "GE-Proton10-34";`) would work but
couples the host config to whatever the proton-ge-bin nixpkgs entry
ships this week; not worth the maintenance.
2026-05-03 00:42:07 -04:00
e010b4e3c1 game-mods: drop in-house launchOptions writer, hardcode FH5 ini
Replaces three handfuls of custom code with upstream / static data:

- Per-app Steam launch options now declared via different-name/steam-
  config-nix's `programs.steam.config.apps.<n>` instead of a custom
  ~70-line `apply_launch_options` Python function. The dropped writer
  was racy: it edited localconfig.vdf without checking for a running
  Steam, so any timer firing while Steam was open would lose its
  changes on the next Steam shutdown. steam-config-nix's `closeSteam`
  flag closes that race.

  Also moves the GE-Proton compat-tool pin to declarative config —
  one fewer manual click in Steam UI to remember.

- `mods.<>.launchOptions` option, the `launchOptionsData` aggregation,
  and `LAUNCH_OPTIONS_DATA` are removed from desktop-game-mods.nix.
  The module now does file-drops only; Steam config lives in its own
  `programs.steam.config` namespace, where it belongs.

  fh5-vkd3d-no-hvv (which existed only to set VKD3D_CONFIG) collapses
  into the FH5 launchOptions block in hosts/yarn/default.nix.

- `unitConfig.X-ConfigHash` on game-mods.service is replaced with
  `restartTriggers`. NixOS already emits `X-Restart-Triggers=<hash>`
  on the unit; the workaround was redundant. The Type=oneshot,
  RemainAfterExit=no semantics make `systemctl restart` re-run
  ExecStart cleanly on hash change.

- The awk pipeline that patched OptiScaler's stock OptiScaler.ini at
  build time is replaced with a hand-written hosts/yarn/optiscaler-
  fh5-rdna3.ini containing only the keys we override (5 of them).
  OptiScaler's Config::readString defaults missing keys to "auto"
  (Config.cpp:1568), so a minimal file is sufficient. Side benefits:
  one upstream-source dependency removed, a key-rename in upstream
  becomes a behavior change rather than a silent awk-no-match.

  Override values + sources:
    Fsr4Update=true              FH5 wiki, FSR4 Linux Setup
    DlssReactiveMaskBias=0.65    FH5 wiki, "Known Issues"
    FsrNonLinearColorSpace=true  FSR4 wiki, "Image Quality"
    EnableFsr2Inputs=false       FH5 wiki, "Known Issues"
    Dxgi=false                   FH5 wiki

- forza-trigger's three custom Python derivations (pydualsense,
  hidapi-usb, fdp) factored out of default.nix into a sibling
  python-packages.nix. Same logic, single-purpose file. Bumping a
  version is now a one-place hash roll.

- pkgs.dualsensectl removed from the daemon's environment.system-
  Packages. Single-shot writes from the CLI get clobbered by the BG
  sendReport thread within ~4ms anyway, so the tool is only useful
  with the daemon stopped — not worth the unconditional install.
  Bring it in ad-hoc with `nix-shell -p dualsensectl`.
2026-05-03 00:35:49 -04:00
1e8c294a80 forza-trigger: gate throttle on clutch state
User report: with the clutch in (pedal pressed, engine disconnected from
wheels), steering left still produced resistance on R2. The throttle
shouldn't have any feel when it's mechanically irrelevant.

RacingDSX's throttle resistance formula is
`avgAccel = sqrt(0.25*X^2 + 1.0*Z^2)`
derived from the accelerometer alone. It never checks clutch state, so
cornering G-forces keep producing trigger resistance even while the
clutch pedal is floored. Bug.

Fix: when Forza's clutch byte > 128 (clutch fully or mostly disengaged)
bypass the entire throttle path \u2014 slip detection and non-slip Feedback
both \u2014 and release the trigger. Uses the same one-shot 0x05 (active
retract) on transition + steady-state 0x00 (no-op) pattern as the
in-race \u2192 not-in-race transition (divergence #4) so we don't get the
trigger-motor whine from re-asserting 0x05 every frame.

Brake is unaffected: brake calipers operate independently of clutch
state, so ABS feel during clutch-in is still correct.

For auto-clutch users this also produces brief (~100 ms) trigger
relaxations during shifts \u2014 physically accurate (the engine *is*
momentarily disconnected during a shift) and matches the haptic feel of
a real manual transmission.

Documented as divergence #5 in the module docstring.
2026-05-03 00:35:49 -04:00
6b72ce2d6d yarn: FH5 OptiScaler FSR 4 + VKD3D upload-hvv workaround
Drops OptiScaler v0.9.1 + a FH5-tuned OptiScaler.ini into the FH5
install dir to unlock FSR 4 INT8 on this RDNA 3 (Navi 32) box.
OptiScaler intercepts FH5's DLSS/XeSS calls and reroutes them through
the bundled FFX SDK. Per the OptiScaler FH5 wiki page: rename
OptiScaler.dll to dxgi.dll, set Dxgi=false, DlssReactiveMaskBias=0.65,
and Fsr4Update=true for the INT8 RDNA 3 path.

Sets Steam launch options PROTON_FSR4_UPGRADE=1 and
DXIL_SPIRV_CONFIG=wmma_rdna3_workaround on fh5-optiscaler (the FSR 4
wiki documents both as required for RDNA 3 on Linux).

fh5-vkd3d-no-hvv is its own mod (no files, just one launchOptions
entry for VKD3D_CONFIG=no_upload_hvv) so the upload-hvv workaround
can be removed when a future Proton release fixes the underlying
issue without disturbing the OptiScaler config.

Extends the intro skip stub to cover the hires variant of the
T10/Microsoft Studios splash; the engine picks SD or hires based on
the installed asset profile, so stub both per PCGamingWiki.
2026-05-03 00:35:49 -04:00
b25cb4a90f forza-trigger: stop emitting mode 0x05 every frame in pre-race idle
The previous fix used canonical Off (mode 0x05) everywhere we wanted the
trigger to feel released \u2014 pre-race per-frame, idle timeout, shutdown.
Per Sony's docs (Nielk1 Rev 6) mode 0x05 "actively returns the trigger
stop to the neutral position". Re-asserting it 60 times/sec from main
thread, propagated by pydualsense's BG thread to the controller at
~250 Hz, made the trigger motor audibly whine as the firmware repeatedly
snapped the (already-neutral) trigger back to neutral.

Right answer: hybrid. One-shot 0x05 on the in-race \u2192 not-in-race
transition (and on the telemetry-idle timeout) so the firmware actually
retracts the motor; mode 0x00 (TriggerModes.Off, no-op clear) for
steady-state pre-race / idle frames so we're not yelling RESET in the
firmware's ear forever.

Implementation: prev_in_race tracks the last frame's race state. Steady
non-race frames call _apply_normal (mode 0x00); the first frame after a
race-end transition calls _apply_off (mode 0x05). pydualsense's BG
thread holds the 0x05 in memory long enough (one main-thread frame =
~16ms = ~4 BG iterations) to publish it to the controller before main
switches the in-memory state to 0x00.

Restores _apply_normal and DS_MODE_NORMAL that the previous commit
deleted. Updates divergence #4 in the module docstring.
2026-05-03 00:35:49 -04:00
bb983a88e2 game-mod: extend module 2026-05-03 00:35:49 -04:00
07583b6f96 steamos: disable steam deck cmdlineConfig for non-steamdeck hosts 2026-05-03 00:35:49 -04:00
876864c854 forza-trigger: actively release trigger and clear lightbar on idle
Two issues in the deployed daemon:

  1. After FH5 exits, the lightbar stayed lit. reset_triggers() touched
     only triggers; pydualsense's BG sendReport thread kept re-publishing
     whatever TouchpadColor we last set, so the controller stayed in the
     last race color forever.

  2. R2 had residual tension in FH5's main menu and on the desktop after
     a race. Pre-race / idle states were emitting RacingDSX's NormalTrigger
     (mode byte 0x00), which per Sony's docs (Nielk1 Rev6) only clears
     state without retracting the trigger motor; mode 0x05 (canonical Off
     / Reset) actively returns the trigger to neutral. RacingDSX-on-Windows
     gets away with 0x00 because something else (Steam Input or the OS)
     reliably resets the motor on focus loss; on Linux nothing does.

Fixes:
  - Drop _apply_normal/DS_MODE_NORMAL. Use _apply_off (mode 0x05) for every
    'release the trigger' intent: pre-race per-frame, idle timeout, mid-race
    zero-strength fallback, shutdown.
  - Add reset_lightbar() that writes RGB(0,0,0).
  - Track have_telemetry and fire the idle-timeout branch whenever
    telemetry has been silent for IDLE_TIMEOUT_S, regardless of in_race.
    Reset both triggers and lightbar in that branch.

Documented as divergence #4 in the module docstring.
2026-05-03 00:35:49 -04:00
6e69b40b4e lact: disable undervolt 2026-05-03 00:35:49 -04:00
de0b5a6009 game-mods: init
Add override for fh5 startup video
2026-05-03 00:35:49 -04:00
7749149c5d lact: -130 -> -120 2026-05-03 00:35:49 -04:00
fa741d9c29 lact: -150 -> -130 2026-05-03 00:35:48 -04:00
31c309af1f yarn: forza dualsense adaptive trigger bridge 2026-05-03 00:35:48 -04:00
975c4f7af1 yarn: declarative lact config 2026-05-03 00:35:48 -04:00
394b890008 yarn: add impermanence for bluetooth devices (doesn't forget them now) 2026-05-03 00:35:48 -04:00
44a5d01960 yarn: mount /var/lib/agenix in initrd
All checks were successful
Build and Deploy / mreow (push) Successful in 2m16s
Build and Deploy / yarn (push) Successful in 1m3s
Build and Deploy / muffin (push) Successful in 1m6s
agenix activation runs from initrd-nixos-activation-start, which fires
right after /sysroot/persistent is mounted but before impermanence's
stage-2 bind mounts. The TPM identity at /var/lib/agenix/tpm-identity
was therefore unreadable at activation time, and every secret silently
failed to decrypt: 'no readable identities found'. Visible downstream
fallout was pull-update-apply hitting HTTP 401 against the binary cache
because nix-cache-netrc was never written to /run/agenix.

Mark /var/lib/agenix as neededForBoot via a bare fileSystems entry,
mirroring the existing /home/${username} bind. Drop the now-redundant
environment.persistence directory entry to avoid two competing units.
2026-04-27 17:42:40 -04:00
2ab1c855ec Revert "muffin: test, move to 7.0"
All checks were successful
Build and Deploy / mreow (push) Successful in 1m45s
Build and Deploy / yarn (push) Successful in 47s
Build and Deploy / muffin (push) Successful in 1m31s
This reverts commit f67ec5bde6.
2026-04-25 10:50:00 -04:00
f67ec5bde6 muffin: test, move to 7.0
Some checks failed
Build and Deploy / mreow (push) Successful in 1h43m17s
Build and Deploy / yarn (push) Successful in 22m1s
Build and Deploy / muffin (push) Failing after 33s
2026-04-25 02:12:21 -04:00
86cf624027 Revert "muffin: test, move to 6.18"
All checks were successful
Build and Deploy / mreow (push) Successful in 50s
Build and Deploy / yarn (push) Successful in 44s
Build and Deploy / muffin (push) Successful in 1m2s
This reverts commit 1df3a303f5.
2026-04-24 14:21:40 -04:00
1df3a303f5 muffin: test, move to 6.18
All checks were successful
Build and Deploy / mreow (push) Successful in 1m15s
Build and Deploy / yarn (push) Successful in 43s
Build and Deploy / muffin (push) Successful in 1m29s
2026-04-24 14:08:26 -04:00
07a5276e40 patiodeck: fix disko partition order (fixed-size before 100%) 2026-04-24 01:47:25 -04:00
f3d21f16fb desktop-jovian: unify steam/jovian config across yarn + patiodeck
- modules/desktop-jovian.nix: shared Jovian deck-mode config (unfree
  predicate, jovian.steam, sddm, gamescope override, imports
  desktop-steam-update.nix)
- home/progs/steam-shortcuts.nix: declarative non-Steam shortcuts
  (Prism Launcher); add new entries here for all Jovian hosts
- hosts/yarn/default.nix: reduced to host-specific config only
- hosts/patiodeck/default.nix: same
2026-04-23 22:42:25 -04:00
5b2a1a652a patiodeck: add prism launcher to steam shortcuts 2026-04-23 22:34:58 -04:00
665793668d patiodeck: add steam deck LCD host 2026-04-23 22:34:47 -04:00
5ccd84c77e yarn: fix steamos-update exit code — 7 means no update, not 0
Some checks failed
Build and Deploy / mreow (push) Successful in 1m48s
Build and Deploy / yarn (push) Successful in 4m39s
Build and Deploy / muffin (push) Failing after 31s
Steam interprets exit 0 from 'steamos-update check' as 'update applied
successfully' and shows a persistent 'update available' notification.
The SteamOS convention is exit 7 = no update available.
2026-04-23 20:47:33 -04:00
b41a547589 yarn: persist root fish history
Some checks failed
Build and Deploy / mreow (push) Successful in 46s
Build and Deploy / yarn (push) Successful in 51s
Build and Deploy / muffin (push) Failing after 28s
2026-04-23 20:17:02 -04:00
e019f2d4fb secrets overhaul: use tpm for laptop (need to migrate desktop later) 2026-04-23 14:22:37 -04:00
22282691e7 grafana: add minecraft server stats 2026-04-23 01:17:10 -04:00
0901f5edf0 deploy: potentially fix self-deploy issue? 2026-04-22 23:02:38 -04:00
d00ff42e8e site-config: dedupe cross-host values, fix stale dark-reader urls, drop desktop 1g hugepages
new site-config.nix holds values previously duplicated across hosts:
  domain, old_domain, contact_email, timezone, binary_cache (url + pubkey),
  dns_servers, lan (cidr + gateway), hosts.{muffin,yarn} (ip/alias/ssh_host_key),
  ssh_keys.{laptop,desktop,ci_deploy}.

threaded through specialArgs on all three hosts + home-manager extraSpecialArgs +
homeConfigurations.primary + serverLib. service-configs.nix now takes
{ site_config } as a function arg and drops its https namespace; per-service
domains (gitea/matrix/ntfy/mollysocket/livekit/firefox-sync/grafana) are
derived from site_config.domain. ~15 service files and 6 vm tests migrated.

breakage fixes rolled in:
 - home/progs/zen/dark-reader.nix: 5 stale *.gardling.com entries in
   disabledFor rewritten to *.sigkill.computer (caddy 301s the old names so
   these never fired and the new sigkill urls were getting dark-reader applied)
 - modules/desktop-common.nix: drop unused hugepagesz=1G/hugepages=3
   kernelParams (no consumer on mreow or yarn; xmrig on muffin still reserves
   its own via services/monero/xmrig.nix)

verification: muffin toplevel is bit-identical to pre-refactor baseline.
mreow/yarn toplevels differ only in boot.json kernelParams + darkreader
storage.js (nix-diff verified). deployGuardTest and fail2banVaultwardenTest
(latter exercises site_config.domain via bitwarden.nix) pass.
2026-04-22 20:48:29 -04:00
8cdb9c4381 yarn: improve pull-update-apply script
Some checks failed
Build and Deploy / mreow (push) Successful in 2m3s
Build and Deploy / yarn (push) Successful in 1m3s
Build and Deploy / muffin (push) Failing after 28s
2026-04-22 20:11:22 -04:00
3902ad5de3 yarn: fix jovian-stubs
Some checks failed
Build and Deploy / mreow (push) Successful in 1m9s
Build and Deploy / yarn (push) Successful in 4m36s
Build and Deploy / muffin (push) Failing after 33s
2026-04-22 19:54:00 -04:00
0538907674 yarn: simplify stubs
Some checks failed
Build and Deploy / mreow (push) Successful in 41s
Build and Deploy / yarn (push) Failing after 1m8s
Build and Deploy / muffin (push) Failing after 1m39s
2026-04-22 19:44:53 -04:00
90ce41cd9e gitea: move gitea-runner user declaration to actions-runner.nix
Some checks failed
Build and Deploy / mreow (push) Successful in 55s
Build and Deploy / yarn (push) Failing after 58s
Build and Deploy / muffin (push) Has started running
2026-04-22 19:24:18 -04:00
1be21b6c52 split off terminal utilities 2026-04-22 18:45:00 -04:00
c3cc94a305 merge common-*.nix files
Some checks failed
Build and Deploy / mreow (push) Successful in 1h37m19s
Build and Deploy / muffin (push) Has been cancelled
Build and Deploy / yarn (push) Has been cancelled
2026-04-22 18:02:05 -04:00
0c8b8232c2 yarn: disable steamos-mandatory-update
All checks were successful
Build and Deploy / mreow (push) Successful in 52s
Build and Deploy / yarn (push) Successful in 4m33s
Build and Deploy / muffin (push) Successful in 1m10s
2026-04-22 11:46:37 -04:00
aef99e7365 deploy-guard: block activation while users are online
Some checks failed
Build and Deploy / mreow (push) Successful in 51s
Build and Deploy / yarn (push) Successful in 47s
Build and Deploy / muffin (push) Failing after 1m9s
- modules/server-deploy-guard.nix: extendable aggregator registered via
  services.deployGuard.checks.<name>.{description,command}. Installs
  deploy-guard-check with per-check timeout, pass/block reporting, JSON
  output, DEPLOY_GUARD_BYPASS / /run/deploy-guard-bypass (single-shot).
- services/jellyfin/jellyfin-deploy-guard.nix: curl+jq on /Sessions,
  blocks when any session carries NowPlayingItem; soft-fails when unreachable.
- services/minecraft-deploy-guard.nix: mcstatus SLP query on 25565, blocks
  when players.online > 0; soft-fails when unreachable.
- flake.nix: wrap deploy.nodes.muffin activation with activate.custom so
  deploy-guard-check runs before switch-to-configuration. Auto-rollback
  catches the failure. dryActivate/boot branches preserved.
- deploy.sh: SSH preflight for ./deploy.sh muffin with --force /
  DEPLOY_GUARD_FORCE=1 (touches remote bypass marker). Connectivity
  failure is soft; activation still enforces.
- tests/deploy-guard.nix: aggregator contract, bypass mechanics, timeout,
  JSON output.
2026-04-22 00:36:21 -04:00
adbb019977 gitea: move runner and main module to services/gitea 2026-04-20 15:18:37 -04:00
primary
56bcaf0580 nix fmt: wrap long expression in yarn home 2026-04-18 01:05:29 -04:00
primary
1719d54ee0 phase 3: new flake.nix + extract common-{nix,doas,shell-fish}; rewire imports
- New unified flake with two nixpkgs channels (unstable for desktops, 25.11 for muffin)
- modules/common-{doas,shell-fish,nix}.nix extracted from duplicated blocks
- modules/desktop-common.nix: renamed from system/common.nix; secret paths point to secrets/desktop/
- hosts/{mreow,yarn}/default.nix import desktop-common; yarn imports modules/no-rgb.nix
- hosts/muffin/default.nix imports common-* + server-prefixed modules + services/; duplicate doas/fish/nix blocks removed; gc retention preserved as mkForce override
- modules/age-secrets.nix: file paths → ../secrets/server/*.age
- services/{minecraft,matrix/livekit}: secret paths → ../secrets/server/
- home/profiles/*.nix: ./progs/ → ../progs/
- hosts/{mreow,yarn}/home.nix: imports rewired to ../../home/profiles/ and ../../home/progs/
- home/progs/pi.nix and hosts/yarn/home.nix: secret reads → ../../secrets/home/
- tests/*.nix: ../modules/security.nix → ../modules/server-security.nix; ../modules/overlays.nix → ../lib/overlays.nix
- lib/default.nix: takes explicit lib param (defaults to nixpkgs-stable.lib)
2026-04-18 00:58:55 -04:00
primary
99e98e39b7 phase 2: move host files to hosts/{mreow,yarn,muffin}/ 2026-04-18 00:47:25 -04:00