> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usecompassai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Audit trail

> Every tick, every plan, every check — recorded as a structured EvaluatorThought, including the ticks that did nothing.

> The audit trail is what makes "glass box" more than a slogan. Every evaluation the agent runs — successful, rejected, or no-op — is written as a structured `EvaluatorThought` with all the inputs needed to replay it.

This page covers what gets recorded, where it lives, and how to read it. For
how thoughts are produced, see
[The deterministic loop](/architecture/deterministic-loop).

<img src="https://mintcdn.com/compassai/Qq7UDvjWweIau4hP/images/audit-trail-diagram.svg?fit=max&auto=format&n=Qq7UDvjWweIau4hP&q=85&s=cc7331808c62dddd81f37594ddb048d5" alt="audit trail diagram" className="rounded-lg" width="1500" height="800" data-path="images/audit-trail-diagram.svg" />

## What gets recorded

Every `EvaluatorThought` is written to the trail, regardless of outcome.
This includes the ticks that decided to do nothing. The "did nothing" ticks
are often the interesting ones — they show *why* the agent stayed put when
yields shifted.

A complete `EvaluatorThought` record contains all five fields from a tick:

```json theme={null}
{
  "thought_id": "th_01HXYZ...",
  "account": "0x7f3a...",
  "ticked_at": "2026-05-26T04:12:37.142Z",
  "trigger": {
    "type": "yield_update",
    "source": "<lending_protocol>:<l2_chain>",
    "old_apr_bps": 412,
    "new_apr_bps": 487
  },
  "load_state": {
    "positions": [...],
    "balances": {...},
    "policy_snapshot_hash": "0x..."
  },
  "fetch_yields": {
    "snapshot": [...]
  },
  "propose": {
    "outcome": "new_route",
    "candidate": {...}
  },
  "check_policy": {
    "outcome": "approved"
  },
  "emit": {
    "type": "signed_call",
    "tx_hash": "0x...",
    "gateway_intent_id": "gi_..."
  }
}
```

Three properties make this useful:

* **The full inputs are captured**, not just the decision. A reader can
  re-run the evaluator against `load_state` and `fetch_yields` and verify
  the same `propose` output.
* **The `trigger` field shows why this tick ran at all.** This is what
  closes the loop on the event-driven scheduler — every record explains
  what woke it up.
* **The `emit` field links to the on-chain artifact** when one exists.
  `tx_hash` for the smart account call, `gateway_intent_id` for the
  cross-chain settlement.

## Five categories of records

The audit trail covers five kinds of events:

| Category            | Source             | What it records                                                |
| :------------------ | :----------------- | :------------------------------------------------------------- |
| **Tick — executed** | Deterministic loop | A complete `EvaluatorThought` ending in a signed call.         |
| **Tick — rejected** | Deterministic loop | A `EvaluatorThought` ending in a `PolicyRejection`.            |
| **Tick — no-op**    | Deterministic loop | Yields changed but no better route exists under current rules. |
| **Chat plan**       | Chat agent         | A user-originated plan, with the prompt that produced it.      |
| **Policy update**   | Owner action       | A rule change, with old and new policy snapshot hashes.        |

Each category uses the same record shape — only the `trigger` and `emit`
fields differ. This means a single query language works across all of them.

## What's not in the trail

Some things are deliberately excluded:

* **LLM raw output for non-chat ticks.** Most ticks don't involve the LLM
  at all. The few that do (chat plans) record the prompt and the resulting
  structured `Plan`, but not the internal LLM tokens.
* **Yield-source raw payloads.** The `fetch_yields` snapshot stores
  normalized rates, not the underlying API responses. The adapter
  contracts and their version hashes are recorded, so a reader can
  reconstruct the raw payload if needed.
* **User PII.** The trail keys on the smart account address, not on any
  off-chain user identifier.

## Where the trail lives

Audit data is stored in two places:

* **Off-chain database, owned by the Compass backend.** This is where the
  full `EvaluatorThought` records live, indexed for query.
* **On-chain transactions.** The `emit` field of any executed tick is a
  real on-chain transaction. These are independently verifiable on Arc and
  on the target chain regardless of what the off-chain database says.

This means: **the off-chain database is the detailed record; the on-chain
transactions are ground truth.** The two should always agree. If they ever
disagreed, the chain wins — every executed `EvaluatorThought` is anchored
by a real `tx_hash` that anyone can independently verify on the block
explorer, regardless of what the Compass database says about it.

What the off-chain trail adds is everything *around* the transaction —
the inputs that led to the decision, the rejected alternatives, the no-op
ticks, the reasoning. None of that is on-chain. Reading it requires
trusting that the Compass backend recorded it faithfully.

<Info>
  The off-chain trail is not cryptographically anchored to the chain. The
  guarantee is operational, not trustless: the Compass team commits to
  storing and serving these records accurately, and the on-chain
  transactions exist independently as a check on any executed decision.
</Info>

## Reading the trail

The dashboard surfaces the trail for the connected account in three views:

* **Timeline.** Reverse-chronological list of all five record categories,
  filterable by category and date.
* **Per-position history.** All ticks that touched a specific position,
  from the open through every rebalance and to the close.
* **Rejected plans.** Just the `Tick — rejected` and the rejected `Chat
  plan` records, with the failed rule name visible. Useful for
  understanding why the agent didn't do something a user expected.

Every record in any view links to:

* The `tx_hash` on the appropriate block explorer.
* The `gateway_intent_id` on Circle's intent viewer (when relevant).
* The full JSON for download.

## Replaying a decision

Because the `EvaluatorThought` captures all inputs, any past decision can
be replayed. The flow:

1. Export a `EvaluatorThought` from the dashboard or query the trail API.
2. Identify the evaluator binary version from the record's
   `evaluator_version` field.
3. Run that version of the evaluator against the recorded `load_state` and
   `fetch_yields`.
4. Verify the output matches the recorded `propose` and `check_policy`.

If the output differs, either the evaluator has a non-determinism bug, the
recorded inputs are incomplete, or the binary version is wrong. All three
are bugs we want to know about.

This is the property that makes "why did the agent do that?" answerable
with a deterministic trace rather than an LLM-generated explanation.

## Retention and access

* **Retention.** Records are kept indefinitely during the testnet phase.
  Retention policy for mainnet is not yet finalized.
* **Access.** The trail for an account is visible to the owner of that
  account via the dashboard. There is no admin view that lets the Compass
  team browse other users' trails.
* **Export.** Owners can download their full account trail as JSON from
  the dashboard. Useful for tax reporting, auditing, or simply keeping a
  copy outside Compass.

<Info>
  The Compass team can access aggregate metrics (number of ticks across all
  accounts, error rates, latency distributions) but not the contents of
  individual records without owner consent. This is enforced at the
  database access-control layer.
</Info>

## Next steps

<CardGroup cols={2}>
  <Card title="The deterministic loop" icon="repeat" href="/architecture/deterministic-loop">
    Where EvaluatorThoughts are produced.
  </Card>

  <Card title="Policy engine" icon="shield-check" href="/architecture/policy-engine">
    How rejections become structured records.
  </Card>

  <Card title="Trust & security model" icon="shield" href="/overview/trust-security">
    What the trail does and doesn't prove about Compass's behavior.
  </Card>

  <Card title="System overview" icon="layers" href="/architecture/system-overview">
    The full three-layer picture, with audit as the dashed cross-cut.
  </Card>
</CardGroup>
