Page MenuHomePhabricator

Bug 2013938 - Update policies to work correctly with AI kill switch. r?mstriemer
ClosedPublic

Authored by mkaply on Feb 2 2026, 6:37 PM.
Referenced Files
Unknown Object (File)
Sep 27 2026, 9:22 AM
Unknown Object (File)
Sep 10 2026, 7:05 AM
Unknown Object (File)
Sep 8 2026, 3:54 PM
Unknown Object (File)
Sep 8 2026, 6:40 AM
Unknown Object (File)
Sep 7 2026, 4:17 PM
Unknown Object (File)
Sep 3 2026, 7:33 AM
Unknown Object (File)
Aug 30 2026, 2:53 AM
Unknown Object (File)
Aug 11 2026, 2:41 PM
Subscribers
None

Diff Detail

Event Timeline

phab-bot published this revision for review.Feb 2 2026, 6:37 PM
phab-bot changed the visibility from "Custom Policy" to "Public (No Login Required)".
phab-bot changed the edit policy from "Custom Policy" to "Restricted Project (Project)".
phab-bot removed a project: secure-revision.
nordzilla requested changes to this revision.EditedFeb 3 2026, 12:05 AM
nordzilla added a reviewer: nordzilla.

Thanks so much Mike!


issue: The dropdown menulists arent behaving how I would expect them to.

I started to do a bit of manual testing with this, and I noticed some behavior that we need to clarify.

Test Case

policies.json

{
  "policies": {
    "GenerativeAI": {
      "Enabled": true,
      "Locked": true
    }
  }
}

Before Toggling

All of this looks to be what I expect. The features are all Available/Enabled, and "Locked," meaning the UI cannot be changed.

image.png (836×790 px, 116 KB)

After Toggling

What is the expected behavior here?

The current implementation does this:

image.png (970×872 px, 141 KB)

The main toggle still moves the features to "Blocked" even though the dropdowns are disabled and the prefs are supposed to be "Locked".

I would expect the behavior to be more like this:

image.png (1×867 px, 143 KB)

Where even though we've turned the switch on, these prefs are managed by their policy and cannot be mutated.


thought:

In order to achieve the latter behavior I described, I think that we will need the policy to set and lock the ai.conrol prefs for each feature, too.

Something like this:

