diff --git a/ee/app/models/concerns/ee/issuable.rb b/ee/app/models/concerns/ee/issuable.rb
index a4d3ba15ae3fd372525496d2ec067954f8e05592..8ab533da7d01f45b728b1a414d6b316f7e9e557c 100644
--- a/ee/app/models/concerns/ee/issuable.rb
+++ b/ee/app/models/concerns/ee/issuable.rb
@@ -66,7 +66,7 @@ def supports_iterations?
     end
 
     def send_to_ai?
-      !try(:confidential) && resource_parent.public?
+      !try(:confidential) && resource_parent.public? && resource_parent.root_ancestor.third_party_ai_features_enabled
     end
 
     override :hook_association_changes
diff --git a/ee/app/models/ee/group.rb b/ee/app/models/ee/group.rb
index 7cf1ef4afe893409c24b75d8b8836eb451848658..25a19e62d20e748e676fa2f017910dee59fd085e 100644
--- a/ee/app/models/ee/group.rb
+++ b/ee/app/models/ee/group.rb
@@ -76,8 +76,6 @@ module Group
 
       delegate :repository_read_only,
                :code_suggestions, :code_suggestions=,
-               :experiment_features_enabled, :experiment_features_enabled=,
-               :third_party_ai_features_enabled, :third_party_ai_features_enabled=,
                :default_compliance_framework_id,
                to: :namespace_settings, allow_nil: true
 
diff --git a/ee/app/models/ee/namespace.rb b/ee/app/models/ee/namespace.rb
index 71c5d01f232395a13f3bb9ca6529037ce20078af..089778e5af7707e41e0706fb02a2f58d84f6fd0f 100644
--- a/ee/app/models/ee/namespace.rb
+++ b/ee/app/models/ee/namespace.rb
@@ -106,6 +106,10 @@ module Namespace
 
       delegate :trial_ends_on, :trial_starts_on, to: :gitlab_subscription, allow_nil: true
 
+      delegate :third_party_ai_features_enabled, :third_party_ai_features_enabled=,
+        :experiment_features_enabled, :experiment_features_enabled=,
+        to: :namespace_settings, allow_nil: true
+
       before_create :sync_membership_lock_with_parent
 
       # Changing the plan or other details may invalidate this cache
diff --git a/ee/app/policies/ee/issue_policy.rb b/ee/app/policies/ee/issue_policy.rb
index c0f86e442d053eb8074c62040a0d8cbf7af8a19c..fcd4b068cae837074541dbd02a3b0d9d60cebbbf 100644
--- a/ee/app/policies/ee/issue_policy.rb
+++ b/ee/app/policies/ee/issue_policy.rb
@@ -7,7 +7,9 @@ module IssuePolicy
     prepended do
       with_scope :subject
       condition(:ai_available) do
-        ::Feature.enabled?(:openai_experimentation) && @subject.send_to_ai?
+        ::Feature.enabled?(:openai_experimentation) &&
+          subject_container.root_ancestor.experiment_features_enabled &&
+          @subject.send_to_ai?
       end
 
       with_scope :subject
diff --git a/ee/app/policies/epic_policy.rb b/ee/app/policies/epic_policy.rb
index 822d7f5dc25ceed616f61a7f0dd37bd02d0b3508..fe66a9c1cbea2cf74c68240e766796a371be4f0b 100644
--- a/ee/app/policies/epic_policy.rb
+++ b/ee/app/policies/epic_policy.rb
@@ -27,7 +27,9 @@ class EpicPolicy < BasePolicy
   end
 
   condition(:ai_available, scope: :subject) do
-    ::Feature.enabled?(:openai_experimentation) && @subject.send_to_ai?
+    ::Feature.enabled?(:openai_experimentation) &&
+      @subject.group.root_ancestor.experiment_features_enabled &&
+      @subject.send_to_ai?
   end
 
   condition(:summarize_notes_enabled, scope: :subject) do
