v0.39.0 — DR-recipe completion: live PBS coord + drop role/restic_repo_coord from v1 drive shape
Live PBS coord: new internal/pbs/live_reporter.go (LiveSnapshotReporter implements
hub.PBSReporter via the cheap Client.Snapshots() list with last-known-good fallback,
bounded by an 8s timeout, list-only — never triggers a verify). Closes the gap where
the recipe's pbs block was omitted whenever the verify-loop SnapshotStore was empty
(one-shot collect + the first ~6h after a daemon restart). SnapshotStore.Get added
(per-datastore LKG). Wired into the collector in both runDaemon and runSelftestHub;
the verify loop keeps Recording into the SAME shared store via one hoisted pbsTargets.
v1 host-half drive shape: dropped drives[].role (hub/operator-owned manifest concept,
not host-derivable) and drives[].restic_repo_coord (named a backup tier that doesn't
exist). Drive shape is now {durable_id, mount_path, intent, fs_type?, total_bytes}.
Hub reads drives as json.RawMessage → no hub struct change; goldens re-pinned
byte-identical (agent + hub copies).
Tests: live_reporter_test.go (T1 load-bearing coord-without-verify + T2..T6),
TestDRRecipeHostHalf_V1DriveShape; each companion demonstrated to fail pre-fix then
reverted. go build/vet/test green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,44 @@
|
||||
All notable changes to **felhom-agent** are recorded here. Update on every code
|
||||
change that gets pushed.
|
||||
|
||||
## v0.39.0 — DR recipe completion: live PBS coord + drop the two unfillable drive fields (2026-06-16)
|
||||
|
||||
**DR-recipe agent-half completion.** A live eyeball of the demo recipe (v0.38.0) found three host-half
|
||||
problems; all three are resolved here. No behavior change outside the recipe path.
|
||||
|
||||
- **PBS coord now resolved LIVE each collect.** New `internal/pbs/live_reporter.go` —
|
||||
`LiveSnapshotReporter` implements `hub.PBSReporter` by doing the cheap `Client.Snapshots()` list
|
||||
itself, with **last-known-good fallback**, instead of reading only the verify-loop's `SnapshotStore`.
|
||||
Previously the recipe's `pbs` block was omitted whenever the store was empty — which a one-shot
|
||||
collect (`--selftest=hub`) and the first ~6 h window of every daemon after a restart always saw (the
|
||||
verify loop populates the store on its own 6 h cadence). The restore SOURCE must not depend on a
|
||||
maintenance cadence. Per-datastore: a live error/timeout → that datastore's last-known-good; a
|
||||
successful (even empty) response is authoritative and updates the shared store. Targets-resolution
|
||||
failure → the full LKG aggregate. Bounded by `DefaultLiveSnapshotTimeout` (8 s) so a hung PBS never
|
||||
stalls the heartbeat. List only — it never triggers a `Verify`. The verify loop keeps Recording into
|
||||
the SAME store (shared last-known-good); both use one hoisted `pbsTargets` closure.
|
||||
- `SnapshotStore.Get(datastore)` added (per-datastore LKG copy) — the only `SnapshotStore` change.
|
||||
- Wired into the collector in BOTH `runDaemon` and `runSelftestHub` (the selftest built its own
|
||||
collector with a `nil` reporter — that is why the live `--selftest=hub` showed `pbs_snapshots:[]`).
|
||||
- Intended side effect: `report.pbs_snapshots` is now live too (fresher hub PBS view).
|
||||
- **`drives[].role` DROPPED from the v1 host-half shape.** A drive's purpose is a hub/operator-owned
|
||||
manifest concept, not cleanly derivable host-side (both demo externals are `content=backup`, yet one
|
||||
is the primary data drive and the other holds no apps). Deferred until the hub/operator stamps it.
|
||||
- **`drives[].restic_repo_coord` DROPPED from the v1 host-half shape.** It named a backup tier that does
|
||||
not exist — cross-drive backup is rsync to the SAME internal SSD; there is no offsite/second-failure-
|
||||
domain bulk copy. RESERVED for a future tier (see the BACKLOG note in REPORT). v1 drive shape is now
|
||||
`{durable_id, mount_path, intent, fs_type?, total_bytes}` — identifiers/intent/size only.
|
||||
- The hub reads drives as `json.RawMessage`, so dropping fields needs NO hub struct change — only
|
||||
golden + test sync. Cross-repo golden (`host-report.golden.json` here + the hub's copy) re-pinned and
|
||||
verified **byte-identical** (sha256 `57f2a5e7…18b2f2b5` — manual checksum-diff discipline): the hub copy
|
||||
previously lacked the `dr_recipe` section entirely; it is now a verbatim copy of the agent golden.
|
||||
- Tests: new `internal/pbs/live_reporter_test.go` (T1 coord-present-without-prior-verify [load-bearing] +
|
||||
inline bare-store companion, T2 error→LKG fallback, T3 success-warms-store, T4 targets-error→aggregate,
|
||||
T5 bounded-by-timeout, T6 empty-success-authoritative); `TestDRRecipeHostHalf_V1DriveShape` (drive
|
||||
object carries neither `role` nor `restic_repo_coord`); `TestBuildDRRecipeHostHalf` /
|
||||
`TestHostReport_ContractMatchesGolden` updated to the v1 drive shape. Each companion was demonstrated
|
||||
to FAIL on the pre-fix/mutated code, then reverted (see REPORT).
|
||||
|
||||
## v0.38.0 — DR recipe: emit the secret-free storage/guest/PBS half in the host-report (2026-06-16)
|
||||
|
||||
**DR recipe slice (agent half).** Additive `dr_recipe` section on the host-report — the agent half of the
|
||||
|
||||
Reference in New Issue
Block a user