Skip to content

Commit 01a1068

Browse files
bokelleyclaude
andauthored
docs(migration)!: add v4.0 → v4.1 migration guide (#302)
Document the three breaking changes folded into the 4.1 release so upgraders have a single artifact to consult: 1. ``ADCPClient.pending_task_id`` → ``ADCPClient.active_task_id`` (and the same on ``A2AAdapter``); ``context_id=`` / ``reset_context()`` raise ``TypeError`` instead of ``ValueError`` on non-A2A protocols. 2. ``FormatId.__name__`` is now ``"FormatReferenceStructuredObject"`` because AdCP 3.0.1 polished ``core/format-id.json``'s title. Public ``FormatId`` keeps working via the aliases module; pickled instances and reflection on ``__name__`` break. 3. ``MEDIA_BUY_STATE_MACHINE`` no longer has ``pending_activation`` — replaced with the spec-correct ``pending_creatives`` and ``pending_start``. BREAKING CHANGE: ``FormatId.__name__`` and ``__qualname__`` change from ``"FormatId"`` to ``"FormatReferenceStructuredObject"`` because AdCP 3.0.1 polished the schema title on ``core/format-id.json``. The public ``adcp.FormatId`` alias keeps working — ``Format(format_id= FormatId(...))`` and ``isinstance(x, FormatId)`` are unchanged. Two niche cases break: pickled ``FormatId`` instances from 4.0 fail to unpickle on 4.1, and snapshot tests / log scrapers asserting on ``__name__`` see the rename. See MIGRATION_v4.0_to_v4.1.md. BREAKING CHANGE: ``MEDIA_BUY_STATE_MACHINE`` no longer accepts ``"pending_activation"`` as a key — that string is not part of the AdCP v3 ``enums/media-buy-status.json``. ``valid_actions_for_status ("pending_activation")`` now returns ``[]``. Use ``"pending_creatives"`` (creatives still awaiting approval) or ``"pending_start"`` (creatives approved, awaiting flight start) per the spec. See MIGRATION_v4.0_to_v4.1.md. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7be949c commit 01a1068

1 file changed

Lines changed: 98 additions & 0 deletions

File tree

MIGRATION_v4.0_to_v4.1.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Migrating from v4.0 to v4.1
2+
3+
4.1 picks up [AdCP 3.0.1](https://adcontextprotocol.org/docs/reference/release-notes#version-301)
4+
(a stable-surface no-op for handlers — no field renames, no new enum values
5+
on stable schemas) and ships the [a2a-sdk 1.0 migration](https://a2a-protocol.org/changelog).
6+
Most code keeps working unchanged. This guide lists the three places where
7+
that's not true.
8+
9+
## 1. `ADCPClient.pending_task_id``ADCPClient.active_task_id`
10+
11+
The attribute name reflects what it actually holds — the *currently active*
12+
A2A task id, including non-terminal states (working, input-required, auth-required).
13+
"pending" suggested only one specific lifecycle phase.
14+
15+
```python
16+
# Before (4.0)
17+
if client.pending_task_id is not None:
18+
...
19+
20+
# After (4.1)
21+
if client.active_task_id is not None:
22+
...
23+
```
24+
25+
Same rename on `A2AAdapter.pending_task_id``active_task_id`.
26+
27+
The constructor's `context_id=` kwarg and `reset_context()` now raise
28+
`TypeError` (was `ValueError`) when called on non-A2A protocols. The string
29+
value remains acceptable; only the operation is invalid for MCP. Catch
30+
`TypeError` if you were catching `ValueError` here.
31+
32+
## 2. `FormatId` class identity changed
33+
34+
AdCP 3.0.1 polished `core/format-id.json`'s schema title from `"Format ID"`
35+
to `"Format Reference (Structured Object)"`. datamodel-code-generator
36+
follows the title, so the canonical class on disk is now
37+
`FormatReferenceStructuredObject` — the public `FormatId` name is preserved
38+
as an alias in `adcp.types.aliases`.
39+
40+
For 99% of code, this is invisible:
41+
42+
```python
43+
# Both work identically on 4.0 and 4.1
44+
from adcp import FormatId, Format
45+
46+
fid = FormatId(agent_url="https://creative.example.com", id="display_300x250")
47+
fmt = Format(format_id=fid, ...)
48+
49+
isinstance(fid, FormatId) # True on both versions
50+
```
51+
52+
Two niche cases break:
53+
54+
- **Pickled `FormatId` instances from 4.0** fail to unpickle on 4.1 because
55+
the qualname `FormatId` no longer exists at
56+
`adcp.types.generated_poc.core.format_id`. Re-create the instances under
57+
4.1 (or migrate to JSON serialization, which round-trips cleanly across
58+
both versions).
59+
- **Reflection on `FormatId.__name__`** sees `"FormatReferenceStructuredObject"`
60+
rather than `"FormatId"`. If you were snapshotting type names in tests or
61+
log scrapers, update the expected values.
62+
63+
```python
64+
# Before (4.0)
65+
assert FormatId.__name__ == "FormatId"
66+
67+
# After (4.1)
68+
assert FormatId.__name__ == "FormatReferenceStructuredObject"
69+
```
70+
71+
## 3. `MEDIA_BUY_STATE_MACHINE` keys match the spec enum
72+
73+
The stale `pending_activation` key has been replaced with `pending_creatives`
74+
and `pending_start` (the two distinct phases that 4.0 was conflating). On
75+
4.0, `valid_actions_for_status("pending_activation")` returned a list; on
76+
4.1 it returns `[]` and the spec-correct keys return the action lists.
77+
78+
```python
79+
# Before (4.0) — was already broken in production agents
80+
actions = valid_actions_for_status("pending_activation") # returns a list
81+
82+
# After (4.1) — match the spec
83+
actions = valid_actions_for_status("pending_creatives") # creatives still pending
84+
# or
85+
actions = valid_actions_for_status("pending_start") # creatives approved, awaiting start
86+
```
87+
88+
If you stored `"pending_activation"` as a status string anywhere, map it to
89+
`"pending_start"` on read.
90+
91+
## What to test after upgrading
92+
93+
- Run your full test suite — the `pending_task_id` rename is a noisy compile
94+
break that surfaces immediately; the other two are quieter.
95+
- If you have any pickle-based fixtures or `__name__` assertions, search for
96+
`FormatId` references and update the expected values.
97+
- If you operate a media-buy state machine, search for `pending_activation`
98+
in your codebase.

0 commit comments

Comments
 (0)