diff --git a/ee/spec/lib/gitlab/llm/open_ai/completions/generate_test_file_spec.rb b/ee/spec/lib/gitlab/llm/open_ai/completions/generate_test_file_spec.rb
index b11dd26105c778875fd26192448e15fc71ecd353..a3f2989dbeb97e76f7512a7f10460be2713c149f 100644
--- a/ee/spec/lib/gitlab/llm/open_ai/completions/generate_test_file_spec.rb
+++ b/ee/spec/lib/gitlab/llm/open_ai/completions/generate_test_file_spec.rb
@@ -4,7 +4,8 @@
 
 RSpec.describe Gitlab::Llm::OpenAi::Completions::GenerateTestFile, feature_category: :code_review_workflow do
   let_it_be(:user) { create(:user) }
-  let_it_be(:project) { create(:project, :public) }
+  let_it_be(:group) { create(:group, :public) }
+  let_it_be(:project) { create(:project, :public, group: group) }
   let_it_be(:merge_request) { create(:merge_request, source_project: project) }
 
   let(:template_class) { ::Gitlab::Llm::OpenAi::Templates::GenerateTestFile }
@@ -26,6 +27,10 @@
     described_class.new(template_class).execute(user, merge_request, { file_path: 'index.js' })
   end
 
+  before do
+    group.namespace_settings.update!(third_party_ai_features_enabled: true)
+  end
+
   describe "#execute" do
     context 'with invalid params' do
       context 'without user' do
diff --git a/ee/spec/models/concerns/ee/issuable_spec.rb b/ee/spec/models/concerns/ee/issuable_spec.rb
index 6f4f7597d66c27c90f4ed981360cabf2b5a701e1..d454e278512cc2520dccb27ec5cc9ccebdae19be 100644
--- a/ee/spec/models/concerns/ee/issuable_spec.rb
+++ b/ee/spec/models/concerns/ee/issuable_spec.rb
@@ -110,12 +110,14 @@
 
   describe '#send_to_ai?' do
     context 'for issues' do
-      where(:confidentiality, :visibility, :send_to_ai) do
+      where(:confidentiality, :visibility, :third_party_ai_features_enabled, :result) do
         [
-          [true, :public, false],
-          [true, :private, false],
-          [false, :public, true],
-          [false, :private, false]
+          [true, :public, false, false],
+          [true, :public, true, false],
+          [true, :private, false, false],
+          [false, :private, false, false],
+          [false, :private, true, false],
+          [false, :public, true, true]
         ]
       end
 
@@ -123,47 +125,64 @@
         let(:project) { build_stubbed(:project, visibility) }
         let(:issuable) { build_stubbed(:issue, confidential: confidentiality, project: project) }
 
+        before do
+          allow(project.namespace).to receive(:third_party_ai_features_enabled).and_return(third_party_ai_features_enabled)
+        end
+
         subject { issuable.send_to_ai? }
 
-        it { is_expected.to eq(send_to_ai) }
+        it { is_expected.to eq(result) }
       end
     end
 
     context 'for epics' do
-      where(:confidentiality, :visibility, :send_to_ai) do
+      where(:confidentiality, :visibility, :third_party_ai_features_enabled, :result) do
         [
-          [true, :public, false],
-          [true, :private, false],
-          [false, :public, true],
-          [false, :private, false]
+          [true, :public, false, false],
+          [true, :public, true, false],
+          [true, :private, false, false],
+          [false, :private, false, false],
+          [false, :private, true, false],
+          [false, :public, true, true]
         ]
       end
-
       with_them do
         let(:group) { build_stubbed(:group, visibility) }
         let(:issuable) { build_stubbed(:epic, confidential: confidentiality, group: group) }
 
+        before do
+          allow(group).to receive(:third_party_ai_features_enabled).and_return(third_party_ai_features_enabled)
+        end
+
         subject { issuable.send_to_ai? }
 
-        it { is_expected.to eq(send_to_ai) }
+        it { is_expected.to eq(result) }
       end
     end
 
     context 'for merge requests' do
