Status: built and signed off; M5 is done (tag m5 on 8f91158,
2026-10-09). The plan itself is not approved: it was drafted on
2026-10-08 for your read, and your call (2026-10-07) was that M5 starts
after the M3/M4 follow-ups whether or not you have read it. Where a
choice is yours, the plan went on with the one marked (recommended) and
said so in the worklog, so it can still be turned round. Section 9 lists
where the build differs from the plan.
M5 turns the hand install of the README into one .deb, smartconfig,
that installs, upgrades, removes and purges cleanly on Ubuntu 24.04, and
proves that on a clean VM in the QEMU lab (both firmware modes) and on
this VM, replacing the hand install.
What goes in it (today’s hand install, moved to packaged paths):
| File | Today (by hand) | In the package |
|---|---|---|
sc |
/usr/local/sbin/sc |
/usr/sbin/sc |
scd.service, sc-boot-seen.service, sc-boot-ok.service |
/etc/systemd/system/ |
/usr/lib/systemd/system/ |
| the rescue and emergency drop-in | /etc/systemd/system/{rescue,emergency}.service.d/50-smartconfig.conf |
/usr/lib/systemd/system/{rescue,emergency}.service.d/50-smartconfig.conf |
42_smartconfig |
/etc/grub.d/42_smartconfig |
the same (a conffile) |
| the store | /var/lib/smartconfig (scd makes it) |
the same; kept on remove, asked about on purge (Q3) |
| docs | the repo | /usr/share/doc/smartconfig/ (README, copyright, changelog) |
/usr/sbin, not /usr/local/sbin: a package never writes /usr/local
(Debian policy 9.1.2), and the rescue boot mounts only /, where /usr
is (merged-usr on 24.04); /usr/local on a disk of its own was a README
caveat that goes away.
Goals:
make deb builds dist/smartconfig_<version>_amd64.deb from a clean
tree, reproducibly (the same bytes twice: SOURCE_DATE_EPOCH from the
commit, sorted members, root:root), with the static sc the lab
tests.daemon-reload, the three units enabled
(deb-systemd-helper, as dh_installsystemd would), scd started,
update-grub run, the grub.cfg checked; the first verdict comes at
the next boot, as today..deb over an older one): scd restarted once, after
the new sc is in place (scd is Type=notify: an old sc under a new
unit never says ready); the store and the boots file untouched.42_smartconfig gone from
grub.cfg (update-grub), the menu flag cleared, the store kept.
Purge: as Q3 says./etc/systemd/system
and /usr/local/sbin/sc that match a released build are moved aside,
others are left and named (Q4)..deb on its clean image instead of
install.sh (a new --deb mode of lab/e2e.py, both firmware
modes), runs the M4 scenario unchanged, then upgrade, remove and purge
checks..deb and checks its contents and control file.Non-goals: an apt repository or PPA (M5 ships the file), signing,
other architectures than amd64 (arm64 later: sc builds for it), other
distributions than Ubuntu 24.04, a Debian source package.
(recommended) dpkg-deb --root-owner-group --build on a staged tree,
from a make deb target and a small script (scripts/build-deb.sh):
dpkg-deb is on every Ubuntu machine and CI runner, so nothing new is
added. The maintainer scripts are plain sh, written out (no debhelper).
The milestone named nfpm: one YAML file instead of the staging script,
but a new tool (a Go module tree, pinned and fetched with go run
github.com/goreleaser/nfpm/v2/cmd/nfpm@vX). The project’s rule is no new
dependency without asking: that is Q1.
Version: 0.5.0 at the tag m5; between tags
0.4.99+git<count since m4>.<UTC time>.<sha7> so a later build always
sorts higher (C3).
sc version prints the same.
postinst configure: deb-systemd-helper enable for the three units
(unmask first), systemctl daemon-reload, systemctl restart scd on
an upgrade (start on a first install), update-grub, then
grub-script-check /boot/grub/grub.cfg; a failing update-grub is
reported and does not fail the install (the system boots as before
without the rescue entry). The hand install’s copies are handled here
(Q4).prerm remove: stop scd. postrm remove: daemon-reload,
update-grub, grub-editenv unset smartconfig_pending.
postrm purge: deb-systemd-helper purge, and the store as Q3 says.set -e, idempotent (dpkg may run them again after a
failure), and quiet when /boot/grub is not there (a container).The units’ ExecStart=, ConditionFileIsExecutable=,
RequiresMountsFor= and the drop-in’s ExecStartPre= name
/usr/sbin/sc; the README’s hand install goes (it points to the
package); lab/guest/install.sh stays for the hand-install mode of the
lab until the .deb mode has passed, then goes; accept-m4.sh reads the
path from the unit. The unit tests’ expectations change with them.
One step at a time, each with its tests, the full checks, a commit, a worklog line, push and CI green.
sc version and the version string (from the build: -ldflags -X)./usr/sbin/sc).scripts/build-deb.sh and make deb: the staged tree, the control
file, md5sums, conffiles, copyright, changelog; reproducible.TestLabGuestFacts does for facts.sh).make deb, dpkg-deb --info/--contents checked against a list,
the .deb as an artifact.--deb mode: install with apt install ./x.deb, the M4
scenario, then upgrade (a second build with a higher version), remove,
purge (checks D.x).make lab-e2e LAB_E2E_ARGS=--deb both modes; on this VM:
install the .deb over the hand install, the post-install checks, a
reboot and its verdict; then remove and install again.make deb twice gives the same sha256.--deb run passes in both modes, D.x included.sc status exit 0, nothing left in
/etc/systemd/system or /usr/local/sbin from the hand install
(or named, per Q4).postinst that fails half way leaves units enabled without sc:
the scripts are ordered so each step can be run again, and the lab’s
remove/purge checks look for leftovers.update-grub in postinst on a machine with a broken GRUB config: it
is reported, not fatal; the README says how to run it again./etc/systemd/system/scd.service
shadows the packaged unit: the migration step (Q4) is what prevents a
Type=exec copy running the new sc./usr/sbin/sc (recommended: policy, and / is all the
rescue boot mounts) or keep /usr/local/sbin/sc?/var/lib/smartconfig (recommended: the history is the
point of the tool; the purge says where it is and how to delete it),
or delete it?smartconfig (recommended) or sc?copyright file names one. Until you choose, it says “No license has
been chosen yet: all rights reserved”. Which license (for example MIT,
Apache-2.0 or GPL-3.0)?sc, a spreadsheet, whose /usr/bin/sc the package’s
/usr/sbin/sc hides for anyone with both installed (/usr/sbin comes
first in Ubuntu’s PATH), and Debian policy 10.1 asks for other names.
Keep sc and say so in the README (recommended for now: the project,
its docs and the rescue report all say sc; nothing is published to
an archive), add Conflicts: sc, or rename the command before a
wider release?The questions run on their recommended answers until you say otherwise; the plan above is as drafted, and these are where the build differs.
| # | Date | Change | Why | Commit |
|---|---|---|---|---|
| C1 | 2026-10-08 | postinst restarts scd on every configure, a first install too (section 3 said start); it runs no grub-script-check (goal 2, section 3): grub-mkconfig checks its output before it replaces grub.cfg. |
A hand install’s scd may still run its old sc, and start leaves a running unit as it is. |
e710ce2 |
| C2 | 2026-10-08 | The hand install is recognised by SmartConfig’s marks in each file (the repo’s URL in a unit, sc status --console in a drop-in, the header line of 42_smartconfig, the store’s Go package path in sc), not by matching a released build (goal 5). |
Every hand install since M2 carries them, and a build of any commit is SmartConfig’s. | e710ce2 |
| C3 | 2026-10-08 | From the review: the takeover runs on a first install only (dpkg passes no version); preinst moves only 42_smartconfig (its conffile prompt), postinst’s first configure the rest, and postrm abort-install puts 42_smartconfig back. The version is 0.N.99+git<count since mN>.<time>.<sha7> (section 2 said <UTC date>.<sha7>), and no mN tag is an error. |
reviews/2026-10-08-m5.md: a remove and install again lost the rescue entry; a failed install left the hand install moved aside; a commit could sort below its parent. | 5e9f1e3, 8284709 |
| C4 | 2026-10-08 | CI prints the package’s control and contents (step 5 said “checked against a list”); TestBuildDeb holds the contents to the list, with a stand-in sc. |
One list, in a test that runs everywhere. | 922e5cc |
| C5 | 2026-10-08 | The lab installs with dpkg -i (step 6 said apt install): the guest has the dependencies, and both run the same maintainer scripts; apt install is the README’s and this VM’s sign-off’s. lab/guest/install.sh stays, for both modes (section 4 said it goes). The lab also checks the takeover of the m4 tag’s hand install (D.4) and a remove and install again (D.5). |
The files mode is still the M4 scenario’s own run. | 7c4e466, 4df3912, 99d91ba |
| C6 | 2026-10-08 | With DPKG_ROOT set (dpkg’s --force-script-chrootless), the scripts keep to that root for their own files, but daemon-reload, the restart and update-grub act on the running system when their guards find run/systemd/system or boot/grub/grub.cfg under it. |
No tool takes a root for them, and the tests need DPKG_ROOT for the files; such installs are rare and need the force flag. |
84f9959 (the review’s A6) |
| C7 | 2026-10-08 | From the sign-off on the dev VM: postinst says when scd was not restarted (its MainPID unchanged, or none while enabled), and prerm when scd still runs after the stop, with the command; /usr/sbin/policy-rc.d is honoured, as every package does. |
This VM’s image has a policy-rc.d that forbids everything, and the hand install’s scd ran on its moved-aside sc, silently. |
8bd34c3 |
| C8 | 2026-10-08 | From the sign-off on the dev VM: sc status does not call a deleted unit or drop-in of /etc/systemd/system an error when systemd reads one of the same name from a later unit directory (deleted; /usr/lib's in use); a mask is no stand-in. |
After the takeover it exited 2 on the hand install’s files and offered sc restore, which would have hidden the package’s units again. |
d81e2d5 |