From ff3923e34f18e2f0a09751e3cdafad772d3a440b Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Mon, 20 Apr 2026 17:53:29 -0400 Subject: [PATCH 1/2] Clearing state for safety limits This is pretty straightforward once I thought it through. Most things are left along if `forgetSites` is false, so that is super easy. When it is true and the set of sites is empty, we already move the value of the last browsing history clear. So we can just drop all state. This is the easiest one. When `forgetSites` is true and the set of sites is not empty, we do nothing special for the global privacy budget. We can retain that. The impression site quota is also pretty easy. We forget that site was ever there. That would reset the amount that impressions from that site can eat from the global budget, except that the last browsing history clear value will ensure that none of those sites will be able to be found anyway. This is the small change. If you think about the effect of the last browing history clear value, it might be that the forgetting of specific sites - for this API - is effectively the same as forgetting all sites, so we can remove the distinction. I guess that the reason we have the current structure is that we wanted to retain the possibility that impressions from non-forgotten sites would be reachable at some point. With the impression site quota limit in place, that might no longer be possible. Still, baby steps. Closes #367. --- api.bs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/api.bs b/api.bs index 93b8d37..9bd3e66 100644 --- a/api.bs +++ b/api.bs @@ -1085,7 +1085,7 @@ that are used to manage the expenditure of [=privacy budgets=]: This value is initialized as a side effect of invoking measureConversion(). -* A singleton [=last browsing history clear=] value +* A singular [=last browsing history clear=] value that tracks when the browsing activity for a [=site=] was last cleared. * The [=global privacy budget store=] records the state @@ -1409,7 +1409,7 @@ returning an [=epoch index=]: 1. Let |rand| be |t| minus a [=duration=] that is randomly selected from between 0 (inclusive) and |period| (exclusive). - + 1. Let |ms| be the number of milliseconds in the [=duration from=] the [=unix epoch=] to |rand|. @@ -1545,8 +1545,9 @@ and a [=moment=] |now|: 1. [=map/clear|Clear=] the [=privacy budget store=]. -

TODO (issue https://github.com/w3c/attribution/issues/367): Define how to clear [=safety limits=] stores: - [=global privacy budget store=] and [=impression site quota store=]. + 1. [=map/clear|Clear=] the [=impression site quota store=]. + + 1. [=map/clear|Clear=] the [=global privacy budget store=]. 1. If |sites| [=set/is empty|is not empty=]: @@ -1554,19 +1555,35 @@ and a [=moment=] |now|: if |sites| [=set/contains=] |impression|'s [=impression/impression site=], [=set/remove=] |impression| from the [=impression store=]. - 1. [=set/iterate|For each=] |key| in the [=map/getting the keys|keys=] of the [=privacy budget store=], + 1. [=set/iterate|For each=] |key| in the [=map/getting the keys|keys=] + of the [=privacy budget store=], if |sites| [=set/contains=] the [=site=] component of |key|, [=map/remove=] [=privacy budget store=]\[|key|]. + 1. [=set/iterate|For each=] |key| in the [=map/getting the keys|keys=] + of the [=impression site quota store=], + if |sites| [=set/contains=] the [=site=] component of |key|, + [=map/remove=] [=impression site quota store=]\[|key|]. + +

+ This process does not touch the [=global privacy budget store=]. + Primarily, this is to ensure that [=privacy budget=], + once expended, is not forgotten. + 1. Set the [=last browsing history clear=] to |now|.

Setting the [=last browsing history clear=] while only clearing state for some sites (that is, when |sites| [=set/is empty|is not empty=]) will make some impressions unreachable for sites that are not present in that set. + Implementations could also remove any unusable impressions + and any budget records + (such as those in the [=global privacy budget store=]) + that cannot be used as a result. + ## Save Impression Algorithm ## {#save-impression-api-operation}

@@ -3522,8 +3539,7 @@ when clearing browsing history. Retaining per-[=site=] information necessary to prevent privacy loss toward sites leaves information about visits to sites -for other users of a computer to discover -when removing browsing history. +for other users of a computer to discover. A user agent that clears browsing history invokes [=clear browsing history for attribution=], From 4e30a16f14211dec405d02ad21dce488d5ff52f9 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Thu, 23 Apr 2026 03:37:38 -1000 Subject: [PATCH 2/2] s/two/one Co-authored-by: Benjamin M. Case <35273659+bmcase@users.noreply.github.com> --- api.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.bs b/api.bs index 9bd3e66..7e35a0c 100644 --- a/api.bs +++ b/api.bs @@ -1498,7 +1498,7 @@ returning an [=epoch index=]: 1. Set |clearEpoch| to |clearEpoch| + 1.

- Adding two is necessary so that the [=epoch=] + Adding one is necessary so that the [=epoch=] range for attribution does not overlap with an [=epoch=] before browsing history was cleared.