Reliability & Consequence 23 September 2026 7 min read 1,631 words

Cancelled is not undone

The Agent2Agent protocol was built on a declared virtue — that a remote agent need never reveal its internal state, memory or tools. That was affordable when delegation meant asking for a value. A2A is a protocol for delegating actions, and its record has no place to put them.

The argument

A2A tells a caller that a delegated task stopped producing output, never that it stopped having effects, so the protocol cannot say whether there is anything to compensate.

Section 3.1.5 of the Agent2Agent specification describes what happens when you change your mind. "Requests the cancellation of an ongoing task. The server will attempt to cancel the task, but success is not guaranteed." Two reasons follow, both fair: the task may already have finished, or cancellation may not be supported at the stage it has reached. If the request does take, the task settles into TASK_STATE_CANCELED, one of four terminal states beside COMPLETED, FAILED and REJECTED.

Read that state slowly, because it says less than it looks like it says. It tells you the task will send you nothing further. It does not tell you that nothing was done. And in a 3,618-line specification there is no second field, no status message convention and no error code that closes the gap: search the document for compensation, rollback, undo, irreversible or side effect and you will not find any of them once. The word destructive appears exactly once, in an example, which we will come back to. Everything argued below is read from the two projects' own published specifications and issue trackers rather than from anyone's commentary on them, which makes the evidence unusually direct and also one-sided in a particular way: these are the documents the standards bodies chose to write.

This is not the familiar anxiety about an agent losing its own transcript. That is a memory problem, and it happens inside a system you own. This is the reverse, and it happens across a boundary you do not control: a caller who never had a record in the first place, because the agent that acted was somebody else's and the protocol connecting them was designed — deliberately, and for good reasons — not to carry one.

The design is not accidental, and A2A is unusually candid about it. The project describes itself in its README as "an open protocol enabling communication and interoperability between opaque agentic applications," and lists among its aims the ability for agents to "operate without exposing their internal state, memory, or tools." One of the four headline goals is Preserve Opacity: collaboration "without needing to share internal memory, proprietary logic, or specific tool implementations, enhancing security and protecting intellectual property." The specification restates it as a principle of Opaque Execution — agents collaborate on declared capabilities and exchanged information, "without needing to share their internal thoughts, plans, or tool implementations." All of that is defensible. A vendor exposing which internal systems its agent touched is exposing its architecture to a competitor, and an interop standard that demanded it would not have been adopted by anyone with a business to protect.

The difficulty is what A2A is for. The same specification distinguishes itself from its sibling protocol by saying it is "about how agents partner or delegate work," and the README is explicit that the point is agents collaborating "as agents, not just as tools." Opacity is a cheap promise when the remote thing is a function that returns a value. It becomes an expensive one when the remote thing is an autonomous system choosing its own means, running for hours, holding your credentials, and — this is the whole pitch — doing things you did not enumerate in advance.

What does come back is narrow and carefully specified. The core interaction model, per section 3.7, is that clients "send messages to initiate a task that produces one or more artifacts," and results "SHOULD BE returned using Artifacts" rather than messages. An artifact is defined in the glossary as "an output (e.g., a document, image, structured data) generated by the agent as a result of a task." Data, in other words. The agent card that advertises what an agent can do is built the same way: the specification's own skill example carries id, name, description, tags, examples, inputModes and outputModes. A skill declares which media types it will accept and which it will return. Nothing in it indicates whether invoking it spends money, sends an email, or cancels somebody's booking.

The specification is not unaware of this. It acknowledges it twice, and where it puts those two acknowledgements is the most telling thing in the document. Section 7.6 introduces in-task authorisation with two examples, the second being "an agent requiring human approval before a destructive action is taken" — handled by moving the task to TASK_STATE_AUTH_REQUIRED and waiting. That is a control that runs before, and only when the remote agent chooses to invoke it. Then, in the security considerations, under Audit and Monitoring: "Agents SHOULD provide audit trails for sensitive operations." A SHOULD, with no format, no field and no operation to retrieve it — an audit trail that lives inside the opaque agent, for the opaque agent's own benefit. Section 7.5 completes the picture by listing "actions attempted within tasks" as something an agent's authorisation logic MAY consider, immediately after declaring that logic implementation-specific. The protocol knows that tasks contain actions. It has decided, three separate times, that actions are somebody else's schema.

