Date: 2026-10-06. Two reviewers (AI agents) read 6ce3263..8f071ed, read-only, with no
root and no QEMU. The chunk is:
scripts/accept-m4.sh (make accept-m4): the parts of M4 that need no
reboot, run once as root on the dev VM in sign-off S1 (3e72281);b722bf4).Reviewer A took the script. Reviewer B took the docs. Their reports are kept outside the
repo (~/smartconfig-work/review-m4e/findings-{a,b}.md).
They found 1 high, 4 medium, 12 low and 6 cleanups. The high one is in the README’s GRUB
password recipe, which had not shipped to anyone. One medium one is a product bug in
sc status, older than this chunk.
| # | Area | Finding | Sev | Fix |
|---|---|---|---|---|
| B1 | README | The GRUB password recipe marks only the “Ubuntu” entry --unrestricted. With GRUB_DEFAULT=saved, a default under “Advanced options”, GRUB_SAVEDEFAULT, GRUB_DISABLE_SUBMENU or a ZFS root, every unattended boot stops at the password prompt. The grep -c check did not show which entry boots, and there was no way back. |
high | Use it only when the defaults show GRUB_DEFAULT=0 alone; check that exactly one line, the Ubuntu entry, is marked; if not, do not reboot, and how to undo it; what to type at the prompt. |
| B2 | README | 10_linux is a grub-common conffile: taking the new one at an update drops --unrestricted while the password stays, and unattended-upgrades skips such updates. |
medium | Say to keep yours (N), what happens otherwise, and to install that update by hand. |
| B4 | sc status | The undo was for the newest change with a blocker or an error. With an older fstab blocker and a newer error elsewhere, the console listed the blocker first and its commands restored the other file: the next boot fails again. Plan 3.1 and chunk B say “the newest blocker”. | medium | 654ee7f: the newest blocker, else the newest error; a test with both, which fails on the old code. |
| A1 | accept-m4 | systemd unloads a finished oneshot that nothing refers to, so the units’ invocation id came back empty. The journal read was empty, so step 2 would FAIL on “sc boot verdict said:”. The seen unit’s checks and Result could not fail, and the run time read 0 ms. |
medium | 4b91d97: RemainAfterExit=yes on the runtime units; the id and times must be there; stop before removal. |
| A2 | accept-m4 | Section 8 opened the real store read-write: the validators’ scratch went to /var/lib/smartconfig/tmp, and the read-only path was never run on the store S3’s rescue shell will read. |
medium | 4b91d97: the real store is bound read-only over itself in a private namespace; --console must fit 80x20 on it. |
| B3 | README | What the password closes was listed in part: older kernels, every other entry, GRUB’s command line, grub-reboot; GRUB reads the password with a US layout. |
low | Listed. |
| B5 | README, plan | The rescue boot mounts only /: a separate /var or /usr/local means no report and no sc; a separate /boot needs mount /boot before restoring under /boot/grub. Plan section 8 said sc status says so; it does not. |
low | README and PROJECT_LOG say what to mount; plan change C7; in MILESTONES as open. |
| B6 | MILESTONES | “The boot is tested … never on the dev VM”: S2 and S3 test it there. | low | Corrected. |
| B7 | MILESTONES, plan | “At most 5 files (C4)”, but C4 says 6: chunk C’s fixes made it 5 without a plan change. | low | C7 records it. |
| B8 | sc status, PROJECT_LOG | “The menu shows once more” was promised in every rescue boot, also one picked by hand after a healthy boot, when no flag is set. | low | 654ee7f: only while the flag is set (a failed boot since the last healthy one, or this boot’s own seen line: the emergency shell); C7; PROJECT_LOG says “after a failed boot”. |
| A3 | accept-m4 | The “no flag after ok” check passed when grub-editenv list itself failed. |
low | 4b91d97: the copy must equal the real block byte for byte. |
| A4 | accept-m4 | Nothing checked that the sed put SC_HOME and BindPaths= into the runtime units; without them sc would write the real grubenv and store. |
low | 4b91d97: checked, and a symlinked unit file is refused. |
| A5 | accept-m4 | GRUB_DISABLE_OS_PROBER=true in the environment did nothing: grub-mkconfig sets it to “auto” itself. |
low | 4b91d97: a copy of /etc/default/grub.d with one more file, bound in the namespace. |
| A6 | accept-m4 | A second Ctrl-C cut the cleanup short, and the cleanup said nothing about what it left. | low | 4b91d97: signals ignored in cleanup; a WARN line for leftovers and changed real files. |
| A7 | accept-m4 | The initrd check could pass with no initrd line, and -w took a prefix. |
low | 4b91d97: the lines must be there and match exactly. |
| A8 | accept-m4 | The checksums left out /etc/default/grub.d and the rest of /boot/grub, and were compared only on success. |
low | 4b91d97: added; compared in cleanup too. |
| A9 | accept-m4 | No “bad” verdict on the real system; no word on what S2’s update-grub will change. | low | 4b91d97: step 2b with a fake systemctl bound in a namespace; a note comparing grub.cfg with what grub-mkconfig makes. |
| B9 | README | The removal left the two .service.d directories. |
cleanup | rmdir --ignore-fail-on-non-empty; the boots file stays with the store. |
| B10 | README | “A verdict for every boot” (the rescue boot gets none); “the same report as a table” (one row per file, validators too); “its sign-off runs are next” (the review first). | cleanup | Corrected. |
| B11 | MILESTONES, sc | Two chunk D open items missing; “a hung sc shows nothing” (it shows the stop line since C6); the stop line said “1m0s”. | cleanup | Added; corrected; 654ee7f says “60 s”. |
| B12 | docs | Stale lines: the worklog’s “Kernel 7.0.0-38 boots at your next restart”, PROJECT_LOG’s backup list. | cleanup | Corrected. |
| B13 | README | The GRUB manual says to export superusers for submenus. |
cleanup | The recipe has the third line. |
| A10 | accept-m4 | Comments that overstated: TMPDIR does nothing for root; two checks could not fail on a read-only mount; “Nothing real is written” with daemon-reloads. |
cleanup | 4b91d97: comments corrected, the two checks dropped. |
42_smartconfig exist only in private mount namespaces, grub-mkconfig
writes only its -o file, and BindPaths= fails closed.d9d505f9, nRec 1), reads(), and every section 3 and 7 check pass when replayed as
a user. Real grub-mkconfig output for this VM is the same on two runs.22383a0. Every
number, exit code, path and VM fact in the docs checks out against the code, plan and
machine. The install and removal commands are sound (install replaces the binary
under a running scd safely).systemd-analyze verify graphical.target with both units added shows no
ordering cycle; a control with a deliberate cycle was caught. That was chunk C’s open
item.password_pbkdf2: no QEMU in this review. The
README says the recipe is not tested in the lab; it is an open item in MILESTONES.654ee7f: TestStatusBlockerBeforeNewerError, TestStatusConsoleFits (rescue by
hand after a healthy boot, then after a failed one), TestSeconds. The first two fail
on the old code (mutations run). The lab’s console goldens are unchanged, and
TestStatusConsoleLab passes.go test ./... as a user and as root; make race; make
lab-test (326).make lab-e2e PASS (22383a0). S1 runs it again
on the final build.