# The archive

What a recorded session contains on disk.

An archive root holds the sessions of one site. Every other stage reads from it.

```text
archive/<host>/
├── sessions/
│   └── <timestamp>-<id>/
│       ├── session.json
│       ├── events.jsonl
│       └── graph.json
└── blobs/
    └── <sha256>
```

| File | Contents |
|---|---|
| `session.json` | Site, task, expert, start and end, Chrome version, viewport, locale, timezone |
| `events.jsonl` | Every event of the session, one JSON object per line, in order |
| `graph.json` | The session's graph, built from `events.jsonl` |
| `blobs/<sha256>` | Response bodies, snapshots and screenshots, shared across the site's sessions |

## The log and the graph

`events.jsonl` and the blobs are the record. They are append-only, safe across crashes, and the sandbox replays them byte for byte.

`graph.json` is derived from the log. It is built live while recording and can be rebuilt at any time, so an improved builder re-derives old sessions:

```sh
graphdom graph archive/<host>/sessions/*
```

The graph has typed nodes (action, navigation, state, request, response, value, tab, frame, file, choice, error, annotation) and typed edges between them, such as *caused* from an action to a request or *rendered* from a response field to a value on the page.

Every edge carries its evidence. An **observed** edge comes from something the recorder saw, like a DevTools initiator or a paste event. An **inferred** edge comes from a heuristic, like a matching value, and carries a confidence. Studio draws the two differently. A *rendered* edge is one of these: a value in a JSON response that equals a text or a field the next DOM snapshot shows. Studio lists it under the step that sent the request, with the element and the JSON path.

The annotations an engineer adds in Studio are kept in `annotations.json` beside the log, never in it, so the graph does not have them. Studio links each one to the value it marks the way the builder links the expert's.

## Privacy

A password field's value is never written. The field is recorded and its value becomes a reference to a secret you supply at run time. Everything else is stored in clear unless you opt in to redaction:

| Recorder option | Redacts |
|---|---|
| `redact.personal` | Italian tax codes, IBANs, e-mail addresses and phone numbers, wherever the page shows them |
| `redact.storage` | Cookie, localStorage, sessionStorage and IndexedDB values. Names and sizes are kept. |
| `redact.otp` | Fields named like one-time codes, handled as password fields |
| `redact.uploads` | The contents of picked files. Name, size and type are kept. |

These are options of the recorder API. The `record` and `relay` commands do not expose them yet.
