Files
felhom.eu/REPORT-r106-r109-recipe-completeness.md
T
admin acfc2b7e95 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.
2026-07-30 13:13:56 +02:00

6.4 KiB

REPORT — R-106 + R-109 (+ R-122): closing the recipe-completeness set (2026-07-30)

Non-overwritten sibling per CLAUDE.md:82-87 — the shared REPORT.md holds R-117 and is not touched.

Shipped: agent v0.118.0 (felhom-agent 1c8a67e) + hub v0.83.0. Neither half is useful alone.

Part 0 — the answers, before the fix

0.1 Which items are actually open, and R-105/R-106's registration

OPEN-ITEMS.md calls itself "the single source of truth for open work" (:1), with ROADMAP.md keeping "the full history and reasoning" (:3-4).

item ROADMAP.md OPEN-ITEMS.md verdict
R-105 row, READY — 2026-07-28 (:108) absent open but UNREGISTERED
R-106 row, READY — 2026-07-28 (:109) absent open but UNREGISTERED
R-108 row (:111) row (:50) registered
R-109 row (:112) row (:61) registered

So R-109's own cell — "third recipe-completeness defect beside R-105/R-106" — was the only place in the register naming two open items. That is exactly the thread-loss the register exists to prevent, and it is itself a finding (filed R-123). Both now have rows.

The set this task closes is R-106 + R-109, matching the arc's stated definition of done (OPEN-ITEMS.md:14). R-105 is NOT in it and was not worked: it is M-sized and is about three hub-held DR records being {} (hosts.dr_record_json, host_escrow.directive_json, and the drives third — already traced and populated by the 2026-07-28 target move). Different fields, different owner, different size.

0.2 Where the recipe is generated — three producers, not two

half repo function
host (guests/pbs/drives/pve_storage) felhom-agent BuildDRRecipeHostHalf, internal/hub/dr_recipe.go:86
app (customer/apps/offsite_restic) felhom-controller controller/internal/report/dr_recipe.go
assembly + delivery felhom.eu/hub AssembleDRRecipe, internal/store/dr_recipe.go:104; served by handleDRRecipeDownload, internal/web/dr_recipe.go:14, route internal/web/server.go:439

R-109's "host-half" is therefore the agent, and the field must also pass the hub's allow-list — see §2.

0.3 What the namespace field actually contained — verified, and the brief was RIGHT

The eleven-session-old brief held up. Live, pre-fix, from the hub for both boxes:

"pbs": { "repo_id": "felhom-pbs", "namespace": "root", "latest_snapshot_id": "9201" }

against /etc/pve/storage.cfg on the same boxes:

pbs: felhom-pbs
        datastore felhom-offsite
        namespace demo-felhom          # demo-hp reads: namespace demo-hp

Traced to source: Snapshot.Namespace decodes ns (internal/pbs/client.go:97), which PBS does not echo per item once the list is namespace-scoped via ?ns= (:118-120) → always empty → ToHub normalises empty to "root" (internal/pbs/report.go:22-25) → latestPBSCoord writes it in.

The authority taken, and why: storage.cfg's namespace on the pbs storage. It is the same field vzdump --storage <pbs> makes PVE read, and the agent's own verify client is built from it (cmd/felhom-agent/main.go:1164). Deriving the recipe from anything else is how it drifts again.

1. R-109's ambiguity is real, in the boxes' own pre-fix recipe

"pve_storage": [
  { "name": "local-lvm",     "type": "lvmthin",   "content": "images,rootdir" },
  { "name": "felhom-backup", "type": "local-dir", "content": "backup" },
  { "name": "felhom-pbs",    "type": "pbs",       "content": "backup" },
  { "name": "local",         "type": "local",     "content": "backup,import,vztmpl,iso" }
]

No backup_target key anywhere. felhom-backup (live, /mnt/hdd_1) and local (/var/lib/vz, archives frozen 2026-07-28) are both content=backup dir storages; local is also the historically correct answer, which is what makes guessing it so easy.

2. R-122 — a fourth defect, found here, and it had already shipped

AssembleDRRecipe's hostHalfShape/appHalfShape are allow-lists dressed as forward-compat. The controller has emitted offsite_restic since fork-4 (controller/internal/report/dr_recipe.go:39-41, "so DR knows WHERE to recover from"); appHalfShape never listed the key. Verified both ways:

  • stored: dr_recipe.app_half_json carries it for all three real customers — peti-felhom, demo-felhom (u629488-sub1.your-storagebox.de:23/home/felhom-repo), demo-hp.
  • delivered: the downloaded recipe's top-level keys were recipe_version, customer, guests, pbs, drives, pve_storage, appsno offsite_restic.

So a restorer reading the recipe had no offsite location at all, for the whole life of the feature, with a green suite throughout — because the test fixture drAppHalf is hand-written and omits the field.

Deviation from the task's §7.10 ("Findings — filed as R-n, none fixed"), stated rather than absorbed: I fixed it. Reasons — (a) Part 0 authorises working the real set if it differs; (b) it is the same symptom the task is named for (the recipe is incomplete), and the worst instance, a whole section missing; (c) it is in the same two structs R-109 forced me to edit, and leaving one of three known keys off a drop-list I was already correcting would be indefensible. It is filed as R-122 with a SHIPPED disposition.

3. The before/after recipe — same box, quoted

Full text in documentation/audits/R106-R109-recipe-completeness-2026-07-30.md §5.

4. Findings filed (none of them fixed except R-122, see §2)

id finding
R-122 AssembleDRRecipe allow-list dropped offsite_restic for the feature's whole life — FIXED here, hub v0.83.0
R-123 R-105 and R-106 were READY in ROADMAP.md with no OPEN-ITEMS.md row — referenced only inside R-109's prose. Registered here
R-124 The recipe spells PBS's root namespace "root", but the PBS API spells it "" and there is no namespace literally named root — a restorer pasting it into pct restore --ns root would fail. Pre-existing wire convention, deliberately unchanged; documented at PBSRootNamespace

5. Not done, and why

  • R-105, R-108, D5 — out of scope by the task's §6. R-108 blocks D5; starting either would leave both half-done.
  • The backup machinery — untouched. This corrects the record, not the doing.
  • demo-felhom's agent was not upgraded past what the deploy step covers — see the audit §6.