feat: #3631526 Let site builders attach one of their guardrail sets on a Safety tab

Issue: #3631526 "Initialize the AI Media module"

Chunk 7 of the UX and integration plan (20 October 2026): the Safety tab and the guardrail set setting (plan section 2.2).

Depends on !13 (closed) (3631526-context-consumer), which depends on !12 (closed), !11 (closed), !10 (closed), !9 (closed), !8 (closed) and !6 (merged). Until those merge, this diff includes them; the change of this MR is its last commit.

What changed

  • New Safety tab on the settings page:
    • "Guardrail set for AI Media requests": a select of the site's guardrail sets (ai.guardrail_helper's repository), empty option "None (global guardrails still apply)". Same shape as AI Agents and AI Automators.
    • Links to Global guardrails and Guardrail sets, and to the AI moderation settings, shown when the user may open them, one per line.
    • The plan's wording: built-in guardrails check text requests only (image and video descriptions are checked by moderation and the provider); add an AI External Moderation rule with the tag ai_media for a provider without built-in moderation; generated images and videos are not moderated, and editors review every result.
  • The chosen set is attached to every AI Media call (generation and "Ask AI") in AiMediaRequest::send(), with applyGuardrailSetToChatInput(); the stop detection from !8 (closed) then covers it. "None" relies on the globals.
  • Stored as guardrail_set (string, nullable, ConfigExists: prefix: 'ai.ai_guardrail_set.'), null in config/install. No update hook.
  • AI Media adds no guardrail plugin, set, moderation or validation of its own. The settings docs describe the tab, including AI Validations for sites that want checks on saved images.

How it was tested

  • Kernel: with no global set, a document with the stop word generates; with the set chosen, the same request is stopped. The schema accepts null and an existing set and refuses an unknown ID. All 26 Kernel tests pass.
  • Plain Drupal 11.4 (aimplan1): choosing a set that is not global on the tab and saving attaches it (the stop message for administrators lists it next to the global set).
  • axe-core 4.10.2: 0 violations on the Safety tab in Claro, Gin and Default Admin at 1440 and 1920 (the first run flagged the two links side by side for target size; they are now one per line).
  • Varbase E2E, Firefox: 06-01-01-settings (now with a Safety scenario) and 08-01-01-guardrails pass (12 scenarios).
  • phpcs (Drupal, DrupalPractice), phpstan level 1, cspell, eslint, stylelint: clean.

Not tested

  • A guardrail set with post-generate guardrails or a non-deterministic (LLM) guardrail.
  • External moderation rules with the ai_media tag on a real provider.
  • Mobile widths (out of scope).

AI-Generated: Yes. Written with Claude Code (Claude Opus 5.5) under the Drupal AI policy; tested by the author before submission.

Checkpoints:

  • File an issue
  • Addition/Change/Update/Fix
  • Testing to ensure no regression
  • Automated unit testing coverage
  • Automated functional testing coverage
  • UX/UI designer responsibilities
  • Readability
  • Accessibility
  • Performance
  • Security
  • Developer Documentation
  • User Guide Documentation
  • Reviewed by human
  • Code review by maintainers
  • Full testing and approval
  • Credit contributors
  • Review with the product owner
  • Release notes snippet
  • Release

Merge request reports

Loading
Loading