# From 0.3 to 1.0 (A2A v1.0.1) Research notes for the manual's migration section. Pin: A2A tag `v1.0.1`, commit `3303592588e388e62e0f69f701af531d2f4e3991`, 2026-05-28. Written 2026-10-06. Conventions are the same as in `extensions-grpc-tenant.md` (verbatim quotes; proto comments without `//`; `main` of `a2aproject/A2A` at `679ab3afc6f95ef47bb969d511053d0f63bca2a2`). Pinned sources for this section: docs whats-new-v1 (`docs/whats-new-v1.md`, lines 1511 to 2504 of `docs.md`), docs announcing-1.0, spec Appendix A (A.1 anchors, A.2 guidance, A.2.1 kind discriminator, A.2.2 extended card), spec §1.4 (change control), §3.6 (versioning), §5.3 to §5.5, §9.1, §11.3, §14.2, and the proto. Live "before" evidence, used only where the pinned sources do not describe 0.3 themselves: the 0.3 proto at [A2A v0.3.0 `specification/grpc/a2a.proto`](https://github.com/a2aproject/A2A/blob/v0.3.0/specification/grpc/a2a.proto) (package `a2a.v1`), the 0.3 prose at [v0.3.0 `docs/specification.md`](https://github.com/a2aproject/A2A/blob/v0.3.0/docs/specification.md), the 0.3 JSON schema at [v0.3.0 `specification/json/a2a.json`](https://github.com/a2aproject/A2A/blob/v0.3.0/specification/json/a2a.json), and the 0.3 extensions page at [v0.3.0 `docs/topics/extensions.md`](https://github.com/a2aproject/A2A/blob/v0.3.0/docs/topics/extensions.md). Line numbers below refer to those files at `v0.3.0`. --- ## D.1 What the pinned sources frame the change as - docs whats-new-v1: "This document provides a comprehensive overview of changes from A2A Protocol v0.3.0 to v1.0. The v1.0 release represents a significant maturation of the protocol with enhanced clarity, stronger specifications, and important structural improvements." - docs announcing-1.0: "The v1.0 release tightens specification behavior, which includes breaking changes in the interaction protocol. AgentCard, however, has evolved in a backward-compatible way and now allows agents to advertise support for both existing v0.3 protocol behavior and v1.0 simultaneously. This enables clients to migrate progressively rather than through a single cutover." and "The official SDKs ensure v1.0 A2A agents work seamlessly with older versions." - spec §1.4, change control: "- Documentation: Migration guidance MUST be provided via an ancillary document when introducing major breaking changes." and "- SDK/Schema Aliases: SDKs and JSON Schemas SHOULD provide deprecated alias types/definitions to maintain backward compatibility." - spec Appendix A: "This appendix catalogs renamed protocol messages and objects, their legacy identifiers, and the planned deprecation/removal schedule. All legacy names and anchors MUST remain resolvable until the stated earliest removal version." - spec §3.6.2: "Agents CAN expose multiple interfaces for the same transport with different versions under the same or different URLs." (the mechanism the announcement calls "advertise support for both") ## D.2 Breaking changes, before and after "Source" names the pinned passage first; a `v0.3.0` reference is live confirmation of the "before" column. ### Operations and method names | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 1 | Send message | JSON-RPC `message/send` | `SendMessage` | whats-new "### Send Message (`message/send` → **`SendMessage`**)", "- **✅ RENAMED:** Operation now **`SendMessage`**"; spec §9.1 "- **Method Naming:** PascalCase method names matching gRPC conventions (e.g., `SendMessage`, `GetTask`)"; v0.3.0 spec L215 | | 2 | Send streaming message | `message/stream` | `SendStreamingMessage` | whats-new "### Send Streaming Message (`message/stream` → **SendStreamingMessage**)"; v0.3.0 spec L216 | | 3 | Get task | `tasks/get` | `GetTask` | whats-new "### Get Task (`tasks/get` → **GetTask**)"; v0.3.0 spec L217 | | 4 | List tasks | whats-new: "- Operation unavailable." (the 0.3 prose lists `tasks/list` "(gRPC/REST only)" at L218 and L846, but the 0.3 proto has no `ListTasks` RPC and the 0.3 JSON schema has no `ListTasks` type) | `ListTasks`, with `ListTasksRequest` filters (`contextId`, `status`, `pageSize`, `pageToken`, `historyLength`, `statusTimestampAfter`, `includeArtifacts`) | whats-new "- **✅ NEW:** New operation **ListTasks** with filtering capabilities"; proto `ListTasksRequest`; spec §3.1.4 | | 5 | Cancel task | `tasks/cancel` | `CancelTask` | whats-new "### Cancel Task (`tasks/cancel` → **CancelTask**)" | | 6 | Subscribe | JSON-RPC `tasks/resubscribe`; gRPC `TaskSubscription(TaskSubscriptionRequest)` | `SubscribeToTask(SubscribeToTaskRequest)` on every binding | whats-new "### Subscribe to task (`tasks/resubscribe` → **SubscribeToTask**)"; v0.3.0 proto L68 | | 7 | Push config create | `tasks/pushNotificationConfig/set`; gRPC `CreateTaskPushNotificationConfig(CreateTaskPushNotificationConfigRequest)` | `CreateTaskPushNotificationConfig(TaskPushNotificationConfig)` | whats-new push operations; proto `A2AService`; v0.3.0 proto L76 | | 8 | Push config get | `tasks/pushNotificationConfig/get` | `GetTaskPushNotificationConfig` | whats-new | | 9 | Push config list | `tasks/pushNotificationConfig/list`; gRPC `ListTaskPushNotificationConfig` | `ListTaskPushNotificationConfigs` (plural) | whats-new; v0.3.0 proto L93 | | 10 | Push config delete | `tasks/pushNotificationConfig/delete` | `DeleteTaskPushNotificationConfig` | whats-new | | 11 | Extended card | `agent/getAuthenticatedExtendedCard`; gRPC `GetAgentCard(GetAgentCardRequest)`; REST `GET /v1/card` | `GetExtendedAgentCard(GetExtendedAgentCardRequest)`; REST `GET /extendedAgentCard` | whats-new "- **✅ RENAMED:** `agent/getAuthenticatedExtendedCard` → **GetExtendedAgentCard**"; spec §5.3; v0.3.0 proto L101, spec L225, L1133 | | 12 | JSON-RPC method pattern | "`{category}/{action}`" | PascalCase | spec §9.1; v0.3.0 spec L80 ("Method names follow the pattern `{category}/{action}`"). §9.3 still shows `"method": "category/action"` (register D14) | | 13 | REST path prefix | `/v1/message:send`, `/v1/tasks/{id}` | `/message:send`, `/tasks/{id}` | whats-new "- **✅ BREAKING:** Removed `/v1` prefix from HTTP+JSON URL paths" and "- **✅ RATIONALE:** Version can be part of the base url if required by agent owner"; v0.3.0 spec L99 | | 14 | gRPC proto package | `package a2a.v1;` | `package lf.a2a.v1;` | the pinned sources say nothing about the old package; proto L3 at both tags. SDKs dispatch 0.3 and 1.0 gRPC by package (D.4) | | 15 | Resource names | compound `name` fields, e.g. `GetTaskRequest.name` = `tasks/{id}`, `TaskPushNotificationConfig.name` = `tasks/{id}/pushNotificationConfigs/{push_id}` | plain IDs: `GetTaskRequest.id`, `TaskPushNotificationConfig.task_id` + `id` | whats-new "#### ID Format Simplification (#1389)", "- **✅ BREAKING:** All IDs are now simple literals"; v0.3.0 proto L627-L643 | ### Enum casing | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 16 | `TaskState` | `"submitted"`, `"working"`, `"completed"`, `"failed"`, `"canceled"`, `"rejected"`, `"input-required"`, `"auth-required"` | `"TASK_STATE_SUBMITTED"`, `"TASK_STATE_WORKING"`, `"TASK_STATE_COMPLETED"`, `"TASK_STATE_FAILED"`, `"TASK_STATE_CANCELED"`, `"TASK_STATE_REJECTED"`, `"TASK_STATE_INPUT_REQUIRED"`, `"TASK_STATE_AUTH_REQUIRED"` (plus `TASK_STATE_UNSPECIFIED = 0`) | whats-new TaskStatus Object: "- ✅ `state`: **BREAKING** - Enum values changed from lowercase to `SCREAMING_SNAKE_CASE` with `TASK_STATE_` prefix"; the "Complete Mapping" list; proto `TaskState`; spec §5.5 "Enum values **MUST** be represented according to the [ProtoJSON specification](https://protobuf.dev/programming-guides/json/), which serializes enums as their string names **as defined in the Protocol Buffer definition** (typically SCREAMING_SNAKE_CASE)." | | 17 | `Role` | `"user"`, `"agent"` | `"ROLE_USER"`, `"ROLE_AGENT"` | whats-new "- ✅ `role`: **BREAKING** - Enum values changed from lowercase to `SCREAMING_SNAKE_CASE` with `ROLE_` prefix"; proto `Role` | | 18 | General | `kebab-case` | `SCREAMING_SNAKE_CASE` | whats-new "- **Breaking:** Enum values changed from `kebab-case` to `SCREAMING_SNAKE_CASE` for compliance with the ProtoJSON specification" | ### `Part` | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 19 | Shape | three types `TextPart`, `FilePart`, `DataPart`, each with `kind` | one `Part` with `oneof content { text, raw, url, data }` plus `metadata`, `filename`, `media_type` | whats-new "- ⛔ **REMOVED:** Separate `TextPart`, `FilePart`, and `DataPart` types", "- ✅ **NEW:** Single unified `Part` message with `oneof content` field", "- ✅ **NEW:** Content type determined by which field is present: `text`, `raw`, `url`, or `data`"; proto `Part`; v0.3.0 proto L197-L218 | | 20 | Text | `{ "kind": "text", "text": "Hello, world!" }` | `{ "text": "Hello, world!" }` | spec Appendix A.2.1 examples | | 21 | Discrimination | `if (part.kind === "text")` | `if ("text" in part)` | whats-new Part migration examples | ### File parts | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 22 | Inline bytes | `{ "kind": "file", "file": { "name": "diagram.png", "mimeType": "image/png", "fileWithBytes": "iVBORw0KGgo..." } }` | `{ "raw": "iVBORw0KGgo...", "filename": "diagram.png", "mediaType": "image/png" }` | spec Appendix A.2.1 Example 2; whats-new "- ✅ **NEW:** `raw` field for inline binary content (base64 in JSON)" | | 23 | By reference | `file.fileWithUri` (proto `file_with_uri`) | `url` | whats-new "- ✅ **NEW:** `url` field for file references (replaces `file.fileWithUri`)"; v0.3.0 proto L211 | | 24 | Media type | `file.mimeType` (proto `mime_type`) | `mediaType` on every part | whats-new "- ✅ **NEW:** `mediaType` field (replaces `mimeType`) - available for all part types" and "- `file.mimeType` → `mediaType`"; proto `Part.media_type` comment "This field is available for all part types." | | 25 | File name | `file.name` | `filename` | whats-new "- ✅ **NEW:** `filename` field - available for all part types (not just files)"; proto comment "An optional `filename` for the file (e.g., "document.pdf")." (N14) | | 26 | Nesting | nested `file` object | flat | whats-new "- ⛔ **REMOVED:** Nested `file` object structure" | | 27 | Data | `{ "kind": "data", "data": {...} }` | `{ "data": {...}, "mediaType": "application/json" }` | spec Appendix A.2.1 Affected Types | ### The `kind` fields | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 28 | Parts | inline `kind` discriminator (`"text"`, `"file"`, `"data"`) | removed; "member presence acts as discriminator" | spec Appendix A.2.1: "Objects used an inline `kind` field as a discriminator to identify the object type" then "Objects now use the **JSON member name** itself to identify the type."; "2. **Breaking:** The `kind` field is no longer part of the protocol and should not be emitted" | | 29 | Stream events | `{ "kind": "status-update", ... }`, `{ "kind": "artifact-update", ... }` (and `"task"`, `"message"` for the other two frames) | `{ "statusUpdate": {...} }`, `{ "artifactUpdate": {...} }`, `{ "task": {...} }`, `{ "message": {...} }` inside `StreamResponse` | spec Appendix A.2.1 Streaming Event Types: "- **Legacy:** `{ "kind": "status-update", "taskId": "...", "status": {...} }`" / "- **Current:** `{ "statusUpdate": { "taskId": "...", "status": {...} } }`"; proto `StreamResponse`; v0.3.0 schema L2277, L2491. whats-new gives the legacy values as `taskStatusUpdate`/`taskArtifactUpdate` and the new wrappers as the same names: register D9 and N1 | | 30 | Push payload | 0.3 webhook body shape (not described in the pinned sources) | the same `StreamResponse` wrapper as streams | whats-new "- **✅ CLARIFIED:** Push notification payloads now use StreamResponse format"; spec §4.3.3 | ### The `final` flag | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 31 | `TaskStatusUpdateEvent.final` | `bool final = 4;` ("Whether this is the last status update expected for this task.") | removed; the binding's stream closure signals the end (`TaskStatusUpdateEvent` fields are `task_id`, `context_id`, `status`, `metadata`) | whats-new "- **✅ REMOVED:** `final` boolean field removed from TaskStatusUpdateEvent. Leverage protocol binding specific stream closure mechanism instead." and "- ✅ **CLARIFIED:** Terminal state indicated by protocol-specific stream closure mechanism"; proto; v0.3.0 proto L287; spec §11.7 "until the task reaches a terminal or interrupted state, at which point the stream closes" | ### Security fields | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 32 | Card requirements | `AgentCard.security` (`repeated Security security = 9;`) | `AgentCard.security_requirements` (`repeated SecurityRequirement security_requirements = 9;`, `SecurityRequirement { map schemes = 1; }`), JSON `securityRequirements: [{ "schemes": { "": { "list": [...] } } }]` | proto; v0.3.0 proto L387. The prose (§3.1.11, §13.3, §8.5 sample) still writes `security`: register D6; main fixed the §8.5 sample to `"securityRequirements": [{ "schemes": { "google": { "list": [...] } } }]` | | 33 | Skill requirements | `AgentSkill.security` (`repeated Security security = 8;`) | `AgentSkill.security_requirements = 8` | proto; v0.3.0 proto L471 | | 34 | OAuth flows | `ImplicitOAuthFlow implicit = 3;`, `PasswordOAuthFlow password = 4;` plain | kept, marked `[deprecated = true]` with comments "Deprecated: Use Authorization Code + PKCE instead." / "Deprecated: Use Authorization Code + PKCE or Device Code."; whats-new says removed | whats-new "- ⛔ `ImplicitOAuthFlow` - Deprecated due to token leakage risks in browser history/logs", "- ⛔ `PasswordOAuthFlow` - Deprecated due to credential exposure risks"; proto `OAuthFlows`: register D11 | | 35 | Device code | none | `DeviceCodeOAuthFlow device_code = 5;` (`device_authorization_url`, `token_url`, `refresh_url`, `scopes`) | whats-new "- ✅ `DeviceCodeOAuthFlow` (RFC 8628) - For CLI tools, IoT devices, and input-constrained scenarios"; proto; v0.3.0 proto L558-L563 has flows 1 to 4 only | | 36 | PKCE | none | `AuthorizationCodeOAuthFlow.pkce_required = 5` | whats-new "- ✅ `pkce_required` field added to `AuthorizationCodeOAuthFlow` (RFC 7636)"; proto | | 37 | mTLS | `mtls_security_scheme = 5` already present | unchanged | whats-new "- Enhanced security scheme declarations with mutual TLS support"; v0.3.0 proto L508 (N11) | | 38 | Push auth | `AuthenticationInfo { repeated string schemes = 1; string credentials = 2; }` | `AuthenticationInfo { string scheme = 1 [REQUIRED]; string credentials = 2; }` (one scheme, "Scheme names are case-insensitive per [RFC 9110 Section 11.1]") | whats-new "- ✅ `authentication`: Enhanced PushNotificationAuthenticationInfo structure"; proto; v0.3.0 proto L324-L328 | | 39 | Card signatures | `repeated AgentCardSignature signatures = 17;` | `signatures = 13` (field number reuse of the removed flag's slot); JCS canonicalization (RFC 8785) spelled out in §8.4 | whats-new "- Agent Card signature verification using JWS and JSON Canonicalization" and "- **✅ NEW:** Canonicalization (RFC 8785) clarified for Agent Card signature"; proto; v0.3.0 proto L403 | ### The extended card flag | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 40 | Flag | top-level `supportsAuthenticatedExtendedCard` (proto `bool supports_authenticated_extended_card = 13;`) | `capabilities.extendedAgentCard` (proto `AgentCapabilities.extended_agent_card = 4`, `optional bool`) | whats-new "- **✅ BREAKING:** `supportsAuthenticatedExtendedCard` moved to `capabilities.extendedAgentCard`" and "- ⛔ `supportsAuthenticatedExtendedCard`: Moved to `capabilities.extendedAgentCard`"; proto; v0.3.0 proto L401, spec L483. Appendix A.2.2 calls the legacy flag `supportsExtendedAgentCard` (D40), says the new field is "(field 5)" (D7) and names the removed proto field `AgentCard.supports_extended_agent_card` (N7) | | 41 | Error name | `AuthenticatedExtendedCardNotConfiguredError` (-32007) | `ExtendedAgentCardNotConfiguredError` (-32007) | spec §3.3.2, §5.4; v0.3.0 spec L1175 | | 42 | Capability gate | "This endpoint is available only if `AgentCard.supportsAuthenticatedExtendedCard`" (0.3 prose) | §3.3.4: missing or false flag → `UnsupportedOperationError`; declared but not configured → `ExtendedAgentCardNotConfiguredError` | spec §3.3.4 | ### Push notification configuration | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 43 | Model | two messages: `PushNotificationConfig { id = 1; url = 2; token = 3; authentication = 4; }` wrapped by `TaskPushNotificationConfig { name = 1; push_notification_config = 2; }` | one flat `TaskPushNotificationConfig { tenant = 1; id = 2; task_id = 3; url = 4 [REQUIRED]; token = 5; authentication = 6; }` | whats-new "- **✅ BREAKING:** model changed for all methods, with TaskPushNotificationConfig flattened"; proto; v0.3.0 proto L310-L316, L486-L489. The prose still calls it `PushNotificationConfig` (§4.3.1 heading, §3.1.7, §3.1.8, §10.4.7, §10.4.8, §13.2): register D4; fixed on main | | 44 | Create request | `CreateTaskPushNotificationConfigRequest` (0.3 proto) / `SetTaskPushNotificationConfigRequest` (0.3 JSON-RPC) | the `TaskPushNotificationConfig` itself, with `task_id` set and `id` empty | proto `rpc CreateTaskPushNotificationConfig(TaskPushNotificationConfig)`; Appendix A table row "`SetTaskPushNotificationConfigRequest` → `CreateTaskPushNotificationConfigRequest`" names a message the 1.0 proto lacks (register D5, N15); §10.4.7 same (fixed on main) | | 45 | In `SendMessageConfiguration` | `PushNotificationConfig push_notification = 2;` | `TaskPushNotificationConfig task_push_notification_config = 2;` ("Task id should be empty when sending this configuration in a `SendMessage` request.") | proto; v0.3.0 proto L123. §5.5 names the JSON field `pushNotificationConfig` (register D22) | | 46 | Config identity in URLs | `{configId}` | `{id}` in the proto annotations, `{configId}` in §5.3/§11.3 prose | proto `GetTaskPushNotificationConfigRequest.id`; whats-new "- Example: `tasks/{taskId}/pushNotificationConfigs/{configId}` → separate `task_id` and `config_id` fields" names a `config_id` field the proto lacks (N9; main changed it to `id`) | | 47 | Phantom fields | | whats-new adds `configId` and `createdAt` to `PushNotificationConfig`; neither exists | register D10; removed on main | ### Error codes and error bodies | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 48 | JSON-RPC codes | `-32001` to `-32007` (last one `AuthenticatedExtendedCardNotConfiguredError`) | `-32001` to `-32009`: `-32007` renamed (row 41), `-32008` `ExtensionSupportRequiredError`, `-32009` `VersionNotSupportedError` | spec §5.4; §9.5 "A2A-specific errors use codes in the range `-32001` to `-32099`."; v0.3.0 spec L1169-L1175 | | 49 | Error model | RFC 9457 Problem Details for HTTP (`application/problem+json`); JSON-RPC `error.data` free-form object | `google.rpc.Status` shape; `details`/`data` is an array of objects each with `@type`; A2A errors carry `google.rpc.ErrorInfo` with `reason` and `domain: "a2a-protocol.org"` | whats-new "#### 7. Standardized Error Handling via google.rpc.Status (HIGH IMPACT)", "- **Impact:** Replaces RFC 9457 for HTTP errors. Enforces structured `ErrorInfo` with `reason` and `domain` for A2A-specific errors."; spec §3.3.2 "Error Payload Structure", §9.5, §10.6, §11.6 | | 50 | HTTP error content type | `application/problem+json` | whats-new: "- **HTTP+JSON Content-Type:** Changed from `application/problem+json` to `application/json`."; spec §11.1: "- **Content-Type:** application/a2a+json **SHOULD** be used for requests and responses"; §11.6 sample `Content-Type: application/a2a+json`; §6.4 and §6.5 samples still `application/problem+json` | register D13 | | 51 | gRPC statuses | not in the pinned sources | table in §5.4 (`NOT_FOUND`, `FAILED_PRECONDITION`, `INVALID_ARGUMENT`, `INTERNAL`) | spec §5.4 | ### `A2A-Version` | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 52 | Header | none (the 0.3 spec never mentions `A2A-Version`; grep at v0.3.0 finds no occurrence) | `A2A-Version: 1.0` service parameter, MUST on every request; "`Major.Minor`" only | spec §3.2.6 row "The A2A protocol version that the client is using. If the version is not supported, the agent returns [`VersionNotSupportedError`](#332-error-handling)"; §3.6.1 "Clients MUST send the `A2A-Version` header with each request to maintain compatibility after an agent upgrades to a new version of the protocol (except for 0.3 Clients - 0.3 will be assumed for empty header)."; §14.2.1 "The value MUST be in the format `Major.Minor` (e.g., "0.3")." | | 53 | Empty header | n/a | means 0.3 | spec §3.6.2 "Agents MUST interpret empty value as 0.3 version." (D.3 below) | | 54 | Patch digits | n/a | never sent, never compared | spec §3.6 "Patch version numbers SHOULD NOT be used in requests, responses and Agent Cards, and MUST not be considered when clients and servers negotiate protocol versions." | | 55 | As a query parameter | n/a | §3.6.1 "Clients MAY provide the `A2A-Version` as a request parameter instead of a header." vs §9.2/§11.2 headers only | register D31 | | 56 | Version in the card | top-level `protocolVersion` (0.3 proto `string protocol_version = 16;`; 0.3 sample `"protocolVersion": "0.2.9"`) | `AgentInterface.protocolVersion` per interface (`string protocol_version = 4 [REQUIRED]`, comment "Use the latest supported minor version per major version. Examples: "0.3", "1.0"") | whats-new "- **✅ BREAKING:** `protocolVersion` moved from AgentCard to individual AgentInterface objects"; proto; v0.3.0 proto L347. Appendix A.2.1 says `protocolVersions` on the card (register D8; fixed on main) | | 57 | Extensions header | `X-A2A-Extensions` (0.3 extensions page L110, L120; the pinned sources say nothing about the old name) | `A2A-Extensions` | whats-new "- More explicit service parameter handling (A2A-Version, A2A-Extensions headers)"; spec §3.2.6, §14.2.2; SDK compat code maps `X-A2A-Extensions` (D.4) | ### The card path and the card shape | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 58 | Well-known card | `/.well-known/agent-card.json` | `/.well-known/agent-card.json`, unchanged (IANA template in §14.3: "**URI suffix:** agent-card.json") | whats-new "- Discovery via `/.well-known/agent-card.json`"; spec §14.3; v0.3.0 spec L293. The what-is-a2a diagram writes `/.well-known/agent-card`: register D32 | | 59 | Extended card path | REST `GET /v1/card`; JSON-RPC `agent/getAuthenticatedExtendedCard` | REST `GET /extendedAgentCard`; JSON-RPC and gRPC `GetExtendedAgentCard` | row 11 | | 60 | Endpoint and transport | top-level `url` + `preferredTransport` + `additionalInterfaces[]` (0.3 proto `url = 3`, `preferred_transport = 14`, `additional_interfaces = 15`; 0.3 `AgentInterface { url = 1; transport = 2; }`) | `supportedInterfaces[]` of `AgentInterface { url = 1; protocol_binding = 2; tenant = 3; protocol_version = 4; }`, "Ordered list of supported interfaces. The first entry is preferred." | whats-new "- **✅ BREAKING:** `preferredTransport` and `additionalInterfaces` consolidated into `supportedInterfaces[]`", "- ⛔ `url`: Primary endpoint now in `supportedInterfaces[0].url`"; proto; v0.3.0 proto L330-L332, L356-L361; spec §8.3.1, §8.3.2 | | 61 | Transport names | `JSONRPC`, `GRPC`, `HTTP+JSON` | same three, now in `protocolBinding`; custom bindings SHOULD use a URI | proto `AgentInterface.protocol_binding` comment; spec §5.8 | | 62 | Tenant | "- Tenants handled implicitly via authentication or URL paths" | `tenant` on `AgentInterface` and on every request message; `/{tenant}/...` REST routes | whats-new "### NEW: Multi-Tenancy Support"; proto (see `extensions-grpc-tenant.md` C) | | 63 | `AgentExtension` | `uri`, `description`, `required` | adds `params = 4` (`google.protobuf.Struct`) | proto; v0.3.0 proto L430-L436. whats-new "- Enhanced extension mechanism with versioning and requirement declarations" (`required` already existed) | ### Other wire changes worth a line | # | Area | Before (0.3) | After (1.0) | Source | |---|---|---|---|---| | 64 | Default execution mode | `SendMessageConfiguration.blocking = 4` (proto3 `bool`, default false) | `SendMessageConfiguration.return_immediately = 4` (default false, so blocking) | spec §3.2.2 "Operations are blocking by default:" and "- **Blocking (`return_immediately: false` or unset)**: The operation MUST wait until the task reaches a terminal state" and "This is the default behavior."; proto comment "If `false` (default), the operation MUST wait until the task reaches a terminal (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or interrupted (`INPUT_REQUIRED`, `AUTH_REQUIRED`) state before returning."; v0.3.0 proto L131. The flag was renamed and its sense inverted, so the default flipped from "return at once" to "wait" (N17). §3.1.1 still says the call returns at once: register D2 | | 65 | `historyLength` | `int32 history_length = 3` | `optional int32 history_length = 3` with unset / 0 / >0 semantics | spec §3.2.4; proto; v0.3.0 proto L126 | | 66 | Pagination | page-based (whats-new's `{ page: 1, perPage: 50 }`) | `pageToken` / `pageSize` / `nextPageToken` (`pageSize` default 50, max 100) | proto `ListTasksRequest`, `ListTasksResponse`; whats-new writes `cursor`, `limit`, `nextCursor`: register D12 (fixed on main) | | 67 | Timestamps | ISO 8601 | ISO 8601 UTC, `YYYY-MM-DDTHH:mm:ss.sssZ`, millisecond precision SHOULD | spec §5.6.1; whats-new "- ✅ `timestamp`: Now explicitly ISO 8601 UTC with millisecond precision (YYYY-MM-DDTHH:mm:ss.sssZ)" | | 68 | `Artifact` field numbers | `name = 3`, `description = 4`, `parts = 5`, `metadata = 6`, `extensions = 7` | `name = 2`, `description = 3`, `parts = 4`, `metadata = 5`, `extensions = 6` | proto; v0.3.0 proto L262-L274. Invisible in JSON, breaking on the gRPC wire (the package change already separates the two) | | 69 | `Message.extensions`, `Artifact.extensions` | present in 0.3 (`Message.extensions = 7`, `Artifact.extensions = 7`; the 0.3 JSON schema has `extensions` on three objects) | present | whats-new lists `extensions[]` under "**Added Fields:**" for both (N10) | | 70 | Legacy type names | `MessageSendParams`, `SendMessageSuccessResponse`, `SendStreamingMessageSuccessResponse`, `ListTaskPushNotificationConfigSuccessResponse`, `GetAuthenticatedExtendedCardRequest` | `SendMessageRequest`, `SendMessageResponse`, `StreamResponse`, `ListTaskPushNotificationConfigsResponse`, `GetExtendedAgentCardRequest` | spec Appendix A table (first, second, third, fifth and sixth rows; the fourth row is D5) | ## D.3 What a server does when the version header is missing Rule: spec §3.6.1 "(except for 0.3 Clients - 0.3 will be assumed for empty header)" and §3.6.2 "Agents MUST interpret empty value as 0.3 version." together with "If the version is not supported by the interface, agents MUST return a [`VersionNotSupportedError`](#332-error-handling)." So a 1.0-only interface MUST answer a header-less request with `VersionNotSupportedError`: JSON-RPC `-32009`, gRPC `FAILED_PRECONDITION`, HTTP `400 Bad Request` (§5.4), `ErrorInfo.reason` `VERSION_NOT_SUPPORTED`. The §6.4 sample ("Version Negotiation Error") shows the HTTP 400 body for an unsupported `0.5` (still in RFC 9457 shape: D13). The pinned sources say nothing about where in the pipeline the check runs (before or after authentication), nor about how a server that serves both 0.3 and 1.0 on one URL should separate the two beyond "CAN expose multiple interfaces". What the SDKs do (server side; from `research/v2/notes/*.md` B7 cells plus a2a-python code): | SDK | Missing or empty header | Unsupported value | Comparison | Where checked | |---|---|---|---|---| | a2a-python 1.2.2 | treated as `'0.3'`, then rejected by a 1.0 handler: `VersionNotSupportedError` (-32009; REST 400) | same error | exact match, else same major (`actual_v.major == expected_v.major`); patch ignored | `@validate_version(PROTOCOL_VERSION_1_0)` on every JSON-RPC and REST dispatcher method; **not** on the gRPC servicer | | a2a-js 1.3.0 | `'0.3'`; rejected unless the card declares `0.3` for that binding | rejected | exact string against the card's `protocolVersion` | all three bindings (`-32009` with HTTP 200; REST 400; gRPC `FAILED_PRECONDITION`) | | a2a-go 2.6.0 | accepted (header never read) | accepted | none | nowhere; `VersionNotSupported` is mapped but never emitted | | a2a-java 1.4.0.Final | `0.3`, rejected: `-32009`, REST 400, gRPC `UNIMPLEMENTED` | rejected | major compared; needs `major.minor` form | per-binding handlers; the optional multiversion modules route `0.3` or absent to the 0.3 handler instead | | a2a-dotnet 1.0.0-preview2 | JSON-RPC accepts missing, `1.0`, `0.3`; REST ignores the header | JSON-RPC `-32009` (HTTP 200) | exact strings | JSON-RPC only; main gRPC: absent accepted, only `"1.0"` accepted, `0.3` rejected | | a2a-rs (server 0.5.1) | JSON-RPC: missing or empty becomes `"0.3"` and is rejected with `-32009` (HTTP 200) | `-32009` | major only | JSON-RPC only; REST and gRPC ignore it | a2a-python evidence: [src/a2a/utils/version_validator.py#L23-L29](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/utils/version_validator.py#L23-L29) ("If the header is missing or empty, it is interpreted as `constants.PROTOCOL_VERSION_0_3` ('0.3')."), [#L68-L78](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/utils/version_validator.py#L68-L78) (reads `A2A-Version` from `context.state['headers']`, falls back to `'0.3'`), [#L80-L90](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/utils/version_validator.py#L80-L90) (major comparison); decorators at [src/a2a/server/routes/rest_dispatcher.py#L177](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/routes/rest_dispatcher.py#L177) onward and [src/a2a/server/routes/jsonrpc_dispatcher.py#L353](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/routes/jsonrpc_dispatcher.py#L353); constants [src/a2a/utils/constants.py#L27-L31](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/utils/constants.py#L27-L31); code `-32009` at [src/a2a/utils/errors.py#L146](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/utils/errors.py#L146). Client side every transport sends `A2A-Version: 1.0` (`PROTOCOL_VERSION_CURRENT`), gRPC as metadata `a2a-version` ([src/a2a/client/transports/grpc.py#L302-L304](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/client/transports/grpc.py#L302-L304)); the card fetch sends none. Read-across: five of six SDKs follow "missing means 0.3"; only Go accepts anything. Two SDK gRPC servers (Python, Rust) and two REST servers (.NET, Rust) do not check at all, so a client that omits the header gets different answers per binding from the same vendor. ## D.4 The 0.3 compatibility layer in each SDK, and how to enable it | SDK | Where | Server: enable | Server: how a request is classified | Client: enable | gRPC 0.3 | |---|---|---|---|---|---| | a2a-python 1.2.2 | `src/a2a/compat/v0_3/` (0.3 Pydantic types, 0.3 proto `a2a_v0_3.proto` in package `a2a.v1`, adapters) | `create_jsonrpc_routes(handler, rpc_url='/', enable_v0_3_compat=True)` and `create_rest_routes(handler, enable_v0_3_compat=True)`; also list a `protocol_version='0.3'` `AgentInterface` in the card | JSON-RPC: by method name; a 0.3 method (`message/send`, ...) is handed to `JSONRPC03Adapter` before the 1.0 version check. REST: the 0.3 routes are mounted beside the 1.0 ones. Old `X-A2A-Extensions` header accepted on that path | automatic: `ClientFactory` picks `CompatJsonRpcTransport` / REST / gRPC compat transports when the selected interface's `protocolVersion` is `>= 0.3` and `< 1.0` (`is_legacy_version`); interface choice prefers `1.0`, then `> 1.0`, then `>= 0.3`, then unversioned | separate servicer `CompatGrpcHandler` on the 0.3 package, registered with `a2a_v0_3_pb2_grpc.add_A2AServiceServicer_to_server` next to the 1.0 one | | a2a-js 1.3.0 | `src/compat/v0_3/` | `legacyCompat: { enabled: true }` on `jsonRpcHandler`, `restHandler`, `agentCardHandler` | by `A2A-Version` (absent = `0.3`); the legacy path answers with `X-A2A-Extensions` | `legacyCompat` on each transport factory and on the card resolver; used when the matched interface's `protocolVersion` is in [0.3, 1.0) | separate `legacyGrpcService` registered next to `grpcService` (no `legacyCompat` option) | | a2a-go 2.6.0 | `a2acompat/a2av0` (JSON-RPC and REST handlers and client transports), `a2agrpc/v0`, `a2apb/v0` | mount a second handler (`a2av0.NewJSONRPCHandler`, `a2av0.NewRESTHandler` under `/v1`) and advertise a second `AgentInterface` with version `0.3` | by handler/URL, never by header (the 1.0 handlers do not read `A2A-Version`) | `a2av0.WithJSONRPCTransport`, `a2av0.WithRESTTransport`, `a2agrpc/v0.WithGRPCTransport`; the factory keys transports by (binding, `protocolVersion`) | `a2agrpc/v0` handler on package `a2a.v1`; 0.3 metadata echo uses `x-a2a-extensions` | | a2a-java 1.4.0.Final | `compat-0.3/` Maven modules (`*_v0_3` classes, `A2AProtocol_v0_3.PROTOCOL_VERSION = "0.3"`) | add `reference/multiversion-jsonrpc` or `reference/multiversion-rest` (`VersionRouter`); plain `reference/{jsonrpc,rest,grpc}` are 1.0 only | `A2A-Version` `"1.0"` → 1.0 handler; `"0.3"` or absent → 0.3 handler | the caller instantiates `Client_v0_3` explicitly; no detection | by proto package: `a2a.v1` (0.3) vs `lf.a2a.v1` (1.0) | | a2a-dotnet 1.0.0-preview2 | `src/A2A.V0_3` (the whole 0.3 SDK, JSON-RPC only) and `src/A2A.V0_3Compat` | call `MapA2AWithV03Compat` instead of `MapA2A` | by `A2A-Version` (absent = 0.3), translated to the 1.0 `IA2ARequestHandler` | `V03CompatClientFactory` / `V03ClientAdapter` expose a 0.3 agent as a 1.0 `IA2AClient` | none (no gRPC at the tag) | | a2a-rs | none | n/a | JSON-RPC rejects a missing header as `0.3` | the factory registers transports only under major 1, so `0.x` interfaces are never selected; REST keeps legacy path aliases (`/message/send`, ...) | none | Evidence: - a2a-python: [src/a2a/server/routes/jsonrpc_routes.py#L32](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/routes/jsonrpc_routes.py#L32) `enable_v0_3_compat: bool = False,`; [src/a2a/server/routes/jsonrpc_dispatcher.py#L162-L167](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/routes/jsonrpc_dispatcher.py#L162-L167) builds `JSONRPC03Adapter`; [#L277-L287](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/routes/jsonrpc_dispatcher.py#L277-L287) routes by `supports_method(method)` before the 1.0 parse; [src/a2a/server/routes/rest_routes.py#L33](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/routes/rest_routes.py#L33) and [#L67-L78](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/routes/rest_routes.py#L67-L78) mount `REST03Adapter.routes()`; [src/a2a/compat/v0_3/grpc_handler.py#L37](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/compat/v0_3/grpc_handler.py#L37) `class CompatGrpcHandler(a2a_v0_3_pb2_grpc.A2AServiceServicer)`, registered in [tests/integration/test_client_server_integration.py#L372](https://github.com/a2aproject/a2a-python/blob/v1.2.2/tests/integration/test_client_server_integration.py#L372); [src/a2a/compat/v0_3/versions.py#L8-L18](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/compat/v0_3/versions.py#L8-L18) `is_legacy_version`; [src/a2a/client/client_factory.py#L101-L127](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/client/client_factory.py#L101-L127) (JSON-RPC producer picks `CompatJsonRpcTransport`), [#L232-L256](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/client/client_factory.py#L232-L256) (`_find_best_interface` preference order); [src/a2a/server/request_handlers/response_helpers.py#L87-L113](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/server/request_handlers/response_helpers.py#L87-L113) `agent_card_to_dict` merges 0.3 card fields such as `supportsAuthenticatedExtendedCard` into the served card; [src/a2a/compat/v0_3/README.md](https://github.com/a2aproject/a2a-python/blob/v1.2.2/src/a2a/compat/v0_3/README.md) ("It is generated into the `a2a.v1` package namespace."); [README.md#L41-L52](https://github.com/a2aproject/a2a-python/blob/v1.2.2/README.md#L41-L52) compatibility table (0.3 compat for JSON-RPC, REST and gRPC, client and server) and the scope note pointing to issue #742. - a2a-js: [src/server/express/json_rpc_handler.ts#L34-L36](https://github.com/a2aproject/a2a-js/blob/v1.3.0/src/server/express/json_rpc_handler.ts#L34-L36); [src/client/transports/json_rpc_transport.ts#L428-L431](https://github.com/a2aproject/a2a-js/blob/v1.3.0/src/client/transports/json_rpc_transport.ts#L428-L431); [src/compat/v0_3/README.md#L68](https://github.com/a2aproject/a2a-js/blob/v1.3.0/src/compat/v0_3/README.md#L68); [src/constants.ts#L20](https://github.com/a2aproject/a2a-js/blob/v1.3.0/src/constants.ts#L20) `A2A_LEGACY_PROTOCOL_VERSION = '0.3'`. - a2a-go: [a2acompat/a2av0/doc.go#L20-L21](https://github.com/a2aproject/a2a-go/blob/v2.6.0/a2acompat/a2av0/doc.go#L20-L21); [a2acompat/a2av0/jsonrpc_server.go#L40](https://github.com/a2aproject/a2a-go/blob/v2.6.0/a2acompat/a2av0/jsonrpc_server.go#L40); [a2acompat/a2av0/rest_server.go#L44-L45](https://github.com/a2aproject/a2a-go/blob/v2.6.0/a2acompat/a2av0/rest_server.go#L44-L45); [a2acompat/a2av0/rest_client.go#L39-L42](https://github.com/a2aproject/a2a-go/blob/v2.6.0/a2acompat/a2av0/rest_client.go#L39-L42); [a2agrpc/v0/client.go#L35-L37](https://github.com/a2aproject/a2a-go/blob/v2.6.0/a2agrpc/v0/client.go#L35-L37). - a2a-java: [compat-0.3/.../A2AProtocol_v0_3.java#L5](https://github.com/a2aproject/a2a-java/blob/v1.4.0.Final/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/A2AProtocol_v0_3.java#L5); [docs/content/dev/compatibility.md#L56-L57](https://github.com/a2aproject/a2a-java/blob/v1.4.0.Final/docs/content/dev/compatibility.md#L56-L57) and [#L92](https://github.com/a2aproject/a2a-java/blob/v1.4.0.Final/docs/content/dev/compatibility.md#L92). - a2a-dotnet: [src/A2A.V0_3Compat/V03ServerCompatEndpointExtensions.cs#L28](https://github.com/a2aproject/a2a-dotnet/blob/v1.0.0-preview2/src/A2A.V0_3Compat/V03ServerCompatEndpointExtensions.cs#L28); [src/A2A.V0_3/JsonRpc/A2AMethods.cs#L11](https://github.com/a2aproject/a2a-dotnet/blob/v1.0.0-preview2/src/A2A.V0_3/JsonRpc/A2AMethods.cs#L11); README L22-L25 ("A backward-compatible `A2A.V0_3` NuGet package is available during the transition"). - a2a-rs: [a2a-client/src/factory.rs#L175](https://github.com/a2aproject/a2a-rs/blob/a2a-server-lf-v0.5.1/a2a-client/src/factory.rs#L175). ## D.5 Migration guides | Where | Document | Scope | |---|---|---| | A2A (pinned) | `docs/whats-new-v1.md` ("What's New in A2A Protocol v1.0") | protocol-level before/after, three-phase "Migration Strategy Recommendations" (Compatibility Layer, Dual Support, v1.0 Only), priority list ("Critical (Do Immediately)": discriminator parsing, card parsing, "Add A2A-Version header to all requests") | | A2A (pinned) | spec Appendix A | legacy name table, A.2 guidance ("Client Implementations SHOULD:" with "- Prefer new names immediately for all new integrations.", "- Implement dual-handling where schemas/types permit (e.g., union type or backward-compatible decoder).", "- Log a warning when receiving legacy-named objects after the first deprecation announcement release."; "Server Implementations MAY:" with "- Accept both legacy and current request message forms during the overlap period." and "- Emit only current form in responses (recommended) while providing explicit upgrade notes."), A.2.1 `kind`, A.2.2 extended card | | A2A (main) | same file, [whats-new-v1.md at `679ab3a`](https://github.com/a2aproject/A2A/blob/679ab3afc6f95ef47bb969d511053d0f63bca2a2/docs/whats-new-v1.md) | 57-line diff after the tag: removed `createdAt`/`lastModified`/`configId` claims, fixed `config_id` to `id`, fixed stream names to `status-update`/`artifact-update` (legacy) and `statusUpdate`/`artifactUpdate` (current), fixed pagination to `pageToken`/`pageSize`/`nextPageToken`; the `index` field on `artifactUpdate` and `agentCard.extensions` remain | | a2a-python 1.2.2 | [docs/migrations/v1_0/README.md](https://github.com/a2aproject/a2a-python/blob/v1.2.2/docs/migrations/v1_0/README.md) "A2A Python SDK Migration Guide: v0.3 → v1.0" | 12 sections: dependencies, types, `DefaultRequestHandler`, executor streaming rules, application setup (Starlette route factories), "6. Supporting v0.3 Clients" (the two-step recipe: add a `protocol_version='0.3'` interface, pass `enable_v0_3_compat=True` to `create_jsonrpc_routes` and `create_rest_routes`), client creation, send message, push config, helpers, summary; database guides in [docs/migrations/v1_0/database/](https://github.com/a2aproject/a2a-python/tree/v1.2.2/docs/migrations/v1_0/database) (`README.md`, `simple_migration.md`, `zero_downtime.md`); README pointer at [README.md#L25](https://github.com/a2aproject/a2a-python/blob/v1.2.2/README.md#L25) | | a2a-js 1.3.0 | [docs/migration-guide.md](https://github.com/a2aproject/a2a-js/blob/v1.3.0/docs/migration-guide.md), [docs/compatibility-v0_3.md](https://github.com/a2aproject/a2a-js/blob/v1.3.0/docs/compatibility-v0_3.md), [src/compat/v0_3/README.md](https://github.com/a2aproject/a2a-js/blob/v1.3.0/src/compat/v0_3/README.md) | user guide, when to enable `legacyCompat`, internals; sample `src/samples/agents/compat-v1-server` | | a2a-dotnet 1.0.0-preview2 | [docs/migration-guide-v1.md](https://github.com/a2aproject/a2a-dotnet/blob/v1.0.0-preview2/docs/migration-guide-v1.md), [docs/taskmanager-migration-guide.md](https://github.com/a2aproject/a2a-dotnet/blob/v1.0.0-preview2/docs/taskmanager-migration-guide.md) | three-phase plan mirroring whats-new; `A2A.V0_3` side by side with `A2A` | | a2a-java 1.4.0.Final | [docs/content/dev/compatibility.md](https://github.com/a2aproject/a2a-java/blob/v1.4.0.Final/docs/content/dev/compatibility.md) | multi-version modules, version routing, `Client_v0_3` | | a2a-go 2.6.0 | no guide; package docs in `a2acompat/a2av0` and [a2acompat/a2av0/migration.go](https://github.com/a2aproject/a2a-go/blob/v2.6.0/a2acompat/a2av0/migration.go) (adapters from the v1 module's interceptors and stores to v2; code, not prose) | | | a2a-rs | none | | ## D.6 Where the docs disagree with the spec or the proto Already in the manual's register and touching this section: D1, D2, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D17, D22, D30, D31, D32, D37, D39, D40 (see `sections/r-6-sources.md`). New findings, numbered on from the register: | ID | Where | The sources say | Follow | Status on main | |---|---|---|---|---| | N1 | docs whats-new-v1, Stream Event Objects and "#### 2. Stream Event Discriminator Pattern" | legacy `"kind": "taskStatusUpdate"` / `"taskArtifactUpdate"`; spec Appendix A.2.1 and the 0.3 JSON schema say `"status-update"` / `"artifact-update"` | Appendix A.2.1 | fixed (diff shows `status-update`, `artifact-update`) | | N2 | docs whats-new-v1, "#### 3. Extension Requirements" | `agentCard.extensions`; proto puts the list at `AgentCapabilities.extensions` (`capabilities.extensions`) | the proto | unchanged (flagged in `brief-docs.md` L1200) | | N3 | docs whats-new-v1, themes | "- **Multi-tenancy support** - Native tenant scoping in gRPC requests"; the proto puts `tenant` on every request message (all bindings) and adds `/{tenant}/` REST routes | the proto | unchanged | | N4 | docs whats-new-v1, List Tasks | "- Operation unavailable." in 0.3; the 0.3 prose lists `tasks/list` (L218, L846) but the 0.3 proto and JSON schema define no such operation | whats-new is right in substance; say "not in the 0.3 schema" | n/a (live-only) | | N5 | spec Appendix A.2.1 | "For **Clients** upgrading from pre-0.3.x:" and "For **Servers** upgrading from pre-0.3.x:" under "**Version 1.0 introduces a breaking change**" | read as pre-1.0 | unchanged | | N6 | spec Appendix A table and "Planned Lifecycle" | "Earliest Removal Version" ">= 0.5.0" and the lifecycle steps "1. 0.3.x: New names introduced; legacy names documented; aliases added." through "3. ≥0.5.0: Legacy names eligible for removal after review; migration appendix updated." for renames that happened in 1.0; the text itself says "(example timeline; adjust per release strategy)" | treat as placeholder; §1.4 "next major release" is the rule | unchanged | | N7 | spec Appendix A.2.2, Proto Changes | "- Removed: `AgentCard.supports_extended_agent_card` (field 13)"; the 0.3 proto field was `supports_authenticated_extended_card = 13` (number right, name wrong); 1.0 reuses 13 for `signatures` | the 0.3 proto | unchanged | | N8 | spec §10.2 Go sample | `"a2a-version", "0.3"` in a 1.0 binding sample (D39 lists §9.2, §11.2, §14.2.1 only) | send `1.0` | unchanged | | N9 | docs whats-new-v1, ID Format Simplification | "separate `task_id` and `config_id` fields"; the proto field is `id` | the proto | fixed (`id`) | | N10 | docs whats-new-v1, Message and Artifact objects | `extensions[]` listed under "**Added Fields:**"; both existed in the 0.3 proto (`Message.extensions = 7`, `Artifact.extensions = 7`) | not new; only `Artifact`'s number moved | unchanged (live-only evidence) | | N11 | docs whats-new-v1, themes | "Enhanced security scheme declarations with mutual TLS support"; `mtls_security_scheme = 5` existed in the 0.3 proto | not new | unchanged (live-only evidence) | | N12 | spec §5.3, §11.3, §11.5 | REST route lists omit the `/{tenant}/...` `additional_bindings` the proto defines on every RPC | the proto | unchanged | | N13 | proto `ListTaskPushNotificationConfigsRequest` | `tenant = 4` while every other request has `tenant = 1` | not a conflict; note for gRPC readers | unchanged | | N14 | docs whats-new-v1 vs proto `Part.filename` | "`filename` field - available for all part types (not just files)" vs "An optional `filename` for the file" | the proto allows it on any part; use it for files | unchanged | | N15 | spec Appendix A table, row 4 | "current" name `CreateTaskPushNotificationConfigRequest` is the 0.3 proto request type (L76), not a 1.0 type; the 1.0 RPC takes `TaskPushNotificationConfig` | the proto (strengthens D5) | unchanged | | N16 | docs whats-new-v1, Field Name Changes | "- Operation names (aliases provided during transition)"; no alias mechanism exists in the 1.0 proto or JSON-RPC method set; aliases live only in SDK compat layers keyed by `A2A-Version` or method name | the spec; name the SDK layer | unchanged | | N17 | docs whats-new-v1, "#### 1. Execution Mode Control" | shows `returnImmediately` as a new capability without saying the 0.3 `blocking` flag (default false, non-blocking) became `return_immediately` (default false, blocking); the default flipped | spec §3.2.2 and the proto comment; warn migrators | unchanged | | N18 | docs extensions, sample card | top-level `"url"` (0.3 shape) | `supportedInterfaces` | fixed | | N19 | spec §10.5.1 | "This is a gRPC-specific type used in resource-oriented operations to provide the full resource name" for `TaskPushNotificationConfig`, which is the create request and stored config on every binding and has no resource-name field in 1.0 | the proto | unchanged | | N20 | tag page multi-tenancy.md, approach 2 | "`securitySchemes` and `security` fields"; the 1.0 field is `securityRequirements` | the proto (D6 family) | unchanged |