Carry browser file bytes through validated HTTP routes into retry-safe storage, then implement download, deletion, and restore.
Files force the stack to handle data that does not belong in JSON event rows. This chapter adds an Attach file control, raw-body upload and download routes, and a content-addressed local store for patches, screenshots, logs, and exports. The browser reports the resulting digest; the service validates size and type; the object store makes a retried upload resolve to the same identity.
Trace bytes separately from metadata
The browser reads the selected File into an ArrayBuffer and posts those bytes to /api/artifacts with its content type. FastAPI enforces a non-empty body and a 5 MiB local-course limit, then calls AutocodeApplication.put_artifact. The application delegates byte identity and atomic writes to LocalArtifactStore.
The response contains the SHA-256 digest, size, and content type. Session events should store that small reference rather than embedding bytes in SQLite or WebSocket frames.
The retry creates one visible object because the digest is both identity and idempotency key. The HTTP test covers browser-shaped bytes, request validation, application delegation, filesystem storage, listing, and download. In a larger deployment, metadata belongs in the database while bytes move to object storage through the same reference contract.
Deletion is a lifecycle, not one unlink
Immediate physical deletion is unsafe when a session, another device, or an in-flight export still references the digest. DELETE /api/artifacts/{digest} creates a tombstone and makes ordinary GET return 404. The bytes remain recoverable during a grace period, and the restore route removes the tombstone.
The browser receives an honest not-found state while recovery remains possible. A retention worker may physically remove old tombstoned bytes only after checking every live reference, backup policy, and grace-period clock. Chapter 09 moves that sweep out of the user request path.
Choose proxy or direct transfer deliberately
The local service proxies bytes because it keeps the entire course runnable with one process. Object storage changes the efficient path: the API authenticates the request and mints a short-lived upload or download URL, while the browser transfers bytes directly to the object service. The session still stores the digest and metadata returned after verification.
Validate declared type, observed type when practical, length, digest, authorization, and filename display separately. Never trust a browser filename as a filesystem path, and never render uploaded HTML under the application’s trusted origin.
The empty-body rejection happens before storage, while content type remains metadata rather than permission to execute bytes. The capstone should add browser upload evidence, retry count, stored object count, and failed download behavior to the release scorecard.
Exercises
Design a retention sweep for tombstones older than a grace period. List the evidence it must check before deleting bytes, and write the idempotency rule that makes running the sweep twice safe.
[P05.1] Design a retention sweep
State the checks required before physically deleting a tombstoned artifact and the property that makes the sweep safe to retry.