Problem
consolidate_exports.py flattens all generated_poc/ types into _generated.py using first-seen-wins (alphabetical sort). When multiple JSON schemas define a type with the same name, one class silently shadows the others. adcp.types.__init__.py re-exports from _generated, so from adcp.types import X may resolve to a different class than the adopter had from their deep generated_poc import.
The migration guide and codemod tell adopters "import from adcp.types (stable public API) instead", but for 66 type names this advice silently swaps the underlying class.
Concrete examples (verified with is identity checks)
| Symbol |
adcp.types resolves to |
Adopter likely needs |
Fields match? |
Brand |
protocol.get_adcp_capabilities_response |
brand (identity, with names, logos, etc.) |
No — 5 vs 80+ fields |
Creative |
creative.get_creative_delivery_response |
creative.list_creatives_response |
No — 6 vs 17+ fields |
Account |
core.account |
account.sync_accounts_request OR sync_accounts_response (3 different classes) |
No |
Sort |
core.tasks_list_request |
creative.list_creatives_request |
No |
Authentication |
account.sync_governance_request |
core.push_notification_config |
No |
Unit |
enums.dimension_unit |
core.duration |
No |
MediaBuy |
core.media_buy |
protocol.get_adcp_capabilities_response (for capabilities) |
No |
GovernanceAgent |
account.sync_governance_request |
core.account |
No |
CreditLimit |
account.sync_accounts_response |
core.account |
No |
Full list: 66 different-shape collisions across non-bundled modules. Only 5 names are in known_collisions; the remaining 61 are unhandled.
Impact on adopters
salesagent (first production adopter) has 85 generated_poc deep imports across 43 files. Following the migration guide, we attempted to rewrite all of them to adcp.types. The result:
- ~40% were safe (class identity preserved)
- ~60% silently swapped classes — code compiled, ruff passed, but mypy caught type mismatches for some; others would have been silent runtime bugs
- The
GENERATED_POC_SYMBOL_MAP in the codemod only covers 8 symbols; lines 148-157 of v3_to_v4.py acknowledge the problem for CreditLimit/Setup/GovernanceAgent but defer resolution
The current workaround (documented in extending-types.md via #644) is to import from the specific submodule. This is correct but means the migration guide's primary advice is unsafe for most types.
Proposed fix
Step 1: Make collisions loud (safety net)
In consolidate_exports.py, add a collision_resolution dict. Any collision not in known_collisions or collision_resolution fails the build. This prevents new silent collisions and forces explicit decisions on existing ones. ~50 lines.
Step 2: Add semantic aliases to aliases.py
For the 66 colliding names, add disambiguated aliases that adopters can import safely:
# aliases.py additions
from adcp.types.generated_poc.brand import Brand as BrandIdentity
from adcp.types.generated_poc.creative.list_creatives_response import Creative as ListingCreative
from adcp.types.generated_poc.creative.get_creative_delivery_response import Creative as DeliveryCreative
from adcp.types.generated_poc.creative.sync_creatives_response import Creative as SyncCreativeResult
# ... etc.
This can be done incrementally — start with the high-impact names above and expand as adopters report needs.
Step 3: Expand the codemod's per-symbol map
Add source-module metadata to GENERATED_POC_SYMBOL_MAP so --auto-apply can generate precise rewrites instead of the generic "import from adcp.types" hint.
Relation to existing work
Problem
consolidate_exports.pyflattens allgenerated_poc/types into_generated.pyusing first-seen-wins (alphabetical sort). When multiple JSON schemas define a type with the same name, one class silently shadows the others.adcp.types.__init__.pyre-exports from_generated, sofrom adcp.types import Xmay resolve to a different class than the adopter had from their deepgenerated_pocimport.The migration guide and codemod tell adopters "import from
adcp.types(stable public API) instead", but for 66 type names this advice silently swaps the underlying class.Concrete examples (verified with
isidentity checks)adcp.typesresolves toBrandprotocol.get_adcp_capabilities_responsebrand(identity, withnames,logos, etc.)Creativecreative.get_creative_delivery_responsecreative.list_creatives_responseAccountcore.accountaccount.sync_accounts_requestORsync_accounts_response(3 different classes)Sortcore.tasks_list_requestcreative.list_creatives_requestAuthenticationaccount.sync_governance_requestcore.push_notification_configUnitenums.dimension_unitcore.durationMediaBuycore.media_buyprotocol.get_adcp_capabilities_response(for capabilities)GovernanceAgentaccount.sync_governance_requestcore.accountCreditLimitaccount.sync_accounts_responsecore.accountFull list: 66 different-shape collisions across non-bundled modules. Only 5 names are in
known_collisions; the remaining 61 are unhandled.Impact on adopters
salesagent (first production adopter) has 85
generated_pocdeep imports across 43 files. Following the migration guide, we attempted to rewrite all of them toadcp.types. The result:GENERATED_POC_SYMBOL_MAPin the codemod only covers 8 symbols; lines 148-157 ofv3_to_v4.pyacknowledge the problem for CreditLimit/Setup/GovernanceAgent but defer resolutionThe current workaround (documented in
extending-types.mdvia #644) is to import from the specific submodule. This is correct but means the migration guide's primary advice is unsafe for most types.Proposed fix
Step 1: Make collisions loud (safety net)
In
consolidate_exports.py, add acollision_resolutiondict. Any collision not inknown_collisionsorcollision_resolutionfails the build. This prevents new silent collisions and forces explicit decisions on existing ones. ~50 lines.Step 2: Add semantic aliases to
aliases.pyFor the 66 colliding names, add disambiguated aliases that adopters can import safely:
This can be done incrementally — start with the high-impact names above and expand as adopters report needs.
Step 3: Expand the codemod's per-symbol map
Add source-module metadata to
GENERATED_POC_SYMBOL_MAPso--auto-applycan generate precise rewrites instead of the generic "import from adcp.types" hint.Relation to existing work