diff --git a/README.md b/README.md index e30a039..d8c233f 100644 --- a/README.md +++ b/README.md @@ -218,31 +218,35 @@ two tables below are split along exactly that line. | `nomarchy.displays.enable` | `true` | nwg-displays interactive monitor arranger (helper for `nomarchy.monitors`) | | `nomarchy.monitors` | `[]` | Declarative per-output layout → Hyprland `monitor` rules (applied on hotplug); `,preferred,auto,1` wildcard kept as fallback | | `nomarchy.themesDir` | Nomarchy's `themes/` | Where per-theme app overrides are probed | +| `nomarchy.package` | overlay's `nomarchy-theme-sync` | The theme/state tool package, overridable if you fork it | **`system.nix`** (NixOS — the machine): | Option | Default | Purpose | |---|---|---| | `nomarchy.system.plymouth.enable` | `true` | Branded boot splash, background from the theme JSON (recolors on system rebuilds) | +| `nomarchy.system.stateFile` | `null` | theme-state.json for the system-side consumers (the Plymouth tint); `lib.mkFlake` wires it for you — set it only when composing the modules by hand | | `nomarchy.system.fileManager.enable` | `true` | Thunar GUI + gvfs/tumbler/udisks2 (the "open folder" handler) | | `nomarchy.system.greeter.enable` | `true` | greetd/tuigreet | | `nomarchy.system.greeter.autoLogin` | `null` | Auto-login this user into Hyprland (installer sets it on LUKS machines) | | `nomarchy.system.audio.enable` | `true` | Pipewire stack | | `nomarchy.system.bluetooth.enable` | `true` | Bluetooth + blueman | +| `nomarchy.system.autoTimezone.enable` | `false` | Automatic timezone (geoclue + automatic-timezoned) — the clock follows your location; toggle from System › Auto timezone (a menu enable rebuilds: it has to unset the static `time.timeZone`) | | `nomarchy.system.snapper.enable` | `false` | Hourly/daily BTRFS timeline snapshots + `nixos-rebuild-snap` (installer enables it; no-op unless root is BTRFS) | | `nomarchy.system.power.enable` | `true` | Active power management (see below) | | `nomarchy.system.power.backend` | `"ppd"` | `"ppd"` (power-profiles-daemon + menu/Waybar switcher) or `"tlp"` (deeper battery tuning, no switcher) — mutually exclusive | | `nomarchy.system.power.laptop` | `false` | Marks a laptop, gating battery-only features; the installer sets it when a battery is present | | `nomarchy.system.power.thermal.enable` | `false` | thermald (Intel-only); the installer enables it on a GenuineIntel CPU | | `nomarchy.system.power.batteryChargeLimit` | `null` | Stop charging at this % (e.g. `80`) where the hardware supports it; needs `power.laptop` | -| `nomarchy.hardware.intel.enable` | `false` | Intel enablement above nixos-hardware (GuC/HuC via `i915.enable_guc=3`); the installer sets it on an Intel CPU/GPU | +| `nomarchy.hardware.intel.enable` | `false` | Intel enablement above nixos-hardware (GuC/HuC firmware via `i915.enable_guc=3` — `.guc` toggles just that; the installer unsets it on `xe`-driver GPUs); the installer sets it on an Intel CPU/GPU | | `nomarchy.hardware.intel.computeRuntime` | `false` | Opt-in: Intel GPU compute — OpenCL/Level-Zero (`intel-compute-runtime`) + oneVPL (`vpl-gpu-rt`) | -| `nomarchy.hardware.amd.enable` | `false` | AMD enablement above nixos-hardware (amd-pstate EPP + radeonsi VA-API); installer-set on an AMD CPU/GPU | +| `nomarchy.hardware.amd.enable` | `false` | AMD enablement above nixos-hardware (amd-pstate EPP + radeonsi VA-API, each toggleable via `.pstate` / `.vaapi`); installer-set on an AMD CPU/GPU | | `nomarchy.hardware.amd.rocm.enable` | `false` | Opt-in: ROCm HIP/OpenCL GPU compute (multi-GB); pair with `.gfxOverride` (e.g. `"11.0.0"`) for an unlisted iGPU | | `nomarchy.hardware.fingerprint.enable` | `false` | fprintd for a detected fingerprint reader (installer-set); enroll with `fprintd-enroll` | | `nomarchy.hardware.fingerprint.pam` | `false` | Opt-in: use the fingerprint for login + sudo (PAM) | | `nomarchy.hardware.npu.enable` | `false` | Opt-in/experimental: load the on-die NPU driver (`amdxdna`/`intel_vpu`); userspace runtime is BYO | | `nomarchy.hardware.latestKernel` | `false` | Opt-in: ship `linuxPackages_latest` instead of the default kernel — for very new hardware whose drivers landed recently | +| `nomarchy.hardware.camera.hideIrSensor` | `false` | Hide a dual-sensor webcam's IR node from PipeWire so apps only ever see the colour camera (the "second, dark Integrated Camera"); installer-set on a paired RGB+IR webcam. `/dev/video*` stays open, so Howdy-style face unlock still works; `.irMatch` overrides the IR-name regex | | `nomarchy.services.tailscale.enable` | `false` | Opt-in: Tailscale mesh VPN (then `sudo tailscale up`) | | `nomarchy.services.syncthing.enable` | `false` | Opt-in: Syncthing file sync as the login user (GUI at `127.0.0.1:8384`) | | `nomarchy.services.podman.enable` | `false` | Opt-in: rootless Podman (`docker` aliased to it) | @@ -259,7 +263,7 @@ two tables below are split along exactly that line. | `nomarchy.services.ollama.enable` | `false` | Opt-in: Ollama local LLM runtime on `127.0.0.1:11434` (CPU; GPU via `services.ollama.acceleration`) | | `nomarchy.services.printing.enable` | `false` | Opt-in: CUPS + Avahi/mDNS network printer discovery | | `nomarchy.services.openrgb.enable` | `false` | Opt-in: OpenRGB daemon for RGB peripheral/motherboard lighting | -| `nomarchy.services.restic.enable` | `false` | Opt-in: scheduled daily restic backup (set `.repository` + `.passwordFile`; 7/4/6 retention; list/restore via the `restic-nomarchy` wrapper) | +| `nomarchy.services.restic.enable` | `false` | Opt-in: scheduled daily restic backup (set `.repository` + `.passwordFile`; backs up `.paths`, default `/home`; 7/4/6 retention; list/restore via the `restic-nomarchy` wrapper) | Beyond the `nomarchy.*` surface, the system layer turns on the usual desktop services with `lib.mkDefault` (override natively). Two worth diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index b35323a..4513ae3 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -22,19 +22,21 @@ next, in what order*. ## NOW -*Items 21–27: real-hardware QA findings from the Latitude 5410 -(Bernardo, 2026-07-04) — bugs found on metal outrank the queue.* - -### 6. Full docs review & restructure -ROADMAP § Full docs review. The roadmap/backlog split is done (this -file); remaining: reconcile every README option table against the live -`nomarchy.*` surface; drift pass over docs/OVERRIDES.md, docs/TESTING.md, -templates/downstream/README.md; read the install/first-run story end to -end; add a short **recovery runbook** (desktop won't start → boot an -older generation / `nomarchy-snapshots` / greetd journal — the pieces -exist, the story isn't written). Site-vs-markdown is a Decision (below). -**Verify:** V0 + a mechanical option-surface diff (eval the options, -compare to the tables — consider making that a permanent check). +### 6. Full docs review & restructure — sliced, one slice per iteration +ROADMAP § Full docs review. Done: the roadmap/backlog split (this file); +slice (a) option-surface reconcile — README tables fixed (9 gaps) and +the diff made permanent as the `option-docs` flake check (eval-walked +surface vs tables, catches stale rows too). Remaining slices: +- **(b) drift pass** over docs/OVERRIDES.md, docs/TESTING.md, + templates/downstream/README.md — read each against the current tree, + fix what lies. +- **(c) install/first-run story** read end to end (README install §§ + + template README as one narrative; fix the seams). +- **(d) recovery runbook** — short doc: desktop won't start → boot an + older generation / `nomarchy-snapshots` / greetd journal. The pieces + exist, the story isn't written. +Site-vs-markdown is a Decision (below). **Verify:** V0 per slice; (b)/(c) +against the live tree, not memory. ## NEXT diff --git a/agent/JOURNAL.md b/agent/JOURNAL.md index 07ab647..92f25cc 100644 --- a/agent/JOURNAL.md +++ b/agent/JOURNAL.md @@ -17,6 +17,23 @@ Template: --- +## 2026-07-04 — docs slice (a): option-surface reconcile (iteration #13, item 6a) +- **Task:** BACKLOG NOW#6, first slice — README tables vs live options. +- **Did:** split item 6 into slices (a–d) in BACKLOG. Reconciled: 9 + undocumented options (autoTimezone.enable!, camera.hideIrSensor + + irMatch!, intel.guc, amd.pstate/vaapi, package, system.stateFile, + restic.paths) — rows/inline mentions added, no stale rows found. + Made it permanent: `checks.option-docs` — flake.nix eval-walks option + names from the 4 option files (config halves stay lazy; dummy args) + → tools/check-option-docs.py enforces row-or-`.leaf`-mention + flags + stale rows. +- **Verified:** V0; V1 — check builds green (78 options); negative test: + same script vs the pre-fix README reports exactly the 9 gaps. +- **Pending:** slices (b) doc drift pass, (c) install story, (d) + recovery runbook. +- **Next suggestion:** item 6 slice (b) — or NEXT#8 (viewers+mime) for + variety; both fine. + ## 2026-07-04 — Back audit (iteration #12, item 24) - **Task:** BACKLOG NOW#24 — every list menu ends in ↩ Back. - **Did:** audited every `rofi -dmenu` call site in the generated diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index a1662ec..034aa6f 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -849,6 +849,16 @@ how to override it. Items marked ✓ are shipped. your theme / essentials" flow (ties into the branding work). ## Known issues & follow-ups +- ✓ **README option tables drift from the live surface** (docs review + slice (a), 2026-07-04): a fresh reconcile found 9 undocumented options + (autoTimezone, camera.hideIrSensor/irMatch, intel.guc, amd.pstate/ + vaapi, package, system.stateFile, restic.paths) — rows/mentions added, + and the diff is now permanent: `checks.option-docs` walks the option + names out of the four option-declaring modules at eval time (their + lazy `config` halves never evaluate, so dummy args suffice) and + requires each a table row — or a backticked `.leaf` mention for + non-enable sub-knobs — plus flags table rows whose option no longer + exists (tools/check-option-docs.py). - ✓ **swaync text invisible on summer-day** (Latitude QA, 2026-07-04): the themed CSS paired @subtext on @base, but palette roles are not uniform across themes — summer-day/flexoki-light use subtext as diff --git a/flake.nix b/flake.nix index 7b8f396..20b074d 100644 --- a/flake.nix +++ b/flake.nix @@ -147,6 +147,42 @@ touch $out ''; + # The README option tables must track the live `nomarchy.*` + # surface. The surface is walked at eval time from the four + # option-declaring modules (their lazy `config` halves stay + # unevaluated), so the live side of the diff can't go stale; + # the script wants a table row per option (inline `.leaf` + # mentions ok for non-enable sub-knobs) and flags stale rows. + option-docs = + let + lib = nixpkgs.lib; + names = prefix: opts: lib.concatLists (lib.mapAttrsToList + (n: v: + if lib.isOption v + then lib.optional (!(v.readOnly or false)) "${prefix}${n}" + else names "${prefix}${n}." v) + opts); + surface = lib.concatLists [ + (names "nomarchy." + ((import ./modules/home/options.nix { inherit lib pkgs; }).options.nomarchy)) + (names "nomarchy.system." + ((import ./modules/nixos/options.nix { inherit lib; }).options.nomarchy.system)) + (names "nomarchy.hardware." + ((import ./modules/nixos/hardware.nix { inherit lib pkgs; config = { }; }).options.nomarchy.hardware)) + (names "nomarchy.services." + ((import ./modules/nixos/services.nix { inherit lib pkgs; config = { }; }).options.nomarchy.services)) + ]; + in + pkgs.runCommand "nomarchy-option-docs" + { nativeBuildInputs = [ pkgs.python3 ]; } + '' + python3 ${./tools/check-option-docs.py} \ + ${pkgs.writeText "option-surface.txt" + (lib.concatStringsSep "\n" surface + "\n")} \ + ${./README.md} + touch $out + ''; + # Config-level VM assertions for the nomarchy.hardware.* toggles — # what they SET (kernel cmdline, fprintd, PAM). Real hardware # behaviour (firmware/driver/device) needs bare metal and is out of diff --git a/tools/check-option-docs.py b/tools/check-option-docs.py new file mode 100644 index 0000000..7263b5e --- /dev/null +++ b/tools/check-option-docs.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +"""Option-surface ↔ README drift check (flake check `option-docs`). + +Usage: check-option-docs.py + + is one full option path per line (nomarchy.…), +generated at eval time in flake.nix by walking the four option-declaring +modules — so the "live surface" side can never go stale by itself. + +Two directions: + +1. Every live option must be documented in the README: either its full + path appears verbatim (a table row), or — for sub-knobs that don't end + in `.enable` — a backticked `.leaf` shorthand appears somewhere (the + convention for tuning knobs documented inline in their parent row, + e.g. nightlight's `.temperature`). `.enable` options always get their + own row: the shorthand `` `.enable` `` would match any of them. + +2. Every `nomarchy.*` path in a README option-table row (lines starting + `| `nomarchy.`) must still exist — catches rows for renamed/removed + options. +""" + +import re +import sys + +surface_file, readme_file = sys.argv[1], sys.argv[2] + +surface = [l.strip() for l in open(surface_file) if l.strip()] +readme = open(readme_file).read() + +# Backticked `.leaf` shorthands present in the README (inline sub-knob docs). +shorthands = set(re.findall(r"`(\.[A-Za-z][A-Za-z0-9]*)`", readme)) + +failures = [] + +for opt in surface: + if opt in readme: + continue + leaf = "." + opt.rsplit(".", 1)[1] + if leaf != ".enable" and leaf in shorthands: + continue + failures.append( + f"undocumented option: {opt} — add a README table row" + + ("" if leaf == ".enable" else f" or an inline `{leaf}` mention") + ) + +# Reverse: option paths claimed by table rows must exist. +for line in readme.splitlines(): + m = re.match(r"\|\s*`(nomarchy\.[A-Za-z0-9.]+)`", line) + if m and m.group(1) not in surface: + failures.append(f"stale README table row: {m.group(1)} is not a live option") + +if failures: + print(f"option-docs: {len(failures)} problem(s)") + for f in failures: + print(" " + f) + sys.exit(1) + +print(f"option-docs: {len(surface)} options all documented, no stale rows")