# Evidence in an agent system

Evidence is the artefact that would convince a sceptic the claim is true: a provider's own acknowledgement, the source a statement came from, the rule a decision was made under. An agent system full of unevidenced claims is not slightly less trustworthy than one with evidence — it is a different kind of system, because none of its assertions can be checked after the fact.

- **Status:** Reference
- **Audience:** both, developer
- **In the app:** #/activity, #/autonomy-audit
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/technology/evidence/

## Three claims and what each needs behind it

| Claim | Not evidence | Evidence |
|---|---|---|
| The message was sent | The send function returned without raising | The provider's own acknowledgement, stored with the message |
| This is our returns policy | The model produced it fluently | The Knowledge source or Fact it was drawn from |
| This prospect works at that company | A plausible address pattern | A published page or record naming them there |
| Connect chose not to reply | A gap in the log | The recorded decision and the rule it was made under |

The middle column is what most systems actually store, and each entry in it fails in the same direction: it records that the software believed something, not that it happened. The distance between those two is where the incidents come from.

## Does Connect use evidence?

**Used**, as a rule about state rather than as a logging habit. The clearest case is sending. A message is not marked sent because the code path finished; it is marked sent when the provider acknowledges it, and until that acknowledgement arrives the state is *uncertain* rather than *sent*. `outbound.py` is the single boundary both the engine and a person's own send go through, so there is one place the rule is enforced and one place to read it. [Why 'sent' must require provider evidence](/research/provider-evidence-for-sent/) is the longer argument.

Three more places the same rule shows up. Prospecting stores the evidence a conclusion rests on and **never guesses an email address** — a pattern that looks right is not a source (`prospect_evidence.py`, `prospect_contacts.py`). Files created or modified by Connect are written as **new versions with provenance**, so what changed and what it was derived from survives. And the [audit trail](/docs/technology/audit-log/) records what was decided, by what, under which rule, and what happened — **including refusals**, because a refusal is a decision and a system that logs only its actions cannot explain its silences.

## Attaching it so it survives

1. **Store it with the record, not in a log line.** A log is rotated, sampled and eventually deleted; the acknowledgement belongs on the message it acknowledges.
2. **Store the identifier the provider issued**, not a rendering of it. It is what you will quote when you ask them what happened.
3. **Store the rule as well as the outcome.** 'Held' is not explicable a month later; 'held because autonomy on this channel was ask-before-send' is.
4. **Record the negative.** Refusals, declines and suppressions are the evidence that a control worked.
5. **Keep it immutable.** Evidence that can be edited to match the current story is a narrative.

> **Careful** Reconstructing evidence later is not evidence. If a value can be recomputed from today's configuration it tells you what the rules are now, not what they were when the decision was taken — and that difference is exactly what is in dispute when anyone asks.

## What an unevidenced claim costs

**Operationally** — A customer says they never received it. With no acknowledgement you cannot tell a delivery failure from a send that never happened, and the two have opposite fixes.
**Commercially** — A promise nobody can trace is honoured or argued about. Both are more expensive than a stored source.
**For the agent itself** — Without stored evidence a retry cannot know whether the first attempt succeeded, so the safe options are to duplicate or to drop.
**For trust** — One discovered invention costs more confidence than a hundred correct answers earn. Evidence is what lets you show the difference rather than assert it.

## Questions

### Is a timestamp evidence?

Only of when a row was written. It says nothing about whether the thing the row describes happened, which is why 'sent at' from the application clock and a provider acknowledgement are not interchangeable, however similar they look side by side in a table.

### Why record refusals?

Because the interesting question months later is usually why nothing happened. A trail that holds only successful actions makes every gap ambiguous — a deliberate hold and an outage look identical. Recording the refusal with its rule is what makes a control demonstrable.

### Does evidence have to be visible to a customer?

No, and mostly it is not. It has to be visible to whoever must answer for the decision — an operator on the activity trail, a developer reading the record. What matters is that it exists before it is needed, since it cannot be created afterwards.

## Related

- [Why 'sent' must require provider evidence](https://connectbyjbrh.com/research/provider-evidence-for-sent/)
- [Provenance](https://connectbyjbrh.com/docs/technology/provenance/)
- [Audit logs](https://connectbyjbrh.com/docs/technology/audit-log/)
- [Evidence-first prospecting without guessed emails](https://connectbyjbrh.com/research/evidence-first-prospecting/)
- [Grounding](https://connectbyjbrh.com/docs/technology/grounding/)

## What this page is based on

- Connect architecture source pack — docs-source/sources/GENERAL.md §5 and §9, the audit trail and file provenance
- Connect capability registry (docs-source/facts.py) — send_evidence, audit_trail, prospect_evidence, no_guessed_email
- `backend/app/outbound.py`, `audit.py` — the send boundary and the decision record
