---
title: "Evidence and replay"
url: https://services.dev/docs/service/evidence
captured: [export.txt]
codes: [needs_a_person, not_found]
---
# Evidence and replay

URL: https://services.dev/docs/service/evidence

> One call assembles a job's evidence bundle, its record, every file by hash and the state replayed from them, so an auditor or a dispute can check the job without trusting you.

The evidence bundle answers one question: can someone else check this job, step by step?

## Smallest form

```bash
curl http://localhost:8787/owner/jobs/job_7Hq2/export   # each artifact's text left out
```

```txt title="magic values: metadata.sandbox.review = flag_once"
  "object": "evidence",
  "job": "job_7Hq2",
  "service": "localization",
  "record": "28 events: job.ordered, charge.held, decision.made, step.proposed, step.committed, review.done, job.delivered, charge.collected",
      "path": "strings/strings.de.json",
      "sha256": "sha256:0c7bd35fe41dfdcf7d5d17e225761e5e9a605ab843eee3e56b7dcec061283a37"
      "path": "listing/listing.de.txt",
      "sha256": "sha256:3cd302d9f573c87f793ef20985f8b7b9c2210fde89b985045ed694e806cff59e"
      "path": "review/qa.json",
      "sha256": "sha256:b02acc1d389f334d06bb64e508e451ff9394cc0b55217fde9aa7e93bca4a130d"
      "path": "strings/strings.de.json",
      "sha256": "sha256:b1c723d0ebe964c8745ded184fd02d9a2e36374d49078b6ab511ee90463a0553"
      "path": "review/qa.json",
      "sha256": "sha256:1b22cc595c1768dfbeabc8fe96d89fd564c1f8c80cd0e004fb8c5b657056de18"
    "record": "sha256:460a07a7ec6cec91856f8bc7d13b00f2277404619272131528ac336e40a4946d"
  "replayed": {
    "status": "delivered",
    "stage": "qa",
```

## Every form

| Key | Written | Left out | Does |
|---|---|---|---|
| `object` | `'evidence'` | required |  |
| `simulated` | `true` | required | Every bundle from the sandbox says so. |
| `job` | `JobId` | required | The job it proves. |
| `service` | `string` | required | The Service the job ran, by its id. |
| `record` | `JobEvent[]` | required | The whole record, every event in order. |
| `artifacts` | `(Artifact & { text: string })[]` | required | Every file the job produced, each with its sha256 and its text. |
| `hashes` | `{ record: Hash }` | required | The sha256 of the record itself. |
| `replayed` | `Summary` | required | The status, stage, what it waits on, its steps and its ledger, replayed from the record and the step graph alone. |

## The bundle

It holds the whole record, every file the job produced with its sha256, a hash of the record itself, and the state the record replays to, as the bundle above shows.

Both rounds of the review are there: the flagged one and the pass, each `review/qa.json` with its own hash.

## Replay

Replaying the record alone, with the Service's step graph, gives the same status, stage and ledger, bit for bit. Every AI decision is pinned to its model and names the brief it read:

```bash
curl http://localhost:8787/owner/jobs/job_7Hq2/export   # each artifact's text left out
```

```txt title="magic values: metadata.sandbox.review = flag_once"
decisions: 10, each pinned to simulated-1; briefs services/localization.md and services/localization/qa.md
replayed from the record alone: identical, bit for bit
```

## Who can export

The export is the owner's, from the owner console or `GET /owner/jobs/:id/export`. A key gets `needs_a_person`, because the bundle holds what a buyer's surfaces never carry. How long a bundle is kept after its last use is the `data` key's `keep`.

## Seven surfaces

| Op | API | CLI | MCP | SDK | Site | Docs | App |
|---|---|---|---|---|---|---|---|
| `job.export` | `GET /jobs/:id/export`, `GET /owner/jobs/:id/export` | `jobs export <job>` | never: a person acts | never: a person acts |  | 1 error page | owner console |
| `job.ledger` | `GET /owner/jobs/:id` | `jobs ledger <job>` | never: a person acts | never: a person acts |  | 1 error page | owner console |

[Operations](https://services.dev/docs/reference/operations.md) has every column of every row.

## Refusals

| Code | Category | HTTP | Why |
|---|---|---|---|
| [`needs_a_person`](https://services.dev/docs/reference/errors.md#needs_a_person) | blocked | 403 | A person approves and signs, in the app. A key or a tool never can. |
| [`not_found`](https://services.dev/docs/reference/errors.md#not_found) | invalid_request | 404 | Nothing has that id. |

---

- Up: [Service()](https://services.dev/docs/service.md)
- Previous: [The record](https://services.dev/docs/service/record.md)
- Next: [Publish before it takes orders](https://services.dev/docs/service/status.md)
