Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InterestGroupBuyers as promise #1093

Closed
patmmccann opened this issue Mar 21, 2024 · 31 comments
Closed

InterestGroupBuyers as promise #1093

patmmccann opened this issue Mar 21, 2024 · 31 comments

Comments

@patmmccann
Copy link
Contributor

patmmccann commented Mar 21, 2024

Similar to #851 , we are attempting to begin the PAAPI auction in parallel with header bidding. However, we [acting as TLS] dont know interestGroupBuyers of the component sellers, who haven't yet provided their perBuyerSignals, at the time of the auction start, and we'd like to include interestGroupBuyers as a promise. We do know the list of components we might expect to participate.

This https://github.com/WICG/turtledove/blob/main/FLEDGE.md#211-providing-signals-asynchronously suggests this field is not on the list. Should we just list every possible buyer we can think of?

@MattMenke2
Copy link
Contributor

Chrome can't do anything at all without the list of buyers, so providing the buyers asynchronously wouldn't allow the auction to make any progress until they were provided. For other fields, Chrome can get the list of buyers, start worklet processes, and start loading bidding scripts, even before they're provided.

That having been said, for component auctions, other components could be loading bidding scripts while another component is waiting on a promise, and perhaps some consumers would find promises here convenient.

I'm not coming out against this idea, just pointing out it doesn't provide as many benefits as promises do elsewhere.

@patmmccann
Copy link
Contributor Author

patmmccann commented Mar 21, 2024

We're noticing a lot of buyers completely dependent on perBuyerSignals delivered to them which is constructed from an off-device auction response. While this seems a poor choice by the buyer entities to me, is it reasonable to just list a bunch of buyers who may not end up delivering perBuyerSignals and counting on their bidding logic to bid zero in the absence of the signal?

Basically, what is worse, listing too many buyers or starting the auction late?

@MattMenke2
Copy link
Contributor

I think that likely depends on the performance of the device, the number of buyers, the number of interest groups per buyers, and the performance of the network, unfortunately.

Some way for buyers to be kicked out of the auction in the middle might help address the issue. We'd also have to delay generating bids until we received that information (booting out the buyer with the winning bid and then having to find a new winner seems like too much complexity, if we allowed buyers to be removed at any point in time.

It would be nice for buyers to be able to indicate they don't want to participate quickly, if they have no per-buyer signals, though I'm not really sure how something like that would be wired up, either. The priorityVector stuff lets buyers opt-out, but doesn't have access to those signals (And we can't provide them, for privacy reason, at the moment, though things may change once we support trusted signals coming from TEEs).

@wojciech-bialy-wpm
Copy link
Contributor

@patmmccann Perhaps componentAuctions, rather that IG buyers, could be provided as a Promise? I agree that the only way to make PAA viable is to execute as much of it as possible asynchronously.

For instance, if we could feed result of a component auction (a Promise that resolves into a Fenced Frame config) into top-level auction, rather than auctionConfig object, then we could spin component auction worklets as soon as prebid bidders return bids / CA configs.

This would of course mean that such result would need to carry more information (winning bid data and buyer logic), but Fenced Frames are already designed to keep information that is opaque to the browser.

@MattMenke2
Copy link
Contributor

