feat: delivery domain completion + media buy test coverage (v3.6)#1081
Open
KonstantinMirin wants to merge 294 commits intoprebid:mainfrom
Open
feat: delivery domain completion + media buy test coverage (v3.6)#1081KonstantinMirin wants to merge 294 commits intoprebid:mainfrom
KonstantinMirin wants to merge 294 commits intoprebid:mainfrom
Conversation
…tes across 4 files) Completes transport-agnostic error handling migration for the complex modules: media_buy_create (23 raise sites + 6 except blocks), products (9 sites), creatives/listing (5 sites), and media_buy_update (4 sites). Adds re-raise guard in media_buy_create to prevent AdCPError from being re-wrapped as MEDIA_BUY_CREATION_ERROR. Updates 8 test files to expect AdCPError subclasses. Also fixes pre-existing mypy errors in mcp_server_enhanced.py and api_v1.py.
Creates transport-agnostic ResolvedIdentity type in src/core/resolved_identity.py with resolve_identity() boundary helper that implements 4-strategy tenant detection (Host/subdomain, x-adcp-tenant, Apx-Incoming-Host, localhost fallback) and token validation. Consolidates auth.py::get_principal_from_token to delegate to auth_utils version (gains retry logic + admin token support). Adds 11 unit tests.
…edIdentity All 14 _impl functions now accept identity: ResolvedIdentity | None instead of ctx: Context | ToolContext | None. Transport-specific auth extraction moves to MCP wrappers via resolve_identity_from_context(). New module: src/core/transport_helpers.py bridges transport types to the transport-agnostic ResolvedIdentity at MCP/A2A/REST boundaries. Updated 19 source files and 20 test files (131 test fixes). 2429 unit tests pass.
Replace broken REST tenant heuristic (split principal on underscores) with shared resolve_identity() used by all three transports. Remove MinimalContext workaround and cast(ToolContext) patterns from A2A server, simplify _verify_principal to accept ResolvedIdentity only.
Move get_http_headers extraction from _impl to MCP transport wrappers in media_buy_create and media_buy_update. Replace rich console.print with logger.info in performance _impl. Add AST-based regression tests ensuring _impl functions never import from fastmcp/a2a/starlette/fastapi and never use console.print.
…vedIdentity Replace ctx= parameter with identity= across 10 test files after prebid#1050 handler migration changed _impl function signatures. Mechanical change: ToolContext/MagicMock/MockContext → ResolvedIdentity with AdCPTestContext. Test intent preserved, only context type changes.
Remove patches targeting get_principal_from_context and get_principal_id_from_context on modules that no longer import them after prebid#1050 migration. Pass identity=ResolvedIdentity directly to _impl functions instead. 8 failures across 3 files fixed.
…ests Replace Mock(spec=['meta']) with ResolvedIdentity in test_get_products_format_id_filter.py. Mock lacked tenant and testing_context attributes now required by _get_products_impl.
After prebid#1050 migration, auth failures raise AdCPAuthenticationError instead of ToolError. Update 6 auth tests across 4 files to accept both exception types, preserving security test intent.
- Add AdCPValidationError to expected exceptions in error_paths tests - Add AdCPAuthenticationError to creative_lifecycle auth tests - Fix A2A get_products to include message/success protocol fields - Fix A2A error response tenant context for artifact extraction - Fix delivery webhook scheduler to patch ResolvedIdentity not ToolContext - File separate issues for pre-existing webhook/UI failures (salesagent-3etp, q6cb)
…ext() Replace 7 scattered try/except blocks in _impl functions with a single ensure_tenant_context(identity) helper. This fixes the remaining 40 "Principal not found" integration test failures caused by the prebid#1050 migration losing the set_current_tenant() side effect. The helper handles: string→dict conversion, ContextVar mismatch detection, DB-backed tenant loading, and identity-based fallback. 23 files changed (8 source, 15 tests).
…ansport boundary - Add TenantContext Pydantic model with typed fields and dict-like backward compat - Update _load_full_tenant() to return TenantContext instead of raw dict - Update resolve_identity() to wrap detected tenant dicts in TenantContext - Remove ensure_tenant_context() calls from all 7 _impl modules - _impl functions now use identity.tenant directly (resolved at transport boundary) - Update regression tests to verify TenantContext type and new patterns - All 2,448 unit tests pass Core invariant: Tenant context is resolved ONCE at the transport boundary and passed through ResolvedIdentity as a TenantContext model — business logic never resolves, loads, or validates tenant itself.
Introduces LazyTenantContext that holds tenant_id immediately and defers the full DB query until a non-tenant_id field is first accessed. This avoids hitting the database for requests that only need tenant_id (the common case) or that fail auth before reaching tenant-dependent logic. - LazyTenantContext supports same dict-like and attribute access as TenantContext - tenant_id, __contains__, __bool__ all work without triggering DB load - DB result is cached after first resolution (single query per request) - set_current_tenant() called lazily when full tenant is resolved - Tests verify no-DB-for-tenant_id-only and single-query-on-field-access
…ions Thread tenant through identity.tenant instead of reading from get_current_tenant()/set_current_tenant() ContextVars. Added tenant parameter to get_adapter() for explicit dependency passing. All 12 _impl modules now use identity.tenant exclusively; only transport- adjacent handlers retain legitimate ContextVar usage.
…igration Thread tenant_id through auth functions instead of reading from ContextVar. Use self.tenant_id in MockAdServer instead of get_current_tenant(). Serialize FormatId before JSONB storage in workflow steps. Update integration tests to use ResolvedIdentity directly and accept AdCPAdapterError from _impl calls.
- Refactor TestAuthOptionalEndpoints to use live_server and test_auth_token fixtures instead of reading TEST_AUTH_TOKEN env var (3 tests no longer skip) - Rename test_page → _check_page to prevent pytest miscollection as standalone test (1 error fixed) - Replace sys.exit(1) with pytest.fail()/pytest.skip() in test_all_admin_pages and handle ConnectionError gracefully (1 failure fixed) - Import integration_db fixture into tests/ui/conftest.py and fix test_environment to preserve DATABASE_URL for @pytest.mark.requires_db tests regardless of directory (4 errors fixed)
Merge run_full_tests_json.sh into run_all_tests.sh. Both quick and ci modes now produce JSON reports in timestamped test-results/<ddmmyy_HHmm>/ folders. Added set -o pipefail to fix exit code masking through tee pipes. Added test-results/ to .gitignore. Updated CLAUDE.md, docs, and quality gates documentation.
E2E (3 tests): Fix MCP endpoint URL in TestAuthOptionalEndpoints — change POST target from /mcp/tools/call (non-existent) to /mcp/ (the actual Streamable HTTP endpoint), add required JSON-RPC 2.0 fields (jsonrpc, id). UI (3 tests): Add marker filter (-m "not requires_server and not slow") to UI suite in run_all_tests.sh to skip test_all_admin_pages which requires a live server. Add missing property_mode and selected_property_tags form fields to test_add_product_json_encoding. Rename formats= to format_ids= kwarg in test_list_products_json_parsing.
…at_ids - E2E: Add required Accept: application/json, text/event-stream header for MCP Streamable HTTP protocol (6 tests in TestAuthOptionalEndpoints) - E2E: Extract MCP_HEADERS class constant to avoid 7x duplication - UI: Use property_mode=none to bypass tag validation in JSON encoding test - UI: Fix format_ids to use AdCP structure (id + agent_url fields)
…ssertion E2E (5 tests): Rewrite TestAuthOptionalEndpoints to use fastmcp Client with StreamableHttpTransport instead of raw requests.post(). MCP Streamable HTTP requires session initialization handshake. Without-auth tests use Host header for domain-based tenant resolution (no xfail). UI test_add_product_json_encoding: Use indexed pricing form fields (pricing_model_0, floor_0) matching what the HTML form actually sends — parse_pricing_options_from_form() expects this indexed format. UI test_list_products_json_parsing: Remove fragile b'500' assertion that matched base template JS setTimeout(..., 500). status_code == 200 and product name presence already verify correct rendering.
…cks, xfails) - salesagent-3laa: Fix unawaited coroutine in ActivityFeed — extract sync _store_activity() method, check for running event loop before creating broadcast coroutine to prevent RuntimeWarning leak - salesagent-5shl: Fix unawaited coroutine in naming.py — replace asyncio.run() with run_async_in_sync_context() for nested event loop safety - salesagent-r5xr: Rename TestScenario → ScenarioSpec to avoid PytestCollectionWarning (pytest collects classes prefixed with "Test") - salesagent-nehy: Replace return with assert in test_create_minimal_gam_tenant (PytestReturnNotNoneWarning) - salesagent-fjxw: Fix 3 xfailed admin domain e2e tests — add admin redirect case to _handle_landing_page(), add nginx proxy + env vars to docker-compose.e2e.yml - salesagent-jmx8: Add missing video_standard_30s to mock format registry, remove reactive skip from GAM pricing test
…bid#1041) - Fix pause/resume early-return not completing workflow step (left in_progress forever) - Fix approval gate storing no request data (empty affected_packages only) - Store original request_data in workflow step for post-approval execution - Remove stale xfail from test_admin_ui_network_detection_endpoint - Fix test session setup: use sess["user"] dict for require_tenant_access - Mock full GAM OAuth chain in network detection test
…noise Suppress ~122 warnings/run from a2a-sdk, starlette, httplib2, google-generativeai, googleads, jsonschema, and zeep. Our own code warnings remain visible via the default action.
…ion warnings httplib2 v0.31.2 fixes deprecated pyparsing API usage (setName, leaveWhitespace, setParseAction, etc.) that produced ~9 warnings per test run.
Replace deprecated jsonschema.RefResolver.from_schema() with the referencing library's Registry(retrieve=...) pattern in the e2e schema validator. Eliminates ~19 DeprecationWarning per e2e test run.
Production code already uses pydantic-ai (google-genai) for all AI operations. Remove the dead google-generativeai dependency, migrate the example file to the google.genai SDK, and clean up 5 dead test fixtures that patched the old module.
FastMCP's __init__.py calls simplefilter("default", DeprecationWarning)
at import time, which prepends a catch-all filter that shadows pytest.ini's
ignore entries. Set FASTMCP_DEPRECATION_WARNINGS=false via pytest_configure()
so the a2a HTTP_413 and starlette WSGI filters work as intended.
- Close event loops in test_task_management_tools.py (3 helpers) - Close TestClient in test_a2a_transport_contract.py fixture teardown - Close subprocess stdout/stderr pipes in mcp_server fixture - Use Flask test_client() context manager in test_health_route_migration.py Reduces ResourceWarnings from 52 to ~15 across test suites.
Swap starlette.middleware.wsgi import to a2wsgi (starlette-recommended drop-in replacement). Also clean up filterwarnings entries for packages no longer installed (httplib2, google-generativeai, jsonschema RefResolver).
Add dedicated e2e test file for AdCP discovery endpoints that exercise the full MCP transport path against the Docker stack with no mocking.
AdCP JSON schema for get-products-request.json added a time_budget field that the adcp library does not yet model. This caused 2 test failures in test_pydantic_schema_alignment.py. Added to KNOWN_SCHEMA_LIBRARY_MISMATCHES until the adcp library adds support.
_get_pricing_options() was casting string pricing_option_ids to int and querying PricingOption.id (auto-increment PK). Non-numeric synthetic IDs like 'cpm_usd_fixed' were silently discarded, causing pricing context loss in delivery responses. The fix reconstructs the synthetic pricing_option_id from the PricingOption's (pricing_model, currency, is_fixed) columns -- the same formula used by product_conversion.py -- and matches against requested string IDs. - Remove stale PricingOption.id.in_ entry from query type safety allowlist - Fix 4 xfail integration tests (now passing) - Update unit test mock to match new lookup behavior - Update test_delivery_v3 roundtrip to use synthetic ID
Add optional conversions (float) and viewability (float, 0.0-1.0) fields to DeliveryTotals schema. Propagate values from adapter response totals through to the delivery response. Update integration tests that were asserting viewability absence (gap G44) to assert presence instead, and remove xfail markers from the 2 obligation tests.
Add GetMediaBuyDeliveryResponse.webhook_payload() that excludes aggregated_totals (polling-only) and supports requested_metrics filtering for per-delivery totals. Remove xfail markers from two webhook payload tests.
… delivery response - Auto-set notification_type: 'scheduled' for active campaigns, 'final' for completed - Compute next_expected_at as now + 24h for non-final deliveries - Persist auto-incrementing sequence_number via WebhookDeliveryLog - Fix status filter: return all matching buys when specific IDs provided
- Add is_paused boolean column to MediaBuy model with migration - _resolve_delivery_status returns 'paused' when is_paused is True - Status filter 'paused' works in _get_target_media_buys - deliver_webhook_with_retry rejects delivery for paused media buys - _get_media_buy_delivery_impl checks circuit breaker state and sets 'reporting_delayed' status when circuit is OPEN - Remove 3 xfail markers from now-passing tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Auth failure (401/403) sets persistent auth_blocked_at on PushNotificationConfig, blocking further delivery until credentials are reconfigured (UC-004-EXT-G-07) - Adapter failures during delivery polling now write AuditLog records for persistent audit trail (NFR-003, UC-004-EXT-F-03) - Add auth_blocked_at column to PushNotificationConfig model - Skip auth-blocked endpoints in WebhookDeliveryService - Remove xfail markers from passing tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation - scripts/check_scoped_coverage.py: per-entity coverage checker using scripts/run-test.sh for test execution (no manual DATABASE_URL exports) - tests/coverage_scopes.yaml: scope definitions derived from AdCP schema entities (delivery=100% target, pre-existing code=90% minimum) Usage: scripts/check_scoped_coverage.py delivery --verbose
The legacy fallback converting raw_request.product_ids to packages format (lines 372-375) is dead code. Investigation confirms: - CreateMediaBuyRequest requires packages (validation raises if empty) - AdCPBaseModel.model_dump uses exclude_none=True by default, so raw_request always contains "packages" key for valid media buys - Transport wrappers accept product_ids but never pass it to the request constructor - A2A server explicitly documents legacy format is not supported Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add TestCircuitBreakerReportingDelayed: exercises real _is_circuit_breaker_open() code path by injecting an OPEN CircuitBreaker into the global singleton, verifying that active media buys get status='reporting_delayed' (covers lines 66-68) - Add TestPartialFailureTolerance: verifies that when one media buy's processing raises an exception, other buys are still returned in the response (covers the outer except handler at lines 485-487) - hq98 diagnosis: adapter failure audit trail (lines 304-319) already covered by existing TestAdapterFailureAuditTrail test Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ith_backoff Add 9 integration tests covering: - Auth-blocked PushNotificationConfig skip (UC-004-EXT-G-07) - HMAC-SHA256 signing with secret validation (UC-004-EXT-G-06) - Bearer token authentication (UC-004-ALT-WEBHOOK-PUSH-REPORTING-08) - Happy path delivery to configured endpoint (UC-004-ALT-WEBHOOK-PUSH-REPORTING-01) - No-config returns false (UC-004-ALT-WEBHOOK-PUSH-REPORTING-01) - Successful delivery records success on circuit breaker (UC-004-EXT-G-01) - 500 retry with backoff and circuit breaker failure (UC-004-EXT-G-01) - Timeout handling with retries (UC-004-EXT-G-01) All tests use CircuitBreakerEnv with real PostgreSQL for PushNotificationConfig queries and mock httpx for HTTP. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ryService Grepped entire codebase — zero callers in production or test code. Other methods in the range (reset_sequence, get_circuit_breaker_state, _shutdown) are live and remain untouched. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover 8 previously uncovered lines in src/core/schemas/delivery.py: - Line 304: model_dump() override forcing next_expected_at=null - Lines 311, 314: __str__() for GetMediaBuyDeliveryResponse - Lines 486-491: __str__() for GetCreativeDeliveryResponse New test classes: - TestMediaBuyDeliveryResponseStr: zero/one/many pattern - TestCreativeDeliveryResponseStr: zero/one/many pattern - TestNextExpectedAtSerialization: final/scheduled/none cases Obligation IDs: UC-004-DISPLAY-01, UC-004-SERIAL-01 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 9 integration tests to test_delivery_webhook_behavioral.py: SSRF validation (salesagent-dk73): - Invalid/internal URL rejected with validation error - Metrics recorded on validation failure with tenant context - Metrics skipped when no tenant_id provided Retry backoff (salesagent-pggp): - 5xx retry with eventual success (503->503->200) - 5xx retry exhaustion (always 500, max retries reached) - Timeout exception triggers retry - ConnectionError triggers retry - RequestException triggers retry - All retries timeout reports failure Covers: webhook_delivery.py lines 93-99 (SSRF) and 222-235 (retry exceptions) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The requires_server marker had its skip logic removed but test_connect_to_local_mcp_server still needs the full Docker stack. Restore conditional skip with socket probe on localhost:8100. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover webhook_delivery.py lines 355, 357, 383-384: the defensive catch-all handlers in _update_delivery_record and _set_auth_blocked that absorb DB errors to avoid disrupting delivery results. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove dead WebhookQueue.size() method (zero callers). Add 11 unit tests covering: CircuitBreaker HALF_OPEN can_attempt, record_success while OPEN, WebhookQueue full/empty, reset_sequence, get_circuit_breaker_state default, generic exception retry break, and _shutdown handler. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove dead code in media_buy_delivery.py: - Unreachable else branch (adapter totals always present) - Unreachable ext lookup (no ext field on adapter response) - Unused _require_admin function and its import Add 5 unit tests: missing principal_id, missing tenant, raw string status filter edge cases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Include test_webhook_delivery.py and test_webhook_delivery_service.py in the delivery coverage scope config so their coverage contribution is measured. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ge cases - is_adjusted notification type (line 239) - queue full drops webhook (lines 408-409) - weak secret omits signature (line 463) - empty dequeue returns False (line 447) Brings webhook_delivery_service.py from 96.9% to ~99% scoped coverage. Only 2 uncovered lines remain (shutdown exception handler lines 545, 547). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zero production callers — all MCP wrappers use resolve_identity() via ResolvedIdentity. Removes: - Function definition from context_helpers.py - Re-exports from helpers/__init__.py and creatives/__init__.py - No-op mock patches from test_update_media_buy_creative_assignment.py - Direct test from test_tenant_context_ordering.py Updates pre-commit hook (check_tenant_context_order.py) to recognize identity.principal_id/identity.tenant as valid auth patterns instead of the removed function. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ption_id code - Fix PricingModel.cpc enum vs string comparison: DB stores raw strings, but code compared against enum member. Use .value for correct comparison. - Remove top-level pricing_option_id collection and usage from raw_request (not in AdCP spec, violates per-package pricing abstraction). - Add integration test: CPC package clicks = floor(spend / cpc_rate) (domain business rule, not spec-mandated). - Add integration test: start_time preferred over start_date for status determination (data migration strategy for legacy NOT NULL column). Delivery scoped coverage: 97.5% -> 98.1% Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolves conflicts from squash-merge of PR prebid#1071 (AdCP v3.6 upgrade) into main. Key resolutions: - Keep our schemas/ package structure (main has flat schemas.py) - Keep our delivery additions (conversions, viewability, webhook_payload) - Keep dead code removals (get_principal_id_from_context, top-level pricing_option_id) - Keep CPC enum comparison fix (PricingModel.cpc.value) - Apply main's Creative schema fix (name required, dates auto-default) - Update test mocks for is_paused field and synthetic pricing IDs - Clean obligation coverage allowlist (remove covered entries) - Update architecture guard known violations for fixed issues Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The squash-merge of prebid#1071 auto-merged test_create_media_buy_behavioral.py and test_update_media_buy_behavioral.py to main's shorter versions (38 tests), silently dropping our branch's 148-test versions (74+74 obligation stubs for UC-002 and UC-003). Restored our branch versions and fixed 7 broken tests where get_product_catalog patch target changed from src.core.main to src.core.tools.products (main moved the import). Removed 110 now-covered entries from obligation_coverage_allowlist.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…delivery-mb-cleanup # Conflicts: # docs/test-obligations/UC-004-deliver-media-buy-metrics.md # src/core/helpers/context_helpers.py # src/core/schemas/__init__.py # src/core/tools/creatives/__init__.py # src/core/tools/media_buy_delivery.py # src/core/version_compat.py # tests/unit/obligation_coverage_allowlist.json # tests/unit/test_architecture_obligation_coverage.py # tests/unit/test_architecture_query_type_safety.py # tests/unit/test_architecture_repository_pattern.py # tests/unit/test_architecture_schema_inheritance.py # tests/unit/test_create_media_buy_behavioral.py # tests/unit/test_delivery.py # tests/unit/test_delivery_behavioral.py # tests/unit/test_media_buy.py # tests/unit/test_tenant_context_ordering.py # tests/unit/test_update_media_buy_behavioral.py # tests/unit/test_version_compat_registry.py # tests/unit/test_webhook_delivery.py # uv.lock
- Commit untracked migration 886966ee9a9d (auth_blocked_at column) that 5cf35536db6f (is_paused) depends on — CI couldn't resolve the chain - Remove get_creative_delivery from expected MCP tools (tool was removed with creative_delivery.py but test_tool_registration.py kept the entry) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the Delivery entity vertical slice and expands Media Buy test coverage
for v3.6. Extracts delivery schemas into a standalone package, creates the
DeliveryRepository, fills 127+ behavioral obligation test stubs, and replaces
dict-based v2 compat with model-level serialization.
Merged with latest main (proper two-parent merge). All test suites pass locally.
Key Changes
35166f48PricingModel.cpcvs string"cpc"never matched; click derivation was silently disabled35166f48pricing_option_idlookup (not in AdCP spec)22dfdcfaget_principal_id_from_contextfunction (replaced by ResolvedIdentity)1ac07a4ed7d8c36fget_product_catalogpatch targetcee9eb3de0aa992a886966ee9a9d+ remove staleget_creative_deliverytool registrationBug found: CPC clicks derivation was silently broken
Line 386 compared
pricing_option.pricing_model(raw string"cpc"from DB) againstPricingModel.cpc(Python enum). Python enums don't compare equal to their.value—so the CPC click derivation formula
clicks = floor(spend / cpc_rate)never executed.Fixed by comparing against
PricingModel.cpc.value.Delivery scoped coverage: 97.9%
Local test results (all passing)
Prior Changes
c7c2727c479f3ca8src/core/schemas/delivery.pypackage95d05cf30deff46fe9404090add_v2_compat09798d8fa992281815213478Delivery domain extraction
src/core/database/repositories/delivery.py):webhook subscription and delivery log queries with tenant-scoped access
src/core/schemas/delivery.py): extracted from monolithicschemas.py; aligned against adcp spec — addedflight_ended/goal_mettoDeliveryStatus, documented naming mismatches (video_completionsvs speccompleted_views), added FIXMEs for webhook metadata placementIntegration test harness + factory_boy
tests/harness/):IntegrationEnvbase with factory session binding;domain envs (
DeliveryPollEnv,WebhookEnv,CircuitBreakerEnv) mock only externalservices, real DB for everything else
tests/factories/):TenantFactory,PrincipalFactory,ProductFactory,PricingOptionFactory,MediaBuyFactory,MediaPackageFactory,PushNotificationConfigFactorywith SubFactory cascadingObligation test coverage (127+ tests)
proposals, extensions, postconditions, upgrade paths
targeting overlay, manual approval, extensions A–O
Related