diff --git a/spec.bs b/spec.bs index 2c0205074..08ddabc42 100644 --- a/spec.bs +++ b/spec.bs @@ -89,6 +89,13 @@ spec: private-aggregation-api; urlPrefix: https://patcg-individual-drafts.github text: debug-details-key; url: #debug-details-key text: aggregation coordinator; url: #aggregation-coordinator text: default aggregation coordinator; url: #default-aggregation-coordinator + text: privateaggregation; url: #privateaggregation + text: batching scope; url: #batching-scope + text: debug scope; url: #debug-scope + text: scoping details; url: #scoping-details + text: contribution cache entry; url: #contribution-cache-entry + text: contribution cache; url: #contribution-cache + text: default filtering id max bytes; url: #default-filtering-id-max-bytes spec: Shared Storage API; urlPrefix: https://wicg.github.io/shared-storage type: dfn text: shared-storage; url: #permissionspolicy-shared-storage @@ -793,6 +800,9 @@ The runAdAuction(|config|) method steps are: 1. Let |settings| be [=this=]'s [=relevant settings object=]. 1. If |global|'s [=associated Document=] is not [=allowed to use=] the "[=run-ad-auction=]" [=policy-controlled feature=], then [=exception/throw=] a "{{NotAllowedError}}" {{DOMException}}. +1. Let |privateAggregationAllowed| be the result of determining whether |global|'s [=associated + Document=] is [=allowed to use=] the "[=private-aggregation=]" [=policy-controlled + feature=]. 1. Let |auctionConfig| be the result of running [=validate and convert auction ad config=] with |config| and true. 1. If |auctionConfig| is failure, then [=exception/throw=] a {{TypeError}}. @@ -824,7 +834,7 @@ The runAdAuction(|config|) method steps are: 1. Let |queue| be the result of [=starting a new parallel queue=]. 1. [=parallel queue/enqueue steps|Enqueue the following steps=] to |queue|: 1. Let |reportingContextMap| be the result of [=creating a reporting context map=] given - |auctionConfig|. + |auctionConfig| and |privateAggregationAllowed|. 1. If |auctionConfig|'s [=auction config/server response=] is not null: 1. Let |winnerInfo| be the result of running [=parse and validate server response=] with |auctionConfig|, null, |global|, |bidIgs|, and |reportingContextMap|. @@ -851,10 +861,13 @@ The runAdAuction(|config|) method steps are: 1. [=Send report=] with |reportUrl| and |settings|. 1. [=Send real time reports=] with |auctionReportInfo|'s [=auction report info/real time reporting contributions map=] and |settings|. + 1. [=Process the Private Aggregation contributions=] given |auctionConfig|, + |reportingContextMap|. 1. Otherwise: 1. Let |winner| be |winnerInfo|'s [=leading bid info/leading bid=]. 1. Let |fencedFrameConfig| be the result of [=filling in a pending fenced frame config=] with - |pendingConfig|, |auctionConfig|, |winnerInfo|, |auctionReportInfo|, and |settings|. + |pendingConfig|, |auctionConfig|, |reportingContextMap|, |winnerInfo|, |auctionReportInfo|, + and |settings|. 1. [=fenced frame config mapping/Finalize a pending config=] on |configMapping| with |urn| and |fencedFrameConfig|. 1. Wait until |auctionConfig|'s [=auction config/resolve to config=] is a boolean. @@ -948,8 +961,9 @@ To construct a pending fenced frame config given an [=auction config=
To fill in a pending fenced frame config given a [=fenced frame config=] -|pendingConfig|, [=auction config=] |auctionConfig|, [=leading bid info=] |winningBidInfo|, -[=auction report info=] |auctionReportInfo|, and an [=environment settings object=] |settings|: +|pendingConfig|, [=auction config=] |auctionConfig|, [=reporting context map=] +|reportingContextMap|, [=leading bid info=] |winningBidInfo|, [=auction report info=] +|auctionReportInfo|, and an [=environment settings object=] |settings|: 1. Let |winningBid| be |winningBidInfo|'s [=leading bid info/leading bid=]. 1. Let |replacements| be an [=ordered map=] whose [=map/keys=] are [=strings=] and whose [=map/values=] are [=strings=]. @@ -1020,8 +1034,8 @@ To fill in a pending fenced frame config given a [=fenced frame confi 1. [=Asynchronously finish reporting=] with |pendingConfig|'s [=fenced frame config/fenced frame reporting metadata=]'s [=fenced frame reporting metadata/value=]'s - [=fenced frame reporting metadata/fenced frame reporting map=], |winningBidInfo|, - |auctionReportInfo| and |settings|. + [=fenced frame reporting metadata/fenced frame reporting map=], |auctionConfig|, + |reportingContextMap|, |winningBidInfo|, |auctionReportInfo| and |settings|. 1. Let |adComponentDescriptorsWithReplacements| be a new [=list=] of [=ad descriptors=]. 1. If |winningBid|'s [=generated bid/ad component descriptors=] is not null: 1. [=list/For each=] |adComponentDescriptor| of |winningBid|'s @@ -1042,7 +1056,8 @@ To fill in a pending fenced frame config given a [=fenced frame confi
To asynchronously finish reporting given a -[=fencedframetype/fenced frame reporting map=] |reportingMap|, [=leading bid info=] |leadingBidInfo|, +[=fencedframetype/fenced frame reporting map=] |reportingMap|, [=auction config=] |auctionConfig|, +[=reporting context map=] |reportingContextMap|, [=leading bid info=] |leadingBidInfo|, [=auction report info=] |auctionReportInfo|, and an [=environment settings object=] |settings|: 1. [=Increment a winning bid's k-anonymity count=] given |leadingBidInfo|'s [=leading bid info/leading bid=]. 1. If |leadingBidInfo|'s [=leading bid info/leading non-k-anon-enforced bid=] is @@ -1099,6 +1114,7 @@ To asynchronously finish reporting given a 1. [=Send report=] with |report| and |settings|. 1. [=Send real time reports=] with |auctionReportInfo|'s [=auction report info/real time reporting contributions map=] and |settings|. +1. [=Process the Private Aggregation contributions=] given |auctionConfig|, |reportingContextMap|.
@@ -1732,10 +1748,11 @@ To generate potentially multiple bids given an [=ordered map=]-or-nul a [=string=] |auctionSignals|, a {{BiddingBrowserSignals}} |browserSignals|, a [=string=]-or-null |perBuyerSignals|, a {{DirectFromSellerSignalsForBuyer}} |directFromSellerSignalsForBuyer|, a [=duration=] |perBuyerTimeout| in milliseconds, a [=currency tag=] |expectedCurrency|, an {{unsigned short}} -|multiBidLimit|, an [=interest group=] |ig|, and a [=moment=] |auctionStartTime|, and an -[=environment settings object=] |settings|, perform the following steps. They return a failure if -failing to fetch the script or wasm, otherwise a [=tuple=] of ([=list=] of [=generated bids=], -[=bid debug reporting info=], [=list=] of [=real time reporting contributions=]). +|multiBidLimit|, an [=interest group=] |ig|, a [=reporting context=] |reportingContext|, a +[=moment=] |auctionStartTime|, and an [=environment settings object=] |settings|, perform the +following steps. They return a failure if failing to fetch the script or wasm, otherwise a +[=tuple=] of ([=list=] of [=generated bids=], [=bid debug reporting info=], +[=list=] of [=real time reporting contributions=]). 1. Let |igGenerateBid| be the result of [=building an interest group passed to generateBid=] with |ig|. 1. Set |browserSignals|["{{BiddingBrowserSignals/joinCount}}"] to the sum of |ig|'s @@ -1792,10 +1809,10 @@ failing to fetch the script or wasm, otherwise a [=tuple=] of ([=list=] of [=gen 1. Let |originKey| be the [=serialization of an origin|serialization=] of |crossOriginTrustedBiddingSignalsOrigin|. 1. [=map/Set=] |crossOriginTrustedBiddingSignalsOrigin|[|originKey|] to |trustedBiddingSignals|. - 1. Return the result of [=evaluating a bidding script=] with |biddingScript|, |multiBidLimit|, |ig|, |expectedCurrency|, - |igGenerateBid|, |auctionSignals|, |perBuyerSignals|, |sameOriginTrustedBiddingSignals|, - |crossOriginTrustedBiddingSignals|, |browserSignals|, |directFromSellerSignalsForBuyer|. - and |perBuyerTimeout|. + 1. Return the result of [=evaluating a bidding script=] with |biddingScript|, |multiBidLimit|, + |ig|, |reportingContext|, |expectedCurrency|, |igGenerateBid|, |auctionSignals|, + |perBuyerSignals|, |sameOriginTrustedBiddingSignals|, |crossOriginTrustedBiddingSignals|, + |browserSignals|, |directFromSellerSignalsForBuyer| and |perBuyerTimeout|.
@@ -1844,27 +1861,29 @@ 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|[|component|], + [=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|[ - |component|], |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|. 1. Decrement |pendingComponentAuctions| by 1. 1. Wait until |pendingComponentAuctions| is 0. 1. If |auctionConfig|'s [=auction config/aborted=] is true, return failure. + 1. Set |reportingContextMap|[|auctionConfig|]'s [=reporting context/local leader info=] to + a copy of |leadingBidInfo|. 1. If |leadingBidInfo|'s [=leading bid info/leading bid=] is null, return null. 1. Let |winningComponentConfig| be |leadingBidInfo|'s [=leading bid info/auction config=]. 1. Set |leadingBidInfo|'s [=leading bid info/auction config=] to |auctionConfig|. 1. Set |leadingBidInfo|'s [=leading bid info/component seller=] to |winningComponentConfig|'s [=auction config/seller=]. 1. Let « |topLevelSellerSignals|, unusedTopLevelReportResultBrowserSignals » be the result of - running [=report result=] with |leadingBidInfo|, |topLevelDirectFromSellerSignalsForSeller|, - |winningComponentConfig|, and |global|. + running [=report result=] with |leadingBidInfo|, |reportingContextMap|[|auctionConfig|], + |topLevelDirectFromSellerSignalsForSeller|, |winningComponentConfig|, and |global|. 1. Set |leadingBidInfo|'s [=leading bid info/auction config=] to |winningComponentConfig|. 1. Set |leadingBidInfo|'s [=leading bid info/component seller=] to null. 1. Set |leadingBidInfo|'s [=leading bid info/top level seller=] to |seller|. @@ -1880,9 +1899,15 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: |leadingBidInfo|'s [=leading bid info/leading bid=]'s [=generated bid/interest group=]'s [=interest group/owner=]. 1. Let « |sellerSignals|, |reportResultBrowserSignals| » be the result of running - [=report result=] with |leadingBidInfo|, |directFromSellerSignalsForSeller|, null, and |global|. - 1. Run [=report win=] with |leadingBidInfo|, |sellerSignals|, |reportResultBrowserSignals|, - |directFromSellerSignalsForBuyer|, and |settings|. + [=report result=] with |leadingBidInfo|, |reportingContextMap|[|winningComponentConfig|], + |directFromSellerSignalsForSeller|, null, and |global|. + 1. Run [=report win=] with |leadingBidInfo|, |reportingContextMap|[|winningComponentConfig|], + |sellerSignals|, |reportResultBrowserSignals|, |directFromSellerSignalsForBuyer|, + and |settings|. + 1. Set |reportingContextMap|[|auctionConfig|]'s [=reporting context/winner reporting id=] to + |leadingBidInfo|'s [=leading bid info/leading bid=]'s [=generated bid/reporting id=]. + 1. Set |reportingContextMap|[|winningComponentConfig|]'s [=reporting context/winner reporting id=] + to |leadingBidInfo|'s [=leading bid info/leading bid=]'s [=generated bid/reporting id=]. 1. Return |leadingBidInfo|. 1. If [=waiting until configuration input promises resolve=] given |auctionConfig| returns failure, @@ -1906,6 +1931,7 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: |browserSignals|["{{BiddingBrowserSignals/requestedSize}}"] to the result of running [=convert an ad size to a map=] with |auctionConfig|'s [=auction config/requested size=]. 1. Let |auctionLevel| be "single-level-auction". +1. Let |reportingContext| be |reportingContextMap|[|auctionConfig|]. 1. Let |componentAuctionExpectedCurrency| be null. 1. If |topLevelAuctionConfig| is not null: 1. [=map/Set=] |browserSignals|["{{BiddingBrowserSignals/topLevelSeller}}"]] to the @@ -1919,7 +1945,7 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: |auctionConfig|, |topLevelAuctionConfig|, |negativeTargetInfo|, |reportingContextMap| and |global|. 1. Let |pendingAdditionalBids| be the [=list/size=] of |additionalBids|. 1. [=list/For each=] |additionalBid| of |additionalBids|, run the following steps [=in parallel=]: - 1. [=Score and rank a bid=] with |auctionConfig|, |reportingContextMap|[|auctionConfig|], + 1. [=Score and rank a bid=] with |auctionConfig|, |reportingContext| |additionalBid|'s [=decoded additional bid/bid=], |leadingBidInfo|, |decisionLogicFetcher|, |trustedScoringSignalsBatcher|, |directFromSellerSignalsForSeller|, null, |auctionLevel|, |componentAuctionExpectedCurrency|, |topLevelOrigin|, and |realTimeContributionsMap|. @@ -2026,12 +2052,13 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: |allTrustedBiddingSignals|, |crossOriginTrustedBiddingSignalsOrigin|, |auctionSignals|, a [=map/clone=] of |browserSignals|, |perBuyerSignals|, |directFromSellerSignalsForBuyer|, |perBuyerTimeout|, |expectedCurrency|, - |multiBidLimit|, |ig|, |auctionStartTime|, and |settings|. + |multiBidLimit|, |ig|, |reportingContext|, |auctionStartTime|, and |settings|. 1. If |generateBidResult| is failure, then: 1. If |optedInForRealTimeReporting| is true, then [=add a platform contribution=] with [=bidding script failure bucket=], |realTimeContributionsMap| and |buyer|. 1. [=iteration/Continue=]. - 1. Let (|bidsBatch|, |bidDebugReportInfo|, |realTimeContributions|) be |generateBidResult|. + 1. Let (|bidsBatch|, |bidDebugReportInfo|, |realTimeContributions|, |paContributions|) be + |generateBidResult|. 1. Let |generateBidDuration| be the [=duration from=] |generateBidStartTime| to |settings|'s [=environment settings object/current monotonic time=], in milliseconds. 1. If |perBuyerCumulativeTimeout| is not null, decrement |perBuyerCumulativeTimeout| by @@ -2055,11 +2082,13 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: |perBuyerTimeout| to |perBuyerCumulativeTimeout|. 1. Let |generateBidStartTime| be |settings|'s [=environment settings object/current monotonic time=]. - 1. Set (|generatedBids|, |bidDebugReportInfo|, |realTimeContributions|) to the result - of running [=generate potentially multiple bids=] with |allTrustedBiddingSignals|, + 1. Set (|generatedBids|, |bidDebugReportInfo|, |realTimeContributions|, + |paContributions|) to the result of running [=generate potentially multiple bids=] + with |allTrustedBiddingSignals|, |crossOriginTrustedBiddingSignalsOrigin|, |auctionSignals|, a [=map/clone=] of |browserSignals|, |perBuyerSignals|, |directFromSellerSignalsForBuyer|, |perBuyerTimeout|, |expectedCurrency|, - 1 (for multiBidLimit), |kAnonRestrictedIG|, |auctionStartTime|, and |settings|. + 1 (for multiBidLimit), |kAnonRestrictedIG|, |reportingContext|, |auctionStartTime|, + and |settings|. Note: passing 1 for multiBidLimit limits the rerun to producing at most a single bid. @@ -2072,32 +2101,35 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: 1. [=Assert=] that [=query generated bid k-anonymity count=] given |generatedBid| returns true. 1. [=Apply any component ads target to a bid=] given |generatedBid|. 1. [=list/Append=] |generatedBid| to |bidsToScore|. - 1. [=Register bids for forDebuggingOnly reports=] given |bidsToScore|, |ig|, - |bidDebugReportInfo|, and |reportingContextMap|[|auctionConfig|]. + 1. [=Register bids for reporting=] given |bidsToScore|, |ig|, |bidDebugReportInfo|, + |paContributions|, and |reportingContext|. 1. If |auctionConfig|'s [=auction config/per buyer real time reporting config=][|buyer|] is "`default-local-reporting`", then [=insert entries to map=] given |realTimeContributionsMap|, |buyer|, and |realTimeContributions|. 1. [=list/For each=] |bidToScore| of |bidsToScore|: 1. If |bidToScore|'s [=generated bid/for k-anon auction=] is true, [=list/append=] |bidToScore|'s [=generated bid/interest group=] to |bidIgs|. - 1. [=Score and rank a bid=] with |auctionConfig|, |reportingContextMap|[ - |auctionConfig|], |bidToScore|, |leadingBidInfo|, - |decisionLogicFetcher|, |trustedScoringSignalsBatcher|, + 1. [=Score and rank a bid=] with |auctionConfig|, |reportingContext|, |bidToScore|, + |leadingBidInfo|, |decisionLogicFetcher|, |trustedScoringSignalsBatcher|, |directFromSellerSignalsForSeller|, |dataVersion|, |auctionLevel|, |componentAuctionExpectedCurrency|, |topLevelOrigin|, and |realTimeContributionsMap|. 1. Decrement |pendingBuyers| by 1. 1. Wait until both |pendingBuyers| and |pendingAdditionalBids| are 0. 1. If |auctionConfig|'s [=auction config/aborted=] is true, return failure. +1. Set |reportingContext|'s [=reporting context/local leader info=] to |leadingBidInfo|. 1. If |leadingBidInfo|'s [=leading bid info/leading bid=] is null, return null. 1. If |topLevelAuctionConfig| is null: 1. Let « |sellerSignals|, |reportResultBrowserSignals| » be the result of running - [=report result=] with |leadingBidInfo|, |directFromSellerSignalsForSeller|, null, and |global|. + [=report result=] with |leadingBidInfo|, |reportingContext|, |directFromSellerSignalsForSeller|, + null, and |global|. 1. Let |directFromSellerSignalsForWinner| be the result of running [=get direct from seller signals for a buyer=] with |directFromSellerSignals|, and |leadingBidInfo|'s [=leading bid info/leading bid=]'s [=generated bid/interest group=]'s [=interest group/owner=]. - 1. Run [=report win=] with |leadingBidInfo|, |sellerSignals|, |reportResultBrowserSignals|, - |directFromSellerSignalsForWinner|, and |settings|. + 1. Run [=report win=] with |leadingBidInfo|, |reportingContext|, |sellerSignals|, + |reportResultBrowserSignals|, |directFromSellerSignalsForWinner|, and |settings|. + 1. Set |reportingContext|'s [=reporting context/winner reporting id=] to |leadingBidInfo|'s + [=leading bid info/leading bid=]'s [=generated bid/reporting id=]. 1. Let |replacements| be an [=ordered map=] whose [=map/keys=] are [=strings=] and whose [=map/values=] are [=strings=]. 1. [=list/For each=] [=ad keyword replacement=], |replacement|, within @@ -2322,9 +2354,9 @@ or "component-auction", a [=currency tag=] |componentAuctionExpectedCurrency|, a "`default-local-reporting`", then [=add a platform contribution=] with [=scoring script failure bucket=], |realTimeContributionsMap| and |seller|. 1. Return. -1. Let « |scoreAdResult|, |debugWinReportUrl|, |debugLossReportUrl|, |realTimeContributions| » be - the result of [=evaluating a scoring script=] with |decisionLogicScript|, |adMetadata|, - |bidValue|'s [=bid with currency/value=], |auctionConfig|'s [=auction config/config idl=], +1. Let « |scoreAdResult|, |debugWinReportUrl|, |debugLossReportUrl|, |realTimeContributions|, + |paContributions| » be the result of [=evaluating a scoring script=] with |decisionLogicScript|, + |adMetadata|, |bidValue|'s [=bid with currency/value=], |auctionConfig|, |reportingContext|, |sameOriginTrustedScoringSignals|, |crossOriginTrustedScoringSignals|, |browserSignals|, |directFromSellerSignalsForSeller|, and |auctionConfig|'s [=auction config/seller timeout=]. 1. If |generatedBid|'s [=generated bid/for k-anon auction=] is true: @@ -2352,6 +2384,8 @@ or "component-auction", a [=currency tag=] |componentAuctionExpectedCurrency|, a 1. If |auctionConfig|'s [=auction config/seller real time reporting config=] is "`default-local-reporting`", then [=insert entries to map=] given |realTimeContributionsMap|, |seller|, and |realTimeContributions|. + 1. [=Commit private aggregation contributions=] given |paContributions|, |generatedBid|'s + [=generated bid/reporting id=] and |reportingContext|. 1. Let |scoreAdOutput| be result of [=processing scoreAd output=] with |scoreAdResult|. 1. Return if any of the following conditions hold: * |scoreAdOutput| is failure; @@ -2770,8 +2804,9 @@ To get direct from seller signals for a buyer given a
To report result given a [=leading bid info=] |leadingBidInfo|, a -[=direct from seller signals=]-or-null |directFromSellerSignals|, an [=auction config=]-or-null -|winningComponentConfig|, and a [=global object=] |global|: +[=reporting context=] |reportingContext|, a [=direct from seller signals=]-or-null +|directFromSellerSignals|, an [=auction config=]-or-null |winningComponentConfig|, +and a [=global object=] |global|: 1. Let |config| be |leadingBidInfo|'s [=leading bid info/auction config=]. 1. Let |bidCurrency| be null. 1. If |winningComponentConfig| is not null: @@ -2859,9 +2894,11 @@ To report result given a [=leading bid info=] |leadingBidInfo|, a |config|'s [=auction config/decision logic url=] and |global|'s [=relevant settings object=]. 1. Let |sellerReportingScript| be the result of [=waiting for script body from a fetcher=] given |sellerReportingScriptFetcher|. - 1. Let « |sellerSignals|, |reportUrl|, |reportingBeaconMap|, ignored » be the result of - [=evaluating a reporting script=] with |sellerReportingScript|, "`reportResult`", |config|'s - [=auction config/config idl=]'s {{AuctionAdConfig/reportingTimeout}}, and + 1. Let « |sellerSignals|, |reportUrl|, |reportingBeaconMap|, ignored, |paContributions| » be the + result of [=evaluating a reporting script=] with |sellerReportingScript|, "`reportResult`", + |reportingContext|, |config|'s [=auction config/seller=], |config|'s [=auction config/seller + Private Aggregation coordinator=], |config|'s [=auction config/config idl=]'s + {{AuctionAdConfig/reportingTimeout}}, and « |config|'s [=auction config/config idl=], |browserSignals|, |directFromSellerSignals| ». 1. Let |reportingResult| be a [=reporting result=] with the following [=struct/items=]: : [=reporting result/report url=] @@ -2873,6 +2910,8 @@ To report result given a [=leading bid info=] |leadingBidInfo|, a [=leading bid info/component seller reporting result=] to |reportingResult|. 1. Otherwise, set |leadingBidInfo|'s [=leading bid info/seller reporting result=] to |reportingResult|. + 1. [=Commit private aggregation contributions=] given |paContributions|, |winner|'s [=generated + bid/reporting id=] and |reportingContext|. 1. [=map/Remove=] |browserSignals|["`desirability`"]. 1. [=map/Remove=] |browserSignals|["`modifiedBid`"]. 1. [=map/Remove=] |browserSignals|["`topLevelSellerSignals`"]. @@ -2885,7 +2924,8 @@ To report result given a [=leading bid info=] |leadingBidInfo|, a
-To report win given a [=leading bid info=] |leadingBidInfo|, a [=string=] |sellerSignals|, +To report win given a [=leading bid info=] |leadingBidInfo|, [=reporting context=] +|reportingContext|, a [=string=] |sellerSignals|, a {{ReportingBrowserSignals}} |browserSignals|, a [=direct from seller signals=]-or-null |directFromSellerSignals|, and an [=environment settings object=] |settings|: @@ -2914,8 +2954,8 @@ a {{ReportingBrowserSignals}} |browserSignals|, a [=direct from seller signals=]
|winner|'s [=generated bid/modeling signals=] if it is not null, {{undefined}} otherwise (TODO: noise and bucket this signal) - 1. Let |igAd| be the [=interest group ad=] from |winner|'s - [=generated bid/interest group=]'s [=interest group/ads=] whose + 1. Let |ig| be |winner|'s [=generated bid/interest group=]. + 1. Let |igAd| be the [=interest group ad=] from ig's [=interest group/ads=] whose [=interest group ad/render url=] is |winner|'s [=generated bid/ad descriptor=]'s [=ad descriptor/url=]. 1. If |winner|'s [=generated bid/selected buyer and seller reporting ID=] is not null: @@ -2953,13 +2993,16 @@ a {{ReportingBrowserSignals}} |browserSignals|, a [=direct from seller signals=] 1. Let |reportFunctionName| be "`reportWin`". 1. If |winner|'s [=generated bid/provided as additional bid=] is true: 1. Set |reportFunctionName| be "`reportAdditionalBidWin`". - 1. Let « ignored, |resultUrl|, |reportingBeaconMap|, |reportingMacroMap| » be the result of - [=evaluating a reporting script=] with |buyerReportingScript|, "`reportWin`", |leadingBidInfo|'s - [=leading bid info/auction config=]'s [=auction config/config idl=]'s - {{AuctionAdConfig/reportingTimeout}}, and + 1. Let « ignored, |resultUrl|, |reportingBeaconMap|, |reportingMacroMap|, |paContributions| » be + the result of [=evaluating a reporting script=] with |buyerReportingScript|, "`reportWin`", + |reportingContext|, |ig|'s [=interest group/owner=], |ig|'s [=interest group/Private Aggregation + coordinator=], |leadingBidInfo|'s [=leading bid info/auction config=]'s [=auction config/config + idl=]'s {{AuctionAdConfig/reportingTimeout}}, and « |leadingBidInfo|'s [=leading bid info/auction config=]'s [=auction config/config idl=]'s {{AuctionAdConfig/auctionSignals}}, |perBuyerSignalsForBuyer|, |sellerSignals|, |reportWinBrowserSignals|, |directFromSellerSignals| ». + 1. [=Commit private aggregation contributions=] given |paContributions|, |winner|'s [=generated + bid/reporting id=] and |reportingContext|. 1. Set |leadingBidInfo|'s [=leading bid info/buyer reporting result=] to a [=reporting result=] with the following [=struct/items=]: : [=reporting result/report url=] @@ -3564,6 +3607,25 @@ A reporting context is a [=struct=] with the following [=struct/items
: debug reporting info :: A [=map=] from [=reporting bid key=] to [=bid debug reporting info=]. + : private aggregation batching scope map + :: A [=map=] from a [=tuple=] consisting of an origin (an + [=origin=]) and a coordinator (an [=aggregation + coordinator=]) to a [=batching scope=]. + + Note: Does not include [=batching scopes=] for contributions conditional on + non-reserved events. + : private aggregation on event contributions + :: A [=map=] from a tuple of ([=reporting bid key=], [=string=]) to a [=list=] of [=on event + contribution entries=]. + : private aggregation allowed + :: A [=boolean=], initially false. + : local leader info + :: A [=leading bid info=], describing information on what, if anything, won the particular + auction this [=reporting context=] is for. + : winner reporting id + :: A [=reporting bid key=] or null, initially null. This can be null even if [=reporting context/ + local leader info=] has a leader set, in case this context is for a component auction that lost + at top-level.
A reporting context map is a [=map=] from [=auction config=] to [=reporting context=]. @@ -3571,16 +3633,45 @@ Here the keys are configurations for auctions that actually produce bids (e.g. n auction in a multi-party auction).
- To create a reporting context map given [=auction config=] |auctionConfig|: + To create a reporting context map given the [=auction config=] |auctionConfig| and + a [=boolean=] |privateAggregationAllowed|: 1. Let |reportingContextMap| be a new [=reporting context map=]. - 1. If |auctionConfig|'s [=auction config/component auctions=] [=list/is empty=], - [=map/set=] |reportingContextMap|[|auctionConfig|] to a new [=reporting context=]. - 1. Otherwise, [=list/for each=] |component| in |auctionConfig|'s + 1. [=map/Set=] |reportingContextMap|[|auctionConfig|] to a new [=reporting context=]. + 1. [=list/For each=] |component| in |auctionConfig|'s [=auction config/component auctions=], [=map/set=] |reportingContextMap|[|component|] to a new [=reporting context=]. + 1. [=map/For each=] _ → |reportingContext| of |reportingContextMap|: + 1. Set |reportingContext|'s [=reporting context/private aggregation allowed=] to + |privateAggregationAllowed| 1. Return |reportingContextMap|.
+
+ To register bids for reporting given a [=list=] of + [=generated bids=] |generatedBids|, [=interest group=] |ig|, [=bid debug reporting info=] + |bidDebugReportInfo|, a [=Private Aggregation contributions=] |paContributions| and a [=reporting + context=] |reportingContext|: + 1. Let |id| be a new [=reporting bid key=] with the following [=struct/items=]: + : [=reporting bid key/context=] + :: |reportingContext| + + : [=reporting bid key/source=] + :: [=reporting bid source/generate-bid=] + + : [=reporting bid key/bidder origin=] + :: |ig|'s [=interest group/owner=] + + : [=reporting bid key/bid identifier=] + :: |ig|'s [=interest group/name=] + 1. [=map/Set=] |reportingContext|'s [=reporting context/debug reporting info=][|id|] to + |bidDebugReportInfo|. + 1. [=Commit private aggregation contributions=] given |paContributions|, |id| and + |reportingContext|. + 1. [=list/For each=] |generatedBid| of |generatedBids|: + 1. Set |generatedBid|'s [=generated bid/reporting id=] to |id|. + +
+ ## {{InterestGroupBiddingAndScoringScriptRunnerGlobalScope/forDebuggingOnly}} ## {#for-debugging-only-header} *This first introductory paragraph is non-normative.* @@ -3654,29 +3745,6 @@ methods for event-level forDebuggingOnly reports for winning and losi 1. Return |auctionReportInfo|.
-
- To register bids for forDebuggingOnly reports given a [=list=] of - [=generated bids=] |generatedBids|, [=interest group=] |ig|, [=bid debug reporting info=] - |bidDebugReportInfo| and a [=reporting context=] |reportingContext|: - 1. Let |id| be a new [=reporting bid key=] with the following [=struct/items=]: - : [=reporting bid key/context=] - :: |reportingContext| - - : [=reporting bid key/source=] - :: [=reporting bid source/generate-bid=] - - : [=reporting bid key/bidder origin=] - :: |ig|'s [=interest group/owner=] - - : [=reporting bid key/bid identifier=] - :: |ig|'s [=interest group/name=] - 1. [=map/Set=] |reportingContext|'s [=reporting context/debug reporting info=][|id|] to - |bidDebugReportInfo|. - 1. [=list/For each=] |generatedBid| of |generatedBids|: - 1. Set |generatedBid|'s [=generated bid/reporting id=] to |id|. - -
- ### Downsampling ### {#downsampling-header} *This first introductory paragraph is non-normative.* @@ -3961,6 +4029,398 @@ RAPPOR noises each coordinate of the bit vector independently, and it is par 1. Return |histogram|.
+## {{InterestGroupScriptRunnerGlobalScope/privateAggregation}} ## {#private-aggregation-reporting-header} + +*This first introductory paragraph is non-normative.* + +For metrics that can be interpreted as histograms aggregated over the entire population, Protected +Audience provides integration with the [Private Aggregation API](https://github.com/patcg-individual-drafts/private-aggregation-api). +In addition to its {{PrivateAggregation/contributeToHistogram(contribution)}} method, the API is +extended with contributeToHistogramOnEvent(event, contribution) +which permits histogram contributions to be conditional and to incorporate values not accessible to +the running script, like values of auction winning bids and various performance metrics. + +

Signal base value

+A signal base value is one of the following: +
+: "winning-bid" +:: The numeric value is the bid value of the winning bid. +: "highest-scoring-other-bid" +:: The numeric value is the bid value of the highest scoring bid that did not + win. +: "script-run-time" +:: The numeric value is the number of milliseconds of CPU time the calling + function (e.g. `generateBid()`) took to run. +: "signals-fetch-time" +:: The numeric value is the number of milliseconds it took for the trusted + bidding or scoring signals fetch to complete, when called from + `generateBid()` or `scoreAd()`, respectively. In other functions it evaluates to 0. +: "bid-reject-reason" +:: 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=]. + +
+ +

On event contribution entry

+An on event contribution entry is a [=struct=] with the following items: +
+: contribution +:: A {{PAExtendedHistogramContribution}} +: batching scope +:: A [=batching scope=] or null +: debug scope +:: A [=debug scope=] +: debug details +:: A [=debug details=] or null (default null) + +
+ +

Worklet function

+A worklet function is one of the following: +
+: "generate-bid" +:: The `generateBid()` function. +: "score-ad" +:: The `scoreAd()` function. +: "report-result" +:: The `reportResult()` function. +: "report-win" +:: The `reportWin()` function. + +
+ +

Private Aggregation contributions

+Private Aggregation contributions is a [=map=] from [=string=] to a [=list=] of [=on event +contribution entries=]. + +### Algorithms ### {#private-aggregation-algorithms} + +
+To prepare for private aggregation given a +{{InterestGroupScriptRunnerGlobalScope}} |global|, a [=reporting context=] |reportingContext|, +and [=origins=] |origin| and |aggregationCoordinator|: +1. Let |debugScope| be a new [=debug scope=]. +1. Set |global|'s [=InterestGroupScriptRunnerGlobalScope/private aggregation=] to a new + [=PrivateAggregation=] with the following [=struct/items=]: + : allowed to use + :: |reportingContext|'s [=reporting context/private aggregation allowed=]. + : scoping details + :: a new [=scoping details=] with the [=struct/items=]: + : get batching scope steps + :: An algorithm that performs the following steps: + 1. If |aggregationCoordinator| is null, set |aggregationCoordinator| to + the [=default aggregation coordinator=]. + 1. Return the result of running [=get or create a batching scope=] given + |origin|, |aggregationCoordinator| and |reportingContext|. + : get debug scope steps + :: An algorithm that returns |debugScope|. + +
+ +
+To finalize private aggregation debug info given a +{{InterestGroupScriptRunnerGlobalScope}} |global|: + 1. Let |debugScope| be the result of running |global|'s {{InterestGroupScriptRunnerGlobalScope/ + privateAggregation}}'s + scoping details's + get debug scope steps. + 1. Let |debugDetails| be the result of [=get a debug details=] given |debugScope|. + 1. Let |onEventContributionMap| be |global|'s [=InterestGroupScriptRunnerGlobalScope/on event + contribution map=]. + 1. [=map/For each=] event → |entries| of |onEventContributionMap|: + 1. [=list/For each=] |onEventEntry| of |entries|: + 1. If |onEventEntry|'s [=on event contribution entry/debug scope=] is |debugScope|, + set |onEventEntry|'s [=on event contribution entry/debug details=] to |debugDetails|. + 1. [=Mark a debug scope complete=] given |debugScope|. +
+ +
+To extract private aggregation contributions given a +{{InterestGroupScriptRunnerGlobalScope}} |global|: + 1. Return |global|'s [=InterestGroupScriptRunnerGlobalScope/on event contribution map=]. + +Issue: TODO: regular histograms need to work the same way, too, so they get discarded for k-anon +runs; this method exists as an abstraction to help add that. +
+ +
+To commit private aggregation contributions given an [=Private Aggregation +contributions=] |onEventMap|, a [=reporting bid key=] |bidKey|, and a [=reporting context=] +|reportingContext|: + 1. [=map/For each=] |event| → |contributions| of |onEventMap|: + 1. Let |key| be (|bidKey|, |event|). + 1. If |reportingContext|'s [=reporting context/private aggregation on event contributions=][|key|] + does not [=map/exist=], set it to a new [=list=]. + 1. [=list/Extend=] |reportingContext|'s [=reporting context/private aggregation on event + contributions=][|key|] with |contributions|. +
+ +
+To get or create a batching scope given an [=origin=] |origin|, an +[=aggregation coordinator=] |aggregationCoordinator| and a [=reporting context=] |reportingContext|, +perform the following steps. They return a [=batching scope=]. +1. Let |batchingScopeMap| be |reportingContext|'s [=reporting context/private aggregation + batching scope map=]. +1. Let |tuple| be (|origin|, |aggregationCoordinator|). +1. If |batchingScopeMap|[|tuple|] does not [=map/exist=]: + 1. Set |batchingScopeMap|[|tuple|] to a new [=batching scope=]. + 1. If |aggregationCoordinator| is not null, [=set the aggregation coordinator for a batching + scope=] given |aggregationCoordinator| and |batchingScopeMap|[|tuple|]. +1. Return |batchingScopeMap|[|tuple|]. + +
+ +
+To process the Private Aggregation contributions given an [=auction config=] +|auctionConfig| and a [=reporting context map=] |reportingContextMap|: + +1. [=Process the Private Aggregation contributions for an auction=] given |auctionConfig|, + |reportingContextMap|[|auctionConfig|]. +1. [=list/For each=] |componentAuction| in |auctionConfig|'s [=auction config/component + auctions=]: + 1. [=Process the Private Aggregation contributions for an auction=] given |componentAuction|, + |reportingContextMap|[|componentAuction|]. + +
+ +
+To process the Private Aggregation contributions for an auction 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=]. +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. [=list/For each=] |onEventEntry| of |contributions|: + 1. Let |filledInContribution| be the result of [=filling in the contribution=] given + |onEventEntry|'s [=on event contribution entry/contribution=] and |leadingBidInfo|. + + Issue: Once WICG/turtledove#627 + is resolved, align 'filling in' logic with `forDebuggingOnly`. + + 1. If |event| does not [=string/start with=] "`reserved.`": + 1. Store |event|, |filledInContribution|, |onEventEntry|'s [=on event contribution entry/debug + details=] in the {{FencedFrameConfig}} as appropriate. + + Note: Each non-reserved |event| will have a different [=batching scope=]. + + Issue: Once WICG/turtledove#616 + and any successors are landed, align integration and fill in fenced frame's + report a private aggregation event. + 1. Otherwise: + 1. Let |entry| be a new [=contribution cache entry=] with the items: + : contribution + :: |filledInContribution| + : batching scope + :: |onEventEntry|'s [=on event contribution entry/batching scope=] + : debug scope + :: |onEventEntry|'s [=on event contribution entry/debug scope=] + : debug details + :: |onEventEntry|'s [=on event contribution entry/debug details=] + 1. [=Append an entry to the contribution cache|Append=] |entry| to the [=contribution cache=]. +1. Let |sellerBatchingScope| be the result of [=get or create a batching + scope|getting or creating a batching scope=] given |auctionConfig|'s [=auction config/seller=], + |auctionConfig|'s [=auction config/seller Private Aggregation coordinator=], and + |reportingContext|. +1. Let |auctionReportBuyersDebugScope| be a new [=debug scope=]. +1. [=map/For each=] |reportType| → |reportBuyerConfig| of |auctionConfig|'s + [=auction config/auction report buyers=]: + 1. [=map/For each=] |buyerOrigin| → |buyerOffset| of |auctionConfig|'s + [=auction config/auction report buyer keys=]: + 1. Let |bucket| be the sum of |buyerOffset| and |reportBuyerConfig|'s + {{AuctionReportBuyersConfig/bucket}}. + + Issue: Handle overflow here or in validation. See WICG/turtledove#1040. + 1. Let |value| be the result (a {{double}}) of switching on + |reportType|: +
+ : "`interestGroupCount`" + :: The number of interest groups in the [=user agent=]'s interest group set whose owner is + |buyerOrigin|. + : "`bidCount`" + :: The number of valid bids generated by interest groups whose owner is + |buyerOrigin|. + : "`totalGenerateBidLatency`" + :: The sum of execution time in milliseconds for all `generateBid()` + calls in the auction for interest groups whose owner is + |buyerOrigin|. + : "`totalSignalsFetchLatency`" + :: The total time spent fetching trusted buyer signals in + milliseconds, or 0 if the interest group didn't fetch any + trusted signals. + : None of the above values + :: [=Assert=]: false, as this enum value is validated in [=validate and convert auction + ad config=] + +
+ + Issue: More formally spec the values here. + + 1. Set |value| to the result of multiplying |reportBuyerConfig|'s + {{AuctionReportBuyersConfig/scale}} with |value|. + 1. Set |value| to the maximum of 0.0 and |value|. + 1. Set |value| to the result of converting |value| to an integer by + truncating its fractional part. + 1. Set |value| to the minimum of |value| and 231−1. + 1. Let |contribution| be a new {{PAHistogramContribution}} with the + items: + : {{PAHistogramContribution/bucket}} + :: |bucket| + : {{PAHistogramContribution/value}} + :: |value| + : {{PAHistogramContribution/filteringId}} + :: 0 + + Issue: Consider allowing the filtering ID to be set here. + 1. [=map/For each=] |ig| of the [=user agent=]'s + interest group set whose + owner is |buyerOrigin|: + 1. If seller capabilities of |ig| don't allow this reporting, [=iteration/continue=]. + + Issue: Align behavior with seller capabilities handling once + WICG/turtledove#966 is resolved. + 1. Let |entry| be a new [=contribution cache entry=] with the items: + : contribution + :: |contribution| + : batching scope + :: |sellerBatchingScope| + : debug scope + :: |auctionReportBuyersDebugScope| + 1. [=Append an entry to the contribution cache|Append=] |entry| to + the [=contribution cache=]. +1. [=Mark a debug scope complete=] given |auctionReportBuyersDebugScope| and + |auctionConfig|'s [=auction config/auction report buyer debug details=]. +1. [=map/For each=] (|origin|, aggregationCoordinator) → + |batchingScope| of |reportingContext|'s [=reporting context/private aggregation batching + scope map=]: + 1. [=Process contributions for a batching scope=] given |batchingScope|, |origin|, + "protected-audience" and null. + +
+ +
+To fill in the contribution given a {{PAExtendedHistogramContribution}} |contribution| +and a [=leading bid info=] |leadingBidInfo|, perform the following steps. They return a +{{PAHistogramContribution}}: +1. Let |bucket| be |contribution|["{{PAExtendedHistogramContribution/bucket}}"]. +1. If |bucket| is a {{PASignalValue}}, set |bucket| to the result of [=filling + in the signal value=] given |bucket|, 2128−1 and |leadingBidInfo|. +1. Let |value| be |contribution|["{{PAExtendedHistogramContribution/value}}"]. +1. If |value| is a {{PASignalValue}}, set |value| to the result of [=filling in + the signal value=] given |value|, 231−1 and |leadingBidInfo|. +1. Let |filledInContribution| be a new {{PAHistogramContribution}} with the + items: + : {{PAHistogramContribution/bucket}} + :: |bucket| + : {{PAHistogramContribution/value}} + :: |value| + : {{PAHistogramContribution/filteringId}} + :: |contribution|["{{PAExtendedHistogramContribution/filteringId}}"] +1. Return |filledInContribution|. + +
+ +
+To fill in the signal value given a {{PASignalValue}} |value|, an +integer |maxAllowed| and a [=leading bid info=] |leadingBidInfo|, perform the following steps. +They return an integer. +1. [=Assert=]: |value|["{{PASignalValue/baseValue}}"] is a valid [=signal base + value=]. +1. Let |returnValue| be the result of [=determining a signal's numeric value=] + given |value|["{{PASignalValue/baseValue}}"] and |leadingBidInfo|. +1. If |value|["{{PASignalValue/scale}}"] [=map/exists=], set |returnValue| to + the result of multiplying |value|["{{PASignalValue/scale}}"] with + |returnValue|. +1. Set |returnValue| to the result of converting |returnValue| to an integer by + truncating its fractional part. +1. If |value|["{{PASignalValue/offset}}"] [=map/exists=], set |returnValue| to + the result of adding |returnValue| to |value|["{{PASignalValue/offset}}"]. +1. Clamp |returnValue| to [=the inclusive range|the range=] 0 to |maxAllowed|, + inclusive, and return the result. + +
+ + +
+To determine a signal's numeric value given a [=signal base value=] +|signalBaseValue| and a [=leading bid info=] |leadingBidInfo|, perform the following steps. +They return a {{double}}. +1. If |signalBaseValue| is "[=signal base value/winning-bid=]": + 1. If |leadingBidInfo|'s [=leading bid info/leading bid=] is null, return 0. + 1. Otherwise, return |leadingBidInfo|'s [=leading bid info/leading bid=]'s [=generated bid/bid=]. +1. If |signalBaseValue| is + "[=signal base value/highest-scoring-other-bid=]": + 1. If |leadingBidInfo|'s [=leading bid info/highest scoring other bid=] is null, return 0. + 1. Otherwise, return |leadingBidInfo|'s [=leading bid info/highest scoring other bid=]'s + [=generated bid/bid=]. +1. If |signalBaseValue| is "[=signal base value/script-run-time=]": + 1. Return the number of milliseconds of CPU time that the calling function + (e.g. `generateBid()`) took to run. +1. If |signalBaseValue| is "[=signal base value/signals-fetch-time=]": + Switch on the associated [=worklet function=]: +
+ : [=worklet function/generate-bid=] + :: Return the number of milliseconds it took for the trusted bidding signals + fetch to complete, or 0 if no fetch was made. + : [=worklet function/score-ad=] + :: Return the number of milliseconds it took for the trusted scoring signals + fetch to complete or 0 if no fetch was made. + : [=worklet function/report-result=] + : [=worklet function/report-win=] + :: Return 0. + +
+1. If |signalBaseValue| is "[=signal base value/bid-reject-reason=]": + 1. If the bid did not succeed purely because it didn't meet the required + k-anonymity threshold, return 8. + 1. Let |bidRejectReason| be "`not-available`". + 1. If the seller provided a reject reason, set |bidRejectReason| to that + value. + 1. If |bidRejectReason| is: +
+ : "`not-available`" + :: Return 0. + : "`invalid-bid`" + :: Return 1. + : "`bid-below-auction-floor`" + :: Return 2. + : "`pending-approval-by-exchange`" + :: Return 3. + : "`disapproved-by-exchange`" + :: Return 4. + : "`blocked-by-publisher`" + :: Return 5. + : "`language-exclusions`" + :: Return 6. + : "`category-exclusions`" + :: Return 7. + : None of the above values + :: [=Assert=]: false + + Note: this enum value is validated in `scoreAd()`. + + Issue: Verify this once + WICG/turtledove#627 is resolved. + + Issue: There are some automatically generated values that are not described here. + + Issue: Verify handling when the bid was not rejected. + +
+ +
+ ## Get storage interest groups for owner ## {#get-storage-interest-groups-for-owner-header} *This first introductory paragraph is non-normative.* @@ -4837,14 +5297,15 @@ of the following global objects:
To evaluate a bidding script given a [=string=] |script|, an {{unsigned short}} - |multiBidLimit|, an [=interest group=] |ig|, a [=currency tag=] |expectedCurrency|, - a {{GenerateBidInterestGroup}} |igGenerateBid|, a [=string=]-or-null - |auctionSignals|, a [=string=]-or-null |perBuyerSignals|, an [=ordered map=]-or-null - |sameOriginTrustedBiddingSignals|, an [=ordered map=]-or-null |crossOriginTrustedBiddingSignals|, - a {{BiddingBrowserSignals}} |browserSignals|, a {{DirectFromSellerSignalsForBuyer}} - |directFromSellerSignalsForBuyer|, and an integer millisecond [=duration=] |timeout|, perform the - following steps. They return a [=tuple=] ([=list=] of [=generated bids=], - [=bid debug reporting info=], [=list=] of [=real time reporting contributions=]). + |multiBidLimit|, an [=interest group=] |ig|, a [=reporting context=] |reportingContext|, + a [=currency tag=] |expectedCurrency|, a {{GenerateBidInterestGroup}} |igGenerateBid|, + a [=string=]-or-null |auctionSignals|, a [=string=]-or-null |perBuyerSignals|, + an [=ordered map=]-or-null |sameOriginTrustedBiddingSignals|, an [=ordered map=]-or-null + |crossOriginTrustedBiddingSignals|, a {{BiddingBrowserSignals}} |browserSignals|, + a {{DirectFromSellerSignalsForBuyer}} |directFromSellerSignalsForBuyer|, and an integer + millisecond [=duration=] |timeout|, perform the following steps. They return a [=tuple=] ([=list=] + of [=generated bids=], [=bid debug reporting info=], [=list=] of [=real time reporting + contributions=]). 1. Let |realm| be the result of [=creating a new script runner realm=] given {{InterestGroupBiddingScriptRunnerGlobalScope}}. @@ -4857,6 +5318,8 @@ of the following global objects: [=InterestGroupBiddingScriptRunnerGlobalScope/group has ad components=] to true if |ig|'s [=interest group/ad components=] is not null, or false otherwise. 1. Set |global|'s [=InterestGroupBiddingScriptRunnerGlobalScope/expected currency=] to |expectedCurrency|. + 1. [=Prepare for private aggregation=] given |global|, |reportingContext|, |ig|'s [=interest + group/owner=] and |ig|'s [=interest group/Private Aggregation coordinator=]. 1. Let |isComponentAuction| be true if |browserSignals|["{{BiddingBrowserSignals/topLevelSeller}}"] is not null, or false otherwise. 1. Set |global|'s [=InterestGroupBiddingScriptRunnerGlobalScope/is component auction=] to @@ -4928,20 +5391,31 @@ of the following global objects: 1. If |contribution|'s [=real time reporting contribution/latency threshold=] is not null, and ≥ |duration|, then [=iteration/continue=]. 1. [=list/Append=] |contribution| to |realTimeContributions|. - 1. Return a [=tuple=] (|generatedBids|, |bidDebugReportInfo|, |realTimeContributions|). + 1. [=Finalize private aggregation debug info=] given |global|. + 1. Let |paContributions| be the result of [=extracting private aggregation contributions=] given + |global|. + 1. Return a [=tuple=] (|generatedBids|, |bidDebugReportInfo|, |realTimeContributions|, + |paContributions|).
To evaluate a scoring script given a [=string=] |script|, a [=string=] |adMetadata|, - a {{double}} |bidValue|, an {{AuctionAdConfig}} |auctionConfigIDL|, an [=ordered map=]-or-null - |sameOriginTrustedScoringSignals|, an [=ordered map=]-or-null |crossOriginTrustedScoringSignals|, + a {{double}} |bidValue|, an [=auction config=] |auctionConfig|, a [=reporting context=] + |reportingContext|, an [=ordered map=]-or-null |sameOriginTrustedScoringSignals|, + an [=ordered map=]-or-null |crossOriginTrustedScoringSignals|, {{ScoringBrowserSignals}} |browserSignals|, a {{DirectFromSellerSignalsForSeller}} |directFromSellerSignalsForSeller|, and an integer millisecond [=duration=] |timeout|: 1. Let |realm| be the result of [=creating a new script runner realm=] given {{InterestGroupScoringScriptRunnerGlobalScope}}. + 1. Let |global| be |realm|'s [=realm/global object=]. + 1. Let |settings| be |realm|'s [=realm/settings object=]. + 1. [=Prepare for private aggregation=] given |global|, |reportingContext|, |auctionConfig|'s + [=auction config/seller=] and |auctionConfig|'s [=auction config/seller Private Aggregation + coordinator=]. 1. Let |browserSignalsJS| be |browserSignals| [=converted to ECMAScript values=]. - 1. Let |auctionConfigJS| be |auctionConfigIDL| [=converted to ECMAScript values=]. + 1. Let |auctionConfigJS| be |auctionConfig|'s [=auction config/config idl=] [=converted to + ECMAScript values=]. 1. Let |sameOriginTrustedScoringSignalsJS| be |sameOriginTrustedScoringSignals| [=converted to ECMAScript values=]. 1. Let |crossOriginTrustedScoringSignalsJS| be |crossOriginTrustedScoringSignals| @@ -4967,17 +5441,24 @@ of the following global objects: 1. If |contribution|'s [=real time reporting contribution/latency threshold=] is not null, and ≥ |duration|, then [=iteration/continue=]. 1. [=list/Append=] |contribution| to |realTimeContributions|. - 1. Return « |scoreAdResult|, |debugWinReportUrl|, |debugLossReportUrl|, |realTimeContributions| ». + 1. [=Finalize private aggregation debug info=] given |global|. + 1. Let |paContributions| be the result of [=extracting private aggregation contributions=] given + |global|. + 1. Return « |scoreAdResult|, |debugWinReportUrl|, |debugLossReportUrl|, |realTimeContributions|, + |paContributions| ».
To evaluate a reporting script given a [=string=] |script|, a [=string=] - |functionName|, an integer millisecond [=duration=] |timeout|, and a [=list=] of arguments - |arguments|: + |functionName|, a [=reporting context=] |reportingContext|, an [=origin=] |origin|, an + [=origin=] |privateAggregationCoordinator|, an integer millisecond [=duration=] |timeout|, + and a [=list=] of arguments |arguments|: 1. Let |realm| be the result of [=creating a new script runner realm=] given {{InterestGroupReportingScriptRunnerGlobalScope}}. 1. Let |global| be |realm|'s [=realm/global object=]. + 1. [=Prepare for private aggregation=] given |global|, |reportingContext|, |origin|, and + |privateAggregationCoordinator|. 1. Let |argumentsJS| be the result of [=converting a Web IDL arguments list to an ECMAScript arguments list|converting=] |arguments| to an ECMAScript arguments list. If this [=exception/throws=] an exception, return « "null", null, null, null ». @@ -4994,8 +5475,12 @@ of the following global objects: 1. If |reportURL| is failure, set |reportURL| to null. 1. Let |macroMap| be |global|'s [=InterestGroupReportingScriptRunnerGlobalScope/reporting macro map=] if |functionName| is "`reportWin`" or "`reportAdditionalBidWin`", null otherwise. + 1. [=Finalize private aggregation debug info=] given |global|. + 1. Let |paContributions| be the result of [=extracting private aggregation contributions=] given + |global|. 1. Return « |resultJSON|, |reportURL|, - |global|'s [=InterestGroupReportingScriptRunnerGlobalScope/reporting beacon map=], |macroMap| ». + |global|'s [=InterestGroupReportingScriptRunnerGlobalScope/reporting beacon map=], |macroMap|, + |paContributions| ».
@@ -5062,10 +5547,113 @@ specification are those that explicitly list the global names provided here.
 [Exposed=InterestGroupScriptRunnerGlobalScope]
 interface InterestGroupScriptRunnerGlobalScope {
+  readonly attribute PrivateAggregation? privateAggregation;
+};
+
+dictionary PASignalValue {
+  required DOMString baseValue;
+  double scale;
+  (bigint or long) offset;
+};
+
+dictionary PAExtendedHistogramContribution {
+  required (PASignalValue or bigint) bucket;
+  required (PASignalValue or long) value;
+  bigint filteringId = 0;
+};
+
+[Exposed=InterestGroupScriptRunnerGlobalScope]
+partial interface PrivateAggregation {
+  undefined contributeToHistogramOnEvent(
+      DOMString event, PAExtendedHistogramContribution contribution);
 };
 
 
+Each {{InterestGroupScriptRunnerGlobalScope}} has a +
+ : private aggregation + :: Null, or a [=PrivateAggregation=]. Initially null. + : on event contribution map + :: A [=map=] from [=string=] to a [=list=] of [=on event contribution entries=]. +
+ +
+The privateAggregation [=getter + steps=] are: + + 1. Return [=this=]'s [=relevant global object=]'s + [=InterestGroupScriptRunnerGlobalScope/private aggregation=]. +
+ +
+The contributeToHistogramOnEvent(DOMString +event, PAExtendedHistogramContribution contribution) method steps are: +1. If [=this=]'s + allowed to use is false, [=exception/throw=] a {{TypeError}}. +1. Let |scopingDetails| be [=this=]'s + scoping details +1. If |event| [=string/starts with=] "`reserved.`" and « "`reserved.always`", + "`reserved.loss`", "`reserved.win`" » does not [=list/contain=] |event|, + return. + + Note: No error is thrown to allow forward compatibility if additional + reserved event types are added later. +1. Let |bucket| be |contribution|["{{PAExtendedHistogramContribution/bucket}}"]. +1. If |bucket| is a {{PASignalValue}}: + 1. If |bucket|["{{PASignalValue/baseValue}}"] is not a valid [=signal base + value=], [=exception/throw=] a {{TypeError}}. + 1. If |bucket|["{{PASignalValue/offset}}"] is not a {{bigint}}, [=exception/ + throw=] a {{TypeError}}. +1. Otherwise, if |contribution|["{{PAExtendedHistogramContribution/bucket}}"] is + not [=set/contained=] in [=the exclusive range|the range=] 0 to + 2128, exclusive, [=exception/throw=] a {{TypeError}}. + + Issue: Make the error type consistent with + {{PrivateAggregation/contributeToHistogram(contribution)}}. +1. Let |value| be |contribution|["{{PAExtendedHistogramContribution/value}}"]. +1. If |value| is a {{PASignalValue}}: + 1. If |value|["{{PASignalValue/baseValue}}"] is not a valid [=signal base + value=], [=exception/throw=] a {{TypeError}}. + 1. If |value|["{{PASignalValue/offset}}"] is a {{bigint}}, [=exception/ + throw=] a {{TypeError}}. +1. Otherwise, if |contribution|["{{PAExtendedHistogramContribution/value}}"] is + negative, [=exception/throw=] a {{TypeError}}. +1. If |contribution|["{{PAExtendedHistogramContribution/filteringId}}"] is + not [=set/contained=] in [=the exclusive range|the range=] 0 to + 256[=default filtering ID max bytes=], exclusive, [=exception/ + throw=] a {{TypeError}}. + + Issue: Make the error types on validation issues here and above consistent + with {{PrivateAggregation/contributeToHistogram(contribution)}}. + + Note: It is not currently possible to set a non-default filtering ID max + bytes for Protected Audience. +1. Let |batchingScope| be null. +1. If |event| [=string/starts with=] "`reserved.`", set |batchingScope| to the + result of running |scopingDetails|' + get batching scope steps. + + Note: Each non-reserved |event| will have a different [=batching scope=] + that is created later. +1. Let |entry| be a new [=on event contribution entry=] with the items: + : [=on event contribution entry/contribution=] + :: |contribution| + : [=on event contribution entry/batching scope=] + :: |batchingScope| + : [=on event contribution entry/debug scope=] + :: The result of running |scopingDetails|' get debug scope steps. + +1. Let |global| be [=this=]'s [=relevant global object=]. +1. Let |onEventContributionMap| be |global|'s + [=InterestGroupScriptRunnerGlobalScope/on event contribution map=]. +1. If |onEventContributionMap|[|event|] does not [=map/exist=], set + |onEventContributionMap|[|event|] to a new [=list=]. +1. [=list/Append=] |entry| to |onEventContributionMap|[|event|]. + +
+
 [Exposed=InterestGroupBiddingAndScoringScriptRunnerGlobalScope]
 interface ForDebuggingOnly {