openvibers/openvibe.contracts Commits
Moderation audit events for ten more producers (ADR-022, WS-D task 1): common.moderation-action@1 (action verb id, target { type, id, owner_subject? }, actor_subject; optional reason and details; never the content) and tools, games, wiki, blog, news, reviews, deals, coupons, trade and codes .moderation.action as thin schemas over it; each manifest produces its type and Network consumes all ten; fixtures and checks (unreleased)
Changes
@@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) thfrom `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,the notes were in the tag and commit messages (`git tag -n1`).++## Unreleased++++**Moderation audit events for ten more producers** (ADR-022, roadmap WS-D task 1). **`common.moderation-action@1`** (owner network, public) is one staff or moderator action on someone else's content or account, modelled on `community.moderation.action`: `action` (a short verb id such as `post.hidden`), `target { type, id, owner_subject? }` and `actor_subject` are required; `reason` and `details` are optional; it never carries the content. Events requires an event's prefix to match its source, so each producer gets its own type, a thin schema over the shared one: **`tools.moderation.action`**, **`games.moderation.action`**, **`wiki.moderation.action`**, **`blog.moderation.action`**, **`news.moderation.action`**, **`reviews.moderation.action`**, **`deals.moderation.action`**, **`coupons.moderation.action`**, **`trade.moderation.action`** and **`codes.moderation.action`**. Each service manifest produces its type, and the network manifest consumes all ten into the moderation audit log. Fixtures for each; `npm test` checks that every one is the shared payload and that Network consumes every `*.moderation.action`. Additive.++## 0.52.0 — 2026-09-26**`common.config-snapshot@1`** (roadmap WS-C task 7, the configuration model): one immutable revision of one service's configuration namespace (`live.site_settings`, `network.site_settings`, `media.storage_tier`), as `openvibe-shared/config` keeps it and `/api/admin/config` shows it. It carries service, namespace, a revision that grows per namespace and the previous one, a state (`proposed`, `active`, `superseded`, `rejected`, `rolled_back`), the values with every secret-class key as `{ redacted: true, fingerprint }` (an HMAC-SHA256 of the value under a secret key the service keeps per namespace: equal fingerprints within a namespace mean the value did not change, and the value cannot be recovered or guessed offline without the key), a `public`/`internal`/`secret` classification per key, a sha256 checksum over the canonical JSON of the values as shown (secrets as their markers, so anyone can check it and it reveals nothing more), who created and activated it and when, a reason, the rejection error, and `copied_from` for a rollback. A rejected revision names its error; an active, superseded or rolled-back one names when it became active. Fixtures for an active revision with a redacted secret, an imported first revision, a rejected tiering change, a rollback and a proposal; an unkeyed `sha256` marker is invalid. Additive.@@@ -190,6 +190,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "common.moderation-action",++ "version": "1.0.0",++ "owner": "network",++ "schema": "common/moderation-action.v1.json",++ "visibility": "public",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "media.file-upload","version": "1.0.0",@@@ -322,6 +332,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "codes.moderation.action",++ "version": "1.0.0",++ "owner": "codes",++ "schema": "events/payloads/codes.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "events.redaction-directive","version": "1.0.0",@@@ -657,6 +677,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "wiki.moderation.action",++ "version": "1.0.0",++ "owner": "wiki",++ "schema": "events/payloads/wiki.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "wiki.citation-attach-request","version": "1.0.0",@@@ -945,6 +975,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "blog.moderation.action",++ "version": "1.0.0",++ "owner": "blog",++ "schema": "events/payloads/blog.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "blog.blog-configure-request","version": "1.0.0",@@@ -2159,6 +2199,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "tools.moderation.action",++ "version": "1.0.0",++ "owner": "tools",++ "schema": "events/payloads/tools.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "live.stream.started","version": "1.0.0",@@@ -2589,6 +2639,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "news.moderation.action",++ "version": "1.0.0",++ "owner": "news",++ "schema": "events/payloads/news.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "news.cluster-audit","version": "1.0.0",@@@ -2886,6 +2946,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "reviews.moderation.action",++ "version": "1.0.0",++ "owner": "reviews",++ "schema": "events/payloads/reviews.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "reviews.correction-submit-request","version": "1.0.0",@@@ -3165,6 +3235,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "coupons.moderation.action",++ "version": "1.0.0",++ "owner": "coupons",++ "schema": "events/payloads/coupons.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "coupons.coupon","version": "1.0.0",@@@ -3327,6 +3407,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "deals.moderation.action",++ "version": "1.0.0",++ "owner": "deals",++ "schema": "events/payloads/deals.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "deals.flag-request","version": "1.0.0",@@@ -3507,6 +3597,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "trade.moderation.action",++ "version": "1.0.0",++ "owner": "trade",++ "schema": "events/payloads/trade.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "trade.alert-read-result","version": "1.0.0",@@@ -3768,6 +3868,16 @@"compatibility": "backward","status": "active"},++ {++ "id": "games.moderation.action",++ "version": "1.0.0",++ "owner": "games",++ "schema": "events/payloads/games.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-022"++ },{"id": "games.announce-frame","version": "1.0.0",nnew file mode 100644@@@ -0,0 +1,31 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/common/moderation-action.v1.json",++ "title": "ModerationAction",++ "description": "common.moderation-action@1 (ADR-022, roadmap WS-D task 1): one staff or moderator action on someone else's content or account, as a service reports it to OpenVibe.Network's moderation audit log. The payload of every <service>.moderation.action event that has no older shape of its own (tools, games, wiki, blog, news, reviews, deals, coupons, trade, codes); modelled on community.moderation.action@1. Written to the service's outbox in the transaction that performs the action. A person acting on their own content is not moderation and is not reported. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself, a secret or an address.",++ "type": "object",++ "required": ["action", "target", "actor_subject"],++ "additionalProperties": false,++ "properties": {++ "action": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$",++ "description": "A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked)."++ },++ "target": {++ "type": "object",++ "required": ["type", "id"],++ "additionalProperties": false,++ "properties": {++ "type": { "type": "string", "minLength": 1, "maxLength": 40, "pattern": "^[a-z][a-z0-9_]*$", "description": "What was acted on, in the service's own words (post, page, release, user, player, …)." },++ "id": { "type": "string", "minLength": 1, "maxLength": 200 },++ "owner_subject": { "type": ["string", "null"], "maxLength": 200, "description": "Whose content or account it was, when known." }++ }++ },++ "actor_subject": { "type": ["string", "null"], "maxLength": 200, "description": "The staff member or moderator (null only for a service acting without a person)." },++ "reason": { "type": ["string", "null"], "maxLength": 500 },++ "details": { "type": "object", "description": "Per action: the fields changed, the previous and new state, a bulk action's count, … never the content." }++ }++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/blog.moderation.action.v1.json",++ "title": "BlogModerationActionPayload",++ "description": "blog.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Blog, such as editorial moderation of someone else's post or blog: hiding, unpublishing, deleting or restoring it, suspending a blog. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/codes.moderation.action.v1.json",++ "title": "CodesModerationActionPayload",++ "description": "codes.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Codes, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/coupons.moderation.action.v1.json",++ "title": "CouponsModerationActionPayload",++ "description": "coupons.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Coupons, such as approving, disabling or removing someone else's coupon, resolving reports, changing a merchant's status. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/deals.moderation.action.v1.json",++ "title": "DealsModerationActionPayload",++ "description": "deals.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Deals, such as resolving flags, hiding, removing or restoring someone else's offer or comment. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/games.moderation.action.v1.json",++ "title": "GamesModerationActionPayload",++ "description": "games.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Games, such as kicking or banning a player, lifting a ban, and revoking or disabling someone else's mod. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/news.moderation.action.v1.json",++ "title": "NewsModerationActionPayload",++ "description": "news.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.News, such as editorial moderation: unpublishing, retracting or restoring a story, resolving flags, blocking a source. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/reviews.moderation.action.v1.json",++ "title": "ReviewsModerationActionPayload",++ "description": "reviews.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Reviews, such as editorial moderation: removing or restoring someone else's signal or review, unpublishing a summary, merging or splitting entities. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/tools.moderation.action.v1.json",++ "title": "ToolsModerationActionPayload",++ "description": "tools.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Tools (apps/gateway and its guard), such as guard blocks and unblocks of an account, an app or an address, and staff actions on someone else's jobs or tool pages. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/trade.moderation.action.v1.json",++ "title": "TradeModerationActionPayload",++ "description": "trade.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Trade, such as hiding, removing or restoring someone else's listing or observation. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/wiki.moderation.action.v1.json",++ "title": "WikiModerationActionPayload",++ "description": "wiki.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Wiki, such as editorial moderation of someone else's page or revision: hiding, unpublishing, deleting, restoring, locking or reverting. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "post.unpublished",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "doxxing"++}nnew file mode 100644@@@ -0,0 +1,13 @@++{++ "action": "post.unpublished",++ "target": {++ "type": "post",++ "id": "pst_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "doxxing",++ "details": {++ "previous": "published"++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "release.revoked",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "malware in 1.4.2"++}nnew file mode 100644@@@ -0,0 +1,14 @@++{++ "action": "release.revoked",++ "target": {++ "type": "release",++ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPT",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "malware in 1.4.2",++ "details": {++ "app": "app_3",++ "version": "1.4.2"++ }++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "action": "Hid The Post",++ "target": {++ "type": "post",++ "id": "x"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"++}nnew file mode 100644@@@ -0,0 +1,9 @@++{++ "action": "post.hidden",++ "target": {++ "type": "post",++ "id": "x"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "content": "the post text"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "action": "post.hidden",++ "target": {++ "type": "post",++ "id": "x"++ }++}nnew file mode 100644@@@ -0,0 +1,9 @@++{++ "action": "post.hidden",++ "target": {++ "type": "post",++ "id": "x"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"++}nnew file mode 100644@@@ -0,0 +1,9 @@++{++ "action": "post.hidden",++ "target": {++ "type": "post",++ "id": "x",++ "title": "Hello"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "action": "post.hidden",++ "target": {++ "type": "post"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "action": "user.banned",++ "target": {++ "type": "user",++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"++}nnew file mode 100644@@@ -0,0 +1,14 @@++{++ "action": "post.hidden",++ "target": {++ "type": "post",++ "id": "pst_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "spam",++ "details": {++ "previous": "published",++ "now": "hidden"++ }++}nnew file mode 100644@@@ -0,0 +1,12 @@++{++ "action": "guard.blocked",++ "target": {++ "type": "address",++ "id": "ip:3f9a1c"++ },++ "actor_subject": null,++ "reason": null,++ "details": {++ "rule": "rate"++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "coupon.disabled",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": null++}nnew file mode 100644@@@ -0,0 +1,13 @@++{++ "action": "coupon.disabled",++ "target": {++ "type": "coupon",++ "id": "cpn_12",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": null,++ "details": {++ "reports": 4++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "offer.hidden",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "expired code reposted"++}nnew file mode 100644@@@ -0,0 +1,13 @@++{++ "action": "offer.hidden",++ "target": {++ "type": "offer",++ "id": "off_5",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "expired code reposted",++ "details": {++ "flags_resolved": 3++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "player.banned",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "griefing"++}nnew file mode 100644@@@ -0,0 +1,14 @@++{++ "action": "player.banned",++ "target": {++ "type": "player",++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "griefing",++ "details": {++ "world": "wld_1",++ "duration_s": 86400++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "story.retracted",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "fabricated source"++}nnew file mode 100644@@@ -0,0 +1,11 @@++{++ "action": "story.retracted",++ "target": {++ "type": "story",++ "id": "sty_17",++ "owner_subject": null++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "fabricated source",++ "details": {}++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "signal.removed",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "fake review"++}nnew file mode 100644@@@ -0,0 +1,13 @@++{++ "action": "signal.removed",++ "target": {++ "type": "signal",++ "id": "sig_9",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "fake review",++ "details": {++ "entity": "ent_3"++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "guard.blocked",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "scripted abuse of the image tools"++}nnew file mode 100644@@@ -0,0 +1,14 @@++{++ "action": "guard.blocked",++ "target": {++ "type": "user",++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "scripted abuse of the image tools",++ "details": {++ "scope": "account",++ "expires_at": "2026-10-02T00:00:00Z"++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "listing.removed",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "counterfeit"++}nnew file mode 100644@@@ -0,0 +1,11 @@++{++ "action": "listing.removed",++ "target": {++ "type": "listing",++ "id": "lst_8",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "counterfeit",++ "details": {}++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "page.locked",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "edit war"++}nnew file mode 100644@@@ -0,0 +1,11 @@++{++ "action": "page.locked",++ "target": {++ "type": "page",++ "id": "pg_42",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "edit war",++ "details": {}++}@@@ -1995,6 +1995,82 @@]}},++ "common.moderation-action": {++ "version": "1.0.0",++ "owner": "network",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/common/moderation-action.v1.json",++ "title": "ModerationAction",++ "description": "common.moderation-action@1 (ADR-022, roadmap WS-D task 1): one staff or moderator action on someone else's content or account, as a service reports it to OpenVibe.Network's moderation audit log. The payload of every <service>.moderation.action event that has no older shape of its own (tools, games, wiki, blog, news, reviews, deals, coupons, trade, codes); modelled on community.moderation.action@1. Written to the service's outbox in the transaction that performs the action. A person acting on their own content is not moderation and is not reported. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself, a secret or an address.",++ "type": "object",++ "required": [++ "action",++ "target",++ "actor_subject"++ ],++ "additionalProperties": false,++ "properties": {++ "action": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$",++ "description": "A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked)."++ },++ "target": {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "type": "string",++ "minLength": 1,++ "maxLength": 40,++ "pattern": "^[a-z][a-z0-9_]*$",++ "description": "What was acted on, in the service's own words (post, page, release, user, player, …)."++ },++ "id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "owner_subject": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 200,++ "description": "Whose content or account it was, when known."++ }++ }++ },++ "actor_subject": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 200,++ "description": "The staff member or moderator (null only for a service acting without a person)."++ },++ "reason": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 500++ },++ "details": {++ "type": "object",++ "description": "Per action: the fields changed, the previous and new state, a bulk action's count, … never the content."++ }++ }++ }++ },"media.file-upload": {"version": "1.0.0","owner": "media",@@@ -4028,6 +4104,18 @@]}},++ "codes.moderation.action": {++ "version": "1.0.0",++ "owner": "codes",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/codes.moderation.action.v1.json",++ "title": "CodesModerationActionPayload",++ "description": "codes.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Codes, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"events.redaction-directive": {"version": "1.0.0","owner": "events",@@@ -6934,6 +7022,18 @@}}},++ "wiki.moderation.action": {++ "version": "1.0.0",++ "owner": "wiki",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/wiki.moderation.action.v1.json",++ "title": "WikiModerationActionPayload",++ "description": "wiki.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Wiki, such as editorial moderation of someone else's page or revision: hiding, unpublishing, deleting, restoring, locking or reverting. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"wiki.citation-attach-request": {"version": "1.0.0","owner": "wiki",@@@ -9503,6 +9603,18 @@}}},++ "blog.moderation.action": {++ "version": "1.0.0",++ "owner": "blog",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/blog.moderation.action.v1.json",++ "title": "BlogModerationActionPayload",++ "description": "blog.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Blog, such as editorial moderation of someone else's post or blog: hiding, unpublishing, deleting or restoring it, suspending a blog. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"blog.blog-configure-request": {"version": "1.0.0","owner": "blog",@@@ -22914,6 +23026,18 @@}}},++ "tools.moderation.action": {++ "version": "1.0.0",++ "owner": "tools",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/tools.moderation.action.v1.json",++ "title": "ToolsModerationActionPayload",++ "description": "tools.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Tools (apps/gateway and its guard), such as guard blocks and unblocks of an account, an app or an address, and staff actions on someone else's jobs or tool pages. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"live.stream.started": {"version": "1.0.0","owner": "live",@@@ -27577,6 +27701,18 @@}}},++ "news.moderation.action": {++ "version": "1.0.0",++ "owner": "news",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/news.moderation.action.v1.json",++ "title": "NewsModerationActionPayload",++ "description": "news.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.News, such as editorial moderation: unpublishing, retracting or restoring a story, resolving flags, blocking a source. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"news.cluster-audit": {"version": "1.0.0","owner": "news",@@@ -31586,6 +31722,18 @@}}},++ "reviews.moderation.action": {++ "version": "1.0.0",++ "owner": "reviews",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/reviews.moderation.action.v1.json",++ "title": "ReviewsModerationActionPayload",++ "description": "reviews.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Reviews, such as editorial moderation: removing or restoring someone else's signal or review, unpublishing a summary, merging or splitting entities. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"reviews.correction-submit-request": {"version": "1.0.0","owner": "reviews",@@@ -36392,6 +36540,18 @@}}},++ "coupons.moderation.action": {++ "version": "1.0.0",++ "owner": "coupons",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/coupons.moderation.action.v1.json",++ "title": "CouponsModerationActionPayload",++ "description": "coupons.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Coupons, such as approving, disabling or removing someone else's coupon, resolving reports, changing a merchant's status. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"coupons.coupon": {"version": "1.0.0","owner": "coupons",@@@ -38010,6 +38170,18 @@}}},++ "deals.moderation.action": {++ "version": "1.0.0",++ "owner": "deals",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/deals.moderation.action.v1.json",++ "title": "DealsModerationActionPayload",++ "description": "deals.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Deals, such as resolving flags, hiding, removing or restoring someone else's offer or comment. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"deals.flag-request": {"version": "1.0.0","owner": "deals",@@@ -40264,6 +40436,18 @@}}},++ "trade.moderation.action": {++ "version": "1.0.0",++ "owner": "trade",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/trade.moderation.action.v1.json",++ "title": "TradeModerationActionPayload",++ "description": "trade.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Trade, such as hiding, removing or restoring someone else's listing or observation. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"trade.alert-read-result": {"version": "1.0.0","owner": "trade",@@@ -42777,6 +42961,18 @@}}},++ "games.moderation.action": {++ "version": "1.0.0",++ "owner": "games",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/games.moderation.action.v1.json",++ "title": "GamesModerationActionPayload",++ "description": "games.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Games, such as kicking or banning a player, lifting a ban, and revoking or disabling someone else's mod. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"games.announce-frame": {"version": "1.0.0","owner": "games",@@@ -736,6 +736,37 @@ export type ConfigSnapshot = {copied_from?: number | null;};++/** [email protected] (owner: network) */++/**++ * common.moderation-action@1 (ADR-022, roadmap WS-D task 1): one staff or moderator action on someone else's content or account, as a service reports it to OpenVibe.Network's moderation audit log. The payload of every <service>.moderation.action event that has no older shape of its own (tools, games, wiki, blog, news, reviews, deals, coupons, trade, codes); modelled on community.moderation.action@1. Written to the service's outbox in the transaction that performs the action. A person acting on their own content is not moderation and is not reported. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself, a secret or an address.++ */++export interface ModerationAction {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: media) *//*** media.file-upload@1: the multipart/form-data body of POST /api/v1/:app/files (media.object.upload, namespace :app): one part named `file` with the bytes and its filename and type. The tenant's quota is checked against the bytes; the answer is media.file@1 (201).@@@ -5969,6 +6000,37 @@ export type CodesReleaseManageRequest =}| NoBody;++/** [email protected] (owner: codes) */++/**++ * codes.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Codes, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface CodesModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: events) *//*** payload.redacts (ADR-026): a producer takes back events it published earlier. Any event may carry it, normally the producer's own *.deleted event. It names event_ids, or subject_type + subject_ids, or both, never an empty list. event_ids names events directly; subject_type + subject_ids names every stored event of the same source (for an app, the same project and environment) about those subjects. OpenVibe.Events rewrites each target into a tombstone (events.tombstone-payload@1) in the transaction that stores the directive. Naming another source's event is 403 events.redaction_not_allowed (the whole batch is refused); a malformed directive is 422 events.invalid_redaction. An event that carries a directive is never redacted itself.@@@ -12458,6 +12520,37 @@ export interface WikiIndexDocumentDeletedPayload {revision: number;}++/** [email protected] (owner: wiki) */++/**++ * wiki.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Wiki, such as editorial moderation of someone else's page or revision: hiding, unpublishing, deleting, restoring, locking or reverting. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface WikiModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: wiki) *//*** wiki.citation-attach-request@1: the body of POST /api/v1/pages/:id/revisions/:n/citations on OpenVibe.Wiki (wiki.citation.attach, editors): sources for the newest revision while it is unpublished (a published revision's sources are fixed: 409 citation.revision_published; an older one is 409 citation.not_head). A URL citation needs retrieved_at; a Sources item id brings its own URL, title and retrieval time.@@@ -13786,6 +13879,37 @@ export interface BlogIndexDocumentDeletedPayload {revision: number;}++/** [email protected] (owner: blog) */++/**++ * blog.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Blog, such as editorial moderation of someone else's post or blog: hiding, unpublishing, deleting or restoring it, suspending a blog. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface BlogModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: blog) *//*** blog.blog-configure-request@1: the body of PATCH /api/v1/blogs/:handle on OpenVibe.Blog (blog.blog.configure; an owner): title (at most 120 characters, not blank), description (500), language (a BCP 47 tag) and feeds { rss, atom, json, item_count (1-50), full_content }. Fields left out keep their value.@@@ -24433,6 +24557,37 @@ export interface ToolsJobFailedPayload {retryable: boolean;}++/** [email protected] (owner: tools) */++/**++ * tools.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Tools (apps/gateway and its guard), such as guard blocks and unblocks of an account, an app or an address, and staff actions on someone else's jobs or tool pages. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface ToolsModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: live) *//*** live.stream.started v1 (OpenVibe.Live server/events/stream-events.js envelopeFor, fired by server/db/database.js createStream). A streams row went live: WebRTC/JSMPEG from the dashboard, RTMP ingest, WHIP, or an OpenRe.Stream session mirrored into Live. Written to Live's event_outbox in the transaction that inserts the row, so the event exists if and only if the stream did. Carries public channel facts only (the stream is listed publicly already); consumers such as Network's go-live notifications decide who hears about it. Never the stream key, the Live user id or the description. Envelope: subject { type: stream, id: <stream_id as a string>, revision: 1 }, visibility public, priority important, actor the streamer's user subject when Live knows it, else service:live.@@@ -26852,6 +27007,37 @@ export interface NewsIndexDocumentDeletedPayload {revision: number;}++/** [email protected] (owner: news) */++/**++ * news.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.News, such as editorial moderation: unpublishing, retracting or restoring a story, resolving flags, blocking a source. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface NewsModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: news) *//*** news.cluster-audit@1: one audited cluster change on OpenVibe.News (server/domain/clusters.js shapeAudit): a merge, a split or the reversal of one, with exactly which source items moved, who did it and why. Merge: cluster_id survived and other_id was absorbed; split: other_id is the new cluster.@@@ -29470,6 +29656,37 @@ export interface ReviewsIndexDocumentDeletedPayload {revision: number;}++/** [email protected] (owner: reviews) */++/**++ * reviews.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Reviews, such as editorial moderation: removing or restoring someone else's signal or review, unpublishing a summary, merging or splitting entities. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface ReviewsModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: reviews) *//*** reviews.correction-submit-request@1: the body of reviews.correction.submit on OpenVibe.Reviews: POST /api/v1/entities/:ref/corrections { body, target_type?, target_id?, evidence_url? } sends a correction to the editors' queue for the person named in X-OV-Subject (a signed-in person: 403 reviews.person_required). Refusals: 422 correction.invalid (unknown target_type, body under 10 or over 4000 characters, evidence_url not http(s)), 409 correction.duplicate (the same open request again), 429 correction.rate_limited (20 a day per person), 404 entity.not_found, 410 entity.deleted.@@@ -35707,6 +35924,37 @@ export interface CouponsIndexDocumentDeletedPayload {revision: number;}++/** [email protected] (owner: coupons) */++/**++ * coupons.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Coupons, such as approving, disabling or removing someone else's coupon, resolving reports, changing a merchant's status. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface CouponsModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: coupons) *//*** coupons.coupon@1: one code as OpenVibe.Coupons shows it (server/domain/coupons.js view): its status and confidence come only from people's reports (counts in a window, report times rounded to the hour), a known or unknown expiry, restrictions, hints and evidence. No submitter or reporter is ever named.@@@ -36715,6 +36963,37 @@ export interface DealsIndexDocumentDeletedPayload {revision: number;}++/** [email protected] (owner: deals) */++/**++ * deals.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Deals, such as resolving flags, hiding, removing or restoring someone else's offer or comment. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface DealsModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: deals) *//*** deals.flag-request@1: the body of POST /api/v1/offers/:id/flags on OpenVibe.Deals (deals.flag.create; a person): { kind, reason?, duplicate_of? } — duplicate_of (the other deal, id, slug or /d/ link) is required for kind duplicate. An open flag of the same kind by the same person is refreshed, not repeated.@@@ -37326,6 +37605,37 @@ export interface TradeIndexDocumentDeletedPayload {revision: number;}++/** [email protected] (owner: trade) */++/**++ * trade.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Trade, such as hiding, removing or restoring someone else's listing or observation. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface TradeModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: trade) *//*** trade.alert-read-result@1: answers of trade.alert.read on OpenVibe.Trade (the acting person's): GET /api/v1/alerts → { rules }; GET /api/v1/alerts/deliveries?limit= → { deliveries } (newest first, at most 200: which rule fired on what, and the event sent).@@@ -38317,6 +38627,37 @@ export interface GamesModRevokedPayload {reason?: string;}++/** [email protected] (owner: games) */++/**++ * games.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Games, such as kicking or banning a player, lifting a ban, and revoking or disabling someone else's mod. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface GamesModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: games) *//*** games.announce-frame@1: the frame OpenVibe.Games broadcasts to every connected player for an announcement (gameServer broadcastAll): { t: announce, text }. A mod's announcement text is prefixed with its name in brackets ([Mod name] text); the binding itself returns nothing.@@@ -48,7 +48,8 @@"blog.post.deleted","blog.schedule.failed","blog.index_document.upserted",-- "blog.index_document.deleted"++ "blog.index_document.deleted",++ "blog.moderation.action"],"eventsConsumed": [],"namespacesOwned": [@@@ -33,7 +33,8 @@"eventsProduced": ["codes.app.published","codes.app.deprecated",-- "codes.app.revoked"++ "codes.app.revoked",++ "codes.moderation.action"],"eventsConsumed": [],"namespacesOwned": [@@@ -43,7 +43,8 @@"coupons.report.created","coupons.confidence.changed","coupons.index_document.upserted",-- "coupons.index_document.deleted"++ "coupons.index_document.deleted",++ "coupons.moderation.action"],"eventsConsumed": [],"namespacesOwned": [@@@ -48,7 +48,8 @@"deals.vote.changed","deals.watch.matched","deals.index_document.upserted",-- "deals.index_document.deleted"++ "deals.index_document.deleted",++ "deals.moderation.action"],"eventsConsumed": ["sources.item.created",@@@ -43,7 +43,8 @@"games.mod.enabled","games.mod.disabled","games.mod.grants_changed",-- "games.mod.revoked"++ "games.mod.revoked",++ "games.moderation.action"],"eventsConsumed": ["network.user.token_valid_after"@@@ -60,13 +60,23 @@],"eventsConsumed": ["billing.staff.action",++ "blog.moderation.action","chat.moderation.action",++ "codes.moderation.action","community.moderation.action",++ "coupons.moderation.action",++ "deals.moderation.action","deals.watch.matched",++ "games.moderation.action","live.moderation.action","live.stream.started",++ "news.moderation.action",++ "reviews.moderation.action","tips.interaction.moderated",-- "trade.alert.triggered"++ "tools.moderation.action",++ "trade.alert.triggered",++ "trade.moderation.action",++ "wiki.moderation.action"],"namespacesOwned": ["identity.*",@@@ -51,7 +51,8 @@"news.story.unpublished","news.story.retracted","news.index_document.upserted",-- "news.index_document.deleted"++ "news.index_document.deleted",++ "news.moderation.action"],"eventsConsumed": ["sources.item.created",@@@ -46,7 +46,8 @@"reviews.summary.updated","reviews.summary.unpublished","reviews.index_document.upserted",-- "reviews.index_document.deleted"++ "reviews.index_document.deleted",++ "reviews.moderation.action"],"eventsConsumed": ["sources.item.created",@@@ -38,7 +38,8 @@"tools.job.created","tools.job.started","tools.job.succeeded",-- "tools.job.failed"++ "tools.job.failed",++ "tools.moderation.action"],"eventsConsumed": ["network.user.token_valid_after"@@@ -47,7 +47,8 @@"trade.source.stale","trade.source.recovered","trade.index_document.upserted",-- "trade.index_document.deleted"++ "trade.index_document.deleted",++ "trade.moderation.action"],"eventsConsumed": ["sources.item.created",@@@ -45,7 +45,8 @@"wiki.page.deleted","wiki.watch.triggered","wiki.index_document.upserted",-- "wiki.index_document.deleted"++ "wiki.index_document.deleted",++ "wiki.moderation.action"],"eventsConsumed": [],"namespacesOwned": [@@@ -655,6 +655,26 @@ await assert.rejects(failing.getToken(), /401: invalid_client/);}}++// ── Moderation audit events (ADR-022, WS-D task 1): one shared payload, one event per producer ──++// Events requires an event's prefix to be its source, so each service has its own type; the ones++// without an older shape are common.moderation-action@1, and Network consumes every one of them.++{++ const moderation = contracts.catalog.filter(c => /\.moderation\.action$/.test(c.id));++ for (const svc of ['tools', 'games', 'wiki', 'blog', 'news', 'reviews', 'deals', 'coupons', 'trade', 'codes']) {++ const id = `${svc}.moderation.action`;++ const c = moderation.find(x => x.id === id);++ ok(c && c.owner === svc && c.adr === 'ADR-022', `${id} is owned by ${svc}`);++ ok(contracts.schema(id).$ref === '../../common/moderation-action.v1.json', `${id} is a common.moderation-action@1`);++ }++ for (const c of moderation) ok(services.get('network').eventsConsumed.includes(c.id), `network consumes ${c.id} into the moderation audit log`);++ const M = (v) => contracts.validate('common.moderation-action@1', v).valid;++ const base = { action: 'post.hidden', target: { type: 'post', id: 'p1', owner_subject: null }, actor_subject: null };++ ok(M(base) && M({ ...base, reason: 'spam', details: { previous: 'published' } }), 'action, target and actor_subject are enough; reason and details are optional');++ for (const k of ['action', 'target', 'actor_subject']) ok(!M({ ...base, [k]: undefined }), `a moderation action needs ${k}`);++ for (const action of ['Post.Hidden', 'post hidden', 'post.', '.hidden', 'x'.repeat(65)]) ok(!M({ ...base, action }), `"${action.slice(0, 12)}" is not a verb id`);++ ok(!M({ ...base, text: 'the post' }) && !M({ ...base, target: { ...base.target, title: 'Hi' } }), 'it never carries the content');++}++// ── Capability schemas (WS-C task 4): a ratchet over compatibility/capability-schema-gaps.json ──execFileSync(process.execPath, [path.join(__dirname, 'capability-schemas.test.js')], { stdio: 'inherit' });
@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
the notes were in the tag and commit messages (`git tag -n1`).
+## Unreleased
+
+**Moderation audit events for ten more producers** (ADR-022, roadmap WS-D task 1). **`common.moderation-action@1`** (owner network, public) is one staff or moderator action on someone else's content or account, modelled on `community.moderation.action`: `action` (a short verb id such as `post.hidden`), `target { type, id, owner_subject? }` and `actor_subject` are required; `reason` and `details` are optional; it never carries the content. Events requires an event's prefix to match its source, so each producer gets its own type, a thin schema over the shared one: **`tools.moderation.action`**, **`games.moderation.action`**, **`wiki.moderation.action`**, **`blog.moderation.action`**, **`news.moderation.action`**, **`reviews.moderation.action`**, **`deals.moderation.action`**, **`coupons.moderation.action`**, **`trade.moderation.action`** and **`codes.moderation.action`**. Each service manifest produces its type, and the network manifest consumes all ten into the moderation audit log. Fixtures for each; `npm test` checks that every one is the shared payload and that Network consumes every `*.moderation.action`. Additive.
+
## 0.52.0 — 2026-09-26
## 0.52.0 — 2026-09-26
**`common.config-snapshot@1`** (roadmap WS-C task 7, the configuration model): one immutable revision of one service's configuration namespace (`live.site_settings`, `network.site_settings`, `media.storage_tier`), as `openvibe-shared/config` keeps it and `/api/admin/config` shows it. It carries service, namespace, a revision that grows per namespace and the previous one, a state (`proposed`, `active`, `superseded`, `rejected`, `rolled_back`), the values with every secret-class key as `{ redacted: true, fingerprint }` (an HMAC-SHA256 of the value under a secret key the service keeps per namespace: equal fingerprints within a namespace mean the value did not change, and the value cannot be recovered or guessed offline without the key), a `public`/`internal`/`secret` classification per key, a sha256 checksum over the canonical JSON of the values as shown (secrets as their markers, so anyone can check it and it reveals nothing more), who created and activated it and when, a reason, the rejection error, and `copied_from` for a rollback. A rejected revision names its error; an active, superseded or rolled-back one names when it became active. Fixtures for an active revision with a redacted secret, an imported first revision, a rejected tiering change, a rollback and a proposal; an unkeyed `sha256` marker is invalid. Additive.
**`common.config-snapshot@1`** (roadmap WS-C task 7, the configuration model): one immutable revision of one service's configuration namespace (`live.site_settings`, `network.site_settings`, `media.storage_tier`), as `openvibe-shared/config` keeps it and `/api/admin/config` shows it. It carries service, namespace, a revision that grows per namespace and the previous one, a state (`proposed`, `active`, `superseded`, `rejected`, `rolled_back`), the values with every secret-class key as `{ redacted: true, fingerprint }` (an HMAC-SHA256 of the value under a secret key the service keeps per namespace: equal fingerprints within a namespace mean the value did not change, and the value cannot be recovered or guessed offline without the key), a `public`/`internal`/`secret` classification per key, a sha256 checksum over the canonical JSON of the values as shown (secrets as their markers, so anyone can check it and it reveals nothing more), who created and activated it and when, a reason, the rejection error, and `copied_from` for a rollback. A rejected revision names its error; an active, superseded or rolled-back one names when it became active. Fixtures for an active revision with a redacted secret, an imported first revision, a rejected tiering change, a rollback and a proposal; an unkeyed `sha256` marker is invalid. Additive.
@@ -190,6 +190,16 @@
@@ -190,6 +190,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "common.moderation-action",
+ "version": "1.0.0",
+ "owner": "network",
+ "schema": "common/moderation-action.v1.json",
+ "visibility": "public",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "media.file-upload",
"id": "media.file-upload",
"version": "1.0.0",
"version": "1.0.0",
@@ -322,6 +332,16 @@
@@ -322,6 +332,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "codes.moderation.action",
+ "version": "1.0.0",
+ "owner": "codes",
+ "schema": "events/payloads/codes.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "events.redaction-directive",
"id": "events.redaction-directive",
"version": "1.0.0",
"version": "1.0.0",
@@ -657,6 +677,16 @@
@@ -657,6 +677,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "wiki.moderation.action",
+ "version": "1.0.0",
+ "owner": "wiki",
+ "schema": "events/payloads/wiki.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "wiki.citation-attach-request",
"id": "wiki.citation-attach-request",
"version": "1.0.0",
"version": "1.0.0",
@@ -945,6 +975,16 @@
@@ -945,6 +975,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "blog.moderation.action",
+ "version": "1.0.0",
+ "owner": "blog",
+ "schema": "events/payloads/blog.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "blog.blog-configure-request",
"id": "blog.blog-configure-request",
"version": "1.0.0",
"version": "1.0.0",
@@ -2159,6 +2199,16 @@
@@ -2159,6 +2199,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "tools.moderation.action",
+ "version": "1.0.0",
+ "owner": "tools",
+ "schema": "events/payloads/tools.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "live.stream.started",
"id": "live.stream.started",
"version": "1.0.0",
"version": "1.0.0",
@@ -2589,6 +2639,16 @@
@@ -2589,6 +2639,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "news.moderation.action",
+ "version": "1.0.0",
+ "owner": "news",
+ "schema": "events/payloads/news.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "news.cluster-audit",
"id": "news.cluster-audit",
"version": "1.0.0",
"version": "1.0.0",
@@ -2886,6 +2946,16 @@
@@ -2886,6 +2946,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "reviews.moderation.action",
+ "version": "1.0.0",
+ "owner": "reviews",
+ "schema": "events/payloads/reviews.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "reviews.correction-submit-request",
"id": "reviews.correction-submit-request",
"version": "1.0.0",
"version": "1.0.0",
@@ -3165,6 +3235,16 @@
@@ -3165,6 +3235,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "coupons.moderation.action",
+ "version": "1.0.0",
+ "owner": "coupons",
+ "schema": "events/payloads/coupons.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "coupons.coupon",
"id": "coupons.coupon",
"version": "1.0.0",
"version": "1.0.0",
@@ -3327,6 +3407,16 @@
@@ -3327,6 +3407,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "deals.moderation.action",
+ "version": "1.0.0",
+ "owner": "deals",
+ "schema": "events/payloads/deals.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "deals.flag-request",
"id": "deals.flag-request",
"version": "1.0.0",
"version": "1.0.0",
@@ -3507,6 +3597,16 @@
@@ -3507,6 +3597,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "trade.moderation.action",
+ "version": "1.0.0",
+ "owner": "trade",
+ "schema": "events/payloads/trade.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "trade.alert-read-result",
"id": "trade.alert-read-result",
"version": "1.0.0",
"version": "1.0.0",
@@ -3768,6 +3868,16 @@
@@ -3768,6 +3868,16 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "games.moderation.action",
+ "version": "1.0.0",
+ "owner": "games",
+ "schema": "events/payloads/games.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-022"
+ },
{
{
"id": "games.announce-frame",
"id": "games.announce-frame",
"version": "1.0.0",
"version": "1.0.0",
new file mode 100644
new file mode 100644
@@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/common/moderation-action.v1.json",
+ "title": "ModerationAction",
+ "description": "common.moderation-action@1 (ADR-022, roadmap WS-D task 1): one staff or moderator action on someone else's content or account, as a service reports it to OpenVibe.Network's moderation audit log. The payload of every <service>.moderation.action event that has no older shape of its own (tools, games, wiki, blog, news, reviews, deals, coupons, trade, codes); modelled on community.moderation.action@1. Written to the service's outbox in the transaction that performs the action. A person acting on their own content is not moderation and is not reported. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself, a secret or an address.",
+ "type": "object",
+ "required": ["action", "target", "actor_subject"],
+ "additionalProperties": false,
+ "properties": {
+ "action": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$",
+ "description": "A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked)."
+ },
+ "target": {
+ "type": "object",
+ "required": ["type", "id"],
+ "additionalProperties": false,
+ "properties": {
+ "type": { "type": "string", "minLength": 1, "maxLength": 40, "pattern": "^[a-z][a-z0-9_]*$", "description": "What was acted on, in the service's own words (post, page, release, user, player, …)." },
+ "id": { "type": "string", "minLength": 1, "maxLength": 200 },
+ "owner_subject": { "type": ["string", "null"], "maxLength": 200, "description": "Whose content or account it was, when known." }
+ }
+ },
+ "actor_subject": { "type": ["string", "null"], "maxLength": 200, "description": "The staff member or moderator (null only for a service acting without a person)." },
+ "reason": { "type": ["string", "null"], "maxLength": 500 },
+ "details": { "type": "object", "description": "Per action: the fields changed, the previous and new state, a bulk action's count, … never the content." }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/blog.moderation.action.v1.json",
+ "title": "BlogModerationActionPayload",
+ "description": "blog.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Blog, such as editorial moderation of someone else's post or blog: hiding, unpublishing, deleting or restoring it, suspending a blog. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/codes.moderation.action.v1.json",
+ "title": "CodesModerationActionPayload",
+ "description": "codes.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Codes, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/coupons.moderation.action.v1.json",
+ "title": "CouponsModerationActionPayload",
+ "description": "coupons.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Coupons, such as approving, disabling or removing someone else's coupon, resolving reports, changing a merchant's status. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/deals.moderation.action.v1.json",
+ "title": "DealsModerationActionPayload",
+ "description": "deals.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Deals, such as resolving flags, hiding, removing or restoring someone else's offer or comment. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/games.moderation.action.v1.json",
+ "title": "GamesModerationActionPayload",
+ "description": "games.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Games, such as kicking or banning a player, lifting a ban, and revoking or disabling someone else's mod. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/news.moderation.action.v1.json",
+ "title": "NewsModerationActionPayload",
+ "description": "news.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.News, such as editorial moderation: unpublishing, retracting or restoring a story, resolving flags, blocking a source. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/reviews.moderation.action.v1.json",
+ "title": "ReviewsModerationActionPayload",
+ "description": "reviews.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Reviews, such as editorial moderation: removing or restoring someone else's signal or review, unpublishing a summary, merging or splitting entities. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/tools.moderation.action.v1.json",
+ "title": "ToolsModerationActionPayload",
+ "description": "tools.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Tools (apps/gateway and its guard), such as guard blocks and unblocks of an account, an app or an address, and staff actions on someone else's jobs or tool pages. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/trade.moderation.action.v1.json",
+ "title": "TradeModerationActionPayload",
+ "description": "trade.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Trade, such as hiding, removing or restoring someone else's listing or observation. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/wiki.moderation.action.v1.json",
+ "title": "WikiModerationActionPayload",
+ "description": "wiki.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Wiki, such as editorial moderation of someone else's page or revision: hiding, unpublishing, deleting, restoring, locking or reverting. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "post.unpublished",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "doxxing"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "action": "post.unpublished",
+ "target": {
+ "type": "post",
+ "id": "pst_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "doxxing",
+ "details": {
+ "previous": "published"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "release.revoked",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "malware in 1.4.2"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+{
+ "action": "release.revoked",
+ "target": {
+ "type": "release",
+ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPT",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "malware in 1.4.2",
+ "details": {
+ "app": "app_3",
+ "version": "1.4.2"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "action": "Hid The Post",
+ "target": {
+ "type": "post",
+ "id": "x"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
+{
+ "action": "post.hidden",
+ "target": {
+ "type": "post",
+ "id": "x"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "content": "the post text"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "action": "post.hidden",
+ "target": {
+ "type": "post",
+ "id": "x"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
+{
+ "action": "post.hidden",
+ "target": {
+ "type": "post",
+ "id": "x"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
+{
+ "action": "post.hidden",
+ "target": {
+ "type": "post",
+ "id": "x",
+ "title": "Hello"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "action": "post.hidden",
+ "target": {
+ "type": "post"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "action": "user.banned",
+ "target": {
+ "type": "user",
+ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+{
+ "action": "post.hidden",
+ "target": {
+ "type": "post",
+ "id": "pst_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "spam",
+ "details": {
+ "previous": "published",
+ "now": "hidden"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
+{
+ "action": "guard.blocked",
+ "target": {
+ "type": "address",
+ "id": "ip:3f9a1c"
+ },
+ "actor_subject": null,
+ "reason": null,
+ "details": {
+ "rule": "rate"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "coupon.disabled",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "action": "coupon.disabled",
+ "target": {
+ "type": "coupon",
+ "id": "cpn_12",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": null,
+ "details": {
+ "reports": 4
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "offer.hidden",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "expired code reposted"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "action": "offer.hidden",
+ "target": {
+ "type": "offer",
+ "id": "off_5",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "expired code reposted",
+ "details": {
+ "flags_resolved": 3
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "player.banned",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "griefing"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+{
+ "action": "player.banned",
+ "target": {
+ "type": "player",
+ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "griefing",
+ "details": {
+ "world": "wld_1",
+ "duration_s": 86400
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "story.retracted",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "fabricated source"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
+{
+ "action": "story.retracted",
+ "target": {
+ "type": "story",
+ "id": "sty_17",
+ "owner_subject": null
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "fabricated source",
+ "details": {}
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "signal.removed",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "fake review"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "action": "signal.removed",
+ "target": {
+ "type": "signal",
+ "id": "sig_9",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "fake review",
+ "details": {
+ "entity": "ent_3"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "guard.blocked",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "scripted abuse of the image tools"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+{
+ "action": "guard.blocked",
+ "target": {
+ "type": "user",
+ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "scripted abuse of the image tools",
+ "details": {
+ "scope": "account",
+ "expires_at": "2026-10-02T00:00:00Z"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "listing.removed",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "counterfeit"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
+{
+ "action": "listing.removed",
+ "target": {
+ "type": "listing",
+ "id": "lst_8",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "counterfeit",
+ "details": {}
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "page.locked",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "edit war"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
+{
+ "action": "page.locked",
+ "target": {
+ "type": "page",
+ "id": "pg_42",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "edit war",
+ "details": {}
+}
@@ -1995,6 +1995,82 @@
@@ -1995,6 +1995,82 @@
]
]
}
}
},
},
+ "common.moderation-action": {
+ "version": "1.0.0",
+ "owner": "network",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/common/moderation-action.v1.json",
+ "title": "ModerationAction",
+ "description": "common.moderation-action@1 (ADR-022, roadmap WS-D task 1): one staff or moderator action on someone else's content or account, as a service reports it to OpenVibe.Network's moderation audit log. The payload of every <service>.moderation.action event that has no older shape of its own (tools, games, wiki, blog, news, reviews, deals, coupons, trade, codes); modelled on community.moderation.action@1. Written to the service's outbox in the transaction that performs the action. A person acting on their own content is not moderation and is not reported. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself, a secret or an address.",
+ "type": "object",
+ "required": [
+ "action",
+ "target",
+ "actor_subject"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "action": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$",
+ "description": "A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked)."
+ },
+ "target": {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 40,
+ "pattern": "^[a-z][a-z0-9_]*$",
+ "description": "What was acted on, in the service's own words (post, page, release, user, player, …)."
+ },
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "owner_subject": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 200,
+ "description": "Whose content or account it was, when known."
+ }
+ }
+ },
+ "actor_subject": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 200,
+ "description": "The staff member or moderator (null only for a service acting without a person)."
+ },
+ "reason": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 500
+ },
+ "details": {
+ "type": "object",
+ "description": "Per action: the fields changed, the previous and new state, a bulk action's count, … never the content."
+ }
+ }
+ }
+ },
"media.file-upload": {
"media.file-upload": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "media",
"owner": "media",
@@ -4028,6 +4104,18 @@
@@ -4028,6 +4104,18 @@
]
]
}
}
},
},
+ "codes.moderation.action": {
+ "version": "1.0.0",
+ "owner": "codes",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/codes.moderation.action.v1.json",
+ "title": "CodesModerationActionPayload",
+ "description": "codes.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Codes, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"events.redaction-directive": {
"events.redaction-directive": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "events",
"owner": "events",
@@ -6934,6 +7022,18 @@
@@ -6934,6 +7022,18 @@
}
}
}
}
},
},
+ "wiki.moderation.action": {
+ "version": "1.0.0",
+ "owner": "wiki",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/wiki.moderation.action.v1.json",
+ "title": "WikiModerationActionPayload",
+ "description": "wiki.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Wiki, such as editorial moderation of someone else's page or revision: hiding, unpublishing, deleting, restoring, locking or reverting. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"wiki.citation-attach-request": {
"wiki.citation-attach-request": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "wiki",
"owner": "wiki",
@@ -9503,6 +9603,18 @@
@@ -9503,6 +9603,18 @@
}
}
}
}
},
},
+ "blog.moderation.action": {
+ "version": "1.0.0",
+ "owner": "blog",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/blog.moderation.action.v1.json",
+ "title": "BlogModerationActionPayload",
+ "description": "blog.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Blog, such as editorial moderation of someone else's post or blog: hiding, unpublishing, deleting or restoring it, suspending a blog. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"blog.blog-configure-request": {
"blog.blog-configure-request": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "blog",
"owner": "blog",
@@ -22914,6 +23026,18 @@
@@ -22914,6 +23026,18 @@
}
}
}
}
},
},
+ "tools.moderation.action": {
+ "version": "1.0.0",
+ "owner": "tools",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/tools.moderation.action.v1.json",
+ "title": "ToolsModerationActionPayload",
+ "description": "tools.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Tools (apps/gateway and its guard), such as guard blocks and unblocks of an account, an app or an address, and staff actions on someone else's jobs or tool pages. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"live.stream.started": {
"live.stream.started": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "live",
"owner": "live",
@@ -27577,6 +27701,18 @@
@@ -27577,6 +27701,18 @@
}
}
}
}
},
},
+ "news.moderation.action": {
+ "version": "1.0.0",
+ "owner": "news",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/news.moderation.action.v1.json",
+ "title": "NewsModerationActionPayload",
+ "description": "news.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.News, such as editorial moderation: unpublishing, retracting or restoring a story, resolving flags, blocking a source. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"news.cluster-audit": {
"news.cluster-audit": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "news",
"owner": "news",
@@ -31586,6 +31722,18 @@
@@ -31586,6 +31722,18 @@
}
}
}
}
},
},
+ "reviews.moderation.action": {
+ "version": "1.0.0",
+ "owner": "reviews",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/reviews.moderation.action.v1.json",
+ "title": "ReviewsModerationActionPayload",
+ "description": "reviews.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Reviews, such as editorial moderation: removing or restoring someone else's signal or review, unpublishing a summary, merging or splitting entities. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"reviews.correction-submit-request": {
"reviews.correction-submit-request": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "reviews",
"owner": "reviews",
@@ -36392,6 +36540,18 @@
@@ -36392,6 +36540,18 @@
}
}
}
}
},
},
+ "coupons.moderation.action": {
+ "version": "1.0.0",
+ "owner": "coupons",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/coupons.moderation.action.v1.json",
+ "title": "CouponsModerationActionPayload",
+ "description": "coupons.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Coupons, such as approving, disabling or removing someone else's coupon, resolving reports, changing a merchant's status. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"coupons.coupon": {
"coupons.coupon": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "coupons",
"owner": "coupons",
@@ -38010,6 +38170,18 @@
@@ -38010,6 +38170,18 @@
}
}
}
}
},
},
+ "deals.moderation.action": {
+ "version": "1.0.0",
+ "owner": "deals",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/deals.moderation.action.v1.json",
+ "title": "DealsModerationActionPayload",
+ "description": "deals.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Deals, such as resolving flags, hiding, removing or restoring someone else's offer or comment. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"deals.flag-request": {
"deals.flag-request": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "deals",
"owner": "deals",
@@ -40264,6 +40436,18 @@
@@ -40264,6 +40436,18 @@
}
}
}
}
},
},
+ "trade.moderation.action": {
+ "version": "1.0.0",
+ "owner": "trade",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/trade.moderation.action.v1.json",
+ "title": "TradeModerationActionPayload",
+ "description": "trade.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Trade, such as hiding, removing or restoring someone else's listing or observation. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"trade.alert-read-result": {
"trade.alert-read-result": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "trade",
"owner": "trade",
@@ -42777,6 +42961,18 @@
@@ -42777,6 +42961,18 @@
}
}
}
}
},
},
+ "games.moderation.action": {
+ "version": "1.0.0",
+ "owner": "games",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/games.moderation.action.v1.json",
+ "title": "GamesModerationActionPayload",
+ "description": "games.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Games, such as kicking or banning a player, lifting a ban, and revoking or disabling someone else's mod. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"games.announce-frame": {
"games.announce-frame": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "games",
"owner": "games",
@@ -736,6 +736,37 @@ export type ConfigSnapshot = {
@@ -736,6 +736,37 @@ export type ConfigSnapshot = {
copied_from?: number | null;
copied_from?: number | null;
};
};
+/** [email protected] (owner: network) */
+/**
+ * common.moderation-action@1 (ADR-022, roadmap WS-D task 1): one staff or moderator action on someone else's content or account, as a service reports it to OpenVibe.Network's moderation audit log. The payload of every <service>.moderation.action event that has no older shape of its own (tools, games, wiki, blog, news, reviews, deals, coupons, trade, codes); modelled on community.moderation.action@1. Written to the service's outbox in the transaction that performs the action. A person acting on their own content is not moderation and is not reported. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself, a secret or an address.
+ */
+export interface ModerationAction {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: media) */
/** [email protected] (owner: media) */
/**
/**
* media.file-upload@1: the multipart/form-data body of POST /api/v1/:app/files (media.object.upload, namespace :app): one part named `file` with the bytes and its filename and type. The tenant's quota is checked against the bytes; the answer is media.file@1 (201).
* media.file-upload@1: the multipart/form-data body of POST /api/v1/:app/files (media.object.upload, namespace :app): one part named `file` with the bytes and its filename and type. The tenant's quota is checked against the bytes; the answer is media.file@1 (201).
@@ -5969,6 +6000,37 @@ export type CodesReleaseManageRequest =
@@ -5969,6 +6000,37 @@ export type CodesReleaseManageRequest =
}
}
| NoBody;
| NoBody;
+/** [email protected] (owner: codes) */
+/**
+ * codes.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Codes, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface CodesModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: events) */
/** [email protected] (owner: events) */
/**
/**
* payload.redacts (ADR-026): a producer takes back events it published earlier. Any event may carry it, normally the producer's own *.deleted event. It names event_ids, or subject_type + subject_ids, or both, never an empty list. event_ids names events directly; subject_type + subject_ids names every stored event of the same source (for an app, the same project and environment) about those subjects. OpenVibe.Events rewrites each target into a tombstone (events.tombstone-payload@1) in the transaction that stores the directive. Naming another source's event is 403 events.redaction_not_allowed (the whole batch is refused); a malformed directive is 422 events.invalid_redaction. An event that carries a directive is never redacted itself.
* payload.redacts (ADR-026): a producer takes back events it published earlier. Any event may carry it, normally the producer's own *.deleted event. It names event_ids, or subject_type + subject_ids, or both, never an empty list. event_ids names events directly; subject_type + subject_ids names every stored event of the same source (for an app, the same project and environment) about those subjects. OpenVibe.Events rewrites each target into a tombstone (events.tombstone-payload@1) in the transaction that stores the directive. Naming another source's event is 403 events.redaction_not_allowed (the whole batch is refused); a malformed directive is 422 events.invalid_redaction. An event that carries a directive is never redacted itself.
@@ -12458,6 +12520,37 @@ export interface WikiIndexDocumentDeletedPayload {
@@ -12458,6 +12520,37 @@ export interface WikiIndexDocumentDeletedPayload {
revision: number;
revision: number;
}
}
+/** [email protected] (owner: wiki) */
+/**
+ * wiki.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Wiki, such as editorial moderation of someone else's page or revision: hiding, unpublishing, deleting, restoring, locking or reverting. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface WikiModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: wiki) */
/** [email protected] (owner: wiki) */
/**
/**
* wiki.citation-attach-request@1: the body of POST /api/v1/pages/:id/revisions/:n/citations on OpenVibe.Wiki (wiki.citation.attach, editors): sources for the newest revision while it is unpublished (a published revision's sources are fixed: 409 citation.revision_published; an older one is 409 citation.not_head). A URL citation needs retrieved_at; a Sources item id brings its own URL, title and retrieval time.
* wiki.citation-attach-request@1: the body of POST /api/v1/pages/:id/revisions/:n/citations on OpenVibe.Wiki (wiki.citation.attach, editors): sources for the newest revision while it is unpublished (a published revision's sources are fixed: 409 citation.revision_published; an older one is 409 citation.not_head). A URL citation needs retrieved_at; a Sources item id brings its own URL, title and retrieval time.
@@ -13786,6 +13879,37 @@ export interface BlogIndexDocumentDeletedPayload {
@@ -13786,6 +13879,37 @@ export interface BlogIndexDocumentDeletedPayload {
revision: number;
revision: number;
}
}
+/** [email protected] (owner: blog) */
+/**
+ * blog.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Blog, such as editorial moderation of someone else's post or blog: hiding, unpublishing, deleting or restoring it, suspending a blog. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface BlogModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: blog) */
/** [email protected] (owner: blog) */
/**
/**
* blog.blog-configure-request@1: the body of PATCH /api/v1/blogs/:handle on OpenVibe.Blog (blog.blog.configure; an owner): title (at most 120 characters, not blank), description (500), language (a BCP 47 tag) and feeds { rss, atom, json, item_count (1-50), full_content }. Fields left out keep their value.
* blog.blog-configure-request@1: the body of PATCH /api/v1/blogs/:handle on OpenVibe.Blog (blog.blog.configure; an owner): title (at most 120 characters, not blank), description (500), language (a BCP 47 tag) and feeds { rss, atom, json, item_count (1-50), full_content }. Fields left out keep their value.
@@ -24433,6 +24557,37 @@ export interface ToolsJobFailedPayload {
@@ -24433,6 +24557,37 @@ export interface ToolsJobFailedPayload {
retryable: boolean;
retryable: boolean;
}
}
+/** [email protected] (owner: tools) */
+/**
+ * tools.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Tools (apps/gateway and its guard), such as guard blocks and unblocks of an account, an app or an address, and staff actions on someone else's jobs or tool pages. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface ToolsModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: live) */
/** [email protected] (owner: live) */
/**
/**
* live.stream.started v1 (OpenVibe.Live server/events/stream-events.js envelopeFor, fired by server/db/database.js createStream). A streams row went live: WebRTC/JSMPEG from the dashboard, RTMP ingest, WHIP, or an OpenRe.Stream session mirrored into Live. Written to Live's event_outbox in the transaction that inserts the row, so the event exists if and only if the stream did. Carries public channel facts only (the stream is listed publicly already); consumers such as Network's go-live notifications decide who hears about it. Never the stream key, the Live user id or the description. Envelope: subject { type: stream, id: <stream_id as a string>, revision: 1 }, visibility public, priority important, actor the streamer's user subject when Live knows it, else service:live.
* live.stream.started v1 (OpenVibe.Live server/events/stream-events.js envelopeFor, fired by server/db/database.js createStream). A streams row went live: WebRTC/JSMPEG from the dashboard, RTMP ingest, WHIP, or an OpenRe.Stream session mirrored into Live. Written to Live's event_outbox in the transaction that inserts the row, so the event exists if and only if the stream did. Carries public channel facts only (the stream is listed publicly already); consumers such as Network's go-live notifications decide who hears about it. Never the stream key, the Live user id or the description. Envelope: subject { type: stream, id: <stream_id as a string>, revision: 1 }, visibility public, priority important, actor the streamer's user subject when Live knows it, else service:live.
@@ -26852,6 +27007,37 @@ export interface NewsIndexDocumentDeletedPayload {
@@ -26852,6 +27007,37 @@ export interface NewsIndexDocumentDeletedPayload {
revision: number;
revision: number;
}
}
+/** [email protected] (owner: news) */
+/**
+ * news.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.News, such as editorial moderation: unpublishing, retracting or restoring a story, resolving flags, blocking a source. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface NewsModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: news) */
/** [email protected] (owner: news) */
/**
/**
* news.cluster-audit@1: one audited cluster change on OpenVibe.News (server/domain/clusters.js shapeAudit): a merge, a split or the reversal of one, with exactly which source items moved, who did it and why. Merge: cluster_id survived and other_id was absorbed; split: other_id is the new cluster.
* news.cluster-audit@1: one audited cluster change on OpenVibe.News (server/domain/clusters.js shapeAudit): a merge, a split or the reversal of one, with exactly which source items moved, who did it and why. Merge: cluster_id survived and other_id was absorbed; split: other_id is the new cluster.
@@ -29470,6 +29656,37 @@ export interface ReviewsIndexDocumentDeletedPayload {
@@ -29470,6 +29656,37 @@ export interface ReviewsIndexDocumentDeletedPayload {
revision: number;
revision: number;
}
}
+/** [email protected] (owner: reviews) */
+/**
+ * reviews.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Reviews, such as editorial moderation: removing or restoring someone else's signal or review, unpublishing a summary, merging or splitting entities. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface ReviewsModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: reviews) */
/** [email protected] (owner: reviews) */
/**
/**
* reviews.correction-submit-request@1: the body of reviews.correction.submit on OpenVibe.Reviews: POST /api/v1/entities/:ref/corrections { body, target_type?, target_id?, evidence_url? } sends a correction to the editors' queue for the person named in X-OV-Subject (a signed-in person: 403 reviews.person_required). Refusals: 422 correction.invalid (unknown target_type, body under 10 or over 4000 characters, evidence_url not http(s)), 409 correction.duplicate (the same open request again), 429 correction.rate_limited (20 a day per person), 404 entity.not_found, 410 entity.deleted.
* reviews.correction-submit-request@1: the body of reviews.correction.submit on OpenVibe.Reviews: POST /api/v1/entities/:ref/corrections { body, target_type?, target_id?, evidence_url? } sends a correction to the editors' queue for the person named in X-OV-Subject (a signed-in person: 403 reviews.person_required). Refusals: 422 correction.invalid (unknown target_type, body under 10 or over 4000 characters, evidence_url not http(s)), 409 correction.duplicate (the same open request again), 429 correction.rate_limited (20 a day per person), 404 entity.not_found, 410 entity.deleted.
@@ -35707,6 +35924,37 @@ export interface CouponsIndexDocumentDeletedPayload {
@@ -35707,6 +35924,37 @@ export interface CouponsIndexDocumentDeletedPayload {
revision: number;
revision: number;
}
}
+/** [email protected] (owner: coupons) */
+/**
+ * coupons.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Coupons, such as approving, disabling or removing someone else's coupon, resolving reports, changing a merchant's status. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface CouponsModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: coupons) */
/** [email protected] (owner: coupons) */
/**
/**
* coupons.coupon@1: one code as OpenVibe.Coupons shows it (server/domain/coupons.js view): its status and confidence come only from people's reports (counts in a window, report times rounded to the hour), a known or unknown expiry, restrictions, hints and evidence. No submitter or reporter is ever named.
* coupons.coupon@1: one code as OpenVibe.Coupons shows it (server/domain/coupons.js view): its status and confidence come only from people's reports (counts in a window, report times rounded to the hour), a known or unknown expiry, restrictions, hints and evidence. No submitter or reporter is ever named.
@@ -36715,6 +36963,37 @@ export interface DealsIndexDocumentDeletedPayload {
@@ -36715,6 +36963,37 @@ export interface DealsIndexDocumentDeletedPayload {
revision: number;
revision: number;
}
}
+/** [email protected] (owner: deals) */
+/**
+ * deals.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Deals, such as resolving flags, hiding, removing or restoring someone else's offer or comment. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface DealsModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: deals) */
/** [email protected] (owner: deals) */
/**
/**
* deals.flag-request@1: the body of POST /api/v1/offers/:id/flags on OpenVibe.Deals (deals.flag.create; a person): { kind, reason?, duplicate_of? } — duplicate_of (the other deal, id, slug or /d/ link) is required for kind duplicate. An open flag of the same kind by the same person is refreshed, not repeated.
* deals.flag-request@1: the body of POST /api/v1/offers/:id/flags on OpenVibe.Deals (deals.flag.create; a person): { kind, reason?, duplicate_of? } — duplicate_of (the other deal, id, slug or /d/ link) is required for kind duplicate. An open flag of the same kind by the same person is refreshed, not repeated.
@@ -37326,6 +37605,37 @@ export interface TradeIndexDocumentDeletedPayload {
@@ -37326,6 +37605,37 @@ export interface TradeIndexDocumentDeletedPayload {
revision: number;
revision: number;
}
}
+/** [email protected] (owner: trade) */
+/**
+ * trade.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Trade, such as hiding, removing or restoring someone else's listing or observation. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface TradeModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: trade) */
/** [email protected] (owner: trade) */
/**
/**
* trade.alert-read-result@1: answers of trade.alert.read on OpenVibe.Trade (the acting person's): GET /api/v1/alerts → { rules }; GET /api/v1/alerts/deliveries?limit= → { deliveries } (newest first, at most 200: which rule fired on what, and the event sent).
* trade.alert-read-result@1: answers of trade.alert.read on OpenVibe.Trade (the acting person's): GET /api/v1/alerts → { rules }; GET /api/v1/alerts/deliveries?limit= → { deliveries } (newest first, at most 200: which rule fired on what, and the event sent).
@@ -38317,6 +38627,37 @@ export interface GamesModRevokedPayload {
@@ -38317,6 +38627,37 @@ export interface GamesModRevokedPayload {
reason?: string;
reason?: string;
}
}
+/** [email protected] (owner: games) */
+/**
+ * games.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Games, such as kicking or banning a player, lifting a ban, and revoking or disabling someone else's mod. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface GamesModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: games) */
/** [email protected] (owner: games) */
/**
/**
* games.announce-frame@1: the frame OpenVibe.Games broadcasts to every connected player for an announcement (gameServer broadcastAll): { t: announce, text }. A mod's announcement text is prefixed with its name in brackets ([Mod name] text); the binding itself returns nothing.
* games.announce-frame@1: the frame OpenVibe.Games broadcasts to every connected player for an announcement (gameServer broadcastAll): { t: announce, text }. A mod's announcement text is prefixed with its name in brackets ([Mod name] text); the binding itself returns nothing.
@@ -48,7 +48,8 @@
@@ -48,7 +48,8 @@
"blog.post.deleted",
"blog.post.deleted",
"blog.schedule.failed",
"blog.schedule.failed",
"blog.index_document.upserted",
"blog.index_document.upserted",
- "blog.index_document.deleted"
+ "blog.index_document.deleted",
+ "blog.moderation.action"
],
],
"eventsConsumed": [],
"eventsConsumed": [],
"namespacesOwned": [
"namespacesOwned": [
@@ -33,7 +33,8 @@
@@ -33,7 +33,8 @@
"eventsProduced": [
"eventsProduced": [
"codes.app.published",
"codes.app.published",
"codes.app.deprecated",
"codes.app.deprecated",
- "codes.app.revoked"
+ "codes.app.revoked",
+ "codes.moderation.action"
],
],
"eventsConsumed": [],
"eventsConsumed": [],
"namespacesOwned": [
"namespacesOwned": [
@@ -43,7 +43,8 @@
@@ -43,7 +43,8 @@
"coupons.report.created",
"coupons.report.created",
"coupons.confidence.changed",
"coupons.confidence.changed",
"coupons.index_document.upserted",
"coupons.index_document.upserted",
- "coupons.index_document.deleted"
+ "coupons.index_document.deleted",
+ "coupons.moderation.action"
],
],
"eventsConsumed": [],
"eventsConsumed": [],
"namespacesOwned": [
"namespacesOwned": [
@@ -48,7 +48,8 @@
@@ -48,7 +48,8 @@
"deals.vote.changed",
"deals.vote.changed",
"deals.watch.matched",
"deals.watch.matched",
"deals.index_document.upserted",
"deals.index_document.upserted",
- "deals.index_document.deleted"
+ "deals.index_document.deleted",
+ "deals.moderation.action"
],
],
"eventsConsumed": [
"eventsConsumed": [
"sources.item.created",
"sources.item.created",
@@ -43,7 +43,8 @@
@@ -43,7 +43,8 @@
"games.mod.enabled",
"games.mod.enabled",
"games.mod.disabled",
"games.mod.disabled",
"games.mod.grants_changed",
"games.mod.grants_changed",
- "games.mod.revoked"
+ "games.mod.revoked",
+ "games.moderation.action"
],
],
"eventsConsumed": [
"eventsConsumed": [
"network.user.token_valid_after"
"network.user.token_valid_after"
@@ -60,13 +60,23 @@
@@ -60,13 +60,23 @@
],
],
"eventsConsumed": [
"eventsConsumed": [
"billing.staff.action",
"billing.staff.action",
+ "blog.moderation.action",
"chat.moderation.action",
"chat.moderation.action",
+ "codes.moderation.action",
"community.moderation.action",
"community.moderation.action",
+ "coupons.moderation.action",
+ "deals.moderation.action",
"deals.watch.matched",
"deals.watch.matched",
+ "games.moderation.action",
"live.moderation.action",
"live.moderation.action",
"live.stream.started",
"live.stream.started",
+ "news.moderation.action",
+ "reviews.moderation.action",
"tips.interaction.moderated",
"tips.interaction.moderated",
- "trade.alert.triggered"
+ "tools.moderation.action",
+ "trade.alert.triggered",
+ "trade.moderation.action",
+ "wiki.moderation.action"
],
],
"namespacesOwned": [
"namespacesOwned": [
"identity.*",
"identity.*",
@@ -51,7 +51,8 @@
@@ -51,7 +51,8 @@
"news.story.unpublished",
"news.story.unpublished",
"news.story.retracted",
"news.story.retracted",
"news.index_document.upserted",
"news.index_document.upserted",
- "news.index_document.deleted"
+ "news.index_document.deleted",
+ "news.moderation.action"
],
],
"eventsConsumed": [
"eventsConsumed": [
"sources.item.created",
"sources.item.created",
@@ -46,7 +46,8 @@
@@ -46,7 +46,8 @@
"reviews.summary.updated",
"reviews.summary.updated",
"reviews.summary.unpublished",
"reviews.summary.unpublished",
"reviews.index_document.upserted",
"reviews.index_document.upserted",
- "reviews.index_document.deleted"
+ "reviews.index_document.deleted",
+ "reviews.moderation.action"
],
],
"eventsConsumed": [
"eventsConsumed": [
"sources.item.created",
"sources.item.created",
@@ -38,7 +38,8 @@
@@ -38,7 +38,8 @@
"tools.job.created",
"tools.job.created",
"tools.job.started",
"tools.job.started",
"tools.job.succeeded",
"tools.job.succeeded",
- "tools.job.failed"
+ "tools.job.failed",
+ "tools.moderation.action"
],
],
"eventsConsumed": [
"eventsConsumed": [
"network.user.token_valid_after"
"network.user.token_valid_after"
@@ -47,7 +47,8 @@
@@ -47,7 +47,8 @@
"trade.source.stale",
"trade.source.stale",
"trade.source.recovered",
"trade.source.recovered",
"trade.index_document.upserted",
"trade.index_document.upserted",
- "trade.index_document.deleted"
+ "trade.index_document.deleted",
+ "trade.moderation.action"
],
],
"eventsConsumed": [
"eventsConsumed": [
"sources.item.created",
"sources.item.created",
@@ -45,7 +45,8 @@
@@ -45,7 +45,8 @@
"wiki.page.deleted",
"wiki.page.deleted",
"wiki.watch.triggered",
"wiki.watch.triggered",
"wiki.index_document.upserted",
"wiki.index_document.upserted",
- "wiki.index_document.deleted"
+ "wiki.index_document.deleted",
+ "wiki.moderation.action"
],
],
"eventsConsumed": [],
"eventsConsumed": [],
"namespacesOwned": [
"namespacesOwned": [
@@ -655,6 +655,26 @@ await assert.rejects(failing.getToken(), /401: invalid_client/);
@@ -655,6 +655,26 @@ await assert.rejects(failing.getToken(), /401: invalid_client/);
}
}
}
}
+// ── Moderation audit events (ADR-022, WS-D task 1): one shared payload, one event per producer ──
+// Events requires an event's prefix to be its source, so each service has its own type; the ones
+// without an older shape are common.moderation-action@1, and Network consumes every one of them.
+{
+ const moderation = contracts.catalog.filter(c => /\.moderation\.action$/.test(c.id));
+ for (const svc of ['tools', 'games', 'wiki', 'blog', 'news', 'reviews', 'deals', 'coupons', 'trade', 'codes']) {
+ const id = `${svc}.moderation.action`;
+ const c = moderation.find(x => x.id === id);
+ ok(c && c.owner === svc && c.adr === 'ADR-022', `${id} is owned by ${svc}`);
+ ok(contracts.schema(id).$ref === '../../common/moderation-action.v1.json', `${id} is a common.moderation-action@1`);
+ }
+ for (const c of moderation) ok(services.get('network').eventsConsumed.includes(c.id), `network consumes ${c.id} into the moderation audit log`);
+ const M = (v) => contracts.validate('common.moderation-action@1', v).valid;
+ const base = { action: 'post.hidden', target: { type: 'post', id: 'p1', owner_subject: null }, actor_subject: null };
+ ok(M(base) && M({ ...base, reason: 'spam', details: { previous: 'published' } }), 'action, target and actor_subject are enough; reason and details are optional');
+ for (const k of ['action', 'target', 'actor_subject']) ok(!M({ ...base, [k]: undefined }), `a moderation action needs ${k}`);
+ for (const action of ['Post.Hidden', 'post hidden', 'post.', '.hidden', 'x'.repeat(65)]) ok(!M({ ...base, action }), `"${action.slice(0, 12)}" is not a verb id`);
+ ok(!M({ ...base, text: 'the post' }) && !M({ ...base, target: { ...base.target, title: 'Hi' } }), 'it never carries the content');
+}
+
// ── Capability schemas (WS-C task 4): a ratchet over compatibility/capability-schema-gaps.json ──
// ── Capability schemas (WS-C task 4): a ratchet over compatibility/capability-schema-gaps.json ──
execFileSync(process.execPath, [path.join(__dirname, 'capability-schemas.test.js')], { stdio: 'inherit' });
execFileSync(process.execPath, [path.join(__dirname, 'capability-schemas.test.js')], { stdio: 'inherit' });