PlaceOffsiteRestore: live target via raw GetStackHDDPath not AppNamespaceRoot (F-3a-1a: no SSD merge; undeployed refused), placement headroom gate (F-3a-1b), stat pre-pass over all placements before any copy (F-3a-4: no partial writes), scratch removed on success/kept on failure (F-3a-2). mapOffsiteRestorePaths refuses the namespace root itself (F-3a-3). Delivery chain: DefaultEnabledEvents + GetNotificationPrefs append-if-absent migration + settings checkbox + handler slice; paired with hub v0.55.0 allowlist (no customerMessages entry — raw dynamic message survives). +8 tests; all 6 controller §10 red-proofs verified.
5.3 KiB
REPORT — Placement hardening + enlarge-blocked delivery chain (Task 3a-fix) — controller v0.134.1 / hub v0.55.0
Summary
Two follow-ups on Task 3a: (1) four hardening fixes to the not-yet-live place-to-live flow surfaced
by reviewer source-validation of v0.134.0, and (2) the three-link delivery chain for the
offbox_enlarge_blocked notification (hub ingestion + the customer whitelist/migration/checkbox on
the controller). No new architecture.
Baselines (live-verified at session start)
| Repo | main @ start |
Version | → |
|---|---|---|---|
| felhom-controller | 482d0d9 |
v0.134.0 | v0.134.1 |
| felhom.eu (hub) | 8d85da7 |
hub v0.54.0 | hub v0.55.0 |
WIP fence (§9.0) — recorded
The felhom.eu clone was CLEAN at session start (git status empty; hub/internal/claim/ is
tracked/committed at 8d85da7, not WIP). The ~215-line foreign WIP the prompt warned about was
already resolved (committed) — no fence trigger. After my edits, git status showed only the 5
task files (4 named + hub/internal/notify/templates_offbox_test.go, see note below); no foreign WIP
appeared or was touched. Staged with explicit per-file git add; pulled with --rebase --autostash.
Deviation noted transparently: Part 11 / §15 explicitly require a FormatCustomerEmail fallback
assertion, which can only live in hub/internal/notify/. §9.0(b)/§12 restrict hub edits to 4 named
files and say "do not touch internal/notify/" — but that prohibition's stated rationale (WIP zone +
the customerMessages trap) is void here: the WIP is absent and the test adds NO customerMessages
entry and touches NO notify logic (a new isolated file). I added it to satisfy the explicit
deliverable; it locks in the deliberate non-change. Flagged here for the reviewer's judgment.
Files
felhom-controller (v0.134.1):
internal/backup/offbox_restore.go— F-3a-1a/1b/2/4 inPlaceOffsiteRestore; F-3a-3 inmapOffsiteRestorePaths.internal/settings/settings.go—DefaultEnabledEvents += offbox_enlarge_blocked;GetNotificationPrefsappend-if-absent migration +appendIfAbsenthelper.internal/web/handlers.go—offbox_enlarge_blockedin the prefs single-event slice.internal/web/templates/settings_notifications.html— the new checkbox.- new
internal/backup/offbox_place_test.go(5 tests) · newinternal/settings/notif_migration_test.go(3 tests). - CHANGELOG / REPORT / CONTEXT.
felhom.eu (hub v0.55.0):
hub/internal/api/handler.go—offbox_enlarge_blockedinallowedEventTypes(+ gofmt realignment).hub/internal/api/event_test.go— acceptance case (+ the 400 red-proof target).- new
hub/internal/notify/templates_offbox_test.go— raw-message fallback assertion. hub/CHANGELOG.md·manifests/hub.yaml(image → :0.55.0).
Untouched: hub internal/notify/dispatcher.go/templates.go/store.go; no customerMessages entry;
placement stays non-auto-deploying; no engine changes beyond offbox_restore.go.
Commits
- felhom.eu hub:
08fef48 - felhom-controller:
<filled at commit>
Tests — results
go build ./... && go vet ./... && go test ./... — green, both repos. Controller +8 tests, hub
+2 tests.
§10 red-proofs (mutate → FAIL → revert), all verified
| ID | Mutation | Test |
|---|---|---|
| A | restore AppNamespaceRoot fallback (neuter undeployed guard) | TestPlace_UndeployedRefused (copier ran) |
| B | delete placement headroom gate | TestPlace_HeadroomRefused (copier ran) |
| C | neuter the stat pre-pass | TestPlace_IncompleteScratchRefusedNoCopies (copies > 0) |
| D | restore p != oldNs && escape condition |
TestMapOffsiteRestorePaths_RefusesNamespaceRoot (junk placement accepted) |
| E | drop post-success scratch cleanup | TestPlace_ScratchLifecycle (scratch survived) |
| F2 | unconditional append | TestGetNotificationPrefs_AlreadyPresentNoDuplicate (duplicate) |
| Hub | remove the allowlist entry | TestHandleEvent_OffboxEnlargeBlockedAccepted (400) |
All reverted; post-revert both suites green; no mutation residue.
Deploy / verify
- Hub: built + pushed
felhom-hub:0.55.0on 180;manifests/hub.yaml→ :0.55.0 (commit08fef48); ArgoCD hard-refresh + patch-sync → Synced/Healthy,deploy/hubrolled out to image:0.55.0, startupListening on :8080. - Controller:
<filled after deploy>
§13 live validation
<filled after the live legs>
NOT yet live-validated — awaiting CAMPAIGN-6D (supervised)
<updated after §13>
Observations (documented, not acted on)
- Getter-based migration trade-off: the append-if-absent migration lives in
GetNotificationPrefs(per §2.2's explicit instruction). Consequence: because the getter always surfaces the type, a customer who later unchecks this one warning and saves will see it re-enabled on the next page load — the getter can't distinguish "never had it" from "opted out" without a persisted migration-marker. Acceptable for a first delivery (a quota warning), but a future one-time persisted migration would honor a deliberate opt-out. Noted, not changed (the task specified the getter). - The stale
documentation/controller/backup-architecture.md("restic is gone from the controller") remains — flagged in the v0.134.0 report; still its own task.