The heid bug-hunt panel on c2b1454 (4/4 arms, five seat-executed probes). The
new size rules governed only cache MISSES; the hit path trusted a name and an
mtime, inside a directory any fleet session can write into.
- A cache hit is a REGULAR file (lstat) carrying its source's EXACT mtime (4/4).
A planted directory at the cache path was returned as the thumbnail, and a
source replaced by `cp -p` or an archive extract kept an older stamp that
`>=` served forever. The encoder now stamps the thumbnail with the source's
mtime, so any change to the source is a miss.
- The cache directories are made component by component and never through a
link (seat P4). A `.thumbs` planted as a link put the cache outside the
booth, beyond the sweep. The booth-mtime restore now keys on creating
`.thumbs` itself.
- The temp file is mkstemp (4/4, seat P5). The old `<out>.<pid>.tmp` was
predictable, and a link planted there made the encoder overwrite its target
(600 B became 316,400 B).
- Palette transparency survives (3/4, seat-executed, and INTRODUCED by
c2b1454). The fits-but-heavy branch newly re-encoded palette PNGs, and
getbands() of mode P has no A even with tRNS.
- EXIF orientation is honoured for sizing and for the saved image (groa,
seat-verified). A camera portrait stored sideways was sized and tiled as a
landscape.
- A 64 MP decode budget (2/4). A header claims any size, and a failure is not
cached, so every request re-decoded it.
- The cache name carries the whole rule: width, height cap, quality and an
encoding version (groa). The width alone would have served stale bytes after
a quality change.
Declined: the utime-restore failing on a foreign-owned booth (booths are the
service user's), and regin's two solos (the THUMB_MAX export is not imported
anywhere; the live fixture is function-scoped). thumbs.toml: 14/14 proved.
The operator on sindra-nude-final: "the images look blurry until they're
selected and blown up." The cap was 512px on the LONGEST side, which the
comment called "comfortably above any tile size", and it was, for a square. A
gallery tile is sized by its WIDTH, though, and a 704x1408 portrait got 256px
of width for a tile Chromium renders at 361 CSS px. That is 1.4x stretched at
1x density and 2.8x on a 2x screen. The review stage serves the original,
which is why it looked sharp once opened.
- THUMB_WIDTH = 768: the widest desktop tile (3 columns, 1440px and up,
measured at 321-361 CSS px across viewports) doubled for a 2x screen.
THUMB_HEIGHT_MAX = 4096 stops a long screenshot going through at full height.
- An original that fits the bounds is served as-is only when it is also light
(<= 64 KB; 768-wide thumbnails average 39 KB over the 381 live images) or
animated, since a thumbnail is one frame. Fitting a tile in pixels is not
being cheap in bytes: these portraits are ~1.1 MB PNGs.
- The size rule is in the cache name (`<rel>.768w.webp`). The live 512-cap
thumbnails are newer than their sources, so the mtime check alone would have
served them forever. The old files are orphans, swept with their booth.
- tests/test_thumbs_browser.py holds THUMB_WIDTH against the rendered grid at
1440, 1920 and 2560. The constant is a layout number, and a redesign that
widens the tiles turns it red instead of soft.
Measured cost, all 381 live images: 4.8 MB -> 14.2 MB of thumbnails, still ~27x
under the 386 MB of originals. Known limit: the 2-column (<=472px) and 1-column
(<=650px) reflows are softer than 768 covers at 2x. tests/mutations/thumbs.toml
proves 7 falsifiers.