Skip to content

feat: feature capability validation API (supports/require)#158

Merged
bokelley merged 1 commit intomainfrom
bokelley/feature-validation
Mar 17, 2026
Merged

feat: feature capability validation API (supports/require)#158
bokelley merged 1 commit intomainfrom
bokelley/feature-validation

Conversation

@bokelley
Copy link
Contributor

Summary

Implements #149. Adds a FeatureResolver class and supports()/require() API for feature capability validation, shared by both buyer (client) and seller (server) sides of the SDK.

  • FeatureResolver — resolves feature support across multiple namespaces: protocols ("media_buy"), extensions ("ext:scope3"), targeting ("targeting.geo_countries"), media buy features ("audience_targeting"), and signals features ("catalog_signals")
  • ADCPClient.supports(feature) — check if a seller supports a feature
  • ADCPClient.require(*features) — fail fast with ADCPFeatureUnsupportedError if features are missing
  • Capabilities cachingfetch_capabilities() with configurable TTL (default 1hr), refresh_capabilities() to bypass cache
  • Opt-in auto-validationvalidate_features=True checks feature requirements before task calls (e.g., sync_event_sources requires conversion_tracking)
  • Server-side validate_capabilities() — development-time check that handler implementations match declared features
  • ADCPFeatureUnsupportedError — includes unsupported features, declared features, and agent context

Test plan

  • 43 new tests across 7 test classes covering all namespaces, caching, auto-validation, error messages, standalone resolver, and server-side validation
  • All 738 tests pass (0 failures)
  • Linter clean on all changed files
  • Code review findings addressed: model_fields constraint on getattr, derived FEATURE_HANDLER_MAP, type(handler).__dict__ for override detection, logger.warning on misconfigured auto-validation

Closes #149

🤖 Generated with Claude Code

Copy link
Collaborator

@KonstantinMirin KonstantinMirin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great feature — clean architecture, solid test coverage.

A few observations:

1. MRO override detection in validate_capabilities() (bug)

type(handler).__dict__ only checks the leaf class. If a handler inherits overrides from an intermediate class, it'll produce false warnings:

class ConversionMixin(ADCPHandler):
    async def log_event(self, ...): ...

class MyHandler(ConversionMixin): pass  # inherits the override

validate_capabilities(MyHandler(), caps)  # warns incorrectly

Should walk the MRO up to (excluding) ADCPHandler:

mro_classes = [cls for cls in type(handler).__mro__ if cls is not ADCPHandler and not issubclass(ADCPHandler, cls)]
is_overridden = any(method_name in cls.__dict__ for cls in mro_classes)

2. Feature namespace prefixes — worth establishing now

Since this is forward-looking, it's worth establishing unambiguous prefixes before more features land. Currently supports("audience_targeting") checks media_buy.features first, then signals.features — if both namespaces ever share a field name, media buy silently wins. Consider requiring signals.catalog_signals (matching the existing targeting. and ext: prefix conventions) so the lookup is unambiguous from the start.

3. TASK_FEATURE_MAP coverage — track what's missing

Only conversion_tracking{sync_event_sources, log_event} is mapped today. Worth opening a tracking issue (or adding a note here) enumerating the unmapped features so it's clear what still needs wiring up:

  • audience_targetingsync_audiences (when added)
  • catalog_managementsync_catalogs (when added)
  • inline_creative_managementsync_creatives, list_creatives
  • property_list_filtering → (already works via get_products filtering, may not need a gate)
  • content_standards → content standards handler methods

This makes it easy for someone to pick up the remaining work.

4. Sales agent impact

No breaking changes — all new constructor args have backward-compatible defaults. The sales agent doesn't use ADCPHandler subclasses (it uses FastMCP tools directly), so validate_capabilities() isn't directly applicable today, but the buyer-side supports()/require() API works correctly against the sales agent's existing capabilities response. No immediate action needed on the sales agent side.

@bokelley
Copy link
Contributor Author

Thanks for the thorough review @KonstantinMirin!

1. MRO override detection — fixed ✅

Good catch on the mixin pattern. Updated validate_capabilities() to walk type(handler).__mro__ up to (excluding) ADCPHandler, so overrides inherited from intermediate classes are correctly detected. Added a test for the ConversionMixin → MyHandler pattern you described. See 3715d59.

2. Feature namespace prefixes

Agree this is worth thinking about. Today media_buy and signals feature names are disjoint in the spec (media_buy has audience_targeting, conversion_tracking, etc.; signals has catalog_signals, get_signals). If the spec ever introduces a collision, the current "media_buy wins" behavior would be a bug.

I'd lean toward adding signals. prefix support in a follow-up when we add more signals features, rather than changing the API shape now when there's only one consumer pattern. Open to discussing if you feel strongly about establishing the convention early.

3. TASK_FEATURE_MAP coverage

Added a comment in the code documenting the intentional scope. Opening a tracking issue for the remaining mappings makes sense — I'll create one after this merges so we can enumerate what's needed as the handler methods land.

4. Sales agent impact

Thanks for confirming no breaking changes on that side. Agreed that validate_capabilities() isn't applicable to FastMCP-based agents today, but the buyer-side supports()/require() API will work against any seller's capabilities response.

Adds FeatureResolver for resolving feature support from capabilities
responses, shared by both client (buyer) and server (seller) sides.

Client-side: supports(), require(), fetch_capabilities() with TTL caching,
and opt-in automatic validation on task calls via validate_features=True.

Server-side: validate_capabilities() checks that declared features have
corresponding handler method overrides, walking the MRO for mixin support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bokelley bokelley force-pushed the bokelley/feature-validation branch from 55d62af to d550c08 Compare March 17, 2026 00:06
@bokelley bokelley merged commit f86f6c4 into main Mar 17, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature capability validation: require/supports API

2 participants