11 Commits

Author SHA1 Message Date
e324876eb7 feat(doctor): #147 — flag machine state the flake never set; linger is the worked example
Some checks failed
Check / eval (push) Has been cancelled
/var/lib survives a migration untouched, and a stray pre-Nomarchy
Linger=yes marker shaped the QA box's session behavior for six months
with nothing in the flake to show for it. Ship the class as guards:

- nomarchy-doctor: new machine-state-drift check after the flake-checkout
  check — loginctl show-user -p Linger; "yes" warns (nothing is broken —
  it is drift) and prints the disable-linger fix; unknown-to-logind skips.
- docs/MIGRATION.md § Post-migration cleanup: "/var/lib machine state
  survives migration" — the worked example and the general suspicion rule.
- checks.doctor: linger sub-case — warn fires under enable-linger, exit
  stays 0, warning clears after disable-linger.

Deliberately NOT hardening the session wiring against the portal-gtk
restart race linger enabled: a clean install cannot reach that state.
The Waybar exec-once loose thread survives as BACKLOG #149.

Verification: V2 — shellcheck clean, nix flake check --no-build green,
nix build .#checks.x86_64-linux.doctor green (both branches exercised).
Implementation by a Sonnet subagent; design and review on Fable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 07:44:43 +01:00
e4800d7d8e feat(nixos): prune system+HM gens after 14d, keep ≥3 past (#128)
Some checks failed
Check / eval (push) Has been cancelled
Weekly nomarchy-gen-prune deletes only generations that are both older
than 14 days and beyond the three most recent past gens (current always
kept), for system and Home Manager profiles. Stock nix.gc no longer uses
--delete-older-than. checks.gen-prune covers selection self-test and
unit wiring; doctor points at the new tool when disk is tight.
2026-07-15 11:59:26 +01:00
d8e1a13d50 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.
2026-07-15 11:26:59 +01:00
Bernardo Magri
fe0b972171 feat(doctor): first-boot pre-activate fail flag (#83)
Some checks failed
Check / eval (push) Has been cancelled
If the installer left /var/log/nomarchy-hm-preactivate.log and no Home
Manager generation exists, doctor reports ✖ with the recovery one-liner
(home-manager switch --flake ~/.nomarchy -b bak). Clears once a
generation is present. checks.doctor covers both arms.

Verified: V2 — checks.doctor green; local smoke.
2026-07-11 10:28:14 +01:00
Bernardo Magri
71786bda6b feat(doctor): battery health readout (#80)
Some checks failed
Check / eval (push) Has been cancelled
Report-only cycle_count + retained capacity (charge_* or energy_*) as
% of design on system batteries; soft warn below 70% of design; skip
when attrs missing. NOMARCHY_POWER_SUPPLY_ROOT for the checks.doctor
fixture (test_power has no cycle/design attrs).

Verified: V2 — nix flake check --no-build; checks.doctor green (fake
BAT0 cycles/% + Device-scope ignore); local BAT0 smoke (energy_*).
2026-07-11 10:06:13 +01:00
Bernardo Magri
e841251399 feat(doctor): #77 hibernate/sleep section (VISION § C)
All checks were successful
Check / eval (push) Successful in 3m41s
nomarchy-doctor gains a read-only hibernate/sleep section (the highest-ROI
Day-2 gap, a natural #76 follow-on): resume device on the kernel cmdline
(+ resume_offset for a swapfile), disk swap >= RAM, zram active, and any
suspend/hibernate error in the previous boot's kernel log. Self-gates
(skip on swap=0) and emits only ok/warn/skip, so it never fails the sheet.
Adds `hibernate` to the checks.doctor probe list so the row is asserted.

Fixes a set -euo pipefail hazard the first VM run caught (exit 1, no
verdict): a no-match grep inside $(...) and a `cond && action` both abort
under set -e — now guarded with || true / || echo 0 / if. Recorded in
MEMORY as a reusable gotcha for writeShellScriptBin scripts.

Verification: V2 PASS — checks.doctor VM test green (fresh build, exit 0;
asserts the hibernate row renders, healthy run stays 0). V1 — ran on real
LUKS+@swap hardware: all three ok rows render (resume set, swap 34G >= RAM,
zram 16G) and the sheet reaches its verdict. V0 bash -n + flake check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:06:45 +01:00
45c584db26 fix(power): Dell charge limit needs Custom type, not Adaptive
All checks were successful
Check / eval (push) Successful in 2m58s
charge_control_end_threshold was written (80) but charge_types stayed
[Adaptive], which ignores the cap while still reporting it — battery
kept charging past 80% on Latitude. Oneshot now selects Custom when a
limit is set, Adaptive/Standard when off; sets start hysteresis; doctor
warns if type ≠ Custom while limited.

V0: flake check --no-build green. V3: re-apply limit, confirm
charge_types shows [Custom] and status stops Charging above cap.
2026-07-10 14:01:19 +01:00
Bernardo Magri
c962d07841 fix(power): #60 name-agnostic system-battery scan
All checks were successful
Check / eval (push) Successful in 2m53s
Replace BAT* globs with type=Battery + !scope=Device (same filter as
nomarchy-battery-notify) in charge-limit oneshot, menu gates, Waybar
power-profile self-gate, doctor, and install chassis detection. CMB0-
style names get charge-cap and laptop modules consistently.

V3 pending: confirm on non-BAT* hardware (HARDWARE-QUEUE). Close #60.

Verified: V1 (option-docs, hardware-db-modules, battery-charge-limit VM).
2026-07-10 08:32:24 +01:00
Bernardo Magri
eba7924b0f feat(doctor): read-only hardware health section (#44)
All checks were successful
Check / eval (push) Successful in 3m4s
Six self-gating hardware checks in nomarchy-doctor, same ok/bad/warn/skip
+ one-fix-command contract: NetworkManager connectivity, default PipeWire
sink, VA-API/OpenGL smoke (only if vainfo/glxinfo present), fprintd unit +
enroll nudge, fwupd daemon + a soft warn when get-updates is non-empty,
and the laptop charge_control_end_threshold when a limit is set. Each
skips cleanly when its tool/service/device is absent, so the section
shrinks to the machine and never hard-fails on a missing feature.

Implemented by a worktree-isolated agent in parallel with the #46 install
VM; diff reviewed and cherry-picked here. Verified V0 (flake check) + V1
(nix build .#…pkgs.nomarchy-doctor — build-time bash -n + shellcheck),
re-run on main after cherry-pick; plus a read-only run on real hardware
(all six checks fired + self-gated). V2 (checks.doctor fakes) pending.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 18:50:37 +01:00
Bernardo Magri
bfb80cb60d feat(state): validation + friendly errors on both write and eval paths (item 11)
All checks were successful
Check / eval (push) Successful in 2m56s
'Never has to master Nix' includes the error messages. The tool grows
validate_state (appearance schema = hard errors; settings.* and
unknown keys = warnings so menu writers and newer schemas keep
working), a read-only `validate` subcommand, and validation BEFORE
every write — an invalid set/apply is refused with the on-disk file
untouched. JSON syntax errors now say line, column, and fix. theme.nix
enforces the same schema at eval time (on the post-defaults state, so
sparse/older files still evaluate) and throws a message naming each
field, its got-value, and the fix paths — the hand-edit escape hatch
no longer ends in a Nix stack trace. Doctor's JSON fix-text points at
validate.

V1: new checks.theme-sync-validate fixture corpus green (good state,
trailing comma, bad hex, bad type, unknown key, refused set with
byte-identical file); negative mkFlake eval of a broken scratch
downstream shows the friendly throw; good-path template-home builds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 20:44:08 +01:00
Bernardo Magri
2a23e82169 feat(doctor): nomarchy-doctor — read-only health sheet + VM check (item 10)
Some checks failed
Check / eval (push) Has been cancelled
The things that actually break user machines, one command (and menu ›
System › Doctor): failed system/user units, disk space (real
filesystems only — fstype allowlist makes it VM/live safe, device
dedupe collapses / and /nix), theme-state.json parses + is
git-tracked, flake dirty/behind as warnings, generation age (profile
symlink mtime — store paths are epoch-1), snapper timeline when
enabled. Read-only by contract; every ✖ prints the one fixing command;
exit 1 on any problem. Ships as pkgs/nomarchy-doctor so the VM check
runs on a minimal node.

Verified: V1 package build (shellcheck-gated) + a real-hardware smoke
that correctly flagged a genuinely failed user unit on the dev box;
V2 green — checks.doctor VM test: induced failed unit flips the sheet
to exit-1 naming the unit and its fix, reset-failed returns healthy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 20:34:11 +01:00