docs(v0.230.0): R-403 — CHANGELOG, CONTEXT rulings, README, REPORT
gates / gates (push) Failing after 13s
gates / gates (push) Failing after 13s
CHANGELOG v0.230.0, leading with the measurement rather than the fix: 120 082 104 B -> 7 036 B on the shipped v0.229.0, reproduced before anything was built. CONTEXT records three rulings: hollowness is a MANIFEST question and never a size question; the guard fences one shape and NOT shrinking, because the derived-copy rebuild is a design decision; and the rehydrate happens inside the restore because a follow-up job races the 5-minute capture. Plus the shape the live run taught: a warning that fires on everything costs the same as the comforting lie it replaces. README documents the refusal, what each surface says, and why the capture job is deliberately not guarded. REPORT leads with Part 1's result, carries the six red-proofs, the per-row Scenario D table with its seven-app control, and eight observations including R-404 filed-not-acted-on and three mistakes of mine recorded rather than tidied away.
This commit is contained in:
+41
-1
@@ -7,7 +7,47 @@
|
||||
>
|
||||
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
|
||||
|
||||
Last updated: 2026-08-31 (v0.229.0 — R-102/R-103: the second drive's copy becomes a way back)
|
||||
Last updated: 2026-08-31 (v0.230.0 — R-403: a poorer copy must never delete a richer one)
|
||||
|
||||
> **2026-08-31 — v0.230.0. THREE RULINGS, recorded so none is re-litigated.**
|
||||
>
|
||||
> **1. HOLLOWNESS IS A MANIFEST QUESTION, NEVER A SIZE QUESTION.** `unitCarriesData` asks whether the
|
||||
> unit's manifest lists any database dump or any volume tar, and nothing else. `dirSizeBytes` lives
|
||||
> two files away and is the obvious wrong answer: a unit with a fat compose capture and no dumps is
|
||||
> exactly the shape that deleted 120 MB on `demo-hp`, and a 360-byte unit belonging to a tiny app is
|
||||
> perfectly healthy. Size answers *how big*; the question is *is there anything to recover*. Absent or
|
||||
> unparseable manifest ⇒ hollow, fail closed: a unit whose contents cannot be vouched for must never
|
||||
> authorise a delete of one whose contents can. `TestR403_SizeIsNeverConsulted` is the fence.
|
||||
>
|
||||
> **2. THE GUARD FENCES ONE SHAPE, NOT SHRINKING — because the derived-copy rebuild is a DESIGN
|
||||
> DECISION.** `07-backup-architecture.md` §8 row 5 records that the secondary is a derived copy,
|
||||
> rebuilt on the next run, and `tier2.go`'s own header records that a classified app's copy
|
||||
> legitimately shrinks as `export` drops out of its class set. `rsync -a --delete` stays, the data legs
|
||||
> are untouched, and complete→hollow and hollow→hollow both still mirror. The ONLY refusal is a source
|
||||
> carrying no data over a destination that carries some. Widening this to "the secondary never shrinks"
|
||||
> would be calling a decision a defect; `TestR403_DataLegShrinkIsUnaffected` is the guard on the guard.
|
||||
>
|
||||
> **3. THE REHYDRATE HAPPENS INSIDE THE RESTORE, BECAUSE A FOLLOW-UP JOB RACES THE CAPTURE.** The
|
||||
> hollow manifest was written **two seconds** after a Tier-2 unit restore, by the 5-minute
|
||||
> `backup-cache` job. A goroutine, a scheduled refresh or a "do it on the next run" would each lose
|
||||
> that race some of the time, and the failure mode is silent. `RestoreTier2Unit` refills the primary
|
||||
> before it returns, and the test asserts ORDERING rather than sleeping.
|
||||
> **And the capture is deliberately NOT guarded:** a capture that describes an empty drive as empty is
|
||||
> CORRECT. With the primary refilled there is no hollow state left to describe. Guarding the capture
|
||||
> would have made the manifest lie, which is the opposite of every other fix this week.
|
||||
>
|
||||
> **A defect the LIVE run caught and the unit tests did not, worth remembering as a shape.** The first
|
||||
> draft of `UnitRestoreDate` also flagged "the package is older than the run" by comparing their dates
|
||||
> — and a unit is ALWAYS captured shortly before the run that mirrors it, so it was true for every
|
||||
> healthy app on the box. Four apps would have been told their package was stale. **A warning that
|
||||
> fires on everything costs the same as the comforting lie it replaces.** The flag is now
|
||||
> `UnitLegPreserved` and nothing else.
|
||||
>
|
||||
> **The credential rider.** `felhom.eu/scripts/read_credential.py` is now the one place that value is
|
||||
> read. Three occurrences (2026-07-20, and twice on 2026-08-31, the third of which rewrote a live box's
|
||||
> password hash) happened while the project already had a memory file, a worked recipe and a session
|
||||
> report describing the mistake. **A note is read by whoever thinks to look; a check runs whether or
|
||||
> not anyone remembers.**
|
||||
|
||||
> **2026-08-31 — v0.229.0. THREE RULINGS, recorded so none is re-litigated.**
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user