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

[Spec] Add downsampling forDebuggingOnly support for B&A response #1325

Merged
merged 11 commits into from
Nov 25, 2024
124 changes: 93 additions & 31 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -3070,17 +3070,39 @@ a [=list=] of [=interest groups=] |bidIgs|, and a [=reporting context map=]
equals |componentAd|. If there is no matching element, return failure.
1. [=list/Append=] a new [=ad descriptor=] whose [=ad descriptor/url=] is
|componentAd| to |winningAdComponents|.
1. Let |bidDebugReportingInfo| be a new [=bid debug reporting info=].
1. [=list/For each=] |key| → |maybeDebugReportUrl| in |response|'s
[=server auction response/component win debugging only reports=]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

What has the responsibility for verifying that this is actually a component auction?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good question. [=server auction response/component win debugging only reports=] only comes from reports whose componentWin(code) is set to true (which is only possible if a B&A response message is from component auction's server, for auctions whose top level auction runs on-device). Currently we trust B&A server should make sure the fields are set correctly, but would probably be good for Chrome to check that the message is from a component auction server if it has a report whose componentWin is set to true.

1. If |key|'s [=server auction debug report key/from seller=] is true:
1. Set |bidDebugReportingInfo|'s [=bid debug reporting info/component seller=] to |seller|.
1. If |key|'s [=server auction debug report key/is debug win=] is true, then set
|bidDebugReportingInfo|'s [=bid debug reporting info/seller debug win report url=] to
|maybeDebugReportUrl|.
1. Otherwise, set |bidDebugReportingInfo|'s
[=bid debug reporting info/seller debug loss report url=] to |maybeDebugReportUrl|.
1. Otherwise,
1. Set |bidDebugReportingInfo|'s [=bid debug reporting info/interest group owner=] to
|response|'s [=server auction response/interest group owner=].
1. If |key|'s [=server auction debug report key/is debug win=] is true, then set
|bidDebugReportingInfo|'s [=bid debug reporting info/bidder debug win report url=] to
|maybeDebugReportUrl|.
1. Otherwise, set |bidDebugReportingInfo|'s
[=bid debug reporting info/bidder debug loss report url=] to |maybeDebugReportUrl|.
1. Set |bidDebugReportingInfo|'s [=bid debug reporting info/server filtered debugging only reports=]
to [=server auction response/server filtered debugging only reports=].
1. Set |reportingContextMap|[|auctionConfig|] to |bidDebugReportingInfo|.
qingxinwu marked this conversation as resolved.
Show resolved Hide resolved
1. Let |reportingId| be a [=reporting bid key=] with the following [=struct/items=]:
: [=reporting bid key/context=]
:: |reportingContextMap|[|auctionConfig|]
: [=reporting bid key/source=]
:: [=reporting bid source/bidding-and-auction-services=]
: [=reporting bid key/bidder origin=]
:: |response|'s [=server auction response/interest group owner=]
: [=reporting bid key/bid identifier=]
:: |response|'s [=server auction response/interest group name=]
1. Let |winningBid| be a new [=generated bid=] with the following [=struct/items=]:
: [=generated bid/reporting id=]
:: A [=reporting bid key=] with the following [=struct/items=]:
: [=reporting bid key/context=]
:: |reportingContextMap|[|auctionConfig|]
: [=reporting bid key/source=]
:: [=reporting bid source/bidding-and-auction-services=]
: [=reporting bid key/bidder origin=]
:: |response|'s [=server auction response/interest group owner=]
: [=reporting bid key/bid identifier=]
:: |response|'s [=server auction response/interest group name=]
:: |reportingId|
: [=generated bid/bid=]
:: |response|'s [=server auction response/bid=]
: [=generated bid/bid in seller currency=]
Expand Down Expand Up @@ -3172,7 +3194,7 @@ a [=list=] of [=interest groups=] |bidIgs|, and a [=reporting context map=]
1. If |updateIfOlderThan| is less than 10 mintues, set it to 10 minutes.
1. If [=current coarsened wall time=] − |ig|'s [=interest group/last updated=] ≥
|updateIfOlderThan|, set |ig|'s [=interest group/next update after=] to the
[=current coarsened wall time=] + |updateIfOlderThan|.
[=current coarsened wall time=] + |updateIfOlderThan|.
1. Return |winningBidInfo|.

</div>
Expand Down Expand Up @@ -3292,6 +3314,8 @@ dictionary AdAuctionDataBuyerConfig {
specified.
</dl>

A <dfn>server auction</dfn> is an auction executed on a trusted auction server.

A <dfn>server auction interest group</dfn> is a [=struct=] with the following [=struct/items=]:
<dl dfn-for="server auction interest group">
: <dfn>name</dfn>
Expand Down Expand Up @@ -3349,8 +3373,8 @@ A <dfn>server auction request context</dfn> is a [=struct=] with the following [
[Section 2.2.4 of Bidding and Auction Services](https://privacysandbox.github.io/draft-ietf-bidding-and-auction-services/draft-ietf-bidding-and-auction-services.html#name-generating-a-request)
</dl>

A <dfn>server auction response</dfn> is a [=struct=] that contains auction result
from an auction executed on the trusted auction server. It has the following [=struct/items=]:
A <dfn>server auction response</dfn> is a [=struct=] that contains auction result from a
[=server auction=]. It has the following [=struct/items=]:

<dl dfn-for="server auction response">
: <dfn>ad render url</dfn>
Expand Down Expand Up @@ -3403,6 +3427,11 @@ from an auction executed on the trusted auction server. It has the following [=s
:: Null or [=server auction reporting info=].
: <dfn>component seller reporting</dfn>
:: Null or [=server auction reporting info=].
: <dfn>component win debugging only reports</dfn>
:: A [=map=] whose [=map/keys=] are [=server auction debug report keys=], and whose [=map/values=]
are [=lists=] of [=urls=].
: <dfn>server filtered debugging only reports</dfn>
:: A [=map=] whose [=map/keys=] are [=origins=] and whose [=map/values=] are [=lists=] of [=urls=].
</dl>

A <dfn>server auction reporting info</dfn> is a [=struct=] with the following [=struct/items=]:
Expand All @@ -3414,6 +3443,14 @@ A <dfn>server auction reporting info</dfn> is a [=struct=] with the following [=
are [=URLs=] whose [=url/schemes=] are "`https`".
</dl>

a <dfn>server auction debug report key</dfn> is a [=struct=] with the following [=struct/items=]:
<dl dfn-for="server auction debug report key">
: <dfn>from seller</dfn>
:: A [=boolean=].
: <dfn>is debug win</dfn>
:: A [=boolean=].
</dl>

<div algorithm="getInterestGroupAdAuctionData()">

The <dfn for=Navigator method>getInterestGroupAdAuctionData(|configIDL|)</dfn> method steps are:
Expand Down Expand Up @@ -3643,7 +3680,7 @@ A <dfn>reporting context</dfn> is a [=struct=] with the following [=struct/items

A <dfn>reporting context map</dfn> is a [=map=] from [=auction config=] to [=reporting context=].
Here the keys are configurations for auctions that actually produce bids (e.g. not the top-level
auction in a multi-party auction).
auction in a multi-seller auction).
qingxinwu marked this conversation as resolved.
Show resolved Hide resolved

<div algorithm>
To <dfn>create a reporting context map</dfn> given the [=auction config=] |auctionConfig| and
Expand Down Expand Up @@ -3697,7 +3734,7 @@ methods for event-level <dfn>forDebuggingOnly reports</dfn> for winning and losi

<div algorithm>
To <dfn>collect a single forDebuggingOnly report</dfn> given a [=URL=] |reportUrl|, an [=origin=]
|invokingOrigin|, and a [=list=] |debugReportUrls|:
|invokingOrigin|, a [=boolean=] |fromServer|, and a [=list=] |debugReportUrls|:

Note: While the browser is experimenting with third party cookie deprecation (before they have
been fully removed), the {{InterestGroupBiddingAndScoringScriptRunnerGlobalScope/forDebuggingOnly}}
Expand All @@ -3706,8 +3743,8 @@ methods for event-level <dfn>forDebuggingOnly reports</dfn> for winning and losi

1. If |reportUrl| is null, or the result of running [=is debugging only in cooldown or lockout=]
with |invokingOrigin| is true, then return.
1. If the result of running [=sample a debug report=] with |invokingOrigin| is true, then
[=list/append=] |reportUrl| to |debugReportUrls|.
1. If the result of running [=sample a debug report=] with |invokingOrigin| and |fromServer| is
true, then [=list/append=] |reportUrl| to |debugReportUrls|.
</div>

<div algorithm>
Expand All @@ -3720,42 +3757,57 @@ methods for event-level <dfn>forDebuggingOnly reports</dfn> for winning and losi
1. [=map/For each=] _ → |reportingContext| of |reportingContextMap|:
1. [=map/For each=] |reportingId| -> |bidDebugReportInfo| of |reportingContext|'s
[=reporting context/debug reporting info=]:
1. Let |fromServer| be true if |reportingId|'s [=reporting bid key/source=] is
[=reporting bid source/bidding-and-auction-services=], false otherwise.
1. If |winningBid| is not null and |reportingId| is equal to |winningBid|'s
[=generated bid/reporting id=]:
1. [=Assert=] that |winningBid|'s [=generated bid/reporting id=] is not null.
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/bidder debug win report url=], |bidDebugReportInfo|'s
[=bid debug reporting info/interest group owner=], and |auctionReportInfo|'s
[=bid debug reporting info/interest group owner=], |fromServer|, and |auctionReportInfo|'s
[=auction report info/debug win report urls=].
1. If |bidDebugReportInfo|'s [=bid debug reporting info/component seller=] is null:
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/seller debug win report url=], |seller|, and
[=bid debug reporting info/seller debug win report url=], |seller|, |fromServer|, and
|auctionReportInfo|'s [=auction report info/debug win report urls=].
1. Otherwise:
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/seller debug win report url=], |bidDebugReportInfo|'s
[=bid debug reporting info/component seller=], |auctionReportInfo|'s
[=bid debug reporting info/component seller=], |fromServer|, and |auctionReportInfo|'s
[=auction report info/debug win report urls=].
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/top level seller debug win report url=], |seller|, and
|auctionReportInfo|'s [=auction report info/debug win report urls=].
[=bid debug reporting info/top level seller debug win report url=], |seller|, |fromServer|,
and |auctionReportInfo|'s [=auction report info/debug win report urls=].
1. Otherwise:
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/bidder debug loss report url=], |bidDebugReportInfo|'s
[=bid debug reporting info/interest group owner=], and |auctionReportInfo|'s
[=bid debug reporting info/interest group owner=], |fromServer|, and |auctionReportInfo|'s
[=auction report info/debug loss report urls=].
1. If |bidDebugReportInfo|'s [=bid debug reporting info/component seller=] is null:
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/seller debug loss report url=], |seller|, and
[=bid debug reporting info/seller debug loss report url=], |seller|, |fromServer|, and
|auctionReportInfo|'s [=auction report info/debug loss report urls=].
1. Otherwise:
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/seller debug loss report url=], |bidDebugReportInfo|'s
[=bid debug reporting info/component seller=], |auctionReportInfo|'s
[=bid debug reporting info/component seller=], |fromServer|, |auctionReportInfo|'s
[=auction report info/debug loss report urls=].
1. [=Collect a single forDebuggingOnly report=] with |bidDebugReportInfo|'s
[=bid debug reporting info/top level seller debug loss report url=], |seller|, and
|auctionReportInfo|'s [=auction report info/debug loss report urls=].
[=bid debug reporting info/top level seller debug loss report url=], |seller|,
|fromServer|, and |auctionReportInfo|'s [=auction report info/debug loss report urls=].
1. [=map/For each=] |invokingOrigin| → |debugURLs| of |bidDebugReportInfo|'s
[=bid debug reporting info/server filtered debugging only reports=]:
1. If |debugURLs| [=list/is empty=]:
1. If the result of running [=is debugging only in cooldown or lockout=] with
|invokingOrigin| is false, then [=update debug report cooldown=] with |invokingOrigin|.
1. [=iteration/Continue=].
Copy link
Collaborator

