microduck/test-support
Pierre Rouanet 8e497c4ed0 An update must not restart the recovery net's oneshot
`robot-boot-check.service` was in `on_apply`'s restart set:

    units_to_restart = ["configd", "padd", "robot-boot-check", "robotd"]

It asks whether the release that booted came up and hands over to `robot-rescue` if
not, so an update restarting it points a rollback check at daemons that are
legitimately mid-restart — and `robot-rescue` can answer by swapping to golden and
rebooting. Mid-update.

`hooks/postinstall` already declines to `enable --now` it, and says exactly why:
"`enable --now` on it would run a rollback check in the middle of the update that
installed it, with daemons legitimately mid-restart". The engine then read every
`*.service` and restarted it a moment later anyway. Two places, one rule, one unit,
and they disagreed.

What kept it harmless is a guard for a different caller: the script declines when
uptime is over ten minutes, and its comment names `postinstall` as the reason that
guard exists. Inside the first ten minutes of a boot — a dev board, or `auto_apply`
polling sixty seconds after `updaterd` starts — the guard does not apply and the check
evaluates its members while two of them are restarting. It needs `failed` or three
restarts to act, so it would usually decline; "usually" is not the property wanted from
the thing that reboots the robot.

Keyed on `[Install]` rather than on a name in `NEVER_RESTART`. A unit without one is
triggered by something else, so its lifecycle is not the update's to drive; and stating
it as the rule makes `postinstall` and the engine agree by construction rather than by
both being remembered. An unreadable unit counts as one to restart, because that is
more likely a permissions problem than a triggerless unit, and failing loudly beats
skipping quietly.

Demonstrated rather than argued: the fixture now ships a unit shaped like the real one,
recording each time it runs, and the harness asserts it did not. With the rule disabled
that assertion fails, printing the `ran` the unit left behind.

`install-path-gap.md` is retitled and closed. Its own body has said the gap is shut
since the artifact-install test landed, while its title and revision note still said
otherwise. `restart-order.md` gains the rule and stops calling five units the whole
set.

Assisted-by: Claude:claude-opus-5
2026-08-11 19:03:38 +02:00
..