You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SUBSCRIBE_TO_TASK_BINDING sends SubscribeToTask over HTTP+JSON as POST, but the A2A specification vendored in this repository declares that method as GET. As a result, the four STREAM-SUB-* MUST requirements cannot pass against an implementation that follows the specification.
The TCK's own spec copy — specification/a2a.proto, vendored from a2aproject/A2A commit 173695755607e884aa9acf8ce4feed90e32727a1 (branch v1.0.0), per specification/version.json:
The path constant is correct (PATH_TASK_SUBSCRIBE = "/tasks/{id}:subscribe", base.py:69); only the method differs.
Why this looks like an oversight rather than a decision
I compared every HTTP+JSON binding in tck/requirements/base.py against the annotations in specification/a2a.proto. Ten of eleven match exactly. SubscribeToTask is the only mismatch:
Operation
TCK binding
Vendored spec
SendMessage
POST /message:send
post:
✅
SendStreamingMessage
POST /message:stream
post:
✅
GetTask
GET /tasks/{id}
get:
✅
ListTasks
GET /tasks
get:
✅
CancelTask
POST /tasks/{id}:cancel
post:
✅
SubscribeToTask
POST/tasks/{id}:subscribe
get:
❌
CreatePushNotificationConfig
POST /tasks/{id}/pushNotificationConfigs
post:
✅
GetPushNotificationConfig
GET …/{configId}
get:
✅
ListPushNotificationConfigs
GET …/pushNotificationConfigs
get:
✅
DeletePushNotificationConfig
DELETE …/{configId}
delete:
✅
GetExtendedAgentCard
GET /extendedAgentCard
get:
✅
Notably SendStreamingMessage is POST because the spec says post: — so "streaming implies POST" isn't the rule being applied; the spec is followed everywhere except here.
Impact
Four MUST-level requirements are unpassable for a spec-conformant SUT:
STREAM-SUB-001 — SubscribeToTask returns Task as first event
STREAM-SUB-002 — SubscribeToTask stream terminates at terminal state
STREAM-SUB-004 — SubscribeToTask returns TaskNotFoundError for invalid task
Our server implements GET /tasks/{id}:subscribe per the spec and correctly returns 405 Method Not Allowed for POST. The TCK reports this as a MUST failure. Because these are MUST-level, a release gate keyed on MUST results is held shut by a correct implementation — and the obvious "fix" on our side would be to accept POST, i.e. to become non-conformant to the specification in order to pass the conformance suite.
Versions affected
1.0.0.alpha2 (29063fe95e903cddac5d8ff811ab94df1ad6ef86) — the tag we pin
main (5996b79f9cefa6fc390980e383e358a66fb9e49e at time of writing) — still HTTP_POST, so upgrading does not resolve it
tck/transport/http_json_client.py:296 also documents the POST behaviour in its docstring ("""Subscribe to task updates via ``POST /tasks/{id}:subscribe``.""") and would want updating alongside. I have not checked whether _request_streaming needs changes to issue a bodyless GET — that's the one part of this I can't assert.
Scope of what I verified
I checked only the HTTP+JSON bindings. I did not evaluate the gRPC or JSON-RPC mappings, so I can't say whether they're affected.
A possible systemic follow-up: since the spec is vendored in-repo with its HTTP annotations, the bindings could be validated against specification/a2a.proto in a unit test, which would catch this class of drift automatically. Happy to open a PR for the one-line fix, the docstring, and/or that check if it would be useful — just say which you'd want.
Relevant log output
FAILED tests/compatibility/core_operations/test_requirements.py::test_must_requirement[STREAM-SUB-004-http_json]
AssertionError: STREAM-SUB-004 [SubscribeToTask returns TaskNotFoundError for invalid taskId]
failed on http_json: Expected error code 404 (TaskNotFoundError), got 405
# SUT implements the spec's `get: "/tasks/{id=*}:subscribe"`, so POST is rejected:
$ curl -i -X POST https://<sut>/a2a/v1/tasks/does-not-exist:subscribe
HTTP/1.1 405 Method Not Allowed
$ grep -n "http_json_method" tck/requirements/base.py | sed -n '6p'
150: http_json_method=HTTP_POST,
$ grep -n 'subscribe' specification/a2a.proto
get: "/tasks/{id=*}:subscribe"
What happened?
SUBSCRIBE_TO_TASK_BINDINGsendsSubscribeToTaskover HTTP+JSON as POST, but the A2A specification vendored in this repository declares that method as GET. As a result, the fourSTREAM-SUB-*MUST requirements cannot pass against an implementation that follows the specification.The TCK's own spec copy —
specification/a2a.proto, vendored froma2aproject/A2Acommit173695755607e884aa9acf8ce4feed90e32727a1(branchv1.0.0), perspecification/version.json:The binding —
tck/requirements/base.py:147:The path constant is correct (
PATH_TASK_SUBSCRIBE = "/tasks/{id}:subscribe",base.py:69); only the method differs.Why this looks like an oversight rather than a decision
I compared every HTTP+JSON binding in
tck/requirements/base.pyagainst the annotations inspecification/a2a.proto. Ten of eleven match exactly.SubscribeToTaskis the only mismatch:/message:sendpost:/message:streampost:/tasks/{id}get:/tasksget:/tasks/{id}:cancelpost:/tasks/{id}:subscribeget:/tasks/{id}/pushNotificationConfigspost:…/{configId}get:…/pushNotificationConfigsget:…/{configId}delete:/extendedAgentCardget:Notably
SendStreamingMessageis POST because the spec sayspost:— so "streaming implies POST" isn't the rule being applied; the spec is followed everywhere except here.Impact
Four MUST-level requirements are unpassable for a spec-conformant SUT:
STREAM-SUB-001— SubscribeToTask returns Task as first eventSTREAM-SUB-002— SubscribeToTask stream terminates at terminal stateSTREAM-SUB-003— SubscribeToTask rejects terminal tasksSTREAM-SUB-004— SubscribeToTask returns TaskNotFoundError for invalid taskOur server implements
GET /tasks/{id}:subscribeper the spec and correctly returns 405 Method Not Allowed for POST. The TCK reports this as a MUST failure. Because these are MUST-level, a release gate keyed on MUST results is held shut by a correct implementation — and the obvious "fix" on our side would be to accept POST, i.e. to become non-conformant to the specification in order to pass the conformance suite.Versions affected
1.0.0.alpha2(29063fe95e903cddac5d8ff811ab94df1ad6ef86) — the tag we pinmain(5996b79f9cefa6fc390980e383e358a66fb9e49eat time of writing) — stillHTTP_POST, so upgrading does not resolve itSuggested fix
SUBSCRIBE_TO_TASK_BINDING = TransportBinding( grpc_rpc=OperationType.SUBSCRIBE_TO_TASK.value, jsonrpc_method=OperationType.SUBSCRIBE_TO_TASK.value, - http_json_method=HTTP_POST, + http_json_method=HTTP_GET, http_json_path=PATH_TASK_SUBSCRIBE, )tck/transport/http_json_client.py:296also documents the POST behaviour in its docstring ("""Subscribe to task updates via ``POST /tasks/{id}:subscribe``.""") and would want updating alongside. I have not checked whether_request_streamingneeds changes to issue a bodyless GET — that's the one part of this I can't assert.Scope of what I verified
specification/a2a.protoin a unit test, which would catch this class of drift automatically. Happy to open a PR for the one-line fix, the docstring, and/or that check if it would be useful — just say which you'd want.Relevant log output
Code of Conduct