# The Decision log and audit

Every answer a deployed Decision gives is recorded before it is returned; the records can be verified, exported and gathered into an evidence pack.

## Every call is recorded

When a deployed Decision answers, the answer goes back as soon as the model replies, and the record of
the call follows within seconds. If storing it fails, TypeFuse keeps a second copy and keeps
retrying, and our team is alerted. If your organisation must never give an answer without its
record, turn on **Record before answering** (Environments → Recording calls): each call then waits
for its record, and the caller gets `503 NOT_RECORDED` instead of an answer if it can't be kept.

A record keeps:

- which Decision, release, execution plan and environment answered, and whether it was the main
  release, a canary, a compatible line or a shadow
- which Application and runtime key called, and when
- the caller's `reference` and `correlationId`, when given
- the answers returned, and fingerprints of the input, the state sent to the model and the raw
  answers; the input itself only when the Decision keeps its calls' inputs (below)
- the model, timing and token counts, or the error

Sandbox runs, Test runs and Comparisons are recorded the same way, marked with where they came from.
A relayed call (see [Calling a Decision](https://typefuse.dev/guides/calling#byok-managed-and-relay)) is marked as
relayed, with the response reported by the caller's app, and a relayed call that was prepared but
never completed shows as abandoned.

## Finding a call

**Audit** in the sidebar opens the **Decision log**: every call across the organisation, newest first.
Search by run id, reference or correlation id (an exact match), and filter by Application, Decision,
environment, status and period.

Inside a Decision, under Monitor, **Runs** lists that Decision's calls wherever they ran, and **Insights** shows how
its answers are distributed over time.

A run's page shows the input, the state sent to the model, the raw answers and an **Audit** panel with
the Application, reference, correlation id and where the call came from.

To make calls easy to find later, pass a `reference` for the record in your own system that the call
is about, such as `{ "type": "order", "id": "A-1042" }`, and a `correlationId` that ties it to the
rest of the request. See [Calling a Decision](https://typefuse.dev/guides/calling#http).

## Sealed and verifiable

Within about a minute of a call, its record is sealed into the organisation's audit trail. Each
batch of records gets a seal over their hashes, and every seal joins one hash chain with the
organisation's changes, such as publishing, deploying and approving. Changing or removing a record
afterwards breaks the chain. For a relayed call, the seal includes the fact that the response was
reported by the caller: TypeFuse checks that the response fits the request, but can't prove
TypeSafe sent it.

A run's Audit panel shows **Seal verifies**, **Seal broken** or **Not sealed yet**, with the hashes of
its plan, input, state and answers. An owner or admin can check the whole trail:

```sh
typefuse audit verify acme
```

It reports any break, and exits with status 2 when the trail isn't intact. TypeFuse also verifies
every organisation's trail each night.

## Changes

**Change history**, beside the Decision log, lists every change in the organisation, newest first:
edits, publishes, deployments, approvals and access, who made them and how. Each Decision's **Audit**
page, under Monitor, shows the changes to that Decision.

## Exports and evidence packs

Owners, admins and viewers can take the audit trail away as files. **Export** on the Decision log
downloads the calls in a period as CSV (for spreadsheets) or JSON (whole records), starting from the
filters on the page: a Decision, environments and a period. Each row has the call's id and time, the
Decision and release that answered, the environment, the Application and runtime key that called,
the caller's reference and correlation id, the answers and how sure each was, the tokens, the
latency, the seal and the deployment that served it. Tick **Include each call's input** to add the
input and the state sent to the model; a call that didn't keep its input says `not kept` there, and
one past your plan's retention says `no longer stored`; its hashes and seal are still in the row.

Exports and evidence packs are part of the paid plans (a trial included); on Free the Decision log, the
Change history and their verification are all here to read.

**Export** on the Change history downloads the changes in a period: versions, deployments, approvals
with who asked, who approved and whether an agent or token asked on the person's behalf, access and
settings. Narrow it to a Decision or an environment the same way.

An **evidence pack** is one download for a Decision and a period, made from **Audit → Exports** or
from the Decision itself. It is a zip holding:

- `summary.pdf`: what the Decision decides in plain words, which releases were live in each
  environment and when, their Evaluations and calibration, the approvals and who gave them, the
  calls each release answered, and the seals that fix those calls' records, with how to check them
- `calls.csv` and `calls.json`, `changes.csv` and `changes.json`: the records the summary counts
- `evaluations.json` and `seals.json`
- `definitions/`: the Definition of every release involved, exactly as published
- `manifest.json`: the SHA-256 of every file, so a copy can be checked against the original

### From a Decision

The same exports start from a Decision's own pages, already narrowed to it:

- **Runs**: **Export** downloads the calls it answered, starting from the environment you picked,
  and **Evidence pack** makes its pack for a period.
- **Audit**: **Export** downloads its history (versions published, deployments, approvals and who
  gave them), and **Evidence pack** as on Runs.
- **Versions**: **Export history**, the same as on its Audit page.

Choose the first and last day, and for calls and history an environment and CSV or JSON. What you
ask for opens under **Audit → Exports**, listed with that Decision's other exports; **Every export**
shows the whole organisation's again.

A small export downloads straight away. A larger one is prepared in the background: you get a
notification saying **Your export is ready**, and it waits under **Audit → Exports**. Files are kept
for seven days and then deleted; ask again for a fresh copy. Every export is recorded in the Change
history, with who asked and which filters. One export holds up to 50,000 calls or changes (5,000
with inputs); choose a shorter period for more.

From the command line, an agent or a script (a read-only token is enough):

```sh
typefuse export acme log --from 2026-09-01 --to 2026-09-30 --env production
typefuse export acme changes --format json --decision refunds
typefuse export acme/refunds evidence --from 2026-09-01 --to 2026-09-30
```

`--to` is the last day included. The command waits for a large export and saves the file under its
own name, or `--out`. The SDK has the same as `tf.exports` (`tf.exports.list(org, { decision })`
lists one Decision's), and agents connected over MCP have the `export_audit` and `get_export` tools
(`get_export` with `decision` lists that Decision's exports).

## How long records are kept

Every run stays in the log for the life of the organisation, with its answers, hashes and seal.

**A deployed Decision's calls don't keep their inputs** unless you ask: on Scale and Enterprise, an
owner or admin can keep inputs for every Decision (Settings → Security) or for one
(its Deployments page, "Calls' inputs"). A kept input is kept for the plan's retention: 90 days on
Scale, 365 days (or as agreed) on Enterprise. A call that didn't keep its input says so on its page;
the state it sent is rebuilt from the release and the input when the input is there.

| Where the call came from | Detail kept for |
| --- | --- |
| A deployed Decision, inputs not kept (the default) | Fingerprints only |
| A deployed Decision keeping inputs, on Scale | 90 days |
| A deployed Decision keeping inputs, on Enterprise | 365 days, or as agreed |
| The Sandbox, on every plan | 90 days |

Calls recorded before inputs became a setting keep their detail for the retention that applied
then (7 days on Free, 30 on Founder). Test runs, Evaluations, Test cases, Examples, Datasets and
Comparisons keep what they hold for as long as they exist, so a call's input that one of them still
uses is kept too.

Without its input, a run's page says the input wasn't kept (or, once its detail expires, that it is
no longer stored), and the answers and their proof stay with the run. Its seal still verifies,
because the hashes are kept, and `typefuse audit verify` still passes. A run without its input
can't be saved as a Test case or replayed in a Comparison.

TypeFuse backs up its data every day and keeps each backup for 30 days, after which it is deleted
automatically. Deleted data is removed from backups within 30 days: a call's expired detail, and
everything an organisation held once the organisation is deleted. The sealed copy of each call is
kept in locked storage for the plan's retention period from when it was recorded, then deleted
automatically; it can't be removed sooner, even when the organisation is deleted.

Expiry isn't switched on in production yet, so for now the detail of every call is still kept.
