Pierre Rouanet 692e1682b1 The transcript said "healthy" about a robot its own journal called degraded
Two things the first full run on a board showed, one of them wrong.

**The health line was false.** `health_gate` returns `Ok(())` for two different
outcomes: the robot reported healthy, and the robot reported *degraded* for a
reason this release cannot have caused and a rollback cannot fix — servo power
off, a sensor unplugged — which is committed on purpose. Collapsing both into a
bool gave a transcript reading

    14:00:55  health   the robot reported healthy

nine lines above a journal entry, at the same second, reading

    committing: the robot is degraded ... no robot on the motor bus

The gate now returns `GatePassed::{Healthy, Degraded(reason)}` and the
transcript carries the reason. The warning that distinction already produced has
been in the journal since the branch was written, precisely so nobody would have
to guess — the transcript was the one place throwing it away.

**The hook output was on screen twice.** `hooks::run` writes it to the journal a
line at a time, deliberately, so it is greppable; the transcript records the
same output as one event. Splicing both put the pre-install hook's ninety lines
— the ONNX and GStreamer survey — through twice in a row, a third of the output.
The splice now drops journal lines from the `updater::hooks` target, since the
transcript above carries them in full. Everything `updater::engine` says stays,
as does every other daemon: that is the half the transcript never sees.

Matched on the target as journald renders it. If that rendering changes the
filter stops matching and the duplicates return, which is the right way for it
to fail — repeated rather than silently dropped.

Assisted-by: Claude:claude-opus-5[1m]
2026-08-27 16:06:43 +02:00
..