-      where(:visibility, :send_to_ai) do
+      where(:visibility, :third_party_ai_features_enabled, :result) do
         [
-          [Gitlab::VisibilityLevel::PUBLIC, true],
-          [Gitlab::VisibilityLevel::INTERNAL, false],
-          [Gitlab::VisibilityLevel::PRIVATE, false]
+          [Gitlab::VisibilityLevel::PUBLIC, true, true],
+          [Gitlab::VisibilityLevel::PUBLIC, false, false],
+          [Gitlab::VisibilityLevel::INTERNAL, false, false],
+          [Gitlab::VisibilityLevel::INTERNAL, true, false],
+          [Gitlab::VisibilityLevel::PRIVATE, false, false],
+          [Gitlab::VisibilityLevel::PRIVATE, true, false]
         ]
       end
 
+      before do
+        allow(project.namespace).to receive(:third_party_ai_features_enabled).and_return(third_party_ai_features_enabled)
+      end
+
       with_them do
-        let(:issuable) { build_stubbed(:merge_request, project: build_stubbed(:project, visibility_level: visibility)) }
+        let(:project) { build_stubbed(:project, visibility_level: visibility) }
+        let(:issuable) { build_stubbed(:merge_request, project: project) }
 
         subject { issuable.send_to_ai? }
 
-        it { is_expected.to eq(send_to_ai) }
+        it { is_expected.to eq(result) }
       end
     end
   end
diff --git a/ee/spec/models/ee/namespace_spec.rb b/ee/spec/models/ee/namespace_spec.rb
index 81cc2f47a8af64a025feabc71dc6f32383a55fd5..94e81ce03af365349dd76bb55da21ce4bc97ef1e 100644
--- a/ee/spec/models/ee/namespace_spec.rb
+++ b/ee/spec/models/ee/namespace_spec.rb
@@ -33,6 +33,10 @@
   it { is_expected.to delegate_method(:temporary_storage_increase_ends_on=).to(:namespace_limit).with_arguments(:args) }
   it { is_expected.to delegate_method(:temporary_storage_increase_enabled?).to(:namespace_limit) }
   it { is_expected.to delegate_method(:eligible_for_temporary_storage_increase?).to(:namespace_limit) }
+  it { is_expected.to delegate_method(:third_party_ai_features_enabled).to(:namespace_settings).allow_nil }
+  it { is_expected.to delegate_method(:third_party_ai_features_enabled=).to(:namespace_settings).with_arguments(:args).allow_nil }
+  it { is_expected.to delegate_method(:experiment_features_enabled).to(:namespace_settings).allow_nil }
+  it { is_expected.to delegate_method(:experiment_features_enabled=).to(:namespace_settings).with_arguments(:args).allow_nil }
 
   shared_examples 'plan helper' do |namespace_plan|
     let(:namespace) { create(:namespace_with_plan, plan: "#{plan_name}_plan") }
diff --git a/ee/spec/policies/epic_policy_spec.rb b/ee/spec/policies/epic_policy_spec.rb
index 1602148903c5a80d8e5919de6b0d6ea031712cf3..6cbc3d71e6cf11f767d96746499ebff0636b7fb0 100644
--- a/ee/spec/policies/epic_policy_spec.rb
+++ b/ee/spec/policies/epic_policy_spec.rb
@@ -370,12 +370,15 @@
     end
   end
 
-  describe 'summarize_notes' do
-    let_it_be(:group) { create(:group, :private) }
+  describe 'summarize_notes', :saas do
+    let_it_be(:group) { create(:group_with_plan, :private, plan: :ultimate_plan) }
 
     before do
-      stub_licensed_features(summarize_notes: true)
+      stub_ee_application_setting(should_check_namespace_plan: true)
+      stub_licensed_features(summarize_notes: true, ai_features: true)
       stub_feature_flags(summarize_comments: group)
+      group.namespace_settings.update!(experiment_features_enabled: true)
+      group.namespace_settings.update!(third_party_ai_features_enabled: true)
     end
 
     context 'when a member' do
@@ -390,6 +393,22 @@
 
         it { is_expected.to be_allowed(:summarize_notes) }
 
