From 7534ea203d6202f6faab08a83f83f06406e4c6b8 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 6 Aug 2026 08:19:07 +0200 Subject: [PATCH] CHANGELOG: controller v0.202.0 (MinAgent 0.126.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declares the coupling: an agent below 0.126.0 answers 400 for both a fetch failure and a wrong code, so FeatureRecoveryFailureClass withholds the refusal reading and the 400 degrades to the neutral message. The gate blocks nothing — it only decides whether the customer may be told to check their typing. --- CHANGELOG.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2719cee..4a788a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,96 @@ +## v0.202.0 — the customer is blamed only after a real attempt refused their code (2026-08-06, R-224/R-226/R-225/R-227/R-228) — MinAgent 0.126.0 + +**CAMPAIGN-11's headline defect had moved, not gone.** v0.201.0 stopped an agent that is too OLD from +being reported as a wrong recovery code. An agent that is **stopped**, and a hub that cannot be +**reached**, still fell through to a message about the code — measured live on 2026-08-05 with a +**correct, current** code at **0.0299 s** and **0.0556 s**, against ~1.0 s for a genuine unseal. The +machine had not tried, and told the customer their code was wrong. + +**And the inverse was true at the same time (R-226).** The one message that says *"check your ten +words"* was tested AFTER the retained-earlier-package message, so on any box that has re-escrowed — +precisely the box whose customer has just been handed a new code — a genuine mistype could never +reach it. Three unrelated failures got the accusation; the one that deserved it got something else. + +**One defect from both ends: nothing on that path asked WHY it failed.** `rerr` was never inspected. + +### The rule, and it is the whole change + +> **The customer is blamed only after a real attempt refused their code. Every other outcome — +> including one we cannot classify — says something else.** + +Five classes, **from the value and never the text**: + +| class | from | what the customer is told | +|---|---|---| +| hub-unreachable | 502/503 | the connection failed; **the code was NOT used** | +| agent-unreachable | no agent verdict at all | the machine's own service is not answering; **NOT used** | +| no-bundle | 404 | nothing is held for this machine; not about the code | +| bundle-too-old | 409 | the code WORKED; the package predates the field | +| **asked-and-refused** | **400** | **the only class that may mention typing** | +| unknown | anything else | **neutral — claims neither that the code was wrong nor that it went unused** | + +`agentapi.RecoveryRefusal` carries the status as a value; `refusalError` flattened it into a sentence, +and a sentence is not something a caller can branch on. + +**THE SAFE DEFAULT IS THE POINT.** `RecoveryUnknown` is the zero value, and an unrecognised status +lands there rather than in an accusation. **That is the rule whose absence let this survive being +fixed once.** + +**Coupling — `MinAgent 0.126.0`.** An agent below it answers **400 for both** a fetch failure and a +wrong code, so a 400 from one cannot be read as a refusal. `FeatureRecoveryFailureClass` withholds +that reading and the 400 degrades to **neutral**. The gate **blocks nothing** — the unlock is +attempted either way — it only decides whether the customer may be told to check their typing, and +"not sure" means they may not. It heals itself when the agent updates. + +**Elapsed time is logged** (it is what diagnosed this, and it is the cheapest tell for the operator) +**and is never the classifier.** Time is a symptom; the status is the fact. + +### R-225 — unknown is not zero + +An unread store rendered `Tároló méret · 0 pillanatkép` and `Tárhelykeret: 0 / 50 GB (0%)` **directly +above a card saying the store held backups under another key**. An SFTP listing found snapshot +`f3d9cd67` and **12 535 KB** really there; `snapshot_count` and `repo_size_bytes` were simply ABSENT +from `settings.json` and the zero value spoke for them. `StatsKnown` is **named**, for the same reason +`OffsiteInventory.Empty` is — zero is what an unread store and an empty one both look like, and both +fields are `omitempty` ints, so on disk "absent" and "0" are the same bytes. The fill bar renders only +when the fill is known: **a 0 %-wide bar is a picture of emptiness, and a picture is a claim.** A +*measured* zero still says zero. + +### R-227 — the gateway error + +**Which layer answers: traefik**, whose config this repo generates. A branded proxy page is therefore +possible here, but traefik v3 serves no static files, so it would need a **new always-up container** +for every 502 on the box — out of proportion to this finding, and **scoped in the report rather than +built**. Shipped instead: the unlock posts via `fetch`, so a gateway failure is answered in Hungarian +without leaving the page. **Progressive enhancement** — with no JS the plain POST is unchanged and +still shows the proxy's error, and this entry says so rather than implying otherwise. + +### R-228 — the set-aside history is visible, and honest + +A customer who chose "I do not want the old data" was told the backups would be **kept**, and the +move-aside did exactly that — 12 535 KB, byte-exact. The box recorded the path in +`orphaned_renamed_to` and **a census found zero references to it in any template or handler.** It is +surfaced now as two facts and stops. + +**It does NOT promise the history can be reopened, and the confirmation copy was corrected for the +same reason.** *"a helyreállítási kód nélkül többé nem lesznek megnyithatók"* implied that **with** +the code they could be; serving a superseded package is an unbuilt link (R-199's inventory), so it +cannot be opened by the customer, the operator, or anyone. The field's own comment called it +*"recovery-code-recoverable"* — the same over-promise, in the code. + +### Tests + +Scenarios A-H at the **handler** and as **render tests per branch of each gate**. Red-proofs, each +demonstrated failing and restored: delete the 502 case (A) - remove the mistype clause (C) - default +to the accusation (D) - route an instant transport failure to the typing message (E) - remove the +`StatsKnown` guards (F) - delete the set-aside block (H). + +**Two existing tests encoded the defect and were corrected rather than deleted.** The web fake +returned a **bare** error for "wrong code" — which is the shape of a failure we cannot classify, and +now correctly renders the neutral message; saying "wrong code" in a test requires saying it the way +the agent says it. And R-222's test forbade **any** mention of typing on a superseded box, **half of +which R-226 deliberately reverses**: what stays forbidden is the bare accusation, not the hint. + ## v0.201.0 — a correct recovery code is never called wrong again (2026-08-05, CAMPAIGN-11) — MinAgent 0.125.0 CAMPAIGN-11 walked the whole recovery journey end to end for the first time. **The data came back