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

# Clean context

> Every document an agent retrieves is an instruction it was never told to distrust. Taint is tracked by provenance, and it propagates forward.

An agent reads a document. The document contains a sentence addressed to the
agent. The agent does what the sentence says.

That is the whole attack, and it keeps working because language models have no
channel separation. Your system prompt, the user's request and the retrieved
document are the same kind of thing by the time they reach the weights.

## The question that has an answer

Do not try to decide whether a document is malicious. You cannot do it
reliably, and every hour spent there is an hour not spent on the question that
is answerable:

> Which parts of this trajectory came from somewhere we do not control, and does
> the action about to happen require that they had not?

Provenance is a fact about your architecture, not a judgement about content. You
know whether a document arrived from a customer upload or from your own curated
store.

## Marking it

Retrieval and tool steps carry a `trusted` flag, and it defaults to **false**.
The default matters: an integration that forgets to think about provenance
records the safe answer rather than the convenient one.

```python theme={"system"}
with rs.agent("doc-analyst").trajectory(document="DOC-9001") as t:
    t.retrieval("upload:DOC-9001")                       # untrusted
    t.retrieval("policy-store:v4", trusted=True)         # ours
    t.tool_call("crm.lookup", trusted=True)
```

## Taint propagates forward

If step 0 read an unverified document, step 4 is downstream of unverified
content whether or not it looks like it. Once that is tracked, a policy becomes
expressible without detecting anything:

> This agent may summarise a document containing untrusted content. It may not
> initiate a payment in the same trajectory.

A grant sets that requirement in `conditions`. When the action arrives, gate 5
checks it and returns `gated` if the trajectory is not clean.

## Not every action needs a clean context

Treating all taint as fatal is the mistake in the other direction. Reading a
customer's email in order to answer it is the job, and refusing on those grounds
is refusing to work.

The requirement belongs on the **action**, not on the agent. Summarising is
fine. Moving money, changing configuration, disclosing data, closing a case
without review: those are where the question deserves an answer before rather
than after.

## Discharging taint

Where a sanitisation step genuinely removes the risk, record it:

```python theme={"system"}
t.sanitise("prompt-injection", method="strip-instructions")
```

This is a claim you are making, and it is recorded as yours. It does not launder
the provenance; it states that a named control ran, so a reviewer can judge
whether it was sufficient.

## What the record says

Three fields, and the third is the one teams forget:

* **which** content was untrusted, by source, not a boolean on the trajectory
* **where** it entered, by step index
* **whether the decision downstream of it was allowed to stand**

The third is the list you review when something turns out to have gone wrong.

Here is a real one from the demo:

```
doc-analyst:DOC-9001:p2   ·   GATED
untrusted: upload:DOC-9001 (unverified_retrieval, step 0)
the grant requires a clean context; this one read an untrusted document
```
