open-standards/wai/live-conformance/moderation/README.md
2026-10-19 07:46:32 -04:00

116 lines
7.7 KiB
Markdown

# live-conformance/moderation — live moderation
The corpus of [`extensions/live-moderation.md`](../../extensions/live-moderation.md) §11:
rooms under review policies, each a room (its `WRD1` descriptor, `WRG1` grants, key-log head
or none, and each principal's `WEV1` chain), its `WMP1` review policies, its `WMN1` notices
and complaints, and the media objects under moderation; the decisions in its chains with
their `WMS1` statements; what a verifier states of them; each restricting decision's
statement-of-reasons export, byte for byte; and clips of a redacted take.
**Moderation equivalence.** For each room vector, a conforming moderation verifier given its
`descriptor`, `grants`, `key_log`, `chains`, `policies`, `notices` and `objects` (§7.1)
reaches the outcome the vector states (§7.5):
- `refuse`: the `reason` and where, `at`: `["room", …]` with the room verifier's own place
(live-rooms §9.1), `["policy", i]`, `["notice", i]`, or `["record", c, i]` for record `i`
of chain `c`;
- `accept` or `gap`: the `room_outcome` (`accept` or `gap`); the `gaps` that remain, each
`principal`, `first` and `last`; the `explained` gaps (§7.3), each with the `decisions`
withholding its seqs from `first` to `last`; the `decisions` (§7.5), each its `digest`,
`decider`, `t`, `target`, `target_type`, `verdict`, `reason`, `statement` (`known`, `none`
or `unknown`), `basis` (`own`, `notice`, `complaint`, `fallback`, or `null` for an unknown
statement), `supersedes`, `notice` and whether it is `standing`; the `items` (§6), each its
`digest`, `target_type`, `kind` (an event kind or a media kind), `t`, `entry` (`mode`,
`deadline_ms`, `fallback`) or `null`, and its `timeline`, each entry's `t`, `state`,
`decision` and whether the state is `visible`; and the `exports`: for each decision, the
`file` holding its record, `null` for an allow, or `refuse` `sor_incomplete` with the
`member` §9.8 names.
Each export file, `NAME.dK.sor.json`, is the record of decision *K* of vector `NAME`, exactly
the bytes §9.2 writes, with no trailing newline.
**Clip equivalence.** For each clip, a conforming verifier of a clip under moderation (§8.3),
given its `descriptor`, `record` and `parts` (as live-recording's corpus gives them) and the
standing restrictions of the room vector its `room` names, reaches the outcome the clip
states: `refuse` with the `reason` and `at` (live-recording's places), or `accept` with the
record's digest `clip`, its `signer`, `window`, `bound_us`, and the `facts` of each part as
live-recording states them (without the FETCH address) and the part's `withheld` chunks, each
its `index` and the `decision` that restricts it.
A verifier that reaches another outcome, reason, place, decision, state, export byte or fact
does not conform.
**Provenance.** Generated here: `wai_live_moderation_vectors gen` writes every file from rooms
authored in code, from fixed seeds. Each chat room principal's key is SHA-256 of a fixed label
and the principal's index; every time is a constant (the rooms' `t0` is 2026-10-16T00:00:00Z);
every text is written for the corpus in English; the phone number is of a reserved fictional
range; every origin, address and link is an `.example` name (RFC 2606); and Ed25519 signing is
deterministic (RFC 8032), so every file is the same bytes on every machine. The recorded take
is live-recording's lesson session, written by that corpus's own rules (`../recordings/`),
so its room, chains, commitments and chunks are that corpus's byte for byte; this corpus adds
the director's decisions to the director's chain, and the performer's complaint. The
generator asserts that each vector reaches the outcome it was written to have, and that the
corpus gives every reason of §10, before it writes. No recorded data. The legal provisions
the vocabulary cites are cited by identifier, as examples of a room's vocabulary; nothing in
the corpus states that any content is or is not lawful.
## Layout
- `vectors.json`: `categories` (§9.5, informative), `principals` and `lesson_principals` (the
keys, by name, informative), `vectors` and `clips`.
- `NAME.dK.sor.json`: the exports.
The rooms:
- `premoderated_chat`: a chat room whose descriptor holds chat for review five seconds and then
denies it; a first policy names a reviewer, a trusted flagger and the vocabulary, and a
second, from 20 s, also reviews reactions after delivery with a fallback of hold. One
message allowed before its deadline, one denied with automated detection, one past its
deadline taking the fallback, which the clock signs; a reaction held at its deadline; a
message allowed by a decision without a statement; a host's message, not reviewed.
- `subscriber_view`: the same room as a subscriber that is not a reviewer receives it: the
denied message and the fallback's are withheld, and the gap they leave is explained.
- `unexplained_gap`: the same room with the allowed message withheld: a delivery gap.
- `notice_and_decision`: an allowed message, a notice that it is illegal, and the decision that
answers it (`SOURCE_ARTICLE_16`); a message the fallback denied, a trusted flagger's notice,
and the redaction that answers it (`SOURCE_TRUSTED_FLAGGER`).
- `appeal_reverses`: a denial with automated means, its author's complaint, and the decision
on the complaint that allows the message.
- `redacted_segment` and `redaction_reversed`: live-recording's lesson session with its video
reviewed after delivery; the director redacts chunk 3 of the performer's take, and in the
second the performer complains and the director restores it.
- refused, one defect each: `not_moderator` (refused by the room, `kind_not_permitted`),
`policy_malformed`, `policy_unlinked`, `policy_conflicts_room`, `policy_bad_signature`,
`policy_wrong_room`, `notice_malformed`, `notice_bad_signature`, `statement_misplaced`,
`statement_malformed`, `reason_not_in_policy`, `target_unknown`, `target_not_decidable`,
`target_prev_mismatch`, `not_reviewer`, `supersede_gap`, `supersede_unknown`,
`supersede_mismatch`, `notice_unknown`, `notice_mismatch`, `fallback_not_in_policy` and
`fallback_early`;
- `sor_incomplete`: a denial whose statement states no facts, accepted, its export refused.
The clips, chunks 2 to 5 of the performer's take: `clip_withheld` and
`clip_trimmed_withheld` (a byte range from inside the redacted chunk) withhold chunk 3;
`clip_redaction_not_applied` gives its bytes; after the appeal, `clip_restored_missing`
leaves it out and `clip_restored_whole` presents it.
## Running
```
cd ../../wai-rs
cargo run --no-default-features --features live_moderation --bin wai_live_moderation_vectors -- verify ../live-conformance/moderation
cargo run --no-default-features --features live_moderation --bin wai_live_moderation_vectors -- gen ../live-conformance/moderation # regenerate
cargo test --no-default-features --features live_moderation --test live_moderation
cd ../live-conformance
python3 -I live_moderation_verify.py moderation
```
`wai_live_moderation_vectors verify` and `tests/live_moderation.rs` require every file to
regenerate byte for byte, no other file but this one to be there, and `wai-rs` to give every
case its outcome; the test also requires §10 to list exactly the reasons the reference
reports, and the generator that the corpus gives each of them. `live_moderation_verify.py` is
the second implementation, written from the extension's text and sharing no code with
`wai-rs`: it verifies each room with `live_rooms_verify.py` and each clip with
`live_record_verify.py`, writes every export itself, reads §9.5, §9.6 and §10 from the
extension, gives every case the same outcome, requires every reason of §10 to appear, and
then mutates copies of the corpus, one defect each, each of which must fail. Pass = an exit
status of 0 from each.