docs for v0.206.0: CHANGELOG, CONTEXT, REUSE, README
gates / gates (push) Successful in 19s

CHANGELOG v0.206.0 with the ruling that reversed the fix, the three changes,
the SEC 7.2 staleness decision, Q7's closed trap, and the two bugs the tests
caught rather than review.

CONTEXT carries the three rules this session established, in the form the next
session needs them:
  - a box does not create a repository key while the hub holds a sealed
    package for it;
  - the fact that answers a question must be kept where the question is asked;
  - fix the state, do not remember that it is wrong.

REUSE gains four rows, each carrying the trap rather than just the signature:
the mint guard is a CONJUNCTION and t.Enabled is load-bearing in the derived
predicate; the discriminator ships INERT unless wired in main.go's confirmer
literal; the countdown removes BOTH halves or neither and must be driven by an
injected clock; and the epoch must be synced FIRST and unconditionally or the
falling edge is lost.

README documents the three customer-visible changes and the operator levers.

No version literal was edited: the controller version is ldflags-only.
This commit is contained in:
2026-08-07 12:12:35 +02:00
parent 72368654e4
commit 0a9158d53e
4 changed files with 145 additions and 1 deletions
+81
View File
@@ -1,3 +1,84 @@
## v0.206.0 — the box does not mint a key over a sealed package, and abandoning ends the question (2026-08-07, R-241) — MinAgent 0.127.0
**R-241 was ruled a MINTING defect, not a screen-predicate defect** (`SPIKE-r241-recovery-offer-2026-08-07.md`),
and that reversed the fix. The recovery screen was telling the truth: there genuinely was nothing
recoverable under the key the box held, **because the box minted that key itself, over the top of a
sealed package it already knew the hub was holding.** Mending the screen would have papered over a
machine quietly making its own backups unopenable.
### 1. It stops minting
`WriteOffboxSecrets` auto-generated on **one** input — does the file exist. Its two neighbours in the
same file, `OffsiteRecoveryOffer` and `needsOffsiteCredential`, both consult
`GetHubEscrowIdentityPresent()`. **The same fact was available on three paths and used on two.**
Measured on the final walk: the credential self-heal reached it at 03:18:06Z and minted `9b4a9a9d…`
over a package sealing `30ef574f…`. The flag was not merely available at that moment — it was the
**precondition of the chain that reached the function**, logged at 02:48:03Z, six ticks earlier.
The guard is a **conjunction** (a package held AND no key present), so a first-time box mints exactly
as before. The refusal is a **holding state, not a failure**: the transport is still written, so the
recovery screen can bring the tier up the instant the key arrives (R-219). Returning an error instead
would have left the hub re-staging a consumed credential for ever. New declared state
`offsite.state=awaiting_recovery_key`, shown inert to every existing hub reader from their code.
### 2. The comparison it already made now drives the offer
`EscrowAutoConfirmer.Reconcile` has compared the hub's `restic_pw_sha256` against the local key on
every ACK since SLICE 3. On the venue it logged the mismatch at **03:28:03Z — thirty-five minutes
before the customer looked** — and threw it away. It is now persisted, and `OffsiteRecoveryOffer`
gains **shape (c)**: the hub holds a package for a key other than the one we are using.
**§7.2, decided deliberately:** a **known difference offers however old the reading** (age is not
gated on — gating would make a box offline from the hub silently stop offering); a **hash never
learned falls back to (a)/(b)**, because an empty hash is the hub positively saying its package seals
no key, not an unknown.
### 3. Abandoning is now a finishable thing
Setting the old history aside used to touch neither the escrow nor the key, so the hub went on holding
a package for a key nobody used and the question returned at every login. It now starts a **14-day
countdown**, visible and reversible, at the end of which the set-aside store **and the sealed package
that protects it are removed together** — after which shape (c) has nothing to compare and the offer
falls silent **because the state is right, not because something remembers it once was not**.
The grace is real: the recovery offer stays reachable throughout. The two halves cannot be atomic
across two machines, so it is a two-phase commit whose confirmation rides the **same ACK** that
carries the request. Needs hub **v0.98.0**.
### 4. The surface, and the trap that does not survive this session
The full page appears **once per entry into the offered state, not once ever** (an epoch, so a box
rebuilt months later is a new situation). Three dismissal levers with three scopes — a per-visit
session cookie, a durable epoch-scoped reminder opt-out, and the existing "most nem" — and **none of
them removes the entry point on the backups page.**
**§7.3 / Q7:** while a recovery is outstanding, „Helyreállítási kód létrehozása" is now **unavailable**
rather than merely captioned. Creating a new code seals the current key, demotes the package that
opens the earlier history to retained custody no shipped path can read (R-199), and re-enables the
screen while invalidating the code it accepts. A warning beside a button is a warning people click
past.
**The abandon confirmation changed with the behaviour (§2.4):** it used to promise *„félretesszük —
nem töröljük"*, and after this the history **is** deleted, on a date it now states.
### 5. Reminders and operator levers
Escalating emphasis at 1/3/7/14 days for an undecided box, 5/3/1 days remaining for an abandoning one.
`--abandon-status` / `--abandon-extend=N` / `--abandon-stop` on the controller CLI, because the path
that actually happens is the customer telephoning. Both levers **refuse rather than no-op** when
nothing is running or the store is already gone.
**The automatic 30-day abandonment is recorded and NOT built** → R-245.
### Caught by tests rather than review
Two real bugs in this change: `OffboxAwaitingRecoveryKey` omitted `t.Enabled`, so a customer who had
switched off-site off would have declared a holding state (caught by the existing
`TestOffsiteDeclare_DisabledTargetIsNotStranded`); and `recoveryInterrupts` returned early when the
offer was false, so the **falling** edge was never recorded and the page never came back — the exact
defect the epoch exists to fix, reintroduced inside the fix.
## v0.205.0 — a backup that skipped an app the customer chose is not „Rendben" (2026-08-06, R-234) — MinAgent 0.127.0
**Two defects, and the one that actually produced the measured sequence was NOT the one filed.**