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:
@@ -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.**
|
||||
|
||||
Reference in New Issue
Block a user