fix(nixos): smartd self-gates on the hardware — the doctor was right, smartd wasn't
Some checks failed
Check / eval (push) Has been cancelled

BACKLOG #118. Bernardo booted the live ISO and the Waybar health icon was red,
reporting smartd. Everything downstream turned out to be working correctly,
which is the part worth recording: smartd's config is DEVICESCAN, and where no
drive answers SMART it exits 17 ("Unable to monitor any SMART enabled
devices"), systemd marks the unit failed, nomarchy-doctor faithfully reports a
failed system unit, and Waybar paints @bad. The doctor was telling the truth.
smartd was the bug.

Scope was never live-only, which is why this sat in NOW rather than as a live
nit: services.smartd.enable mkDefaults true on every machine and QEMU virtio
exposes no SMART, so every VM install has been booting to a health warning
about a daemon with nothing to do — and every V2 run had been showing it as
noise.

Fixed with the distro's own self-gate convention: an ExecCondition running
`smartctl --scan`, which prints nothing exactly when smartd would find nothing.
A failed condition leaves the unit inactive rather than failed. Deliberately
NOT SuccessExitStatus = 17: that would also swallow exit 17 from a machine that
does have drives, which is the entire reason the daemon ships.

V2. checks.smartd-gate boots the REAL distro module rather than a restatement
of it (its nixpkgs.config needs mkForce to yield to the test's pkgs) and
asserts both halves, because they pull in opposite directions: a gate that
never skips leaves the red icon, and a gate that always skips silently disables
drive-health monitoring on real hardware — the failure nobody notices until a
disk dies quietly. So the no-SMART node must go ActiveState=inactive, unfailed,
and absent from `systemctl --failed` (what the doctor actually reads); and the
gate's logic is driven against a scan that DOES find a device, since QEMU
cannot answer SMART honestly and pretending otherwise would test nothing. The
check was proved to fail by unwiring the condition. flake check, doctor,
hardware-toggles, live-baseline-apps, option-docs and state-bridges pass.

V3 pending: that smartd still RUNS where drives have SMART (dev box, real
NVMe). Queued with an explicit fail-condition — if it skips there, revert the
gate rather than tune it.

Also swept: #120's size table said the duplicate chromium was gone; #121 was
reverted, so it is back and the table says so.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 17:38:58 +01:00
parent 0727ba6d44
commit 19ba4e2b12
6 changed files with 162 additions and 51 deletions

View File

@@ -30,48 +30,6 @@ These are separate queue items from one real install/session pass. Preserve
that separation when fixing them: the installer blocker, unclear installer
copy, and post-install desktop failures have different verification paths.
### 118. smartd fails where no drive has SMART, so the health icon greets you red
Bernardo, live ISO 2026-07-14: the Waybar doctor module shows a smartd error.
**Root cause, reproduced headlessly 2026-07-14** (scratch `runNixOSTest`, a
node whose only config is `services.smartd.enable = true` — the same block
`modules/nixos/default.nix:166` mkDefaults ON for every machine):
smartd[567]: In the system's table of devices NO devices found to scan
smartd[567]: Unable to monitor any SMART enabled devices. Exiting.
smartd.service: Main process exited, code=exited, status=17/n/a
Status: "No devices to monitor"
`smartctl --scan` prints **nothing** on such a machine — which is both the
cause and the ready-made gate. The rest of the chain is each part working
correctly: `systemctl --failed` lists `smartd.service`, so nomarchy-doctor's
generic failed-unit check (`nomarchy-doctor.sh:24-28`) reports "failed system
unit(s): smartd.service", and Waybar's `#custom-doctor` goes `@bad`. **Fix
smartd, not the doctor** — the doctor is telling the truth about a unit that
genuinely failed.
**Scope is wider than the live ISO** (which is why it's here and not filed as
a live-only nit): `services.smartd.enable` mkDefaults true on `nomarchy` as
well as `nomarchy-live`, and QEMU virtio disks expose no SMART — so a plain
VM install boots to a red health icon out of the box, as does a live USB whose
stick has no SMART. Every V2 QEMU run has been showing this.
Fix direction: **self-gate on the hardware**, the convention the rest of the
distro follows (`ExecCondition`, like the night-light; "each half self-gates
on its hardware"). A condition that runs `smartctl --scan` and skips the unit
when it finds nothing leaves the unit *inactive* rather than *failed*, so real
SMART failures on real drives still surface. Do **not** paper over it with
`SuccessExitStatus = 17` — that also swallows the case where smartd dies on a
machine that does have drives, which is the whole reason the daemon is here.
Pass = on a machine with no SMART-capable device the unit is inactive (not
failed), `systemctl --failed` is empty and the doctor is green; on a machine
with one, smartd runs as it does today; a permanent `checks.*` covers both
halves (the scratch repro above is most of it — the no-SMART node exists, the
with-SMART node needs a QEMU disk that answers SMART, or the gate script
tested directly against a stubbed `smartctl`).
### 94. Live ISO/install: no default browser observed
**Progress 2026-07-13:** installed path VERIFIED at V1 — the exact HM
@@ -177,10 +135,11 @@ distro: "works on a plane" and "8 GiB is absurd to download" are both true, and
a second target settles them without compromising either.
**Measured facts (2026-07-14), so this starts from numbers, not vibes.**
*(Taken before #121 landed; it removed a duplicate 687 MiB chromium, so the
uncompressed figures below are each ~0.67 GiB lower now — the live desktop is
**13.34 GiB**, not 14.01. The shape of the argument is unchanged. Re-measure
before acting rather than trusting these.)*
*(These stand as measured: #121 would have cut ~0.67 GiB of duplicate chromium
from them, but it was **reverted** — decided against, ROADMAP § one chromium,
not two. If a netinstall ships, revisit it: the duplicate is worth ~195 MiB of
**download**, which is this item's whole currency, even though it is worth
almost nothing on disk or on the ISO.)*
> **Read this before using the numbers below.** They are **closure arithmetic**,
> and #121 proved the hard way that closure size is neither disk size nor image
@@ -200,7 +159,7 @@ before acting rather than trusting these.)*
**~13.3 GiB** desktop → roughly **6 GiB** compressed at the same ratio.
**So "no pin" alone is NOT the lighter ISO** — this is the trap to avoid.
- The desktop's own top weights: libreoffice 1457 MiB, initrd 1369,
linux-firmware 770, chromium 704 (was 1391 before #121), llvm-lib 540,
linux-firmware 770, chromium 1391 (two builds — #121, left in), llvm-lib 540,
bibata-cursors 322, mesa 264, mbrola-voices 259, nerd-fonts ~420 combined.
Note what that list implies: no single lever gets a desktop ISO under ~4 GB —
which is the case for (b) below.

View File

@@ -429,6 +429,18 @@ the **T14s** (webcam case).
double-clicking a text file is #119's problem, so don't file it twice.
## AMD dev box only
- [ ] **#118 smartd still runs where drives DO have SMART** (this commit) — the
half a VM cannot answer: QEMU exposes no SMART, so `checks.smartd-gate`
proves the skip but has to drive the *with-device* path through a stub.
On the dev box (real NVMe), after `nomarchy-rebuild` + reboot:
`systemctl status smartd` is **active/running**, and
`systemctl show -p ExecCondition --value smartd` names
`smartd-any-smart-device`. **Pass** = smartd is running, exactly as
before this commit — i.e. the gate skips nothing on real hardware.
**Fail** = inactive/skipped, which would mean the gate is silently
disabling drive-health monitoring: revert it, don't tune it.
Cheap bonus while you are there: `nomarchy-doctor` reports no failed
units (the red-icon symptom that started #118).
- [ ] **AMD runtime bits** — VA-API (`vainfo` → radeonsi), amd-pstate EPP
active and PPD switching governors; opt-ins: ROCm (`rocminfo`, a GPU
PyTorch/Ollama smoke) and the XDNA NPU driver loading.

View File

@@ -19,6 +19,37 @@ Template:
---
## 2026-07-14 — #118: smartd self-gates; the doctor was right all along (this commit)
- **Task:** BACKLOG #118 — Bernardo's live ISO showed a red Waybar health icon
reporting smartd.
- **Did:** smartd's DEVICESCAN finds nothing where no drive answers SMART and
exits **17**, so systemd marks it failed, the doctor honestly reports a
failed unit, and Waybar paints `@bad`. Everything downstream was correct —
**smartd was the bug, not the doctor**. Added an `ExecCondition` running
`smartctl --scan` (empty exactly when smartd would find nothing), so the
unit goes **inactive** rather than failed. NOT `SuccessExitStatus = 17`,
which would also swallow exit 17 on a machine that has drives — the reason
the daemon exists.
- **Scope was never live-only:** smartd mkDefaults true everywhere and QEMU
virtio has no SMART, so every VM install has been booting to a health
warning, and every V2 run had been showing it as noise.
- **Verified:** **V2**`checks.smartd-gate` boots the **real** distro module
(not a restatement of it; `nixpkgs.config` needed `mkForce` to yield to the
test's pkgs) and asserts both halves, since they pull opposite ways: a gate
that never skips leaves the red icon, one that always skips silently kills
drive-health monitoring — the failure nobody notices until a disk dies
quietly. No-SMART node → `ActiveState=inactive`, not failed, absent from
`systemctl --failed` (what the doctor actually reads); and the gate's logic
driven against a scan that *finds* a device → exit 0, because QEMU cannot
answer SMART honestly and pretending otherwise would test nothing. **Proved
to fail** by unwiring the condition. flake check + doctor + hardware-toggles
+ live-baseline-apps + option-docs + state-bridges green.
- **Pending:** **V3** — that smartd still RUNS on real drives (dev box, real
NVMe). Queued with an explicit fail-condition: if it skips there, revert the
gate rather than tune it.
- **Next suggestion:** #119 (`text/plain` names vscode — the last of #94's bug
class), or #95 (Ghostty does not open) at the top of NOW.
## 2026-07-14 — #121 reverted: the fix worked, the gain didn't survive measuring (this commit)
- **Task:** Bernardo's call on #121 (shipped 0b464af, reverted here): *"Let's
leave it honestly. Sounds too much work for a negligible gain."*

View File

@@ -404,6 +404,30 @@ Design/decision records and a running log of shipped work (items marked
decision rather than a drive-by. Proved to fail: dropping snapshot makes it
name the missing entry. **V3 pending** — that the apps *launch* needs real
hardware (HARDWARE-QUEUE, Acer M5-481T).
- ✓ **smartd self-gates on the hardware (#118):** Bernardo booted the live ISO
and the Waybar health icon was red. Everything downstream was working
correctly, which is what made it worth writing down: smartd's config is
DEVICESCAN, and where no drive answers SMART it exits **17** ("Unable to
monitor any SMART enabled devices"), systemd marks the unit **failed**,
nomarchy-doctor honestly reports a failed system unit, and Waybar paints
`@bad`. **The doctor was right; smartd was the bug.** Scope was never
live-only — `services.smartd.enable` mkDefaults true on every machine and
QEMU virtio exposes no SMART, so *every VM install booted to a health
warning* and every V2 run had been showing it as noise.
Fixed by the distro's own self-gate convention: an `ExecCondition` running
`smartctl --scan` (which prints nothing exactly when smartd would find
nothing) leaves the unit **inactive** instead of failed. **Deliberately not
`SuccessExitStatus = 17`** — that would also swallow exit 17 from a machine
that *does* have drives, which is the entire reason the daemon ships.
**V2:** `checks.smartd-gate` boots the real distro module and asserts both
halves, because they pull in opposite directions — a gate that never skips
leaves the red icon; a gate that always skips silently disables drive-health
monitoring on real hardware, the failure nobody notices until a disk dies
quietly. So: no-SMART node → `ActiveState=inactive`, not failed, absent from
`systemctl --failed` (what the doctor reads); and the gate's logic driven
against a scan that *finds* a device → exit 0, since QEMU cannot answer SMART
honestly. Proved to fail by unwiring the condition. **V3 pending:** on real
drives smartd still runs (HARDWARE-QUEUE, dev box).
- ✗ **One chromium, not two (#121) — investigated, measured, DECIDED AGAINST
(Bernardo, 2026-07-14): "too much work for a negligible gain".** The bug is
real and the fix worked; the *gain* is what failed to survive measurement.

View File

@@ -560,10 +560,6 @@
touch $out
'';
# nomarchy-doctor's contract: an induced failed unit flips the
# sheet to ✖/exit-1 and names the unit; with the failure
# cleared it reports healthy/exit-0. Minimal node (just the
# package) — the disk/flake/snapper checks self-skip in a VM.
# Live-ISO baseline apps (ROADMAP § live-ISO baseline apps, #103).
# The live session shipped no
# browser and no office for as long as it existed — the thing a user
@@ -654,6 +650,74 @@
touch $out
'';
# smartd self-gate (BACKLOG #118). Where no drive answers SMART,
# smartd exits 17 and systemd marks the unit FAILED — so the doctor
# honestly reported a failed unit and Waybar went red on every QEMU
# guest and most live USBs. Both halves matter and they pull in
# opposite directions, which is why both are asserted here: a
# gate that never skips leaves the red icon, and a gate that always
# skips silently disables drive-health monitoring on real hardware —
# the failure nobody would notice until a disk died quietly.
smartd-gate = pkgs.testers.runNixOSTest {
name = "nomarchy-smartd-gate";
nodes = {
# QEMU virtio: no SMART. The machine Bernardo saw. Imports the
# REAL distro module, so this guards the shipped wiring rather
# than a restatement of it — runNixOSTest supplies the node's
# pkgs, so the module's own `nixpkgs.config` has to yield.
nosmart = { lib, pkgs, ... }: {
imports = [ ./modules/nixos/default.nix ];
nixpkgs.config = lib.mkForce { allowUnfree = true; };
nomarchy.system.greeter.enable = false;
# For the test's own probing only — the gate calls smartctl by
# store path, so this changes nothing about what is measured.
environment.systemPackages = [ pkgs.smartmontools ];
};
};
testScript = ''
nosmart.wait_for_unit("multi-user.target")
# The gate itself agrees there is nothing to monitor.
cond = nosmart.succeed(
"systemctl show -p ExecCondition --value smartd.service"
)
assert "smartd-any-smart-device" in cond, f"gate not wired: {cond}"
nosmart.succeed("smartctl --scan | tee /dev/stderr | (! grep -q .)")
# Inactive, NOT failed the whole point. Before #118 this was
# 'failed' with Result=exit-code / status=17.
state = nosmart.succeed(
"systemctl show -p ActiveState --value smartd.service"
).strip()
assert state == "inactive", f"expected inactive, got {state}"
nosmart.fail("systemctl is-failed --quiet smartd.service")
# And therefore the thing the user actually sees: the doctor's
# failed-unit check is what reddened the Waybar icon.
failed = nosmart.succeed("systemctl --failed --no-legend --plain")
assert "smartd" not in failed, f"smartd still failed: {failed}"
# The other half: a machine WITH a SMART device must still run
# smartd. QEMU cannot answer SMART, so drive the gate's logic
# against a scan that finds one, rather than pretend otherwise.
nosmart.succeed(
"mkdir -p /tmp/fake && "
"printf '#!/bin/sh\\necho \"/dev/sda -d scsi # /dev/sda, SCSI device\"\\n' "
"> /tmp/fake/smartctl && chmod +x /tmp/fake/smartctl"
)
gate = cond.split("argv[]=")[1].split(" ")[0].strip("; ]")
nosmart.succeed(
f"sed 's|/nix/store/[^ ]*/bin/smartctl|/tmp/fake/smartctl|' {gate} > /tmp/gate2"
)
nosmart.succeed("chmod +x /tmp/gate2")
nosmart.succeed("/tmp/gate2") # exit 0 => smartd would start
'';
};
# nomarchy-doctor's contract: an induced failed unit flips the
# sheet to ✖/exit-1 and names the unit; with the failure
# cleared it reports healthy/exit-0. Minimal node (just the
# package) — the disk/flake/snapper checks self-skip in a VM.
doctor = pkgs.testers.runNixOSTest {
name = "nomarchy-doctor";
nodes.machine = { ... }: {

View File

@@ -168,6 +168,27 @@ in
notifications.x11.enable = lib.mkDefault true;
notifications.wall.enable = lib.mkDefault true;
};
# Self-gate on the hardware, like every other conditional bit of the
# distro. smartd's config is DEVICESCAN, and where no drive answers SMART
# it exits **17** ("Unable to monitor any SMART enabled devices") — which
# systemd records as a FAILED unit, nomarchy-doctor faithfully reports as
# a failed system unit, and Waybar renders as a red health icon. That is
# every QEMU guest (virtio exposes no SMART), most live USB sticks, and
# some eMMC — so a plain VM install greeted the user with a health warning
# about a daemon that had nothing to do (Bernardo, live ISO 2026-07-14).
#
# ExecCondition is the right lever, not SuccessExitStatus = 17: a failed
# *condition* leaves the unit **inactive** and unfailed, while exit 17
# from a machine that DOES have drives still fails loudly — which is the
# entire reason the daemon is here. `smartctl --scan` prints nothing
# exactly when smartd would find nothing, so it is the same question
# asked before the daemon can fail it.
systemd.services.smartd.serviceConfig.ExecCondition =
lib.mkIf config.services.smartd.enable
(lib.mkDefault "${pkgs.writeShellScript "smartd-any-smart-device" ''
[ -n "$(${pkgs.smartmontools}/bin/smartctl --scan)" ]
''}");
# Core security: enable AppArmor to confine desktop apps and services.
security.apparmor.enable = true;
security.apparmor.killUnconfinedConfinables = false;