3.0 KiB
REPORT — controller v0.197.0: R-203, both halves (2026-08-04)
Deployed to demo-hp guest 9201. No hub change. Nothing deleted, wiped or moved; the R-201 drill was not resumed.
What shipped
Part 1 — one resolver, five callers. appbackup.NamespaceRootFor / IsEnrolledDrive are now the
single expression of the drive-kind rule; backup.Manager.namespaceRoot and stacks.Manager.inGuest
delegate (they were two copies that already differed over filepath.Clean). Routed through it:
stacks/deploy.go withPathVars (the live defect), appexport/fabplan.go + export.go via a new
GetStackNamespaceRoot provider method, web/handlers.go's FileBrowser mounts (the fifth site, which
the spec did not name — latent today), and stacks/delete.go's ExportDataMounts (its own commit).
ComputeFabBuckets now receives the namespace root, matching ComputeCaptureSet.
Part 2 — the verdict. last_status gains incomplete; the capture gaps are recorded structurally
so the verdict has something to act on; the operator hears it through the existing per-run digest.
Proven live on demo-hp
bind before: /mnt/sys_drive/userdata/media/books
bind after: /mnt/sys_drive/felhom-data/userdata/media/books
capture log: 0 mandatory path(s) -> 1 mandatory path(s)
$ restic ls -l latest --tag calibre-web
-rw-r--r-- 1000 1000 181 2026-08-04 12:53:06 .../media/books/DRILL-SENTINEL.txt
The file, by name and size, inside the snapshot — not a green status.
Tests
go build && go vet && go test ./... rc=0; controller_gates.py --fast OK. Table-driven over BOTH
drive kinds, because this defect survived by being invisible on the kind that already worked.
One red-proof PASSED and the test was wrong, not the code: the first Scenario-C test reached only
offboxCaptureSet while the mutation lives in runOffboxInternal. Replaced with a run-level test
driving RunOffboxBackup; it now fails under both an unreachable gap-recording and an unconditional
ok. Scenario D's proof also could not fail by construction (the tier filter already excludes
optional paths) — the two-part mutation that does is recorded.
Corrections to the spec
- Five call sites, not four. The fifth is the FileBrowser mount builder.
ExportDataMountsis export-only despite living indelete.go. Its only caller is the.fabadapter, and the delete path's ownProtectedHDDPathsguard is layout-agnostic by construction, so the destructive-path risk the spec flagged does not exist.
Observations
resolveAbs resolves RootHDD and RootUserdata against one root — fine on enrolled drives, and now
consistent between export and backup, but whether ${HDD_PATH} should mean the namespace root on the
system drive is a separate decision affecting every deployed app. The deploy API is
first-deployment-only (409 after), so an existing app picks up the corrected path via start/redeploy.
The CSRF form field is _csrf, not csrf_token — second session running that this cost time.