Choose a reason for hiding this comment

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

So I don't understand what's happening here, especially wrt. to the empty list check. (Or is meant to be not empty? But no, you do update cooldown when fromServer is true, so why do you need to update it if there are no reports; in case the server didn't sample any? What if there weren't any in the first place)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In order to send less fDO reports back to client to reduce the response size, we decided to let the server side do the 1/1000 sampling, and only send sampled urls back to client. Client will then check origin's cooldown, and also filter sampled urls based on final auction result (if needed).
There's a difference between origin->[], and not having an origin. If there weren't any call, then there won't be a per_origin_debug_reports in the response for that origin, thus no entry for this origin in [=bid debug reporting info/server filtered debugging only reports=].
A differene case is:
For example, one losing component buyer called debugLoss API, but the URL was not picked by server side due to we're doing sampling there, then the server still needs to tell client that the origin did call the loss api to set its cooldown. In this case, per_origin_debug_reports has the origin, but its debug report URLs array can be empty. We still need to update the origin's cooldown since it did call the loss API (and it loses).

The design is a little tricky that client side needs to believe B&A server did the right thing (i.e., meeting all the assumptions client side expects, which we agreed in the design)

Copy link
Collaborator

Choose a reason for hiding this comment

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

That makes sense, but may be worth some sort of a note in the spec about server inserting a blank array to denote when it didn't sample but when we still need to update the lockout?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah added a note. It's complicated, so a note would be very helpful.