+        context 'when experiment features are disabled' do
+          before do
+            group.namespace_settings.update!(experiment_features_enabled: false)
+          end
+
+          it { is_expected.to be_disallowed(:summarize_notes) }
+        end
+
+        context 'when third party ai features are disabled' do
+          before do
+            group.namespace_settings.update!(third_party_ai_features_enabled: false)
+          end
+
+          it { is_expected.to be_disallowed(:summarize_notes) }
+        end
+
         context 'when license is not set' do
           before do
             stub_licensed_features(summarize_notes: false)
diff --git a/ee/spec/policies/issue_policy_spec.rb b/ee/spec/policies/issue_policy_spec.rb
index 3f8ff592987814286ebd40c8b0974796aa10b41f..3d36e62134b167df9afeb0dea017e1a2116b71e7 100644
--- a/ee/spec/policies/issue_policy_spec.rb
+++ b/ee/spec/policies/issue_policy_spec.rb
@@ -2,152 +2,130 @@
 
 require 'spec_helper'
 
-RSpec.describe IssuePolicy do
+RSpec.describe IssuePolicy, :saas, feature_category: :team_planning do
   let_it_be(:owner) { create(:user) }
-  let_it_be(:namespace) { create(:group) }
-  let_it_be(:project) { create(:project, group: namespace) }
-  let_it_be(:issue) { create(:issue, project: project) }
   let(:user) { owner }
 
   subject { described_class.new(user, issue) }
 
-  before do
-    namespace.add_owner(owner)
+  context 'on group namespace' do
+    let_it_be(:namespace) { create(:group_with_plan, plan: :ultimate_plan) }
+    let_it_be(:project) { create(:project, group: namespace) }
+    let_it_be(:issue) { create(:issue, project: project) }
 
-    allow(issue).to receive(:project).and_return(project)
-    allow(project).to receive(:namespace).and_return(namespace)
-    allow(project).to receive(:design_management_enabled?).and_return true
-  end
-
-  it { is_expected.to be_allowed(:create_issue, :update_issue, :read_issue_iid, :reopen_issue, :create_design, :create_note) }
-
-  describe 'summarize_notes' do
     before do
-      stub_licensed_features(summarize_notes: true)
-      stub_feature_flags(summarize_comments: project)
-    end
+      namespace.add_owner(owner)
 
-    context 'when a member' do
-      context 'on a public project' do
-        before do
-          project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
-        end
+      allow(issue).to receive(:project).and_return(project)
+      allow(project).to receive(:namespace).and_return(namespace)
+      allow(project).to receive(:design_management_enabled?).and_return true
+    end
 
-        it { is_expected.to be_allowed(:summarize_notes) }
+    it { is_expected.to be_allowed(:create_issue, :update_issue, :read_issue_iid, :reopen_issue, :create_design, :create_note) }
 
-        context 'when license is not set' do
-          before do
-            stub_licensed_features(summarize_notes: false)
-          end
+    describe '#rules' do
+      context 'on a group namespace' do
+        before do
+          stub_ee_application_setting(should_check_namespace_plan: true)
+          stub_licensed_features(summarize_notes: true, ai_features: true, generate_description: true)
+          stub_feature_flags(summarize_comments: project, generate_description_ai: project)
 
-          it { is_expected.to be_disallowed(:summarize_notes) }
+          namespace.namespace_settings.update!(experiment_features_enabled: true)
+          namespace.namespace_settings.update!(third_party_ai_features_enabled: true)
         end
 
-        context 'when feature flag is not set' do
-          before do
-            stub_feature_flags(summarize_comments: false)
-          end
-
-          it { is_expected.to be_disallowed(:summarize_notes) }
-        end
+        context 'when a member' do
+          context 'on a public project' do
+            before do
+              project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+            end
 
-        context 'on confidential issue' do
-          let_it_be(:issue) { create(:issue, :confidential, project: project) }
+            it { is_expected.to be_allowed(:summarize_notes) }
+            it { is_expected.to be_allowed(:generate_description) }
 
