A2A Expectations Extension, Version 1
Extension URI: https://rsaxb.com/a2a/expectations/v1
Status: Draft. Published 2026-09-05.
Editors: RSA Cross Border.
Independent extension. Not published by, endorsed by, or affiliated with the
A2A project. It is published under a URI its authors control, which the
A2A extension governance
permits without registration. The a2aproject URI prefixes are reserved for
artifacts that have been through that project's process; this one has not.
Companion: the Learnables extension is independent of this one. Neither requires the other; §16 says where they touch.
Feedback: the reference implementation and the issue tracker are maintained by RSA Cross Border. Comments are welcome.
Paragraphs marked Rationale are non-normative and may be skipped.
1. Abstract
Every state change in A2A is caused by something arriving: a message, an answer, an event, a cancellation. Nothing in the protocol lets the passage of time cause one. An agent that asks a question waits for the answer indefinitely. An agent that knows a document is due on Thursday has no way to say so, and no way to be told on Friday that it did not come. The failures that cost the most in the domains A2A is being deployed into — logistics, finance, support — are absences, and an absence does not emit an event.
This extension defines:
- how an agent raises an expectation — a statement, attached to the work it has done, that a named fact about a named subject is due by a stated time;
- how an expectation is satisfied, deterministically, by a fact arriving, and how a satisfied step re-anchors the steps that depended on it;
- the three ways an expectation lapses — overdue, skipped, and stalled — and the requirement that each lapse becomes a new task for the agent that raised it, under the same context, rather than a silent condition;
- the watcher role: the party that keeps time, which in most deployments is not the agent;
- the rules that keep unattended, time-triggered work from acquiring authority nobody granted it, and from firing forever.
It does not define a scheduler, a cron syntax, a task deadline, or a long-running task. It does not put a clock in the agent. It says what an agent may declare about the future and what the protocol does when the future fails to arrive.
2. Status of this document
This is a Draft. Field names and semantics MAY change.
A stable release of this URI is announced by setting status to stable in the
extension descriptor (Appendix A). Breaking changes are published under a new
URI, never by amending this one (§15).
3. Conformance
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals.
Three roles carry requirements:
- a conformant agent raises expectations and answers for their lapses;
- a conformant watcher keeps time: it records expectations, matches facts to them, and submits a lapse task when time runs out;
- a conformant client reads expectations and renders them, and MAY report facts.
One implementation MAY fill more than one role. In the reference deployment the client and the watcher are the same application; the agent is neither.
4. Motivation
A2A specifies the moment work is requested and the moments it produces something: a status, an artifact, a question. Between those moments the protocol is silent, and it has no vocabulary for the case where the next moment never comes. Implementations meet that in one of four ways, all in production somewhere:
- Wait. A task in
TASK_STATE_INPUT_REQUIREDstays there. Nothing in the protocol expires a question, so a question nobody answers is a task nobody closes. - Bolt a scheduler on. A cron job outside the protocol wakes up, queries the agent's store directly, and pokes it. The agent's knowledge of what was supposed to happen lives in the cron job's SQL, invisible to any client and to the agent itself.
- Give the task a deadline. A deadline bounds how long the task may run. It says nothing about the world: a customs entry can be filed on time and the release still not come.
- Hold the task open until the world responds. A task that stays
WORKINGfor four days, waiting on a carrier, is a task that cannot be reasoned about, listed usefully, or resumed on a host that restarted.
The A2A maintainers have already described the shape they prefer for recurring and deferred work: not a new state, but a new task under the same context, created when the trigger fires (a2aproject/A2A#654). This extension takes that shape and specifies the trigger. The agent states what it expects and by when; a watcher holds the clock; when the clock runs out, the watcher submits a task and the agent decides what the silence means.
The agent expects. The watcher keeps time. The agent answers for the lapse.
Rationale. Two things are deliberately kept out of the agent. The first is the clock: many agents cannot hold one, being serverless, heartbeat-driven (#1667), or simply not running between requests. The second is the decision that a lapse is unimportant. An expectation the agent raised and then quietly let go is indistinguishable, in the record, from one that was met. The lapse task exists so that the decision to do nothing is itself a task with a history.
5. Terminology
Expectation — a statement raised by a task that a named fact about a named subject is due by a stated time. Immutable once raised.
Subject — the thing the expectation is about: a shipment, an invoice, a case. Identified by type and id; opaque to the watcher.
Fact — an observation that something happened, carrying a key. A fact
satisfies an expectation when its key matches the expectation's satisfiedBy.
Satisfaction — the watcher recording that a matching fact arrived. Monotonic: a satisfied expectation does not become unsatisfied.
Due — the instant by which the fact is expected. Grace is the period after due during which the watcher waits before declaring a lapse.
Anchor — an earlier expectation whose satisfaction fixes this one's due time. An anchored expectation carries a projected due time at raising and a current due time once its anchor is satisfied.
Horizon — an instant after which continued silence on the subject is itself a lapse, regardless of individual expectations.
Lapse — the watcher's determination that an expectation will not be met in the ordinary way. Three kinds: overdue, skipped, stalled (§9.1).
Lapse task — the A2A task the watcher submits to the agent when an expectation lapses.
Watcher — the party holding the clock and the record of expectations. MAY be the agent; in the reference deployment it is the client application.
Withdrawal — the closing of an expectation without satisfaction and without lapse, because the task that raised it was canceled or a later task superseded it.
6. Extension declaration
6.1 The AgentExtension entry
A conformant agent MUST declare the extension in capabilities.extensions with
uri set to this document's extension URI, and required set to false.
Rationale. Nothing here changes the meaning of a core A2A request. A client that does not read expectations receives the same artifacts and the same questions; it just cannot see what the agent is waiting for.
The declaration is carried in params:
{
"capabilities": {
"extensions": [
{
"uri": "https://rsaxb.com/a2a/expectations/v1",
"description": "States what this agent expects to happen next for a shipment, and by when, so that a step that never happens is noticed.",
"required": false,
"params": {
"keepsTime": false,
"lapseSkill": "handle_lapse",
"kinds": [
{
"kind": "shipment.manifest",
"subjectType": "shipment",
"describes": "the airline manifest for a booked shipment",
"basis": "observed",
"skills": ["book_shipment", "recheck_booking"]
},
{
"kind": "question.answer",
"subjectType": "task",
"describes": "a person's answer to a question this agent asked",
"basis": "declared"
}
]
}
}
]
}
}
| Field | Type | Required | Meaning |
|---|---|---|---|
keepsTime | boolean | yes | Whether the agent runs its own clock (§12.2). false asserts that no expectation this agent raises will lapse unless a watcher makes it. |
lapseSkill | string | yes | The skill id a lapse task invokes. MUST name a skill on the card. |
kinds | ExpectationKind[] | yes | What this agent expects, by kind. MAY be empty, which asserts the agent understands the extension and currently expects nothing. |
6.2 The ExpectationKind object
| Field | Type | Required | Meaning |
|---|---|---|---|
kind | string | yes | Identifier for this class of expectation. MUST be unique within one declaration. Dotted names are conventional, not required. |
subjectType | string | yes | What kind of thing the expectation is about. |
describes | string | yes | What is expected, in a person's words. MUST NOT be a placeholder. |
basis | string | yes | Where the due times for this kind come from: "observed", "contract", or "declared" (§13.3). |
skills | string[] | no | Skill ids whose tasks may raise this kind. Absent means any. |
Rationale. basis is required because a due time is a claim about the world
and a person reading a lapse is entitled to know whether it came from what the
lane actually does, from what was sold, or from somebody's guess. The three
produce very different amounts of noise, and the noise is the way this whole
mechanism fails (§13.3).
7. Activation
The declaration in §6 is data-only. A client MAY read it without activating anything, and an agent MUST publish it whether or not any client activates.
Raising expectations (§8), reporting facts
(§9), and submitting lapse tasks
(§10) are profile behaviour. A client or watcher MUST
request them by including the extension URI in the A2A-Extensions request
header, and a conformant agent MUST echo activated URIs in the response header.
A2A-Extensions: https://rsaxb.com/a2a/expectations/v1
An agent MUST NOT emit an expectation to a client that has not activated the extension.
Rationale. An expectation nobody is watching is a promise made to an empty room. The activation is how the agent learns there is a watcher; raising expectations without one produces a record that looks kept and is not.
Activation is not authorization; see §13.1.
8. The Expectation object
An agent raises an expectation by attaching it to an Artifact, in the
Artifact's metadata keyed by this extension's URI. A status-update Message
MAY carry one in the same way (§11).
{
"artifactId": "booking-7f3a",
"name": "Booking confirmation",
"parts": [{ "text": "Booked on EK203 departing DXB 2026-09-11 02:15Z" }],
"extensions": ["https://rsaxb.com/a2a/expectations/v1"],
"metadata": {
"https://rsaxb.com/a2a/expectations/v1": {
"expectations": [
{
"expectationId": "exp-01J8Q0MANIFEST",
"kind": "shipment.manifest",
"subject": { "type": "shipment", "id": "PA-2026-0901" },
"expects": "the airline manifest for PA-2026-0901",
"satisfiedBy": { "factKey": "shipment.manifest.received:PA-2026-0901" },
"dueAt": "2026-09-10T20:15:00Z",
"grace": "PT2H",
"basis": "observed"
},
{
"expectationId": "exp-01J8Q0DEPART",
"kind": "shipment.departure",
"subject": { "type": "shipment", "id": "PA-2026-0901" },
"expects": "a departure event for EK203",
"satisfiedBy": { "factKey": "shipment.departed:PA-2026-0901" },
"dueAt": "2026-09-11T03:15:00Z",
"grace": "PT6H",
"basis": "observed",
"after": ["exp-01J8Q0MANIFEST"]
},
{
"expectationId": "exp-01J8Q0ARRIVE",
"kind": "shipment.arrival",
"subject": { "type": "shipment", "id": "PA-2026-0901" },
"expects": "an arrival event at DOH",
"satisfiedBy": { "factKey": "shipment.arrived:PA-2026-0901" },
"dueAt": "2026-09-11T05:00:00Z",
"grace": "PT6H",
"anchor": { "expectationId": "exp-01J8Q0DEPART", "offset": "PT1H45M" },
"basis": "observed",
"after": ["exp-01J8Q0DEPART"],
"horizon": "2026-09-13T05:00:00Z"
}
]
}
}
}
| Field | Type | Required | Meaning |
|---|---|---|---|
expectationId | string | yes | Agent-generated. MUST be unique among expectations the agent has ever raised. |
kind | string | yes | MUST name a kind declared on the card. |
subject | Subject | yes | { "type": string, "id": string }. type SHOULD match the kind's subjectType. |
expects | string | yes | What is expected, in a person's words, specific to this subject. |
satisfiedBy | Matcher | yes | { "factKey": string }. The fact key that satisfies this expectation. Exact match. |
dueAt | string | yes | RFC 3339 instant, UTC. When anchored, the projected due time at the moment of raising. |
grace | string | no | ISO 8601 duration after dueAt before an overdue lapse. Absent means zero. |
anchor | Anchor | no | { "expectationId": string, "offset": duration }. When present, the current due time is the anchor's satisfaction instant plus offset (§9.3). |
after | string[] | no | Expectations on the same subject that are expected to be satisfied before this one (§9.1, skipped). |
horizon | string | no | RFC 3339 instant after which silence on the subject is a stalled lapse. |
basis | string | yes | "observed", "contract", or "declared". MUST be truthful. |
supersedes | string | no | An open expectation this one replaces (§10.3). |
The following are REQUIRED of the raising agent:
dueAtMUST be present. There is no open-ended expectation.satisfiedBy.factKeyMUST be a key that some party can produce deterministically from an observation. An expectation MUST NOT be satisfied by a model's judgement that it has probably been met.- An expectation MUST NOT be modified after it is raised. A change of due
time, grace, or matcher is a new expectation carrying
supersedes. basisMUST describe wheredueAtcame from, and MUST NOT claim"observed"for a time derived from a contract or a default.- An
expectationIdMUST NOT be reused, including by a later task that re-raises the same expectation about the same subject.
Rationale. The matcher is a key and not a predicate because the watcher is the party that evaluates it, and the watcher is generic. A watcher that can evaluate "a manifest has probably been received" is a watcher with a model in it, and every property this document establishes about determinism and attribution goes with it. The key is the whole contract between the agent and the watcher, and it is enough: the party that observes the manifest arriving knows it is a manifest and knows the shipment.
8.1 Withdrawal
When the task that raised an expectation is canceled, or reaches
TASK_STATE_FAILED or TASK_STATE_REJECTED, the watcher MUST withdraw
every open expectation that task raised. A withdrawn expectation MUST NOT
lapse and MUST remain in the record, marked withdrawn.
An expectation carrying supersedes withdraws the expectation it names at the
moment it is recorded.
An agent MAY withdraw an expectation explicitly by emitting, in a later
artifact under the same key, { "withdraw": ["exp-…"], "reason": "…" }.
Rationale. An expectation raised by a task that no longer exists is a lapse waiting to fire on a shipment nobody is handling. The rule is stated here rather than left to implementations because it is the one that gets forgotten, and the symptom — lapse tasks for canceled work — is what makes an operations team turn the mechanism off.
9. Facts, satisfaction, and lapse
9.1 The three kinds of lapse
A watcher MUST distinguish three ways an expectation fails, because they are three different problems:
| Lapse | Condition | What it usually means |
|---|---|---|
overdue | dueAt + grace has passed and no matching fact has arrived, and nothing listed in a later expectation's after for this subject has been satisfied. | The step has not happened, or has not been reported yet. The ordinary case. |
skipped | A fact satisfied an expectation whose after names this one, while this one is still open. | The step happened and the report never reached us — or a party in the chain does not report that step and never has. A data problem wearing an operational costume. |
stalled | horizon has passed, this expectation is open, and no fact of any kind has been recorded for the subject since the most recent satisfaction (or since the expectation was raised). | Nothing is happening. Freight in a bonded shed waiting for a document; a query in a mailbox nobody reads. |
A skipped lapse MUST be raised as soon as the condition holds. It MUST
NOT wait for dueAt.
Rationale. A timeline that renders only what arrived cannot show the second kind at all: a step that was skipped looks identical to a step that has not happened yet. Only the plan knows a step was expected between the two that arrived. The third kind is where the expensive exceptions live, and it is detectable only if "nothing has happened for longer than expected" can itself become an event — which is the entire content of this extension.
9.2 Facts
A fact is reported to the watcher as:
{
"factKey": "shipment.departed:PA-2026-0901",
"observedAt": "2026-09-11T02:41:00Z",
"source": "carrier-feed:emirates",
"subject": { "type": "shipment", "id": "PA-2026-0901" }
}
| Field | Type | Required | Meaning |
|---|---|---|---|
factKey | string | yes | Matched exactly against satisfiedBy.factKey. |
observedAt | string | yes | RFC 3339 instant the fact was observed, UTC. Used for lateness; not for lapse. |
source | string | yes | Who observed it. MUST be attributable (§13.5). |
subject | Subject | no | The subject the fact concerns. Used for stalled. |
A fact MAY be reported by the agent, in an Artifact's metadata under
"facts"; by a client, in a Message's metadata under the same key; or by any
other party the watcher has authorized, over a transport this document does not
specify.
On receiving a fact the watcher MUST:
- satisfy every open expectation whose
satisfiedBy.factKeyequals the fact's key, recordingsatisfiedAtas the instant of receipt andobservedAtfrom the fact; - record the fact against its subject, so that
stalledcan be evaluated; - re-anchor every open expectation whose
anchornames a newly satisfied one (§9.3); - raise a
skippedlapse for every open expectation named in the newly satisfied expectation'safter.
A fact that satisfies an expectation after dueAt MUST be recorded as late.
Lateness is a property of the record, not a lapse: a watcher MUST NOT submit
a lapse task for an expectation that has been satisfied. An implementation MAY
report lateness to the agent by another means.
A fact matching no open expectation MUST NOT be treated as an error.
9.3 Re-anchoring
When an expectation with an anchor is recorded, its current due time is its
dueAt — the projection the agent made when it raised it. When the anchor is
satisfied, the watcher MUST set the current due time to the anchor's
observedAt plus offset, and MUST preserve the projected due time
unchanged.
The watcher's record of an expectation therefore carries both:
| Field | Meaning |
|---|---|
projectedDueAt | dueAt as raised. Never changes. |
dueAt | The current due time. Changes exactly once, when the anchor is satisfied. |
An overdue lapse is evaluated against the current due time.
An anchored expectation whose anchor lapses MUST NOT itself lapse as
overdue on the projected time. It is evaluated only against horizon, if
present, until its anchor is satisfied or it is withdrawn.
Rationale. Without re-anchoring, one late milestone turns every downstream step red and keeps it red, and the alerting is noise within a week. Without the projected time, every re-anchor forgives the previous slip and the cumulative drift disappears: nobody can say the shipment is now four hours behind where it was ever meant to be. Original plan, current plan, actuals — three tracks, even though most interfaces draw two. The last rule prevents a cascade: one lapse on a chain of six anchored steps produces one lapse task, not six.
10. The lapse task
10.1 Submission
When an expectation lapses, the watcher MUST submit a new task to the agent that raised it, by the core Send Message operation, with:
- the
contextIdof the task that raised the expectation; referenceTaskIdsincluding the id of the task that raised it;- no
taskId, so that a new task is created rather than the origin task resumed; - a
messageIdderived deterministically from(expectationId, lapse kind, dueAt), so that a watcher which fires twice produces one task; - the lapse block below in the Message's
metadata, keyed by this extension's URI.
{
"role": "ROLE_USER",
"contextId": "ctx-northgate-sep",
"referenceTaskIds": ["task-booking-7f3a"],
"messageId": "lapse:exp-01J8Q0MANIFEST:skipped:2026-09-10T20:15:00Z",
"parts": [{ "text": "PA-2026-0901 departed on EK203 at 02:41Z but no manifest was ever received." }],
"extensions": ["https://rsaxb.com/a2a/expectations/v1"],
"metadata": {
"https://rsaxb.com/a2a/expectations/v1": {
"lapse": {
"expectationId": "exp-01J8Q0MANIFEST",
"kind": "shipment.manifest",
"subject": { "type": "shipment", "id": "PA-2026-0901" },
"expects": "the airline manifest for PA-2026-0901",
"lapse": "skipped",
"projectedDueAt": "2026-09-10T20:15:00Z",
"dueAt": "2026-09-10T20:15:00Z",
"lapsedAt": "2026-09-11T02:41:07Z",
"lastFactAt": "2026-09-11T02:41:00Z",
"satisfiedAfter": ["exp-01J8Q0DEPART"],
"lineage": 0
}
}
}
}
| Field | Type | Required | Meaning |
|---|---|---|---|
expectationId, kind, subject, expects | yes | Copied from the expectation, so the agent need not look it up. | |
lapse | string | yes | "overdue", "skipped", or "stalled". |
projectedDueAt | string | yes | As raised. |
dueAt | string | yes | Current due time at the moment of lapse. |
lapsedAt | string | yes | When the watcher determined the lapse. |
lastFactAt | string | no | Most recent fact of any kind on the subject. Absent means none since the expectation was raised. |
satisfiedAfter | string[] | no | For skipped: the later expectations whose satisfaction revealed the gap. |
lineage | integer | yes | How many superseded ancestors this expectation has (§10.3). |
The parts of the lapse message MUST state the lapse in a person's words.
The block is for the agent; the text is for whoever reads the task history.
A watcher that missed a sweep — because it was down, or slow — MUST submit
the lapse late rather than skip it. The deterministic messageId is what makes
this safe.
10.2 What the agent may do
The lapse task invokes lapseSkill. Within it the agent MAY, in any
combination:
- move the origin task to
TASK_STATE_CANCELEDorTASK_STATE_FAILED, with a status message naming the expectation, where the origin task is still open and the lapse means it can no longer complete; - propose an action — a chase, an escalation, a re-booking — as it would in any other task, through whatever authorization the deployment applies to actions;
- ask a human, by moving the lapse task to
TASK_STATE_INPUT_REQUIRED; - raise a new expectation that extends the old one (§10.3);
- conclude that the lapse needs nothing and complete, stating why.
The agent MUST NOT treat the lapse task as authorizing anything the origin task was not authorized to do (§13.1).
The lapse task MUST conclude in the ordinary way. It is a task, and it has a history; that is the point of it.
10.3 Extending
An agent that decides an expectation should be given more time MUST raise a
new expectation carrying supersedes naming the lapsed one. It MUST NOT
raise an expectation identical in kind, subject, satisfiedBy, and dueAt
to one in its own lineage.
The new expectation's lineage is the lapsed one's plus one. A watcher MUST
bound lineage and MUST refuse to record an expectation beyond the bound,
reporting the refusal to the agent as a rejected artifact or by another means
the deployment provides. The bound is a deployment choice; three is a
reasonable one.
Rationale. The obvious way for this mechanism to run away is for an agent to answer every lapse by asking for more time. The identity rule stops the degenerate loop; the lineage bound stops the patient one. After the bound, the only way an expectation gets more time is that a person gives it.
11. Questions that expire
A status-update Message that moves a task to TASK_STATE_INPUT_REQUIRED or
TASK_STATE_AUTH_REQUIRED MAY carry an expectation in its metadata, under
the same key and in the same shape as §8, whose
subject is the task itself:
{
"expectationId": "exp-01J8Q0ANSWER",
"kind": "question.answer",
"subject": { "type": "task", "id": "task-booking-7f3a" },
"expects": "someone to say whose shipment this is",
"satisfiedBy": { "factKey": "task.answered:task-booking-7f3a" },
"dueAt": "2026-09-09T12:00:00Z",
"grace": "PT1H",
"basis": "declared"
}
A watcher that is also the client MUST report the satisfying fact when it sends the answer. A watcher that is not the client satisfies the expectation on observing the origin task leave the interrupted state.
On lapse, the ordinary lapse task is submitted. The agent decides what an unanswered question means: escalate to a different person, close the origin task with a reason, or proceed under a stated default. A client MUST NOT silently discard a question because its expectation lapsed; whatever happens to it happens as a task event with a history.
Rationale. This is the smallest useful deployment of the extension, and it
closes the oldest gap: input-required has no expiry in core, so a question
that nobody answers is a task that stays open until somebody notices the list.
With one expectation per question, the agent that asked is told it was not
answered, and decides, on the record, what that means.
12. Transport and profiles
Raising expectations and submitting lapse tasks use core A2A operations and extension points; nothing new is defined. How facts reach a watcher that is not the client, and how the watcher stores its record, are out of scope.
12.1 External watcher (RECOMMENDED)
The agent declares keepsTime: false. A client, orchestrator, or dedicated
service records expectations from the agent's artifacts, receives facts, and
submits lapse tasks. The agent learns that time has passed only by receiving a
lapse task.
An agent in this profile MUST NOT hold local state whose correctness depends on a lapse arriving. If no watcher is present, expectations are simply never checked, and the agent's behaviour on the tasks it does receive is unchanged.
12.2 Self-timing agent
An agent that holds its own clock MAY declare keepsTime: true and act as its
own watcher. It MUST still:
- emit every expectation in artifact metadata, so a client can see what it is waiting for;
- create a lapse as a new task under the same context, never by mutating the origin task's state without one;
- derive the lapse
messageIddeterministically, so a restart does not fire a lapse twice; - accept facts reported by clients, since the agent is rarely the party that observes the world.
Rationale. The second requirement is the one a self-timing agent will want to skip: it has the clock and the task, so why not just fail the task at the deadline? Because then the record says a task failed, and not that an expectation the agent stated in advance went unmet — and because the client, which may have been holding the human, finds out from a state change with no history behind it.
13. Security considerations
A lapse task is work the agent does with nobody in the loop, triggered by the absence of anything, at a time when the person who started the original task may have gone home.
13.1 Unattended work
The lapse task MUST be authorized as any task from that watcher would be. The watcher's identity is the caller; the origin task's authority does not transfer. An action the agent proposes in a lapse task MUST pass through whatever approval the deployment requires for that action in any other task.
Implementations SHOULD treat "raised a lapse task" as an event worth surfacing to a person, even when the agent concluded that nothing was needed.
Rationale. The most consequential thing an unattended agent can do is act. The second most consequential is decide, unattended and unrecorded, not to. The first is prevented by keeping authorization where it already is; the second by making the decision a task.
13.2 Amplification and loops
A watcher MUST bound the number of open expectations per subject and per raising agent, and MUST refuse to record beyond the bound. The identity and lineage rules in §10.3 are REQUIRED, not advisory. A watcher SHOULD rate-limit lapse submissions per agent.
Rationale. The objection raised against scheduled tasks in #210 — that a public agent becomes a source of repeated requests to third parties — applies here in a narrower form. An expectation cannot recur; it fires at most once per kind. The remaining risk is volume and lineage, and both are bounded by the watcher, which is the party with an interest in bounding them.
13.3 Dishonest due times
A due time derived from a contract, or from what a lane is sold as, produces a lapse on nearly every task. Within a fortnight every reader has learned to ignore the colour, and the mechanism is an expensive noise generator with a nice interface. The lapse that mattered is then indistinguishable from the hundred that did not.
basisMUST be truthful (§8).- Due times SHOULD be derived from observed history for the kind and subject class, and revised when the operation changes.
- A client SHOULD render
basisalongside a lapse, and SHOULD render an anchored expectation whose anchor is unsatisfied as less certain than one whose due time is fixed.
Rationale. This is the uncomfortable requirement. Encoding what the lane actually does means writing down that a lane sold as four days is a six-day lane, and having somebody senior read that. The first useful output of a deployment is usually not a lapse at all: it is the discovery that the published transit time and the real one have disagreed for a long while.
13.4 Clock trust
dueAt, observedAt, and lapsedAt are UTC instants (A2A §5.6.1).
A lapse is determined against the watcher's clock. A watcher MUST NOT
determine a lapse from timestamps supplied by the agent or by fact sources; it
uses those for lateness and ordering only. Implementations SHOULD tolerate
skew of the order of grace, and an agent SHOULD NOT raise an expectation
with a grace shorter than the skew it can expect.
13.5 Forged arrivals
A fact satisfies an expectation, and an expectation that is satisfied never lapses. A party that can report facts can therefore silence the watcher for any subject whose keys it can guess.
- A watcher MUST authorize every fact reporter and MUST scope facts to the tenant of the expectations they may satisfy.
sourceMUST be recorded and MUST be attributable to the reporting party, not supplied by it unchecked.- An implementation SHOULD be able to say, for any satisfied expectation, who satisfied it and with what.
13.6 Cancellation
Withdrawal on cancellation (§8.1) is the expectation-side counterpart of cascading cancellation (#2119). A watcher MUST withdraw on the origin task's terminal state regardless of whether the deployment propagates cancellation to delegated tasks.
14. Privacy considerations
Subjects and fact keys routinely embed identifiers — shipment references, invoice numbers, case ids — that are personal data in some jurisdictions when linked to a person. An expectation additionally reveals a plan: what is expected to happen to whom, and when.
Implementations:
- MUST treat the watcher's record as carrying the data classification of the most sensitive subject it references;
- SHOULD key subjects by stable internal identifiers rather than by values that are themselves personal data;
- MUST define retention for satisfied, lapsed, and withdrawn records, and SHOULD NOT retain lapse task history longer than the tasks it references.
15. Versioning
The extension URI is the version. Any change that would break a watcher reading an expectation or an agent reading a lapse block — a removed field, a narrowed type, a changed meaning — MUST be published under a new URI ending in a higher version segment.
The following are not breaking and MUST NOT change the URI:
- new optional fields on any object defined here;
- new
basisvalues; - new lapse kinds, provided an agent receiving an unrecognised
lapsevalue treats it as"overdue".
An agent MAY declare several versions simultaneously during a migration. A watcher SHOULD use the highest version it understands.
16. Relationship to Learnables
The two extensions are independent. Where both are deployed:
- which expectations a subject class carries — which lane has a pre-arrival declaration step, what a corridor's observed transit is — is exactly the kind of knowledge a Learnable may cover. A lapse task MAY emit a teach block.
- a Lesson's
expiresAtis a due time on knowledge rather than on the world. An implementation MAY raise an expectation of kindlesson.reviewwhen a lesson is taught with an expiry, so that its end is noticed rather than merely enforced.
Neither dependency is normative.
17. Relationship to core A2A
Nothing here changes the meaning of a core A2A message. A client ignoring this
extension sees one extra entry in capabilities.extensions, one extra key in
some artifacts' metadata, and — if a watcher is present — additional tasks in
a context that reference earlier ones, all of which are ordinary A2A.
Six parts of core A2A are load-bearing and are used as specified, not redefined:
capabilities.extensions— the declaration lives inparams;- Artifact
metadata— where an expectation is raised; - Message
metadata— where a fact, or a lapse block, is carried; contextIdandreferenceTaskIds— how a lapse task is tied to the task that raised the expectation, following the shape the maintainers gave in #654;messageId— the deduplication handle core §3.3.1 already permits, which is what makes at-least-once watchers safe;- Cancel Task and the terminal states — what withdrawal keys off.
This extension is deliberately not a task deadline (#857). A deadline is the client's budget for the agent's work and belongs on the request. An expectation is the agent's statement about the world and belongs on the result. The two compose: a task with a deadline may raise expectations that outlive it.
Appendix A. JSON Schema
The machine-readable descriptor and JSON Schema for the objects above are served
at https://rsaxb.com/a2a/expectations/v1/extension.json, whose $defs define
ExpectationKind, Expectation, Subject, Fact, Lapse, and
ExpectationRecord.
Appendix B. Worked example
A pre-alert application, a booking agent, and a carrier feed. The application is the watcher. No scheduler is deployed; the application's existing periodic sweep is enough.
- The application fetches the agent's card, reads
keepsTime: false, and knows it must keep time. - A shipment is booked. The agent's confirmation artifact raises three
expectations: manifest by 20:15Z, departure by 03:15Z (after the manifest),
arrival 1h45 after departure (anchored), with a two-day horizon on the
subject. Every due time carries
basis: "observed", because they came from what this lane has done for the last quarter, not from the airline's schedule. - The carrier feed reports departure at 02:41Z. The application reports the
fact. The departure expectation is satisfied, early. The arrival expectation
re-anchors: current due 04:26Z, projected due 05:00Z preserved. The manifest
expectation, still open, is named in the departure's
after— the application raises a skipped lapse immediately. - The lapse task is submitted under the booking's context, referencing the
booking task, with a message id that would be the same if the sweep ran
twice. The agent's
handle_lapseskill reads the block: the freight has left and the manifest never came. It proposes a chase to the airline's documentation desk. The proposal passes through the same approval every outbound message in the deployment passes through. The lapse task completes with the receipt. - Nothing arrives for two days. The horizon passes with no fact on the subject since 02:41Z. A stalled lapse is submitted. The agent asks a human: the freight has not arrived and nobody has said why. The question carries its own expectation, due in four hours.
- The record shows two tracks. The projected plan as a faint upper line; what happened solid beneath; a hole where the manifest should have been, and a flat line after departure. The application drew nothing it was not told.
Appendix C. Changelog
| Version | Date | Change |
|---|---|---|
| v1 draft | 2026-09-05 | Initial publication. |
References
- A2A Protocol Specification
- A2A Extensions
- A2A Extension & Binding Governance
- a2aproject/A2A#654 — maintainer guidance on modelling deferred work as new tasks under one context
- a2aproject/A2A#857 — task deadlines
- a2aproject/A2A#210 — scheduled tasks (closed)
- a2aproject/A2A#1667 — heartbeat agents
- a2aproject/A2A#2119 — cascading cancellation
- A2A Learnables Extension, Version 1
- RFC 2119 / RFC 8174 — requirement keywords
- RFC 3339 — timestamps
