Attachments Cross the Boundary
Some scoped work cannot fit in text. A spreadsheet, screenshot, export, or source packet may be the evidence the executor must inspect. Attachments belong to the delegation package, but they do not belong in the source repository that implements the workshop.
An engine-owned material store gives them a separate lifecycle. Metadata lives with the delegation: original name, media type, byte size, digest, and storage key. Blobs live outside Git under limits and access rules. The brief contains a manifest so the author knows what exists without embedding bytes in prose.
Upload and replacement are queued-only mutations. Taking the work freezes the manifest and bytes together. Deleting a still-queued delegation may remove its material; taken, landed, or abandoned records keep the package because it explains what the session saw.
Serving attachments requires narrow identifiers and authorization. Raw filesystem paths never cross the API. A request resolves delegation plus attachment key, checks ownership and state, and streams the stored bytes with a safe content type and filename.
Manifest Before Bytes
Let the session inspect the manifest first: name, size, type, and digest. It can decide which files to open without crawling a directory or guessing from private paths.
Verify lifecycle as a matrix: upload, replace, take, read, delete delegation, and retention. A happy-path download proves almost none of the boundary.