1. [=list/For each=] |url| of |debugURLs|:
1. [=Collect a single forDebuggingOnly report=] with |url|, |invokingOrigin|,
|fromServer| (true), and |auctionReportInfo|'s [=auction report info/debug loss report urls=].

Note: For server filtered ones, post auction signals were filled on the server side. As
a result, there's no difference if they go to loss or win lists, since post auction
signals was the difference.
qingxinwu marked this conversation as resolved.
Show resolved Hide resolved
1. Return |auctionReportInfo|.
</div>

Expand Down Expand Up @@ -3807,23 +3859,30 @@ and [=map/values=] are [=moments=] at which the cool down for the origin key exp
</div>

<div algorithm>
To <dfn>sample a debug report</dfn> given an [=origin=] |origin|:
To <dfn>sample a debug report</dfn> given an [=origin=] |origin| and a [=boolean=] |fromServer|:

Note: forDebuggingOnly reports from [=server auction response=] were downsampled on truested
Copy link
Collaborator

Choose a reason for hiding this comment

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

Typo, truested. So the downsampling happens on the server not just for the filtered list, but also the conditional one?

Copy link
Collaborator Author

@qingxinwu qingxinwu Nov 22, 2024

Choose a reason for hiding this comment

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

yes, it samples all. Because every url is sampled independently, so we think "sampling first on server and then pick which sampled one is going to be sent on device" is the same as "picking which ones can be sampled and then sample from them" which happens on device. This way it greatly reduces the number of URLs sent back to client.

