Skip to main content

WAI Extension: Live Moderation

Mirrored from the canonical text at commit f871af55 ().

Status: Draft. Registers the record wai.live.moderation: moderation for rooms. The room authority signs a review policy, WMP1: which event kinds and media are held for review before delivery or reviewed after it, by whom, the deadline of each, the fallback when no decision arrives in time (allow, deny or hold), and the reason codes in use, each with its ground. A moderator’s verdict is a decision event of live-events (§4.11 there), unchanged, followed by a meta event whose payload is this extension’s statement, WMS1: what kind of thing the decision targets (an event, or a media object such as a recorded chunk), the decision it supersedes, its basis (own initiative, a notice, a complaint, or the policy’s fallback), whether automated means detected the content or took the decision, and its ground, explanation and facts. Decisions on one target form a line by digest, so a later decision overrides an earlier one and the outcome of an appeal is a decision too. Anyone can submit a signed notice, WMN1, about an event or an object, and anyone affected a complaint about a decision. A restricted item is withheld, and where it is withheld from a chain, a recording or a clip, its absence is proven by the decisions that restrict it. Each restricting decision maps, deterministically, onto one record of the statement-of-reasons format of the database the European Commission keeps under Regulation (EU) 2022/2065. No new transport. The reference implementation is the live_moderation module of wai-rs (feature live_moderation); the corpus is live-conformance/moderation/, and its second implementation is live-conformance/live_moderation_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.

Texts read for this revision, each pinned to the version named: Regulation (EU) 2022/2065 (OJ L 277, 27.10.2022, p. 1), Articles 16, 17, 20 and 24(5), as the Publications Office serves its only consolidated version, 02022R2065-20221027, with no amending act recorded and no English corrigendum; the DSA Transparency Database’s “API and schema” documentation and its explanation of the statement attributes (transparency.dsa.ec.europa.eu), for the submission schema in force from 1 July 2025, which the documentation’s changelog calls API v2 and which is still submitted at /api/v1/statement, as the database’s published source has it at revision fc3b1fd5 (2026-09-23) of the documentation and revision bf0afeb8 (2026-06-09) of the submission’s validation rules; and Commission Implementing Regulation (EU) 2024/2835, Annex II, whose categories the database uses. An article or paragraph number in this text is the Regulation’s unless it says otherwise.

1. Scope

In scope: the review policy, its signature, its rules and the policy in effect at each instant (§3); the decision event as this extension reads it, the statement, who may decide, lines of decisions and fallback decisions (§4); notices and complaints (§5); the items under review, their states, and what a relay and a sink do with them (§6); verification, with the gaps that restricted items leave explained (§7); the effect of a restriction on a stream, a recording and a clip (§8); and the statement-of-reasons export (§9).

Out of scope: a transport; how a moderator or a classifier reaches a verdict; how a notice or a complaint reaches the room authority; the notification of a submitter or an affected participant (Article 16(5), Article 17(1), Article 20(5)); the submission of a record to the database, which is an authenticated HTTP request this extension does not define; and the restriction of accounts, payments or the provision of a service (Article 17(1)(b) to (d)), which no WAI record expresses. This extension states what the records carry and how they map onto the database’s format. Which decisions a service takes, and which records it submits, is not its subject.

Relationship to the core spec: wai.live.moderation is a record (SPEC §5): a signed record a WAI tool emits and verifies. It names no payload format and is not dispatchable.

Relationship to live-events: this extension changes nothing in it. Its decision payload (§4.11 there) holds a verdict, a target digest and a reason code and no more, so the statement rides in the meta kind, which live-events leaves to applications (§4.2 there), and is bound to its decision by the event chain (§4.2 here), as timed-text’s annotation is bound to its caption. A decision’s target is the digest of an event, as live-events has it, or, where its statement says so, of a media object (§4.1).

Relationship to live-rooms: the room descriptor’s review field (§3.6 there) fixes the room’s review at its creation; a review policy refines it and never contradicts it (§3.5). The moderate power (§3.3 there) is the power to decide.

Relationship to live-recording: a restriction changes what a recording package holds and what a clip presents (§8). A clip’s inclusion proof does not change: it is over the chunks’ descriptors, which a restriction leaves in place.

2. Terms