Meanwhile, look at where the engineering effort is going. The roadmap, last updated on 15 September, lists four near-term initiatives: v1.1 protocol enhancements, bidirectional streaming, a CLI for coding harnesses, and elicitation with multi-turn workflows. The first of those points at issue 1991, an epic titled "Coherent Task History — gaps in semantics, querying, and observability," carrying eleven child issues against the v1.1 milestone. Its six problem areas are worth listing, because each is a genuine defect and each is about the same thing: task history holds only Message objects, so artifacts cannot be interleaved chronologically; messages have no timestamps, so ordering is unreliable; historyLength is too blunt to page or offset; no event fires when history changes; there is no standard way to inject a pre-existing history; and there is no stable versioning field for detecting missed events or managing concurrency. This is careful, unglamorous, necessary work. It is also, all of it, about making the record of what was said precise, ordered, queryable and replayable. Eleven issues on the fidelity of the conversation. Zero on the existence of the consequences.

The contrast with the protocol next door sharpens this rather than softening it. MCP's tool definitions carry a ToolAnnotations object with four booleans: readOnlyHint, destructiveHint, idempotentHint and openWorldHint. They are weak — the schema itself says in a note that all of them are hints, "not guaranteed to provide a faithful description of tool behavior," and the specification instructs clients to treat annotations from untrusted servers as untrusted. But they exist, their defaults are conservative in the right direction (destructiveHint defaults to true, idempotentHint to false), and they give a caller somewhere to look. MCP describes a tool inside your own trust boundary and still thought consequence worth a field. A2A describes an autonomous peer across an organisational one and has none.

The strongest objection to all this is that I am asking a transport to carry business semantics, and that the history of distributed systems is unkind to people who try. Two-phase commit across company lines does not work. Sagas exist precisely because compensation is domain logic — refunding a payment, recalling a dispatch, reversing a ledger entry — and no general protocol can enumerate the compensations for every domain it might be used in. HTTP does not define undo either, and nobody considers that a flaw. On this reading, effects belong to the application layer, extensions are the correct escape hatch, and a protocol that tried to standardise consequence would be standardising something it has no competence to describe.

Nearly all of that is right, and none of it is a reason for the current position. Nobody needs A2A to perform a rollback. The gap is one level below compensation: the caller cannot tell whether there is anything to compensate. FAILED and CANCELED are, as far as the protocol is concerned, indistinguishable in the only respect that matters when you are deciding what to do next — whether the world moved. Two booleans on a skill, or a field on TaskStatus saying that external effects may have occurred, would not standardise anyone's domain logic. They would tell a client which of its own procedures to run. And the asymmetry in the operation semantics makes the point sharper than any argument could: section 3.3.1 states plainly that Cancel Task is idempotent, while Send Message — the one operation that causes an agent to act — merely MAY be idempotent, with duplicate detection resting on a messageId the agent "may utilize." The safe operation gets a guarantee. The consequential one gets a maybe.

For anyone building on A2A now, in the absence of that field, the practical move is unglamorous and should be written down as an assumption rather than discovered in an incident. Treat every task you delegate as having had effects unless the remote agent's contract — not its agent card — says otherwise. Keep your own ledger of what you asked for, keyed by messageId, before the request goes out, because it is the only record either party is obliged to let you read. Negotiate compensation out of band, in the commercial agreement, where the words refund and reversal already exist. And treat TASK_STATE_CANCELED as the beginning of an investigation, not the end of one.

Delegation between organisations has always rested on two things: instructions going out, and an account coming back. We have spent two years building superb machinery for the first half. The industry's most carefully specified way of handing consequential work to a stranger currently returns a beautifully ordered transcript of the conversation, and no account at all.

What this is argued from

Reporting and primary material the piece rests on, dated at the time of writing. The interpretation is mine; the facts belong to these.

  1. A2A Protocol Specification — docs/specification.md, sections 3.1.5, 3.3.1, 3.7, 7.5, 7.6, 13 (read at commit f63dbb4) A2A Project / Linux Foundation / GitHub · 2026-08-28
  2. A2A Protocol — README.md, design goals and governance A2A Project / Linux Foundation / GitHub · 2026-09-23
  3. A2A protocol roadmap — docs/roadmap.md, near-term initiatives A2A Project / GitHub · 2026-09-15
  4. Epic — Coherent Task History: gaps in semantics, querying and observability, issue 1991, milestone v1.1 A2A Project / GitHub · 2026-06-25
  5. A2A Protocol releases — v1.0.0 and v1.0.1 A2A Project / GitHub · 2026-05-28
  6. Model Context Protocol — ToolAnnotations in schema/2026-07-28/schema.ts Model Context Protocol / GitHub · 2026-09-23
  7. Model Context Protocol — Tools, 2026-07-28 specification Model Context Protocol / GitHub · 2026-09-23

Editorials on this site are written to be argued with. If you think the reading is wrong, it probably is in some particular way, and that is the useful part.

agentsprotocol designdelegationaccountabilityinterop