June 15, 2026

document attachments, async composable, timer auto-silence, api-client auth

TKT-990 closes out the document-attachment bug in chat across both frontends

TKT-990 closes out the document-attachment bug in chat across both frontends. Two commits (one for the Vue port, one for the original) route documents through the same path as images: the attachments store now holds every picked file as a raw File with a preview chip, getFiles() ships them all down the multipart POST /chat, and the previews render in the user bubble. The entire pre-upload synthesis-card flow is deleted — uploadDocument, the DuplicateState/DocCard types, DocumentConfirmCard, and the orphaned api/documents module. POST /documents/upload stays because the Brain document library still uses it. A follow-up also swaps the doc chip frame from a non-existent --surface-raised token (falling back to #222) to --bg-surface-2 so light mode gets a near-white chip with dark text and dark mode gets a faint-light chip with light text.

TKT-991 hoists the load/error/data/reload boilerplate out of ten brain panels into a shared useAsyncResource composable, plus a useBrainResource wrapper that surfaces fetch failures as a toast via apiErrorMessage. Panels now declare what they fetch rather than the lifecycle around it — net -76 LOC with no behaviour change. Panels with bespoke lifecycles (stale-response guards, selective allSettled toasts, multi-ref distribution, reactive v-model objects) were left on the hand-rolled form. Skill mutations reassign skills with a new array so the change flows unambiguously through the computed mirror.

TKT-992 normalises SFC authoring: two