Skip to content

feat(decisioning): built-in fields projection on get_products responses#503

Merged
bokelley merged 1 commit into
mainfrom
claude/issue-492-fields-projection
May 3, 2026
Merged

feat(decisioning): built-in fields projection on get_products responses#503
bokelley merged 1 commit into
mainfrom
claude/issue-492-fields-projection

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 3, 2026

Closes #492

Adds framework-level projection of GetProductsRequest.fields to MediaBuyHandler.get_products. After the adopter's platform method returns, if params.fields is set the framework strips unrequested product fields before the response reaches the buyer — honoring the lightweight-discovery contract without requiring every adopter to reimplement the same post-filter.

Three field categories always pass through regardless of the buyer's selection:

  1. All eight schema-required Product fields (derived dynamically from Product.model_fields.is_required() so schema regenerations stay in sync): product_id, name, description, publisher_properties, format_ids, delivery_type, pricing_options, reporting_capabilities
  2. Nine optional declared fields with no GetProductsField enum entry (buyer has no mechanism to select/deselect them): cancellation_policy, ext, is_custom, material_submission, measurement_readiness, measurement_terms, performance_standards, property_targeting_allowed, signal_targeting_allowed
  3. All extra='allow' extension fields

When params.fields is None the response is returned unchanged with no allocation.

New files:

  • src/adcp/decisioning/_get_products_helpers.py_project_product_fields helper + three module-level constants; mirrors the webhook_emit.py intercept-at-the-seam pattern
  • tests/test_get_products_projection.py — 17 tests covering constant integrity, projection correctness, extra-field preservation, default-false boolean preservation, handler integration

What was tested:

  • pytest tests/test_get_products_projection.py tests/test_decisioning_handler.py → 29/29 passed
  • mypy src/adcp/decisioning/_get_products_helpers.py src/adcp/decisioning/handler.py → no issues
  • ruff check → clean

Pre-PR review:

  • code-reviewer: approved — no blockers; nits applied (renamed _FIELD1_VALUES_GET_PRODUCTS_FIELD_VALUES, removed redundant __all__, renamed test for enum-count accuracy, applied mode="json" consistency nit)
  • ad-tech-protocol-expert: approved — non-breaking per spec; confirmed unconditional projection is correct AdCP behavior (no fields_projection_supported capability gate in spec); confirmed proposals[] exclusion is correct

Nits surfaced (not blocking):

  • DX expert noted an opt-out flag (apply_fields_projection: bool = True) would benefit adopters who project at the DB query level. The issue author explicitly ruled out a capability gate; this can be added as a non-breaking follow-up if needed.
  • "Linked from migration guide" acceptance criterion (docs: salesagent → adcp Python SDK migration guide #489) requires human action — cannot be automated.

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/cse_01H7Q7ZKYj9Atw5KCBBo5ndC


Generated by Claude Code

Closes #492

Adds framework-level projection of `GetProductsRequest.fields` to
`MediaBuyHandler.get_products`. After the adopter's platform method
returns, if `params.fields` is set the framework strips unrequested
product fields before the response reaches the buyer, honoring the
lightweight-discovery contract without requiring every adopter to
reimplement the same post-filter.

Three field categories always pass through regardless of the buyer's
selection: (1) all eight schema-required Product fields (derived
dynamically from `Product.model_fields.is_required()`), (2) nine
optional declared fields that have no GetProductsField enum entry and
are therefore not selectable by the buyer, and (3) all extra='allow'
extension fields. When `params.fields` is None the response is
returned unchanged with no allocation.

https://claude.ai/code/cse_01H7Q7ZKYj9Atw5KCBBo5ndC
@bokelley bokelley marked this pull request as ready for review May 3, 2026 23:01
@bokelley bokelley merged commit 06aaf51 into main May 3, 2026
14 checks passed
@bokelley bokelley deleted the claude/issue-492-fields-projection branch May 3, 2026 23:01
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(decisioning): built-in fields projection on get_products responses

2 participants