Integers are little-endian. A digest is SHA-256 (FIPS 180-4), 32 bytes. Ed25519 is RFC 8032’s, verified strictly (SPEC §7 Signatures): a key that fails step 1 or 2 is bad_key, and a signature that fails a later step is bad_signature. A text field is a u16 length and that many bytes, which are UTF-8 (RFC 3629): no overlong form, no surrogate, nothing above U+10FFFF.

3. The review policy

3.1 Layout

fieldsizemeaning
magic4WMP1 (ASCII)
version11 in this revision
room32the room id (live-rooms §3.2)
prev32the digest of the policy this one replaces (§3.4); 32 zero bytes for the first
effective8u64: the room-clock instant from which this policy applies; 0 for the first
reviewers1 + 32 × na u8 count (0 to 16), then each reviewer’s Ed25519 key
flaggers1 + 32 × na u8 count (0 to 16), then each key the authority recognises as a trusted flagger’s (§9.3 source_type)
entries1 + 10 × na u8 count (0 to 32), then each entry: scope (u8), code (u8), mode (u8), deadline_ms (u32), fallback (u8), fallback_reason (u16)
reasons1 + …a u8 count (1 to 64), then each reason code: code (u16), ground (u8), category (u8), reference (text), url (text)
territory1 + 2 × na u8 count (1 to 30), then each state’s code (§9.3 territorial_scope), two ASCII capitals
redresstexthow an affected participant can seek redress (§9.4, Article 17(3)(f))
sig64§3.2

An entry says how items of one kind are reviewed:

A reason code is one entry of the room’s vocabulary:

3.2 Digest and signature

The digest of a policy is SHA-256 over its record from magic through redress. The signature is Ed25519 by the room descriptor’s authority over the 27 bytes wai:live-moderation-policy (ASCII) and 0x01, followed by the bytes the digest covers.

3.3 Reading and rules

A reader reads exactly the bytes it is given as one policy, in the order of §3.1, and refuses at the first of these that holds:

  1. Fewer than 4 bytes: truncated. A magic other than WMP1: malformed. No byte after the magic: truncated. A version other than 1: unknown_version.
  2. The bytes end before a field the layout requires: truncated.
  3. Bytes after sig: malformed.

It then holds the policy to these rules, and refuses one that breaks any of them as policy_malformed:

Then, in the steps of §7.2: its room is the room id (wrong_room); its signature verifies (bad_key, bad_signature); its link (§3.4, policy_unlinked); and the room’s review field (§3.5, policy_conflicts_room).

3.4 The policy in effect

A verifier is given a room’s policies in a list. The first has prev zero and effective 0. Each later one has as prev the digest of the one before it in the list, and an effective above that one’s. A policy that breaks this is refused policy_unlinked. The policy in effect at room-clock instant t is the last of the list whose effective is at or below t. A room given no policy has none in effect at any instant.

A policy is replaced, never amended: the authority signs a new one, chained to the old, with the instant it takes effect. Each item is reviewed under the policy in effect at its t, and each decision is checked against the policy in effect at the decision’s t.

3.5 The room’s review field

The room descriptor’s review field (live-rooms §3.6) names the event kinds held for review, one deadline and one fallback, allow or deny; the room id commits to it, so every principal that joined the room joined under it. Every policy of the room MUST keep it: for each kind that field names, the policy has an entry of scope 1 for that kind, with mode 1 (pre), the field’s deadline_ms and the field’s fallback. Otherwise policy_conflicts_room. A policy may add entries for other kinds and for media, and name reviewers, flaggers and the vocabulary, which the field does not hold.

4. Decisions

4.1 The decision event

A decision is a decision event (live-events §4.11): verdict (1 allow, 2 deny, 3 redact), target (32 bytes) and reason (u16). Its statement (§4.2) says what target names:

A decision without a statement targets an event, supersedes nothing, and is of the moderator’s own initiative.

Verdicts:

A restriction lasts until a later decision of its line supersedes it. A restriction for a set time is a decision and, at the time’s end, an allow that supersedes it.

4.2 The statement

A decision’s statement is the payload of a meta event whose first four bytes are WMS1, by the same principal, at the decision’s seq + 1 and at the decision’s t.

