Skip to content

Commit

Permalink
Merge branch 'main' into kvv2-explainer
Browse files Browse the repository at this point in the history
  • Loading branch information
JensenPaul authored Dec 19, 2024
2 parents 2dd6b03 + 6395988 commit c1b3e94
Show file tree
Hide file tree
Showing 10 changed files with 1,968 additions and 381 deletions.
103 changes: 47 additions & 56 deletions FLEDGE.md

Large diffs are not rendered by default.

26 changes: 14 additions & 12 deletions FLEDGE_browser_bidding_and_auction_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This document seeks to propose an API for web pages to perform Protected Audienc
To execute an on-server Protected Audience auction, sellers begin by calling `navigator.getInterestGroupAdAuctionData()` with returns a `Promise<AdAuctionData>`:

```javascript
const auctionBlob = navigator.getInterestGroupAdAuctionData({
const auctionBlob = await navigator.getInterestGroupAdAuctionData({
// ‘seller’ works the same as for runAdAuction.
'seller': 'https://www.example-ssp.com',
// 'coordinatorOrigin' of the TEE coordinator, defaults to
Expand All @@ -35,6 +35,8 @@ const auctionBlob = navigator.getInterestGroupAdAuctionData({
'https://buyer2.origin.example.com': {}
}
});
const request = auctionBlob.request;
const requestId = auctionBlob.requestId;
```

