memory: the cache that aged the thing it cached
Two lessons from the thumbnail work, the second of which nearly shipped. We parked progressive loading on a count of images and the cost was in bytes. 'Measure the real booth before optimising it' was followed and still gave the wrong answer, because we measured the dimension that was easy to measure rather than the one the user feels. And a cache living inside the thing it describes can age that thing. Excluding every path under the cache dir passed its own test and was still wrong: creating the directory touches the BOOTH's own mtime, which is what _newest_mtime seeds from. The contents were excluded; the existence was the leak. Had it reached the Desk, one index load would have pushed every booth's expiry out and the TTL would never have fired again.
This commit is contained in:
@@ -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 `<img loading=lazy>` 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.
|
||||
Reference in New Issue
Block a user