wai.live.moderation: review policies, signed decisions, explained redactions, and DSA statements of reasons #337
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/moderation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Slice L12 of the live and interactive work: moderation for rooms. One extension, its reference module, a corpus written from fixed seeds, and an independent verifier.
What this adds
wai/extensions/live-moderation.mdregisters the recordwai.live.moderation.Review policy,
WMP1. Signed by the room authority, and chained to the policy it replaces with the room-clock instant it takes effect. It states:Every policy must keep the room descriptor's
reviewfield exactly (live-rooms §3.6). §6.3 says what a relay holds, for how long, and what happens at the deadline; §6.4 says what a sink shows.Decisions. A
decisionevent of live-events is used unchanged. It is followed in its author's chain by ametaevent carrying the statement,WMS1, which states:prev;Decisions on one target form a line by digest. An appeal's outcome is a decision that supersedes the decision complained of. The room's clock signs each fallback the policy applies.
Notices and complaints,
WMN1. A notice (Article 16) carries the target digest, ground, cited provision, statement, contact and good-faith flag. A complaint (Article 20) names a decision. Anyone may sign either with their own key; neither needs a grant.Statement-of-reasons export. A deterministic mapping from a restricting decision, plus its room's policy and notices, onto one record of the DSA Transparency Database's single-statement format. §9.2 gives the exact JSON; §9.3 is the member table, with each member's WAI source, closed or free form, and length limit. §9.4 maps each Article 17 element to WAI's field, §9.5 lists the categories, §9.6 the content types, and §9.7 covers personal data.
Refusal reasons, twenty in all, from
policy_malformedtoredaction_not_applied(§10).wai/wai-rs/src/live_moderation.rssits behind the featurelive_moderation = ["live_events", "live_room", "live_record"].cbindgen:ignoreand adds no dependency.live_record::verify_clip_exemptingis new.verify_clipcalls it exempting nothing, so live-recording's corpus regenerates byte for byte.wai/live-conformance/moderation/is written bywai_live_moderation_vectors genfrom fixed seeds. It holdsvectors.json, ten exports asNAME.dK.sor.json, and a README with the provenance line.wai/live-conformance/live_moderation_verify.pyis standard library only and shares no code with wai-rs.live_rooms_verify.pyand clips throughlive_record_verify.py, which gains anexemptparameter that changes nothing by default.required-features.WMP1,WMS1andWMN1, followed by a regeneratedwai registry export.int_kernels_vectorsexclusion reason forlive-conformancenow covers moderation.Format version mapped to
The export targets the DSA Transparency Database's submission schema in force from 1 July 2025, which its documentation's changelog calls "API v2". It is still posted to
POST /api/v1/statement.fc3b1fd5(2026-09-23), and the validation rules (StatementStoreRequest) at revisionbf0afeb8(2026-06-09). The documentation page carries no version or date of its own.puidpattern).Redaction semantics: withheld, never replaced; absence proven
prevand goes back through the standing restricting decisions on each withheld digest.prev(target_prev), so a run of adjacent withheld events stays linked.delivery_gap.redaction_not_applied.clip_chunk_missing.chunk_missing/delivery_gap. This package rule is specified only (§8.2), and the corpus has no package vector.Design choices a reviewer should check
metaevent at the decision'sseq+ 1, as timed-text'sWTX1does. live-events §4.11 fixes the decision payload (verdict, target, reason), and live-events is unchanged.decisionkind require the power, so the room verifier refuses it askind_not_permitted. The corpus has that vector (not_moderator). The moderation-level check that remains isnot_reviewer, against the policy's reviewer list.supersede_gap. It covers two cases: a decision that supersedes nothing while the target already has one, and a decision that names a decision someone already superseded (a fork). A reference to an unknown decision issupersede_unknown; one to another target's decision issupersede_mismatch.fallback_not_in_policy, andfallback_early). A policy whose fallback value is outside allow/deny/hold is refusedpolicy_malformed.fallback_denyand thendeniedat the same instant. A moderator's decision at or before the deadline does forestall it.end_date_*member is left out (the database reads that as indefinite). A timed restriction is a deny followed by an allow.DECISION_VISIBILITY_CONTENT_DISABLED; redact →..._CONTENT_REMOVED; an allow has no export.SOURCE_TYPE_OTHER_NOTIFICATION, following the database's guidance. A flagger listed in the policy →SOURCE_TRUSTED_FLAGGER.source_identityis never written. Article 17(3)(f) (redress) has no database member; the policy carries it asredress.pub(crate)items in its corpus module), and adds the director's decisions to the director's chain.Verification
Every cargo run went through
~/kani-logs/remote/rb <worktree> -- '...'on the build host under memguard, with output logged on the host and grepped:wai/wai-rs)cargo test --no-default-features --features live_record --no-run(warm-up)cargo build --no-default-features --features live_moderation --bin wai_live_moderation_vectorsjson!index needed parentheses), then 0rb --pull:cargo run ... --bin wai_live_moderation_vectors -- gen ../live-conformance/moderationcargo test --no-default-features --features live_moderation --lib live_moderation::cargo test --no-default-features --features live_moderation --test live_moderationReason::ALL)cargo test --no-default-features --features live_record --lib -- live_record:: output_tree::cargo test --no-default-features --features live_record --test live_recordThe next batch was first refused by
rbwith exit 75: the build host's shared work volume was below its 40 GiB floor, at 30 GiB free. My own target dir there was 3.6 GiB, so I deleted nothing and did not lower the floor. Once the volume was freed, the batch ran:wai/wai-rs)cargo run --no-default-features --bin wai -- registry export --checkregistry/capabilities.json,vocab/v2.ttl, the REGISTRY.md table) is exactly what the generator writestouch cbindgen.toml+cargo build --no-default-features --features live_moderation --lib+git diff --exit-code include/wai.hinclude/wai.hunchangedcargo test --no-default-features --lib codecs::registry::cargo test --no-default-features --test cli_registry --test corpus_provenancecargo test --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int --test int_kernels_vectorscargo clippy --no-default-features --features live_moderation --all-targets9614a2c1and re-run with none left in any file this PR touches. The crate's other warnings are in modules this PR does not changelive_moderationlib tests,--test live_moderation, andwai_live_moderation_vectors verify ../live-conformance/moderationPython verifiers (stdlib, run locally):
python3 -I live-conformance/live_moderation_verify.py live-conformance/moderation: exit 0. All 30 rooms, 5 clips and 10 exports agree with wai-rs; every reason of §10 appears; 19 of 19 mutated copies fail.python3 -I live-conformance/live_record_verify.py live-conformance/recordings: exit 0, unchanged by theexemptparameter.Repo checks, run locally, all exit 0:
check-tests-in-ci.py,check-spec-refs.py,check-wai-section-refs.py,check-no-vanity-metrics.sh,check-comparative-prose.sh,check-orphan-sources.py,check-workflow-concurrency.sh.check-public-names.shneeds the denylist secret and runs on push to main; I reviewed the added text by hand and it names no company or product. Laws and standards are cited by identifier only.🤖 Generated with Claude Code