The `seller` field will be checked to ensure it matches the `seller` specified
Expand All @@ -45,7 +47,7 @@ request. The `coordinatorOrigin` must be a coordinator that is known to Chrome
The `requestSize` and `perBuyerConfig` fields are described in more detail in
the [Request Size and Configuration](#request-size-and-configuration) section below.

The returned `auctionBlob` is a Promise that will resolve to an `AdAuctionData` object. This object contains `requestId` and `request` fields.
The `navigator.getInterestGroupAdAuctionData()` returns a Promise that will resolve to an `AdAuctionData` object, in this case `auctionBlob`. This object contains `requestId` and `request` fields.
The `requestId` contains a UUID that needs to be presented to `runAdAuction()` along with the response.
The `request` field is a `Uint8Array` containing the information needed for the [ProtectedAudienceInput](https://github.com/privacysandbox/fledge-docs/blob/main/bidding_auction_services_api.md#protectedaudienceinput) in a `SelectAd` B&A call,
encrypted using HPKE with an encryption header like that used in [OHTTP](https://www.ietf.org/archive/id/draft-thomson-http-oblivious-01.html).
Expand All @@ -60,12 +62,12 @@ The `seller` is required to have its [site](https://html.spec.whatwg.org/multipa

### Step 2: Send auction blob to servers

A seller’s JavaScript then sends auctionBlob to their server, perhaps by initiating a [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) using a PUT or POST method with auctionBlob attached as the request body:
A seller’s JavaScript then sends `request` to their server, perhaps by initiating a [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) using a PUT or POST method with `request` attached as the request body:

<pre>
fetch('https://www.example-ssp.com/auction', {
method: "PUT",
<b>body: auctionBlob</b>,
<b>body: request</b>,
})
</pre>
Expand All @@ -88,22 +90,22 @@ Response blobs can also be retrieved using an `iframe` navigation by specifying
For each response blob sent back to the browser, the seller’s server attaches a response header containing the base64url encoded (RFC 4648 section 5) SHA-256 hash of the response blob:

```
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0
```

Multiple hashes can be included in a response by either repeating the
header or by specifying multiple hashes separated by a `,` character. So
```
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=,9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0,9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k
```
is equivalent to
```
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=
Ad-Auction-Result: 9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0
Ad-Auction-Result: 9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k
```
and both versions should be accepted.

It should be noted that the `fetch()` request using `adAuctionHeaders` can also be used to send `auctionBlob` (e.g. in the request body) and receive the response blob (e.g. in the response body).
It should be noted that the `fetch()` request using `adAuctionHeaders` can also be used to send `request` (e.g. in the request body) and receive the response blob (e.g. in the response body).

### Step 4: Complete auction in browser

Expand Down Expand Up @@ -385,7 +387,7 @@ Then the request is zero padded to a set of pre-configured lengths (TBD).

### Example

The JSON equivalent of an example `auctionBlob` would look like this:
The JSON equivalent of an example `request` would look like this:

```json
{
Expand Down Expand Up @@ -428,8 +430,8 @@ The JSON equivalent of the interest group would look like the following example:

The response blob from a B&A auction contains an HPKE encrypted message containing the information from [AuctionResult](https://github.com/privacysandbox/bidding-auction-servers/blob/main/api/bidding_auction_servers.proto#L193).
This response has an encryption header like that
used in OHTTP and serves as the response for the encryption context started by the `auctionBlob` from `navigator.getInterestGroupAdAuctionData`.
The response contains a framing header like the request and contains a blob of compressed data, using the same schema version and same compression algorithm as specified in the `auctionBlob`.
used in OHTTP and serves as the response for the encryption context started by the `request` from `navigator.getInterestGroupAdAuctionData`.
The response contains a framing header like the request and contains a blob of compressed data, using the same schema version and same compression algorithm as specified in the `request`.
The response needs to be padded to a set of sizes to limit the amount of information leaking from the auction.

Prior to compression and encryption, the AuctionResult is encoded as CBOR with the following schema (specified using [JSON Schema](https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-01)):
Expand Down
95 changes: 95 additions & 0 deletions FLEDGE_extended_PA_reporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ Where `signalBucket` and `signalValue` is a dictionary which consists of:
* generateBid() hitting timeout
* The auction was aborted (i.e. calling endAdAuction())
* an auction that never rendered the ad
* Some additional values described [separately](#per-participant-base-values).
* optional `offset` and `scale` that allow the reporter to manipulate the browser signal to customize the buckets and values they will receive in reports:
* `scale` will be multiplied by the browser provided value. Scale is applied before `offset` is added. Default value is 1.0.
* `offset` will be added to the browser provided value (allows you to shift buckets, etc). Default value is 0.
Expand Down Expand Up @@ -255,6 +256,100 @@ The `reserved.always` event-type is a special value that indicates a report shou
matter whether a bid wins the auction or not. The browser will always trigger reporting for the
`always` contributions.

## Per-participant metrics

More recent versions of Chrome offer some additional features, focused on measuring resource
usage and whole-auction metrics rather than those specific to a particular function execution
or the winning bid.

First, the new `reserved.once` event-type is a special value that, for each (sub)auction, selects a
random invocation of `generateBid()` and of `scoreAd()` independently, and reports private
aggregation contributions with that event only from those invocations. (In case of an auction
with component auctions, the top-level auction will have a single `scoreAd()` invocation selected as
well).

The event may not be used in `reportWin()` or `reportResult()`; since those already run at most
once per auction level, `reserved.always` may be used instead.

This feature is intended for reporting overall per-participant metrics only once rather than for
every interest group participating. A number of new `baseValues` representing such values are
available and described below, but it can also be useful with per-interest-group metrics which are
not expected to vary much, like `signals-fetch-time`, to sample them once per (sub)auction.

While usage of `reserved.once` will be ignored by older versions, newly added `baseValues` will not
be, so the calls to `contributeToHistogramOnEvent()` should be individually wrapped in `try/catch`.
That is also encouraged in general since `contributeToHistogramOnEvent()` is specified to throw
on permission policy violations.

Users using this are strongly encouraged to report their metrics during the beginning of their
scripts, since if the script hits a per script timeout before asking to report them nothing will
get sent, which can result in inaccuracy, especially for `percent-scripts-timeout`.

### Per-participant base values.

The newly added base values, that work best with `reserved.once`, are as following:
* `participating-ig-count`: number of interest groups that got a chance to participate in this
(sub)auction, i.e. they had registered ads, did not have unsatisfied capabilities, and were not
filtered based on priority. Interest groups included in this might not actually get to bid if the
cumulative timeout expires, or the script fails to load, etc, but they would have otherwise.
* `average-code-fetch-time`: average time of all code fetches (including JavaScript and WASM) used
for all invocations of particular function type for given (sub)auction.
* `percent-scripts-timeout`: percentage of script executions of this kind that hit
`perBuyerTimeouts`, `sellerTimeout`, or `reportingTimeout`. For `generateBid()`, this is out of
of the interest groups that could have participated (see `participating-ig-count` above for
description of participation qualifications).
* `percent-igs-cumulative-timeout`: percentage of interest groups from this buyer that did not get
to participate in this (sub)auction due to the per-buyer cumulative timeout, out of the interest
groups that could have participated (see `participating-ig-count` above for description of
participation qualifications).
* `cumulative-buyer-time`: total time spent for buyer's bid generation (downloading resources,
parsing them, and all generate bid calls), in milliseconds; this is what
would normally be compared against the per-buyer cumulative timeout (which must be set for this
to be non-zero). If the timeout is not hit, the value will be how long the buyer actually took,
capped by the per-buyer cumulative timeout, if the timeout is hit, the reported value will be the
timeout + 1000 (to make it easier to assign it to a different bucket).
* `percent-regular-ig-count-quota-used`,`percent-negative-ig-count-quota-used`,
`percent-ig-storage-quota-used`: percentage of the database quota used by the buyer for
regular interest group count, negative targeting interest group count, and overall byte usage
respectively. This is capped at 110 since the quotas may not be enforced immediately (and actual
usage in that case may be bigger than 110%).
* `regular-igs-count`, `negative-igs-count`, `ig-storage-used`: the raw counts for the buyer's
number of regular interest group, negative targeting interest groups, and overall byte usage,
respectively. This is also capped at 1.1x the current quota, but please do keep in mind that the
quota might increase in the future, so if you use these metrics rather than percentage-based ones,
you may wish to reserve some extra margin around the bucket space (perhaps something like 15x) to
avoid confusion in the future. If you use `ig-storage-used` base value for a contribution value
rather than for a bucket number, the local contribution budget cap may become an issue unless
it's scaled down considerably.

Note that these metrics are measured only for some kinds of worklet executions &mdash; some are
only relevant for bidders, and get 0 in the seller functions. In case of reporting functions,
they sometimes repeat what was available in the corresponding `generateBid()` or `scoreAd()`,
and sometimes get their own measurement. This is shown below:

| `baseValue` name | In `generateBid() ` | In `reportWin()` | In `scoreAd()` | In `reportResult()` |
| ---------------- | ------------------- | ---------------- | -------------- | ------------------- |
| `average-code-fetch-time` | Measured | Measured | Measured | Measured |
| `percent-scripts-timeout` | Measured | Measured | Measured | Measured |
| `participating-ig-count` | Measured | From `generateBid()` | 0 | 0 |
| `percent-igs-cumulative-timeout` | Measured | From `generateBid()` | 0 | 0 |
| `cumulative-buyer-time` | Measured | From `generateBid()` | 0 | 0 |
| `percent-regular-ig-count-quota-used` | Measured | From `generateBid()` | 0 | 0 |
| `percent-negative-ig-count-quota-used` | Measured | From `generateBid()` | 0 | 0 |
| `percent-ig-storage-quota-used` | Measured | From `generateBid()` | 0 | 0 |
| `regular-igs-count` | Measured | From `generateBid()` | 0 | 0 |
| `negative-igs-count` | Measured | From `generateBid()` | 0 | 0 |
| `ig-storage-used` | Measured | From `generateBid()` | 0 | 0 |

For example, `percent-scripts-timeout` in `generateBid()` is the portion of executions of
`generateBid()` in that (sub)auction that timed out, while `percent-scripts-timeout` in
`reportWin()` is either 0 or 100 dependent on whether the reporting function's execution timed out
or not (assuming reporting is done early enough to happen if it did); while
`percent-igs-cumulative-timeout` will be the same value in both.

Similarly, `percent-scripts-timeout` makes sense for seller functions like `scoreAd()`, but
`percent-igs-cumulative-timeout` doesn't, so it just evaluates to 0.

## Reporting Per-Buyer Latency and Statistics to the Seller

The seller may want to collect aggregate statistics on latency and bids for their auctions.
Expand Down
4 changes: 2 additions & 2 deletions Fenced_Frames_Ads_Reporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ registerAdMacro(‘SOURCE_URL_ENC’, ‘http%3A%2F%2Fpub%2Eexample%2Fpage’);

### registerAdBeacon

The `reportResult` and `reportWin` worklet code will be able to register two new events, called `reserved.top_navigation_start` and `reserved.top_navigation_commit`, via `registerAdBeacon`.
The `reportResult` and `reportWin` worklet code will be able to register two new events, called `'reserved.top_navigation_start'` and `'reserved.top_navigation_commit'`, via `registerAdBeacon()`:

```
registerAdBeacon({
Expand All @@ -224,7 +224,7 @@ registerAdBeacon({
});
```

The new events, if registered, implies that an automatic beacon will be sent by the browser to the registered URL when a top-level navigation is invoked from within the fenced frame and the navigation was preceded by a call to [window.fence.setReportEventDataForAutomaticBeacons](#api-to-populate-event-data-for-reservedtop_navigation). More specifically, a `reserved.top_navigation_start` beacon will be sent when a top-level navigation [begins](https://html.spec.whatwg.org/multipage/browsing-the-web.html#beginning-navigation) and a `reserved.top_navigation_commit` beacon will be sent when the navigation successfully [completes](https://html.spec.whatwg.org/multipage/browsing-the-web.html#ending-navigation). This will impact top-level navigation initiated from the fenced frame in the same tab (via [unfencedTop target](https://github.com/WICG/fenced-frame/blob/master/explainer/integration_with_web_platform.md#top-level-navigation)) or in a different tab. Note that this beacon is gated on a transient user activation. More details about the beacon are below.
The new events, if registered, implies that an automatic beacon will be sent by the browser to the registered URL when a top-level navigation is invoked from within the fenced frame and the navigation was preceded by a call to [window.fence.setReportEventDataForAutomaticBeacons](#api-to-populate-event-data-for-reservedtop_navigation). These events are not triggered by the fenced frame's initial navigation and commit (e.g. when rendering the original ad), only subsequent ones (e.g. when triggered by a user clicking on the ad). More specifically, a `reserved.top_navigation_start` beacon will be sent when a top-level navigation [begins](https://html.spec.whatwg.org/multipage/browsing-the-web.html#beginning-navigation) and a `reserved.top_navigation_commit` beacon will be sent when the navigation successfully [completes](https://html.spec.whatwg.org/multipage/browsing-the-web.html#ending-navigation). This will impact top-level navigation initiated from the fenced frame in the same tab (via [unfencedTop target](https://github.com/WICG/fenced-frame/blob/master/explainer/integration_with_web_platform.md#top-level-navigation)) or in a different tab. Note that this beacon is gated on a transient user activation (e.g. a click). More details about the beacon are below.

### reportEvent

Expand Down
17 changes: 17 additions & 0 deletions PA_Feature_Detecting.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,23 @@ navigator.protectedAudience && navigator.protectedAudience.queryFeatureSupport(
"selectableReportingIds")
```

## Seller Nonce
[Intent to Ship](https://groups.google.com/a/chromium.org/g/blink-dev/c/jjFGRDm2Dr4)

From context of a web page:
```
navigator.protectedAudience && navigator.protectedAudience.queryFeatureSupport(
"sellerNonce")
```

## [Trusted Key-Value Server Support](https://chromestatus.com/feature/5072384013631488)

From context of a web page:
```
navigator.protectedAudience && navigator.protectedAudience.queryFeatureSupport(
"trustedSignalsKVv2")
```

## Getting browser-side detectable features as an object
Sometimes it's desirable to get status of all features detectable via `queryFeatureSupport` in a
forward-compatible way. Sufficiently recent versions provide this functionality via
Expand Down
Loading

0 comments on commit c1b3e94

Please sign in to comment.