Recording who approved

An agent that pauses for a person leaves a record of the pause. It does not usually leave a record of the person. That gap is invisible while everything works and total the moment anybody asks.

The question asked afterwards is never whether a pause occurred. It is who decided, on what basis, and how anyone knows it was them. A record that answers the first and not the rest describes a procedure rather than an event.

What an approval has to carry

Four properties, and each exists because a reader cannot otherwise detect its absence.

  1. The action, and its risk class, from outside the model. If the system proposing the action also decides how dangerous it is, there is no gate, only a suggestion. The class belongs in a registry or a policy file the proposing model cannot write to.
  2. A person, named. Not that a human approved. Which one, or which named role holder.
  3. That name taken from authentication. An identity supplied in a request body, or produced by the model, is an assertion about a person rather than a fact about one.
  4. The approver distinct from the proposer. An agent's own credential signing off its own action satisfies every other requirement and is worth nothing.

A refusal is worth the same care. A system that records only what it did is a receipt, and the interesting question is usually what it was stopped from doing.

Where the identity has to come from

It is tempting to take the approver from whatever state the run is carrying, because the value is already there. That value identifies the person the run was started for, which is not necessarily the person who answered, and anything able to write to that state can set it.

The identity exists in exactly one place at exactly one moment: the authenticated request that submits the decision. Read it there, and record it with the outcome.

def submit_decision(thread_id, approved, session):
    approver = session.user          # from the auth layer, not from state
    record.approval(
        decision=thread_id,
        approver={"id": approver.id, "kind": "human"},
        identity_source="auth-session",
        verdict="permitted" if approved else "refused",
    )

Nothing above is specific to any framework, and none of it needs any particular software. It is the shape of the problem.

The approval nobody came back to

An approval that is never answered is the case every design forgets, and it is the common one. The person was on leave, the queue was not monitored, the run that raised the pause died. What the record says afterwards decides whether the gap is a fact or a hole.

The usual answer is a deadline: give the request an expiry, and treat it as lapsed once the deadline passes. That is right and it is not enough, because it leaves two questions open.

  • Who notices? If the deadline is only evaluated when something reads the row, and the thing that would read it is the run that died, nothing ever evaluates it. The request sits in a state that is neither approved nor refused, indefinitely, and the record shows a proposal followed by silence.
  • What is written? A request that quietly disappears at its deadline leaves the same evidence as one that was never made. A reader afterwards cannot tell an action nobody got to from an action nobody proposed.

Both close the same way: expiry is a refusal, and it is evaluated at the door.

  • An expired request is refused, with a reason, in the record. Not dropped, not left pending. "Nobody answered before the deadline" is a fact about what happened and it belongs beside the approvals, carrying the same weight. A system that records only the requests somebody got to is describing its own attentiveness rather than its behaviour.
  • Expiry is settled before any read and before any decision, rather than by something that has to still be alive to run. Then it does not matter that the originating run is gone: nobody can act on an expired request, because the act of looking settles it first. The liveness problem becomes a property of whoever reads next, and somebody always reads eventually, or the record was never going to be examined at all.
  • There is no option for never. A request that can wait forever is a pending state that can outlive the system that made it, and a policy of "expires: null" is how a queue silently becomes a list of things nobody has to answer for.

The test is a question a reader can put to any queue: pick a request from six months ago that nobody answered. What does the record say about it now? If the answer is "it is still pending", the record cannot distinguish a decision that was never taken from one that was never needed.

What this looks like in practice

Agent frameworks generally pause and resume by passing a value back into a paused run. The value says what was decided. Most of them model no principal on that boundary at all, so any code holding the handle can resume it, including the process that raised the pause.

That is not a defect in those frameworks. They are orchestration libraries and they never claimed to be authorisation layers. It does mean that an approval flow built on them produces, by default, a record in which somebody who read the arguments and decided is indistinguishable from a script that approved everything.

How widespread this is was measured rather than assumed. Of eight agent memory and agent framework implementations assessed in September 2026, six take or gate actions. Against the question of whether an approval identifies a person or a named role holder, four were assessed absent and one could not be established either way. The assessment includes the author's own implementation, which is the single entry that passes, and states that this entry carries no evidential weight. Every verdict cites a file and a line at a named commit, so any of them can be overturned by pointing at code.

Why it is becoming urgent

Obligations for high-risk systems under the EU AI Act began applying on 2 August 2026, and Article 14 requires oversight by natural persons who can understand, interpret, decide against, and intervene. The harmonised standard that will say what satisfies that, prEN 18229-3, is still at public comment. Deployers are being asked for evidence of oversight before the document defining that evidence exists.

A record that names the approver is not compliance, and nothing here claims it is. Whether a deployment satisfies a legal obligation is a matter for the parties to it and their regulator. But an organisation that cannot say who approved an action has no answer to give, whatever the standard eventually says.

The record format

These four properties are levels TR-3 of the Testimony Record, which is published as an Internet-Draft and carries a validator anyone can run. Implementing it costs nothing and requires no permission. A record can be checked in a browser without installing anything.