diff --git a/CONTEXT.md b/CONTEXT.md index 72bf06a..82abcb1 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -15,6 +15,30 @@ > would make one of the two audiences stop reading. `STATUS.md` is also a **view of `OPEN-ITEMS.md`** > and holds nothing of its own; this file does hold its own content, namely the standing rulings below. +## A record that lives inside a row about something else has not been recorded + +**Earned 2026-08-10, at a measured cost of two sessions.** Thirty-three package deletions — an +operator-ruled prune, with the keep set asserted first and every delete returning 204 — were written +down inside **R-267, the row about the Configuration page being slow**, because pruning artifacts is +what made that page fast. It was a perfectly good record in a place nobody would look. + +**What it cost.** One session searched the register and reported *"no register row records a package +prune"*. A second exhausted Gitea's router logs, its activity feed and its schema, then concluded the +deleter *"may be unestablishable from this side"*. Both were wrong, and the answer was in +`OPEN-ITEMS.md` throughout. Worse, the second session argued against the prune using an **unpaginated** +package count — the exact trap that same R-267 row documents one paragraph above the sentence it could +not find. + +**Findability is part of recording, not a nicety.** A fact filed under the story of how it was +discovered is filed under the wrong thing. Concretely: + +- **An execution record gets its own row**, even when the execution was incidental to something else. + A row may cross-reference; it may not be the only home. +- **A row about a fix is not the home for the acts the fix required.** +- This is the second measured cost of the register's illegibility in two days, and it is a *different* + failure from the first: prose rows make claims ambiguous, rows-about-other-things make facts + unfindable. Both are in R-288. + ## A check and the policy it enforces must read the same number from the same place **Earned 2026-08-09.** The container registry retains N versions per package; `check-published-versions.py` diff --git a/REPORT.md b/REPORT.md index c4e5f7e..e522d53 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,152 +1,150 @@ -# REPORT — the guards, and one thing I could not establish (2026-08-09 evening) +# REPORT — the census, the receipts, and a promise we should stop making (2026-08-10) -No machine touched. Both demo boxes stayed offline and in transit; nothing here needed them. - -**Parts 1, 2 and 3 are done. Part 4 and Part 5 are NOT done** — see §6 and §8. Part 5 was marked -droppable and was dropped; **Part 4 was not marked droppable and I ran out of session before it**, -which is a shortfall rather than a decision. +Documentation and one read-only census. **No code that runs on a customer's machine, no deploy, no +bake.** Both demo boxes are online and were not changed. **The tester's machine was not contacted** — +only its hub-side record was read, and it has none. --- -## 1. Part 1.1 — the deleter: **NOT ESTABLISHED** +## 1. Part 2's answer, first -**This prompt's account is not corroborated by any source I can reach**, and the prompt itself said -not to take its word for it. +> **No. A machine that is not ours cannot be in the state that cost demo-felhom its history — not +> today, and not for anything enrolled from now on.** -| claim in the prompt | what I found | +The hub holds escrow for **three** hosts. Both demo boxes lost their pre-fix key in the same four-hour +window on 2026-08-04; that is the entire affected population and it is entirely ours. `peti-felhom` +has **no host row and no escrow at all**, and neither does `david`. Anything enrolled from here escrows +under the fixed code, which has been in force since 2026-08-04. + +## 2. The census, and the control that came first + +**Control (run before the census, and it had to pass or the census was worthless):** + +``` +demo-felhom-8363b5 host_escrow -> present (572 bytes) want present OK +demo-felhom-8363b5 host_escrow_superseded -> absent (NULL) want absent OK +control PASSED: the query distinguishes both states on known cases. +``` + +| host | current | superseded | material | superseded_at | verdict | +|---|---|---|---|---|---| +| `demo-felhom-8363b5` | 572 B | id=4 | **ABSENT** | 2026-08-04 07:20:08 | old backups lost (before the fix) | +| `demo-hp-bb76ea` | 572 B | id=3 | **ABSENT** | 2026-08-04 07:15:36 | old backups lost (before the fix) | +| `drill-r50-0a4f9a` | none | 0 | – | – | no supersession has happened | +| `peti-felhom` | — | — | — | — | **no host record, no escrow** | +| `david` | — | — | — | — | **no host record, no escrow** | + +An orphan check found no escrow row pointing at a host the hub does not know. + +**One correction I made to my own instrument.** The first run labelled both losses *"superseded AFTER +the fix — unexpected"*, because a date-only comparison puts `2026-08-04 07:20:08` after `2026-08-04`. +The in-force moment is pinned instead from the hub's own first post-fix escrow row — **11:11:37Z** — +which independently agrees with the register's *"four hours before v0.93.0 fixed the retention"*. Both +losses are then correctly *before* the fix: explained, not anomalous. + +**What this does NOT claim:** that a *retained* blob has ever been unwrapped on a superseded row. +Retention is proven; recovery **from** a superseded row remains unexercised. + +## 3. Part 1 — the deleter is ESTABLISHED, and it was on file all along + +The locator was correct: the record is **inside the R-267 row** — *"Pruned to the newest 10 per package +on the operator's rule, with the live-vouched golden/agent/floor asserted into the KEEP set before a +single DELETE was issued; 33 deletions, all HTTP 204."* + +Every corroboration checked and every one holds: + +- **The arithmetic:** 23 agent + 7 golden = 30, plus three older agent versions (0.81.0/0.80.0/0.79.0) + that *"only became visible after the first 30 deletions moved them onto page one"* = **33**. +- **The live PAGINATED listing** — 14 pages, 653 package-versions — `felhom-agent` generic at **exactly + 10**, `felhom-golden` generic at **exactly 10**. That is what a newest-10 prune leaves. + +The midnight-cleanup candidate is retired, and **R-291's blocking condition is released**: the operator +was being asked to establish something already written down. + +**My counter-argument yesterday was wrong, in precisely the way R-267 warns about.** I argued against +the prune because *"container packages hold 19 each"*. That came from an **unpaginated** query the API +caps at 50/page. Paginated, they hold **270** and **169** — they were never in the prune. R-267 records +the identical trap one paragraph above the sentence I could not find: *"An unpaginated listing is not +evidence of a total — this repo's own rule, walked into while measuring."* + +## 4. Part 3 — the twelve + +**Three restored. Nine honest greys.** The map already read PROVEN-LIVE for the three, so the dataset +was *behind* it — restoring follows the map rather than raising a status in the view. + +| claim | outcome | |---|---| -| "the register records … pruned to the newest ten … 33 deletions, all HTTP 204" | **No such row exists.** The only prune-adjacent row is **R-210**, which is `WAITING-ON-OPERATOR`, says in terms *"Nothing was deleted; this is a list, not an action"*, and concerns **local Docker images on DooPlex**, not the Gitea registry | -| "newest ten per package" | **Not visible in the current state.** `felhom-agent` generic holds 10, but `felhom-controller` and `felhom-hub` container packages hold **19 each** | +| `drives.enrol` | **RESTORED** — `audits/SPIKE-raw-drive-enroll-2026-06-15.md`: a live drive walked scan → format → mount → PVE storage → one-click enrol, with the resulting `storage.cfg` entry and mount unit recorded | +| `backup.tier1` | **RESTORED** — `audits/CAMPAIGN-8-backup-restore-2026-07-27.md`: adversarial, destructive, unattended, both boxes + ep0; A2 proven end to end | +| `fail.lost-recovery-code` | **RESTORED** — `audits/REHEARSAL-byo-reinstall-2026-08-09.md`, and proven the hard way on 2026-08-10 | +| `backup.restore-proof` | **grey — THE DECAY RULE FIRED** (below) | +| `install.installer-by-tag` | grey — hits are ISO spikes; nothing walks a tag rollback | +| `use.lifecycle` | grey — two passing mentions, no walk | +| `drives.migrate` | grey — one or two mentions only | +| `backup.whole-machine` | grey — diagnostics and phase findings, no walk of the claim | +| `fault.selfheal` | grey — **the best hit argues the other way**: `INCIDENT-guest-dhclient-killed-2026-07-20.md` documents self-heal's *absence* through a 1 h 15 m outage | +| `fault.operator-email` | grey — source-verified, delivery never observed | +| `fail.drive-filling` | grey — weak hits only | +| `fail.hub-down` | grey — Campaign 11's hub-unreachable work produced a *finding* (R-224), not a pass | -Everything else I could reach is silent, and silence here is not evidence of anything: -`package_cleanup_rule` is **empty**; `package_version` has **no soft-delete column**, so a deletion -leaves no row; Gitea's `action` feed carries **no package operation at all** across 2026-08-08 → -2026-08-09 and nothing whatever on the evening of 08-08; the Gitea pod has **53 days uptime, 0 -restarts**. +## 5. Did the "code moved under the proof" rule fire? **Yes — for the first time.** -**And I withdrew one of my own claims.** R-287 said *"no DELETE on the packages API appears in 48 h of -Gitea router logs"*. Re-checked: `kubectl logs --since=72h` returns nothing older than **2026-08-09 -16:35** and contains **zero** `api/packages` lines even for requests I made myself. **The log never -covered the window, so its silence was never evidence.** Withdrawn in the register. +`backup.restore-proof` **has** a receipt: `architecture/_recovery-inventory-2026-07-28.md` carries live +journal lines for scheduled restore-tests on both boxes and both tiers. It is superseded anyway — +demo-hp logged `restore_test_failed` on 2026-08-05, and the box has since been wiped and reinstalled. +The claim is about a **continuing** scheduled behaviour, so a 2026-07-28 observation cannot carry it. -**What remains established, unchanged:** `v0.120.0` downloadable at 2026-08-08 14:29 UTC (run 267 -printed `ok v0.120.0`), 404 by 2026-08-09 09:30 UTC (run 284), and `0.128.0` published at 14:47 UTC — -eighteen minutes after the good run. **It may be unestablishable from this side: Gitea keeps no -package-deletion trail.** +**So the rule can fire, and now has.** Two nights ago it fired zero times out of twelve because every +downgrade came from *missing* evidence, not decayed evidence — there was nothing for it to bite on. +**A consequence to note: the capability map still reads `PROVEN-LIVE (2026-08-03)` for that row, so the +map is now the thing out of step**, and it is the source. Recorded rather than silently rewritten. -Per §8 I halted that part's attribution and carried on; the rest is independent. +## 6. Part 4 — the promise, and why the wording is what it is -## 2. The number, and the two places that read it +**Surfaces:** -`felhom-agent/scripts/retention-policy.json` → `generic_versions_kept: 10`. +| file:line | | +|---|---| +| `controller/internal/web/templates/backups_remote.html:101` | **the false promise** | +| `controller/internal/web/templates/backups_remote.html:98` | the orphan explanation — accurate, keep | +| `controller/internal/web/templates/layout.html:143` | the 14-day abandon countdown — accurate, keep | +| `controller/internal/settings/settings.go:337-338` | `OrphanedRenamedTo` schema comment — accurate, keep | -Read by **`scripts/check-published-versions.py`** (bounds its assertion) and referenced by the prune -procedure. The file states, in its own header, that ten is an **observed state and not a located -ruling**, and that the principled bound is the hub's vouched `min_agent` floor — nothing can install -below it — which needs network the gate does not have. +*(The capability map was searched and makes no such claim — nothing to correct there.)* -**What CI no longer covers:** *a released version older than the retention window is no longer -asserted downloadable.* Its **git tag and config tree are still asserted**; only the binary's presence -is dropped. The check **prints the dropped versions every run**: +**The three cases:** set aside **before** the fix → not recoverable by construction (the restic +password lives only in the identity bundle, `escrow/identity.go:39` read by `escrow/recover.go:91`, and +those rows are NULL); set aside **after** → recoverable in principle, never demonstrated; **today's +population is entirely the first case**. -``` -11 released version(s); retention policy keeps the newest 10 -NOT ASSERTED (older than the retention window …): 0.120.0 -^ these versions still have git TAGS … what is no longer asserted is the BINARY's presence. -``` +**The deciding fact: neither the box nor the customer can tell which case they are in.** The hub holds +the discriminator (`host_escrow_superseded.identity_blob`); the box caches only +`HubEscrowIdentityPresent`, which is about the *current* escrow; and **no field on the report or ACK +wire carries superseded-blob retention**. The box renders the card. **A conditional promise the +renderer cannot evaluate is the same defect as an unconditional false one** — so the specified copy +stops promising, says plainly what happens, explains why it cannot promise, and names a route +(write to us). -Three controls: green at 10 naming what it dropped (**exit 0**); widened to 11 the evicted version -re-enters and convicts (**exit 1**, `FAIL v0.120.0`); the policy file removed → **exit 2 INCONCLUSIVE**, -naming the path it tried — never silently unbounded. +**Specification:** `documentation/design/SPEC-orphan-card-copy-2026-08-10.md` — copy, surfaces, and the +render tests that should pin it, including a regression guard that the string `visszaállítható lehet` +never returns. **Not implemented, on purpose:** it lands in the controller, and a controller release is +undelivered until a golden carries it (R-242). It should ship with the next controller change so one +bake and one approval cover both, and the spec says so. -## 3. `felhom-agent` green +## 7. Register -``` -reuse-refs OK · instructions OK · published OK · release-complete OK · all agent gates OK -``` +**Ceiling R-292 → R-294.** Opened **R-293** (the census) and **R-294** (the promise + spec). **R-287 +turned to ESTABLISHED** with my unpaginated-count error withdrawn. **R-291's blocking condition +released.** **R-288 gained a second measured cost**, and it is a different failure mode from the first: +prose rows make claims ambiguous; rows-about-other-things make facts unfindable. -**At `main`: green**, pushed as `53d047a`, and the pre-push hook ran the same entry point. -**At a tag: not re-proved tonight, and I will not claim it.** The available evidence is that the gate -is ref-independent — it enumerates from the Gitea tags API, and runs **190** (`v0.126.0`) and **216** -(`v0.127.0`) were tag pushes that passed. Minting a tag purely to prove it would have published a -release, which this session forbids. +## 8. Observations — noticed, not acted on -## 4. Red-proofs - -| # | mutation | asserted applied | outcome | -|---|---|---|---| -| 1 | **tag check removed** | `grep -c` → 1 | **scenario A FAILED, reporting `flash = "artifacts_set"`** — Friday's exact defect returned: the manifest saved with no tag | -| 2 | package check removed | `grep -c` → 1 | scenario B FAILED, `flash = "artifacts_set"` | -| 3 | inconclusive branch mapped onto success | `grep -c` → 2 | scenario E FAILED | - -All reverted; `grep -c MUTATION` → **0**; all seven tests green again. - -**Red-proof 3, stated precisely rather than flatteringly:** with the inconclusive branch mapped onto -success the save did **not** complete — it fell through to `artifact_sha_invalid`. So the mutation -proves the guard is load-bearing for *the message the operator sees*, not for the save itself. That is -the honest reading, and it is exactly the defect scenario E exists to prevent: the operator being told -"missing or invalid" when the truth is "I could not reach the registry". - -## 5. The five scenarios, as the operator sees them - -| | outcome | the message | -|---|---|---| -| **A** tag missing | REFUSED | *"Refused: that version has no usable git tag. The installer fetches an agent's config files from `raw/tag/v/configs/`, so a version published without its tag makes every fresh install and reinstall fail at step 5 of 8 — as root, on a virgin machine. … Fix it by pushing the tag: `git tag -a v && git push origin v`"* | -| **B** package pruned | REFUSED | *"Refused: that version's artifact is not downloadable. The version is tagged but its package is not in the registry, so a box would 404 fetching the binary itself. … Publish it — `bash scripts/release-agent.sh `"* | -| **C** no checksum | REFUSED | the pre-existing *"Couldn't set the checksum …"* — see the note below | -| **D** both good | **SAVES**, `artifacts_set`, byte-identical behaviour | — | -| **E** registry unreachable | REFUSED | *"Refused: could not verify — this does not mean anything is missing. … It refuses rather than saving with a warning, because a warning beside a success reads as a success. … There is deliberately no override: the registry is on your own server, so if it is unreachable the vouch can wait."* | - -**Scenario C changed shape because my first draft modelled nothing real,** and that is worth recording. -With a Gitea client configured, `resolveArtifactSHA` fetches the sha **authoritatively and ignores what -was submitted** — so "submit an empty sha" cannot produce an empty stored sha. The genuine shape is -Gitea answering with no `sha256`, and the **existing** refusal already owns it. The test now pins the -guarantee (*the manifest is unchanged*) rather than a mechanism I had invented. - -**No override was built, and none is wanted.** §8's halt condition did not trigger. - -## 6. Part 4 — NOT DONE - -The twelve downgraded claims were not re-examined and no receipts were searched for. **The honest-grey -count is therefore still the twelve from last night, unverified in either direction**, and -`where-felhom-stands.*` is untouched. This is the session's shortfall: Parts 1–3 took the budget, and -splitting Part 4 in half would have produced exactly the kind of half-checked green the whole exercise -exists to prevent. - -**Whether the "code moved under the proof" rule can fire at all** is therefore still open from last -night, where it fired **zero** times out of twelve — every downgrade came from missing evidence, not -from decayed evidence. My reading remains that it *can* fire but will stay rare until rows cite -evidence at all, which is R-290. - -## 7. Hub deployed - -**v0.102.0**, live and verified: deploy image `gitea.dooplex.hu/admin/felhom-hub:0.102.0`, rollout -complete, and the page footer reads `0.102.0`. Manifest commit **`36bcd12`**; code commit `b55fc17`. -The image was verified **served by the registry before** the manifest was bumped, not after. ArgoCD's -`felhom` app has `automated.enabled: false`, so the sync was triggered explicitly — **no -`kubectl set image` at any point.** - -## 8. Part 5 — dropped, as marked - -Not started. It was explicitly droppable and it is the only part that touches customer-facing wording, -which is where a rushed edit does most harm. - -## 9. Register - -**Ceiling R-290 → R-292.** Opened **R-291** (the narrowing, with its reason, so it can be widened -deliberately) and **R-292** (`artifact_sha_invalid` conflates three facts — found by scenario E -failing, worked around by ordering, message untouched). Closed: **R-273's owed-guards tail**, both -guards built. Corrected: **R-287**, twice. - -## 10. Observations — noticed, not acted on - -- **R-292 is the interesting one.** A test I wrote to check a new guard failed for a reason that had - nothing to do with the guard, and that reason was a real pre-existing defect. The five scenarios - earned their keep before the feature shipped. -- **The golden gets no tag probe.** It is fetched by version and has no config tree, so a tag probe - would assert something the installer never does. Deliberate, and stated in the code. -- **The gate is skipped entirely when no Gitea client is configured**, or a hub without registry - credentials could never vouch anything. Pinned by its own test, and worth knowing: the guard is only - as present as the client is. -- `check-release-complete` runs in `--fast`, so a missing tag is now caught by the **pre-push hook**, - earlier than CI. +- **The capability map is now out of step in two directions** — behind the dataset for three claims it + already called PROVEN-LIVE, and ahead of it for `backup.restore-proof`. Both point at R-288. +- **`fault.selfheal`'s only real document argues against it.** Worth someone deciding whether the + capability is real and unwalked, or overstated. +- **Retention is proven; recovery from a superseded row is not.** The census proves blobs are now kept; + nobody has ever unwrapped one. That is the next thing worth a drill, and it needs no customer. +- The page now shows the three restored claims as **"moved twice"** rather than once, so an unsettled + status reads as unsettled. diff --git a/STATUS.md b/STATUS.md index 25deff6..33cfeb2 100644 --- a/STATUS.md +++ b/STATUS.md @@ -27,6 +27,52 @@ So I took your stated fallback: the old store was **moved aside, not deleted** ( **One thing that needs your judgement, not mine.** The card that offered this told the customer their set-aside backups *may be restorable later with their recovery code*. For these ones that is simply untrue, and it is said to precisely the people who have just lost their history. *(R-202 — now evidenced.)* +## Can anyone else lose their history the way demo-felhom did? No. + +**One read of the hub's own records, no machine touched.** The hub holds backup keys for exactly +**three** machines. Both demo boxes lost their old key in the same four-hour window on 4 August, +before the retention fix was in force — that is the whole population of the problem, and it is +entirely ours. **The tester's machine has no record at all**, so it cannot be affected; and anything +enrolled from now on is covered, because the fix has been in force since 4 August. + +I ran a control before trusting the query: it had to say *material present* for a machine known to +have it and *absent* for one known not to. It did both. + +## Three green dots came back, nine stayed grey, and one rule finally fired + +**The nine greys are the honest number.** For those, no document anywhere walks the claim, and saying +so is more useful than a dot nobody can defend. + +- **Back to green**, each citing the document that walked it: the drive wizard (a live drive taken + through scan → format → mount → enrol), the on-box app backups (an overnight destructive campaign + across both machines), and the lost-recovery-code case — which we then proved the hard way this + morning. +- **One claim stayed grey for a new reason, and it is the interesting one.** The unattended + restore-proof *does* have a receipt from 28 July — but demo-hp's restore-test failed on 5 August and + the machine has since been wiped and rebuilt. It is a claim about something that keeps happening, so + an old observation cannot carry it. **This is the first time that rule has fired**; two nights ago it + fired zero times out of twelve. + +## The prune mystery is solved, and the answer was written down all along + +Who deleted the old versions: **you did, on 4 August evening, on your own rule** — 33 deletions, keep +set asserted first, every one a clean 204. **It was recorded inside the row about the Configuration +page being slow**, because pruning artifacts is what made that page fast. Two sessions failed to find +it. **You are no longer blocked** on establishing something that was already on file. + +I also got a number wrong yesterday and it is corrected: I said the container packages held nineteen +versions and used that to argue against the prune. Counted properly — with pages — they hold 270 and +169, and the two that *were* pruned sit at exactly ten each. + +## The sentence we should stop saying + +When a machine's off-site history is set aside, the card tells the customer it *may be restorable +later with their recovery code*. **The machine showing that card cannot know whether it is true** — +the fact lives on the hub and is not sent to the box. For anything set aside before 4 August it is +simply false. **The replacement wording is written and waiting** +(`documentation/design/SPEC-orphan-card-copy-2026-08-10.md`); it ships with the next controller +release so one image bake and one approval cover it, rather than costing you two of each. + ## What works A blank machine boots the Felhom disc, installs itself unattended, and is claimed by the customer, who @@ -40,74 +86,18 @@ destroyed on purpose and its files came back byte for byte identical — four ti their recovery code got everything back with **no command line inside the machine at any point**, in 72 seconds. The two rough edges that walk found are also gone. *(R-201, R-252, R-253 — closed.)* -## The guard is in. An approval that cannot be installed is now refused. +## Shipped 2026-08-09 — the guards, and the rehearsal that earned them -**Yesterday morning every install in existence failed for hours, and nothing would have stopped it -happening again. Now something does.** When you press Save on the Day-0 artifacts, the hub checks — -before it writes — that each version you are vouching actually has its git label **and** that its file -can actually be downloaded. If either is missing it refuses and tells you which, for which version, -and the one command that fixes it. **Hub v0.102.0 is live.** +**An approval that cannot be installed is now refused** at the moment you press Save: the hub checks +the version's git label and that its file downloads, and refuses with a message naming the fix. A +second machine catches it a step earlier in the agent repo. Both were owed after every install in +existence failed for hours on 2026-08-09. **Hub v0.102.0 is live.** -Three details worth your knowing: -- **It checks the exact file the installer fetches first** — the one whose absence broke Friday — not - some other file that happens to exist. A test pins that, because probing the wrong file is precisely - how the failure stayed invisible. -- **"Could not check" also refuses**, with a different message. Saving with a warning would read as a - success, and we have the scars. **There is no override**: the registry is on your own server, so if - it is unreachable the approval can wait. -- **A second machine now catches it one step earlier** — the agent repo refuses to consider a release - complete unless its label and its package both exist. - -## The red repository is green, and the two rules now share one number - -The tidy-up keeps the newest ten versions; the check demanded every version ever labelled still be -downloadable. Both are sensible and together impossible, so the red would have returned on your next -publish. They now read the same number from one file. **What the check no longer covers, plainly: a -version older than the ten is no longer asserted downloadable** — its label and its config files still -are — and it prints which ones it dropped on every run so this cannot go quiet. - -**One thing I could not establish, and I am not guessing.** Who actually deleted the old versions is -**still unknown**. Gitea keeps no deletion trail: no cleanup rule is configured, the version table has -no deleted-marker, the activity feed shows no package operation, and the server log no longer reaches -back that far. I also **withdrew my own claim from yesterday** that the logs showed no deletion — the -logs did not cover the window, so they never said anything. - -## The rehearsal finished. The data came back byte for byte; the journey did not. - -**We wiped a working demo machine and put it back. All four test files returned identical — including -the two with Hungarian accents, checked as raw bytes, not as text on screen.** The unlock took 21 -seconds and the restore 13. **But it only finished because I could open a terminal twice.** A -household would have stopped, twice, and the second time the screen would have told them it was easy. - -**The two walls, both fixed-or-fixable, neither about the data:** - -- **The install died four steps in** — the agent version you approved had been published as a download - but never given its version label, and the installer looks it up by that label. **Now unblocked** — - I pushed the label after checking the published file matched what you vouched. *(R-273 — closed. The - two guards that would stop it recurring are still owed.)* -- **A reinstalled machine cannot re-attach its own data drive.** Every route is a dead end, and the - restore page cheerfully says „**Ez két kattintás**" while pointing at an empty list. The drive is - fine and the machine can see it — it just is not offered, because the same drive is also the backup - target. I got past it by typing an internal path no customer could know. **This is the one to fix - before the tester's visit.** *(R-280)* - -**Also broken, found on the way:** - -- **Taking Felhom off a machine leaves the one thing that stops it going back on.** We install a small - network service at setup; removing Felhom restarts it without its settings, it seizes the port the - next install needs, and the next install then refuses — appearing to blame the owner's network. - *(R-272)* -- **A machine we removed keeps its private line to us open.** *(R-276)* -- **The hub said nothing at all** while a machine was wiped, rebuilt, re-claimed and had its sealed - backups opened. No false alarm — but also no word, and the alarm that exists for "someone is opening - this customer's backups" stayed silent through a real one. *(R-281)* -- **A rebuilt machine may still come back on software from last week** — narrower than I first wrote: - the resumed install fetched the right version, but a fresh one takes whatever copy is newest on the - disk without checking it against what you approved. *(R-274)* -- **demo-felhom has not had an off-site backup in six days** and is waiting for a recovery code nobody - has entered. demo-hp, rebuilt the same day, recovered by itself. *(R-278)* -- **One code, three different names**, and the email points at a page the machine is not showing — - this cost us a wasted code today. *(R-282, R-283)* +**The reinstall rehearsal:** a demo machine was wiped and put back. All four test files returned +**byte for byte**, accented Hungarian filenames included, checked as raw bytes. But it only finished +because a terminal was available twice — the install died on a missing version label *(R-273, now +guarded)* and **a reinstalled machine still cannot re-attach its own data drive** *(R-280 — the one to +fix before the tester's visit)*. Detail: `documentation/audits/REHEARSAL-byo-reinstall-2026-08-09.md`. ## What's broken @@ -121,27 +111,6 @@ household would have stopped, twice, and the second time the screen would have t accumulates. *(R-244)* - **Putting restored files back where they belong is still manual.** *(R-213)* -## The rest of what the rehearsal found - -Sixteen findings in one afternoon, **none of them visible from reading the code** — three sessions of -review had not seen any. - -- Removing Felhom leaves five files holding old keys *(R-275)*, and rotating a leaked key does not - revoke the old one until the service restarts *(R-269)* — the written recipe for it is a step short - *(R-270)*, and the alarm it raises can never be closed because the fix it recommends is what - silences the all-clear *(R-271)*. -- **It caught me being wrong twice, and that matters more than the count.** I told you the fleet's - off-site backups were down; demo-hp had eighteen snapshots and I had read three misleading screens - instead of asking the machine *(R-277)*. And I raised a leftover permissions file as a security - hole, then tested it and refuted myself — it is inert. - -**What worked, and should not be lost in the count:** the machine came up on its own at the approved -version; the setup page appeared unprompted, in Hungarian, naming the customer; **the recovery screen -appeared without being looked for** and said plainly that unlocking changes nothing; the restore told -the truth about putting files in a checking folder rather than back in place; and no false alarm fired. - -Full account: `documentation/audits/REHEARSAL-byo-reinstall-2026-08-09.md`. - ## Three rulings, written down so they stop living in a conversation - **The managed-update floor.** It is deliberately parked, and the trigger to raise it is **the first diff --git a/documentation/architecture/where-felhom-stands.html b/documentation/architecture/where-felhom-stands.html index 012bce9..efdeb26 100644 --- a/documentation/architecture/where-felhom-stands.html +++ b/documentation/architecture/where-felhom-stands.html @@ -7,15 +7,15 @@

