Root cause of "uploads silently land as 0-byte __file": aiohttp default body
limit is 1 MiB; PDFs almost always exceed it, request.json() raises
HTTPRequestEntityTooLarge, the generic read_json() swallows it as bare
Exception, upload_handler then sees an empty dict and happily writes an
empty file with name='file', returning ok=true. Front-end thinks the
upload worked.
Bridge:
- Set web.Application(client_max_size=1MB) explicitly so the limit is
visible at the call site (kept at 1MB intentionally for now; bump later
if larger uploads are needed)
- upload_handler reads body itself instead of read_json so it can catch
HTTPRequestEntityTooLarge and HTTPBadRequest and return a real error
to the client instead of silently writing 0 bytes
- Reject blob == b'' as a second line of defence
Frontend:
- addFiles skips files with size === 0 (handles drag-folder ghost File
and edge-case clipboard items) with a dedicated 'upload.empty' toast
- 4x showSystem(...) in addFiles -> showChanToast(title, detail, 'err').
Upload failures should be transient toasts, not permanent system
messages glued into the chat transcript.