test(state): #133 — pin the #107 legacy-name shim (and its fail-closed gate)
All checks were successful
Check / eval (push) Successful in 4m9s
All checks were successful
Check / eval (push) Successful in 4m9s
mkFlake prefers state.json and still accepts the legacy theme-state.json, because a machine only migrates on its next menu write. Nothing evaluated a checkout carrying ONLY the legacy name, so the shim could rot with every check green — breaking rebuilds for precisely the users who have not opened the menu since #107, i.e. the ones least likely to see it coming. checks.state-legacy-name evaluates two fixtures: legacy-only must resolve, and no-state-at-all must still throw. The gate is half the shim's contract (it turns "no state file" into one readable error instead of a readFile stack from inside the module system) and was equally unpinned. Cheap by construction: mkFlake wraps its return in `builtins.seq _themeState`, so forcing the attrset forces the state read and nothing else — no module system, no home.nix. Hence a one-file fixture and no measurable cost (flake check still ~35s). That file is a SYMLINK to the shipped template's state.json: a copy would drift and the check would quietly start testing a fossil. The fixture also asserts it has no state.json, or it would pass while testing nothing. Both assertions proven by breaking lib.nix — deleting the fallback, then defeating the gate — and watching each fail by name. Delete this check together with the shim and the nomarchy-theme-sync alias. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -153,18 +153,6 @@ whether Nomarchy holds itself higher — darker label, or a darker accent mix
|
|||||||
for light palettes — and note `tools/check-theme-contrast.py` covers palette
|
for light palettes — and note `tools/check-theme-contrast.py` covers palette
|
||||||
pairings only, never GTK widget surfaces. `[human]` for the aesthetic call.
|
pairings only, never GTK widget surfaces. `[human]` for the aesthetic call.
|
||||||
|
|
||||||
### 133. No check pins the #107 legacy-name compat shim
|
|
||||||
|
|
||||||
`lib.mkFlake`, doctor and lifecycle all still accept `theme-state.json`, and
|
|
||||||
`nomarchy-state-sync` migrates it on write — but nothing in `checks.*`
|
|
||||||
evaluates a checkout that has *only* the legacy name, so the shim can rot
|
|
||||||
silently while every check stays green. It is load-bearing until every
|
|
||||||
existing machine has taken one menu write. Add a cheap eval check: a fixture
|
|
||||||
dir with `theme-state.json` only → `mkFlake` resolves it; plus the write-side
|
|
||||||
migration (state.json created + git-staged, legacy `git rm`'d). Proven by
|
|
||||||
hand 2026-07-15 (drvPaths identical across the rename) — this just keeps it
|
|
||||||
proven. Delete together with the shim + the `nomarchy-theme-sync` alias.
|
|
||||||
|
|
||||||
### 143. Rofi keeps the selected *row number* when the search changes, so the highlight lands on an unrelated entry
|
### 143. Rofi keeps the selected *row number* when the search changes, so the highlight lands on an unrelated entry
|
||||||
|
|
||||||
Bernardo 2026-07-16, and his repro is exact: open the app menu, type `ca`, move
|
Bernardo 2026-07-16, and his repro is exact: open the app menu, type `ca`, move
|
||||||
|
|||||||
1
checks/fixtures/legacy-state/theme-state.json
Symbolic link
1
checks/fixtures/legacy-state/theme-state.json
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../../templates/downstream/state.json
|
||||||
5
checks/fixtures/no-state/README.md
Normal file
5
checks/fixtures/no-state/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Deliberately empty: a checkout with **neither** `state.json` nor the legacy
|
||||||
|
`theme-state.json`. `checks.state-legacy-name` asserts `mkFlake` fails closed
|
||||||
|
here — the fail-closed gate in `lib.nix` is what turns "you have no state file"
|
||||||
|
into one readable error instead of a raw `readFile` stack from deep inside the
|
||||||
|
module system.
|
||||||
@@ -555,6 +555,22 @@ Design/decision records and a running log of shipped work (items marked
|
|||||||
`%26`, `%3F`, `%23`, `caf%C3%A9`. **Unverified on purpose:** whether each
|
`%26`, `%3F`, `%23`, `caf%C3%A9`. **Unverified on purpose:** whether each
|
||||||
vendor's page fills the box or auto-submits — testing that means posting into
|
vendor's page fills the box or auto-submits — testing that means posting into
|
||||||
Bernardo's own accounts.
|
Bernardo's own accounts.
|
||||||
|
- ✓ **The #107 compat shim is pinned (#133, 2026-07-16):** `mkFlake` prefers
|
||||||
|
`state.json` and still accepts the legacy `theme-state.json`, because a
|
||||||
|
machine only migrates on its next menu write — but nothing evaluated a
|
||||||
|
checkout carrying **only** the legacy name, so the shim could rot with every
|
||||||
|
check green, breaking rebuilds for exactly the users who have not touched the
|
||||||
|
menu since #107 (i.e. the least likely to notice). `checks.state-legacy-name`
|
||||||
|
now evaluates two fixtures: legacy-only must resolve, and **no state at all
|
||||||
|
must still throw** — the fail-closed gate is half the shim's contract and was
|
||||||
|
equally unpinned. Cheap by construction: `mkFlake` wraps its return in
|
||||||
|
`builtins.seq _themeState`, so forcing the attrset forces the state read and
|
||||||
|
nothing else — no module system, no `home.nix` — which is why the fixture is
|
||||||
|
one file and the check costs no measurable time. That file is a **symlink** to
|
||||||
|
the shipped template's `state.json`: a copy would drift and the check would
|
||||||
|
quietly start testing a fossil. Both assertions were proven by breaking
|
||||||
|
`lib.nix` — deleting the fallback, then defeating the gate — and watching each
|
||||||
|
fail by name. Delete it with the shim and the `nomarchy-theme-sync` alias.
|
||||||
- ✓ **The VM's verdict on menu geometry is worthless — and so is measuring
|
- ✓ **The VM's verdict on menu geometry is worthless — and so is measuring
|
||||||
(#132, 2026-07-16):** the guest draws the picker with icons at ~¼ of
|
(#132, 2026-07-16):** the guest draws the picker with icons at ~¼ of
|
||||||
`ui.iconSize` and rows short enough to clip a 6-row root, so screenshots are
|
`ui.iconSize` and rows short enough to clip a 6-row root, so screenshots are
|
||||||
|
|||||||
45
flake.nix
45
flake.nix
@@ -1511,6 +1511,51 @@
|
|||||||
in
|
in
|
||||||
assert ok; pkgs.runCommand "nomarchy-rofi-text-width" { } "touch $out";
|
assert ok; pkgs.runCommand "nomarchy-rofi-text-width" { } "touch $out";
|
||||||
|
|
||||||
|
# The #107 rename shipped a compat shim: mkFlake prefers state.json
|
||||||
|
# and still accepts the legacy theme-state.json (lib.nix), because a
|
||||||
|
# machine only migrates on its next menu write. Nothing evaluated a
|
||||||
|
# checkout carrying ONLY the legacy name, so the shim could rot with
|
||||||
|
# every check green — and it is load-bearing for exactly the users who
|
||||||
|
# have not touched the menu since #107, i.e. the ones least likely to
|
||||||
|
# notice before their rebuild breaks.
|
||||||
|
#
|
||||||
|
# Cheap by construction: mkFlake wraps its return in
|
||||||
|
# `builtins.seq _themeState`, so forcing the attrset forces the state
|
||||||
|
# read and nothing else — no module system, no home.nix. Which is also
|
||||||
|
# why the fixture needs only that one file.
|
||||||
|
#
|
||||||
|
# Delete this check together with the shim and the
|
||||||
|
# `nomarchy-theme-sync` alias.
|
||||||
|
state-legacy-name =
|
||||||
|
let
|
||||||
|
inherit (nixpkgs) lib;
|
||||||
|
expect = cond: msg: lib.assertMsg cond "state-legacy-name: ${msg}";
|
||||||
|
legacy = ./checks/fixtures/legacy-state;
|
||||||
|
none = ./checks/fixtures/no-state;
|
||||||
|
evalsOk = src:
|
||||||
|
(builtins.tryEval
|
||||||
|
(builtins.isAttrs (self.lib.mkFlake { inherit src; username = "fixture"; })))
|
||||||
|
.success;
|
||||||
|
ok =
|
||||||
|
# Fixture drift: if someone adds a state.json here the check
|
||||||
|
# would still pass, while testing nothing at all.
|
||||||
|
expect (builtins.pathExists (legacy + "/theme-state.json"))
|
||||||
|
"fixture drift: checks/fixtures/legacy-state has no theme-state.json"
|
||||||
|
&& expect (! builtins.pathExists (legacy + "/state.json"))
|
||||||
|
("fixture drift: checks/fixtures/legacy-state also has a state.json, "
|
||||||
|
+ "so it no longer exercises the legacy-only path")
|
||||||
|
&& expect (evalsOk legacy)
|
||||||
|
("mkFlake cannot evaluate a checkout carrying only theme-state.json — "
|
||||||
|
+ "the #107 compat shim is broken and every pre-#107 machine "
|
||||||
|
+ "fails to rebuild")
|
||||||
|
# The other half of the shim's contract: no state at all must
|
||||||
|
# still fail, and fail here rather than deep in a module.
|
||||||
|
&& expect (! evalsOk none)
|
||||||
|
("mkFlake accepted a checkout with no state file at all — the "
|
||||||
|
+ "fail-closed gate in lib.nix is gone");
|
||||||
|
in
|
||||||
|
assert ok; pkgs.runCommand "nomarchy-state-legacy-name" { } "touch $out";
|
||||||
|
|
||||||
# Docking artifact guard: default/no-profile Home Manager output
|
# Docking artifact guard: default/no-profile Home Manager output
|
||||||
# must still launch both hotplug watchers, put Rofi on the focused
|
# must still launch both hotplug watchers, put Rofi on the focused
|
||||||
# monitor, expose the manual keyboard picker, and never ship the
|
# monitor, expose the manual keyboard picker, and never ship the
|
||||||
|
|||||||
Reference in New Issue
Block a user