## v0.145.0 — the OS update repairs itself after a power cut; a short-session box gets restore-tested; "sent late" (R-876, R-874, R-875) (2026-10-05) Released by `scripts/release-agent.sh`: binary sha256 `894da35c7b9e1ac78885690b78352b634e6831e7d99b321573c75d878db8886e`, config bundle sha256 `78c00adce662d2d966b2ac50ebde46cde1ae225f0107c6a7c02b70ec8ce80c4f`. The wrapper changed: a box needs the signed `agent_update` AND the signed `agent_config_update`. - **R-876.** After a crash during an install, `dpkg --audit` can read clean while dpkg's update journal (`/var/lib/dpkg/updates/`) is not — and apt refuses every install until `dpkg --configure -a` (measured on demo-hp 2026-10-05: every later pass failed until a person typed it). The wrapper now reads `--audit` and the journal in ONE `sh -c` call (`DPKG_STATE_SCRIPT`) — a clean pass still costs one call (R-845's speed, pinned) — and repairs when either shows something; as a belt, when apt itself says "dpkg was interrupted", it repairs and retries the install ONCE. `REPAIR` now logs `journal=N`; a journal still not empty after the repair refuses (R13). Tests `CrashLeftTheJournal` (the measured shape, the speed, the belt); 3 red-proofs. - **R-874.** The restore-test's first due-check runs 30 minutes after the agent starts (`DefaultFirstEval`), then every interval; a box whose power-on sessions are shorter than the 6 h interval never evaluated. A crash-looping agent restarting faster than 30 minutes still never evaluates (the earned restraint, pinned). - **R-875.** A kept report's reason is neutral — "sent late — kept on the box until the hub could take it" — the copy cannot tell a killed agent from an absent hub. - Red-proofs: `felhom.eu/documentation/audits/catchup-2026-10-05/part{C,D}/`. ## v0.144.1 — a killed pass really keeps its report: the wrapper survives a dead reader; the agent looks again every 5 minutes (R-868, measured live) (2026-10-05) Released by `scripts/release-agent.sh`: binary sha256 `6ccd521d47e64999017e8eb5bc613d724543cfdc5ef9b13bcae9e3ea8c53b8f3`, config bundle sha256 `e89a9ddfb767e177f8874d56f3dcd3bfd47409d157ff830d362653333bf815e8`. The wrapper changed again: a box needs the signed `agent_update` AND the signed `agent_config_update`. - **Found live on demo-hp 2026-10-05 05:45 UTC with v0.144.0** (the night's A5 shape: kill -9 of the pass and the daemon while apt-get ran): apt finished all 13 packages, but the wrapper's next log line went to a stderr pipe no process read any more → `BrokenPipeError` → the wrapper died before it saved its report copy (journal: `PLAN upgrade=13`, then nothing; no copy; the hub got nothing). v0.144.0's mechanism was right and never reached. `Runner.log` and the final `OSAPPLY-REPORT` line now survive a dead reader (the journal still gets every line). Test `AgentDiesMidPass` drives the REAL `log()` into a pipe that breaks while apt-get runs. - **Also found live:** the restarted daemon looked for kept copies ~7 s before the orphaned wrapper wrote one. The daemon now looks at start and every 5 minutes (`Leg.SendUnsentLoop`); `TestR868_ACopyWrittenAfterTheStartIsSentByTheLoop`. - Red-proofs: `felhom.eu/documentation/audits/night-fixes-2026-10-05/partD/r868-brokenpipe-red-proof.txt`. - A second agent release in one session, against "one release per repo": recorded as `09` decision 108 (operator may reverse) — the alternative was to ship a fix proven not to work. ## v0.144.0 — R8 measures the real download; an OS pass reports even when its agent was killed; the debug pass runs with the hub away (R-865, R-868, R-866) (2026-10-05) Released by `scripts/release-agent.sh`: binary sha256 `f18093c3466749ec4cd47f83f97a401160a24bad1e704f1183051adad14db928`, config bundle `felhom-config-bundle.json` sha256 `6acf42fe46df5223384d767801cb2bf73238ba4dab82debb7811ca2f790591d8`. The wrapper `felhom-os-apply` changed, so a box needs BOTH the signed `agent_update` and the signed `agent_config_update`. - **R-865.** `download_bytes` runs `apt-get --print-uris` WITHOUT `-s`: with `-s` apt prints the simulation and no URI list, so R8 summed 0 B and only its 500 MB floor ever applied. `--print-uris` alone downloads nothing (measured on 9202: the archive cache and the versions unchanged). The test fake now answers like real apt (with `-s`: no URIs), and `test_R8_counts_the_real_download` / `test_download_bytes_never_simulates` pin it. - **R-868.** The wrapper writes every apply pass's report to `/report---apply.json` before it prints it (root writes into the agent's dir: the dir opened O_NOFOLLOW and checked to be the agent's own, the file created O_EXCL|O_NOFOLLOW, 0600, handed to the agent). The plan now carries `run_id`, `trigger`, `ring`, echoed in the report. The agent deletes the copy once the hub has the report; a copy left on disk (the agent was killed, or the hub was away) is sent at the agent's start and before every pass (`Leg.SendUnsent`), then deleted. A pass lock (flock on `pass.lock`, across the daemon and a selftest) keeps the sender off a pass that is still running. - **R-866.** The daemon saves the hub's newest os_update block (`os-update-block.json`); `--selftest=os-update` uses it when the hub cannot be reached and says so in its header (`block=SAVED(