Skip to content

A2A webhook builder emits invalid 'unspecified' state when status is unknown #603

@bokelley

Description

@bokelley

Surfaced during the protocol review of #602 (to_wire_dict seam).

Bug

create_a2a_webhook_payload in src/adcp/webhooks.py defaults to pb.TaskState.TASK_STATE_UNSPECIFIED when the input status doesn't match any known AdCP status:

adcp_to_task_state: dict[str, int] = {
    "completed": pb.TaskState.TASK_STATE_COMPLETED,
    ...
}
task_state_enum = adcp_to_task_state.get(status_value, pb.TaskState.TASK_STATE_UNSPECIFIED)

_normalize_a2a_task_state_to_v03 then rewrites TASK_STATE_UNSPECIFIEDunspecified on the wire. unspecified is not a valid A2A v0.3 TaskState — the spec enum is submitted | working | input-required | completed | canceled | failed | rejected | auth-required | unknown. A buyer receiver that validates against the A2A schema will reject the webhook.

Fix options

  1. Fail fast in the builder. Raise ValueError on unknown status — callers shouldn't be silently producing payloads buyers will reject.
  2. Map to unknown. A2A 0.3 has a defined unknown state; defaulting unknown AdCP statuses to it preserves delivery and signals the ambiguity to the buyer.

(1) is more correct (loud failure beats silent wire violation); (2) is more lenient. Recommend (1) since the AdCP→A2A status table is closed and any miss is a bug in the caller.

Additional spec-walking gap

_normalize_a2a_task_state_to_v03 doesn't traverse Task.artifacts[].parts[] for nested Message parts, nor TaskStatusUpdateEvent.metadata if a future caller stuffs role-bearing payloads there. Rare today (create_a2a_webhook_payload doesn't emit those), but worth tightening if hand-built Task payloads start flowing through to_wire_dict.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions