The export ZIP now carries every image any included log references under
media/<attachmentId>.<ext>, read and verified from the attachment store with
one entry per shared image. The endpoint requires the attachments service
alongside persistence and session-query; a referenced image that cannot be
read fails the stream like a missing descendant.
Chunk boundaries never split a surrogate pair (a lone high surrogate
re-encodes as U+FFFD and silently corrupts the exported artifact), production
yields whenever the response queue fills so a slow consumer bounds the
accumulation, includeDescendants rejects values other than true/false instead
of silently under-exporting, the dead missing-services arm is deleted by
narrowing the streaming deps, and the readRaw failure answers 500 without
leaking host paths into the browser error bar.
Streams one ZIP of the root session artifact plus each subagent descendant
verbatim (the persistence readRaw bytes) from GET /api/session.export as a
host-only download — no wire envelope, absent from IApiClient. The downloads
domain owns the query schema, the fetch handler answers the GET alongside the
SSE routes, and compression runs on the host with fflate's streaming Zip API.