diff --git a/browser/components/enterprisepolicies/Policies.sys.mjs b/browser/components/enterprisepolicies/Policies.sys.mjs
index 2a6d3b297ff9..e355af7ecde2 100644
--- a/browser/components/enterprisepolicies/Policies.sys.mjs
+++ b/browser/components/enterprisepolicies/Policies.sys.mjs
@@ -1674,14 +1674,34 @@ export var Policies = {
       const defaultValue = "Enabled" in param ? param.Enabled : undefined;
 
       const features = [
-        ["Chatbot", ["browser.ml.chat.enabled", "browser.ml.chat.page"]],
-        ["LinkPreviews", ["browser.ml.linkPreview.optin"]],
-        ["TabGroups", ["browser.tabs.groups.smart.userEnabled"]],
-        ["Translations", ["browser.translations.enable"]],
-        ["PDFAltText", ["pdfjs.enableAltText"]],
+        [
+          "Chatbot",
+          ["browser.ml.chat.enabled", "browser.ml.chat.page"],
+          "browser.ai.control.sidebarChatbot",
+        ],
+        [
+          "LinkPreviews",
+          ["browser.ml.linkPreview.optin"],
+          "browser.ai.control.linkPreviewKeyPoints",
+        ],
+        [
+          "TabGroups",
+          ["browser.tabs.groups.smart.userEnabled"],
+          "browser.ai.control.smartTabGroups",
+        ],
+        [
+          "Translations",
+          ["browser.translations.enable"],
+          "browser.ai.control.translations",
+        ],
+        [
+          "PDFAltText",
+          ["pdfjs.enableAltText"],
+          "browser.ai.control.pdfjsAltText",
+        ],
       ];
 
-      for (const [key, prefs] of features) {
+      for (const [key, prefs, aiControlPref] of features) {
         if (key == "Translations") {
           if (!(key in param)) {
             // If the TranslateEnabled policy is being used, don't change
@@ -1696,6 +1716,11 @@ export var Policies = {
           for (const pref of prefs) {
             PoliciesUtils.setDefaultPref(pref, value, param.Locked);
           }
+          PoliciesUtils.setDefaultPref(
+            aiControlPref,
+            value ? "enabled" : "blocked",
+            param.Locked
+          );
         }
       }
     },

This is what TranslateEnabled currently does. If that's not correct, then I need to change TranslateEnabled, which I previously tested under these expectations that even the switch could not mutate the dropdown menulists while "Locked", for example:

image.png (1×878 px, 171 KB)


thought:

I'm also seeing an issue in the console logs, which looks to be a preexisting issue with TranslateEnabled since this is happening on the main branch with only the TranslateEnabled policy.

JavaScript error: resource://gre/modules/ActorManagerParent.sys.mjs, line 830: NotSupportedError: ChromeUtils.registerWindowActor: 'Translations' actor is already registered.
JavaScript error: resource://gre/modules/ActorManagerParent.sys.mjs, line 830: NotSupportedError: ChromeUtils.registerProcessActor: 'TranslationsEngine' actor is already registered.

Depending on how involved the fix may be involving ActorManagerParent, we may not want to risk it in uplift, if it is already a long-standing issue that went unnoticed.

I haven't looked into it yet, but can look into it tomorrow.

browser/components/enterprisepolicies/Policies.sys.mjs
1699

praise:

Thank you for considering the TranslateEnabled policy independently.

This revision now requires changes to proceed.Feb 3 2026, 12:05 AM

Update:

I dug more into these errors this morning:

JavaScript error: resource://gre/modules/ActorManagerParent.sys.mjs, line 830: NotSupportedError: ChromeUtils.registerWindowActor: 'Translations' actor is already registered.
JavaScript error: resource://gre/modules/ActorManagerParent.sys.mjs, line 830: NotSupportedError: ChromeUtils.registerProcessActor: 'TranslationsEngine' actor is already registered.

I tried a build back from June 2025, and this is a long-standing thing if someone attempts to set a pref value to true via policy, when the default is already true.

It causes the actor to be registered twice.

I've filed a bug and put up one attempt at a fix for review, but I'm not sure if we'll want to uplift into beta at this point, especially since this isn't on the primary UX path.

https://bugzilla.mozilla.org/show_bug.cgi?id=2014226

mkaply requested review of this revision.Feb 3 2026, 9:41 PM
mkaply updated this revision to Diff 1196982.
mkaply retitled this revision from Bug 2013938 - Add PDFAltText amd Translations to GenerativeAI policy. r?mstriemer to Bug 2013938 - Update policies to work correctly with AI kill switch. r?mstriemer.
browser/components/enterprisepolicies/schemas/policies-schema.json
893–894 ↗(On Diff #1196982)
issue: (before landing)

It looks like "Translations" accidentally got left out of the cleanup.

praise:

I think this looks great, Mike, barring my one new inline comment.

Thanks so much!

I'm just going to do a bit of manual testing, and will likely approve before the end of my work day.

browser/components/enterprisepolicies/schemas/policies-schema.json
893–894 ↗(On Diff #1196982)

Update: it's not just that "Translations" wasn't removed, but that it accidentally replaced "Locked".

(I didn't notice this until I started my manual testing.)

Manual Testing

Done with the inline fix applied:

diff --git a/browser/components/enterprisepolicies/schemas/policies-schema.json b/browser/components/enterprisepolicies/schemas/policies-schema.json
index 8547f35646f9..426a9fc0d388 100644
--- a/browser/components/enterprisepolicies/schemas/policies-schema.json
+++ b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -890,7 +890,7 @@
         "Enabled": {
           "type": "boolean"
         },
-        "Translations": {
+        "Locked": {
           "type": "boolean"
         }
       }

Case 1: Default enabled, not locked
{
  "policies": {
    "GenerativeAI": {
      "Enabled": true,
      "Locked": false
    }
  }
}

Switch Off
{F57565992}

Switch On
{F57566015}


Case 2: Default disabled, not locked
{
  "policies": {
    "GenerativeAI": {
      "Enabled": false,
      "Locked": false
    }
  }
}

Switch Off
{F57566207}

Switch On
{F57566234}


Case 3: Default enabled, locked
{
  "policies": {
    "GenerativeAI": {
      "Enabled": true,
      "Locked": true
    }
  }
}

Switch Off

image.png (1×916 px, 208 KB)

Switch On

image.png (1×916 px, 208 KB)


Case 4: Default disabled, locked
{
  "policies": {
    "GenerativeAI": {
      "Enabled": false,
      "Locked": true
    }
  }
}

Switch Off

image.png (1×916 px, 183 KB)

Switch On

image.png (1×916 px, 208 KB)


Case 5: Default enabled, locked, with per-feature overrides
{
  "policies": {
    "GenerativeAI": {
      "Enabled": true,
      "Chatbot": false,
      "LinkPreviews": true,
      "TabGroups": false,
      "Locked": true
    }
  }
}

Switch Off

image.png (1×916 px, 197 KB)

Switch On

image.png (1×916 px, 208 KB)


Case 6: Default disabled, locked, with per-feature overrides
{
  "policies": {
    "GenerativeAI": {
      "Enabled": false,
      "Chatbot": true,
      "LinkPreviews": false,
      "TabGroups": true,
      "Locked": true
    }
  }
}

Switch Off

image.png (1×916 px, 183 KB)

Switch On

image.png (1×916 px, 208 KB)


Case 7: Default disabled, locked, chatbot enabled, with TranslateEnabled
{
  "policies": {
    "GenerativeAI": {
      "Enabled": false,
      "Chatbot": true,
      "Locked": true
    },
    "TranslateEnabled": true
  }
}

Switch Off

image.png (1×916 px, 197 KB)

Switch On

image.png (1×916 px, 210 KB)


Conclusion

Manual testing looks correct to me, with the inline fix applied before landing.

r+

testing-exception-other:

  • This has undergone extensive manual testing, but has no automated tests at this time.
This revision is now accepted and ready to land.Feb 3 2026, 10:42 PM
mkaply added inline comments.
browser/components/enterprisepolicies/schemas/policies-schema.json
893–894 ↗(On Diff #1196982)

That's what I get for rushing. Thanks!

mkaply marked an inline comment as done.