offsetsizefieldmeaning
04magicWMS1 (ASCII)
41version1 in this revision
51target_type1 an event, 2 a media object (§4.1)
632target_prevfor an event: the target’s prev (live-events §3.1), so that a chain withholding it stays linked (§7.3); for an object: 32 zero bytes
3832supersedesthe digest of the decision event this one supersedes (§4.5); 32 zero bytes for none
701basis1 the moderator’s own initiative, 2 a notice, 3 a complaint, 4 the policy’s fallback (§4.6)
7132noticefor basis 2 and 3: the digest of the notice or complaint it answers (§5); otherwise 32 zero bytes
1031automatedbit 0: the content was detected or identified by automated means; bits 1 and 2: how far the decision was taken by automated means, 0 not, 1 partially, 2 fully; every other bit 0
1041ground1 illegal content, 2 incompatible with the terms
105textground_refthe legal provision or the clause of the terms relied on; empty when the reason code’s reference is the one
…textexplanationwhy the item is considered illegal, or incompatible, on that ground
…textfactsthe facts and circumstances relied on in taking the decision

4.3 Reading a statement

A statement is refused statement_malformed when: it ends before a field or holds bytes after facts; its version is not 1; target_type is not 1 or 2; target_type is 2 and target_prev is not zero; basis is not 1 to 4; notice is zero for basis 2 or 3, or not zero for basis 1 or 4; automated sets a bit above bit 2, or bits 1 and 2 read 3; basis is 4 and automated’s bits 1 and 2 do not read 2, or supersedes is not zero; ground is not 1 or 2; or a text field is not UTF-8.

The meta payload is bounded by the principal’s policy (live-events §5, max_payload), 1024 bytes by default, which bounds the three texts together.

4.4 Who decides

A decision is the event of a moderator. The room verifier already holds every decision to it: a grant whose policy permits decision has the moderate power (live-rooms §3.3, §4.3 step 5), and a participant’s event is verified under its grant in effect at its t (live-rooms §9.2 step 4). A decision by a principal without the moderate power is therefore refused by the room, kind_not_permitted, before this extension reads it. A room key decides as the authority, without a grant.

Where the target is an item a policy reviews (§6.1) and the policy in effect at the decision’s t names reviewers, the decider is one of them or a room key: otherwise not_reviewer.

4.5 Lines: superseding by digest

The decisions on one target form one line. The first supersedes none; each later decision names in supersedes the line’s last decision before it, so that it overrides it from its own t. A verifier checks each decision, in the merged order, against the line as it stands:

An appeal is a complaint (§5) against a decision, and its outcome is a decision of basis 3 that supersedes the decision complained of and names the complaint. It may reverse that decision (allow after deny) or confirm it.

4.6 Fallback decisions

At an item’s deadline with no decision, its entry’s fallback applies (§6.2) whether or not any record says so. A room key SHOULD sign it, as a fallback decision at or after the deadline: basis 4, automated fully, supersedes zero, the entry’s fallback as its verdict (1 allow, 2 deny) and the entry’s fallback_reason as its reason. A fallback decision lets a subscriber that never received the item explain its absence (§7.3), and gives the restriction a signed record to export (§9). A fallback of hold has no decision: the item waits.

A fallback decision is refused fallback_not_in_policy when: its author is not a room key; its target is not an item reviewed under an entry whose fallback is allow or deny; or its verdict is not that fallback, or its reason not the entry’s fallback_reason. It is refused fallback_early when its t is before the item’s deadline. It supersedes nothing (§4.3), so a target that already has a decision refuses it by its line (§4.5, supersede_gap): a decision by the deadline forestalls the fallback.

5. Notices and complaints

5.1 Layout

A notice (Article 16) says that an item is illegal content, or incompatible with the terms; a complaint (Article 20) contests a decision. Anyone can sign one with a key of their own; neither needs a grant of the room.

fieldsizemeaning
magic4WMN1 (ASCII)
version11 in this revision
room32the room id
type11 a notice, 2 a complaint
target_type1a notice: 1 an event, 2 a media object (§4.1); a complaint: 1, the decision event complained of
target32the target’s digest: the exact location of the information (Article 16(2)(b))
t8u64: the room-clock instant at which it was submitted
ground1a notice: 1 illegal content, 2 incompatible with the terms; a complaint: 0
good_faith11: the submitter confirms its bona fide belief that what it states is accurate and complete (Article 16(2)(d)); 0: it does not
ground_reftextthe provision or clause the submitter cites; may be empty
statementtextthe submitter’s explanation of its reasons (Article 16(2)(a)), or of its complaint
contacttextthe submitter’s name and email address (Article 16(2)(c)); may be empty
submitter32the Ed25519 key that signs it
sig64§5.2

