docs(agent): D1 — README self-update section, REUSE, CHANGELOG v0.70.0, CONTEXT

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-05 15:36:13 +02:00
parent 8033a522cd
commit 915642aaaa
4 changed files with 93 additions and 0 deletions
+30
View File
@@ -1,3 +1,33 @@
## v0.70.0 — agent self-update (operator-signed, A/B slots, crash-loop auto-rollback) (2026-07-05)
Closes the update asymmetry: the root-adjacent agent was updated by manual SSH binary-replace while
the lower-stakes controller already auto-updates. Design provenance:
`felhom.eu/documentation/audits/SPIKE-agent-selfupdate-2026-07-05.md` (SF-findings binding). Core
principle (as with the controller swap): the thing that performs rollback is never the thing being
updated — here systemd + an ~80-line root wrapper.
- **Trust model:** an update is an operator-signed `agent_update` op (new `reconcile.ClassAgentUpdate`,
always Destructive) through the existing signed-jobs pipeline; the signed params pin version + sha256,
so the sha is the ONLY integrity root (hub = dumb transport, Gitea = dumb storage — neither can
substitute a binary). `felhom-opsign -op agent_update -agent-version <v> -sha256 <hex>`.
- **Host artifacts** (`configs/`): `felhom-selfupdate-guarded` (apply/commit/rollback — root re-verify,
path confinement, same-fs assert, `.prev`, atomic mv, pending marker, detached restart [SF-6];
rollback pending-guarded [SF-1]); `felhom-agent-rollback.service` (OnFailure oneshot);
`felhom-agent-limits.conf` ([Unit]-only drop-in [SF-3] with the spike's tuned 120s/4 [SF-2] +
OnFailure=); `FELHOM_SELFUPDATE` sudoers alias.
- **Go** (`internal/selfupdate/`): `Executor` (download → verify vs signed sha → `sudo -n` wrapper
apply; job completed after verify+download, before apply); `Manager` (startup dwell → `commit`;
version-mismatch → no-commit + WARN + marker-left; report seam `SelfUpdatePending()`). Wired as a
3rd executor-chain element + a `MaybeCommit` goroutine after core init. `SelfUpdateConfig`
(url_template/creds/dwell, Token redacted). Additive report fields `selfupdate_pending(+version)`
(omitempty → cross-repo golden contract byte-stable, no hub change). 3 non-critical capability probes.
- **felhom.eu:** `felhom-host-install.sh` installs the wrapper + rollback unit + drop-in on day-0
(self-update from birth); agent README "Self-update" section.
- Tests: executor (happy / sha-mismatch + companion / bad-params / wrapper-fail), gate ride-along
(agent_update rides the LOCKED gate: pinned-key executes, non-pinned + retarget rejected), commit
(dwell-commit / version-mismatch / no-pending / shutdown), opsign, classify. Wrapper covered by
shellcheck + the live crash-rollback drill. Full `go test ./...` green.
## v0.69.0 — S5: host-loss DR — recovered WG-key install + directive→restore-PLAN (safe halves) (2026-07-04)
The two safe, non-destructive mechanical links for host-loss DR (the destructive in-place restore is