diff --git a/spec.bs b/spec.bs
index 08ddabc42..cad944aa0 100644
--- a/spec.bs
+++ b/spec.bs
@@ -1779,14 +1779,22 @@ following steps. They return a failure if failing to fetch the script or wasm, o
1. Let |prevWinElement| be the [=sequence=]<{{PreviousWinElement}}>
«|timeDelta|, |prevWinAdIDL|».
1. [=list/Append=] |prevWinElement| to |prevWins|.
1. [=map/Set=] |browserSignals|["{{BiddingBrowserSignals/prevWinsMs}}"] to |prevWins|.
+ 1. Let |metrics| be a new [=execution metrics=].
1. Let |biddingScriptFetcher| be the result of [=creating a new script fetcher=] with
|ig|'s [=interest group/bidding url=], and |settings|.
1. Let |biddingScript| be the result of [=waiting for script body from a fetcher=] given
|biddingScriptFetcher|.
+ 1. [=Add a sample to an averager=] given |metrics|'s [=execution metrics/average code fetch
+ time=] and |biddingScriptFetcher|'s [=script fetcher/fetch duration=].
1. If |biddingScript| is failure, return failure.
1. If |ig|'s [=interest group/bidding wasm helper url=] is not null:
+ 1. Let |wasmFetchStart| be |settings|'s [=environment settings object/current monotonic time=].
1. Let |wasmModuleObject| be the result of [=fetching WebAssembly=] with |ig|'s
[=interest group/bidding wasm helper url=] and |settings|.
+ 1. Let |wasmFetchDuration| be the [=duration from=] |wasmFetchStart| to
+ |settings|'s [=environment settings object/current monotonic time=], in milliseconds.
+ 1. [=Add a sample to an averager=] given |metrics|'s [=execution metrics/average code fetch
+ time=] and |wasmFetchDuration|.
1. If |wasmModuleObject| is not failure, then [=map/set=]
|browserSignals|["{{BiddingBrowserSignals/wasmHelper}}"] to |wasmModuleObject|.
1. Otherwise, return failure.
@@ -1810,7 +1818,7 @@ following steps. They return a failure if failing to fetch the script or wasm, o
|crossOriginTrustedBiddingSignalsOrigin|.
1. [=map/Set=] |crossOriginTrustedBiddingSignalsOrigin|[|originKey|] to |trustedBiddingSignals|.
1. Return the result of [=evaluating a bidding script=] with |biddingScript|, |multiBidLimit|,
- |ig|, |reportingContext|, |expectedCurrency|, |igGenerateBid|, |auctionSignals|,
+ |ig|, |reportingContext|, |metrics|, |expectedCurrency|, |igGenerateBid|, |auctionSignals|,
|perBuyerSignals|, |sameOriginTrustedBiddingSignals|, |crossOriginTrustedBiddingSignals|,
|browserSignals|, |directFromSellerSignalsForBuyer| and |perBuyerTimeout|.
@@ -1964,6 +1972,8 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|:
1. If |perBuyerExperimentGroupIds| is not null and |perBuyerExperimentGroupIds|[|buyer|]
[=map/exists=], then set |buyerExperimentGroupId| to |perBuyerExperimentGroupIds|[|buyer|].
1. Apply interest groups limits to prioritized list:
+ 1. Let |metrics| be the result of [=accessing per-participant metrics=] for |reportingContext|,
+ |buyer|, [=worklet function/generate-bid=].
1. Let |buyerGroupLimit| be |allBuyersGroupLimit|.
1. Let |perBuyerGroupLimits| be |auctionConfig|'s
[=auction config/per buyer group limits=].
@@ -1981,6 +1991,9 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|:
1. [=map/For each=] slotSizeQueryParam → |perSignalsUrlGenerator| of |perSlotSizeQueryParam|:
1. [=map/For each=] joiningOrigin → |groups| of |perSignalsUrlGenerator|:
1. [=list/Remove=] from |groups| any [=interest group=] [=list/contained=] in |igs|.
+ 1. Set |metrics|'s [=per participant metrics/participating interest group count=] to
+ |metrics|'s [=per participant metrics/participating interest group count=] + [=list/
+ size=] of |groups|.
1. Let |perBuyerSignals| be null.
1. If |auctionConfig|'s [=auction config/per buyer signals=] is not null and
[=auction config/per buyer signals=][|buyer|] [=map/exists=], then set |perBuyerSignals| to
@@ -2057,8 +2070,8 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|:
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|, |paContributions|) be
- |generateBidResult|.
+ 1. Let (|bidsBatch|, |bidDebugReportInfo|, |realTimeContributions|, |paContributions|,
+ |executionMetrics|) 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
@@ -2083,8 +2096,8 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|:
1. Let |generateBidStartTime| be |settings|'s
[=environment settings object/current monotonic time=].
1. Set (|generatedBids|, |bidDebugReportInfo|, |realTimeContributions|,
- |paContributions|) to the result of running [=generate potentially multiple bids=]
- with |allTrustedBiddingSignals|,
+ |paContributions|, |executionMetrics|) 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|, |reportingContext|, |auctionStartTime|,
@@ -2102,7 +2115,7 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|:
1. [=Apply any component ads target to a bid=] given |generatedBid|.
1. [=list/Append=] |generatedBid| to |bidsToScore|.
1. [=Register bids for reporting=] given |bidsToScore|, |ig|, |bidDebugReportInfo|,
- |paContributions|, and |reportingContext|.
+ |paContributions|, |executionMetrics|, 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|.
@@ -2354,21 +2367,32 @@ 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 |metrics| be the result of [=access per-participant metrics=] given |reportingContext|,
+ |auctionConfig|'s [=auction config/seller=], [=worklet function/score-ad=].
+1. [=Add a sample to an averager=] given |metrics|'s [=per participant metrics/average code fetch
+ time=] and |decisionLogicFetcher|'s [=script fetcher/fetch duration=].
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=].
+ |paContributions|, |executionMetrics| » 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. Set |metrics|'s [=per participant metrics/script executions attempted=] to |metrics|'s [=per
+ participant metrics/script executions attempted=] + 1.
+1. If |executionMetrics|'s [=execution metrics/script timeout occurred=] is true, set |metrics|'s
+ [=per participant metrics/script timeouts occurred=] to |metrics|'s [=per participant metrics/
+ script timeouts occurred=] + 1.
1. If |generatedBid|'s [=generated bid/for k-anon auction=] is true:
Note: Non-k-anonymous bids do not participate in reporting (except for platform real-time
contributions, and some special handling of private aggregation requests involving reject-reason);
as it would be problematic to report a winner that didn't actually win.
- 1. If |reportingContext|'s [=reporting context/debug reporting info=][|generatedBid|'s [=generated
- bid/reporting id=]] does not [=map/exist=], set it to a new [=bid debug reporting info=].
+ 1. Let |reportingId| be |generatedBid|'s [=generated bid/reporting id=].
+ 1. If |reportingContext|'s [=reporting context/debug reporting info=][|reportingId|] does not
+ [=map/exist=], set it to a new [=bid debug reporting info=].
1. Let |bidDebugReportInfo| be |reportingContext|'s [=reporting context/debug reporting info=]
- [|generatedBid|'s [=generated bid/reporting id=]].
+ [|reportingId|].
1. If |auctionLevel| is "top-level-auction":
1. Set |bidDebugReportInfo|'s [=bid debug reporting info/top level seller debug loss report
url=] to |debugLossReportUrl|.
@@ -2384,8 +2408,11 @@ 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. [=set/Insert=] |reportingId| into |reportingContext|'s [=reporting context/seller
+ participants=].
+ 1.
+ 1. [=Commit private aggregation contributions=] given |paContributions|, |reportingId|, 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;
@@ -2890,17 +2917,25 @@ and a [=global object=] |global|:
[=generated bid/interest group=], |igAd|, and null is true:
1. If |igAd|'s [=interest group ad/buyer and seller reporting ID=] is not null, [=map/set=]
|browserSignals|["{{ReportingBrowserSignals/buyerAndSellerReportingId}}"] to it.
+ 1. Let |metrics| be the result of [=access per-participant metrics=] given |reportingContext|,
+ |config|'s [=auction config/seller=], [=worklet function/report-result=].
1. Let |sellerReportingScriptFetcher| be the result of [=creating a new script fetcher=] with
|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, |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
+ 1. [=Add a sample to an averager=] given |metrics|'s [=per participant metrics/average code fetch
+ time=] and |sellerReportingScriptFetcher|'s [=script fetcher/fetch duration=].
+ 1. Let « |sellerSignals|, |reportUrl|, |reportingBeaconMap|, ignored, |paContributions|,
+ |executionMetrics| » be the result of [=evaluating a reporting script=] with
+ |sellerReportingScript|, [=worklet function/report-result=], |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=]:
+ 1. Set |metrics|'s [=per participant metrics/script executions attempted=] to 1.
+ 1. If |executionMetrics|'s [=execution metrics/script timeout occurred=] is true, set |metrics|'s
+ [=per participant metrics/script timeouts occurred=] to 1.
+ 1. Let |reportingResult| be a [=reporting result=] with the following [=struct/items=]:
: [=reporting result/report url=]
:: |reportUrl|
: [=reporting result/reporting beacon map=]
@@ -2955,6 +2990,8 @@ a {{ReportingBrowserSignals}} |browserSignals|, a [=direct from seller signals=]
(TODO: noise and bucket this signal)
1. Let |ig| be |winner|'s [=generated bid/interest group=].
+ 1. Let |metrics| be the result of [=access per-participant metrics=] given |reportingContext|,
+ |ig|'s [=interest group/owner=], [=worklet function/report-win=].
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=].
@@ -2990,17 +3027,23 @@ a {{ReportingBrowserSignals}} |browserSignals|, a [=direct from seller signals=]
|winner|'s [=generated bid/interest group=]'s [=interest group/bidding url=] and |settings|.
1. Let |buyerReportingScript| be the result of [=waiting for script body from a fetcher=] given
|buyerReportingScriptFetcher|.
+ 1. [=Add a sample to an averager=] given |metrics|'s [=per participant metrics/average code fetch
+ time=] and |buyerReportingScriptFetcher|'s [=script fetcher/fetch duration=].
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|, |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
+ 1. Let « ignored, |resultUrl|, |reportingBeaconMap|, |reportingMacroMap|, |paContributions|,
+ |executionMetrics| » be the result of [=evaluating a reporting script=] with
+ |buyerReportingScript|, [=worklet function/report-win=], |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. Set |metrics|'s [=per participant metrics/script executions attempted=] to 1.
+ 1. If |executionMetrics|'s [=execution metrics/script timeout occurred=] is true, set |metrics|'s
+ [=per participant metrics/script timeouts occurred=] to 1.
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=]
@@ -3626,8 +3669,30 @@ A reporting context is a [=struct=] with the following [=struct/items
:: 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.
+ : bidder participants
+ :: A [=set=] of [=reporting bid keys=], representing interest groups that got a chance to generate
+ bids for the auction. This will be empty in top-level auctions, as the relevant state will be
+ in the component auctions.
+ : seller participants
+ :: A [=set=] of [=reporting bid keys=], representing various `scoreAd()` executions. Note that
+ some of these may be based on bids that started as additional bids or from component auctions
+ run by Bidding and Auction services, and not interest groups, so this list may be quite
+ different from [=reporting context/bidder participants=].
+ : participant metrics
+ :: A [=map=] from a pair ([=origin=], [=worklet function=]) to [=per participant metrics=].
+
+To access per-participant metrics given a [=reporting context=] |reportingContext|,
+an [=origin=] |origin| and [=worklet function=] |workletFunction|:
+1. Let |key| be (|origin|, |workletFunction|).
+1. If |reportingContext|'s [=reporting context/participant metrics=][|key|] does not [=map/exist=],
+ set |reportingContext|'s [=reporting context/participant metrics=][|key|] to a new [=per participant
+ metrics=].
+1. Return |reportingContext|'s [=reporting context/participant metrics=][|key|].
+
+
+
A reporting context map 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).
@@ -3649,8 +3714,8 @@ auction in a multi-party auction).
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|:
+ |bidDebugReportInfo|, a [=Private Aggregation contributions=] |paContributions|,
+ [=execution metrics=] |executionMetrics| and a [=reporting context=] |reportingContext|:
1. Let |id| be a new [=reporting bid key=] with the following [=struct/items=]:
: [=reporting bid key/context=]
:: |reportingContext|
@@ -3665,6 +3730,16 @@ auction in a multi-party auction).
:: |ig|'s [=interest group/name=]
1. [=map/Set=] |reportingContext|'s [=reporting context/debug reporting info=][|id|] to
|bidDebugReportInfo|.
+ 1. Let |metrics| be the result of [=access per-participant metrics=] given |reportingContext|,
+ |ig|'s [=interest group/owner=], [=worklet function/generate-bid=].
+ 1. [=Merge samples to an averager=] given |metrics|'s [=per participant metrics/average code fetch
+ time=] and |executionMetrics|'s [=execution metrics/average code fetch time=].
+ 1. Set |metrics|'s [=per participant metrics/script executions attempted=] to
+ |metrics|'s [=per participant metrics/participating interest group count=].
+ 1. If |executionMetrics|'s [=execution metrics/script timeout occurred=] is true, set |metrics|'s
+ [=per participant metrics/script timeouts occurred=] to |metrics|'s [=per participant metrics/
+ script timeouts occurred=] + 1.
+ 1. [=set/Insert=] |id| into |reportingContext|'s [=reporting context/bidder participants=].
1. [=Commit private aggregation contributions=] given |paContributions|, |id| and
|reportingContext|.
1. [=list/For each=] |generatedBid| of |generatedBids|:
@@ -4061,6 +4136,16 @@ A signal base value is one of the following:
Note: this mapping to an integer is defined in [=determine a signal's
numeric value=].
+: "
average-code-fetch-time
"
+:: The numeric value is the average time it took to fetch code resources (JavaScript or WebAssembly)
+ for this particular worklet function, for this participant.
+: "
participating-ig-count
"
+:: The numeric value is the number of interest groups for the buyer actually participating in the
+ auction, after considering prioritization and capabilities.
+: "
percent-scripts-timeout
"
+:: The numeric value is percentage of executions of this script that hit their individual timeout,
+ out of all executions that were expected to happen.
+
On event contribution entry
@@ -4074,6 +4159,10 @@ An on event contribution entry is a [=struct=] with the following items:
:: A [=debug scope=]
:
debug details
:: A [=debug details=] or null (default null)
+:
worklet function
+:: A [=worklet function=].
+:
origin
+:: The [=origin=] of the script that contributed the entry.
@@ -4091,6 +4180,74 @@ A worklet function is one of the following:
+
+To
find corresponding bid and score phase function given a [=worklet function=] |fn|:
+
+ 1.Switch on on |fn|:
+
+ : [=worklet function/generate-bid=]
+ :: Return [=worklet function/generate-bid=].
+ : [=worklet function/score-ad=]
+ :: Return [=worklet function/score-ad=].
+ : [=worklet function/report-result=]
+ :: Return [=worklet function/score-ad=].
+ : [=worklet function/report-win=]
+ :: Return [=worklet function/generate-bid=].
+
+
+
+
+### Averager ### {#private-aggregation-averager}
+An
averager is a a [=struct=] with the following [=struct/items=]:
+
+ : count
+ :: A {{long}}, initially 0.
+ : sum
+ :: A {{double}}, initially 0.
+
+
+
+To add a sample to an averager given an [=averager=] |averager|, a {{double}} |sample|:
+1. Set |averager|'s [=averager/count=] to |averager|'s [=averager/count=] + 1.
+1. Set |averager|'s [=averager/sum=] to |averager|'s [=averager/sum=] + |sample|.
+
+
+
+
+To merge samples to an averager given [=averagers=] |dest| and |source|:
+1. Set |dest|'s [=averager/count=] to |dest|'s [=averager/count=] + |source|'s [averager/count=].
+1. Set |dest|'s [=averager/sum=] to |dest|'s [=averager/sum=] + |source|'s [averager/sum=].
+
+
+
+
+To get the value to report from an averager given an [=averager=] |averager|:
+1. If |averager|'s [=averager/count=] = 0, return 0.
+1. Return |averager|'s [=averager/sum=] / [=averager/count=].
+
+
+
+### Metrics structures ### {#private-aggregation-metrics-structures}
+An
execution metrics is a [=struct=] with the following [=struct/items=]:
+
+ : average code fetch time
+ :: An [=averager=].
+ : script timeout occurred
+ :: A [=boolean=], initially false.
+
+
+A
per participant metrics is a [=struct=] with the following [=struct/items=]:
+
+ : participating interest group count
+ :: A {{long}}, initially 0.
+ : average code fetch time
+ :: An [=averager=].
+ : script timeouts occurred
+ :: A {{long}}, initially 0.
+ : script executions attempted
+ :: A {{long}}, initially 0.
+
+
Private Aggregation contributions
Private Aggregation contributions is a [=map=] from [=string=] to a [=list=] of [=on event
contribution entries=].
@@ -4099,9 +4256,11 @@ contribution entries=].
To
prepare for private aggregation given a
-{{InterestGroupScriptRunnerGlobalScope}} |global|, a [=reporting context=] |reportingContext|,
-and [=origins=] |origin| and |aggregationCoordinator|:
+{{InterestGroupScriptRunnerGlobalScope}} |global|, a [=worklet function=] |workletFunction|,
+a [=reporting context=] |reportingContext|, and [=origins=] |origin| and |aggregationCoordinator|:
1. Let |debugScope| be a new [=debug scope=].
+1. Set |global|'s [=InterestGroupScriptRunnerGlobalScope/worklet function=] to |workletFunction|.
+1. Set |global|'s [=InterestGroupScriptRunnerGlobalScope/origin=] to |origin|.
1. Set |global|'s [=InterestGroupScriptRunnerGlobalScope/private aggregation=] to a new
[=PrivateAggregation=] with the following [=struct/items=]:
:
allowed to use
@@ -4191,14 +4350,26 @@ an [=auction config=] |auctionConfig| and a [=reporting context=] |reportingCont
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. Let |bidderOnceRep| be null.
+1. If |reportingContext|'s [=reporting context/bidder participants=] [=set/is not empty=],
+ set |bidderOnceRep| to a random [=set/item=] of [=reporting context/bidder participants=].
+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. [=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/
+ generate-bid=]:
+ 1. If |bidId| ≠ |bidderOnceRep|, [=iteration/continue=].
+ 1. Otherwise:
+ 1. If |bidId| ≠ |sellerOnceRep|, [=iteration/continue=].
1. Let |filledInContribution| be the result of [=filling in the contribution=] given
- |onEventEntry|'s [=on event contribution entry/contribution=] and |leadingBidInfo|.
+ |reportingContext|, |onEventEntry| and |leadingBidInfo|.
Issue: Once
WICG/turtledove#627
is resolved, align 'filling in' logic with `forDebuggingOnly`.
@@ -4310,15 +4481,18 @@ an [=auction config=] |auctionConfig| and a [=reporting context=] |reportingCont
-To fill in the contribution given a {{PAExtendedHistogramContribution}} |contribution|
-and a [=leading bid info=] |leadingBidInfo|, perform the following steps. They return a
-{{PAHistogramContribution}}:
+To fill in the contribution given a [=reporting context=] |reportingContext|,
+an [=on event contribution entry=] |onEventEntry| and a [=leading bid info=] |leadingBidInfo|,
+perform the following steps. They return a {{PAHistogramContribution}}:
+1. Let |contribution| be |onEventEntry|'s [=on event contribution entry/contribution=].
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|.
+ in the signal value=] given |reportingContext|, |onEventEntry|, |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|.
+ the signal value=] given |reportingContext|, |onEventEntry|, |value|, 231−1 and
+ |leadingBidInfo|.
1. Let |filledInContribution| be a new {{PAHistogramContribution}} with the
items:
: {{PAHistogramContribution/bucket}}
@@ -4332,13 +4506,15 @@ and a [=leading bid info=] |leadingBidInfo|, perform the following steps. They r
-To
fill in the signal value given a {{PASignalValue}} |value|, an
+To
fill in the signal value given a [=reporting context=] |reportingContext|,
+an [=on event contribution entry=] |onEventEntry|, 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|.
+ given |reportingContext|, |onEventEntry|, |value|["{{PASignalValue/baseValue}}"] and
+ |leadingBidInfo|.
1. If |value|["{{PASignalValue/scale}}"] [=map/exists=], set |returnValue| to
the result of multiplying |value|["{{PASignalValue/scale}}"] with
|returnValue|.
@@ -4353,9 +4529,17 @@ They return an integer.
-To determine a signal's numeric value given a [=signal base value=]
+To determine a signal's numeric value given a [=reporting context=] |reportingContext|,
+an [=on event contribution entry=] |onEventEntry|, a [=signal base value=]
|signalBaseValue| and a [=leading bid info=] |leadingBidInfo|, perform the following steps.
They return a {{double}}.
+1. Let |metrics| be the result of [=access per-participant metrics=] given |reportingContext|,
+ |onEventEntry|'s [=on event contribution entry/origin=], [=on event contribution entry/
+ worklet function=].
+1. Let |bidAndScoreMetrics| be the result of [=access per-participant metrics=] given
+ |reportingContext|, |onEventEntry|'s [=on event contribution entry/origin=], and the result of
+ [=find corresponding bid and score phase function=] given [=on event contribution entry/worklet
+ function=].
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=].
@@ -4418,6 +4602,25 @@ They return a {{double}}.
Issue: Verify handling when the bid was not rejected.
+1. If |signalBaseValue| is "[=signal base value/average-code-fetch-time=]
":
+ 1. Return the result of [=getting the value to report from an averager=] given |metrics|'s [=per
+ participant metrics/average code fetch time=].
+1. If |signalBaseValue| is "[=signal base value/participating-ig-count=]
":
+ 1. Return |bidAndScoreMetrics|'s [=per participant metrics/participating interest group count=].
+1. If |signalBaseValue| is "[=signal base value/percent-scripts-timeout=]
":
+ 1. Return the result of [=computing a percentage metric=] given |metrics|'s [=per participant
+ metrics/script timeouts occurred=] and |metrics|'s [=per participant metrics/script executions
+ attempted=].
+
+
+
+
+To compute a percentage metric given {{long}}s |numerator| and |denominator|:
+1. If |denominator| is 0, return 0.
+1. Let |result| be 100.0 * |numerator| / |denominator|, performing the computation with
+ {{double}}s.
+1. If |result| > 110.0, set |result| to 110.0
+1. Return |result|.
@@ -5298,6 +5501,7 @@ of the following global objects:
To evaluate a bidding script given a [=string=] |script|, an {{unsigned short}}
|multiBidLimit|, an [=interest group=] |ig|, a [=reporting context=] |reportingContext|,
+ an [=execution metrics=] |executionMetrics|,
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
@@ -5318,8 +5522,9 @@ 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. [=Prepare for private aggregation=] given |global|, [=worklet function/generate-bid=],
+ |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
@@ -5340,7 +5545,8 @@ of the following global objects:
1. Let |crossOriginTrustedBiddingSignalsJS| be |crossOriginTrustedBiddingSignals|
[=converted to ECMAScript values=].
1. Let |startTime| be |settings|'s [=environment settings object/current monotonic time=].
- 1. Let |result| be the result of [=evaluating a script=] with |realm|, |script|, "`generateBid`",
+ 1. Let (|result|, |executionMetrics|'s [=execution metrics/script timeout occurred=]) be the
+ result of [=evaluating a script=] with |realm|, |script|, "`generateBid`",
« |igJS|, |auctionSignalsJS|, |perBuyerSignalsJS|, |sameOriginTrustedBiddingSignalsJS|,
|browserSignalsJS|, |directFromSellerSignalsJS|, |crossOriginTrustedBiddingSignalsJS| »,
and |timeout|.
@@ -5395,7 +5601,7 @@ of the following global objects:
1. Let |paContributions| be the result of [=extracting private aggregation contributions=] given
|global|.
1. Return a [=tuple=] (|generatedBids|, |bidDebugReportInfo|, |realTimeContributions|,
- |paContributions|).
+ |paContributions|, |executionMetrics|).
@@ -5410,9 +5616,9 @@ of the following global objects:
{{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. [=Prepare for private aggregation=] given |global|, [=worklet function/score-ad=],
+ |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 |auctionConfig|'s [=auction config/config idl=] [=converted to
ECMAScript values=].
@@ -5423,7 +5629,9 @@ of the following global objects:
1. Let |directFromSellerSignalsJs| be |directFromSellerSignalsForSeller|
[=converted to ECMAScript values=].
1. Let |startTime| be |settings|'s [=environment settings object/current monotonic time=].
- 1. Let |scoreAdResult| be the result of [=evaluating a script=] with |realm|, |script|, "`scoreAd`",
+ 1. Let |executionMetrics| be a new [=execution metrics=].
+ 1. Let (|scoreAdResult|, |executionMetrics|'s [=execution metrics/script timeout occurred=]) be
+ the result of [=evaluating a script=] with |realm|, |script|, "`scoreAd`",
«|adMetadata|, |bidValue|, |auctionConfigJS|, |sameOriginTrustedScoringSignalsJS|,
|browserSignalsJS|, |directFromSellerSignalsJs|, |crossOriginTrustedScoringSignalsJS|»,
and |timeout|.
@@ -5445,25 +5653,29 @@ of the following global objects:
1. Let |paContributions| be the result of [=extracting private aggregation contributions=] given
|global|.
1. Return « |scoreAdResult|, |debugWinReportUrl|, |debugLossReportUrl|, |realTimeContributions|,
- |paContributions| ».
+ |paContributions|, |executionMetrics| ».
- To evaluate a reporting script given a [=string=] |script|, a [=string=]
- |functionName|, a [=reporting context=] |reportingContext|, an [=origin=] |origin|, an
- [=origin=] |privateAggregationCoordinator|, an integer millisecond [=duration=] |timeout|,
- and a [=list=] of arguments |arguments|:
+ To evaluate a reporting script given a [=string=] |script|, a [=worklet function=]
+ |function|, 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 |functionName| be `"reportWin"`.
+ 1. If |function| is [=worklet function/report-result=], set |functionName| to `"reportResult"`.
+ 1. [=Prepare for private aggregation=] given |global|, |function|, |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 ».
- 1. Let |result| be the result of [=evaluating a script=] with |realm|, |script|,
- |functionName|, |argumentsJS|, and |timeout|.
+ 1. Let |executionMetrics| be a new [=execution metrics=].
+ 1. Let (|result|, |executionMetrics|'s [=execution metrics/script timeout occurred=]) be the
+ result of [=evaluating a script=] with |realm|, |script|, |functionName|, |argumentsJS|,
+ and |timeout|.
1. If |result| is an [=ECMAScript/abrupt completion=], return « "null", null, null, null ».
1. Let |resultJSON| be "null".
1. If |functionName| is "`reportResult`", then set |resultJSON| to the result of
@@ -5480,20 +5692,23 @@ of the following global objects:
|global|.
1. Return « |resultJSON|, |reportURL|,
|global|'s [=InterestGroupReportingScriptRunnerGlobalScope/reporting beacon map=], |macroMap|,
- |paContributions| ».
+ |paContributions|, |executionMetrics| ».
To evaluate a script with a [=ECMAScript/realm=] |realm|, [=string=] |script|, [=string=]
|functionName|, a [=list=] |arguments|, and an integer millisecond [=duration=] |timeout|, run these steps.
- They return a [=ECMAScript/Completion Record=], which is either an [=ECMAScript/abrupt completion=] (in
- the case of a parse failure or execution error), or a [=ECMAScript/normal completion=] populated with the
- [=ECMAScript/ECMAScript language value=] result of invoking |functionName|.
+ They return a tuple of a [=ECMAScript/Completion Record=], which is either an [=ECMAScript/abrupt
+ completion=] (in the case of a parse failure or execution error), or a [=ECMAScript/normal
+ completion=] populated with the [=ECMAScript/ECMAScript language value=] result of invoking
+ |functionName|, and a [=boolean=] stating whether the script was interrupted due to reaching
+ |timeout|.
1. [=Assert=] that these steps are running [=in parallel=].
- 1. If |timeout| ≤ 0, [=immediately=] interrupt the execution and set |finalCompletion| to a
- new [=ECMAScript/throw completion=] given null.
+ 1. If |timeout| ≤ 0, return (new [=ECMAScript/throw completion=] given null, true).
+
+ 1. Let |timeoutOccurred| be false.
1. Let |global| be |realm|'s [=realm/global object=], and run these steps in |realm|'s [=realm/agent=]:
@@ -5524,8 +5739,8 @@ of the following global objects:
|arguments|)).
In |timeout| milliseconds, if the invocation of [$Call$] has not completed,
- [=immediately=] interrupt the execution and set |finalCompletion| to a new
- [=ECMAScript/throw completion=] given null.
+ [=immediately=] interrupt the execution, set |finalCompletion| to a new
+ [=ECMAScript/throw completion=] given null, and set |timeoutOccurred| to true.
1. Return: at this point |finalCompletion| will be set to a
[=ECMAScript/Completion Record=].
@@ -5534,7 +5749,7 @@ of the following global objects:
execution context|running JavaScript execution context=], and remove it from the
[=ECMAScript/execution context stack|JavaScript execution context stack=].
- 1. Return |finalCompletion|.
+ 1. Return (|finalCompletion|, timeoutOccurred).
## Global scopes ## {#global-scopes}
@@ -5576,6 +5791,12 @@ Each {{InterestGroupScriptRunnerGlobalScope}} has a
:: Null, or a [=PrivateAggregation=]. Initially null.
:
on event contribution map
:: A [=map=] from [=string=] to a [=list=] of [=on event contribution entries=].
+ :
worklet function
+ :: A [=worklet function=]. Affects some
+ [Private Aggregation API](https://github.com/patcg-individual-drafts/private-aggregation-api)
+ functionality.
+ :
origin
+ :: The [=origin=] of the script being executed.
@@ -5589,16 +5810,21 @@ The
privateAggregation
The
contributeToHistogramOnEvent(DOMString
event, PAExtendedHistogramContribution contribution) method steps are:
+1. Let |global| be [=this=]'s [=relevant global object=].
+1. Let |function| be |global|'s [=InterestGroupScriptRunnerGlobalScope/worklet function=].
+1. Let |origin| be |global|'s [=InterestGroupScriptRunnerGlobalScope/origin=].
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|,
+ "`reserved.loss`", "`reserved.win`", "`reserved.once`" » does not [=list/contain=] |event|,
return.
Note: No error is thrown to allow forward compatibility if additional
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. Let |bucket| be |contribution|["{{PAExtendedHistogramContribution/bucket}}"].
1. If |bucket| is a {{PASignalValue}}:
1. If |bucket|["{{PASignalValue/baseValue}}"] is not a valid [=signal base
@@ -5644,8 +5870,10 @@ event, PAExtendedHistogramContribution contribution) method steps are:
: [=on event contribution entry/debug scope=]
:: The result of running |scopingDetails|'
get debug scope steps.
-
-1. Let |global| be [=this=]'s [=relevant global object=].
+ : [=on event contribution entry/worklet function=]
+ :: |function|
+ : [=on event contribution entry/origin=]
+ :: |origin|
1. Let |onEventContributionMap| be |global|'s
[=InterestGroupScriptRunnerGlobalScope/on event contribution map=].
1. If |onEventContributionMap|[|event|] does not [=map/exist=], set
@@ -7819,6 +8047,8 @@ headers. It's a [=struct=] with the following [=struct/items=]:
:
origins authorized for cross origin trusted signals
:: A [=list=] of [=origins=] or null. Initially null. Parsed value of
[:Ad-Auction-Allow-Trusted-Scoring-Signals-From:].
+ :
fetch duration
+ :: A [=duration=] in milliseconds, denoting how long it took the fetch to complete.
@@ -7896,6 +8126,8 @@ a [=script fetcher=] |fetcher|:
Issue: Stop using "`no-cors`" mode where possible
(
WICG/turtledove#667).
+
+ 1. Let |fetchStart| be |settings|'s [=environment settings object/current monotonic time=].
1. Let |fetchController| be the result of [=fetching=] |request| with [=fetch/useParallelQueue=]
set to true, and [=fetch/processResponse=] set to the following steps given
a [=response=] |response|:
@@ -7903,6 +8135,8 @@ a [=script fetcher=] |fetcher|:
1. [=fetch controller/Abort=] |fetchController|.
1. Set |fetcher|'s [=script fetcher/origins authorized for cross origin trusted signals=] to
an empty [=list=] of [=origins=].
+ 1. Set |fetcher|'s [=script fetcher/fetch duration=] to the [=duration from=] |fetchStart| to
+ |settings|'s [=environment settings object/current monotonic time=], in milliseconds.
1. Set |fetcher|'s [=script fetcher/script body=] to failure.
1. Set |fetcher|'s [=script fetcher/origins authorized for cross origin trusted signals=] to the
result of [=parsing allowed trusted scoring signals origins=] given |response|'s [=response/
@@ -7911,6 +8145,8 @@ a [=script fetcher=] |fetcher|:
1. Let |bodyReader| be result of [=ReadableStream/getting a reader=] from |bodyStream|.
1. Let |successSteps| be a set of steps that take a [=byte sequence=] |responseBody|, and
perform the following:
+ 1. Set |fetcher|'s [=script fetcher/fetch duration=] to the [=duration from=] |fetchStart| to
+ |settings|'s [=environment settings object/current monotonic time=], in milliseconds.
1. If [=validate fetching response mime and body=] with |response|, |responseBody| and
"`text/javascript`" returns false, set |fetcher|'s [=script fetcher/script body=] to
failure.