auction servers, so do not downsample them again on client.
1. Let |canSendAfterSampled| be false.
1. Let |sampleRand| be a random {{long}}, 0 &le; |sampleRand| &lt; 1000, so each possible long would be
chosen with a probability equal to [=sampling rate=].
1. If |sampleRand| is 0:
1. If |fromServer| is true or |sampleRand| is 0:
1. Set |canSendAfterSampled| to true.
1. Set [=user agent=]'s [=debug report lockout until=] to [=current coarsened wall time=] plus
[=lockout period=].
1. Let |cooldownRand| be a random {{long}} &ge; 0 and &lt; 10, which corresponds to
1. [=Update debug report cooldown=] with |origin|.
1. Return |canSendAfterSampled|.
</div>

<div algorithm>
To <dfn>update debug report cooldown</dfn> given an [=origin=] |origin|:

1. Let |cooldownRand| be a random {{long}} &ge; 0 and &lt; 10, which corresponds to
[=long cooldown rate=].
1. Let |cooldownPeriod| be [=long cooldown period=] if |cooldownRand| is 0,
[=short cooldown period=] otherwise.
1. Set [=user agent=]'s [=debug report cooldown=][|origin|] to [=current coarsened wall time=]
plus |cooldownPeriod|.
1. Return |canSendAfterSampled|.
</div>

## {{InterestGroupBiddingAndScoringScriptRunnerGlobalScope/realTimeReporting}} ## {#real-time-reporting-header}
Expand Down Expand Up @@ -5023,7 +5082,7 @@ from querying the server during an auction.
1. Let |reportingHashCode| be the result of [=query reporting ID k-anonymity count=]
given |ig|, |igAd|, and |selectableReportingId|.
1. If [=query k-anonymity cache=] for |reportingHashCode| returns true, then
[=list/Append=] |selectableReportingId| to |kAnonRestrictedSelectableReportingIds|.
[=list/append=] |selectableReportingId| to |kAnonRestrictedSelectableReportingIds|.
1. Set |igAd|'s [=interest group ad/selectable buyer and seller reporting IDs=] to
|kAnonRestrictedSelectableReportingIds|.
1. [=list/Append=] |igAd| to |kAnonRestrictedIG|'s [=interest group/ads=].
Expand Down Expand Up @@ -8552,6 +8611,9 @@ A <dfn>bid debug reporting info</dfn> is a [=struct=] with the following [=struc
won it, and was then scored by the top-level seller. Set by top-level seller's `scoreAd()`'s
{{InterestGroupBiddingAndScoringScriptRunnerGlobalScope/forDebuggingOnly}}'s
{{ForDebuggingOnly/reportAdAuctionLoss(url)}}.
: <dfn>server filtered debugging only reports</dfn>
:: A [=map=] whose [=map/keys=] are [=origins=] and whose [=map/values=] are [=lists=] of [=urls=].
forDebuggingOnly reports that have been filtered (also downsampled) by the trusted auction server.
</dl>

A <dfn>bid with currency</dfn> is a [=struct=] with the following [=struct/items=]:
Expand Down
Loading