# REPORT — R-204 item 4 (controller v0.199.0), 2026-08-05 **A rebuilt box declares that it needs a credential.** The box half of the last manual intervention the 2026-08-04 drill needed. Hub half: `felhom.eu` v0.96.0, reported in that repo's `REPORT-r204-item4.md`. ## 1. Baselines `felhom-controller` at `68f195676b91` / v0.198.0 — **exact match**, tree clean, `HEAD == origin/main`. §4's landmarks held: `backup.OffboxReportStatus` returned `nil` when no target existed (the ambiguity), and the ACK's `escrow` object was discarded on an unconfigured box because `EscrowAutoConfirmer.Reconcile` returns early when the box is neither pending nor escrowed. **Register drift worth flagging:** the task states R-204 is the highest ID in use. It is **R-211**; grepped before minting, and the hub session mints R-212. ## 2. What changed **The ACK field stopped being discarded.** `RecordPresence` is called FIRST in `Reconcile`, before every gate. It lives in the auto-confirmer because that is already the one place the ACK escrow object arrives and is already wired — a second consumer would be a second wiring point, and this project's built-but-never-wired count is six. Last-write-wins, not set-only, so a customer RESET turns the declaration back off; a nil ACK escrow records nothing (absence of a statement is not a statement of absence); a record failure is logged and does not block the auto-confirm. **The declaration needs BOTH halves** (`needsOffsiteCredential`): a fresh data area (no repository password) AND a hub-held recovery package. Freshness alone is a box that never had off-site backups — declaring on it would make every un-configured box in the fleet ask for a credential. A merely DISABLED target is the customer's own choice and never declares. **Inert to every existing reader**, established from the hub's code: `enabled:false` + zero sizes, so `isStale` short-circuits on `!Enabled` and `fillBand` returns OK on a zero quota/size; an unknown `state` string is ignored by `encoding/json`. **A configured box's JSON is byte-identical to v0.198.0's.** The one reader that would have misread it is the hub's `reportHasOffsite`, tightened in hub v0.96.0. ## 3. Files modified | File | Change | |---|---| | `controller/internal/settings/settings.go` | **new** `HubEscrowIdentityPresent` field + accessors (saves only on a change) | | `controller/internal/report/escrow_confirm.go` | **new** `RecordPresence` seam, called before every gate | | `controller/internal/backup/offbox.go` | **new** `OffsiteStateNeedsCredential`, `needsOffsiteCredential`; `State` on the report object | | `controller/cmd/controller/main.go` | wires `RecordPresence` | | `controller/internal/backup/offbox_declare_test.go` | **new** — Scenarios A and B + the two exclusions + the byte-compat assertion | | `controller/internal/report/escrow_presence{,_wiring}_test.go` | **new** — the recorder and its AST wiring test | | `.githooks/pre-push` | the workspace-root assertion (rider) | **Commits on `main`:** `1214bae` (the declaration) · `a91f055` (rider) · `992803c` (CHANGELOG). **Deployed:** `felhom-controller:0.199.0` on demo-felhom 9201 and demo-hp 9201, both healthy. ## 4. Tests and red-proofs Green gate: `go build ./... && go vet ./... && go test ./...` — **rc=0**. `python3 controller/scripts/controller_gates.py --fast` — **all eight gates OK**. | Scenario | Test | Result | Red-proof — what was mutated | Outcome | |---|---|---|---|---| | A | `TestOffsiteDeclare_RebuiltBoxDeclaresNeedsCredential` | PASS | dropped the escrow condition from `needsOffsiteCredential` | **Scenario B FAILED** — *"a box that never had off-site backups DECLARED a need… every un-configured box in the fleet would now ask for a credential"*. This is the plausible wrong fix, and B is the guard that catches it. | | B | `TestOffsiteDeclare_NeverHadOffsiteSaysNothing` | PASS | (as above) | **FAILED** | | — | `TestOffsiteDeclare_BoxThatStillHoldsItsRepoPasswordDoesNotDeclare` | PASS | — | — | | — | `TestOffsiteDeclare_DisabledTargetIsNotStranded` | PASS | — | — | | — | `TestOffsiteDeclare_ConfiguredBoxJSONIsUnchanged` | PASS | — | — | | — | `TestEscrowConfirm_RecordsPresenceEvenWhenOffboxUnconfigured` (+ nil-ACK, record-failure) | PASS | — | — | | seam | `TestMainWiresRecordPresence` | PASS | commented out `RecordPresence:` in main.go | **FAILED** — *"EscrowAutoConfirmer is constructed WITHOUT RecordPresence — R-204 item 4 ships inert"* | ## 5. Live validation 1. **The recorder works on a HEALTHY box** — the case that used to return early. Both demo boxes now carry `hub_escrow_identity_present = true` in `settings.json`. 2. **The declaration, produced live without wiping a box.** demo-felhom 9201 was arranged **reversibly** into the stranded shape (settings + `offbox/` backed up first). The hub received report **id=16743**: `{"enabled":false,"escrow_state":"","state":"needs_credential", "snapshot_count":0,"repo_size_bytes":0,"quota_gb":0}`. Restored the same minute — report id=16744 is healthy. **The single declaration was absorbed by the hub's debounce; no self-heal event fired.** 3. **A push from outside the workspace is refused**, naming the expected root, before the gates run; with the assertion removed the same push succeeds. Both directions demonstrated. 4. **Part 4 (the deletion) HALTED at its STOP** — the measured paths do not match the register. See `felhom.eu/REPORT-r204-item4.md` §8 and R-212. **Teardown:** demo-felhom restored and verified (`enabled=True`, `escrow_state=escrowed`, `repo_password present=True`); the pre-change backup remains at `/root/r204-backup` on that guest. Scratch clones removed. Nothing provisioned. ## 6. CI and hooks **`--no-verify` was NOT used.** Every push ran the pre-push gate, including the new workspace-root assertion. CI runs were confirmed green by head_sha for each push. ## 7. Observations — noticed, NOT acted on - The workspace-root assertion is per-clone like the rest of the hook, so it binds only an armed clone; CI remains the half that is neither per-clone nor skippable (R-168). - `felhom-agent`'s `reuse-refs` gate incidentally also fails outside the workspace (the shared checker lives in the `felhom.eu` sibling). Repo-specific and not a substitute for the assertion.