5.2 Digest, signature and rules

The digest is SHA-256 over the record from magic through submitter. The signature is Ed25519 by submitter over the 27 bytes wai:live-moderation-notice (ASCII) and 0x01, followed by the bytes the digest covers.

A reader reads it as §3.3 steps 1 to 3 read a policy, with WMN1 for WMP1, and refuses as notice_malformed one in which: type is not 1 or 2; a notice’s target_type is not 1 or 2, or its ground not 1 or 2; a complaint’s target_type is not 1 or its ground not 0; good_faith is not 0 or 1; a text field is not UTF-8; or whose digest is an earlier notice’s in the list. Then its room is the room id (wrong_room), and its signature verifies (bad_key, bad_signature).

A decision of basis 2 names a notice (type 1) and one of basis 3 a complaint (type 2) that the verifier is given, otherwise notice_unknown. A notice’s target is the decision’s target, and its target_type the statement’s; a complaint’s target is the decision the answering decision supersedes; and its t is at or before the decision’s t. Otherwise notice_mismatch. A complaint may be submitted by anyone the decision affects, the participant whose item it restricts or the submitter of the notice it answers among them; this extension does not check who.

contact is personal data. No export carries it (§9.7).

6. Review

6.1 Items

An item under review is:

Its entry gives its mode, its deadline, t + deadline_ms × 1000, and its fallback. An item that is not under review but that a decision targets is an item too, with no entry.

6.2 States

An item’s state at room-clock instant x, from its t on, is:

  1. when a decision on it has its t at or below x: the verdict of the last such decision of its line, allowed, denied or redacted;
  2. otherwise, an item with no entry: shown;
  3. otherwise, before its deadline: held in mode pre, pending in mode post;
  4. otherwise (at or after the deadline, with no decision): fallback_allow, fallback_deny or fallback_hold, by its entry’s fallback.

The fallback applies at the deadline unless a decision other than a fallback decision (§4.6) has its t at or below the deadline; a fallback decision records the fallback, and does not forestall it.

An item is visible in the states shown, pending, allowed and fallback_allow, and withheld in every other. A decision decides an item from its own t whatever came before it, so a moderator’s decision after a fallback overrides the fallback, and an appeal’s outcome overrides the decision it supersedes. A moderator’s decision at the deadline itself is a decision by the deadline, and no fallback applies.

An item’s timeline is the sequence of its states from its t: one entry at its t, one at its deadline when the fallback applies, and one at each decision on it in the merged order. The entries are in the order of their instants and, at one instant, in that order (the item’s, the fallback’s, the decisions’). Each entry is the instant, the state, the decision’s digest where a decision made it, and whether the state is visible. The item’s state at an instant is that of its last entry at or before it.

6.3 What a relay does

A relay that delivers a room’s tracks under a policy applies it to each subscriber session:

A relay that signs fallback decisions (§4.6) does so as the room’s clock.

6.4 What a sink shows

A sink shows an item at instant x only when its state at x is visible, by the decisions it holds. Holding a decision’s event and statement, it SHOULD NOT show what the decision restricts (live-events §4.11). A sink that holds a decision but not its target shows nothing of the target, and states the decision’s verdict and reason in its place where it shows the chain. A sink that labels a restriction for a viewer takes the label from the statement and the reason code’s vocabulary entry, never from the target’s content.

7. Verification

7.1 Inputs

A moderation verifier is given what a room verifier is given (live-rooms §9.1: a descriptor, grants, a key-log head or none, and the chains), and:

7.2 Steps

