R-109 + R-122: the recipe assembly stops dropping sections (hub v0.83.0)
AssembleDRRecipe's hostHalfShape/appHalfShape are ALLOW-LISTS, not the forward-compat their comment advertised: a section an emitter adds is silently discarded until it is named in both the shape struct and AssembledRecipe. No error, no log, no failing test. R-122 (found this session): that already happened and shipped. The controller has emitted offsite_restic since fork-4 — the offsite recovery LOCATION — the hub stored it for all three real customers, and appHalfShape never listed the key, so no delivered recipe has ever contained it. It stayed green because the fixture drAppHalf is hand-written and omits the field. R-109: the agent's new backup_target is a new top-level host-half section and would have been dropped identically, making the fix read as shipped while changing nothing an operator can see. 3 tests built on halves read verbatim out of the live dr_recipe table, plus 2 red-proofs (each mutation asserted to have landed). vet rc=0, suite rc=0, 17 ok. Registers: R-106 + R-109 dispositioned; R-105/R-106 were READY in ROADMAP with no OPEN-ITEMS row (→ R-123, registered); R-124 filed on the "root" spelling.
This commit is contained in:
@@ -1,3 +1,47 @@
|
||||
## v0.83.0 — R-109 + R-122: the recipe assembly stops dropping sections (2026-07-30)
|
||||
|
||||
Pairs with **agent v0.118.0** (R-106 + R-109). The agent half is useless without this one.
|
||||
|
||||
**`AssembleDRRecipe`'s two shape structs are ALLOW-LISTS, and nobody had noticed.** The doc comment sold
|
||||
`hostHalfShape`/`appHalfShape` as forward-compat — "encoding/json drops any unknown top-level key" — which
|
||||
is true and is also the trap: a section an emitter adds is **silently discarded** until it is named in both
|
||||
the shape struct and `AssembledRecipe`. No error, no log, no failing test. The section is simply not in the
|
||||
file the operator downloads.
|
||||
|
||||
**R-122 (found this session) — that already happened, and it shipped.** The controller has emitted
|
||||
`offsite_restic` since fork-4 — the offsite restic repo's non-secret coordinates, whose entire purpose is
|
||||
"so DR knows WHERE to recover from". The hub stored it intact for **every real customer**
|
||||
(`peti-felhom`, `demo-felhom`, `demo-hp` all carry it in `dr_recipe.app_half_json` today) and `appHalfShape`
|
||||
never listed the key, so no delivered recipe has ever contained it. Verified both ways before the fix: the
|
||||
stored half has it, `GET /customers/demo-felhom/dr-recipe.json` did not.
|
||||
|
||||
**R-109 — and it would have happened again the same day.** The agent's new `backup_target` (which storage
|
||||
holds the local whole-guest archives) is a new top-level host-half section. Without this commit it would
|
||||
have been stored and dropped exactly like `offsite_restic`, and the R-109 fix would have read as shipped
|
||||
while changing nothing an operator can see.
|
||||
|
||||
Both keys are now on `hostHalfShape` / `appHalfShape` / `AssembledRecipe`, and the allow-list comment says
|
||||
what it actually is, plus the rule: **adding a recipe section is a TWO-REPO change.**
|
||||
|
||||
Tests: 3 new, all consequence-level and all built on the halves production **really stores** — read verbatim
|
||||
out of the hub's own `dr_recipe` table (the pre-existing `drHostHalf`/`drAppHalf` constants are hand-written
|
||||
and OMITTED `offsite_restic`, which is precisely why the drop stayed green for the feature's whole life).
|
||||
`TestAssembleDRRecipe_CarriesEveryEmittedSection` enumerates every section both emitters produce and fails
|
||||
on any that does not survive assembly — the guard the allow-list needed and never had.
|
||||
`..._NamesTheLiveBackupTargetAmongTwoCandidates` asserts the delivered recipe names `felhom-backup` at
|
||||
`/mnt/hdd_1` and not the frozen `local`, and refuses to run if the fixture stops posing that problem.
|
||||
`..._UnknownBackupTargetSurvivesVerbatim` pins that the agent's explicit unknown reaches the operator AS an
|
||||
unknown and does not acquire a `storage_id` on the way through.
|
||||
|
||||
Red-proofs: 2, each mutation asserted to have landed before running — drop `offsite_restic` from the
|
||||
allow-list (the R-122 defect restored) → 2 tests fail; drop `backup_target` → 4 fail, naming the section.
|
||||
`go build` + `go vet` rc=0; suite rc=0, 17 packages, 0 FAIL.
|
||||
|
||||
- `internal/store/dr_recipe.go` — `backup_target` + `offsite_restic` on both the shape structs and
|
||||
`AssembledRecipe`; the allow-list warning.
|
||||
- `internal/store/testdata/dr-recipe.golden.json` — both new sections + `namespace_state`.
|
||||
- `internal/api/testdata/host-report.golden.json` — synced byte-identical with the agent's copy (`f4bc3554…`).
|
||||
|
||||
## v0.82.0 — R-120: the vouch path refuses a golden the fleet has already outrun (2026-07-30)
|
||||
|
||||
**The mechanism half of R-120.** The golden's version *is* the controller it bakes
|
||||
|
||||
Reference in New Issue
Block a user