From 5c7d67102d908819631ed45e5ffe084e0c3d565f Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Wed, 5 Aug 2026 07:17:37 +0200 Subject: [PATCH] CHANGELOG: hub v0.95.0 (R-196 / R-204 item 2) --- hub/CHANGELOG.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/hub/CHANGELOG.md b/hub/CHANGELOG.md index 030ba57..2ef4b74 100644 --- a/hub/CHANGELOG.md +++ b/hub/CHANGELOG.md @@ -1,3 +1,55 @@ +## v0.95.0 — a re-issue no longer marks a healthy escrow stale (2026-08-05, R-196 / R-204 item 2) + +`ReissueCredentials` called `MarkEscrowStale` on every re-issue that found an escrow row. The mark was +**precautionary, not evidential**: it guessed that the box's re-apply MIGHT mint a fresh repository +password. On the ordinary re-issue shape — a box that still holds its `/offbox/repo_password` +— the password does not change, so it marked a HEALTHY escrow stale. The 2026-08-04 recovery drill +(R-201) is what promoted this from a nit to a blocker. + +**What the mark actually did**, because "asks for an unnecessary ceremony" understates it: + +1. `stale_at` set → `GetEscrowStatusForCustomer` WITHHOLDS `restic_pw_sha256` from the report ACK. +2. With no hash, the controller's SLICE-3 auto-confirm cannot flip pending→escrowed. +3. `OffboxRunnable() = OffboxConfigured() && EscrowState=="escrowed"` → **every off-site backup + refused, indefinitely**, on a box whose key was never in doubt. +4. The customer is told to re-run the recovery ceremony — which mints a new recovery code and + supersedes the sealed blob. During a recovery that is the one act that would have destroyed the key + just recovered. + +A precautionary flag that stops the data protection it is guarding is not conservative. + +**Removing it leaves no gap — the case it guessed at is measured elsewhere, and better.** + +- **Continuous, box-side:** the controller compares the ACK's sealed hash against its CURRENT local repo + password on every report ACK (`report.EscrowAutoConfirmer.reconcileEscrowed`, the Scenario-F + re-check). In the guest-rebuild shape — the only shape where a re-issue is followed by a fresh + repository password — that mismatches within one report cycle and raises the stale card plus the + „create a new recovery code" CTA. Pinned by the controller's `TestEscrowStale_MismatchWarnsOnceAndFlags`. + **And the mark was BLINDING it:** by emptying the hash (step 1) it removed the very value that + comparison needs, leaving the box able to report only the hash-LESS reason, which is false. +- **Edge-triggered, hub-side:** R-197's `offsite_repo_key_changed` fires on a proven hash difference + across a supersession and pages the operator. Pinned by `TestEscrowPut_ChangedRepoKey_RaisesSignal`; + red-proved by removing the `maybeEmitRepoKeyChanged` call. + +`offsite_reissued` is unchanged and still always fires — the customer must still learn that the +credential moved. Only the stale marking and its `escrow_stale` event are gone. + +**`MarkEscrowStale` is kept, not deleted, and now has no caller** — deliberately. The `stale_at` flag +is still live and correct (read by the ACK, the operator card and the PBS-DR view); the right way to +set it is a future caller that has MEASURED a key change rather than guessed at one. Its doc now says +so, and `TestEscrowStaleMechanism_StillWithholdsAndClears` keeps the mechanism from decaying while +nothing writes it. + +**Disagreement recorded** (the R-96 standing rule): the task's Scenario D asked that a real key change +also "mark the escrow stale". It must not, and nothing was changed to make it — the hub learns of a +real change at the moment a supersession SEALS THE NEW PASSWORD, i.e. when the escrow is freshest. +Marking it stale there would ask for a ceremony to fix the ceremony that just ran. The correct +consequence at that instant is the operator alarm, which is what R-197 already does. + +`TestReissue_InvalidatesEscrow` is replaced in place by `TestReissue_DoesNotMarkAHealthyEscrowStale`, +its exact inverse, so the reversal is visible in `git log -L`. The old test was not wrong about the +effect it measured; it was wrong about the cause, and it pinned the defect. + ## v0.94.0 — a box can fetch its own sealed recovery package (2026-08-04, R-199 link 6) **Chain link 6 had no client.** The hub has served the identity blob since slice 10D, from