Thesis: The client JSON for an evidence row is an id, a title, a status, a published time, and a basename. The object key, the repo path, and assessor notes stay on the server. Download is a separate authenticated call.
What we tried first
The list response was the row we stored. That row includes the object key, which is how the vault finds the bytes. It also had a path inside the client repo and a note written for the assessor, not for the person holding the browser.
The working shape
The list the browser sees:
{
"id": "artifact-1",
"title": "Control matrix",
"status": "published",
"published_at": "2026-09-12T15:04:00Z",
"filename": "control-matrix.md"
}
filename is a basename. A path in that field is the key coming back under another name.
Checklist
- List JSON has no object key, no repo path, no assessor notes.
- Filename is a basename, not a path.
- Download is authenticated. No long-lived object URL on the list.
Related: tenant isolation without a bucket per customer. Why the basename still has an extension: why downloads lose their extensions. How we deliver: methodology.
Engineering commentary only — not audit, legal, or certification advice.