Files
felhom-controller/REPORT.md
T
2026-08-05 11:06:19 +02:00

6.2 KiB

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 --fastall 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.