Those independently run component auctions would have to return opaque nonces (We'd probably want to make them single use). That's not too difficult, though - the additionalBids stuff already uses opaque nonces. More difficult would be the fact that the "promise" isn't really a promise - we expose some information about the top-level auction to component auctions (namely, the top-level seller), so unless we made some way of passing that information in, we couldn't actually generate any bids until the promise was delivered to the main auction, so the promise would never actually resolve. And then we'd need some way of smuggling information out of an unresolved promise, which seems somewhat weird.

@MattMenke2
Copy link
Contributor

Actually, I guess the API to create unresolved component auctions could just return the nonce directly (Or a promise that returns a nonce before the auction actually completes), so that should be fine.

@wojciech-bialy-wpm
Copy link
Contributor

wojciech-bialy-wpm commented Mar 25, 2024

@MattMenke2

So.... we should be able to set up PAAPI vs Header Bidding like this?

async_component_auctions

This is an example with one just bidder providing one component auction config

In such case, we should be able to run buyer worklets of the component auctions (which requires the most computing power - proportional to buyers x interest groups x ads | ad components in an IG) concurrently with header bidding and adserver requests.

@MattMenke2
Copy link
Contributor

Yes - we'd probably want to have the promise for the component auction resolve instantly (or even just return a value directly) to an opaque GUID, rather than wait for the component auction to complete, to minimize timing leaks. Note that I'm just commenting on the technical feasibility of doing this without leaks, and not promising we'll take this on. This would also add yet more complexity to our already rather complicated auction.

@patmmccann
Copy link
Contributor Author

How about you support InterstGroupBuyers = all so I don't need to maintain a list of every buyer on the internet in an open source project to fill in this field?

@MattMenke2
Copy link
Contributor

MattMenke2 commented Apr 18, 2024

That's discussed back in #201. It was in earlier versions of the explainer, but support was never added, at the behest of the security folks (despite me being the only person who responded on that issue, not a decision I made).

@patmmccann
Copy link
Contributor Author

I think it is worth revisiting, because as an implementor, if we want to initiate PAAPI in parallel with header bidding, our only current path is to maintain a list of every dsp on the internet and pass them all in this field every time. I cannot imagine how forcing us into this workaround for the missing wild card serves some security concern, but I am often baffled by the attack vectors imagined.

@dgirardi
Copy link

dgirardi commented Apr 18, 2024

A middle ground could be to accept a promise for interestGroupBuyers, pre-fetch all IG's bidding logic when it is, but still only include the given whitelist when the promise resolves. As far as I understand the bidding logic cannot start until the signals are resolved, so in this scenario network time is the only thing that can be optimized.

@michaelkleber
Copy link
Collaborator

Hi @patmmccann: How can a seller possibly accept bids from everyone, even bidders with whom they have no financial relationship?

Separate from that, I think the security concern is pretty fundamental here: a publisher page is explicitly delegating the "ability to run code" to some collection of sellers (presumably with whom they have a trust relationship of some sort), and the sellers are in turn explicitly delegating that ability to some buyers. A seller who says "I will delegate the ability to run code to anyone in the world" is a radically different situation from today's web, in which any 3p that is invoked from a publisher page has some chain of trust going back to the 1p.

(These two issues are both discussed in #201 which led to the current no-wildcard state.)

@wojciech-bialy-wpm
Copy link
Contributor

Hi @patmmccann,

When it comes to fully parallel (like we're testing now), there is another issue - namely the fact that the potential buyers would like to generate Per Buyer Signals for their Component Auctions. This means that - since we wanted to completely untangle PAA from other ad channels - we had to recreate the logic that provides PBS signals separately from Prebid (think of it as a trimmed down version of the prebid adapter). It's doable when working with a limited set of test buyers (that you have a good relation with), it is however becoming an issue as we're scaling up our tests. That's why I'm looking now into asynchronously executing component auctions on adapter response.

But the point is that in both cases (independent PAA, PAA dependent on Prebid responses), we aren't really working with 'all buyers wilcard' scenario. We have to specify which partners (SSPs) are allowed to execute on-device code (Prebid adapter, or PAA analogue) and indicate willingness to participate in PAA auction.

@patmmccann
Copy link
Contributor Author

PBS can be a promise though and relies on the contextual auction, so I am pretty comfortable filling it in as a promise.

@patmmccann
Copy link
Contributor Author

@wojciech-bialy-wpm will you be in london for prebid ascent next week by any chance? would love to chat more

@wojciech-bialy-wpm
Copy link
Contributor

@patmmccann

Unfortunately no, though I would love an opportunity to chat. Perhaps it would be possible to set up a call (not necessarily during the Ascent)?

@patmmccann
Copy link
Contributor Author

Some way for buyers to be kicked out of the auction in the middle might help address the issue. We'd also have to delay generating bids until we received that information

@MattMenke2 this seems like a great idea, how about we list all the buyers up front but give the ssp a single culling opportunity at the same time auctionSignals is resolved?
Cc @michaelkleber

@thegreatfatzby
Copy link
Contributor

@patmmccann was thinking about an idea and I think Demetrio nailed it a few comments above here. Making sure the bidding logic is downloaded, attestations valid, etc, subject to normal caching, would save a lot of time, and then the calls can just be made/not-made based on something determined after auctionConfig is fully formed.

@thegreatfatzby
Copy link
Contributor

thegreatfatzby commented May 3, 2024

Talking with Pat offline (well, a different online), want to avoid nuanced confusion, here's what I understand @dgirardi to be suggesting and I'm agreeing with.

An auctionConfig would be declared with auctionSignals, perBuyerSignals as a promise, and interestGroupBuyers could now look something like below, with a static list (as today) but also a filtering callback:

auctionConfig = {
...
auctionConfig: promiseOne,
perBuyerSignals: promiseTwo,
interestGroupBuyers: {
   'list': [ib.adnxs.com, cool.tradedesk.com, epic.audigent.com...],
   'filterFunction': function(auctionConfig, list) {
       // logic that takes perBuyerSignals, seller signals, etc, and filter the ^ list further
   }
}
...
}

And what Chrome would do would be something like:

  1. navigator.runAdAuction(auctionConfig from above) is called, with auctionSignals and
  2. Among other things, Chromium starts to verify attestations and pull down/from-cache bidding functions for each origin in the auctionConfig.interestGroupBuyers.list. I think for on-device it's fine to spin up any worklets as well...server side that might get a bit more interesting.
  3. The promises resolve and Chrome sees that and calls the interestGroupBuyers.filterFunction with the auction config and interestGroupBuyers.list (fine to do this promise'y but this is just how my brain thinks about it)
  4. The function returns a new list of domains, and only IGs from the filtered list have their previously spun up worklets invoked with their bidding functions.

To be clear I am not saying this would require buyers=*...I see that as an independent question.

@dgirardi
Copy link

dgirardi commented May 3, 2024

Among other things, Chromium starts to verify attestations and pull down/from-cache bidding functions for each origin in the auctionConfig.interestGroupBuyers.list. I think for on-device it's fine to spin up any worklets as well...server side that might get a bit more interesting.

As I understand it, this still requires a list of buyers to be compiled before runAdAuction (and any worklet/network activity) can start. Functionally this is already possible if the filtering happens in decision logic, although I understand that may look different security wise.

Coming up with an a-priori list of buyers is the difficult bit - it requires us to essentially maintain and deploy a list of all known buyers on the Internet.

Since the buyers that can actually end up in the auction are a much smaller subset that is already known to the browser, it makes much more sense to have some mechanism to tell runAdAuction "please spin up what you can for all active IGs, while I collect buyers". Of course this is assuming that there's at least some useful things that can be done without compromising security.

@thegreatfatzby
Copy link
Contributor

@dgirardi I'm actually not 100% following why a list of buyers being known upfront is an issue overall...I do see why Prebid as an entity can't know that for all possible PB auctions, with all publisher configurations etc; I'm a little less clear why, for a specific auction, the SSPs that are included by the publishers build wouldn't be able to know their list of possible buyers in advance. My memory is that the SSPs wrapper can now return an auctionConfig that will be used as one of the configs for a component auction once GAM/the-ad-server reaches the private auction stage...won't the SSP be able to provide a list of buyers they are potentially interested in? Maybe Prebid takes that and as TLS provides a filtering callback.

Another thought that came to mind is allowing the auctionConfig, even in the absence or promises, to say something like "here are the buyers I'd like to include, please trigger getting their attestation/scripts/worklets, but if it's not already cached feel free to skip them for this auction", which presumably only happens at most once on a browser, at least for a good period of time.

@dgirardi
Copy link

dgirardi commented May 3, 2024 via email

@MattMenke2
Copy link
Contributor

Some way for buyers to be kicked out of the auction in the middle might help address the issue. We'd also have to delay generating bids until we received that information

@MattMenke2 this seems like a great idea, how about we list all the buyers up front but give the ssp a single culling opportunity at the same time auctionSignals is resolved? Cc @michaelkleber

I guess we would hold off on all scoring until that promise was resolved (or restructure auctions to keep around all bidding+scoring information until all bids have been scored + that promise has been resolved, instead of incrementally updating the top bid as scores come in). Seems feasible, at least, if we want to go that route.

@patmmccann
Copy link
Contributor Author

@michaelkleber @JensenPaul @MattMenke2 can we add this to the May 15 agenda? Would love to discuss live, seems like a lively discussion.

@patmmccann
Copy link
Contributor Author

patmmccann commented May 22, 2024

@michaelkleber made excellent points in live discussion:

  1. The proposed second phase of buyer ejection could be implemented in the sellerSignals promise, with the seller worklet using that signals to force some bidders to zero
  2. The browser, without a configuration object change, could implement some optimizations to avoid calling some buyers with inevitable 0 desirability

@JensenPaul indicated one could set the buyer timeout to zero to eject them with a promise.

@wojciech-bialy-wpm made a case for a more radical change, with the entire component auction config coming in as a promise. The chrome team suggested this is not practical to rehash.

@myonlinematters
Copy link

myonlinematters commented May 22, 2024

see meeting notes from 2024-05-22 for a more detailed discussion of the conclusions for current operations and remaining open design issues for this issue.

@patmmccann
Copy link
Contributor Author

@MattMenke2 @JensenPaul @michaelkleber this seems to be sorted prebid/Prebid.js#12205

any objections to me closing this?

@MattMenke2
Copy link
Contributor

None from me, at least.

@wojciech-bialy-wpm
Copy link
Contributor

Looks good!

The only issue I see is that this will not work with the Google Ad Manager at the moment:

"Currently this is only relevant with topLevelPAAPI, where it has the effect of starting PAAPI auctions at the time of requestBids. The same could be done for GAM/paapiForGpt as soon as we have a method to trigger its PAAPI auctions separately from targeting/slot refreshes."

Then again, this not an issue with PAAPI, or with Prebid for that matter - but with the way GAM bundles PAAPI config with contextual ad request.

@patmmccann
Copy link
Contributor Author

@wojciech-bialy-wpm I suspect GAM will react to market forces; if people are much more successful at TLS using this method, GAM will likely want to participate.

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

No branches or pull requests

7 participants