-          it { is_expected.to be_disallowed(:summarize_notes) }
-        end
-      end
+            context 'when experiment features are disabled' do
+              before do
+                namespace.namespace_settings.update!(experiment_features_enabled: false)
+              end
 
-      context 'on a private project' do
-        let_it_be(:project) { create(:project, :private) }
+              it { is_expected.to be_disallowed(:summarize_notes) }
+            end
 
-        it { is_expected.to be_disallowed(:summarize_notes) }
-      end
+            context 'when third party ai features are disabled' do
+              before do
+                namespace.namespace_settings.update!(third_party_ai_features_enabled: false)
+              end
 
-      context 'on confidential issue' do
-        let_it_be(:issue) { create(:issue, :confidential, project: project) }
+              it { is_expected.to be_disallowed(:summarize_notes) }
+              it { is_expected.to be_disallowed(:generate_description) }
+            end
 
-        it { is_expected.to be_disallowed(:summarize_notes) }
-      end
-    end
+            context 'when license is not set' do
+              before do
+                stub_licensed_features(summarize_notes: false, generate_description: false)
+              end
 
-    context 'when not a member' do
-      let_it_be(:user) { create(:user) }
+              it { is_expected.to be_disallowed(:summarize_notes) }
+              it { is_expected.to be_disallowed(:generate_description) }
+            end
 
-      context 'on a public project' do
-        let_it_be(:project) { create(:project, :public) }
+            context 'when feature flag is not set' do
+              before do
+                stub_feature_flags(summarize_comments: false, generate_description_ai: false)
+              end
 
-        it { is_expected.to be_disallowed(:summarize_notes) }
-      end
+              it { is_expected.to be_disallowed(:summarize_notes) }
+              it { is_expected.to be_disallowed(:generate_description) }
+            end
 
-      context 'on a private project' do
-        it { is_expected.to be_disallowed(:summarize_notes) }
-      end
-    end
-  end
+            context 'on confidential issue' do
+              let_it_be(:issue) { create(:issue, :confidential, project: project) }
 
-  describe 'generate_description' do
-    before do
-      stub_licensed_features(generate_description: true)
-      stub_feature_flags(generate_description_ai: project)
-    end
-
-    context 'when a member' do
-      context 'on a public project' do
-        before do
-          project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
-        end
+              it { is_expected.to be_disallowed(:summarize_notes) }
+              it { is_expected.to be_disallowed(:generate_description) }
+            end
+          end
 
-        it { is_expected.to be_allowed(:generate_description) }
+          context 'on a private project' do
+            let_it_be(:project) { create(:project, :private) }
 
-        context 'when license is not set' do
-          before do
-            stub_licensed_features(generate_description: false)
+            it { is_expected.to be_disallowed(:summarize_notes) }
+            it { is_expected.to be_disallowed(:generate_description) }
           end
 
-          it { is_expected.to be_disallowed(:generate_description) }
-        end
+          context 'on confidential issue' do
+            let_it_be(:issue) { create(:issue, :confidential, project: project) }
 
-        context 'when feature flag is not set' do
-          before do
-            stub_feature_flags(generate_description_ai: false)
+            it { is_expected.to be_disallowed(:summarize_notes) }
+            it { is_expected.to be_disallowed(:generate_description) }
           end
-
-          it { is_expected.to be_disallowed(:generate_description) }
         end
 
-        context 'on confidential issue' do
-          let_it_be(:issue) { create(:issue, :confidential, project: project) }
+        context 'when not a member' do
+          let_it_be(:user) { create(:user) }
 
-          it { is_expected.to be_disallowed(:generate_description) }
-        end
-      end
+          context 'on a public project' do
+            let_it_be(:project) { create(:project, :public) }
 
-      context 'on a private project' do
-        let_it_be(:project) { create(:project, :private) }
-
-        it { is_expected.to be_disallowed(:generate_description) }
-      end
-
-      context 'on confidential issue' do
-        let_it_be(:issue) { create(:issue, :confidential, project: project) }
+            it { is_expected.to be_disallowed(:summarize_notes) }
+            it { is_expected.to be_disallowed(:generate_description) }
+          end
 
