Skip to content

feat(examples): MediaBuy.invoice_recipient first-class column (3.1 readiness)#395

Draft
bokelley wants to merge 2 commits intomainfrom
claude/issue-378-mediabuy-invoice-recipient
Draft

feat(examples): MediaBuy.invoice_recipient first-class column (3.1 readiness)#395
bokelley wants to merge 2 commits intomainfrom
claude/issue-378-mediabuy-invoice-recipient

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 3, 2026

Closes #378

AdCP 3.1 surfaces media_buy.invoice_recipient as a per-buy billing entity override. Previously it was buried in request_snapshot only — not queryable, not enforceable, and not surfaced in responses. This PR promotes it to a first-class SQLAlchemy column and wires it through the full create → update → list lifecycle in the v3 reference seller.

Changes:

  • models.py: adds nullable invoice_recipient JSON column to MediaBuy; updates module docstring to note 3.1-readiness alongside Account
  • platform.py: extracts and persists invoice_recipient in create_media_buy; propagates it (including explicit-null clearing via model_fields_set) in update_media_buy; adds get_media_buys implementation that queries the column and strips write-only bank via _project_invoice_recipient(); uses dict-based GetMediaBuysResponse.model_validate() to avoid importing generated_poc directly
  • tests/test_smoke.py: two new tests — ORM column presence check and BusinessEntityResponse bank-stripping round-trip
  • README.md: updates the Spec versioning section to enumerate invoice_recipient alongside the other 3.1-ready columns

What was tested:

  • pytest examples/v3_reference_seller/tests/test_smoke.py::test_invoice_recipient_round_trips_without_bank — passes
  • pytest tests/ -q — 3097 passed, 1 pre-existing failure (TLS integration test unrelated to this change)
  • ruff check examples/v3_reference_seller/src/ — all checks passed
  • mypy src/adcp/ --ignore-missing-imports — no issues found in 744 source files

Nits (not fixed, surfaced for reviewer):

  • status_filter duck-typing via hasattr(..., "root") is fragile if generated shape changes; prefer isinstance(status_filter, RootModel) with a comment
  • test_smoke.py test replicates _project_invoice_recipient logic inline rather than importing the function directly

Pre-PR review:

  • code-reviewer: approved — fixed str(status_filter).value blocker (silent zero-row bug), fixed generated_poc import violation via dict+model_validate, fixed currency/total_budget null fabrication, fixed model_fields_set for clearable update; 2 nits noted above
  • dx-expert: approved — _project_invoice_recipient follows to_account_response pattern, migration comment in docstring addresses adopter gotcha, generated_poc import violation resolved via dict approach

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/session_01CixjgSAnrbc2cdHYDrFcfH


Generated by Claude Code

claude added 2 commits May 3, 2026 00:40
- Fix status_filter single-enum branch: .value not str() (was silently returning zero rows)
- Remove generated_poc import: use dict + model_validate on GetMediaBuysResponse instead
- Skip rows with NULL currency/total_budget instead of fabricating wire data
- Use model_fields_set to allow explicit null clearing of invoice_recipient in update

https://claude.ai/code/session_01CixjgSAnrbc2cdHYDrFcfH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(v3-ref-seller): MediaBuy.invoice_recipient first-class column (3.1 readiness)

2 participants