It runs these steps and stops at the first refusal, which it reports with the reason and where:

  1. The room (live-rooms §9): a refusal is the moderation verifier’s, at room with the room verifier’s own place. A gap is not a refusal: the steps go on, and §7.3 says which gaps decisions explain.
  2. The policies, in the list’s order (§3.3, §3.4, §3.5): the refusal, at the policy’s index.
  3. The notices, in the list’s order (§5.2): the refusal, at the notice’s index.
  4. The statements. For each meta event the room accepted whose payload begins with WMS1, in the merged order: when its seq is 0, statement_misplaced; when the verifier holds its principal’s event at seq − 1, that is a decision at the same t, otherwise statement_misplaced; when the verifier does not, the statement is an orphan of a delivery gap, and is read no further. A statement in place reads (§4.3), otherwise statement_malformed. At the statement’s record.
  5. The gaps (§7.3): which gaps restricted items explain. No refusal.
  6. The decisions, in the merged order, each by §7.4: the refusal, at the decision’s record.
  7. The outcome (§7.5).

A gap remains when the room has a gap that §7.3 does not explain. With a gap remaining, a check of §7.4 that fails because the verifier does not hold a decision, an event or a statement is unresolved, which is not a refusal; with none, it is the refusal the check names.

7.3 Explained gaps

A gap of principal P, seqs a to b (live-events §6.2), is explained when the verifier holds P’s event at b + 1, and walking back from it reaches P’s event at a − 1 (or the start of the chain, when a is 0) through restricted events only:

  1. D is the prev of the event at b + 1.
  2. For each s from b down to a: of the decisions the room accepted whose target is D, the last in the merged order has a statement of target_type 1 and a restricting verdict, otherwise the gap is not explained; seq s is withheld by that decision, and D becomes its statement’s target_prev.
  3. D is then the digest of the event at a − 1, or 32 zero bytes when a is 0; otherwise the gap is not explained.

Each step is checked from what the verifier holds: the link from the gap to the event after it is the event’s own prev, and each link inside the gap is a moderator’s signed statement about an event it decided on, so no event is passed off as withheld that its chain does not hold at that place. An explained gap is not a delivery gap. A gap that is not explained stays one, with live-events’ code delivery_gap.

The events an explained gap withholds are withheld targets: the verifier knows their digests and their places, not their kinds or their times.

7.4 Each decision

For a decision E of principal P, with target X, in the merged order, its statement being P’s event at seq + 1 when that is a statement in place (step 4), unknown when the verifier does not hold that seq because a gap remains there, and none otherwise:

  1. The reason. A policy is in effect at E’s t, its vocabulary has E’s reason, and a known statement’s ground is that code’s: otherwise reason_not_in_policy.
  2. The target.
    • Of type 2: an object the verifier is given has digest X and a t at or below E’s: otherwise target_unknown.
    • Of type 1 (or with no statement): when X is the digest of an event the room accepted, that event comes before E in the merged order, otherwise target_unknown; it is of a decidable kind, otherwise target_not_decidable; and a known statement’s target_prev is its prev, otherwise target_prev_mismatch. When X is a withheld target (§7.3), these hold. Otherwise target_unknown, unresolved while a gap remains.
  3. The reviewer (§4.4): not_reviewer. Not made for a withheld target.
  4. The line (§4.5): supersede_gap, supersede_unknown (unresolved while a gap remains) or supersede_mismatch. Not made for an unknown statement; with none, supersedes is zero.
  5. The basis, for a known statement: of basis 2 or 3, §5.2 (notice_unknown, notice_mismatch); of basis 4, §4.6 (fallback_not_in_policy, fallback_early), its entry’s checks not made for a withheld target.

E then becomes the last decision of X’s line.

7.5 Outcomes and what a verification states

With accept or gap, the verifier states:

8. Redaction in streams, recordings and clips

A restricted item is withheld, never replaced, and its absence is proven: whatever held it shows where it was, and the decision that restricts it shows why. A WAI chain, a take tree and a clip all bind their contents by digest, so an item cannot be swapped for a stand-in without breaking them; withholding keeps them whole, because each of them names the item without holding it.

8.1 Streams

An event withheld from a subscriber session leaves a gap in its author’s chain, and the decisions that restrict it explain the gap (§7.3): the session knows the event existed, where, under which decision and why, and holds nothing of it. A media object withheld from a session is an object the relay does not forward. A restricted object’s receipts, which name it by its digest, stay where they are.

8.2 A recording package

A recording sealed after a decision applies it to what it keeps:

