SmartConfig

Review of chunk J: the M5 follow-ups’ restore and check items

Date: 2026-10-12, after M5 follow-ups 3, 4, 5 and 5a and 8b98817 were built (5f93d06..f48e3c0):

How it was reviewed:

Gate: no high-severity finding. Three were medium (J1, J2, J3). All 13 are fixed. Three asked for a decision, and the owner picked the recommended answer for each (2026-10-12): J1, J6 and J7.

What held up

Findings

Area Finding Severity Fixed
the rescue undo (J1) The undo a rescue report prints, sc restore GOOD, asked when GOOD had an error the file now lacked, or when the file was now missing or a link (all of GOOD’s problems counted as added); without a terminal it exited 2. The README said it asks nothing. medium Your pick: the version sc status’s undo names (the path’s row at the last healthy boot whose row is known) booted healthy, so it is written with no check and no question. Status’s boundary code is healthyLine, which both use (4b3c88b).
status and check (J2) sc status and sc check <id> judged a version without its row’s mode. A sudoers drop-in made world-writable was “no problem found” in the rescue report, with no undo and exit 0, while scd logged an error. medium Both use CheckVersion with each row’s mode and owner (5a9b069).
grub.d (J3) NAME=$NAME word and NAME+="...", the two ways a drop-in appends wrongly, passed the check. dash runs the word as a command, and update-grub, and with it a kernel’s postinst, stops. medium Both are blockers; a value of plain characters, $NAME and ${NAME} is judged (b5ce497).
cut checks (J4) A check cut short (a validator out of time) restored without a word. low Its notes go to stderr (9a08186).
refusal order (J5) The check and its question came before Restore’s own refusals: a read-only store, a fingerprint-only path or a directory that became a symlink was asked about and a yes then refused; the symlink’s refusal read differently with --force. low store.RestoreRefusal runs them first, in Restore’s order (9a08186).
the question (J6) The question read whatever stdin was and wrote to stdout: sc restore X > file waited with its prompt in the file, and a while read id loop gave it the next line as its answer. sc prune did the same. low Your pick: both ask only when stdin and stdout are terminals; without one they read nothing, name --force or --yes on stderr, and exit 2 (71ba76d).
removals (J7) Restoring a “did not exist” or deleted row of a checked file removed it with no question; sc status then called it “error: deleted”. low Your pick: such a removal asks, unless --force, for the files statusProblem calls an error (not flag files, ld.so.preload, or a unit a later directory stands in for) (4b3c88b).
scd’s check (J8) scd’s check of the version after a change read the mode on disk, and remembered it by content alone: a chmod before the check was blamed on the content row, and the chmod’s row said nothing. low The version after is checked by its row’s mode and owner; the result is remembered by content, mode and owner (ed5c93f).
grub.d (J9) GRUB_TIMEOUT=0 GRUB_TIMEOUT_STYLE=hidden, which sets both, was a blocker; grub.d/.50-old.cfg, which sh’s *.cfg skips, was checked. low Assignments in a row are fine. A name with a leading dot that only a wildcard matched has no checker, in every directory of the graph: sh, glob(3), systemd, udev and sudo all skip it (b5ce497).
help (J10) sc help restore abc123 said unknown command "restore abc123"; sc help help had lost its text. low restore has no command "abc123" (see: sc help restore), exit 1; an unknown topic is as before (87f987e).
scratch (J11) A scratch directory was made, or its absence noted, before knowing whether the path is checked at all. cleanup The checker is looked up first (9a08186).
docs (J12) Comments on mutating, on a link at the restored path and on grub.d, the README’s “asks nothing”, the worklog’s “Now”, and MILESTONES’ Open items 3 and 11 no longer said what the code does. cleanup Fixed with the findings they belong to, and in this write-up’s commit.
tests (J13) Mutations survived the suite: answers (“yes”, spaces), the question’s newline, the explanation, a check that fails, no scratch directory, the read-only root, the row’s uid and gid, a warning that asked, the setgid, sticky and gid bits, scd’s version before by gid, InitDefaultHelpFlag. cleanup The reviewer’s passing tests are kept, and new ones added (TestRestoreAnswers, TestRestoreUnchecked, TestRestoreCheckCannotRun, TestRestoreChecksOwner, TestRestoreWarningNotAsked, TestRestoreRemovalNotAsked, TestRestoreCtrlCAtQuestion, TestStatusBeforeByRowMode, TestCheckVersionModeBits, TestCheckRestoreModeOkAgain, TestCheckRowOwners). All 59 mutations are killed.

Not changed