Commit Graph

2 Commits

Author SHA1 Message Date
kami 61ba58388f media: bound an image by pixels, not by compressed bytes
The only cap was 64 MiB of input, and a decode bomb is a small file. A
20000x20000 PNG of flat colour compresses to a few hundred kilobytes,
decodes to 400 million pixels, and flattenAndScale then allocated a
second buffer of the same dimensions before scaling anything. That is
3.2 GB of live heap from one request, on a laptop, in the process that
owns the database and the socket, and max_dim never got a chance to
help. The header is read first now and a source over forty megapixels is
refused. The scaler reads the source through At and allocates only the
destination, so flattening no longer doubles the peak.

Found in review of #72.
2026-08-01 14:21:29 +04:00
kami d92349ca6e Store and describe images through a shared media intake (#252)
Vision needs a second model this box does not have, so the shipped half is
the part that works without one: an image arrives, is sniffed, is stored
content-addressed, and is prepared for inference. The describing half is
written and tested against a fake server, and refuses any endpoint that is
not on this box.

internal/media is the intake all three senses share — hearing and speaker
recognition store their audio in the same place under the same retention.
Blobs stay out of the sqlite store; only the derived text becomes a note,
and only when the caller asks. Retention is enforced by an hourly prune
loop rather than by a comment.

The plan's RemoteProvider step is refused: no cloud model, inference stays
on the box, and vision.NewLocal validates that at construction.
2026-08-01 04:53:07 +04:00