-        it { is_expected.to be_disallowed(:generate_description) }
+          context 'on a private project' do
+            it { is_expected.to be_disallowed(:summarize_notes) }
+            it { is_expected.to be_disallowed(:generate_description) }
+          end
+        end
       end
     end
+  end
 
-    context 'when not a member' do
-      let_it_be(:user) { create(:user) }
-
-      context 'on a public project' do
-        let_it_be(:project) { create(:project, :public) }
-
-        it { is_expected.to be_disallowed(:generate_description) }
-      end
+  context 'on a user namespace' do
+    let_it_be(:namespace) { owner.namespace }
+    let_it_be(:project) { create(:project, namespace: namespace) }
+    let_it_be(:issue) { create(:issue, project: project) }
 
-      context 'on a private project' do
-        it { is_expected.to be_disallowed(:generate_description) }
-      end
-    end
+    it { is_expected.to be_disallowed(:summarize_notes) }
+    it { is_expected.to be_disallowed(:generate_description) }
   end
 end
diff --git a/ee/spec/requests/api/graphql/mutations/projects/generate_test_file_spec.rb b/ee/spec/requests/api/graphql/mutations/projects/generate_test_file_spec.rb
index 3ed698de156659c57a7ae9c60d12a0f36281d16b..6dbb1988c208dbdf9af3a3a1c332afacc340d360 100644
--- a/ee/spec/requests/api/graphql/mutations/projects/generate_test_file_spec.rb
+++ b/ee/spec/requests/api/graphql/mutations/projects/generate_test_file_spec.rb
@@ -6,7 +6,8 @@
   include GraphqlHelpers
   include Graphql::Subscriptions::Notes::Helper
 
-  let_it_be(:project) { create(:project, :public) }
+  let_it_be(:group) { create(:group, :public) }
+  let_it_be(:project) { create(:project, :public, group: group) }
   let_it_be(:current_user) { create(:user, developer_projects: [project]) }
   let_it_be(:merge_request) { create(:merge_request, source_project: project) }
   let_it_be(:file_path) { "files/js/commit.coffee" }
@@ -23,6 +24,7 @@
 
   before do
     stub_licensed_features(generate_test_file: true)
+    group.namespace_settings.update!(third_party_ai_features_enabled: true)
   end
 
   it 'successfully performs an explain code request' do
diff --git a/ee/spec/requests/groups/epics_controller_spec.rb b/ee/spec/requests/groups/epics_controller_spec.rb
index 3f5931691d7d12bf201ad48fc4d510514af5e936..a9cbeef35acb889fb7c74dbca98fa38da5159fcf 100644
--- a/ee/spec/requests/groups/epics_controller_spec.rb
+++ b/ee/spec/requests/groups/epics_controller_spec.rb
@@ -38,38 +38,28 @@
     end
 
     context 'for summarize notes feature' do
-      let(:summarize_notes_enabled) { true }
       let(:group) { create(:group, :public) }
 
       before do
-        stub_licensed_features(epics: true, summarize_notes: summarize_notes_enabled)
-      end
-
-      context 'when user is a member' do
-        before do
-          group.add_developer(user)
-        end
+        allow(Ability).to receive(:allowed?).and_call_original
+        allow(Ability).to receive(:allowed?).with(user, :summarize_notes, epic).and_return(summarize_notes_enabled)
 
-        context 'when license is set' do
-          it 'exposes the required feature flags' do
-            get group_epic_path(group, epic)
-
-            expect(response.body).to have_pushed_frontend_feature_flags(summarizeComments: true)
-          end
-        end
+        stub_licensed_features(epics: true)
+      end
 
-        context 'when license is not set' do
-          let(:summarize_notes_enabled) { false }
+      context 'when feature is available set' do
+        let(:summarize_notes_enabled) { true }
 
-          it 'does not expose the feature flags' do
-            get group_epic_path(group, epic)
+        it 'exposes the required feature flags' do
+          get group_epic_path(group, epic)
 
