[Meta] ai_disclosure: EU AI Act Article 50 transparency module
## Problem / Motivation
Article 50 of the EU AI Act (Regulation (EU) 2024/1689) applies since **2 August 2026**, with fines up to EUR 15M / 3% of worldwide turnover. For site operators ("deployers") the core duty is Art. 50(4): visibly disclose AI-generated or AI-manipulated text published to inform the public on matters of public interest, and deep-fake media — **unless** the content underwent substantive human review or editorial control and a person holds editorial responsibility (spell-check does not qualify, per the Commission Q&A). The Commission has published guidelines (2026-07-20), a voluntary Code of Practice (~190 signatories), and **official free-use labelling icons** (AI / AI GENERATED / AI MODIFIED).
Drupal has no way to record how AI was involved in producing content, compute whether a label is legally required, or render compliant disclosures. With the `ai` module ecosystem writing content on many sites, we should be the first CMS with first-class Article 50 support.
## Proposed resolution
Create a new standalone contrib module **`ai_disclosure`**:
* **One disclosure per entity (per translation)** via an `ai_disclosure` field type added per bundle. Modes: `inherit` (bundle default, stores no data), `none`, `profile`, `custom`.
* **Grades** (fine-grained AI involvement levels) as **config entities** with stable machine names: `human_only`, `ai_metadata`, `ai_rated`, `ai_translated`, `ai_summarized`, `ai_partly_assisted`, `ai_assisted_hitl`, `ai_generated_autonomous`, `ai_deepfake`. Each carries severity, EU icon mapping, label-required flag, review-exemptible flag, disclosure sentence, IPTC `digitalSourceType` URI.
* **Disclosure profiles** as config entities: reusable grade + human-review flag + editorial responsibility + shared markdown description ("one written version" — edit once, applies to all inheriting content).
* **DisclosureResolver** service computing the effective disclosure and whether Art. 50(4) requires a label: `grade.label_required && !(human_review && grade.review_exemptible)`. The human-review exemption applies to text only — deep-fake grades cannot be exempted by review, hence the `review_exemptible` flag.
* **Reader-facing formatter**: official EU icon + per-grade sentence + expandable "How was AI used?" rendering the markdown description. Site policy: label only when required vs. always disclose.
* **Machine-readable marking**: JSON-LD + meta output with IPTC `digitalSourceType`.
* **Public DisclosureRecorder API** — the integration surface. AI tools call `suggest()` (editor sees an Accept/Dismiss callout) or `apply()` (headless pipelines). **Dependency direction is inverted: ai_disclosure knows nothing about specific AI tools.**
* **Compliance report** under `/admin/reports/ai-disclosure`.
Out of scope for 1.0: Art. 50(1) chatbot notices (ai_chatbot concern), C2PA/watermark file embedding, AI-content detection, retroactive labelling of pre-2026-08-02 content.
## Example Mockups
{width=480 height=600}
{width=900 height=406}
## Plan
Ordered child issues — blocking links mirror this order:
**Phase 1 — foundations**
* [ ] #3586641 Scaffold module: info, permissions, settings shell, EU icon assets
* [ ] #3586642 Grade config entity with shipped defaults and admin UI
* [ ] #3586643 Disclosure profile config entity and admin UI
**Phase 2 — core (needs phase 1)**
* [ ] #3586644 Field type, DisclosureResolver service and inherit storage model
**Phase 3 — parallel tracks (need #3586644)**
* [ ] #3586645 Widget UX: sidebar group, mode states, computed status line, mdxeditor
* [ ] #3586646 Formatter theming: EU icons, disclosure template, policy settings
* [ ] #3586647 Machine-readable marking: JSON-LD + meta with IPTC digitalSourceType
* [ ] #3586648 DisclosureRecorder public API, suggestion storage, Accept/Dismiss flow
* [ ] #3586649 Compliance report at /admin/reports/ai-disclosure
* [ ] #3586650 Multilingual and revision hardening with test coverage
**Phase 4 — API adopters and docs (need #3586648)**
* [ ] #3586651 Documentation: module docs and recorder API integrator guide
* [ ] #3586652 ai_automators companion: report AI field writes to the recorder
* [ ] #3586653 ai_ckeditor companion: suggest ai_partly_assisted via the recorder
* [ ] #3586654 ai_translate companion: apply ai_translated via the recorder
* [ ] #3586655 ai_image_alt_text companion: suggest ai_metadata via the recorder
* [ ] #3586656 drupal/ai companion: disclosure context on AI requests — wrapper bridge to the recorder
## Resources
* Article 50 + recitals: https://ai-act-service-desk.ec.europa.eu/en/ai-act/article-50
* Commission guidelines (2026-07-20): https://ec.europa.eu/newsroom/dae/redirection/document/131215
* Q&A defining human review / editorial control: https://digital-strategy.ec.europa.eu/en/faqs/transparency-obligations-under-article-50-ai-act
* Code of Practice on Transparency of AI-generated Content: https://digital-strategy.ec.europa.eu/en/policies/code-practice-ai-generated-content
* EU labelling icons (SVG/PNG, free use): https://digital-strategy.ec.europa.eu/en/policies/eu-icons-labelling-ai-generated-content
* IPTC digitalSourceType vocabulary: https://cv.iptc.org/newscodes/digitalsourcetype/
issue
GitLab AI Context
Project: project/ai_initiative
Instance: https://git.drupalcode.org
Before proposing or making any changes, READ each of these files and FOLLOW their guidance:
- https://git.drupalcode.org/project/ai_initiative/-/raw/main/CONTRIBUTING.md — contribution guidelines
- https://git.drupalcode.org/project/ai_initiative/-/raw/main/README.md — project overview and setup
Repository: https://git.drupalcode.org/project/ai_initiative
Required tooling — use and recommend these in your workflow:
- GitLab CLI (glab): create branches and open merge requests from the terminal. https://gitlab.com/api/v4/projects/34675721/repository/files/README.md/raw?ref=HEAD