cd /news/ai-policy/labeling-ai-content-for-russia-s-mar… Β· home β€Ί topics β€Ί ai-policy β€Ί article
[ARTICLE Β· art-167581] src=dev.to β†— pub= topic=ai-policy verified=true sentiment=Β· neutral

Labeling AI content for Russia's March 2027 rules: an engineering checklist

A developer published an engineering checklist for complying with Russia's AI content labeling rules, which take effect 1 March 2027, covering provenance manifests, JSON Schema validation, ExifTool metadata embedding and ffmpeg remuxing. The approach pairs each asset with a single manifest sharing an ID, then derives file metadata, visible labels and HTTP headers from that one source so the provenance record cannot drift or be silently stripped. The author estimates 90–120 minutes for the first asset and about ten minutes for each subsequent one once the schema, metadata commands and CI verification script exist.

by read4 min views1 publishedNov 11, 2026

Russian rules on labeling AI-generated content take effect on 1 March 2027. The legal analysis belongs to someone else; what landed on my desk is the engineering side β€” making sure every asset that leaves the pipeline carries a provenance record both a person and a machine can read, and that it cannot quietly lose that record later. Below is the setup I would hand to another developer.

Budget 90–120 minutes for the first asset. Once the manifest format, the metadata commands and the CI script exist, each additional asset costs roughly ten minutes.

Rule number one: every artifact gets one manifest and one asset file sharing the same ID. That single convention is what makes everything else scriptable β€” checksums, metadata writing and the CI loop all key off the same name.

mkdir -p ai-labeling/{schema,manifests,assets,scripts}
cd ai-labeling
git init
ai-labeling/
β”œβ”€β”€ schema/label.schema.json
β”œβ”€β”€ manifests/img-2027-0001.json
β”œβ”€β”€ assets/img-2027-0001.jpg
└── scripts/verify_labels.sh

Tools to have ready, with the version check I run first:

jsonschema package (pip install jsonschema); confirm with python3 --version. ajv-cli runs through npx, so there is nothing to install globally: check node -v and npx --version. exiftool -ver. ffmpeg -version | head -n 1.$PSVersionTable.PSVersion. The manifest is a plain-text provenance record: what produced the asset, when, and whether a human reviewed it. It exists before any output surface, so the file metadata, the page label and the API header are all derived from one source and cannot drift apart. Writing it first also forces you to capture the model identifier while you still have it β€” copy the exact string from the API response body, never type a model name from memory.

manifests/img-2027-0001.json:

{
  "asset_id": "img-2027-0001",
  "asset_sha256": "<output-of-sha256sum>",
  "created_at": "2027-02-14T10:22:00Z",
  "origin": "ai-generated",
  "model_provider": "<provider-name-from-your-contract>",
  "model_id": "<exact-model-id-returned-by-the-api>",
  "ai_generated_share": 1.0,
  "human_reviewed": true,
  "reviewer": "editor@example.com",
  "reviewed_at": "2027-02-14T11:05:00Z",
  "disclosure": { "visible_label": "AI-generated image", "machine_readable": true }
}

For AI-written text that an editor reworked, keep the same schema and set origin to ai-assisted.

Describe the fields in schema/label.schema.json and make these required: asset_id, asset_sha256, created_at, origin, model_id, ai_generated_share, human_reviewed, disclosure. Then hash the file and validate:

sha256sum assets/img-2027-0001.jpg > checksums.txt
python3 -c "import json,jsonschema;jsonschema.validate(json.load(open('manifests/img-2027-0001.json')),json.load(open('schema/label.schema.json')));print('manifest valid')"

Confirm the schema actually enforces something: the terminal should print manifest valid. Then copy the manifest, remove model_id, validate the copy, and check that you get a ValidationError naming that field. A schema that never fails is decoration.

Three different readers need three different surfaces. Metadata inside the file survives download and re-upload. The visible label is what a human sees. An HTTP header is what an automated client sees. A caption alone vanishes the moment someone embeds the image elsewhere, and metadata alone is invisible to a reader β€” ship both.

Image metadata with ExifTool (-overwrite_original keeps .jpg_original backups out of your build output):

exiftool -overwrite_original \
  -XMP-dc:Description="AI-generated image. Model: <model-id>. Provenance: /provenance/img-2027-0001.json" \
  -XMP-xmpMM:DocumentID="img-2027-0001" \
  assets/img-2027-0001.jpg

For video, -codec copy remuxes without re-encoding, so quality is untouched and the job finishes in seconds:

ffmpeg -i assets/clip-2027-0002.mp4 -codec copy \
  -metadata comment="AI-generated video; provenance clip-2027-0002" \
  assets/clip-2027-0002.labeled.mp4

Page markup β€” one tag for machines, one sentence for people:

<meta name="ai-generated" content="true">
<p class="ai-disclosure">AI-generated image. <a href="https://dev.to/provenance/img-2027-0001.json">Provenance record</a></p>

And on every API endpoint that returns generated text, image or audio:

X-AI-Generated: true
X-AI-Provenance: /provenance/img-2027-0001.json

If your provider supports embedded, signed provenance manifests, sign the file with c2patool instead of plain XMP. Flag names and signing-key setup change between releases, so read the current docs and pin the version you used.

Check both surfaces: exiftool -s3 -XMP-dc:Description assets/img-2027-0001.jpg should print the description line, and curl -sI https://<your-domain>/api/render | grep -i x-ai-generated should return x-ai-generated: true.

Labels disappear quietly. Design tools, image optimizers and CDN pipelines strip XMP blocks without complaint, and nobody notices until someone else does. A failing build is the only reminder that survives a team change.

scripts/verify_labels.sh:

#!/usr/bin/env bash
set -euo pipefail
npx ajv-cli validate -s schema/label.schema.json -d "manifests/*.json" --errors=text
sha256sum -c checksums.txt
for f in assets/*.jpg; do
  exiftool -s3 -XMP-dc:Description "$f" | grep -q "AI-generated" \
    || { echo "MISSING LABEL: $f"; exit 1; }
done
echo "all labels verified"

Wire it into CI as a single step running bash scripts/verify_labels.sh, and make that step required for merges.

Check it end to end: three lines should appear in order β€” manifests/img-2027-0001.json valid, assets/img-2027-0001.jpg: OK, all labels verified. Then copy an asset, strip it with exiftool -all= assets/test-unlabeled.jpg, re-run the script and confirm you see MISSING LABEL: assets/test-unlabeled.jpg followed by echo $? printing 1.

Scope is a legal question, not a build question. Which of your outputs fall under the rules, which exemptions apply, and the exact wording of the disclosure all have to be confirmed against the current regulation text with your legal team before you ship anything. Everything above covers only the mechanics of producing and enforcing the label.

model_id from the API response at generation time, not from memory. This article was originally published on AI Release β€” https://ai-release.org. Shorter, recurring notes on tooling and compliance work like this show up in the channel at https://t.me/ai_release1.

── more in #ai-policy 4 stories Β· sorted by recency
── more on @russia 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/labeling-ai-content-…] indexed:0 read:4min 2026-11-11 Β· β€”