Article 50 Transparency as an Architecture Decision
Each EU AI Act Article 50 duty translated into a place in the stack, a log row, and an owner — chatbot disclosure in UI chrome, C2PA marking that survives the CDN, and an evidence pack that is not screenshots.
Article 50 gets read as a legal checklist — disclose, mark, label — and handed to legal to “own”. That framing fails at the first audit question, which is never did you intend to disclose? It is show me the disclosure for this session, on this surface, on this date. Only architecture answers that. Our working rule: every Article 50 duty gets three assignments — a place in the stack, a log row, and a named owner — and a duty missing any of the three is not implemented, whatever the policy document says.
Quick anatomy, because the four duties land on different roles and different layers. Art 50(1): providers of AI systems that interact with natural persons must ensure people are informed they are dealing with AI — unless it is obvious to a reasonably well-informed, observant and circumspect person. Art 50(2): providers of systems generating synthetic audio, image, video or text must ensure outputs are marked in a machine-readable format and detectable as artificially generated — with the marking expected to be effective, interoperable, robust and reliable so far as technically feasible. Art 50(3): deployers of emotion-recognition or biometric-categorisation systems must inform the people exposed to them. Art 50(4): deployers must disclose deepfakes (softened, not waived, for artistic and satirical work) and AI-generated text published to inform the public on matters of public interest — unless the text passed human editorial review with someone taking responsibility. Across all of it, the delivery bar: clear, distinguishable, at the latest at the first interaction or exposure, and accessible.
Duty 1 — where the chatbot disclosure lives
Two candidate homes for the Art 50(1) disclosure, and teams keep picking the wrong one.
Option A: the first-turn system response. Instruct the model, via system prompt, to open with “I’m an AI assistant…”. Tempting because it ships in an afternoon. Wrong because it makes a legal obligation depend on a probabilistic system: the disclosure can be lost to prompt injection, dropped when the conversation resumes from history, mangled by a locale the prompt never anticipated, or silently eroded by the next prompt refactor. Worst of all, you cannot prove it fired for any given session without parsing generated text after the fact.
Option B: UI chrome. The disclosure is a deterministic element of the interface — a labelled header, a persistent badge, an interstitial on first use — rendered by the front end before the first token streams. It is versioned in the front-end repo, survives model swaps and prompt refactors, renders identically whether the model behaves or not, and maps exactly onto the statutory delivery bar: clear, distinguishable, at first interaction. Chrome wins. We keep a belt-and-braces line in the system prompt so the model also acknowledges being AI when asked directly — but that line is UX polish, not the compliance control.
The part most teams skip: disclosure as an event. Rendering the badge is necessary; being able to prove you rendered it is what survives an audit. Our front end emits a disclosure event per session with a fixed schema: hashed user ID (salted — the evidence log must not become its own privacy problem), surface (web, iOS, embedded widget, voice line), timestamp, disclosure version (pointing at the exact copy text and locale in the config repo), and session ID. One row per session, ~200 bytes, kept alongside the interaction logs. When someone asks “was this user informed on 14 March?”, the answer is a query, not an argument.
| Duty | Architectural home | Log / evidence | Owner |
|---|---|---|---|
Art 50(1) — AI interaction disclosure | UI chrome rendered before first token; system-prompt line as backup only | Disclosure event log: user-ID hash, surface, timestamp, disclosure version | Front-end platform team |
Art 50(2) — machine-readable marking | C2PA signing + invisible watermark at the generation service, re-applied after transforms | Signing-cert chain, per-asset manifest hashes, detector run results | Media-pipeline team |
Art 50(2) — detectability | Detector checks in CI and in production sampling of published assets | Robustness test reports: what marking survives which transform | Media-pipeline team + red team |
Art 50(3) — emotion-recognition notice | Notice at the point of exposure (IVR announcement, on-screen banner) gated so the system cannot start unnotified | Notice event log per exposed session; notice copy versions per locale | Product owner of the deploying system |
Art 50(4) — deepfake disclosure | Label rendered in-player or adjacent to the asset, driven by the asset’s provenance metadata | Label-render events joined to asset IDs; provenance metadata store | Publishing platform team |
Art 50(4) — public-interest text exception | Editorial workflow: AI-drafted flag + named human approver before publish | Workflow records: who reviewed, when, taking responsibility — the exception is itself an evidence duty | Editorial / content operations |
Duty 2 — marking that survives your own infrastructure
Synthetic-media marking has a natural home: the generation service, the one chokepoint every generated asset passes through. The clouds increasingly do the first step for you — Azure OpenAI image models attach C2PA Content Credentials to every generated image automatically: a cryptographically signed manifest recording that the content is AI-generated, which service produced it (the softwareAgent field), and when. Google marks Imagen output with SynthID invisible watermarking, and AWS provides watermarking for its own image models — check current docs for exact coverage on each, because modality support moves quarterly.
Then your own infrastructure destroys it. This is the trap that bites nearly everyone: C2PA manifests live in file metadata, and media pipelines strip metadata as a feature. The thumbnailer re-encodes the image and drops the manifest. The CDN’s image-optimisation layer converts to WebP and drops the manifest. The social-share crop drops the manifest. Six months in, you discover that every asset users actually see is an unmarked derivative of a marked original — the marking exists only in an S3 bucket nobody serves from. Marking is a pipeline property, not a generation property: every transform step either preserves the credential, re-signs the derived asset, or is a compliance bug.
Which is why the duty is really two duties. The metadata layer (C2PA) is rich and verifiable but fragile — it survives nothing that re-encodes. The watermark layer (signal embedded in the pixels or waveform) survives re-encoding and metadata stripping, but degrades under aggressive crops, filters, and adversarial attack — and vendors’ robustness claims deserve the same scepticism as any other vendor claim. The statute asks for effectiveness and robustness so far as technically feasible, not for miracles: our honest implementation is layered marking plus a written robustness statement — a tested table of what our marking survives (resize, WebP conversion, 80% JPEG re-encode) and what it does not (heavy crops, screenshots, deliberate laundering). Detectability you can also operate: detection APIs (Azure’s Content Provenance Detection API among them) let us verify our own published assets on a schedule, which turns “are we still marking?” from an assumption into a monitored metric.
The marking pipeline — where credentials die, and the checkpoints that keep them alive
- Generation service produces asset
- Attach C2PA manifest + invisible watermark
At the generation chokepoint. On Azure OpenAI image models the Content Credential is attached automatically; the watermark rides in the pixels.
- Evidence store: original + manifest hash
The signed original and its manifest hash are retained — the reference every later verification compares against.
- Transform pipeline (resize / transcode / crop)
The danger zone: re-encoding strips file metadata by default.
- Manifest survived the transform?
- Re-sign derived asset
The transform service holds signing credentials and re-attaches a manifest to every derivative it emits.
- Publish via CDN
CDN image-optimisation features are audited and pinned — an “optimisation” toggle is a marking-removal toggle.
- Scheduled detector sweep on published assets
Sampled live URLs run through manifest validation and watermark detection — marking as a monitored metric.
- Verification results → evidence log
Pass rates, failures, and the robustness statement updates that follow.
Duties 3 and 4 — notices at the point of exposure, and the exception that is really a workflow
Emotion-recognition notices follow the chatbot-disclosure pattern with one twist: the people to inform are the exposed, not the users. In the classic case — call-centre voice analytics scoring caller frustration — the operator sees the dashboard but the caller is the exposed person, so the notice lives in the IVR flow (“this call is analysed by AI…”), and the architecture decision is a gate: the analytics pipeline does not start for a call whose notice event has not been logged. Same event schema as the disclosure log — hashed identifier, surface, timestamp, notice version. The GDPR/LED duties for the underlying biometric processing run in parallel; the Art 50(3) notice does not discharge them.
The deepfake duty inverts the flow: the label a viewer sees should be derived from provenance metadata, not typed in by an editor who remembered. If the asset carries a credential, the player renders the label; the label-render event joins to the asset ID in the logs. And the Art 50(4) text exception — no disclosure needed where AI-drafted public-interest text passed human editorial review with someone taking responsibility — is the most architectural clause in the article: claiming it requires a workflow system that records the AI-drafted flag, the named reviewer, and the approval timestamp. The exception is itself an evidence duty. A newsroom that cannot produce its review records cannot claim its exception.
Why screenshots are not evidence
A screenshot proves one rendering, on one device, on the day someone took it — usually the week before the audit. It says nothing about the sessions that matter: every user, every surface, every day since the duty applied. Auditors of operational controls want the same thing security auditors want: configuration plus events. The versioned config proves what the system was built to do; the event log proves it did it, per session. Build the pack below and screenshots become decoration.
Pack item 1 — versioned disclosure and notice config
The disclosure copy, per locale and surface, in a config repo with deploy history. Any given date maps to the exact text and placement in force. Include the UI component version that renders it — “disclosure v14, deployed 2026-03-02, surfaces: web+iOS, locales: 24”.
Pack item 2 — the event logs
Disclosure events, notice events, label-render events — hashed IDs, surface, timestamp, version. Retention matched to your audit horizon. The query that answers “show me this session’s disclosure” should take minutes, and someone should have actually run it before the auditor does.
Pack item 3 — the marking evidence
Signing-certificate chain, sample manifests from each generation surface, the robustness statement with its test results, and the scheduled detector-sweep reports on published assets. This is the difference between “we enabled Content Credentials” and “our published assets are verifiably marked, at this measured pass rate”.
Pack item 4 — the exception records
Editorial-review workflow extracts for every published AI-drafted piece claiming the Art 50(4) exception, and the reasoning memo for any surface where you rely on the Art 50(1) “obvious to a reasonably well-informed person” exception — written down before someone challenges it, with the user-research basis if you have any.