The recording verifier (live-recording §4.4) then finds the take’s chunk missing and the chain’s gap, and fails complete with chunk_missing or delivery_gap. A moderation verifier explains them: a chunk the manifest lists, with no file, whose leaf a standing redaction names, and a gap §7.3 explains with redactions alone. Where every missing chunk and every gap is so explained, the recording is complete but for what was redacted.

What this revision implements of this section: nothing beyond §7.3 and §8.3. The reference explains gaps in a room’s chains and verifies clips; it does not verify a package under moderation, and the corpus has no package vector.

8.3 Clips

A clip’s chunks are proved against a commitment the device made while it captured, by a range proof over their descriptors (live-recording §5.3). A restriction leaves the descriptors in place, so the proof still verifies over every chunk the clip covers; what changes is which chunks’ bytes the clip presents. A chunk is restricted when its leaf is the target of a standing decision that restricts it.

A clip under moderation is verified by live-recording §5.4 with two changes:

  1. In step (k), a restricted chunk is passed over: its bytes are neither required nor checked, and bytes given for it are not presented. The part presents the bytes of its other chunks, in order, less trim_in when its first chunk is not restricted and trim_out when its last is not.
  2. Then, after every part: a restricted chunk whose bytes are given is redaction_not_applied, at the first such chunk.

A clip that passes is accepted, and states what live-recording §5.4 states, and for each part the indexes of its restricted chunks, each with the decision that restricts it. A clip whose restricted chunk is restored by a later allow presents it again, and is refused clip_chunk_missing when its bytes are not given. A clip’s inclusion proof thus verifies in every case, and a clip fails only with a stated reason: one of live-recording §9’s, or redaction_not_applied.

9. The statement-of-reasons export

9.1 The format and its version

A restricting decision maps onto one statement of reasons in the form the DSA Transparency Database accepts at its single-statement endpoint (POST /api/v1/statement): the submission schema in force from 1 July 2025, which the database’s documentation calls API v2, read at the revisions named at the head of this text. The export is the request body. An allow restricts nothing, and has no export.

9.2 The record

The record is one JSON object (RFC 8259) whose members are those of §9.3 that apply, in the order of §9.3, written with no whitespace. Each string is UTF-8, written with " as \", \ as \\, U+0008, U+0009, U+000A, U+000C and U+000D as \b, \t, \n, \f and \r, any other code point below U+0020 as \u and four lowercase hexadecimal digits, and every other code point as itself. There is no byte after the closing brace. A date is YYYY-MM-DD, the UTC date of the instant t0 + t of the room clock, t0 the descriptor’s.

9.3 Members and their sources

“Closed” marks a member whose value is one of a list the database fixes; “free” a text the database accepts up to the length given, in characters (code points).

membervaluesourceform
decision_visibility["DECISION_VISIBILITY_CONTENT_DISABLED"] for deny, ["DECISION_VISIBILITY_CONTENT_REMOVED"] for redactthe decision’s verdictclosed, an array
decision_factsthe statement’s factsstatementfree, 1 to 5000
decision_groundDECISION_GROUND_ILLEGAL_CONTENT (1) or DECISION_GROUND_INCOMPATIBLE_CONTENT (2)statement groundclosed
decision_ground_reference_urlthe reason code’s url, only when it is not emptypolicya URL, up to 500
illegal_content_legal_groundground 1 only: the statement’s ground_ref, or the reason code’s reference when that is emptystatement, policyfree, 1 to 500
illegal_content_explanationground 1 only: the statement’s explanationstatementfree, 1 to 2000
incompatible_content_groundground 2 only: as illegal_content_legal_groundstatement, policyfree, 1 to 500
incompatible_content_explanationground 2 only: as illegal_content_explanationstatementfree, 1 to 2000
content_typea one-element array, by the target (§9.6)the target’s kind or mediaclosed, an array
content_type_otheronly with CONTENT_TYPE_OTHER: §9.6’s textthe target’s kindfree, up to 500
categorythe reason code’s category, by §9.5policyclosed
territorial_scopethe policy’s territory, in its orderpolicyclosed, an array of the thirty codes AT, BE, BG, CY, CZ, DE, DK, EE, ES, FI, FR, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK
content_datethe date of the target’s t (an event’s, or an object’s as given), from 2000-01-01 to 2038-01-01the targeta date
application_datethe date of the decision’s t, from 2020-01-01 to 2038-01-01the decisiona date
source_typebasis 1 and 4: SOURCE_VOLUNTARY; basis 2: SOURCE_TRUSTED_FLAGGER when the notice’s ground is 1 and its submitter is one of the policy’s flaggers, SOURCE_ARTICLE_16 when its ground is 1 and it is not, SOURCE_TYPE_OTHER_NOTIFICATION when its ground is 2; basis 3: the source_type of the decision it supersedesstatement, notice, policyclosed
automated_detectionYes when automated bit 0 is set, No otherwisestatementclosed
automated_decisionAUTOMATED_DECISION_NOT_AUTOMATED (0), AUTOMATED_DECISION_PARTIALLY (1) or AUTOMATED_DECISION_FULLY (2), by automated bits 1 and 2statementclosed
puidthe decision’s digest, 64 lowercase hexadecimal digitsthe decision[a-zA-Z0-9-_], up to 500, unique

