REPORT + CONTEXT: v0.157.0 live proof on the three test boxes; not vouched
gates / gates (push) Successful in 30s

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
2026-10-15 21:54:58 +02:00
parent 52ed52c131
commit e569ec6c5f
2 changed files with 41 additions and 30 deletions
+6
View File
@@ -1,5 +1,11 @@
# CONTEXT — felhom-agent working state
> **2026-10-15 (night) — v0.157.0 RELEASED, NOT VOUCHED (storage identity build A, felhom.eu `16` §13).** Every storage
> place carries `kind`, `physical_disks`, `identity` (+ reason) in `GET /disks` and the hub report; `POST /disks/same-disk`
> answers the controller (v0.317.0, MinAgent 0.157.0). Computed on every read, never cached. Delivered by signed jobs to
> Tester 1, demo-hp, N100 only. Next: the operator vouches 0.157.0 → the global floor 0.317.0 / MinAgent 0.157.0. Build B
> (partition candidates, the internal place) waits for a task file (R-1079).
> **2026-10-08 (day) — UNRELEASED on main, ships with tomorrow's release (decision 178).** R-899: `POST /backup?trigger=manual`
> runs no OS leg (`localapi/server.go`); after-boot kernel reports carry the saved block's ring (`kernelReportRing`). R-304:
> `escrow.ErrRetainedUnchecked` → HTTP 424 `older_unchecked` when not every earlier package was tried (withheld, caps,
+35 -30
View File
@@ -1,38 +1,43 @@
# REPORT — v0.156.1: after a power cut the box clears up (R-1006, R-1008) (2026-10-14)
# REPORT — v0.157.0: every storage place knows its physical disk(s); POST /disks/same-disk (2026-10-15)
Evidence: felhom.eu `documentation/audits/power-cut-fixes-2026-10-14/` — the spike (C1 the night's leftover, C2 a killed
worker, C3 a real power cut, C4 a full disk), the 17 red-proofs.
## What the spike showed
- A power cut mid-backup leaves `vzdump-lxc-<vmid>-<date>.tar.dat` + `.tmp/` (root, in `/var/lib/vz/dump`); Proxmox never
lists it as a backup; nothing removes it; every later backup is skipped „not enough space".
- The dead vzdump task stays in Proxmox's active list ~30–60 s after the boot — long enough for the agent's start-up pass
to call it „genuinely in flight" (R-1008). Short, so R-1008's harm is small.
- A killed worker leaves `tar`/`zstd` writing into the `.tar.dat` for minutes, none named „vzdump" — the reason the root
helper checks open files, not only process names.
- On „No space left" vzdump removes its own partial (both paths): the preflight's sizing stays. But a full host root breaks
LVM's own metadata writes (a half-removed snapshot; the janitor cannot clear it — new row).
## 0.156.0 is superseded — do not vouch it
A background security review of the pushed 0.156.0 flagged „fail-open state drift": its in-flight rule compared a task's
wall-clock start with the kernel's `btime`, which moves when the clock is corrected after the boot (an NTP step after a
power cut) — a live backup could then look „from before the boot" and its lock be cleared. 0.156.1 uses Proxmox's own
liveness rule instead (the UPID's pid + pstart against `/proc/<pid>/stat` start tick and state; no clock), and fails safe
when this agent cannot see root's processes (PID 1 not visible).
Written in ASD-STE100 Simplified Technical English. Design read first: felhom.eu `architecture/16-storage-physical-identity.md`
(§3, §4, §8, §10; ACCEPTED 2026-10-15, §13 = what was built), `03-host-agent.md`. Task: storage identity build A (operator
rulings D1–D6). Controller counterpart: felhom-controller v0.317.0 (MinAgent 0.157.0); hub v0.154.0 shows the fields.
## What changed
See `CHANGELOG.md` v0.156.0: `vzdumpInFlight` behind the one `BackupRunning`; `internal/vzpartial` at start-up and before
each backup; the root helper `felhom-vzdump-partial-clean` + one sudoers line + the bundle entry.
- `internal/storage/identity.go`: the physical disk(s) under a place, from `/sys`, `/run/udev/data`, `/proc/mounts` only
(no block I/O). `proven`, or `unknown` with `vm` / `network` / `usb_bridge` / `weak_wwn` / `no_serial`.
- `GET /disks` rows and the hub report's `storage_targets` gain `kind`, `physical_disks`, `identity`, `identity_reason`.
- `POST /disks/same-disk` `{a, b}` → `{different, proven, reason, a, b}`; scoped like every `/disks` call; a path the agent
did not mount itself is `unmapped`.
- `configs/` unchanged.
## Gates
## Tests and red-proofs
`go build ./... && go vet` clean; `go test ./... -count=1` rc 0; `agent_gates.py` all OK; `visudo -cf` parsed OK; the
config bundle tests (55) and the helper's tests (21) pass. 17 mutations, 17 red.
Fixture `/sys` + udev trees for every spike case and five same-disk handler tests. Seen failing first: the LVM thin
„diamond" (tmeta/tdata under one pool) read as a failure — fixed by counting a seen node once. Broken on purpose and seen
failing: the VM rule, the vendor-less WWN rule, the own-mount rule (an absent drive), the `sys_drive` mapping.
`python3 scripts/agent_gates.py`: all OK.
## Next
## Release and delivery
Released: tag `v0.156.0`, binary sha256 `8db22788…`, bundle `a2160521…`, step bundle `0.156.0-step1` `8be2bb8f…`. Then the operator's vouch + floor, then the live proof on demo-hp (a cut mid-backup) and
delivery to Tester 1 and the N100.
- `scripts/release-agent.sh 0.157.0`: tag `v0.157.0`, sha256 `addd4041…0aef`, bundle `0604bc60…397a`.
- Delivered by signed `agent_update` jobs to Tester 1, demo-hp and the N100 (the three test boxes). **NOT VOUCHED** — the
operator's act. Until the vouch, the global floor cannot declare MinAgent 0.157.0.
## Live proof (method: the agent's local API on each PVE host, with the guest's own token)
| Box | `GET /disks` | same-disk: drive vs system data |
|---|---|---|
| demo-hp | `local`/`local-lvm` proven (SATA SSD), NVMe drive proven (`eui:`), PBS `network` | different, proven |
| N100 | system proven (SATA SSD serial), USB drive proven (the bridge passes the real serial) | different, proven |
| Tester 1 (VM) | every place `unknown/vm` | not proven (`vm`) |
On all three: system data vs `/var/lib/docker` → same disk, proven; a drive name that is not mounted → `unmapped`. The hub
stored the same fields (read from its database with the WAL). Evidence: felhom.eu `audits/storage-identity-buildA-2026-10-15/`.
## Observations
1. FILED: R-1083 — scratch box 9202 has no `local_api` in its `bootstrap.json`, so it cannot use any agent call.
2. NOT-A-FINDING: `usb_bridge` is built from the design's rule and was not seen on a real enclosure; that is R-1077, already open.