Add configuration-driven OpenRTB auction providers - #1016
Add configuration-driven OpenRTB auction providers#1016ChristianPavilonis wants to merge 6 commits into
Conversation
8de9eab to
0c98095
Compare
|
@ChristianPavilonis to test in staging |
Make auction behavior derive from one validated provider plan so startup, runtime routing, browser demand, and platform backend handling cannot drift across adapters.\n\nPreserve existing Prebid and APS behavior while allowing multiple typed OpenRTB providers and rejecting the retired list-shaped configuration.
51239d1 to
ba2eea6
Compare
prk-Jr
left a comment
There was a problem hiding this comment.
Summary
Large, coherent rework: provider identity, routing, transport, and response handling all move out of singleton integrations into one immutable, validated AuctionPlan shared by every adapter. The plan compiler, profile registry, and pure backend-naming policy are well factored, and the new validation (endpoint canonicalization, backend-name collision prediction, notification seat limits, static-extension bounds) is thorough.
Two blocking issues: the required cargo test check is failing because of this PR, and the config schema break ships with no operator-facing migration note.
1 of the inline comments below carries a one-click GitHub
suggestion— use Commit suggestion to apply it as a commit on the PR branch. The remaining comments describe the fix in prose because the change spans multiple files, touches lines outside the diff, or is a design question rather than a patch.
Blocking
wrench
- Required
cargo testjob fails: template-cache harness configures no auction provider — see Cross-cutting below - Breaking config cutover with no CHANGELOG entry and no safe deploy ordering — see Cross-cutting below
- Dead tautological assertion in the moved registration loop — see inline at
crates/trusted-server-core/src/integrations/registry.rs:827
Non-blocking
thinking / refactor
- One malformed envelope entry silently zeroes a slot's server-side demand — see inline at
crates/trusted-server-core/src/auction/routing.rs:434 - HTTPS-only endpoint canonicalization blocks loopback stub endpoints — see inline at
crates/trusted-server-core/src/auction/plan.rs:570 #[cfg(test)]orchestrator harness re-implements the production dispatch path — see inline atcrates/trusted-server-core/src/auction/orchestrator.rs:318run_auctioncarries the same body twice under oppositecfggates — see inline atcrates/trusted-server-core/src/auction/orchestrator.rs:849apply_prebidpairs imps to slots positionally — see inline atcrates/trusted-server-core/src/auction/openrtb.rs:280- Browser shim ownership inverted: unowned bidders now fail open to client-side — see Cross-cutting below
praise
- Response currency is finally checked — see inline at
crates/trusted-server-core/src/auction/openrtb.rs:552
Cross-cutting / body-level findings
-
wrench — Required
cargo testjob fails: the template-cache harness no longer configures any auction provider.scripts/template-cache-local-test.shis not touched by this PR, but thecargo testjob runs it, and it patches the example config by literal string replacement:s = s.replace('[integrations.prebid]\nenabled = false\nserver_url = "https://prebid.example.com/openrtb2/auction"', ...) s = s.replace('providers = []', 'providers = ["prebid"]', 1)
Both target strings were deleted from
trusted-server.example.tomlby this PR (grep -c 'providers = \[\]'andgrep -c server_urlboth return 0), so both replacements are silent no-ops. The stub then runs with[auction] enabled = trueand zero providers, so no bids are produced and 6 assertions fail in thecargo testjob:FAIL a bids script is present — got '0', want '1' FAIL the seam carries slot definitions, not just bids — got '0', want '1' FAIL the slot definitions reach the guarded scheduler — got '0', want '1' FAIL the winning bid's bucketed price reaches the reader — got '0', want '1' FAIL the served seam failed the real GPT module contract: Error: served document has no executable seam payload FAIL cache hit streams: the article is delivered before the auction resolves — got 'no', want 'yes' 15 passed, 6 failedRewriting the replacements to the new map shape is not sufficient on its own:
canonicalize_endpointrequiresscheme == "https"(crates/trusted-server-core/src/auction/plan.rs:570) and the harness stub endpoint ishttp://127.0.0.1:{port}/bid. The previous path accepted any scheme, sinceserver_urlcarried only#[validate(url)]. The harness needs either an HTTPS stub backend or an explicit loopback exemption in endpoint validation. -
wrench — Breaking config cutover ships with no CHANGELOG entry and no safe deploy ordering. Two schema breaks land together:
[auction].providerschanges from a list to a map (the list shape is explicitly rejected), andPrebidIntegrationConfigis rebuilt as a browser-only config with#[serde(deny_unknown_fields)], droppingserver_url,bidders, and the server-side override fields.IntegrationRegistry::with_plancallsprebid::register_for_plan, which doessettings.integration_config::<PrebidIntegrationConfig>(PREBID_INTEGRATION_ID)?. A live config blob still carryingserver_urltherefore fails to parse, the error propagates out ofbuild_state_from_settings, and the adapter comes up on the startup-error router. The reverse ordering fails too: a map-shaped blob does not parse on a binary that predates this PR. There is no deploy ordering that avoids an outage window — binary and config have to cut over together.CHANGELOG.mdis untouched by this PR. The repo documents exactly this class of change under[Unreleased] / Changedwith a Breaking marker and explicit upgrade/rollback ordering (see thesanitize_creativesand APS OpenRTB entries, both of which spell out "upgrade the binary first, then push the config" and the rollback constraint). This change needs the same treatment, including the fact thatts config pushnow rejects the old shape and that the previous log-and-strip tolerance for unknownbidders/client_side_biddersentries is now a hard startup error. -
thinking — Browser shim ownership inverted: unowned bidders now fail open to client-side. In
crates/trusted-server-js/lib/src/integrations/prebid/index.ts,installPrebidNpmpreviously folded every bidder not listed inclientSideBiddersinto thetrustedServerenvelope and stripped it fromunit.bids. It now folds only codes present inserverSideBidders(that is,[auction.bidders]) and leaves everything else in browser demand:unit.bids = unit.bids.filter( (bid) => bid?.bidder === ADAPTER_CODE || !serverSideBidders.has(bid?.bidder ?? '') );
An operator who upgrades the binary and pushes a config without populating
[auction.bidders]silently moves all demand from the server-side auction to direct browser SSP calls. There is no error and no warning;validate_browser_bidder_ownershiponly rejects codes claimed by both sides at once. Worth calling out explicitly in the migration note above, since it is a first-party-proxying regression that will not show up as a failure anywhere.
CI Status
- cargo test: FAIL (required)
- cargo fmt: PASS (required)
- format-typescript: PASS (required)
- format-docs: PASS (required)
- cargo test (axum native): PASS
- cargo test (cloudflare native): not reported separately;
cargo check (cloudflare native + wasm32-unknown-unknown): PASS - cargo check/build/test (spin native + wasm32-wasip1): PASS
- cargo test (cross-adapter parity): PASS
- cargo test (ts CLI, native): PASS
- vitest: PASS
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- browser integration tests: PASS
- prepare integration artifacts: PASS
- CodeQL: PASS
- Analyze (rust): PASS
- Analyze (javascript-typescript): PASS (reported twice, from two workflow runs)
- Analyze (actions): PASS
The suggestion in this review was applied in an isolated worktree at ba2eea6 and verified against the full gate: cargo fmt --all -- --check, all six clippy aliases, cargo test-fastly / test-axum / test-cloudflare / test-spin, and the cross-adapter parity suite — all pass, with no drift between the approved bytes and the post-verification tree.
|
Addressed the requested changes in 35e1897:
I deliberately retained fail-closed malformed-envelope handling, HTTPS-only provider endpoints, and configured browser/server bidder ownership. The broader Validation passed across Fastly, Axum, Cloudflare, Spin, CLI, parity, clippy, JS, formatting, and both template-cache harness modes. All inline threads have replies and are resolved. |
Summary
The old design tied provider identity, routing, transport, and response handling to singleton implementations. Adding another standards-compliant endpoint required more provider-specific code, and each adapter could derive backend behavior independently. This implementation moves those decisions into validated configuration while preserving existing Prebid Server and Amazon Publisher Services behavior.
Changes
Changed files
Root configuration and guidance
Cargo.lockREADME.mdTESTING.mdtrusted-server.example.tomlAdapters and CLI
crates/trusted-server-adapter-axum/src/app.rscrates/trusted-server-adapter-axum/src/platform.rscrates/trusted-server-adapter-axum/tests/routes.rscrates/trusted-server-adapter-cloudflare/src/app.rscrates/trusted-server-adapter-cloudflare/src/platform.rscrates/trusted-server-adapter-fastly/Cargo.tomlcrates/trusted-server-adapter-fastly/src/app.rscrates/trusted-server-adapter-fastly/src/backend.rscrates/trusted-server-adapter-fastly/src/platform.rscrates/trusted-server-adapter-fastly/src/tinybird.rscrates/trusted-server-adapter-spin/src/app.rscrates/trusted-server-adapter-spin/src/platform.rscrates/trusted-server-cli/src/prebid_bundle.rscrates/trusted-server-cli/tests/config_env_overlay.rsAuction core
crates/trusted-server-core/src/auction/README.mdcrates/trusted-server-core/src/auction/endpoints.rscrates/trusted-server-core/src/auction/formats.rscrates/trusted-server-core/src/auction/mod.rscrates/trusted-server-core/src/auction/openrtb.rscrates/trusted-server-core/src/auction/openrtb/test_executor.rscrates/trusted-server-core/src/auction/openrtb/tests.rscrates/trusted-server-core/src/auction/orchestrator.rscrates/trusted-server-core/src/auction/plan.rscrates/trusted-server-core/src/auction/profile.rscrates/trusted-server-core/src/auction/provider.rscrates/trusted-server-core/src/auction/routing.rscrates/trusted-server-core/src/auction/telemetry.rscrates/trusted-server-core/src/auction/test_support.rscrates/trusted-server-core/src/auction/types.rsConfiguration, platform, and request handling
crates/trusted-server-core/src/auction_config_types.rscrates/trusted-server-core/src/config.rscrates/trusted-server-core/src/config_payload.rscrates/trusted-server-core/src/creative_opportunities.rscrates/trusted-server-core/src/html_processor.rscrates/trusted-server-core/src/platform/backend_naming.rscrates/trusted-server-core/src/platform/http.rscrates/trusted-server-core/src/platform/mod.rscrates/trusted-server-core/src/platform/test_support.rscrates/trusted-server-core/src/platform/traits.rscrates/trusted-server-core/src/publisher.rscrates/trusted-server-core/src/settings.rscrates/trusted-server-core/src/test_support.rsIntegrations
crates/trusted-server-core/src/integrations/adserver_mock.rscrates/trusted-server-core/src/integrations/aps.rscrates/trusted-server-core/src/integrations/didomi.rscrates/trusted-server-core/src/integrations/google_tag_manager.rscrates/trusted-server-core/src/integrations/gpt_diagnostics.rscrates/trusted-server-core/src/integrations/mod.rscrates/trusted-server-core/src/integrations/nextjs/mod.rscrates/trusted-server-core/src/integrations/prebid.rscrates/trusted-server-core/src/integrations/registry.rscrates/trusted-server-core/src/integrations/sourcepoint.rsBrowser and integration tests
crates/trusted-server-integration-tests/fixtures/configs/trusted-server.integration.tomlcrates/trusted-server-js/lib/src/integrations/prebid/index.tscrates/trusted-server-js/lib/test/integrations/prebid/index.test.tscrates/trusted-server-js/lib/test/prebid-artifact-integration.test.mjsOperator and architecture documentation
docs/guide/api-reference.mddocs/guide/architecture.mddocs/guide/auction-orchestration.mddocs/guide/configuration.mddocs/guide/ec-setup-guide.mddocs/guide/error-reference.mddocs/guide/fastly.mddocs/guide/first-party-proxy.mddocs/guide/getting-started.mddocs/guide/integration-guide.mddocs/guide/integrations-overview.mddocs/guide/integrations/aps.mddocs/guide/integrations/prebid.mddocs/guide/proxy-signing.mddocs/superpowers/plans/2026-08-11-config-first-auction-provider-architecture-implementation-plan.mddocs/superpowers/specs/2026-08-10-config-first-auction-provider-architecture-design.mdScope
This is a large change because provider configuration is now the single source of truth for startup validation, adapter backend registration, runtime dispatch, browser bidder exposure, telemetry, and operator documentation. Shipping only part of that path would leave the old and new models active at the same time and allow them to disagree. The pull request keeps the work focused on auction-provider configuration and execution; it does not replace the existing static mock mediator or add runtime-loadable provider plugins.
Target-aware validation before
ts config pushremote I/O remains blocked on publishing and pinning the required EdgeZero callback dependency. The shared target-independent compiler and adapter startup validation are included here.Closes
Closes #1026
Test plan
Full verification still needs to run on the rebased implementation head. The current remote head has completed only the JavaScript and TypeScript CodeQL check.
cargo test-fastly && cargo test-axum && cargo test-cloudflare && cargo test-spin./scripts/test-cli.shcargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test paritycargo fmt --all -- --checkcargo clippy-fastly && cargo clippy-axum && cargo clippy-cloudflare && cargo clippy-cloudflare-wasm && cargo clippy-spin-native && cargo clippy-spin-wasmcd crates/trusted-server-js/lib && npx vitest runcd crates/trusted-server-js/lib && npm run formatcd docs && npm run formatChecklist
unwrap()in production code; useexpect("should ...")logmacros, notprintln!