The policy is the one in effect at the decision’s t. A notice of ground 2 is not a notice under Article 16, and the database’s documentation names SOURCE_TYPE_OTHER_NOTIFICATION for it. A decision on a complaint keeps the source of the restriction it answers. The database’s other members are not written: decision_monetary, decision_provision and decision_account (no WAI decision restricts payments, the service or an account), their _other texts, decision_visibility_other, account_type, incompatible_content_illegal, category_addition, category_specification and category_specification_other, content_id (a product number), content_language, every end_date_* (a restriction lasts until a decision supersedes it, which the database reads as indefinite when the date is left out), and source_identity (§9.7).

9.4 Article 17, element by element

Article 17what it asks forWAI’s fieldthe member
(1)(a)a restriction of the visibility of specific itemsverdict deny or redactdecision_visibility
(1)(b)–(d)payments, the service, the accountnonenot written
(3)(a)removal, disabling, demotion or restriction; territorial scope; durationverdict; policy territory; the line (a restriction lasts until superseded)decision_visibility; territorial_scope; no end date
(3)(b)facts and circumstances; whether on a notice or on own initiative; the notifier’s identity where strictly necessarystatement facts; basis and the notice; nonedecision_facts; source_type; not written
(3)(c)use of automated means, in the decision and in detectionstatement automatedautomated_decision, automated_detection
(3)(d)for illegal content: the legal ground and why the item is illegal on itstatement ground 1, ground_ref or the code’s reference, explanationdecision_ground, illegal_content_legal_ground, illegal_content_explanation
(3)(e)for incompatibility: the contractual ground and why the item is incompatible with itstatement ground 2, ground_ref or the code’s reference, explanation; the code’s urldecision_ground, incompatible_content_ground, incompatible_content_explanation, decision_ground_reference_url
(3)(f)the possibilities for redresspolicy redress; a complaint (§5) and its decision (§4.5)none: the database has no member for it; it is the statement to the affected participant’s
the category of the decision(the database’s, from Implementing Regulation (EU) 2024/2835 Annex II)the reason code’s categorycategory
the item’s kind and date(the database’s)the targetcontent_type, content_date
the decision’s date and identifier(the database’s)the decision’s t and digestapplication_date, puid

9.5 Categories

numbercategory
1STATEMENT_CATEGORY_ANIMAL_WELFARE
2STATEMENT_CATEGORY_CONSUMER_INFORMATION
3STATEMENT_CATEGORY_CYBER_VIOLENCE
4STATEMENT_CATEGORY_CYBER_VIOLENCE_AGAINST_WOMEN
5STATEMENT_CATEGORY_DATA_PROTECTION_AND_PRIVACY_VIOLATIONS
6STATEMENT_CATEGORY_ILLEGAL_OR_HARMFUL_SPEECH
7STATEMENT_CATEGORY_INTELLECTUAL_PROPERTY_INFRINGEMENTS
8STATEMENT_CATEGORY_NEGATIVE_EFFECTS_ON_CIVIC_DISCOURSE_OR_ELECTIONS
9STATEMENT_CATEGORY_NOT_SPECIFIED_NOTICE
10STATEMENT_CATEGORY_OTHER_VIOLATION_TC
11STATEMENT_CATEGORY_PROTECTION_OF_MINORS
12STATEMENT_CATEGORY_RISK_FOR_PUBLIC_SECURITY
13STATEMENT_CATEGORY_SCAMS_AND_FRAUD
14STATEMENT_CATEGORY_SELF_HARM
15STATEMENT_CATEGORY_UNSAFE_AND_PROHIBITED_PRODUCTS
16STATEMENT_CATEGORY_VIOLENCE

