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

96 lines
6.2 KiB
Markdown

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