From 1a537b68a731118b558a2abcc2ab3f8644b10e0f Mon Sep 17 00:00:00 2001 From: caraitto Date: Fri, 13 Oct 2023 11:12:13 -0400 Subject: [PATCH 1/4] [Spec] Add directFromSellerSignals (#771) * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs * Update spec.bs --- spec.bs | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) diff --git a/spec.bs b/spec.bs index 35b51ef42..d58c2bd0d 100644 --- a/spec.bs +++ b/spec.bs @@ -20,6 +20,10 @@ Assume Explicit For: yes
+urlPrefix: https://fetch.spec.whatwg.org/; spec: Fetch
+  type: dfn
+    text: HTTP-network-or-cache fetch; url: #concept-http-network-or-cache-fetch
+    text: task destination; for: fetch params; url: fetch-params-task-destination
 urlPrefix: https://www.ietf.org/rfc/rfc4122.txt
   type: dfn; text: urn uuid
 urlPrefix: https://github.com/WICG/turtledove/blob/main/FLEDGE_k_anonymity_server.md
@@ -42,6 +46,7 @@ spec: RFC8941; urlPrefix: https://httpwg.org/specs/rfc8941.html
     for: structured header
       text: boolean; url: boolean
       text: integer; url: integer
+      text: boolean; url: boolean
 spec: WebAssembly; urlPrefix: https://webassembly.github.io/spec/core/
   type: dfn
     urlPrefix: appendix/embedding.html
@@ -519,6 +524,8 @@ bid in the auction for the chance to display their advertisement.
 
 

runAdAuction()

+TODO: Promise wiring, pass results to worklets. This is being done in +https://github.com/WICG/turtledove/pull/774. [SecureContext] partial interface Navigator { @@ -533,6 +540,7 @@ dictionary AuctionAdConfig { Promise<any> auctionSignals; Promise<any> sellerSignals; Promise<USVString> directFromSellerSignals; + Promise<DOMString> directFromSellerSignalsHeaderAdSlot; unsigned long long sellerTimeout; unsigned short sellerExperimentGroupId; USVString sellerCurrency; @@ -2932,6 +2940,202 @@ This specification defines two [=policy-controlled features=] identified by the Issue(WICG/turtledove#522): Move from "`*`" to "`self`". +# Handling Direct from Seller Signals # {#handling-direct-from-seller-signals} + +This section specifies a manner by which signals may be provided to auctions such that the signals +are only used within their intended auction. + +Any {{Document}} in a [=traversable navigable=] may run a Protected Audience auction (with +{{Window/navigator}}.{{Navigator/runAdAuction()}}) whose worklet functions receive signal objects +derived from JSON from an [:Ad-Auction-Signals:] header captured by a +{{WindowOrWorkerGlobalScope/fetch()}} call (using the {{RequestInit/adAuctionHeaders}} option) +initiated by any *other* {{Document}} in the *same* [=traversable navigable=]. + +<div algorithm="fetch capture adAuctionHeaders boolean patch"> +Modify the definition of a [=request=]: + +A [=request=] has an associated boolean <dfn for=request>capture-ad-auction-headers</dfn>. +Unless stated otherwise it is false. +</div> + +<div algorithm="fetch capture adAuctionHeaders RequestInit patch"> +Modify [[FETCH]]'s {{RequestInit}} dictionary to add an adAuctionHeaders attribute: + +<pre class=idl> +partial dictionary RequestInit { + boolean adAuctionHeaders; +}; +</pre> +</div> + +<div algorithm="fetch new request patch"> +The following step will be added to the <code><a constructor for="Request" lt="Request()"> +new Request (<var ignore>input</var>, <var ignore>init</var>)</a></code> constructor steps, before +step "Set [=this=]'s [=Request/request=] to |request|": + +1. If <var ignore>init</var>["{{RequestInit/adAuctionHeaders}}"] [=map/exists=], then set + |request|'s [=request/capture-ad-auction-headers=] to it. + +</div> + +<div algorithm="fetch Sec-Ad-Auction-Fetch patch"> +The following step will be added to the [=HTTP-network-or-cache fetch=] algorithm, before step +"Modify |httpRequest|'s [=request/header list=] per HTTP. ...": + +1. If [=request=]'s [=request/capture-ad-auction-headers=] is true, then [=header list/set a + structured field value=] given «[:Sec-Ad-Auction-Fetch:], the [=structured header/boolean=] `?1`» + in |httpRequest|'s [=header list=]. + +</div> + +<div algorithm="fetch per traversable navigable structures patch"> +Modify [[FETCH]]'s [[FETCH#infrastructure]] to add a new section called "Per Traversable Navigable +Structures", with the following content: + +<h3 id=direct-from-sellers-signals-key-struct>Direct from seller signals key</h3> +A <dfn>direct from seller signals key</dfn> is a [=struct=] with the following [=struct/items=]: + +NOTE: This is only captured during a [=request=] whose [=request/initiator type=] is `"fetch"`, made +with the {{RequestInit/adAuctionHeaders}} option set to `true`, as described in the +[:Ad-Auction-Signals:] header description. + +<dl dfn-for="direct from seller signals key"> +: <dfn>seller</dfn> +:: An [=origin=]. Matches the origin that served the captured [:Ad-Auction-Signals:] header. +: <dfn>ad slot</dfn> +:: A [=string=]. Matches the `adSlot` key of the JSON dictionaries in the top-level array of the + [:Ad-Auction-Signals:] value. + +</dl> + +<h3 id=direct-from-sellers-signals-struct>Direct from seller signals</h3> +A <dfn>direct from seller signals</dfn> is a [=struct=] with the following [=struct/items=]: + +NOTE: This is only captured during a [=request=] whose [=request/initiator type=] is `"fetch"`, made +with the {{RequestInit/adAuctionHeaders}} option set to `true`, as described in the +[:Ad-Auction-Signals:] header description. + +<dl dfn-for="direct from seller signals"> +: <dfn>auction signals</dfn> +:: Null or a [=string=]. + Opaque JSON data passed to both buyers' and the seller's [=script runners=]. +: <dfn>seller signals</dfn> +:: Null or a [=string=]. + Opaque JSON data passed to the seller's [=script runner=]. +: <dfn>per buyer signals</dfn> +:: A [=map=] whose [=map/keys=] are [=origins=] and whose [=map/values=] are [=strings=]. + [=map/Keys=] are buyers and must be valid HTTPS origins. [=map/Values=] are opaque JSON data + passed to corresponding buyer's [=script runner=]. + +</dl> + +Each [=traversable navigable=] has a <dfn for="traversable navigable">captured ad auction headers +</dfn>, which is a [=map=] whose [=map/keys=] are [=direct from seller signals keys=] and whose +[=map/values=] are [=direct from seller signals=]. +</div> + +<div algorithm="fetch auction headers patch"> +The following will be added to [[Fetch#http-extensions]]: + +<h3 id=sec-ad-auction-fetch-header>The \`<a http-header><code>Sec-Ad-Auction-Fetch</code></a>\` HTTP +request header</h3> + +The \`<dfn http-header><code>Sec-Ad-Auction-Fetch</code></dfn>\` request header is an optional +[=structured header=] with of type [=structured header/boolean=]. [:Sec-Ad-Auction-Fetch:] will only +be set on a [=request=] whose [=request/initiator type=] is `"fetch"`, made with the +{{RequestInit/adAuctionHeaders}} option set to `true`. If [:Sec-Ad-Auction-Fetch:] is equal to `?1`, +the user agent will remove any [:Ad-Auction-Signals:] from the returned [=response=] -- the +[:Ad-Auction-Signals:] value will instead only be used in Protected Audiences auctions. + +<h3 id=ad-auction-signals-header>The \`<a http-header><code>Ad-Auction-Signals</code></a>\` HTTP +response header</h3> + +The \`<dfn http-header><code>Ad-Auction-Signals</code></dfn>\` response header provides value +of a JSON array of dictionaries, each with an `adSlot` key. Protected Audience non-component, +component, and top-level auctions may specify which signals to load by the `adSlot` key. +</div> + +<div algorithm="fetch auction signals redirect patch"> +The following step will be added to the [=HTTP fetch=] algorithm, immediately under the step "If +<var ignore>internalResponse</var>’s [=status=] is a [=redirect status=]:" + +1. [=header list/Delete=] "[:Ad-Auction-Signals:]" from <var ignore>response</var>'s + [=response/header list=]. + +</div> + +<div algorithm="fetch auction signals response patch"> +The following step will be added to the [=HTTP fetch=] algorithm, before step +"Return |response|.": + +1. If |response| is not null, |response|'s [=status=] is not a [=redirect status=], |fetchParams|'s + [=fetch params/task destination=] is a [=global object=] that's a {{Window}} object, and + |request|'s [=request/capture-ad-auction-headers=] is `true`, then run [=update captured headers=] + with |fetchParams|'s [=fetch params/task destination=]'s [=associated Document's=] [=node + navigable's=] [=traversable navigable's=] [=traversable navigable/captured ad auction headers=], + |response|'s [=response/header list=], and |request|'s [=request/URL=]'s [=url/origin=]. + +</div> + +<div algorithm="fetch update captured headers patch"> +The following algorithm will be added to the [[FETCH#fetching]] section: + +<h3 id=update-captured-headers>Update captured headers</h3> + + To <dfn id=concept-update-captured-headers>update captured headers</dfn> with a [=traversable + navigable/captured ad auction headers=] |storedHeaders|, [=header list=] |responseHeaders|, and + [=origin=] |requestOrigin|: + 1. Let |adAuctionSignals| be the result of [=header list/getting=] [:Ad-Auction-Signals:] from + |responseHeaders|. + 1. If |adAuctionSignals| is null, return. + 1. [=header list/Delete=] "[:Ad-Auction-Signals:]" from |responseHeaders|. + + NOTE: This step prevents the header value from being used outside the intended auctions -- + that is, scripts making the {{WindowOrWorkerGlobalScope/fetch()}} request aren't able to load + the header value. + 1. Let |parsedSignals| be the result of [=parsing JSON bytes to an Infra value=], given + |adAuctionSignals|. + 1. If |parsedSignals| is failure, return. + 1. If |parsedSignals| is not a [=list=], return. + 1. [=list/For each=] |signal| in |parsedSignals|: + 1. If |signal| is not an [=ordered map=], [=iteration/continue=]. + 1. If |signal|["`adSlot`"] doesn't exist, [=iteration/continue=]. + 1. Create a new [=direct from seller signals key=] |signalsKey|, with its + [=direct from seller signals key/seller=] set to |requestOrigin| and its + [=direct from seller signals key/ad slot=] set to |signal|["`adSlot`"]. + 1. Create a new [=direct from seller signals=] |processedSignals|. + 1. [=map/Remove=] |signal|["`adSlot`"]. + 1. [=map/For each=] |key| → |value| of |signal|: + 1. Switch on |key|: + <dl class=switch> + <dt>"`sellerSignals`" + <dd> + 1. Set |processedSignals|'s [=direct from seller signals/seller signals=] to the result + of [=serializing an Infra value to a JSON string=], given |value|. + + <dt>"`auctionSignals`" + <dd> + 1. Set |processedSignals|'s [=direct from seller signals/auction signals=] to the result + of [=serializing an Infra value to a JSON string=], given |value|. + + <dt>"`perBuyerSignals`" + <dd> + 1. If |value| is not an [=ordered map=], [=iteration/continue=]. + 1. For each |buyer| → |buyerSignals| of |value|: + 1. Let |buyerOrigin| be the result of [=parsing an https origin=] on |buyer|. If this + [=exception/throws=], [=iteration/continue=]. + 1. Let |buyerSignalsString| be the result of + [=serializing an Infra value to a JSON string=], given |buyerSignals|. + 1. Set |processedSignals|'s + [=direct from seller signals/per buyer signals=][|buyerOrigin|] to |buyerSignalsString|. + + </dl> + + 1. Set |storedHeaders|[|signalsKey|] to |processedSignals|. + +</div> + + # Structures # {#structures} <xmp class="idl"> From ffc0e8dfd30eac6a6ddb7575d75cc5acdb0170fe Mon Sep 17 00:00:00 2001 From: qingxinwu <6334674+qingxinwu@users.noreply.github.com> Date: Fri, 13 Oct 2023 13:44:48 -0400 Subject: [PATCH 2/4] Handles header-based directFromSellerSignals. (#774) * Handle directFromSellerSignalsHeaderAdSlot * Handles header-based directFromSellerSignals. Resolves auction config's directFromSellerSignalsHeaderAdSlot promise. Passes directFromSellerSignals to worklets (generateBid(), scoreAd(), reportWin(), reportResult()). * Address comments, and pass signal to top level auction. * Small change. * Return failure if ad slot promise resolves failure. * Define IDLs for directFromSellerSignals and convert to JS. * Add or-undefined to direct seller signals parameter. * Cleanup * Address comments. * Some fix. * Address comments * Address Dom's comments. * Address Caleb's comments. * Address Caleb's comments * Parse signals json before passed to worklets. * Random commit to regenerate preview. * Address Dom's comments. * Address Dom's comments. * address nit * remove section redundant with 771 * fix name of captured headers * add link * fix link syntax --------- Co-authored-by: Qingxin Wu <qingxinwu@google.com> Co-authored-by: Paul Jensen <JensenPaul@users.noreply.github.com> --- spec.bs | 241 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 176 insertions(+), 65 deletions(-) diff --git a/spec.bs b/spec.bs index d58c2bd0d..045459405 100644 --- a/spec.bs +++ b/spec.bs @@ -539,7 +539,6 @@ dictionary AuctionAdConfig { sequence<USVString> interestGroupBuyers; Promise<any> auctionSignals; Promise<any> sellerSignals; - Promise<USVString> directFromSellerSignals; Promise<DOMString> directFromSellerSignalsHeaderAdSlot; unsigned long long sellerTimeout; unsigned short sellerExperimentGroupId; @@ -933,20 +932,23 @@ To <dfn>validate and convert auction ad config</dfn> given an {{AuctionAdConfig} * To parse the value |result|, set |auctionConfig|'s [=auction config/seller signals=] to the result of [=serializing a JavaScript value to a JSON string=], given |result|. * To handle an error, set |auctionConfig|'s [=auction config/seller signals=] to failure. -1. If |config|["{{AuctionAdConfig/directFromSellerSignals}}"] [=map/exists=]: - 1. TODO: The receiving end of this isn't specified yet, so there is no place to put the computed value. +1. If |config|["{{AuctionAdConfig/directFromSellerSignalsHeaderAdSlot}}"] [=map/exists=]: 1. [=Handle an input promise in configuration=] given |auctionConfig| and - |config|["{{AuctionAdConfig/directFromSellerSignals}}"]: + |config|["{{AuctionAdConfig/directFromSellerSignalsHeaderAdSlot}}"]: + + Note: The JavaScript code calling {{Navigator/runAdAuction()}} is responsible for resolving + |config|["{{AuctionAdConfig/directFromSellerSignalsHeaderAdSlot}}"] only when the {{Promise}} + returned from an associated {{WindowOrWorkerGlobalScope/fetch()}} that was made with the + `{adAuctionHeaders: true}` option resolves or rejects. Otherwise, there will be a race + condition that the worklet can run without the direct from seller signals that it needs. + See [handling direct from seller signals](#handling-direct-from-seller-signals) for details. + * To parse the value |result|: - 1. Let |directFromSellerSignalsPrefix| be the result of running the [=URL parser=] on |result|. - 1. [=exception/Throw=] a {{TypeError}} if any of the following conditions hold: - * |directFromSellerSignalsPrefix| is failure; - * |directFromSellerSignalsPrefix| is not [=same origin=] with |auctionConfig|'s - [=auction config/seller=]; - * |directFromSellerSignalsPrefix|'s [=url/query=] is not null. - 1. [=Assert=]: |directFromSellerSignalsPrefix|'s [=url/scheme=] is "`https`". + 1. Set |auctionConfig|'s [=auction config/direct from seller signals header ad slot=] to + |result|. * To handle an error: - 1. TODO: set the rep in |auctionConfig| to failure. + 1. Set |auctionConfig|'s [=auction config/direct from seller signals header ad slot=] to + failure. 1. If |config|["{{AuctionAdConfig/sellerTimeout}}"] [=map/exists=], set |auctionConfig|'s [=auction config/seller timeout=] to |config|["{{AuctionAdConfig/sellerTimeout}}"] in milliseconds or 500 milliseconds, whichever is smaller. @@ -1136,10 +1138,11 @@ To <dfn>build bid generators map</dfn> given an [=auction config=] |auctionConfi <div algorithm="generate a bid"> -To <dfn>generate a bid</dfn> given an [=ordered map=] |allTrustedBiddingSignals|, a -[=string=] |auctionSignals|, a {{BiddingBrowserSignals}} |browserSignals|, a [=string=] -|perBuyerSignals|, a [=duration=] |perBuyerTimeout| in milliseconds, a [=currency tag=] |expectedCurrency|, -an [=interest group=] |ig|, and a [=moment=] |auctionStartTime|: +To <dfn>generate a bid</dfn> given an [=ordered map=] |allTrustedBiddingSignals|, a [=string=] +|auctionSignals|, a {{BiddingBrowserSignals}} |browserSignals|, a [=string=]-or-null |perBuyerSignals|, +a {{DirectFromSellerSignalsForBuyer}} |directFromSellerSignalsForBuyer|, a [=duration=] +|perBuyerTimeout| in milliseconds, a [=currency tag=] |expectedCurrency|, an [=interest group=] |ig|, +and a [=moment=] |auctionStartTime|: 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 @@ -1175,7 +1178,7 @@ an [=interest group=] |ig|, and a [=moment=] |auctionStartTime|: |allTrustedBiddingSignals|[|key|]. 1. Return the result of [=evaluating a bidding script=] with |biddingScript|, |ig|, |expectedCurrency|, |igGenerateBid|, |auctionSignals|, |perBuyerSignals|, |trustedBiddingSignals|, |browserSignals|, - and |perBuyerTimeout|. + |directFromSellerSignalsForBuyer|, and |perBuyerTimeout|. </div> <div algorithm="generate and score bids"> @@ -1191,21 +1194,32 @@ To <dfn>generate and score bids</dfn> given an [=auction config=] |auctionConfig 1. Let |bidGenerators| be the result of running [=build bid generators map=] with |auctionConfig|. 1. Let |leadingBidInfo| be a new [=leading bid info=]. 1. Let |queue| be the result of [=starting a new parallel queue=]. +1. Let |capturedAuctionHeaders| be |global|'s [=associated Document's=] [=node navigable's=] + [=traversable navigable's=] [=traversable navigable/captured ad auction headers=]. 1. If |auctionConfig|'s [=auction config/component auctions=] are not [=list/is empty|empty=]: 1. [=Assert=] |topLevelAuctionConfig| is null. 1. Let |pendingComponentAuctions| be the [=list/size=] of |auctionConfig|'s [=auction config/component auctions=]. + 1. Let |topLevelDirectFromSellerSignalsForSeller| be null. + 1. Let |topLevelDirectFromSellerSignalsRetrieved| be false. 1. [=list/For each=] |component| in |auctionConfig|'s [=auction config/component auctions=], [=parallel queue/enqueue steps|enqueue the following steps=] to |queue|: 1. Let |compWinner| be the result of running [=generate and score bids=] with |component|, |auctionConfig|, |global|, and |settings|. 1. If |compWinner| is failure, return failure. - 1. If [=recursively wait until configuration input promises resolve=] given |auctionConfig| - returns failure, return failure. + 1. If [=recursively wait until configuration input promises resolve=] given |auctionConfig| returns + failure, return failure. + 1. If |topLevelDirectFromSellerSignalsRetrieved| is false: + 1. Let |topLevelDirectFromSellerSignals| be the result of running + [=get direct from seller signals=] given |auctionConfig|'s [=auction config/seller=], + |auctionConfig|'s [=auction config/direct from seller signals header ad slot=], and + |capturedAuctionHeaders|. + 1. Let |topLevelDirectFromSellerSignalsForSeller| be the result of running + [=get direct from seller signals for a seller=] given |topLevelDirectFromSellerSignals|. + 1. Set |topLevelDirectFromSellerSignalsRetrieved| to true. 1. If |compWinner| is not null, then run [=score and rank a bid=] with |auctionConfig|, |compWinner|, |leadingBidInfo|, |decisionLogicScript|, null, "top-level-auction", null, and |settings|'s [=environment/top-level origin=]. - 1. Decrement |pendingComponentAuctions| by 1. 1. Wait until |pendingComponentAuctions| is 0. 1. If |leadingBidInfo|'s [=leading bid info/leading bid=] is null, return null. @@ -1214,24 +1228,39 @@ To <dfn>generate and score bids</dfn> given an [=auction config=] |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| and |winningComponentConfig|. + running [=report result=] with |leadingBidInfo|, |topLevelDirectFromSellerSignalsForSeller| and + |winningComponentConfig|. 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 |auctionConfig|'s [=auction config/seller=]. 1. Set |leadingBidInfo|'s [=leading bid info/top level seller signals=] to |topLevelSellerSignals|. + 1. Let |directFromSellerSignals| be the result of running [=get direct from seller signals=] given + |winningComponentConfig|'s [=auction config/seller=], |winningComponentConfig|'s + [=auction config/direct from seller signals header ad slot=], and |capturedAuctionHeaders|. + 1. Let |directFromSellerSignalsForSeller| be the result of running + [=get direct from seller signals for a seller=] given |directFromSellerSignals|. + 1. Let |directFromSellerSignalsForBuyer| 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. Let « |sellerSignals|, |reportResultBrowserSignals| » be the result of running - [=report result=] with |leadingBidInfo| and null. - 1. Run [=report win=] with |leadingBidInfo|, |sellerSignals|, and |reportResultBrowserSignals|. + [=report result=] with |leadingBidInfo|, |directFromSellerSignalsForSeller|, and null. + 1. Run [=report win=] with |leadingBidInfo|, |sellerSignals|, |reportResultBrowserSignals|, and + |directFromSellerSignalsForBuyer|. 1. Return |leadingBidInfo|'s [=leading bid info/leading bid=]. 1. If [=waiting until configuration input promises resolve=] given |auctionConfig| returns failure, return failure. 1. Let |allBuyersExperimentGroupId| be |auctionConfig|'s [=auction config/all buyer experiment group id=]. -1. Let |allBuyersGroupLimit| be |auctionConfig|'s - [=auction config/all buyers group limit=]. +1. Let |allBuyersGroupLimit| be |auctionConfig|'s [=auction config/all buyers group limit=]. 1. Let |auctionSignals| be |auctionConfig|'s [=auction config/auction signals=]. +1. Let |directFromSellerSignals| be the result of running [=get direct from seller signals=] given + |auctionConfig|'s [=auction config/seller=], |auctionConfig|'s + [=auction config/direct from seller signals header ad slot=], and |capturedAuctionHeaders|. +1. Let |directFromSellerSignalsForSeller| be the result of running + [=get direct from seller signals for a seller=] given |directFromSellerSignals|. 1. Let |browserSignals| be a {{BiddingBrowserSignals}}. 1. Let |topLevelHost| be the result of running the <a spec=url>host serializer</a> on [=this=]'s [=relevant settings object=]'s [=environment/top-level origin=]'s [=origin/host=]. @@ -1296,9 +1325,13 @@ To <dfn>generate and score bids</dfn> given an [=auction config=] |auctionConfig 1. [=map/For each=] joiningOrigin → |groups| of |perSignalsUrlGenerator|: 1. [=list/For each=] |ig| of |groups|: 1. If |ig|'s [=interest group/bidding url=] is null, [=iteration/continue=]. + 1. Let |directFromSellerSignalsForBuyer| be the result of running + [=get direct from seller signals for a buyer=] with |directFromSellerSignals|, and + |ig|'s [=interest group/owner=]. 1. Let |generatedBid| be the result of [=generate a bid=] given |allTrustedBiddingSignals|, |auctionSignals|, a [=map/clone=] of |browserSignals|, - |perBuyerSignals|, |perBuyerTimeout|, |expectedCurrency|, |ig|, and |auctionStartTime|. + |perBuyerSignals|, |directFromSellerSignalsForBuyer|, |perBuyerTimeout|, |expectedCurrency|, + |ig|, and |auctionStartTime|. 1. If |generatedBid| is failure, [=iteration/continue=]. 1. If [=query generated bid k-anonymity count=] given |generatedBid| returns false: @@ -1328,23 +1361,28 @@ To <dfn>generate and score bids</dfn> given an [=auction config=] |auctionConfig [=interest group/ad components=]. 1. Set |generatedBid| to the result of [=generate a bid=] given |allTrustedBiddingSignals|, |auctionSignals|, a [=map/clone=] of |browserSignals|, - |perBuyerSignals|, |perBuyerTimeout|, |expectedCurrency|, and |ig|. + |perBuyerSignals|, |directFromSellerSignalsForBuyer|, |perBuyerTimeout|, |expectedCurrency|, + and |ig|. 1. Set |ig|'s [=interest group/ads=] to |originalAds|. 1. Set |ig|'s [=interest group/ad components=] to |originalAdComponents|. 1. If |generatedBid| is failure, [=iteration/continue=]. 1. [=list/Insert=] |generatedBid|'s [=generated bid/interest group=] in |bidIgs|. 1. [=Score and rank a bid=] with |auctionConfig|, |generatedBid|, |leadingBidInfo|, - |decisionLogicScript|, |dataVersion|, |auctionLevel|, |componentAuctionExpectedCurrency|, and |settings|'s - [=environment/top-level origin=]. - + |decisionLogicScript|, |directFromSellerSignalsForSeller|, |dataVersion|, |auctionLevel|, + |componentAuctionExpectedCurrency|, and |settings|'s [=environment/top-level origin=]. 1. Decrement |pendingBuyers| by 1. 1. Wait until |pendingBuyers| is 0. 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| and null. - 1. Run [=report win=] with |leadingBidInfo|, |sellerSignals|, and |reportResultBrowserSignals|. + [=report result=] with |leadingBidInfo|, |directFromSellerSignalsForSeller|, and null. + 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|, and + |directFromSellerSignalsForWinner|. 1. Return |leadingBidInfo|'s [=leading bid info/leading bid=]. </div> @@ -1412,9 +1450,10 @@ To <dfn>convert to an AuctionAd sequence</dfn> given a [=list=]-or-null |ads|: To <dfn>score and rank a bid</dfn> given an [=auction config=] |auctionConfig|, a [=generated bid=] |generatedBid|, a [=leading bid info=] |leadingBidInfo|, a [=string=] |decisionLogicScript|, a -{{unsigned long}}-or-null |biddingDataVersion|, an enum |auctionLevel|, which is -"single-level-auction", "top-level-auction", or "component-auction", a [=currency tag=] -|componentAuctionExpectedCurrency|, and an [=origin=] |topWindowOrigin|: +{{DirectFromSellerSignalsForSeller}} |directFromSellerSignalsForSeller|, an {{unsigned long}}-or-null +|biddingDataVersion|, an enum |auctionLevel|, which is "single-level-auction", "top-level-auction", +or "component-auction", a [=currency tag=] |componentAuctionExpectedCurrency|, and an [=origin=] +|topWindowOrigin|: 1. Let |renderURL| be [=URL serializer|serialized=] |generatedBid|'s [=generated bid/ad descriptor=]'s [=ad descriptor/url=]. @@ -1475,8 +1514,8 @@ To <dfn>score and rank a bid</dfn> given an [=auction config=] |auctionConfig|, </dl> 1. Let |scoreAdResult| be the result of [=evaluating a scoring script=] with |decisionLogicScript|, |adMetadata|, |bidValue|'s [=bid with currency/value=], |auctionConfig|'s - [=auction config/config idl=], |trustedScoringSignals|, |browserSignals|, and |auctionConfig|'s - [=auction config/seller timeout=]. + [=auction config/config idl=], |trustedScoringSignals|, |browserSignals|, + |directFromSellerSignalsForSeller|, and |auctionConfig|'s [=auction config/seller timeout=]. 1. Let |scoreAdOutput| be result of [=processing scoreAd output=] with |scoreAdResult|. 1. If |scoreAdOutput| is failure, return. 1. If |auctionLevel| is not "single-level-auction", and |scoreAdOutput| @@ -1847,8 +1886,55 @@ To <dfn>round a value</dfn> given a {{double}} |value|: </div> <div algorithm> -To <dfn>report result</dfn> given a [=leading bid info=] |leadingBidInfo| and [=auction config=] or -null |winningComponentConfig|: +To <dfn>get direct from seller signals</dfn> given an [=origin=] |seller|, a [=string=]-or-null +|adSlot|, and a [=map=] |capturedAuctionHeaders|: + + 1. If |adSlot| is not a [=string=], then return null. + 1. Let |directFromSellerSignals| be null. + 1. Let |directFromSellerSignalsKey| be a new [=direct from seller signals key=] with its + [=direct from seller signals key/seller=] set to |seller|, and + [=direct from seller signals key/ad slot=] set to |adSlot|. + 1. If |capturedAuctionHeaders|[|directFromSellerSignalsKey|] [=map/exists=]: + 1. Set |directFromSellerSignals| to |capturedAuctionHeaders|[|directFromSellerSignalsKey|]. + 1. Return |directFromSellerSignals|. +</div> + +<div algorithm> +To <dfn>get direct from seller signals for a seller</dfn> given a +[=direct from seller signals=]-or-null |directFromSellerSignals|: + + 1. Let |directFromSellerSignalsForSeller| be a new {{DirectFromSellerSignalsForSeller}}. + 1. If |directFromSellerSignals| is null, then return |directFromSellerSignalsForSeller|. + 1. [=map/Set=] |directFromSellerSignalsForSeller|["auctionSignals"] to the result of running + [=parse a JSON string to an Infra value=] given |directFromSellerSignals|'s + [=direct from seller signals/auction signals=]. + 1. [=map/Set=] |directFromSellerSignalsForSeller|["sellerSignals"] to the result of running + [=parse a JSON string to an Infra value=] given |directFromSellerSignals|'s + [=direct from seller signals/seller signals=]. + 1. Return |directFromSellerSignalsForSeller|. +</div> + +<div algorithm> +To <dfn>get direct from seller signals for a buyer</dfn> given a +[=direct from seller signals=]-or-null |directFromSellerSignals|, and an [=origin=] |owner|: + + 1. Let |directFromSellerSignalsForBuyer| be a new {{DirectFromSellerSignalsForBuyer}}. + 1. If |directFromSellerSignals| is null, then return |directFromSellerSignalsForBuyer|. + 1. [=map/Set=] |directFromSellerSignalsForBuyer|["auctionSignals"] to the result of running + [=parse a JSON string to an Infra value=] given |directFromSellerSignals|'s + [=direct from seller signals/auction signals=]. + 1. If |directFromSellerSignals|'s [=direct from seller signals/per buyer signals=][|owner|] + [=map/exists=]: + 1. [=map/Set=] |directFromSellerSignalsForBuyer|["perBuyerSignals"] to the result of running + [=parse a JSON string to an Infra value=] given |directFromSellerSignals|'s + [=direct from seller signals/per buyer signals=][|owner|]. + 1. Return |directFromSellerSignalsForBuyer|. +</div> + +<div algorithm> +To <dfn>report result</dfn> given a [=leading bid info=] |leadingBidInfo|, a +[=direct from seller signals=]-or-null |directFromSellerSignals|, and an [=auction config=]-or-null +|winningComponentConfig|: 1. Let |config| be |leadingBidInfo|'s [=leading bid info/auction config=]. 1. Let |bidCurrency| be null. 1. If |winningComponentConfig| is not null: @@ -1922,7 +2008,7 @@ null |winningComponentConfig|: [=auction config/decision logic url=]. 1. Let « |sellerSignals|, |reportUrl|, |reportingBeaconMap|, ignored » be the result of [=evaluating a reporting script=] with |sellerReportingScript|, "`reportResult`", and - « |config|'s [=auction config/config idl=], |browserSignals| ». + « |config|'s [=auction config/config idl=], |browserSignals|, |directFromSellerSignals| ». 1. Let |reportingResult| be a [=reporting result=] with the following [=struct/items=]: : [=reporting result/report url=] :: |reportUrl| @@ -1946,8 +2032,9 @@ null |winningComponentConfig|: </div> <div algorithm> -To <dfn>report win</dfn> given a [=leading bid info=] |leadingBidInfo|, a [=string=] |sellerSignals| -and a {{ReportingBrowserSignals}} |browserSignals|: +To <dfn>report win</dfn> given a [=leading bid info=] |leadingBidInfo|, a [=string=] |sellerSignals|, +a {{ReportingBrowserSignals}} |browserSignals|, and a [=direct from seller signals=]-or-null +|directFromSellerSignals|: 1. Let |config| be |leadingBidInfo|'s [=leading bid info/auction config=]. 1. Let |winner| be |leadingBidInfo|'s [=leading bid info/leading bid=]. @@ -1992,7 +2079,7 @@ and a {{ReportingBrowserSignals}} |browserSignals|: [=evaluating a reporting script=] with |buyerReportingScript|, "`reportWin`", and « |leadingBidInfo|'s [=leading bid info/auction config=]'s [=auction config/config idl=]'s {{AuctionAdConfig/auctionSignals}}, |perBuyerSignalsForBuyer|, |sellerSignals|, - |reportWinBrowserSignals| ». + |reportWinBrowserSignals|, |directFromSellerSignals| ». 1. Set |leadingBidInfo|'s [=leading bid info/buyer reporting result=] to a [=reporting result=] with the following [=struct/items=]: : [=reporting result/report url=] @@ -2247,8 +2334,9 @@ of the following global objects: <div algorithm> To <dfn>evaluate a bidding script</dfn> given a [=string=] |script|, an [=interest group=] |ig|, a [=currency tag=] |expectedCurrency|, a {{GenerateBidInterestGroup}} |igGenerateBid|, a [=string=]-or-null - |auctionSignals|, a [=string=]-or-null |perBuyerSignals|, an [=ordered map=] |trustedBiddingSignals|, a - {{BiddingBrowserSignals}} |browserSignals|, and an integer millisecond [=duration=] |timeout|: + |auctionSignals|, a [=string=]-or-null |perBuyerSignals|, an [=ordered map=] |trustedBiddingSignals|, + a {{BiddingBrowserSignals}} |browserSignals|, a {{DirectFromSellerSignalsForBuyer}} + |directFromSellerSignalsForBuyer| and an integer millisecond [=duration=] |timeout|: 1. Let |realm| be the result of [=creating a new script runner realm=] given {{InterestGroupBiddingScriptRunnerGlobalScope}}. @@ -2270,10 +2358,12 @@ of the following global objects: given |perBuyerSignals| if |perBuyerSignals| is not null, otherwise {{undefined}}. 1. Let |trustedBiddingSignalsJS| be |trustedBiddingSignals| [=converted to ECMAScript values=]. 1. Let |browserSignalsJS| be |browserSignals| [=converted to ECMAScript values=]. + 1. Let |directFromSellerSignalsJs| be |directFromSellerSignalsForBuyer| + [=converted to ECMAScript values=]. 1. Let |startTime| be the [=current wall time=]. 1. Let |result| be the result of [=evaluating a script=] with |realm|, |script|, "`generateBid`", - « |igJS|, |auctionSignalsJS|, |perBuyerSignalsJS|, |trustedBiddingSignalsJS|, |browserSignalsJS| », - and |timeout|. + « |igJS|, |auctionSignalsJS|, |perBuyerSignalsJS|, |trustedBiddingSignalsJS|, |browserSignalsJS|, + |directFromSellerSignalsJs| », and |timeout|. 1. Let |duration| be the [=current wall time=] minus |startTime| in milliseconds. 1. If |global|'s [=InterestGroupBiddingScriptRunnerGlobalScope/priority=] is not null and not failure: 1. Set |ig|'s [=interest group/priority=] to |global|'s @@ -2309,17 +2399,20 @@ of the following global objects: <div algorithm> To <dfn>evaluate a scoring script</dfn> given a [=string=] |script|, a [=string=] |adMetadata|, a {{double}} |bidValue|, an {{AuctionAdConfig}} |auctionConfigIDL|, an [=ordered map=] - |trustedScoringSignals|, a {{ScoringBrowserSignals}} |browserSignals|, and an integer millisecond - [=duration=] |timeout|: + |trustedScoringSignals|, a {{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 |browserSignalsJS| be |browserSignals| [=converted to ECMAScript values=]. 1. Let |auctionConfigJS| be |auctionConfigIDL| [=converted to ECMAScript values=]. 1. Let |trustedScoringSignalsJS| be |trustedScoringSignals| [=converted to ECMAScript values=]. + 1. Let |directFromSellerSignalsJs| be |directFromSellerSignalsForSeller| + [=converted to ECMAScript values=]. 1. Return the result of [=evaluating a script=] with |realm|, |script|, "`scoreAd`", - «|adMetadata|, |bidValue|, |auctionConfigJS|, |trustedScoringSignalsJS|, |browserSignalsJS|», - and |timeout|. + «|adMetadata|, |bidValue|, |auctionConfigJS|, |trustedScoringSignalsJS|, |browserSignalsJS|, + |directFromSellerSignalsJs|», and |timeout|. </div> <div algorithm> @@ -2331,10 +2424,10 @@ of the following global objects: 1. Let |global| be |realm|'s [=realm/global object=]. 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 ». + [=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 50 milliseconds. - 1. If |result| is an [=ECMAScript/abrupt completion=], return « "null", null, null ». + 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 [=serializing a JavaScript value to a JSON string=] given |result|. @@ -2730,7 +2823,7 @@ Each {{InterestGroupReportingScriptRunnerGlobalScope}} has a # Interest Group Updates # {#interest-group-updates} -[=Interest groups=] have a [=interest group/update url=] field that allows updating the +[=Interest groups=] have an [=interest group/update url=] field that allows updating the interest group definition stored on disk with information periodically retrieved from the [=interest group/update url=]. The [=interest group update=] steps are triggered during {{Navigator/runAdAuction()}} and by calls to {{Navigator/updateAdInterestGroups()}} API: @@ -3203,9 +3296,8 @@ dictionary ReportingBrowserSignals { <dd>[=round a value|Stochastically rounded=] winning bid. This is always in the bidder's own currency <dt>{{ReportingBrowserSignals/highestScoringOtherBid}} - <dd>The [=round a value|stochastically rounded value=] of the bid that got the second highest score, or 0 if it's - - not available. 0 for top-level auctions with components + <dd>The [=round a value|stochastically rounded value=] of the bid that got the second highest + score, or 0 if it's not available. 0 for top-level auctions with components <dt>{{ReportingBrowserSignals/bidCurrency}} <dd>The currency the {{ReportingBrowserSignals/bid}} is in <dt>{{ReportingBrowserSignals/highestScoringOtherBidCurrency}} @@ -3281,6 +3373,20 @@ dictionary ReportWinBrowserSignals : ReportingBrowserSignals { bidding signals server </dl> +<xmp class="idl"> +dictionary DirectFromSellerSignalsForBuyer { + any auctionSignals; + any perBuyerSignals; +}; + + + +dictionary DirectFromSellerSignalsForSeller { + any auctionSignals; + any sellerSignals; +}; + +

Interest group

An interest group is a [=struct=] with the following [=struct/items=]: @@ -3524,8 +3630,8 @@ An auction config is a [=struct=] with the following items: : pending promise count :: An integer, initially 0. The number of [=auction config/auction signals=], [=auction config/per buyer signals=], [=auction config/per buyer currencies=], - [=auction config/per buyer timeouts=], directFromSellerSignals, or [=auction config/seller signals=] - whose {{Promise}}s are not yet resolved. + [=auction config/per buyer timeouts=], [=auction config/direct from seller signals header ad slot=], + or [=auction config/seller signals=] whose {{Promise}}s are not yet resolved. : config idl :: {{AuctionAdConfig}}. : resolve to config @@ -3545,6 +3651,8 @@ An auction config is a [=struct=] with the following items: component auctions are expected to use if [=auction config/per buyer currencies=] does not specify a particular value. +: direct from seller signals header ad slot +:: Null, a [=string=], a {{Promise}}, or failure. Initially null. @@ -3552,17 +3660,20 @@ An auction config is a [=struct=] with the following items: To wait until configuration input promises resolve given an [=auction config=] |auctionConfig|: 1. Wait until |auctionConfig|'s [=auction config/pending promise count=] is 0. 1. [=Assert=] |auctionConfig|'s [=auction config/auction signals=], [=auction config/seller signals=], - [=auction config/per buyer signals=], [=auction config/per buyer currencies=], and - [=auction config/per buyer timeouts=] are not {{Promise}}s. + [=auction config/per buyer signals=], [=auction config/per buyer currencies=], + [=auction config/per buyer timeouts=], and [=auction config/direct from seller signals header ad slot=] + are not {{Promise}}s. 1. If |auctionConfig|'s [=auction config/auction signals=], [=auction config/seller signals=], - [=auction config/per buyer signals=], [=auction config/per buyer currencies=] or - [=auction config/per buyer timeouts=] is failure, return failure. -1. TODO: the above two steps should also check directFromSellerSignals once something handles it. + [=auction config/per buyer signals=], [=auction config/per buyer currencies=], + [=auction config/per buyer timeouts=], or [=auction config/direct from seller signals header ad slot=] + is failure, return failure. +1. Return.
-To recursively wait until configuration input promises resolve given an [=auction config=] |auctionConfig|: +To recursively wait until configuration input promises resolve given an [=auction config=] +|auctionConfig|: 1. [=list/For each=] |componentAuctionConfig| in |auctionConfig|'s [=auction config/component auctions=]: 1. If the result of [=waiting until configuration input promises resolve=] given |componentAuctionConfig| is failure, return failure. From 82cbe4e128fa94fac36533420eadc931b2e003f5 Mon Sep 17 00:00:00 2001 From: caraitto Date: Fri, 13 Oct 2023 16:41:02 -0400 Subject: [PATCH 3/4] Remove direct from seller TODO that's done (#860) --- spec.bs | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec.bs b/spec.bs index 045459405..68582b661 100644 --- a/spec.bs +++ b/spec.bs @@ -524,8 +524,6 @@ bid in the auction for the chance to display their advertisement.

runAdAuction()

-TODO: Promise wiring, pass results to worklets. This is being done in -https://github.com/WICG/turtledove/pull/774. [SecureContext] partial interface Navigator { From d68ea6e0de591130e7b5416387cbd81ae0853a08 Mon Sep 17 00:00:00 2001 From: caraitto <caraitto@chromium.org> Date: Fri, 13 Oct 2023 17:11:03 -0400 Subject: [PATCH 4/4] Set directFromSellerSignals dict members to null (#861) --- spec.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec.bs b/spec.bs index 68582b661..7f7bd34a8 100644 --- a/spec.bs +++ b/spec.bs @@ -3373,15 +3373,15 @@ dictionary ReportWinBrowserSignals : ReportingBrowserSignals { <xmp class="idl"> dictionary DirectFromSellerSignalsForBuyer { - any auctionSignals; - any perBuyerSignals; + any auctionSignals = null; + any perBuyerSignals = null; }; dictionary DirectFromSellerSignalsForSeller { - any auctionSignals; - any sellerSignals; + any auctionSignals = null; + any sellerSignals = null; };