-            expect(response.body).not_to have_pushed_frontend_feature_flags(summarizeComments: true)
-          end
+          expect(response.body).to have_pushed_frontend_feature_flags(summarizeComments: true)
         end
       end
 
-      context 'when user is not a member' do
+      context 'when feature is not available' do
+        let(:summarize_notes_enabled) { false }
+
         it 'does not expose the feature flags' do
           get group_epic_path(group, epic)
 
diff --git a/ee/spec/requests/projects/issues_controller_spec.rb b/ee/spec/requests/projects/issues_controller_spec.rb
index 5278af3faf59ea274f44f404c68453eb9f74f3e2..82919fa9b75483918e9f504db1f02cb915ebe07c 100644
--- a/ee/spec/requests/projects/issues_controller_spec.rb
+++ b/ee/spec/requests/projects/issues_controller_spec.rb
@@ -74,11 +74,13 @@ def get_show
       context 'when user is a member' do
         before do
           project.add_guest(user)
+
+          allow(Ability).to receive(:allowed?).and_call_original
         end
 
-        context 'when license is set' do
+        context 'when feature is available' do
           before do
-            stub_licensed_features(summarize_notes: true)
+            allow(Ability).to receive(:allowed?).with(user, :summarize_notes, issue).and_return(true)
           end
 
           it 'exposes the required feature flags' do
@@ -88,7 +90,11 @@ def get_show
           end
         end
 
-        context 'when license is not set' do
+        context 'when feature is not available' do
+          before do
+            allow(Ability).to receive(:allowed?).with(user, :summarize_notes, issue).and_return(false)
+          end
+
           it 'does not expose the feature flags' do
             get_show
 
diff --git a/ee/spec/services/llm/base_service_spec.rb b/ee/spec/services/llm/base_service_spec.rb
index aa0d4ef6e8ea50a7b9bc070b34c9884927f42787..5631620725bba2b7945588c693e52c0946267a25 100644
--- a/ee/spec/services/llm/base_service_spec.rb
+++ b/ee/spec/services/llm/base_service_spec.rb
@@ -3,8 +3,9 @@
 require 'spec_helper'
 
 RSpec.describe Llm::BaseService, feature_category: :no_category do # rubocop: disable RSpec/InvalidFeatureCategory
+  let_it_be(:group) { create(:group, :public) }
   let_it_be(:user) { create(:user) }
-  let_it_be(:project) { create(:project, :public) }
+  let_it_be(:project) { create(:project, :public, group: group) }
   let_it_be(:resource) { create(:issue, project: project) }
   let(:options) { {} }
 
diff --git a/ee/spec/services/llm/generate_description_service_spec.rb b/ee/spec/services/llm/generate_description_service_spec.rb
index a53c9787dafed506bbd2bea53440ea23359e46ad..06e191400e12aae2666480ad34b0cb45ab35509e 100644
--- a/ee/spec/services/llm/generate_description_service_spec.rb
+++ b/ee/spec/services/llm/generate_description_service_spec.rb
@@ -9,11 +9,16 @@
 
   let(:current_user) { user }
   let(:service) { described_class.new(current_user, resource, {}) }
+  let(:generate_description_license_enabled) { true }
 
   describe '#perform' do
     before do
       stub_licensed_features(generate_description: true)
+      group.namespace_settings.update!(third_party_ai_features_enabled: true)
       group.add_guest(user)
+      allow(Ability).to receive(:allowed?).and_call_original
+      allow(Ability).to receive(:allowed?)
+        .with(user, :generate_description, resource).and_return(generate_description_license_enabled)
     end
 
     subject { service.execute }
@@ -39,7 +44,7 @@
     shared_examples 'ensures license and feature flag checks' do
       using RSpec::Parameterized::TableSyntax
 
-      where(:generate_description_license_flag, :openai_experimentation_ff, :result) do
+      where(:generate_description_license_enabled, :openai_experimentation_ff, :result) do
         true  | true  | true
         true  | false | false
         false | true  | false
