Follow-ups from the expert-review rounds on the A2A 1.0 extraction spec (bokelley/a2a-1.0-update branch, PR pending). The branch ships the 1.0 wire-format migration plus immediate security/correctness fixes. Items below are valuable but non-blocking — group them into a post-merge hardening pass.
Wrapper policy — status-message asymmetry
Current spec: {response: {...}} single-key wrapper rejection applies only to artifact DataParts (final states), not to DataParts in status.message.parts (interim states or final-state fallback). A server bug emitting wrappers in interim updates currently slips through silently. Decide:
- Hoist wrapper detection into a shared helper applied at every
return part.data site; or
- Document the asymmetry as intentional (interim is lightweight progress, not normative schema surface).
Related: cross-repo conflict with adcp-client-python (see adcp-client-python#263) where the Python client unwraps rather than rejects.
Prototype-pollution test hardening
Existing vector proto-pollution-payload only exercises __proto__, which JSON.parse already handles correctly. The realistic threat is downstream Object.assign/spread. Add:
- A vector with
constructor: { prototype: { isAdmin: true } }.
- A test that simulates
Object.assign({}, extracted) and asserts no pollution on ({}).isAdmin.
Concrete size + timeout bounds
Extraction spec mentions "e.g., 1 MB" for DataPart size. Tighten for raw FileParts and challenge_url fetches:
raw decoded: suggest 5 MB cap.
challenge_url fetch (if server-side validation): 256 KB response, 10 s timeout, redirect limit 3.
Intermediary-injection — actionable guidance
Current text ("validate artifact part count matches expectations") isn't implementable since buyers rarely know the expected count. Either:
- Flag as future work pending artifact signing or header-based checksums (
X-AdCP-Parts-Hash); or
- Replace with more practical advice (e.g., "accept only from authenticated peer with validated agent card").
Test-vector expansion
- 100+ DataPart boundary vector — locks in "last wins at scale" and guards against accidental O(n²) regression.
- Two-key / empty-key /
{"": {...}} malformed-envelope vectors — behavior is correct in code but not asserted.
{ task: { ... state: TASK_STATE_REJECTED ... } } and { statusUpdate: { ... state: TASK_STATE_AUTH_REQUIRED ... } } combinatorial vectors — currently envelope-wrapping and new states are tested separately, not combined.
- Wrapper-in-status-message vector — whether to throw or extract is the policy question above, but add a vector once decided.
Vector quality-of-life
path field (artifact / status_message / none) is documentation-only; add an assertion that the actual extraction path matches, or drop the field.
- Timestamps still mixed 2025 vs 2026 — standardize on ISO-8601 UTC with ms precision across all vectors.
extractTextPartFromArtifacts asymmetry
TextPart uses first-match (.find) while DataPart uses last-match (.filter().at(-1)). Defensible (text is presentational, data is authoritative) but not documented. Add one-line comment or make symmetric.
Origin of follow-ups
Flagged across four expert-review passes during the 1.0 migration. Protocol and product reviewers gave "ship it" on the main branch; code and security reviewers found additional hardening opportunities.
🤖 Filed with Claude Code.
Follow-ups from the expert-review rounds on the A2A 1.0 extraction spec (
bokelley/a2a-1.0-updatebranch, PR pending). The branch ships the 1.0 wire-format migration plus immediate security/correctness fixes. Items below are valuable but non-blocking — group them into a post-merge hardening pass.Wrapper policy — status-message asymmetry
Current spec:
{response: {...}}single-key wrapper rejection applies only to artifact DataParts (final states), not to DataParts instatus.message.parts(interim states or final-state fallback). A server bug emitting wrappers in interim updates currently slips through silently. Decide:return part.datasite; orRelated: cross-repo conflict with adcp-client-python (see adcp-client-python#263) where the Python client unwraps rather than rejects.
Prototype-pollution test hardening
Existing vector
proto-pollution-payloadonly exercises__proto__, whichJSON.parsealready handles correctly. The realistic threat is downstreamObject.assign/spread. Add:constructor: { prototype: { isAdmin: true } }.Object.assign({}, extracted)and asserts no pollution on({}).isAdmin.Concrete size + timeout bounds
Extraction spec mentions "e.g., 1 MB" for DataPart size. Tighten for
rawFileParts andchallenge_urlfetches:rawdecoded: suggest 5 MB cap.challenge_urlfetch (if server-side validation): 256 KB response, 10 s timeout, redirect limit 3.Intermediary-injection — actionable guidance
Current text ("validate artifact part count matches expectations") isn't implementable since buyers rarely know the expected count. Either:
X-AdCP-Parts-Hash); orTest-vector expansion
{"": {...}}malformed-envelope vectors — behavior is correct in code but not asserted.{ task: { ... state: TASK_STATE_REJECTED ... } }and{ statusUpdate: { ... state: TASK_STATE_AUTH_REQUIRED ... } }combinatorial vectors — currently envelope-wrapping and new states are tested separately, not combined.Vector quality-of-life
pathfield (artifact/status_message/none) is documentation-only; add an assertion that the actual extraction path matches, or drop the field.extractTextPartFromArtifactsasymmetryTextPart uses first-match (
.find) while DataPart uses last-match (.filter().at(-1)). Defensible (text is presentational, data is authoritative) but not documented. Add one-line comment or make symmetric.Origin of follow-ups
Flagged across four expert-review passes during the 1.0 migration. Protocol and product reviewers gave "ship it" on the main branch; code and security reviewers found additional hardening opportunities.
🤖 Filed with Claude Code.