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 private aggregation support for B&A response #1344

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 111 additions & 16 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1870,13 +1870,13 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|:
[=get direct from seller signals for a seller=] given |topLevelDirectFromSellerSignals|.
1. Set |topLevelDirectFromSellerSignalsRetrieved| to true.
1. If |compWinnerInfo|'s [=leading bid info/leading bid=] is not null, then run
[=score and rank a bid=] with |auctionConfig|, |reportingContextMap|[auctionConfig],
[=score and rank a bid=] with |auctionConfig|, |reportingContextMap|[|auctionConfig|],
|compWinnerInfo|'s [=leading bid info/leading bid=], |leadingBidInfo|,
|decisionLogicFetcher|, |trustedScoringSignalsBatcher|, null, "top-level-auction", null,
and |topLevelOrigin|.
1. If |compWinnerInfo|'s [=leading bid info/leading non-k-anon-enforced bid=]
is not null, then run [=score and rank a bid=] with |auctionConfig|, |reportingContextMap|[
auctionConfig], |compWinnerInfo|'s [=leading bid info/leading non-k-anon-enforced bid=],
|auctionConfig|], |compWinnerInfo|'s [=leading bid info/leading non-k-anon-enforced bid=],
|leadingBidInfo|, |decisionLogicFetcher|, |trustedScoringSignalsBatcher|,
|topLevelDirectFromSellerSignalsForSeller|, null, "top-level-auction", null, |topLevelOrigin|,
and |realTimeContributionsMap|.
Expand Down Expand Up @@ -3137,17 +3137,20 @@ a [=list=] of [=interest groups=] |bidIgs|, and a [=reporting context map=]
[=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|]'s [=reporting context/debug reporting info=] to
1. Let |reportingContext| be |reportingContextMap|[|auctionConfig|].
1. Set |reportingContext|'s [=reporting context/debug reporting info=] to
|bidDebugReportingInfo|.
1. Let |reportingId| be a [=reporting bid key=] with the following [=struct/items=]:
: [=reporting bid key/context=]
:: |reportingContextMap|[|auctionConfig|]
:: |reportingContext|
: [=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. [=Handle server response private aggregation fields=] given |response|, |requestContext| and
|reportingId|.
1. Let |winningBid| be a new [=generated bid=] with the following [=struct/items=]:
: [=generated bid/reporting id=]
:: |reportingId|
Expand Down Expand Up @@ -3247,6 +3250,69 @@ a [=list=] of [=interest groups=] |bidIgs|, and a [=reporting context map=]

</div>

<div algorithm>
To <dfn>handle server response private aggregation fields</dfn> given a [=server auction response=]
|response|, a [=reporting context=] |reportingContext|, and a [=reporting bid key=] |reportingId|:

1. [=Assert=] that these steps are running [=in parallel=].
1. [=Commit server response private aggregation contributions=] given |response|'s
[=server auction response/component win private aggregation contributions=], |reportingContext|,
|reportingId| and false.
1. [=Commit server response private aggregation contributions=] given |response|'s
[=server auction response/server filtered private aggregation reserved contributions=],
|reportingContext|, |reportingId| and true.
1. [=Commit server response private aggregation contributions=] given |response|'s
[=server auction response/server filtered private aggregation non reserved contributions=],
|reportingContext|, |reportingId| and true.

</div>

<div algorithm>
To <dfn>commit server response private aggregation contributions</dfn> given a
[=server auction response=] |contributionsMap|, a [=reporting context=] |reportingContext|, a
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think server auction response is the right type here?

[=reporting bid key=] |reportingId| and a [=boolean=] |serverFiltered|:

1. [=map/For each=] (|reportingOrigin|, |coordinator|, |event|) → |contributions| of |contributionsMap|:
1. Let |eventToContributionsMap| be a new [=Private Aggregation contributions=].
1. Let |scopingDetails| be a new [=scoping details=] with the [=struct/items=]:
: <a spec="private-aggregation-api" for="scoping details">get batching scope steps</a>
:: An algorithm that performs the following steps:
1. If |coordinator| is null, set |coordinator| to the [=default aggregation coordinator=].
1. Return the result of running [=get or create a batching scope=] given |reportingOrigin|,
|coordinator| and |reportingContext|.
: <a spec="private-aggregation-api" for="scoping details">get debug scope steps</a>
:: An algorithm that returns a new [=debug scope=].
Copy link
Collaborator

Choose a reason for hiding this comment

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

So technically you don't need a |scopingDetails| here since you're not integrating with contributeToHistogram[OnEvent], though it might be worthwhile for consistency?


1. Let |batchingScope| be null.
1. If |event| [=string/starts with=] "`reserved.`", set |batchingScope| to the
result of running |scopingDetails|' <a spec="private-aggregation-api" for="scoping details">
get batching scope steps</a>.

Note: Each non-reserved |event| will have a different [=batching scope=]
that is created later.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is copied from on-device PAgg part. I don't see a place that creates the batching scope for non-reserved events, IIUC

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it may be because those are sent, well, on event?

1. [=list/For each=] |contribution| of |contributions|:
1. Let |entry| be a new [=on event contribution entry=] with the items:
: [=on event contribution entry/contribution=]
:: |contribution|
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to have some sort of an assert here that it doesn't have any baseValues?

: [=on event contribution entry/batching scope=]
:: |batchingScope|
: [=on event contribution entry/debug scope=]
:: The result of running |scopingDetails|' <a spec="private-aggregation-api"
for="scoping details">get debug scope steps</a>.
: [=on event contribution entry/worklet function=]
:: "`generate-bid`" (it does not matter for server returned contributions)
: [=on event contribution entry/server filtered=]
:: |serverFiltered|
: [=on event contribution entry/origin=]
:: |reportingOrigin|
1. If |eventToContributionsMap|[|event|] does not [=map/exist=], set
|eventToContributionsMap|[|event|] to « |entry| ».
1. Otherwise, [=list/append=] |eventToContributionsMap|[|event|] with |entry|.
Copy link
Collaborator

Choose a reason for hiding this comment

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

....append ... with ... is kinda strange. Append |entry| to ... ?

1. [=Commit private aggregation contributions=] given |eventToContributionsMap|, |reportingId| and
|reportingContext|.

</div>

<h3 id="canloadadauctionfencedframe">canLoadAdAuctionFencedFrame()</h3>

*This first introductory paragraph is non-normative.*
Expand Down Expand Up @@ -3478,6 +3544,20 @@ A <dfn>server auction response</dfn> is a [=struct=] that contains auction resul
:: Null or [=server auction reporting info=].
: <dfn>component seller reporting</dfn>
:: Null or [=server auction reporting info=].
: <dfn>component win private aggregation contributions</dfn>
:: A [=map=] whose [=map/keys=] are ([=reporting bid key=], [=string=]), and whose [=map/values=]
are [=lists=] of [=on event contribution entries=]. Private aggregation contributions from
winners of component auctions run on trusted auction servers. These need to be filtered by the
client based on the top level auction's outcome.
: <dfn>server filtered private aggregation reserved contributions</dfn>
:: A [=map=] from a tuple of ([=reporting bid key=], [=string=]) to a [=list=] of [=on event
contribution entries=]. Server filtered private aggregation contributions with reserved event
types (already set to "reserved.always"), which are not dependent on the final auction result and
should always be reported.
: <dfn>server filtered private aggregation non reserved contributions</dfn>
:: A [=map=] from a tuple of ([=reporting bid key=], [=string=]) to a [=list=] of [=on event
contribution entries=]. Server filtered private aggregation contributions with non reserved event
types, which are not dependent on the final auction result and should always be reported.
: <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=].
Expand Down Expand Up @@ -3531,18 +3611,22 @@ The <dfn for=Navigator method>getInterestGroupAdAuctionData(|configIDL|)</dfn> m
1. Set |config|'s [=auction data config/encryption key=] to |key|.
1. Set |config|'s [=auction data config/encryption key id=] to |keyId|.
1. Let |igMap| be a new [=map=] whose [=map/keys=] are [=origins=] and [=map/values=] are [=lists=].
1. Let |igPAggCoordinatorMap| be a new [=map=] whose [=map/keys=] are tuples of ([=origins=], [=strings=])
and [=map/values=] are [=origins=].
1. Let |startTime| be a [=moment=] equal to the [=current coarsened wall time=].
1. [=list/For each=] |ig| of the [=user agent=]'s [=interest group set=]:
1. If |ig|'s [=interest group/ads=] is null or [=list/is empty=], [=iteration/continue=].
1. Let |owner| be |ig|'s [=interest group/owner=].
1. Let |name| be |ig|'s [=interest group/name=].
1. If |config|'s [=auction data config/per buyer config=] [=map/is not empty=] and
|config|'s [=auction data config/per buyer config=][|owner|] does not
[=map/exist=], then [=iteration/continue=].
1. If |igMap|[|owner|] does not [=map/exist=], then [=map/set=] |igMap|[|owner|] to a new [=list=].
1. Let |ads| be a new [=list=].
1. [=list/For each=] |ad| in |ig|'s [=interest group/ads=], [=list/append=] |ad|'s [=interest group ad/ad render ID=] to |ads|.
1. Let |components| be a new [=list=].
1. [=list/For each=] |component| in |ig|'s [=interest group/ad components=], [=list/append=] |component|'s [=interest group ad/ad render ID=] to |components|.
1. [=list/For each=] |component| in |ig|'s [=interest group/ad components=], [=list/append=]
|component|'s [=interest group ad/ad render ID=] to |components|.
1. Let |prevWins| be a new <code>[=sequence=]<[=server auction previous win=]></code>.
1. [=list/For each=] |prevWin| of |ig|'s [=interest group/previous wins=] for all days within the
the last 30 days:
Expand All @@ -3567,7 +3651,7 @@ The <dfn for=Navigator method>getInterestGroupAdAuctionData(|configIDL|)</dfn> m
:: |prevWins|
1. Let |serverIg| be a new [=server auction interest group=] with the following [=struct/items=]:
: [=server auction interest group/name=]
:: |ig|'s [=interest group/name=]
:: |name|
: [=server auction interest group/bidding signals keys=]
:: |ig|'s [=interest group/trusted bidding signals keys=]
: [=server auction interest group/user bidding signals=]
Expand All @@ -3581,11 +3665,13 @@ The <dfn for=Navigator method>getInterestGroupAdAuctionData(|configIDL|)</dfn> m
: [=server auction interest group/priority=]
:: |ig|'s [=interest group/priority=]
1. [=list/Append=] |serverIg| to |igMap|[|owner|].
1. If |ig|'s [=interest group/Private Aggregation coordinator=] is not null, then [=map/set=]
|igPAggCoordinatorMap|[(|owner|, |name|)] to it.
1. Let |result| be a new {{AdAuctionData}}.
1. Let |requestId| be the [=string representation=] of a [=version 4 UUID=].
1. [=map/Set=] |result|["{{AdAuctionData/requestId}}"] to |requestId|.
1. Let (|requestBlob|, |context|) be the result of serializing |igMap| using
|config|. The serialization method may follow that described in
1. Let (|requestBlob|, |context|) be the result of serializing |igMap| with |config| and
|igPAggCoordinatorMap|. The serialization method may follow that described in
[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).
1. Set |result|["{{AdAuctionData/request}}"] to |requestBlob|.
1. [=Queue a global task=] on the [=DOM manipulation task source=], given |global|, to
Expand Down Expand Up @@ -4206,8 +4292,7 @@ A signal base value is one of the following:
: "<dfn><code>bid-reject-reason</code></dfn>"
:: The numeric value is an integer representing the reason a bid was rejected.

