Repository: webmachinelearning/writing-assistance-apis
Pull request #47: Add privacy and security mitigations
Author: login: domenic
Created: 2025-03-19T07:49:37Z | Merged: 2025-04-23T02:08:16Z

See individual commits for details.

This is also intended to apply to the two specs in https://github.com/webmachinelearning/translation-api, so the language is somewhat generic (e.g. a lot of discussion of "these APIs"). As with many things in built-in AI, the split across 2-3 repositories is a bit awkward, and I'm choosing for now to centralize the shared stuff into the writing assistance APIs spec.

<del>This won't build until I either eliminate some of the Storage Standard references or get them exported.</del><ins>I've worked around this for now.</ins>


<!--
    This comment and the below content is programmatically generated.
    You may add a comma-separated list of anchors you'd like a
    direct link to below (e.g. #idl-serializers, #idl-sequence):

    Don't remove this comment or modify anything below this line.
    If you don't want a preview generated for this pull request,
    just replace the whole of this comment's content by "no preview"
    and remove what's below.
-->
***
<a href="https://pr-preview.s3.amazonaws.com/webmachinelearning/writing-assistance-apis/pull/47.html" title="Last updated on Apr 23, 2025, 1:57 AM UTC (ccfb9f7)">Preview</a> | <a href="https://pr-preview.s3.amazonaws.com/webmachinelearning/writing-assistance-apis/47/70d4bb8...ccfb9f7.html" title="Last updated on Apr 23, 2025, 1:57 AM UTC (ccfb9f7)">Diff</a>


Diff:
diff --git a/README.md b/README.md
index ba189da..11e489d 100644
--- a/README.md
+++ b/README.md
@@ -417,29 +417,11 @@ For the time being, the Chrome built-in AI team is moving forward more aggresive
 
 ## Privacy considerations
 
-### General concerns about language-model based APIs
+Please see [the specification](https://webmachinelearning.github.io/writing-assistance-apis/#privacy).
 
-If cloud-based language models are exposed through this API, then there are potential privacy issues with exposing user or website data to the relevant cloud and model providers. This is not a concern specific to this API, as websites can already choose to expose user or website data to other origins using APIs such as `fetch()`. However, it's worth keeping in mind, and in particular as discussed in our [Goals](#shared-goals), perhaps we should make it easier for web developers to know whether a cloud-based model is in use, or which one.
+## Security considerations
 
-If on-device language models are updated separately from browser and operating system versions, this API could enhance the web's fingerprinting service by providing extra identifying bits. Mandating that older browser versions not receive updates or be able to download models from too far into the future might be a possible remediation for this.
-
-Finally, we intend to prohibit (in the specification) any use of user-specific information that is not directly supplied through the API. For example, it would not be permissible to fine-tune the language model based on information the user has entered into the browser in the past.
-
-### Detecting available options
-
-The [`availability()` API](#testing-available-options-before-creation) specified here provide some bits of fingerprinting information, since the availability status of each option and language can be one of four values, and those values are expected to be shared across a user's browser or browsing profile. In theory, this could be up to ~6.6 bits for the current set of summarizer options, plus an unknown number more based on the number of supported languages, and then this would be roughly tripled by including writer and rewriter. <!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
-
-In practice, we expect the number of bits to be much smaller, as implementations will likely not have separate, independently-downloadable pieces of collateral for each option value. (For example, in Chrome's case, we anticipate having a single download for all three APIs.) But we need the API design to be robust to a variety of implementation choices, and have purposefully designed it to allow such independent-download architectures so as not to lock implementers into a single strategy.
-
-There are a variety of solutions here, with varying tradeoffs, such as:
-
-* Grouping downloads to reduce the number of bits, e.g. by ensuring that downloading the "formal" tone also downloads the "neutral" and "casual" tones. This costs the user slightly more bytes, but hopefully not many.
-* Partitioning downloads by top-level site, i.e. repeatedly downloading extra fine-tunings or similar and not sharing them across all sites. This could be feasible if the collateral necessary to support a given option is small; it would not generally make sense for the base language model.
-* Adding friction to the download with permission prompts or other user notifications, so that sites which are attempting to use these APIs for tracking end up looking suspicious to users.
-
-We'll continue to investigate the best solutions here. And the specification will at a minimum allow user agents to add prompts and UI, or reject downloads entirely, as they see fit to preserve privacy.
-
-It's also worth noting that a download cannot be evicted by web developers. Thus the availability states can only be toggled in one direction, from `"downloadable"` to `"downloading"` to `"available"`. And it doesn't provide an identifier that is very stable over time, as by browsing other sites, users will gradually toggle more and more of the availability states to `"availale"`.
+Please see [the specification](https://webmachinelearning.github.io/writing-assistance-apis/#security).
 
 ## Stakeholder feedback
 
diff --git a/index.bs b/index.bs
index eeb8b9d..b5adcd2 100644
--- a/index.bs
+++ b/index.bs
@@ -244,13 +244,13 @@ enum SummarizerLength { "short", "medium", "long" };
 
   1. [=Assert=]: this algorithm is running [=in parallel=].
 
-  1. If there is some error attempting to determine whether the user agent supports summarizing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
+  1. If there is some error attempting to determine whether the user agent [=model availability/can support=] summarizing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
 
-  1. If the user agent supports summarizing text into the type of summary described by |type|, in the format described by |format|, and with the length guidance given by |length| without performing any downloading operations, then return "{{Availability/available}}".
+  1. If the user agent [=model availability/currently supports=] summarizing text into the type of summary described by |type|, in the format described by |format|, and with the length guidance given by |length|, then return "{{Availability/available}}".
 
-  1. If the user agent believes it can summarize text according to |type|, |format|, and |length|, but only after finishing a download (e.g., of an AI model or fine-tuning) that is already ongoing, then return "{{Availability/downloading}}".
+  1. If the user agent believes it will be able to [=model availability/support=] summarizing text according to |type|, |format|, and |length|, but only after finishing a download that is already ongoing, then return "{{Availability/downloading}}".
 
-  1. If the user agent believes it can summarize text according to |type|, |format|, and |length|, but only after performing a download (e.g., of an AI model or fine-tuning), then return "{{Availability/downloadable}}".
+  1. If the user agent believes it will be able to [=model availability/support=] summarizing text according to |type|, |format|, and |length|, but only after performing a not-currently-ongoing download, then return "{{Availability/downloadable}}".
 
   1. Otherwise, return "{{Availability/unavailable}}".
 </div>
@@ -260,7 +260,7 @@ enum SummarizerLength { "short", "medium", "long" };
 
   1. [=Assert=]: this algorithm is running [=in parallel=].
 
-  1. If there is some error attempting to determine whether the user agent supports summarizing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
+  1. If there is some error attempting to determine whether the user agent [=model availability/can support=] summarizing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
 
   1. Return a [=language availabilities triple=] with:
 
@@ -425,6 +425,8 @@ The <dfn attribute for="Summarizer">inputQuota</dfn> getter steps are to return
 
      The summarization should conform to the guidance given by |type|, |format|, and |length|, in the definitions of each of their enumeration values.
 
+     The summarization process must conform to the guidance given in [[#privacy]] and [[#security]], notably including (but not limited to) [[#privacy-user-input]] and [[#security-runtime]].
+
      If |outputLanguage| is non-null, the summarization should be in that language. Otherwise, it should be in the language of |input| (which might not match that of |context| or |sharedContext|). If |input| contains multiple languages, or the language of |input| cannot be detected, then either the output language is [=implementation-defined=], or the implementation may treat this as an error, per the guidance in [[#summarizer-errors]].
 
   1. While true:
@@ -621,7 +623,7 @@ When summarization fails, the following possible reasons may be surfaced to the
     <tr>
       <td>"{{UnknownError}}"
       <td>
-        <p>All other scenarios, or if the user agent would prefer not to disclose the failure reason.
+        <p>All other scenarios, including if the user agent believes it cannot summarize and also meet the requirements given in [[#privacy]] or [[#security]]. Or, if the user agent would prefer not to disclose the failure reason.
 </table>
 
 <p class="note">This table does not give the complete list of exceptions that can be surfaced by the summarizer API. It only contains those which can come from certain [=implementation-defined=] steps.
@@ -820,13 +822,13 @@ enum WriterLength { "short", "medium", "long" };
 
   1. [=Assert=]: this algorithm is running [=in parallel=].
 
-  1. If there is some error attempting to determine whether the user agent supports writing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
+  1. If there is some error attempting to determine whether the user agent [=model availability/can support=] writing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
 
-  1. If the user agent supports writing text with the tone described by |tone|, in the format described by |format|, and with the length guidance given by |length| without performing any downloading operations, then return "{{Availability/available}}".
+  1. If the user agent [=model availability/currently supports=] writing text with the tone described by |tone|, in the format described by |format|, and with the length guidance given by |length|, then return "{{Availability/available}}".
 
-  1. If the user agent believes it can write text according to |tone|, |format|, and |length|, but only after finishing a download (e.g., of an AI model or fine-tuning) that is already ongoing, then return "{{Availability/downloading}}".
+  1. If the user agent believes it will be able to [=model availability/support=] writing text according to |type|, |format|, and |length|, but only after finishing a download that is already ongoing, then return "{{Availability/downloading}}".
 
-  1. If the user agent believes it can write text according to |tone|, |format|, and |length|, but only after performing a download (e.g., of an AI model or fine-tuning), then return "{{Availability/downloadable}}".
+  1. If the user agent believes it will be able to [=model availability/support=] writing text according to |type|, |format|, and |length|, but only after performing a not-currently-ongoing download, then return "{{Availability/downloadable}}".
 
   1. Otherwise, return "{{Availability/unavailable}}".
 </div>
@@ -836,7 +838,7 @@ enum WriterLength { "short", "medium", "long" };
 
   1. [=Assert=]: this algorithm is running [=in parallel=].
 
-  1. If there is some error attempting to determine whether the user agent supports writing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
+  1. If there is some error attempting to determine whether the user agent [=model availability/can support=] writing text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
 
   1. Return a [=language availabilities triple=] with:
 
@@ -972,6 +974,8 @@ The <dfn attribute for="Writer">inputQuota</dfn> getter steps are to return [=th
 
      The written output should conform to the guidance given by |tone|, |format|, and |length|, in the definitions of each of their enumeration values.
 
+     The writing process must conform to the guidance given in [[#privacy]] and [[#security]], notably including (but not limited to) [[#privacy-user-input]] and [[#security-runtime]].
+
      If |outputLanguage| is non-null, the writing should be in that language. Otherwise, it should be in the language of |input| (which might not match that of |context| or |sharedContext|). If |input| contains multiple languages, or the language of |input| cannot be detected, then either the output language is [=implementation-defined=], or the implementation may treat this as an error, per the guidance in [[#writer-errors]].
 
   1. While true:
@@ -1130,7 +1134,7 @@ When writing fails, the following possible reasons may be surfaced to the web de
     <tr>
       <td>"{{UnknownError}}"
       <td>
-        <p>All other scenarios, or if the user agent would prefer not to disclose the failure reason.
+        <p>All other scenarios, including if the user agent believes it cannot write and also meet the requirements given in [[#privacy]] or [[#security]]. Or, if the user agent would prefer not to disclose the failure reason.
 </table>
 
 <p class="note">This table does not give the complete list of exceptions that can be surfaced by the writer API. It only contains those which can come from certain [=implementation-defined=] steps.
@@ -1329,13 +1333,13 @@ enum RewriterLength { "as-is", "shorter", "longer" };
 
   1. [=Assert=]: this algorithm is running [=in parallel=].
 
-  1. If there is some error attempting to determine whether the user agent supports rewriting text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
+  1. If there is some error attempting to determine whether the user agent [=model availability/can support=] rewriting text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
 
-  1. If the user agent supports rewriting text with the tone modification described by |tone|, in the format described by |format|, and with the length modification given by |length| without performing any downloading operations, then return "{{Availability/available}}".
+  1. If the user agent [=model availability/currently supports=] rewriting text with the tone modification described by |tone|, in the format described by |format|, and with the length modification given by |length|, then return "{{Availability/available}}".
 
-  1. If the user agent believes it can rewrite text according to |tone|, |format|, and |length|, but only after finishing a download (e.g., of an AI model or fine-tuning) that is already ongoing, then return "{{Availability/downloading}}".
+  1. If the user agent believes it will be able to [=model availability/support=] rewriting text according to |type|, |format|, and |length|, but only after finishing a download that is already ongoing, then return "{{Availability/downloading}}".
 
-  1. If the user agent believes it can rewrite text according to |tone|, |format|, and |length|, but only after performing a download (e.g., of an AI model or fine-tuning), then return "{{Availability/downloadable}}".
+  1. If the user agent believes it will be able to [=model availability/support=] rewriting text according to |type|, |format|, and |length|, but only after performing a not-currently-ongoing download, then return "{{Availability/downloadable}}".
 
   1. Otherwise, return "{{Availability/unavailable}}".
 </div>
@@ -1345,7 +1349,7 @@ enum RewriterLength { "as-is", "shorter", "longer" };
 
   1. [=Assert=]: this algorithm is running [=in parallel=].
 
-  1. If there is some error attempting to determine whether the user agent supports rewriting text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
+  1. If there is some error attempting to determine whether the user agent [=model availability/can support=] rewriting text, which the user agent believes to be transient (such that re-querying could stop producing such an error), then return null.
 
   1. Return a [=language availabilities triple=] with:
 
@@ -1481,6 +1485,8 @@ The <dfn attribute for="Rewriter">inputQuota</dfn> getter steps are to return [=
 
      The rewritten output should conform to the guidance given by |tone|, |format|, and |length|, in the definitions of each of their enumeration values.
 
+     The rewriting process must conform to the guidance given in [[#privacy]] and [[#security]], notably including (but not limited to) [[#privacy-user-input]] and [[#security-runtime]].
+
      If |outputLanguage| is non-null, the rewritten output text should be in that language. Otherwise, it should be in the language of |input| (which might not match that of |context| or |sharedContext|). If |input| contains multiple languages, or the language of |input| cannot be detected, then either the output language is [=implementation-defined=], or the implementation may treat this as an error, per the guidance in [[#rewriter-errors]].
 
   1. While true:
@@ -1643,7 +1649,7 @@ When rewriting fails, the following possible reasons may be surfaced to the web
     <tr>
       <td>"{{UnknownError}}"
       <td>
-        <p>All other scenarios, or if the user agent would prefer not to disclose the failure reason.
+        <p>All other scenarios, including if the user agent believes it cannot rewrite and also meet the requirements given in [[#privacy]] or [[#security]]. Or, if the user agent would prefer not to disclose the failure reason.
 </table>
 
 <p class="note">This table does not give the complete list of exceptions that can be surfaced by the rewriter API. It only contains those which can come from certain [=implementation-defined=] steps.
@@ -1812,6 +1818,22 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
       ::
         1. If |availability| is "{{Availability/downloadable}}", then:
 
+          1. If |realm|'s [=realm/global object=] does not have [=transient activation=], then:
+
+            1. [=Queue a global task=] on the [=AI task source=] given |realm|'s [=realm/global object=] to [=reject=] |promise| with a "{{NotAllowedError}}" {{DOMException}}.
+
+            1. Abort these steps.
+
+          1. [=Consume user activation=] given |realm|'s [=realm/global object=].
+
+          1. <span id="step-download-user-interface"></span>The user agent may display a user interface to the user to confirm that they want to perform the download operation given by |startDownload|, or to show the progress of the download. Alternately, the user agent may decide to deny the ability to perform |startDownload| based on implicit signals of the user's intent, including the considerations in [[#privacy-availability-eviction]] and [[#security-disk-space]]. If the user explicitly or implicitly signals that they do not want to start the download, then:
+
+            1. [=Queue a global task=] on the [=AI task source=] given |realm|'s [=realm/global object=] to [=reject=] |promise| with a "{{NotAllowedError}}" {{DOMException}}.
+
+            1. Abort these steps.
+
+            <p class="note">The case where the user cancels the download after it starts is handled later, as part of the download loop.
+
           1. Let |startDownloadResult| be the result of performing |startDownload| given |options|.
 
           1. If |startDownloadResult| is false, then:
@@ -1832,6 +1854,8 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
               <p>This prevents the web developer-perceived progress from suddenly jumping from 0% to 90%, and then taking a long time to go from 90% to 100%. It also provides some protection against the (admittedly not very powerful) fingerprinting vector of measuring the current download progress across multiple sites.
              </div>
 
+             <p id="step-fake-download">If the actual number of bytes necessary to download is 0, but the user agent is faking a download for the reasons described in [[#privacy]] (notably [[#privacy-language-availability]]), then set this number to an [=implementation-defined=] value that helps with the download faking.
+
           1. Let |lastProgressFraction| be 0.
 
           1. Let |lastProgressTime| be the [=monotonic clock=]'s [=monotonic clock/unsafe current time=].
@@ -1840,13 +1864,13 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
 
           1. While true:
 
-            1. If downloading has failed, then:
+            1. If downloading has failed, or the user has canceled the download, then:
 
               1. [=Queue a global task=] on the [=AI task source=] given |realm|'s [=realm/global object=] to [=reject=] |promise| with a "{{NetworkError}}" {{DOMException}}.
 
               1. Abort these steps.
 
-            1. Let |bytesSoFar| be the number of bytes downloaded so far.
+            1. Let |bytesSoFar| be the number of bytes downloaded so far. (Or the number of bytes fake-downloaded so far, if the user agent is faking the download.)
 
             1. [=Assert=]: |bytesSoFar| is greater than or equal to 0, and less than or equal to |totalBytes|.
 
@@ -1856,7 +1880,7 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
 
               1. Let |progressFraction| be [$floor$](|rawProgressFraction| &times; 65,536) &divide; 65,536.
 
-                  <div class="note">
+                <div class="note" id="note-download-progress-fraction">
                   <p>We use a fraction, instead of firing a progress event with the number of bytes downloaded, to avoid giving precise information about the size of the model or other material being downloaded.</p>
 
                   <p>|progressFraction| is calculated from |rawProgressFraction| to give a precision of one part in 2<sup>16</sup>. This ensures that over most internet speeds and with most model sizes, the {{ProgressEvent/loaded}} value will be different from the previous one that was fired ~50 milliseconds ago.</p>
@@ -1955,8 +1979,14 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
 
               1. Set |lastProgressTime| to the [=monotonic clock=]'s [=monotonic clock/unsafe current time=].
 
+            <p class="advisement" id="warning-download-cancelation-fully-active">If |document| stops being [=Document/fully active=], this loop does <em>not</em> terminate, and the user agent should not cancel the download, for the reasons explained in [[#privacy-availability-cancelation]]. It could pause the download, effectively meaning that the loop will never again have observable effects such as firing {{CreateMonitor/downloadprogress}} events. But even in such a case, future calls to |getAvailability| given |options| need to return "{{Availability/downloading}}" instead of "{{Availability/downloadable}}", and the material downloaded so far needs to persist even across user agent restarts.
+
+            <p class="note" id="note-downloading-while-in-bfcache">If the user agent does continue downloading while |document| is not [=Document/fully active=], then the loop will periodically queue tasks to fire {{CreateMonitor/downloadprogress}} events anyway. If the document becomes [=Document/fully active=] again, by coming out of the back/forward cache, these tasks will be run at that time, and the download progress will be reported to the web developer.
+
         1. [=If aborted=], then abort these steps.
 
+          <p class="advisement" id="warning-download-cancelation-abort-signal">The user agent should not actually cancel the underlying download, as explained in [[#privacy-availability-cancelation]]. As <a href="#warning-download-cancelation-fully-active">above</a>, it could fulfill this requirement by pausing the download, but it cannot cancel discard the progress made so far.
+
         1. [=Initialize and return an AI model object=] given |promise|, |options|, a no-op algorithm, |initialize|, and |create|.
     </dl>
 
@@ -2246,6 +2276,8 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
 
     1. Let |availability| be the result of |compute| given |options|.
 
+    1. <span id="step-download-masking"></span>If |availability| is "{{Availability/available}}" or "{{Availability/downloading}}", and if [[#privacy-availability-masking|download masking]] is needed to protect the user's privacy, the user agent should set |availability| to "{{Availability/downloadable}}".
+
     1. [=Queue a global task=] on the [=AI task source=] given |global| to perform the following steps:
 
       1. If |availability| is null, then [=reject=] |promise| with an "{{UnknownError}}" {{DOMException}}.
@@ -2267,6 +2299,8 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
   1. Return "{{Availability/available}}".
 </div>
 
+For the purposes of our algorithms related to model availability, a user agent <dfn for="model availability" lt="currently supports|currently supported|can support|supports">currently supports</dfn> an operation if it can perform that operation without first downloading the necessary capabilities. (For example, without first downloading an AI model or fine tuning.) Such determination of support should incorporate the privacy considerations described in [[#privacy-model-version]]. That is, even if a user agent has a suitable model available or could in theory download one, it may choose instead to report the operation as unsupported, in order to avoid using models whose versions skew too far from the user agent's version.
+
 <h3 id="supporting-language-availability">Language availability</h3>
 
 A <dfn>language availabilities partition</dfn> is a [=map=] whose [=map/keys=] are "{{Availability/downloading}}", "{{Availability/downloadable}}", or "{{Availability/available}}", and whose [=map/values=] are [=sets=] of strings representing [=Unicode canonicalized locale identifiers=]. [[!ECMA-402]]
@@ -2282,15 +2316,15 @@ A <dfn>language availabilities triple</dfn> is a [=struct=] with the following [
 
   1. Let |partition| be «[ "{{Availability/available}}" → an empty [=set=], "{{Availability/downloading}}" → an empty [=set=], "{{Availability/downloadable}}" → an empty [=set=] ]».
 
-  1. [=list/For each=] human language |languageTag|, represented as a [=Unicode canonicalized locale identifier=], for which the user agent supports |purpose|, without performing any downloading operations:
+  1. [=list/For each=] human language |languageTag|, represented as a [=Unicode canonicalized locale identifier=], for which the user agent [=model availability/currently supports=] |purpose|:
 
     1. [=set/Append=] |languageTag| to |partition|["{{Availability/available}}"].
 
-  1. [=list/For each=] human language |languageTag|, represented as a [=Unicode canonicalized locale identifier=], for which the user agent is currently downloading material (e.g., an AI model or fine-tuning) to support |purpose|:
+  1. [=list/For each=] human language |languageTag|, represented as a [=Unicode canonicalized locale identifier=], for which the user agent believes it will be able to [=model availability/support=] |purpose|, but only after finishing a download that is already ongoing:
 
     1. [=set/Append=] |languageTag| to |partition|["{{Availability/downloading}}"].
 
-  1. [=list/For each=] human language |languageTag|, represented as a [=Unicode canonicalized locale identifier=], for which the user agent believes it can support |purpose|, but only after performing a not-currently-ongoing download (e.g., of an AI model or fine-tuning):
+  1. [=list/For each=] human language |languageTag|, represented as a [=Unicode canonicalized locale identifier=], for which the user agent believes it will be able to [=model availability/support=] |purpose|, but only after performing a not-currently-ongoing download:
 
     1. [=set/Append=] |languageTag| to |partition|["{{Availability/downloadable}}"].
 
@@ -2372,3 +2406,132 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<!-- In the source, we use HTML comments prefixed with "Main text reference:" throughout this section to try to ensure that these normative requirements are at least *referenced* from the main text. For negative requirements (e.g. "should not") this is not comprehensive, since they are requiring that an unlimited number of spec steps do not do something. -->
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent downloads separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status by returning "{{Availability/downloadable}}" even if the actual download status is "{{Availability/available}}" or "{{Availability/downloading}}". This is done as part of <a href="#step-download-masking">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<!-- Main text reference: #step-download-masking -->
+<strong>Implementations which use such a [=storage key=]-based masking scheme must ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+(For details on cases where downloading might happen more than once, and how privacy and security are preserved in those cases, see [[#privacy-availability-cancelation]], [[#privacy-availability-eviction]], and [[#security-disk-space]].)
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation-abort-signal">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download progress so far will be preserved, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+<!-- Main text reference (negative requirement): one specific case in #warning-download-cancelation-fully-active -->
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. The specific case of navigation is covered by another "should"-level <a href="#warning-download-cancelation-fully-active">requirement</a>.
+
+Note that canceling downloads in response to user-controlled actions is not problematic.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a quota-based eviction system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+<!-- Main text reference (negative requirement): mentioned in #step-download-user-interface -->
+To avoid this, <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>, including via indirect triggers such as further subsequent downloads. One way to fulfill this requirement is to never evict downloaded material in response to web page-initiated storage pressure, instead refusing to download new material if doing so would cause storage pressure.
+
+Evicting downloads in response to user-controlled actions is not problematic, and providing such user affordances is discussed further in [[#security-disk-space]].
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the user's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+<!-- Main text reference: #step-fake-download -->
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+<!-- Main text reference: "currently supports" definition -->
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates alongside already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, when determining whether a model-backed operation is [=model availability/currently supported=]. Examples of possible techniques include not providing model updates to older user agent versions, or ignoring the presence of already-downloaded models below a minimum version threshold after a user agent update (instead downloading a newer version above that threshold). Note that such techniques might not always be available, for example if the user agent always uses a model bundled with the operating system, whose updates are not under the user agent's control.
+
+There is a tradeoff between reducing the fingerprinting bits that can be derived from the model version, and reducing the fingerprinting bits that can be derived from the model download status. (The latter is discussed in [[#privacy-availability]].) Aggressively locking new user agent versions to new model versions can result in more frequent transitions between "{{Availability/available}}" and "{{Availability/downloadable}}". This can be mitigated by allowing usage of older model versions with newer user agent versions while the new model version is downloading. This ensures the availability state stays at "{{Availability/available}}", at the cost of short periods where web pages can, with some effort, identify the user as belonging to the smaller cohort of older-model, newer-user-agent users.
+
+<h3 id="privacy-user-input">User input</h3>
+
+<!-- Main text reference: each "the algorithm" section -->
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.)
+
+Using user input in such a way would provide a vector for exposing the user's information to web pages, or for exposing information derived from the user's interactions with one site to another site, both of which are unacceptable privacy leaks.
+
+<h3 id="privacy-cloud-implementations">Cloud-based implementations</h3>
+
+The implementation-defined parts of these APIs can be implemented by delegating to user-agent-provided cloud-based services. This is not, in itself, a significant privacy risk: web developers already have the ability to send arbitrary data (including user-provided data) to cloud services via APIs such as {{WindowOrWorkerGlobalScope/fetch()}}. Indeed, it's likely that web developers will fall back to such cloud services when these APIs are not present. Additionally, in some cases entire user agents are already implemented as cloud services, with their user interfaces streamed to the user's device.
+
+However, this is something for web developers to be aware of when they use this API, in case their web page has requirements on not sending certain information to third parties. We're contemplating giving control over this possibility to web developers in <#38>.
+
+<h2 id="security">Security considerations</h2>
+
+<em>Unlike many "security considerations" sections, which only summarize and restate security considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="security-disk-space">Disk space</h3>
+
+Downloading models for these APIs could use significant amounts of the user's disk space. Depending on the implementation strategy, web pages might be able to trigger more such usage, by repeatedly calling the `create()` methods with different options.
+
+<!-- Main text reference: #step-download-user-interface -->
+<strong>In the event of storage pressure, user agents should balance the utility of these APIs with the disk space they take up</strong>, possibly failing a new download (as discussed in <a href="#step-download-user-interface">this step</a>) or freeing up disk space in some other way. However, user agents need to be mindful of the privacy impacts discussed in [[#privacy-availability-eviction]] when considering freeing up disk space by evicting model downloads. <!-- Main text reference: NONE (for the idea of a model management UI) --><strong>User agents may involve the user in these decisions</strong>, e.g., via download-time prompts (mentioned <a href="#step-download-user-interface">in the downloading algorithm</a>) or some sort of model management UI.
+
+<!-- Main text reference: each "the algorithm" section -->
+<strong>If model eviction happens while the model is being actively used by a web page, in such a way that the API can no longer operate, then the user agent should fail these APIs with an "{{UnknownError}}" {{DOMException}}.</strong>
+
+<h3 id="security-runtime">Runtime shared resources</h3>
+
+Current implementation strategies for these APIs can involve significant usage of resources such as GPU memory and processing power. This leads to a common implementation strategy of loading the appropriate model once, and sharing its capabilities between multiple web pages that interface with it via these APIs.
+
+<!-- Main text reference: each "the algorithm" section -->
+<strong>User agents should ensure that one web page's use of these APIs does not overly interfere with another web page's use of these APIs, or another web page's general operation</strong>. For example, it should not be possible for a background tab to prevent a foreground tab from using these APIs by calling them in a tight loop, or for one web page to lock up shared GPU resources indefinitely by repeatedly submitting large inputs.
+
+<!-- Main text reference: each "the algorithm" section -->
+This specification does not mandate any particular mitigation strategy for these issues, but possible useful strategies include queuing, rate limiting, abuse detection, and treating differently web pages which the user is actively interacting with versus those in the background. <strong>If necessary, the user agent may fail these APIs with an "{{UnknownError}}" {{DOMException}} to prevent such problems.</strong>
+
+<h3 id="security-os">OS-provided models</h3>
+
+One implementation strategy for these APIs is to delegate to models provided by the operating system. This can provide a number of benefits, such as a more uniform experience for the user across multiple applications, or less disk space usage.
+
+However, doing so comes with the usual dangers of exposing operating system capabilities to the web platform. User agents still need to ensure that the various privacy and security requirements in this specification are followed when using OS-provided models, even if the user agent has less control over the model's behavior. Particularly notable requirements to watch out for are those in [[#privacy-user-input]] and [[#security-runtime]].
diff --git a/security-privacy-questionnaire.md b/security-privacy-questionnaire.md
index 99bc110..13167c3 100644
--- a/security-privacy-questionnaire.md
+++ b/security-privacy-questionnaire.md
@@ -9,12 +9,12 @@ This feature exposes two large categories of information:
 
 - The availability information for various capabilities of the API, so that web developers know what capabilities are available in the current browser, and whether using them will require a download or the capability can be used readily.
 
-The privacy implications of both of these are discussed [in the explainer](./README.md#privacy-considerations).
+The privacy implications of both of these are discussed [in the specification](https://webmachinelearning.github.io/writing-assistance-apis/#privacy).
 
 > 02.  Do features in your specification expose the minimum amount of information
 >      necessary to implement the intended functionality?
 
-We believe so. It's possible that we could remove the exposure of the after-download vs. readily information. However, it would almost certainly be inferrable via timing side-channels. (I.e., if downloading a language model or fine-tuning is required, then the web developer can observe the creation of the summarizer/writer/rewriter object taking longer.)
+We believe so. It's possible that we could remove the exposure of the download status information. However, it would almost certainly be inferrable via timing side-channels. (I.e., if downloading a language model or fine-tuning is required, then the web developer can observe the creation of the summarizer/writer/rewriter object taking longer.)
 
 > 03.  Do the features in your specification expose personal information,
 >      personally-identifiable information (PII), or information derived from
@@ -69,7 +69,7 @@ None.
 
 We use permissions policy to disallow the usage of these features by default in third-party (cross-origin) contexts. However, the top-level site can delegate to cross-origin iframes.
 
-Otherwise, it's possible that some of the [anti-fingerprinting mitigations](./README.md#privacy-considerations) might involve partitioning download status, which is kind of like distinguishing between first- and third-party contexts.
+Otherwise, some of the possible [anti-fingerprinting mitigations](https://webmachinelearning.github.io/writing-assistance-apis/#privacy-availability) involve partitioning information across sites, which is kind of like distinguishing between first- and third-party contexts.
 
 > 14.  How do the features in this specification work in the context of a browser’s
 >      Private Browsing or Incognito mode?
@@ -81,9 +81,10 @@ Otherwise, we do not anticipate any differences.
 > 15.  Does this specification have both "Security Considerations" and "Privacy
 >      Considerations" sections?
 
-There is no specification yet, but there is a [privacy considerations](./README.md#privacy-considerations) section in the explainer.
+Yes:
 
-We do not anticipate significant security risks for these APIs at this time.
+* [Privacy considerations](https://webmachinelearning.github.io/writing-assistance-apis/#privacy)
+* [Security considerations](https://webmachinelearning.github.io/writing-assistance-apis/#security)
 
 > 16.  Do features in your specification enable origins to downgrade default
 >      security protections?


Reviews:
user: login: jyasskin
body: Sorry that it took me so long to get to this. The privacy and security considerations look great! I left a bunch of small points, and I can't guarantee I'll have noticed everything, but this is a big improvement to the features' overall threat modeling.
state: APPROVED
author_association: NONE
submitted_at: 2025-04-14T22:40:46Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T03:03:09Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T04:36:32Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T04:40:50Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T04:43:06Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T04:59:06Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T04:59:32Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T05:24:41Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T06:10:08Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T06:13:01Z
user: login: jyasskin
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-16T18:49:11Z
user: login: jyasskin
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-16T18:53:15Z
user: login: jyasskin
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-16T19:03:57Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T02:15:04Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T02:35:32Z
user: login: domenic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T03:17:44Z

Review comments:
diff_hunk: @@ -621,7 +628,7 @@ When summarization fails, the following possible reasons may be surfaced to the
     <tr>
       <td>"{{UnknownError}}"
       <td>
-        <p>All other scenarios, or if the user agent would prefer not to disclose the failure reason.
+        <p>All other scenarios, including if the user agent believes it is necessary to fail to meet the requirements given in [[#privacy]] or [[#security]]. Or, if the user agent would prefer not to disclose the failure reason.
path: index.bs
user: login: jyasskin
body: This (and other instances of similar text below) looks like the UA is deciding not to meet the privacy requirements, but I think you mean that the UA decided to fail the API call.

```suggestion
        <p>All other scenarios, including if the user agent believes it cannot summarize and also meet the requirements given in [[#privacy]] or [[#security]]. Or, if the user agent would prefer not to disclose the failure reason.
```
created_at: 2025-03-26T20:33:01Z
author_association: NONE
diff_hunk: @@ -2258,6 +2284,8 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
 
     1. Let |availability| be the result of |compute| given |options|.
 
+    1. <span id="download-masking-step"></span>If |availability| is "{{Availability/available}}" or "{{Availability/downloading}}", the user agent should set |availability| to "{{Availability/downloadable}}" if doing so would improve the user's privacy, per the discussions in [[#privacy-availability-masking]].
path: index.bs
user: login: jyasskin
body: It's a bit confusing to put the two 'if' clauses on opposite sides of the action:

```suggestion
    1. <span id="download-masking-step"></span>If |availability| is "{{Availability/available}}" or "{{Availability/downloading}}", and if [[#privacy-availability-masking|download masking]] is needed to protect the user's privacy, the user agent should set |availability| to "{{Availability/downloadable}}".
```
created_at: 2025-04-14T20:13:53Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
path: index.bs
user: login: jyasskin
body: Could this be "must ensure" to ensure someone doesn't think they have a good reason to ignore it, and thereby create a supercookie?
created_at: 2025-04-14T20:59:13Z
author_association: NONE
diff_hunk: @@ -1808,6 +1814,22 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
       ::
         1. If |availability| is "{{Availability/downloadable}}", then:
 
+          1. If |realm|'s [=realm/global object=] does not have [=transient activation=], then:
+
+            1. [=Queue a global task=] on the [=AI task source=] given |realm|'s [=realm/global object=] to [=reject=] |promise| with a "{{NotAllowedError}}" {{DOMException}}.
+
+            1. Abort these steps.
+
+          1. [=Consume user activation=] given |realm|'s [=realm/global object=].
+
+          1. <span id="step-download-user-interface"></span>The user agent may display a user interface to the user to confirm that they want to perform the download operation given by |startDownload|, or to show the progress of the download. Alternately, the user agent may decide to deny the ability to perform |startDownload| based on implicit signals of the user's intent, including the considerations in [[#security-disk-space]]. If the user explicitly or implicitly signals that they do not want to start the download, then:
path: index.bs
user: login: jyasskin
body: This is your spec, and you know the tradeoffs, so I don't insist, but it's generally easier to read future diffs if long lines are wrapped somewhere. 
created_at: 2025-04-14T21:04:14Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
path: index.bs
user: login: jyasskin
body: Nearly all of the requirements here are referenced from particular places in the normative algorithms, so we could think of them as being specified in those places rather than in the Considerations sections. I think that makes your pattern better than the usual COMEFROM antipattern in Considerations sections. It'd be nice to ensure this more systematically, if we can come up with a way ... maybe by using Bikeshed's <dfn> support to make it possible to link between the requirements in considerations vs the algorithms?
created_at: 2025-04-14T21:08:39Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
path: index.bs
user: login: jyasskin
body: Maybe:

```suggestion
For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent downloads separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
```
created_at: 2025-04-14T21:09:53Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
path: index.bs
user: login: jyasskin
body: It might be good to start with a definition of what it means to mask the current download status. People can follow the link to get the idea that it's about always showing _availability_ as `"downloadable"`, but it'd be best if they didn't have to.
created_at: 2025-04-14T21:13:26Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
path: index.bs
user: login: jyasskin
body: Maybe link to the eviction sections (e.g. `#security-disk-space`) and explain how they don't compromise the claim that downloads are a one-time operation.
created_at: 2025-04-14T21:35:01Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
path: index.bs
user: login: jyasskin
body: `#warning-download-cancelation` says the download might just be paused, contrary to this paragraph's claim that "download will continue in the background". I don't see a problem with letting the download just pause, but the two sections should be consistent.
created_at: 2025-04-14T21:37:37Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
path: index.bs
user: login: jyasskin
body: I don't see a piece of the spec that refers to this requirement. That's not too surprising since it's a "should not" requirement, but it might be good to mention it in the place that, in another spec, would say "when the page is unloaded, the download should stop."
created_at: 2025-04-14T21:40:50Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
path: index.bs
user: login: jyasskin
body: Does a user-wide disk space quota really help with this? I could image a page that uses 30 small models as its signal, and resets the signal by downloading 100 multi-GB models that are likely to exceed any user's disk space. (The create() mitigations and the overall time it takes to download such large models probably prevent this attack, but they might also prevent attacks through an API-specific quota.)
created_at: 2025-04-14T21:43:17Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
path: index.bs
user: login: jyasskin
body: I'm more worried about stale models being used with new UA versions. Would it make sense to also suggest that each UA version define an oldest model version that can count as `"available"`?
created_at: 2025-04-14T21:57:03Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
path: index.bs
user: login: jyasskin
body: Why "roughly the same" and not "the same"?
created_at: 2025-04-14T21:59:54Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
+
+Using user input in such a way would provide a vector for exposing the user's information to web pages, or for exposing information derived from the user's interactions with one site to another site, both of which are unacceptable privacy leaks.
+
+<h3 id="privacy-cloud-implementations">Cloud-based implementations</h3>
+
+The implementation-defined parts of these APIs can be implemented by delegating to user-agent-provided cloud-based services. This is not, in itself, a significant privacy risk: web developers already have the ability to send arbitrary data (including user-provided data) to cloud services via APIs such as {{WindowOrWorkerGlobalScope/fetch()}}. Indeed, it's likely that web developers will fall back to such cloud services when these APIs are not present.
path: index.bs
user: login: jyasskin
body: It might also be worth noting that entire UAs can be implemented in the cloud.
created_at: 2025-04-14T22:35:41Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
+
+Using user input in such a way would provide a vector for exposing the user's information to web pages, or for exposing information derived from the user's interactions with one site to another site, both of which are unacceptable privacy leaks.
+
+<h3 id="privacy-cloud-implementations">Cloud-based implementations</h3>
+
+The implementation-defined parts of these APIs can be implemented by delegating to user-agent-provided cloud-based services. This is not, in itself, a significant privacy risk: web developers already have the ability to send arbitrary data (including user-provided data) to cloud services via APIs such as {{WindowOrWorkerGlobalScope/fetch()}}. Indeed, it's likely that web developers will fall back to such cloud services when these APIs are not present.
+
+However, this is something for web developers to be aware of when they use this API, in case their web page has requirements on not sending certain information to third parties. We're contemplating giving control over this possibility to web developers in <#38>.
+
+<h2 id="security">Security considerations</h2>
+
+<em>Unlike many "security considerations" sections, which only summarize and restate security considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="security-disk-space">Disk space</h3>
+
+Downloading models for these APIs could use significant amounts of the user's disk space. Depending on the implementation strategy, web pages might be able to trigger more such usage, by repeatedly calling the `create()` methods with different options.
+
+<strong>In the event of storage pressure, user agents should balance the utility of these APIs with the disk space they take up</strong>, possibly failing a new download (as discussed in <a href="#step-download-user-interface">this step</a>) or evicting an old one. However, user agents need to be mindful of the privacy impacts discussed in [[#privacy-availability-eviction]] for any such eviction strategy. <strong>User agents may involve the user in these decisions</strong>, e.g., via download-time prompts or some sort of model management UI.
path: index.bs
user: login: jyasskin
body: I think "User agents may involve the user in these decisions" is already provided by #step-download-user-interface and so doesn't need to be a `<strong>` novel normative requirement from this section.
created_at: 2025-04-14T22:38:11Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
path: index.bs
user: login: domenic
body: Good idea, done.
created_at: 2025-04-16T03:00:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
path: index.bs
user: login: domenic
body: Yeah, that seems fair. Done.
created_at: 2025-04-16T03:00:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
path: index.bs
user: login: domenic
body: Good catch. Revised to say "...will still receive a rejected promise, but the download progress so far will be preserved, and the availability status...", which I think works out.
created_at: 2025-04-16T03:01:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
+
+Using user input in such a way would provide a vector for exposing the user's information to web pages, or for exposing information derived from the user's interactions with one site to another site, both of which are unacceptable privacy leaks.
+
+<h3 id="privacy-cloud-implementations">Cloud-based implementations</h3>
+
+The implementation-defined parts of these APIs can be implemented by delegating to user-agent-provided cloud-based services. This is not, in itself, a significant privacy risk: web developers already have the ability to send arbitrary data (including user-provided data) to cloud services via APIs such as {{WindowOrWorkerGlobalScope/fetch()}}. Indeed, it's likely that web developers will fall back to such cloud services when these APIs are not present.
path: index.bs
user: login: domenic
body: Good idea, done. (In general I very much enjoyed https://github.com/w3ctag/design-reviews/issues/1038#issuecomment-2803693504.)
created_at: 2025-04-16T03:02:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
+
+Using user input in such a way would provide a vector for exposing the user's information to web pages, or for exposing information derived from the user's interactions with one site to another site, both of which are unacceptable privacy leaks.
+
+<h3 id="privacy-cloud-implementations">Cloud-based implementations</h3>
+
+The implementation-defined parts of these APIs can be implemented by delegating to user-agent-provided cloud-based services. This is not, in itself, a significant privacy risk: web developers already have the ability to send arbitrary data (including user-provided data) to cloud services via APIs such as {{WindowOrWorkerGlobalScope/fetch()}}. Indeed, it's likely that web developers will fall back to such cloud services when these APIs are not present.
+
+However, this is something for web developers to be aware of when they use this API, in case their web page has requirements on not sending certain information to third parties. We're contemplating giving control over this possibility to web developers in <#38>.
+
+<h2 id="security">Security considerations</h2>
+
+<em>Unlike many "security considerations" sections, which only summarize and restate security considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="security-disk-space">Disk space</h3>
+
+Downloading models for these APIs could use significant amounts of the user's disk space. Depending on the implementation strategy, web pages might be able to trigger more such usage, by repeatedly calling the `create()` methods with different options.
+
+<strong>In the event of storage pressure, user agents should balance the utility of these APIs with the disk space they take up</strong>, possibly failing a new download (as discussed in <a href="#step-download-user-interface">this step</a>) or evicting an old one. However, user agents need to be mindful of the privacy impacts discussed in [[#privacy-availability-eviction]] for any such eviction strategy. <strong>User agents may involve the user in these decisions</strong>, e.g., via download-time prompts or some sort of model management UI.
path: index.bs
user: login: domenic
body: The novel part was the model management UI. I've added a cross-link to the #step-download-user-interface though to make it clearer that part is not novel. Let me know what you think.
created_at: 2025-04-16T03:02:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
path: index.bs
user: login: domenic
body: I was a bit hesitant to constrain implementations overly. Some completely made-up examples of ways implementations might consider varying capabilities between sites:

- Tie compute budget (which might translate to output quality) to user engagement
- Give more unknown errors to sites which trigger abuse heuristics
- Vary quotas

That said, maybe adding "roughly" just raises more questions, and we should sweep the above possibilities under the existing implementation-defined clauses.
created_at: 2025-04-16T04:36:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
path: index.bs
user: login: domenic
body: Gave this a shot; let me know what you think.
created_at: 2025-04-16T04:40:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
path: index.bs
user: login: domenic
body: I guess in your model you are assuming FIFO storage. If you just refused to download the last model that put you over quota, then the user would be protected. The way that FIFO systems are vulnerable is important to capture; let me try adding some text about that.
created_at: 2025-04-16T04:43:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
path: index.bs
user: login: domenic
body: Yeah, those are the reasons I qualified with "more or less". I've added a parenthetical paragraph linking. Let me know what you think.
created_at: 2025-04-16T04:59:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
path: index.bs
user: login: domenic
body: Re-reading the spec text I wrote, I think you're basically completely right: FIFO is the issue, and API-specific vs. whole-disk quota is irrelevant. I rewrote the section.
created_at: 2025-04-16T04:59:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
path: index.bs
user: login: domenic
body: Good idea, done! I ended up writing a decent bit about this.
created_at: 2025-04-16T05:24:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
path: index.bs
user: login: domenic
body: I appreciate you thinking about this, as I wasn't sure myself about the approach I took.

I tried something inspired by what you were saying, by adding HTML comments. That revealed that we're missing main text references for:

- Tying model version to the UA version. I'm a bit unsure where I'd put this, as I'd really want it to affect the true availability computation.

   That is, unlike download masking, which we can just patch in the centralized "compute AI model availability" before exposing to the web developer, we'd want this requirement to fundamentally change whether a model is considered available or not.

    The way to do that in the current structure would be to update every place we get the underlying availability. I guess that's "get the language availabilities partition" plus the once-per-API "$apiName non-language options availability" algorithm? That wouldn't be terrible, but it's a bit spread out. Hmm.

- The idea of a model management UI. This doesn't feel like it has any place to go. It's a bit odd anyway, and it's one of the few "may"s... Not sure if there's a good solution here.

- "user agents must ensure that the various privacy and security requirements in this specification are still followed when using OS-provided models": it's a meta-point so probably not needed.

Let me know what you think.
created_at: 2025-04-16T06:10:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1808,6 +1814,22 @@ Every [=interface=] [=interface/including=] the {{DestroyableModel}} interface m
       ::
         1. If |availability| is "{{Availability/downloadable}}", then:
 
+          1. If |realm|'s [=realm/global object=] does not have [=transient activation=], then:
+
+            1. [=Queue a global task=] on the [=AI task source=] given |realm|'s [=realm/global object=] to [=reject=] |promise| with a "{{NotAllowedError}}" {{DOMException}}.
+
+            1. Abort these steps.
+
+          1. [=Consume user activation=] given |realm|'s [=realm/global object=].
+
+          1. <span id="step-download-user-interface"></span>The user agent may display a user interface to the user to confirm that they want to perform the download operation given by |startDownload|, or to show the progress of the download. Alternately, the user agent may decide to deny the ability to perform |startDownload| based on implicit signals of the user's intent, including the considerations in [[#security-disk-space]]. If the user explicitly or implicitly signals that they do not want to start the download, then:
path: index.bs
user: login: domenic
body: It sounds like you're more concerned with getting smaller diffs, but in case you were struggling with scrollbars, note that GitHub lets you toggle wrapping by using "split" diff mode: 
![image](https://github.com/user-attachments/assets/86d38e7d-aa7c-42e3-b512-b0a09bc81318)

But yeah, my preference is to not wrap in the source.
created_at: 2025-04-16T06:13:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
path: index.bs
user: login: jyasskin
body: 1. Yes, tying this to the underlying availability sounds right. You currently use the undefined term "supports" in "get the language availabilities partition" and "$apiName non-language options availability". Might it make sense to define that, and incorporate the versioning restrictions there?
2. I suspect https://storage.spec.whatwg.org/#ui-guidelines should be the main text for this part of the security considerations. Do you think that section needs any changes to protect privacy or security around these large model downloads?
3. Saying that requirements on browsers still apply when the browsers delegate down to the OS, seems like a perfect use of a Considerations section, since it's already part of the spec but is something implementers might forget. You could turn it from a "must" to just a factual statement.
created_at: 2025-04-16T18:49:10Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
path: index.bs
user: login: jyasskin
body: Looks good. When thinking about the version restrictions above, I realized that they make the download process a ~once-per-browser-version process, and there's a tradeoff between reducing the fingerprinting bits from allowing multiple model versions, vs from model download state. This can be mitigated if the browser guesses that a new version will eventually be needed for models that were used in the past, and auto-downloads it. It's probably worth mentioning those considerations somewhere.
created_at: 2025-04-16T18:53:15Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
path: index.bs
user: login: jyasskin
body: Hmmm, now I think the question of whether capabilities vary by sites is orthogonal to the question of fine-tuning on user input. E.g. if the global models were fine-tuned based on all the user's input across all sites, that would be bad, but it would still count as exposing the same capabilities to all sites. But if the model is fine-tuned on data collected within a single origin, between clearing storage, maybe that's fine? Maybe just delete this second sentence?
created_at: 2025-04-16T19:03:57Z
author_association: NONE
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
+
+<h4 id="privacy-availability-cancelation">Download cancelation</h4>
+
+An important part of making the download status into a less-useful fingerprinting vector is to ensure that the website cannot toggle the availability state back and forth by starting and canceling downloads. Doing so would allow sites much more fine-grained control over the possible fingerprinting bits, allowing them to read the bits via the `create()` methods without destroying them.
+
+The part of these APIs which, on the surface, gives developers control over the download process is the {{AbortSignal}} passed to the `create()` methods. This allows developers to signal that they are no longer interested in creating a model object, and immediately causes the promise returned by `create()` to become rejected. The specification has a "should"-level <a href="#warning-download-cancelation">requirement</a> that the user agent not actually cancel the underlying download when the {{AbortSignal}} is aborted. The web developer will still receive a rejected promise, but the download will continue in the background, and the availability status (as seen by future calls to the `availability()` method) will update accordingly.
+
+User agents might be inclined to cancel the download in other situations not covered in the specification, such as when the page is unloaded. This needs to be handled with caution, as if the page can initiate these operations using JavaScript (for example, by navigating away to another origin) that would re-open the privacy hole. So, <strong>user agents should not cancel the download in response to any page-controlled actions</strong>. Canceling in response to user-controlled actions, however, is fine.
+
+<h4 id="privacy-availability-eviction">Download eviction</h4>
+
+Another ingredient in ensuring that websites cannot toggle the availability state back and forth is to ensure that user agents don't use a fixed quota system for the downloaded material. For example, if a user agent implemented the translator API with one download per language arc, supported 100 language arcs, and evicted all but the 30 most-recently-used language arcs, then web pages could toggle the readable-via-`create()` availability state of language arcs from "{{Availability/available}}" back to "{{Availability/downloadable}}" by creating translators for 30 new language arcs.
+
+The simplest mitigation to this is to avoid any API-specific quota, and instead rely on a per-user disk space-based quota. This specification does not mandate that particular solution, but does require that <strong>user agents should not implement systems which allow web pages to control the eviction of downloaded material</strong>.
+
+<h4 id="privacy-availability-alternatives">Alternate options</h4>
+
+While some of the above requirements, such as those on user activation or permissions policy, are specified using "must" language to ensure interoperability, most are specified using "should". The reason for this is that it's possible for implementations to use completely different strategies to preserve user privacy, especially for APIs that use small models. (For example, the language detector API.)
+
+The simplest of these is to treat model downloads like most other stored resources, partitioning them by the downloading page's [=storage key=]. This lets the web origin model's existing privacy protections operate, obviating the need for anything more complicated. The downside is that this spends more of the user's time, bandwidth, and disk space redundantly downloading the same model across multiple sites.
+
+A slight variant of this is to re-download the model every time it is requested by a new [=storage key=], while re-using the on-disk storage. This still uses the uesr's time and bandwidth, but at least saves on disk space.
+
+Going further, a user agent could attempt to fake the download for new [=storage keys=] by just waiting for a similar amount of time as the real download originally took. This then only spends the user's time, sparing their bandwidth and disk space. However, this is less private than the above alternatives, due to the presence of network side channels. For example, a web page could attempt to detect the fake downloads by issuing network requests concurrent to the `create()` call, and noting that there is no change to network throughouput. The scheme of remembering the time the real download originally took can also be dangerous, as the first site to initiate the download could attempt to artificially inflate this time (using concurrent network requests) in order to communicate information to other sites that will initiate a fake download in the future, from which they can read the time taken. Nevertheless, something along these lines might be useful in some cases, implemented with caution and combined with other mitigations.
+
+<h3 id="privacy-language-availability">Sensitive language availability</h3>
+
+Even if the user agent mitigates most of the fingerprinting risks associated with the availability of AI models per [[#privacy-availability]], such that probing availability requires a destructive action per [[#privacy-availability-creation]], the information about download availabilities for different languages can still be a privacy risk beyond fingerprinting. This is most obvious in the case of the translator API, where, for example, knowing that the user has downloaded a translator from English to a minority language might be sensitive information. But it can apply just as well to other APIs, via options such as their expected input languages, which might be implemented using downloadable fine-tunings with variable availability.
+
+For this reason, on top of the creation-time mitigations discussed in [[#privacy-availability-creation]], <strong>user agents may artificially fake a download if they believe it would be helpful for privacy reasons</strong>, instead of instantly creating the model. This is *not* a fingerprinting mitigation, but instead provides some degree of plausible deniability for the user, such that web pages cannot be certain of the user's demographic information. If the web page sees model object creation taking 2–3 seconds and emitting {{CreateMonitor/downloadprogress}} events, then perhaps this is a fake download due to the user previously downloading a translator for that minority language, or perhaps it is a real download that completed quickly.
+
+As discussed in [[#privacy-availability-alternatives]], such fake downloads are not foolproof, and a determined web page could attempt to detect them. However, they do provide some privacy benefit, and can be combined with other mitigations (such as prompts) to provide a more robust defense, and to make such demographic probing impractically unreliable for attackers.
+
+<h3 id="privacy-model-version">Model version</h3>
+
+Separate from the availability of a model, the specific version or behavior of a model can also be a fingerprinting vector.
+
+For this reason, these APIs do not expose model versions directly. And they take some efforts to avoid exposing the model version indirectly, for example by <a href="#note-download-progress-fraction">censoring the download size</a> in the [=create an AI model object=] algorithm, so that {{CreateMonitor/downloadprogress}} events do not directly expose the size of the model. This also encourages interoperability, by making it harder for web pages to safelist specific models, and instead encouraging them to program against the general API surface.
+
+However, such mitigations are not foolproof. They only protect against simple attempts to passively discover the model version; behavioral probing can still reveal it. (For example, by sending a number of inputs, and checking the output against known patterns for different versions.)
+
+The best way to prevent the model version from becoming a fingerprinting vector is to tie it to the user agent's version, such that the model's version (and thus behavior) only updates in lockstep with already-exposed information such as {{NavigatorID/userAgent|navigator.userAgent}}. <strong>User agents should limit the number of possible model versions that a single user agent version can be paired with</strong>, for example by not providing model updates to older user agent versions. (However, this may not always be possible, for example because the user agent might be obtaining results by using a model bundled with the operating system, whose updates are not under the user agent's control.)
+
+<h3 id="privacy-user-input">User input</h3>
+
+<strong>Implementations must not train or fine-tune models on user input, or otherwise store user input in a way that models can consult in the future.</strong> (For example, using retrieval-augmented generation technology.) <strong>Instead, implementations should expose roughly "the same" capabilities to all sites.</strong>
path: index.bs
user: login: domenic
body: Good point! I wonder if "the same capabilities to all users" is what I was aiming for. But yeah, let's just delete it...
created_at: 2025-04-17T02:15:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
+
+<h3 id="privacy-availability">Model availability</h3>
+
+For any of the APIs that use the infrastructure described in [[#supporting]], the exact download status of the AI model or fine-tuning data can present a fingerprinting vector. How many bits this vector provides depends on the options provided to the API creation, and how they influence the download.
+
+For example, if the user agent uses a single model, with no separately-downloadable fine-tunings, to support the summarizer, writer, and rewriter APIs, then the download status provides two bits (corresponding to the four {{Availability}} values) across all three APIs. In contrast, if the user agent uses separate fine-tunings for each value of {{SummarizerType}}, {{SummarizerFormat}}, and {{SummarizerLength}} on top of a base model, then the download status for those summarizer fine-tunings alone provides ~6.6 bits of entropy.
+<!-- log_2(4 (availability) * 4 (type) * 3 (length) * 2 (format)) = ~6.6 -->
+
+<h4 id="privacy-availability-masking">Download masking</h4>
+
+One of the specification's mitigations is to suggest that the user agent mask the current download status, per <a href="#download-masking-step">this step</a> in the [=compute AI model availability=] algorithm which backs the `availability()` APIs.
+
+Because implementation strategies differ (e.g. in how many bits they expose), and other mitigations such as permission prompts are available, a specific masking scheme is not mandated. For APIs where the user agent believes such masking is necessary, a suggested heuristic is to mask by default, subject to a masking state that is established for each (API, options, [=storage key=]) tuple. This state can be set to "unmasked" once a web page in a given [=storage key=] calls the relevant `create()` method with a given set of options, and successfully starts a download or creates a model object. Since [=create an AI model object=] has stronger requirements (see [[#privacy-availability-creation]]), this ensures that web pages only get access to the true download status after taking a more costly and less-repeatable action.
+
+<strong>Implementations which use such a [=storage key=]-based masking scheme should ensure that the masking state is reset when other storage for that origin is reset.</strong>
+
+<h4 id="privacy-availability-creation">Creation-time friction</h4>
+
+The mitigation described in [[#privacy-availability-masking]] works against attempts to silently fingerprint using the `availability()` methods. The specification also contains requirements to prevent `create()` from being used for fingerprinting, by introducing enough friction into the process to make it impractical:
+
+* [=Create an AI model object=] both requires and consumes [=user activation=], when it would initiate a download.
+* [=Create an AI model object=] allows the user agent to prompt the user for permission, or to implicitly reject download attempts based on previous signals (such as an observed pattern of abuse).
+* [=Create an AI model object=] is gated on an per-API [=policy-controlled feature=], which means that only top-level origins and their delegates can use the API.
+
+Additionally, initiating the download process is more or less a one-time operation, so the availability status will only ever transition from "{{Availability/downloadable}}" to "{{Availability/downloading}}" to "{{Availability/available}}" via these guarded creation operations. That is, while `create()` can be used to read some of these fingerprinting bits, at the cost of the above friction, doing so will destroy the bits as well.
path: index.bs
user: login: domenic
body: Yeah, I see what you mean. Let me add some text in that regard.

Realistically I don't think it'll be once-per-browser-version. I'd expect something like this:

- Browser version B released alongside model version M
- Browser version B + 1, ..., B + 5 released. These all keep using model version M.
- Browser version B + 6 released alongside model version M + 1:
  - Not ideal for privacy:
    - Un-updated browsers at B, ..., B + 5 who have previously downloaded version M update themselves to version M + 1
    - Un-updated browsers at B, ..., B + 5 who have not yet downloaded any model download M + 1 in response to web dev requests
    - A browser upgrade from B + 5 to B + 6 keeps using already-downloaded M indefinitely
  - Ideal for privacy:
    - Un-updated B, ..., B + 5 either stick with M if they already have it, or download M in response to web dev requests
    - A browser upgrade from B + 5 to B + 6 wipes the storage of M and switches model status to to "downloadable", indicating that it's ready to download M + 1
  - More-realistic middle ground:
    - Un-updated browsers at B, ..., B + 5 that have previously downloaded M keep using it, with no upgrades
    - Un-updated browsers at B, ..., B + 5 that have not previously downloaded a model end up with "unavailable"
      - Or maybe we let them download M + 1, and count on browser auto-updating to keep this population small and transient
    - A user who upgrades from B + 5 to B + 6 keeps M around and uses it for a bit, but downloads M + 1 in the background and swaps to it as soon as is feasible.
created_at: 2025-04-17T02:35:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2380,3 +2408,110 @@ A <dfn export>quota exceeded error information</dfn> is a [=struct=] with the fo
 <h3 id="supporting-task-source">Task source</h3>
 
 [=Tasks=] queued by this specification use the <dfn export>AI task source</dfn>.
+
+<h2 id="privacy">Privacy considerations</h2>
+
+<em>Unlike many "privacy considerations" sections, which only summarize and restate privacy considerations that are already normatively specified elsewhere in the document, this section contains some normative requirements that are not present elsewhere, and adds more detail to the normative requirements present elsewhere. The novel normative requirements are called out using <strong>strong emphasis</strong>.</em>
path: index.bs
user: login: domenic
body: > 1. Yes, tying this to the underlying availability sounds right. You currently use the undefined term "supports" in "get the language availabilities partition" and "$apiName non-language options availability". Might it make sense to define that, and incorporate the versioning restrictions there?

Something like this sounds promising. Let me give it a try...

> 2\. I suspect https://storage.spec.whatwg.org/#ui-guidelines should be the main text for this part of the security considerations. Do you think that section needs any changes to protect privacy or security around these large model downloads?

The Storage Standard seems pretty focused around origin- or site-scoped storage, and that section in particular leads with "for individual websites". It doesn't seem as applicable here. We could reference it still, e.g. "alongside per-website storage management UIs [as discussed in _Storage_](https://storage.spec.whatwg.org/#ui-guidelines)". But it seems pretty different.

> 3\. Saying that requirements on browsers still apply when the browsers delegate down to the OS, seems like a perfect use of a Considerations section, since it's already part of the spec but is something implementers might forget. You could turn it from a "must" to just a factual statement.

Great point. Rephrased and removed the bold.
created_at: 2025-04-17T03:17:44Z
author_association: CONTRIBUTOR

PR comments:
user: login: nathanmemmott
created_at: 2025-04-18T18:27:19Z
body: With the download masking, what are the possible states of `after_create_availability`:
```
// Assume we're in the "downloadable" state.
const before_create_availability = await AiAPI.availability();
assert_equals(before_create_availability, "downloadable");

const create_promise = AiAPI.create().then(()=>"model created first");
const after_create_availability_promise = AiAPI.availability();

const result = await Promise.race([create_promise, after_create_availability_promise]);

// Assume availability resolves first.
assert_not_equals(result, "model created first");
const after_create_availability = result;
```

Could it be "downloadable"? Or only "downloading"?
author_association: NONE
user: login: domenic
created_at: 2025-04-21T05:51:47Z
body: I think it could be "downloadable". Once we go in-parallel, there's a race between determining the availability and starting the download. If starting the download loses that race, then [compute AI model availability](https://pr-preview.s3.amazonaws.com/webmachinelearning/writing-assistance-apis/pull/47.html#compute-ai-model-availability) will get back "downloadable".

Additionally, even if the download has already started, download masking can censor "downloading" to "downloadable".
author_association: CONTRIBUTOR