Where Felhom stands

What we built, what happens when things go wrong, and what is still missing. Generated from where-felhom-stands.yaml, which cites the capability map, register row or evidence document behind every claim — and which is checked by scripts/check_stands.py.
Verified 2026-08-09 against felhom-agent 28ba8593b8, felhom-controller c732fe1283, hub 56f8aa611c. 12 status(es) moved in that pass — each is marked on the page.
-
Walked (20)done end to end on real hardware, evidence on file
Built (17)shipped and tested, the real path never walked
Partial (14)some walked, some not — the note says which
Missing (4)does not exist
needs-hardwareonly a running box could settle it
+
Walked (23)done end to end on real hardware, evidence on file
Built (14)shipped and tested, the real path never walked
Partial (14)some walked, some not — the note says which
Missing (4)does not exist
needs-hardwareonly a running box could settle it
The journey
Seven stages, left to right, as they happen to a person.
1  Getting a box
A blank machine installs itself from our own boot image and registers itself as unclaimed — proven on two different boardsTwo boards: N100 2026-07-18, HP t740 2026-07-21.capability-map Bare-metal Felhom ISO (blank hardware → zero-touch auto-ins… · evidence tests/VALIDATION-n100-rehearsal-2026-07-18.md
The installer is published rather than pushed: rolling it back is one actchanged 2026-08-09, was walkedGate 6 of hostinstall_gates asserts the manifest names an installer-v tag; ran green tonight.why it moved: gate 6 asserts the manifest names an installer tag, but no walk of a rollback is on filecapability-map The installer is PUBLISHED, not pushed · register R-110
Installing onto hardware the customer already owns — the path exists, the first real one has not happenedUPGRADED: a real --mode byo install completed on demo-hp 2026-08-09 (Day-0 provision SUCCESS, 3m49s). Still not a customer's own hardware, so not 'walked' — but 'has not happened' is now false.evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
A machine that ends up on the wrong network port explains itself on screen and finds its way back — proven in a virtual drill, never on metalMap says the same: PROVEN-LIVE (nested drill — nested != metal).capability-map Box survives a wrong-NIC install · evidence audits/SPIKE-firstboot-nic-sweep-2026-07-22.md
Reinstalling a machine we previously installed refuses, because our own removal leaves a name service holding the port our own installer checksWarning card. Confirmed live 2026-08-09; dnsmasq restarted by --uninstall seizes :53.register R-272 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
2  Making it theirs
An emailed one-time code; the customer sets their own password and the operator never sees itExercised live 2026-08-09: reset code accepted at /claim, 302 + session.capability-map Customer claim: one-time emailed code → customer sets own p… · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
The customer can bind their own machine from a link, with no operator present — done once, for realattempts=0, locked=0, source customer_selfbind, 2026-07-18.capability-map Customer binds their own appliance (self-service) · evidence tests/VALIDATION-n100-rehearsal-2026-07-18.md
It has never been done by a person who is not the operatorMap records MISSING (as evidence). Still true after 2026-08-09.capability-map A customer (not the operator) performs a restore via UI alone
The same word is used for two different secrets across three surfaces; the email points at a page a rebuilt machine does not showWarning card. Cost a real code on 2026-08-09.register R-282 · register R-283
3  Using it
Apps installed from a catalog of about 52, with a memory guard and health-aware progress53 templates listed on the rebuilt box 2026-08-09; deploy driven live.capability-map Deploy an app from the catalog (env config, memory guard, h… · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
Start, stop, restart, update, logs, remove — and the parts that must not be stopped cannot bechanged 2026-08-09, was walkedwhy it moved: no walk document cited by the map row or anywhere elsecapability-map App lifecycle: start/stop/restart/update/logs/remove/redeploy · register R-108
Reachable from anywhere through a tunnel, per-app addressesVerified tonight: the rebuilt box answered on its public URL from outside.capability-map Remote access via Cloudflare Tunnel + Traefik (per-app subd… · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
Reachable on the home network when the internet is downneeds-hardwareOnly an observation on a running box with WAN pulled could settle it. Boxes are off.capability-map LAN access when internet is down (lan_resolver)
Phone photos, documents with text recognition, files from Windows Explorer or a Maccapability-map Files from Windows Explorer / Mac Finder (SMB server) · evidence audits/SPIKE-lan-discovery-2026-07-18.md
A one-tap launcher, and a read-only guest link for visitorscapability-map Indítópult (app launcher) — one-tap grid of the household's…
Media to a TVMap: MISSING.capability-map Media to TV via DLNA
Separate accounts per household memberMap: MISSING.capability-map Multiple household users / per-person accounts
-
4  Drives
A new drive is found, offered, formatted, mounted and enrolled — including on awkward older boot layoutschanged 2026-08-09, was walkedApplies to a NEW drive. Re-attaching an existing one after a reinstall is R-280 and fails.why it moved: the 2026-08-09 walk exercised RE-attach (which failed, R-280); first-enrolment of a NEW drive has no walk on filecapability-map Drive wizard: scan/format/mount/enroll, incl. legacy-boot L… · register R-220
Moving data between drives, crash-safe; removing a drive safely; unplug detectedchanged 2026-08-09, was walkedwhy it moved: no walk document citedcapability-map Data migration between drives (all / per-app), crash-safe
A network drive can be browsed and hold bulk media, but may not hold an app's data — enforcedRefuseAsAppNamespace is the fail-closed predicate.capability-map Network storage (NAS) is browse + bulk-media only · register R-108 · evidence audits/R108-network-app-namespace-2026-07-30.md
After a reinstall the data drive cannot be re-attached through any dashboard routeWarning card. /api/disks/candidates returns empty; the restore page promises two clicks.register R-280 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
-
5  Backing up
App data on the machine, nightly database dumps, a copy on a second drivechanged 2026-08-09, was walkedwhy it moved: no walk document citedcapability-map Tier-2 secondary-drive copy: class-driven legs
A whole-machine archive that lands off the guest's own disk — a single-drive machine is recorded as degraded rather than pretendingchanged 2026-08-09, was walkedwhy it moved: no walk document citedcapability-map Whole-guest backup lands OFF the guest's own physical device · register R-165
An encrypted off-site copy, sealed with a key the operator cannot readVerified tonight from the repo itself: 18 snapshots, daily, unbroken.capability-map Offsite (restic → Hetzner Storage Box) · register R-199 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
The backups prove themselves: a restore is actually performed, unattended, on every tier, on both machineschanged 2026-08-09, was walked'on both machines, unattended, every tier' is a continuing claim about scheduled runs. Both boxes are off; the last recorded restore-test on demo-hp FAILED (notification_log 2026-08-05 restore_test_failed). Cannot be settled tonight.why it moved: no walk document cited, and the last recorded restore-test on demo-hp FAILED (2026-08-05)capability-map Restore-proof is UNATTENDED — the scheduler covers EVERY tier · register R-86
The customer is warned before a drive fills, per drive, in their own languageR-177 (no operator-triggerable run) limits testing, not the capability.capability-map The customer is warned BEFORE a filesystem fills · register R-167 · evidence audits/SPIKE-r165-mp1-merge-2026-08-02.md
A backup that covered nothing still calls itself successfulWarning card.register R-240
+
4  Drives
A new drive is found, offered, formatted, mounted and enrolled — including on awkward older boot layoutsmoved twice: 2026-08-09 walked -> built, then 2026-08-10 back to walkedApplies to a NEW drive. Re-attaching an existing one after a reinstall is R-280 and fails.why it moved: receipt found 2026-08-10: a live throwaway drive on felhom-pve walked scan -> format -> mount -> PVE dir storage -> one-click Regisztralas, with the resulting storage.cfg entry and systemd mount unit recorded. The map already read PROVEN-LIVE; the dataset was behind it. Scope unchanged: this is a NEW drive. Re-attaching an existing one after a reinstall is R-280 and still fails.capability-map Drive wizard: scan/format/mount/enroll, incl. legacy-boot L… · register R-220 · evidence audits/SPIKE-raw-drive-enroll-2026-06-15.md
Moving data between drives, crash-safe; removing a drive safely; unplug detectedchanged 2026-08-09, was walkedwhy it moved: no walk document citedcapability-map Data migration between drives (all / per-app), crash-safe
A network drive can be browsed and hold bulk media, but may not hold an app's data — enforcedRefuseAsAppNamespace is the fail-closed predicate.capability-map Network storage (NAS) is browse + bulk-media only · register R-108 · evidence audits/R108-network-app-namespace-2026-07-30.md
After a reinstall the data drive cannot be re-attached through any dashboard routeWarning card. /api/disks/candidates returns empty; the restore page promises two clicks.register R-280 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
+
5  Backing up
App data on the machine, nightly database dumps, a copy on a second drivemoved twice: 2026-08-09 walked -> built, then 2026-08-10 back to walkedwhy it moved: receipt found 2026-08-10: an adversarial, destructive, unattended overnight campaign across both boxes and ep0, with A2 (one quiesce, two tiers) proven end to end. Map already read PROVEN-LIVE.capability-map Tier-2 secondary-drive copy: class-driven legs · evidence audits/CAMPAIGN-8-backup-restore-2026-07-27.md
A whole-machine archive that lands off the guest's own disk — a single-drive machine is recorded as degraded rather than pretendingchanged 2026-08-09, was walkedwhy it moved: no walk document citedcapability-map Whole-guest backup lands OFF the guest's own physical device · register R-165
An encrypted off-site copy, sealed with a key the operator cannot readVerified tonight from the repo itself: 18 snapshots, daily, unbroken.capability-map Offsite (restic → Hetzner Storage Box) · register R-199 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
The backups prove themselves: a restore is actually performed, unattended, on every tier, on both machineschanged 2026-08-09, was walked'on both machines, unattended, every tier' is a continuing claim about scheduled runs. Both boxes are off; the last recorded restore-test on demo-hp FAILED (notification_log 2026-08-05 restore_test_failed). Cannot be settled tonight.proof decay: PROOF-DECAY RULE FIRED (first time it has). A receipt EXISTS - architecture/_recovery-inventory-2026-07-28.md carries live journal lines for scheduled restore-tests on both boxes and both tiers - but it is superseded by later observation: demo-hp logged restore_test_failed on 2026-08-05, and the box has since been wiped and reinstalled (2026-08-09). The claim is about a CONTINUING scheduled behaviour, so a 2026-07-28 observation cannot carry it. Stays grey until a scheduled restore-test is seen passing on the rebuilt box. THE CAPABILITY MAP STILL READS PROVEN-LIVE (2026-08-03) AND IS NOW THE THING OUT OF STEP.why it moved: no walk document cited, and the last recorded restore-test on demo-hp FAILED (2026-08-05)capability-map Restore-proof is UNATTENDED — the scheduler covers EVERY tier · register R-86
The customer is warned before a drive fills, per drive, in their own languageR-177 (no operator-triggerable run) limits testing, not the capability.capability-map The customer is warned BEFORE a filesystem fills · register R-167 · evidence audits/SPIKE-r165-mp1-merge-2026-08-02.md
A backup that covered nothing still calls itself successfulWarning card.register R-240
6  When something goes wrong
The machine watches itself and repairs some faults without telling anyone it had tochanged 2026-08-09, was walkedR-264 records that the self-heal counters reach the hub and are decoded nowhere.why it moved: no walk document citedcapability-map Box survives an unattended app or guest-network failure · register R-264
Failures reach the operator by email, one mail per run, every failing app namedchanged 2026-08-09, was walkedCONFIRMED against source: backup_run_failures digest is allowlisted (api/handler.go:1837), operator-only (dispatcher.go:423), templated (templates.go:48); recovery_unit_capture_failed is record-only (dispatcher.go:376). NOTE: R-182's register row still describes the PRE-FIX behaviour — see R-289.why it moved: the digest is wired and source-verified, but no run of it has been observed deliveringcapability-map A failed per-app Tier-1 backup reaches the OPERATOR — EVERY… · register R-182
Failures reach the customerThe customer leg is built; today's log shows customer-channel rows skipped as operator_only.capability-map App crashes → customer notified (one event per transition, …
An already-paired box is still told to pair itselfWarning card.register R-214 · register R-235
7  Getting everything back
A rebuilt machine shows a full-page recovery screen without anyone looking for it, and says plainly that nobody can replace a lost recovery codeSeen unsought on the rebuilt demo-hp 2026-08-09, seal date matching host_escrow.created_at.register R-193 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
The customer's code opens the sealed package and the data returns byte for byte — including accented Hungarian filenames, verified as raw bytesReproduced 2026-08-09: 4/4 byte-identical, name bytes NFC-preserved, out of snapshot 41c830db.register R-201 · evidence tests/walk5-r201-2026-08-07/journal.md · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
Walked end to end with no command line inside the machine (2026-08-07)contestedCONTESTED-RESOLVED: not a contradiction. The walk proves the ROUTE needs no guest shell; the map's MISSING row is about a NON-OPERATOR doing it, which has still never happened. Two questions, one word 'customer'.register R-201 · evidence tests/walk5-r201-2026-08-07/journal.md · capability-map A customer (not the operator) performs a restore via UI alone
Putting restored files back where they belong is still manualWarning card. Confirmed 2026-08-09: the restore lands in a verification folder and says so.register R-213
The tripwire that says someone is opening this customer's backups does fireCONFIRMED tonight from the hub store: escrow_blob_served 2026-08-09 10:19:41Z = 12:19 CEST in the operator's mailbox. R-281's original claim of silence is WITHDRAWN.register R-281 · register R-285 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
@@ -32,7 +32,7 @@
The whole machine is wiped and reinstalled
The whole machine is wiped and reinstalled — the journey needs a terminal twiceCONTESTED-RESOLVED against the map: the map's PROVEN-LIVE row is scoped to a controller-data-volume REBUILD (2026-08-04), not a whole-host reinstall. The map has no row for the host case, so there was no contradiction — only a gap.register R-273 · register R-280 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
The machine is stolen, and someone opens the backups
The machine is stolen, and someone opens the backups — the operator is toldConfirmed 2026-08-09 from the store and the mailbox.register R-281 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
The customer forgets their dashboard password
The customer forgets their dashboard passwordExercised 2026-08-09 via the reset code.evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
-
The customer loses their recovery code
The customer loses their recovery code — by design, the data is unrecoverablechanged 2026-08-09, was walkedThe recovery screen states it in Hungarian.why it moved: a by-design refusal; no walk document citedcapability-map Escrow ceremony: customer-facing wizard, one-shot R claim, … · register R-198
+
The customer loses their recovery code
The customer loses their recovery code — by design, the data is unrecoverablemoved twice: 2026-08-09 walked -> built, then 2026-08-10 back to walkedThe recovery screen states it in Hungarian.why it moved: receipt found 2026-08-10, and then proven the hard way: the recovery screen states in Hungarian that nobody can replace a lost code, and on 2026-08-10 demo-felhom's pre-fix key was confirmed unrecoverable by construction (identity_blob NULL; the restic password lives only in that bundle). The by-design refusal is real.capability-map Escrow ceremony: customer-facing wizard, one-shot R claim, … · register R-198 · evidence audits/REHEARSAL-byo-reinstall-2026-08-09.md
The machine moves house / new network
The machine moves house / new networkcapability-map Box survives a site/network change (relocation, different s… · evidence audits/AUDIT-vacation-remote-ops-2026-07-20.md
The internet goes down
The internet goes down — built, never walkedneeds-hardwareNeeds a running box with WAN pulled.capability-map LAN access when internet is down (lan_resolver)
The hub is down
The hub is downchanged 2026-08-09, was walkedwhy it moved: no walk document citedcapability-map Config/state change round-trips in seconds (hub↔box immediacy
diff --git a/documentation/architecture/where-felhom-stands.yaml b/documentation/architecture/where-felhom-stands.yaml index f5a4cdb..3f6b57e 100644 --- a/documentation/architecture/where-felhom-stands.yaml +++ b/documentation/architecture/where-felhom-stands.yaml @@ -240,17 +240,20 @@ claims: band: journey stage: 4 title: "A new drive is found, offered, formatted, mounted and enrolled — including on awkward older boot layouts" - status: built + status: walked note: "Applies to a NEW drive. Re-attaching an existing one after a reinstall is R-280 and fails." sources: - capability-map: "Drive wizard: scan/format/mount/enroll, incl. legacy-boot LVM-root hosts" - register: "R-220" + - evidence: "audits/SPIKE-raw-drive-enroll-2026-06-15.md" changed: - from: walked - reason: "the 2026-08-09 walk exercised RE-attach (which failed, R-280); first-enrolment of a NEW drive has no walk on file" + from: built + also_moved: 2026-08-09 walked -> built + reason_superseded: "the 2026-08-09 walk exercised RE-attach (which failed, R-280); first-enrolment of a NEW drive has no walk on file" + reason: "receipt found 2026-08-10: a live throwaway drive on felhom-pve walked scan -> format -> mount -> PVE dir storage -> one-click Regisztralas, with the resulting storage.cfg entry and systemd mount unit recorded. The map already read PROVEN-LIVE; the dataset was behind it. Scope unchanged: this is a NEW drive. Re-attaching an existing one after a reinstall is R-280 and still fails." verified: date: 2026-08-09 - verdict: downgraded + verdict: upgraded depth: source-read - id: drives.migrate band: journey @@ -297,16 +300,19 @@ claims: band: journey stage: 5 title: "App data on the machine, nightly database dumps, a copy on a second drive" - status: built + status: walked sources: - capability-map: "Tier-2 secondary-drive copy: class-driven legs" + - evidence: "audits/CAMPAIGN-8-backup-restore-2026-07-27.md" changed: - from: walked - reason: "no walk document cited" + from: built + also_moved: 2026-08-09 walked -> built + reason_superseded: "no walk document cited" + reason: "receipt found 2026-08-10: an adversarial, destructive, unattended overnight campaign across both boxes and ep0, with A2 (one quiesce, two tiers) proven end to end. Map already read PROVEN-LIVE." verified: date: 2026-08-09 - verdict: downgraded - depth: register+map + verdict: upgraded + depth: source-read - id: backup.whole-machine band: journey stage: 5 @@ -348,6 +354,7 @@ claims: changed: from: walked reason: "no walk document cited, and the last recorded restore-test on demo-hp FAILED (2026-08-05)" + decay: "PROOF-DECAY RULE FIRED (first time it has). A receipt EXISTS - architecture/_recovery-inventory-2026-07-28.md carries live journal lines for scheduled restore-tests on both boxes and both tiers - but it is superseded by later observation: demo-hp logged restore_test_failed on 2026-08-05, and the box has since been wiped and reinstalled (2026-08-09). The claim is about a CONTINUING scheduled behaviour, so a 2026-07-28 observation cannot carry it. Stays grey until a scheduled restore-test is seen passing on the rebuilt box. THE CAPABILITY MAP STILL READS PROVEN-LIVE (2026-08-03) AND IS NOW THE THING OUT OF STEP." verified: date: 2026-08-09 verdict: downgraded @@ -621,17 +628,20 @@ claims: - id: fail.lost-recovery-code band: failures title: "The customer loses their recovery code — by design, the data is unrecoverable" - status: built + status: walked note: "The recovery screen states it in Hungarian." sources: - capability-map: "Escrow ceremony: customer-facing wizard, one-shot R claim, operator zero-knowledge" - register: "R-198" + - evidence: "audits/REHEARSAL-byo-reinstall-2026-08-09.md" changed: - from: walked - reason: "a by-design refusal; no walk document cited" + from: built + also_moved: 2026-08-09 walked -> built + reason_superseded: "a by-design refusal; no walk document cited" + reason: "receipt found 2026-08-10, and then proven the hard way: the recovery screen states in Hungarian that nobody can replace a lost code, and on 2026-08-10 demo-felhom's pre-fix key was confirmed unrecoverable by construction (identity_blob NULL; the restic password lives only in that bundle). The by-design refusal is real." verified: date: 2026-08-09 - verdict: downgraded + verdict: upgraded depth: source-read - id: fail.moves-house band: failures diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md index 315453b..2a266ef 100644 --- a/documentation/backlog/OPEN-ITEMS.md +++ b/documentation/backlog/OPEN-ITEMS.md @@ -515,12 +515,14 @@ applied.** The one that matters: Scenario A **fails against today's tree** with | **R-284** | **„A kiválasztott tárhely majdnem megtelt." on a store that is 93 % FREE — an apparent inverted threshold.** Calibre-Web's deploy page rendered `