@@ -48,7 +53,6 @@
 
       with_them do
         it 'checks validity' do
-          stub_licensed_features(generate_description: generate_description_license_flag)
           stub_feature_flags(openai_experimentation: openai_experimentation_ff)
 
           expect(service.valid?).to be(result)
diff --git a/ee/spec/services/llm/generate_summary_service_spec.rb b/ee/spec/services/llm/generate_summary_service_spec.rb
index 8308a6f444ae55028afc58f8c24bff0dd0892707..4fca95d085d090fecddde4dc98b8b04aa247ef73 100644
--- a/ee/spec/services/llm/generate_summary_service_spec.rb
+++ b/ee/spec/services/llm/generate_summary_service_spec.rb
@@ -7,12 +7,15 @@
   let_it_be(:group) { create(:group, :public) }
   let_it_be(:project) { create(:project, :public, group: group) }
 
+  let(:summarize_notes_enabled) { true }
   let(:current_user) { user }
 
   describe '#perform' do
     before do
-      stub_licensed_features(summarize_notes: true)
       group.add_guest(user)
+
+      allow(Ability).to receive(:allowed?).and_call_original
+      allow(Ability).to receive(:allowed?).with(user, :summarize_notes, resource).and_return(summarize_notes_enabled)
     end
 
     subject { described_class.new(current_user, resource, {}).execute }
@@ -40,18 +43,8 @@
     end
 
     shared_examples 'ensures feature flags and license' do
-      context 'without the correct license' do
-        before do
-          stub_licensed_features(summarize_notes: false)
-        end
-
-        it { is_expected.to be_error.and have_attributes(message: eq(described_class::INVALID_MESSAGE)) }
-      end
-
-      context 'without the feature specific flag enabled' do
-        before do
-          stub_feature_flags(summarize_comments: false)
-        end
+      context 'without the license available' do
+        let(:summarize_notes_enabled) { false }
 
         it { is_expected.to be_error.and have_attributes(message: eq(described_class::INVALID_MESSAGE)) }
       end
diff --git a/ee/spec/services/llm/generate_test_file_service_spec.rb b/ee/spec/services/llm/generate_test_file_service_spec.rb
index 67633a3ea08d2abc31723b5876b424872765fbeb..906a95a27071615388530dc5fbe60a6aaa573e7e 100644
--- a/ee/spec/services/llm/generate_test_file_service_spec.rb
+++ b/ee/spec/services/llm/generate_test_file_service_spec.rb
@@ -3,8 +3,9 @@
 require 'spec_helper'
 
 RSpec.describe Llm::GenerateTestFileService, feature_category: :code_review_workflow do
+  let_it_be(:group) { create(:group, :public) }
   let_it_be(:user) { create(:user) }
-  let_it_be(:project) { create(:project, :public) }
+  let_it_be(:project) { create(:project, :public, group: group) }
   let_it_be(:merge_request) { create(:merge_request, source_project: project) }
   let(:options) { {} }
 
@@ -13,6 +14,7 @@
   describe '#execute' do
     before do
       stub_licensed_features(generate_test_file: true)
+      group.namespace_settings.update!(third_party_ai_features_enabled: true)
       allow(Llm::CompletionWorker).to receive(:perform_async)
     end
 
diff --git a/ee/spec/workers/llm/completion_worker_spec.rb b/ee/spec/workers/llm/completion_worker_spec.rb
index 7bcace047f81f2446d7a3b15d4200f1603d4df9b..eebd4cda6647e998360f2055ddc23c7e83d11502 100644
--- a/ee/spec/workers/llm/completion_worker_spec.rb
+++ b/ee/spec/workers/llm/completion_worker_spec.rb
@@ -9,7 +9,8 @@
 
   describe '#perform' do
     let_it_be(:user) { create(:user) }
-    let_it_be(:project) { create(:project, :public) }
+    let_it_be(:group) { create(:group, :public) }
+    let_it_be(:project) { create(:project, :public, group: group) }
     let_it_be(:resource) { create(:issue, project: project) }
 
     let(:user_id) { user.id }