# Why your own logs are not evidence

A log records what a system did. Evidence is something another party can check without taking your word for it. A log you write and keep yourself is the first and not the second, for three reasons.

This guide goes through the three, says what write-once storage and a SIEM change, and ends on what a third party can check with one command, and what that still does not prove.

## Three things a log cannot rule out

The person asking is an auditor, a customer's security team or a regulator. They were not there when the agent ran. They have the log and your account of it.

### An edit

A line in a log file or a row in a table can be changed by anyone with write access: an engineer, an administrator, the application itself. A changed line looks like any other line. The reader cannot tell the amount was `180` when the agent approved the payout and `1800` in the file they were given, or the other way round.

### A drop

A missing line leaves nothing behind. If the agent made ten tool calls and the log shows eight, the log is still a well-formed log. Nothing in it says how many lines there should be, so the reader cannot tell a complete log from one that was thinned out, or from one where a tool was never logged in the first place.

### A backdate

The time on a log line is what the writer's clock said, or what the writer typed. A line written this morning can carry last week's date. The reader has no way to tell when the line came to exist, only when it claims to have.

None of this says anyone did edit, drop or backdate anything. The problem is that the log cannot show they did not.

## Write-once storage and a SIEM

Teams often answer with two things they already have, and both are worth having.

Write-once storage, such as S3 Object Lock, does one thing well: once written, an object cannot be changed or deleted before its retention date, even by an administrator. That deals with an edit after the write. A SIEM is good at collecting events and alerting on them, and it keeps a second copy away from the application.

Neither proves anything to a third party. The bucket and the SIEM are yours, so an auditor has to take your word for what went in: a record you never wrote, or wrote late with an earlier date, or left out, looks the same as a complete log.

| | Edit after writing | A record left out | Written late, dated early |
|---|---|---|---|
| Your own log | not shown | not shown | not shown |
| Write-once storage | prevented | not shown | not shown |
| A SIEM | a second copy to compare | not shown | not shown |

## What a third party can check

Three additions close the three gaps, and none of them can come from a store you control:

- **A signature and a chain.** Each record is signed with the agent's own key and carries the hash of the record before it. An edit breaks the signature or the content hash; a removed record breaks the chain.
- **An independent co-signature.** A second party signs each batch of records and the newest record of each agent. Neither you nor that party can change a record alone, and the signed head shows that nothing was cut from the end.
- **Public time bounds.** Each batch is written after a public randomness round and before a public timestamp, so a record has an earliest and a latest time that do not rest on anyone's clock.

This is what a signafAIde record is. The side-by-side table is on [Compared with your own logs](/docs/compared), and [How it works](/how-it-works) says where each part happens.

## The same three changes, tried on signed records

An agent with three tools was run once and its ten local records verified. Then each change was made by hand to a copy of the chain file, and `signafaide verify` was run again. These are the lines that changed in its output.

The amount in one decision changed from `180` to `1800`:

```text
12. Content hashes               FAIL         10 records
      - _pending/nokey/claims-bot#9: content hashes to d66d65371209648672ef8be13db4d0e4ac7610a876292dc99187c2c03f587f8c, envelope says cd06903ab65da6340b878e7c052837d234d408c4c1c600f063979ddafb62de51
FAIL: 1 of 12 checks failed (content hashes), 3 passed, 8 not checked
```

Two records removed from the middle:

```text
 4. Agent chains                 FAIL         8 records
      - _pending/nokey/claims-bot#9: the local chain is missing seq 7..8
FAIL: 1 of 12 checks failed (agent chains), 3 passed, 8 not checked
```

The time of one record moved back a day:

```text
 3. Client signatures            FAIL         10 records
      - _pending/nokey/claims-bot#9: signature does not verify
 4. Agent chains                 FAIL         10 records
      - _pending/nokey/claims-bot#9: time 2026-11-13T09:00:00.000Z is earlier than the time of seq 8 (2026-11-14T23:04:08.926Z)
      - _pending/nokey/claims-bot#10: prev does not equal the record_hash of seq 9
FAIL: 2 of 12 checks failed (client signatures, agent chains), 2 passed, 8 not checked
```

These runs were local, before anything was co-signed, and that matters. On a machine that holds the agent's key, a person who rewrites the whole chain and signs it again gets a chain that passes. Signing alone catches a careless or partial change, not a determined owner. The co-signature and the public timestamp are what take the owner's word out of it, and they exist only once the records have been sent to a witness.

## The verify command

For a period, the auditor downloads the pack with your agent keys and head file and runs one command on their own machine:

```bash
npx signafaide verify pack.json \
  --keys https://<service>/.well-known/signafaide-keys.json \
  --agent-keys agent-keys.json \
  --head head.json
```

It prints one line per check, then `PASS` or `FAIL` with how many of the 12 checks passed, are pending or were not checked. A check that was not run is never counted as passed. The verifier is open source, so the result does not rest on the word of the service or of the customer. What each check means is in [Verify](/docs/verify), and the worked example is in [A tamper-evident audit trail for an agent in ten minutes](/docs/guides/audit-trail-in-ten-minutes).

## The limits

- **Evidence, not certification.** A record proves who signed it, that it has not changed and when it existed. It never says whether the decision was right, and it does not make a system compliant.
- **Only what goes through it.** Recording covers the tool calls that pass through a wrapped tool or the gateway. A call made around them leaves no record. The signed tool list lets a reader see which tools are recorded: see [Tool coverage](/docs/coverage).
- **Time is a window.** The proven time of a record is the window between the randomness round and the public timestamp of its batch, not the time the agent's clock claimed.
- **Keep the rest.** Write-once storage and a SIEM still do their own jobs. You can keep writing to both; the records verify the same.