These are the sixteen values the database accepts in this version, in its order. Category 9 is for a notice that does not specify the kind of illegal content (Implementing Regulation (EU) 2024/2835, Annex II).

9.6 Content types

targetcontent_typecontent_type_other
chat, caption, poll_open, markerCONTENT_TYPE_TEXT
reactionCONTENT_TYPE_OTHERreaction
voteCONTENT_TYPE_OTHERpoll vote
poll_closeCONTENT_TYPE_OTHERpoll tally
metaCONTENT_TYPE_OTHERtimed metadata
cueCONTENT_TYPE_OTHERcue
an object of media 1 (audio)CONTENT_TYPE_AUDIO
an object of media 2 (video) or 3 (screen)CONTENT_TYPE_VIDEO

9.7 Personal data

Article 24(5) has the information submitted to the database contain no personal data. The export writes nothing from a principal’s key, a notice’s or a complaint’s contact, statement or submitter, or the content of the item: its members come from the decision’s verdict, t and digest, the target’s kind and t, the policy’s vocabulary and territory, and the statement’s three texts. It never writes source_identity, which the database documentation reserves for the notifier’s identity where strictly necessary. The statement’s texts are copied as their author wrote them; whether they hold personal data is a question about their content that no verifier can answer, and they are written knowing that they are published.

9.8 When no record can be written

The record is written from the members in the order of §9.3. The first member that cannot be written as §9.3 has it names the refusal, sor_incomplete, stated with that member’s name:

10. Reasons

The codes this extension adds, each with where it is raised:

reasonraised at
policy_malformed§3.3
policy_unlinked§3.4
policy_conflicts_room§3.5
notice_malformed§5.2
statement_misplaced§7.2 step 4
statement_malformed§4.3, §7.2 step 4
reason_not_in_policy§7.4 step 1
target_unknown§7.4 step 2
target_not_decidable§4.1, §7.4 step 2
target_prev_mismatch§7.4 step 2
not_reviewer§4.4, §7.4 step 3
supersede_gap§4.5, §7.4 step 4
supersede_unknown§4.5, §7.4 step 4
supersede_mismatch§4.5, §7.4 step 4
notice_unknown§5.2, §7.4 step 5
notice_mismatch§5.2, §7.4 step 5
fallback_not_in_policy§4.6, §7.4 step 5
fallback_early§4.6, §7.4 step 5
sor_incomplete§9.8, with the member
redaction_not_applied§8.3

A moderation verifier also raises every code a room verifier raises (live-rooms §11 and the live-events codes it lists), at the room: kind_not_permitted among them for a decision by a principal without the moderate power (§4.4); truncated, malformed and unknown_version for a policy or a notice that does not read; wrong_room, bad_key and bad_signature for a policy or a notice of another room or whose signature fails; and delivery_gap for a gap that remains, which is not a refusal. A clip under moderation raises every code a clip verifier raises (live-recording §9), and redaction_not_applied.

11. Conformance

live-conformance/moderation/ holds the corpus, written from fixed seeds by wai_live_moderation_vectors gen: vectors.json, and each export as a file of its own, NAME.dK.sor.json, K the decision’s position among the vector’s decisions. It has:

A conforming verifier gives every room, export and clip the outcome, the reason, the place and everything else the corpus states. wai_live_moderation_vectors verify and the test tests/live_moderation.rs check that every file regenerates byte for byte, that wai-rs gives every case its outcome, that every reason of §10 appears, and that §10 lists exactly the reference’s codes. live-conformance/live_moderation_verify.py is the second implementation, written from this text: it shares no code with wai-rs; it verifies each room with the live-rooms corpus’s second implementation (live_rooms_verify.py), each clip with the live-recording corpus’s (live_record_verify.py), and every signature with WAI’s strict rule (claim-conformance/_ed25519.py); it writes every export from §9 and requires its bytes; and it mutates copies of the corpus and requires every copy to fail.

12. Security and privacy considerations