CHANGELOG: hub v0.95.0 (R-196 / R-204 item 2)
gates / gates (push) Successful in 7s

This commit is contained in:
2026-08-05 07:17:37 +02:00
parent d1a8edb332
commit 5c7d67102d
+52
View File
@@ -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 `<DataDir>/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