Note: this mapping to an integer is defined in [=determine a signal's
numeric value=].
Note: this mapping to an integer is defined in [=determine a signal's numeric value=].

: "<dfn><code>average-code-fetch-time</code></dfn>"
:: The numeric value is the average time it took to fetch code resources (JavaScript or WebAssembly)
Expand Down Expand Up @@ -4258,6 +4343,9 @@ An on event contribution entry is a [=struct=] with the following items:
:: A [=debug details=] or null (default null)
: <dfn>worklet function</dfn>
:: A [=worklet function=].
: <dfn>server filtered</dfn>
:: A [=boolean=], initially false. Only set to true when the contribution is already filtered by the
trusted auction server before sent back to the client.
: <dfn>origin</dfn>
:: The [=origin=] of the script that contributed the entry.

Expand Down Expand Up @@ -4423,7 +4511,7 @@ runs; this method exists as an abstraction to help add that.
</div>

<div algorithm>
To <dfn>commit private aggregation contributions</dfn> given an [=Private Aggregation
To <dfn>commit private aggregation contributions</dfn> given a [=Private Aggregation
contributions=] |onEventMap|, a [=reporting bid key=] |bidKey|, and a [=reporting context=]
|reportingContext|:
1. [=map/For each=] |event| → |contributions| of |onEventMap|:
Expand Down Expand Up @@ -4465,6 +4553,7 @@ To <dfn>process the Private Aggregation contributions</dfn> given an [=auction c
<div algorithm>
To <dfn>process the Private Aggregation contributions for an auction</dfn> given
an [=auction config=] |auctionConfig| and a [=reporting context=] |reportingContext|:

1. If |auctionConfig|'s [=auction config/aborted=] is true, return.
1. Let |winnerId| be |reportingContext|'s [=reporting context/winner reporting id=]
1. Let |leadingBidInfo| be |reportingContext|'s [=reporting context/local leader info=].
Expand All @@ -4474,11 +4563,15 @@ an [=auction config=] |auctionConfig| and a [=reporting context=] |reportingCont
1. Let |sellerOnceRep| be null.
1. If |reportingContext|'s [=reporting context/seller participants=] [=set/is not empty=],
set |sellerOnceRep| to a random [=set/item=] of [=reporting context/seller participants=].
1. [=map/For each=] (|bidId|, |event|) → |contributions| of
|reportingContext|'s [=reporting context/private aggregation on event contributions=]:
1. If |event| is "`reserved.win`" or does not [=string/start with=] "`reserved.`":
1. If |bidId| is not |winnerId|, [=iteration/continue=].
1. If |event| is "`reserved.loss`" and |bidId| is |winnerId|, [=iteration/continue=].
1. [=map/For each=] (|bidId|, |event|) → |contributions| of |reportingContext|'s
[=reporting context/private aggregation on event contributions=]:
1. If |event| does not [=string/start with=] "`reserved.`":
1. [=list/For each=] |onEventEntry| of |contributions|:
1. If |onEventEntry|'s [=on event contribution entry/server filtered=] is false and |bidId| is
not |winnerId|, then [=list/remove=] |onEventEntry| from |contributions|.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I would prefer if you checked it inside the existing loop over contributions, and just used continue as everything else, rather than have a different pre-filtering loop.

1. If |onEventEntry|'s [=on event contribution entry/server filtered=] is false:
Copy link
Collaborator

Choose a reason for hiding this comment

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

...and you don't even have onEventEntry at this level? I think you probably just want to move the reserved.win/reserved.loss check into the "For each onEventEntry of contributions :" loop, since now it needs to check the server filtered bit.... except shouldn't things that are server-filtered only be using reserved.always anyway?

...I am not sure you actually need the server-filtered bid if the part about them always having reserved.always are true.

(The way losing components is supposed to be handled is by not having a winnerId be set on them).

1. If |event| is "`reserved.win`" and |bidId| is not |winnerId|, then [=iteration/continue=].
1. If |event| is "`reserved.loss`" and |bidId| is |winnerId|, [=iteration/continue=].
1. [=list/For each=] |onEventEntry| of |contributions|:
1. If |event| is "`reserved.once`":
1. If |onEventEntry|'s [=on event contribution entry/worklet function=] is [=worklet function/
Expand Down Expand Up @@ -6042,6 +6135,8 @@ event, PAExtendedHistogramContribution contribution)</dfn> method steps are:
reserved event types are added later.
1. If |event| is "`reserved.once`" and |function| is [=worklet function/report-result=] or
[=worklet function/report-win=], [=exception/throw=] a {{TypeError}}.
1. If |event| does not [=string/start with=] "`reserved.`", and |function| is "`scoreAd()`" or
"`report-result`", return.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not understand this change.

1. Let |bucket| be |contribution|["{{PAExtendedHistogramContribution/bucket}}"].
1. If |bucket| is a {{PASignalValue}}:
1. If |bucket|["{{PASignalValue/baseValue}}"] is not a valid [=signal base
Expand Down
Loading