diff --git a/persistent-memory.d/2026-09-23-the-cache-that-aged-the-thing-it-cached.md b/persistent-memory.d/2026-09-23-the-cache-that-aged-the-thing-it-cached.md new file mode 100644 index 0000000..7f1c713 --- /dev/null +++ b/persistent-memory.d/2026-09-23-the-cache-that-aged-the-thing-it-cached.md @@ -0,0 +1,56 @@ +# The cache that aged the thing it cached + +_2026-09-23 · booth_ + +**Thumbnails: 77.5 MB → 0.78 MB on the biggest gallery, ~100 MB → 1.12 MB on +the Desk.** The operator found the defect in about a minute of using the live +redesign. Two lessons, and the second nearly shipped. + +## ⚠ LESSON 1 — we parked it on a count and the cost was in the bytes + +ROADMAP parked progressive loading on *"the largest gallery is 66 images; at +that size a lazy grid is almost certainly fine"*, and the parking-lot row said +*"270 `` may be fine."* **Both count IMAGES. Neither weighs +BYTES.** 66 is a fine count sitting on 77.5 MB of 1024×1024 PNGs rendered at +250px — roughly 16× the pixels that reach the screen. + +The rule "measure the real booth before optimising it" was followed and still +produced the wrong answer, because **we measured the dimension that was easy to +measure rather than the one that determines the experience.** Before parking +anything on a measurement again, ask what the user would actually feel. + +## ⚠ LESSON 2 — a cache INSIDE the thing it describes can age it, and excluding the cache is not enough + +`.thumbs/` lives inside the booth on purpose, so it is swept with the booth and +can never outlive what it describes. But `_newest_mtime` — which feeds +`is_expired`, which feeds `rmtree` — walks the booth, so **the server writing a +cache on a mere view counted as the operator touching the booth.** + +**The first fix passed its own test and was still wrong.** Excluding every path +under `THUMB_DIR` does not help, because **creating the directory touches the +BOOTH DIRECTORY's own mtime**, and `_newest_mtime` SEEDS from exactly that. The +cache's contents were excluded; its *existence* was the leak. + +The fix restores the booth's stamp across the `mkdir`. That cannot hide real +activity: any file an agent adds is counted by its own mtime in the same walk, +so the directory stamp is only a seed. + +**The blast radius if it had reached the Desk.** The Desk pulls a preview +thumbnail per booth, so ONE INDEX LOAD would have pushed EVERY booth's expiry +out — the TTL would never fire again and nothing would ever sweep. Caught by +design-dev from the outside, hours before the strip landed; verified after the +fix on the live set: **29 booths, two Desk loads, 22 caches generated, 0 clocks +moved.** + +`.viewed` counting as activity is different and deliberate — that is a record of +a *person* looking, which U4 says is activity. **A server-written derived cache +is machinery, like the `.lock` sidecars already excluded.** Any future cache +inherits this: exclude it from the clock AND preserve the parent's stamp. + +## A third, smaller one: the dot-namespace was only skin deep + +`booth_items` and `zip_booth` both tested `p.name.startswith(".")` — the FILE's +name — so `.thumbs/a.png` (name `a.png`) would have rendered as a gallery item +and shipped inside every zip download. CLAUDE.md invariant 2 promises a dotfile +costs nothing in item counts, galleries or zips; **that was true only at the top +level.** Both now skip every dot-prefixed path COMPONENT. diff --git a/persistent-memory.md b/persistent-memory.md index ea6a9ca..4e0b4a2 100644 --- a/persistent-memory.md +++ b/persistent-memory.md @@ -199,6 +199,7 @@ _As of 2026-09-22:_ ## Recent decisions +- `[2026-09-23]` ⚠ **The cache that aged the thing it cached** — thumbnails 77.5MB→0.78MB; READ BEFORE PARKING ANYTHING ON A MEASUREMENT (we counted images and the cost was in bytes), and BEFORE PUTTING A SERVER-WRITTEN CACHE INSIDE A BOOTH (excluding its contents does not stop it aging the booth) → `persistent-memory.d/2026-09-23-the-cache-that-aged-the-thing-it-cached.md` - `[2026-09-23]` ⚠ **The probe that nearly dismissed a live injection vector** — the link board rendered `javascript:` hrefs; READ BEFORE TRUSTING A NEGATIVE RESULT FROM AN OBVIOUS PROBE, and before assuming an existing scheme check is the guard you are looking for → `persistent-memory.d/2026-09-23-the-probe-that-nearly-dismissed-a-live-vector.md` - `[2026-09-23]` ✅ **The bug-hunt panel found six defects and five vacuous falsifiers** — READ BEFORE BUILDING ANY FRAGMENT ANCHOR (browsers match raw before decoded, so both sides must be encoded), and before trusting a well-commented diff's guards → `persistent-memory.d/2026-09-23-the-bug-hunt-panel-and-five-vacuous-falsifiers.md` - `[2026-09-22]` ✅ **v1.0.0b1 — the v1 target staged as a beta, and a version that was two copies** — READ BEFORE DERIVING A VERSION FROM `importlib.metadata` HERE; it reports a different artifact, and `booth/__init__.py` turns out to be stdlib-only → `persistent-memory.d/2026-09-22-v1-staged-as-a-beta-and-a-second-copy-of-the-version.md`