refactor(#107): theme-state.json → state.json, theme-sync → state-sync
Some checks failed
Check / eval (push) Has been cancelled

The machine flake's git-tracked settings file is system state, not
"theme" only — rename it to state.json. CLI becomes nomarchy-state-sync
with a nomarchy-theme-sync symlink for scripts and muscle memory.

Eval (mkFlake, doctor, lifecycle) still accepts theme-state.json; the
next write migrates to state.json and removes the legacy file.
Documented in MIGRATION.md; drop the CLI alias after release notes.
This commit is contained in:
2026-07-15 11:26:59 +01:00
parent 013403deb4
commit d8e1a13d50
62 changed files with 463 additions and 369 deletions

View File

@@ -226,7 +226,7 @@ always — the same on-AC question `modules/home/idle.nix`'s suspend listener
already answers with `${onAc} ||`.
In-flake state like the rest (`settings.*`), menu-writable, and read via
`theme-state-read.nix` on the NixOS side — NOT `config.nomarchy.settings`,
`state-read.nix` on the NixOS side — NOT `config.nomarchy.settings`,
which does not exist there (ROADMAP § *NixOS-side state bridges (#116)*; copy
the `bluetooth.enable` shape in `modules/nixos/default.nix` and add a case to
`checks.state-bridges`). Pass = the toggle survives a rebuild,
@@ -234,22 +234,6 @@ a suspended machine hibernates after the configured delay and resumes, and a
machine without hibernate support hides the row instead of offering a
suspend that never wakes.
### 107. Rename `theme.json` to reflect that it is the system state
The state file long ago stopped being about themes: it carries night-light,
keyboard memory, display resolution and profiles, auto-commit, services and
more, so `theme.json` now misnames its own contents and misleads anyone
reading the flake. Rename it to `state.json` (Bernardo's call, 2026-07-14 —
settled, do not revisit), and carry the `nomarchy-theme-sync` tool name along
with it.
Standalone task — do not fold it into a feature. Ships with a compatibility
shim that keeps reading an existing `theme.json` so downstream checkouts do
not break on a pull, plus a migration note. Pass = a fresh install and an
existing downstream checkout both work, every in-repo reference (modules,
tools, template, docs) uses the new name, and the shim is documented with the
release it can be dropped in.
### 104. Runtime Airplane mode
Add Airplane mode under System connectivity controls. It must disable Wi-Fi
@@ -280,7 +264,7 @@ read, so *these two toggles have never actually worked for any user*. That
cuts both ways: "preserve existing behavior" is not a reason to keep them
(there is no behavior to preserve), but the state keys and their bridges are
real now and outlive the TUI — dropping the rows must not drop the keys, or a
machine whose theme-state.json already says `bluetooth.enable = false` will
machine whose state.json already says `bluetooth.enable = false` will
silently flip back on at the next rebuild. `checks.state-bridges` covers those
two keys and will fail loudly if the bridges go with the tool; keep it green,
and if a key is deliberately retired, remove its case in the same commit.

View File

@@ -24,7 +24,7 @@ those, it probably shouldn't exist.
## Feature design
- **In-flake state:** any user-settable config gets a menu writer that
lands it in `theme-state.json` (`settings.*`), git-tracked. No
lands it in `state.json` (`settings.*`), git-tracked. No
`~/.local/state`, no side files. Instant-effect where possible
(`--no-switch` + flip the service; the service reads the *live* working
tree at start — the night-light `ExecCondition` pattern). Rebuild-baked

View File

@@ -14,7 +14,7 @@ confidence, default identity, release bar) live in
on-hardware QA.
2. **Reproducible, with zero hidden state.** The downstream flake checkout
*is* the machine. All user-settable config is menu-writable into the
git-tracked state file (`theme-state.json` `settings.*`) — never
git-tracked state file (`state.json` `settings.*`) — never
`~/.local/state`, never `~/.config` side files. Re-cloning your flake
reproduces the machine, settings and all.
3. **Effortless to configure.** The user never has to learn Nix. Every

View File

@@ -237,7 +237,7 @@ the **T14s** (webcam case).
open Ghostty, so the hand `btop.theme` assets were only guest-file
asserted (main_bg / inactive_fg keys) + desktop/bar rendered for
rose-pine, everforest, summer-night, vantablack, catppuccin. On a
real session: `nomarchy-theme-sync apply <slug>` then `btop` and
real session: `nomarchy-state-sync apply <slug>` then `btop` and
confirm backgrounds/text match the theme (esp. rose-pine Dawn light
bg `#faf4ed`, vantablack near-black `#0d0d0d`, catppuccin Mocha
`#1E1E2E`). One pass cycling those five is enough.

View File

@@ -19,6 +19,17 @@ Template:
---
## 2026-07-15 — #107 state.json + nomarchy-state-sync
- **Task:** BACKLOG #107 — rename misnamed system state file and CLI.
- **Did:** `theme-state.json``state.json` (template, root, docs, modules);
package/CLI `nomarchy-theme-sync``nomarchy-state-sync` with symlink
alias; `modules/state-read.nix`; mkFlake/doctor/lifecycle read legacy
name; writes always land on `state.json` and remove the old file.
- **Verified:** py_compile; legacy-file unit migrate (write removes
theme-state.json); V0 flake check pending in same push.
- **Pending:** drop `nomarchy-theme-sync` alias after release notes.
- **Next suggestion:** #104 airplane, or #98 with a screenshot.
## 2026-07-15 — Close #94 installed chromium + kill Hyprland update-news
- **Task:** Residual #94 (chromium on installed path) + first-boot polish
seen while probing.
@@ -373,7 +384,7 @@ Template:
(`modules/home/options.nix:412`), so `or <fallback>` had been swallowing a
missing-attribute error on the NixOS side forever. Options now declare a
*static* default and the implementing module reads the state via
`theme-state-read.nix` + `lib.mkIf (state != null) (lib.mkDefault state)`
`state-read.nix` + `lib.mkIf (state != null) (lib.mkDefault state)`
done for `bluetooth.enable` (default.nix) and `services.printing.enable`
(services.nix). `batteryChargeLimit`'s read is simply deleted: power.nix's
oneshot reads the key with `jq` at *runtime*, which is why that menu worked.
@@ -421,7 +432,7 @@ Template:
Making both state-owned surfaced two real bugs: `greeter.autoLogin`
defaulted from `config.nomarchy.settings…`, an attribute that exists ONLY
on the HM side, and `or null` swallowed it — the state path never worked on
any machine ever built; and `theme-sync get` printed Python's `None` for a
any machine ever built; and `state-sync get` printed Python's `None` for a
JSON null, so any `case … null)` would miss.
- **Verified:** **V1** — flake check, installer-safety, option-docs pass.
Proved by eval/build: a state carrying autoLogin yields greetd
@@ -580,14 +591,14 @@ Template:
- **Next suggestion:** wait on round 7 before touching the dock path again.
## 2026-07-13 — #99 live-seed git-init; theme-switch failure filed as #113 (this commit)
- **Task:** BACKLOG #99 — false "theme-state.json NOT git-tracked" doctor/
- **Task:** BACKLOG #99 — false "state.json NOT git-tracked" doctor/
Waybar warning in the live session; resolve the held question from Fable.
- **Did:** hosts/live.nix `nomarchy-seed-flake` now `git init`+`add`+`commit`s
the seeded `~/.nomarchy` (like nomarchy-install.sh:654), so the live
checkout is a committed repo. Also committed #94's live-posture comment in
flake.nix (separate commit).
- **Verified:** V2 — focused serial-log VM run (`/tmp/nomarchy-v2-theme-99/`):
doctor prints `theme-state.json is git-tracked` + `✔ flake checkout is
doctor prints `✔ state.json is git-tracked` + `✔ flake checkout is
clean`, `GIT_REPO_OK`/`TRACKED_OK` markers. Held question RESOLVED: the
same run's offline gruvbox switch failed with a 1176-drv source rebuild,
but a local drv-equivalence test proved the failing
@@ -885,14 +896,14 @@ Template:
## 2026-07-12 — auto-commit sweep before pull/rebuild/home (interactive)
- **Task:** Bernardo's request (no BACKLOG item): with autoCommit on,
hand edits to `~/.nomarchy` (his had 4) stayed forever-dirty —
theme-sync's commit is pathspec-limited to theme-state.json by design.
state-sync's commit is pathspec-limited to state.json by design.
- **Did:** New internal `nomarchy-autocommit` in nomarchy-lifecycle:
live-reads `settings.autoCommit`, commits *everything* dirty with
message `nomarchy: auto-commit before <label>` + file list in the
body; called (`|| true`, never blocks) at the top of nomarchy-pull /
-rebuild / -home. Exposed as `passthru.autocommit`; package exported.
Docs/comments swept: README, RECOVERY, ROADMAP ✓ entry, rofi toggle
text, control-center prompt, theme-sync docstring.
text, control-center prompt, state-sync docstring.
- **Verified:** V1+ — `nix flake check --no-build` green; new permanent
`checks.lifecycle-autocommit` builds (real binary, sandbox repos:
sweep/clean/off/non-repo); end-to-end on a *copy* of the real
@@ -1301,7 +1312,7 @@ Template:
- **Task:** Bernardo challenged the "V3 real-session" framing — a simulated
sunset IS VM-testable. He's right; I'd conflated "needs a real desktop"
with "needs the generic home-manager switch."
- **Did:** Added `checks.auto-theme` runNixOSTest: installs nomarchy-theme-sync,
- **Did:** Added `checks.auto-theme` runNixOSTest: installs nomarchy-state-sync,
points `NOMARCHY_DEFAULT_THEMES` at presets, stubs the switch via
`NOMARCHY_REBUILD` (a marker), configures the pair+schedule, then **walks
the VM clock** 19:55→20:05→20:06→next-day 07:30 asserting slug goes
@@ -1320,7 +1331,7 @@ Template:
- **Task:** BACKLOG #79 slice 3 — the menu; completes the feature.
- **Did:** `rofi.nix` — "Auto theme (on/off)" row in Look & Feel + an
`autotheme)` submenu: toggle, pick day/night (from
`nomarchy-theme-sync list`), set sunrise/sunset (HH:MM input, validated).
`nomarchy-state-sync list`), set sunrise/sunset (HH:MM input, validated).
Enable writes the flag + defaults the summer pair `--no-switch`, then
`exec auto --force` — one rebuild installs the timer AND applies the right
theme. Disable is instant `--no-switch` (`auto` self-gates; the lingering
@@ -1342,14 +1353,14 @@ Template:
- **Did:** `modules/home/autotheme.nix` (imported in home default.nix):
`systemd.user.{service,timer}.nomarchy-auto-theme`, install gated on
`config.nomarchy.settings.autoTheme.enable or false` (state-driven, like
updates.nix gates on its enable). Service runs `nomarchy-theme-sync auto`
updates.nix gates on its enable). Service runs `nomarchy-state-sync auto`
with a PATH for `home-manager`; timer `OnStartupSec=1min` +
`OnCalendar=*:0/15` + `Persistent`. Chose periodic over exact
sunrise/sunset timers — robust to suspend/DST, and `auto` is idempotent so
ticks are cheap (rebuild only at the transition).
- **Verified:** **V1** — real-config eval (state temp-enabled, restored):
`settings.autoTheme.enable`→true, timer `OnCalendar`=`*:0/15`, service
ExecStart=`… nomarchy-theme-sync auto`; disabled→no units (isolation eval
ExecStart=`… nomarchy-state-sync auto`; disabled→no units (isolation eval
condition=false). `systemd-analyze calendar '*:0/15'` valid. **V0** flake
check green. (Gotcha: a new .nix file is invisible to the flake until
`git add` — flake eval only sees tracked files.)
@@ -1360,7 +1371,7 @@ Template:
## 2026-07-10 — #79 slice 1: auto time-of-day theme CLI primitive
- **Task:** Split BACKLOG #79 (`VISION § D`, `[big]`) into 3 slices (CLI /
timer / menu); took slice 1.
- **Did:** `nomarchy-theme-sync auto` — reads
- **Did:** `nomarchy-state-sync auto` — reads
`settings.autoTheme.{enable,day,night,sunrise,sunset}`, computes day/night
by the local clock, and applies the matching preset **only if different**
(idempotent → the slice-2 timer won't rebuild needlessly). `--which`
@@ -1371,7 +1382,7 @@ Template:
against scratch state: wide-day→day slug, 00:0000:01 window→night,
disabled→no-op, missing day/night→die, `auto --no-switch` writes state,
re-run→"already on" no-op, plain `apply` still writes (refactor intact).
**V0** py_compile + flake check + `checks.theme-sync-validate` green.
**V0** py_compile + flake check + `checks.state-sync-validate` green.
- **Pending:** slices 2 (systemd sunrise/sunset timers + login apply, V2)
and 3 (Look & Feel menu) remain under #79.
- **Next suggestion:** #79 slice 2 — the timer/hook (V2 runNixOSTest).

View File

@@ -100,10 +100,10 @@ iteration would otherwise rediscover.
- **NixOS release bump is a trap:** the discarded attempt
(branch deleted 2026-06-22) hit a Hyprland OOM blocker; a redo is a
deliberate `v2`, never part of routine lock bumps.
- `theme-state.json` is git-tracked inside an 86 MB flake tree, so every
- `state.json` is git-tracked inside an 86 MB flake tree, so every
state write re-copies the source before eval — the wallpapers-artifact
split (BACKLOG LATER) is the decided fix (§ Faster switches).
- **Friendly theme-state load** (`modules/theme-state-read.nix`, #66):
- **Friendly theme-state load** (`modules/state-read.nix`, #66):
`builtins.tryEval` does **not** catch `readFile`/`fromJSON` failures —
gate with `pathExists` + empty/non-object checks before `fromJSON`.
Subtle JSON syntax errors still surface from nlohmann (line/col);