@calmlens/sdk 0.16.2 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +399 -162
- package/cjs/BrowserUpload-DZ0Vbmxi.js +10 -0
- package/cjs/BrowserUpload-uZjVFGfP.d.ts +11 -0
- package/cjs/CalmLensAppClient-CV_K26Ce.d.ts +40 -0
- package/cjs/CalmLensAppClient-DBGmaDlG.js +89 -0
- package/cjs/CalmLensConnection-K1TAD1Z-.js +659 -0
- package/cjs/CalmLensServerClient-C-pxiz0C.js +645 -0
- package/cjs/CalmLensServerClient-JtP687a3.d.ts +235 -0
- package/cjs/CalmLensTypes-9Vt16pc7.d.ts +40400 -0
- package/cjs/Classification-94kSYWZw-CMnQKW13.d.ts +5873 -0
- package/cjs/CryptoUtils-B_x8lMIx-YBW1-bvL.js +42 -0
- package/cjs/FileIcons-Ob003MdS.js +175 -0
- package/cjs/Jurisdiction-FusEXb4U-zVs21tDv.js +91 -0
- package/cjs/ModerationContext-9lGm-Mna-CcmbRnOy.d.ts +67 -0
- package/cjs/ModerationContextLimits-Dj1YAl3G.js +1311 -0
- package/cjs/ReactUpload-DxtFMr06.js +54 -0
- package/cjs/ReactUpload-nZahpmyg.d.ts +17 -0
- package/cjs/TestTriggers-By07LR31-CmK0yTyR.d.ts +271 -0
- package/cjs/TestTriggers-DcArt0Nu-CvoaONUB.js +1326 -0
- package/cjs/UploadController-BBkN4Ni6.js +618 -0
- package/{esm/index-C9Xw1aid.d.ts → cjs/WebhookPayload-2aL31v0J.d.ts} +131 -155
- package/cjs/app.d.ts +7 -44
- package/cjs/app.js +11 -89
- package/cjs/elements.d.ts +88 -0
- package/cjs/elements.js +555 -0
- package/cjs/file-icons.d.ts +67 -0
- package/cjs/file-icons.js +10 -0
- package/cjs/index-CI4BzN4W.d.ts +252 -0
- package/cjs/index.d.ts +6 -4
- package/cjs/index.js +9 -4
- package/cjs/react-native.d.ts +56 -0
- package/cjs/react-native.js +495 -0
- package/cjs/react.d.ts +30 -0
- package/cjs/react.js +370 -0
- package/cjs/server.d.ts +12 -191
- package/cjs/server.js +18 -378
- package/cjs/test-inputs.d.ts +2 -2
- package/cjs/test-inputs.js +9 -264
- package/cjs/testing.d.ts +285 -190
- package/cjs/testing.js +2393 -1203
- package/cjs/ui-CgZpgpNo.d.ts +526 -0
- package/cjs/ui-KceuoVCM.js +583 -0
- package/cjs/ui.d.ts +2 -0
- package/cjs/ui.js +27 -0
- package/cjs/vue.d.ts +490 -0
- package/cjs/vue.js +419 -0
- package/esm/BrowserUpload-D7-zNmc0.js +5 -0
- package/esm/BrowserUpload-uZjVFGfP.d.ts +11 -0
- package/esm/CalmLensAppClient-CV_K26Ce.d.ts +40 -0
- package/esm/CalmLensAppClient-FVMwrHlH.js +84 -0
- package/esm/CalmLensConnection-iyNQHA8L.js +582 -0
- package/esm/CalmLensServerClient-JtP687a3.d.ts +235 -0
- package/esm/CalmLensServerClient-fQEYKLw4.js +586 -0
- package/esm/CalmLensTypes-9Vt16pc7.d.ts +40400 -0
- package/esm/Classification-94kSYWZw-CMnQKW13.d.ts +5873 -0
- package/esm/CryptoUtils-B_x8lMIx-DhuWGzqn.js +25 -0
- package/esm/FileIcons-M6dzjFxd.js +128 -0
- package/esm/Jurisdiction-FusEXb4U-1ov6m5yE.js +46 -0
- package/esm/ModerationContext-9lGm-Mna-CcmbRnOy.d.ts +67 -0
- package/esm/ModerationContextLimits-D1x_WAtP.js +1114 -0
- package/esm/ReactUpload-D6yBCkcw.js +37 -0
- package/esm/ReactUpload-nZahpmyg.d.ts +17 -0
- package/esm/TestTriggers-By07LR31-CmK0yTyR.d.ts +271 -0
- package/esm/TestTriggers-DcArt0Nu-s0AQZuWE.js +1266 -0
- package/esm/UploadController-txp5NuzH.js +589 -0
- package/{cjs/index-C9Xw1aid.d.ts → esm/WebhookPayload-2aL31v0J.d.ts} +131 -155
- package/esm/app.d.ts +7 -44
- package/esm/app.js +3 -86
- package/esm/elements.d.ts +88 -0
- package/esm/elements.js +528 -0
- package/esm/file-icons.d.ts +67 -0
- package/esm/file-icons.js +1 -0
- package/esm/index-CI4BzN4W.d.ts +252 -0
- package/esm/index.d.ts +6 -4
- package/esm/index.js +1 -1
- package/esm/react-native.d.ts +56 -0
- package/esm/react-native.js +467 -0
- package/esm/react.d.ts +30 -0
- package/esm/react.js +343 -0
- package/esm/server.d.ts +12 -191
- package/esm/server.js +3 -369
- package/esm/styles.css +147 -0
- package/esm/svelte/CalmLensMedia.svelte +134 -0
- package/esm/svelte/CalmLensUploader.svelte +175 -0
- package/esm/svelte/Icon.svelte +7 -0
- package/esm/svelte/index.d.ts +37 -0
- package/esm/svelte/index.js +6 -0
- package/esm/test-inputs.d.ts +2 -2
- package/esm/test-inputs.js +1 -256
- package/esm/testing.d.ts +285 -190
- package/esm/testing.js +2329 -1122
- package/esm/ui-Ca_SpJXf.js +458 -0
- package/esm/ui-CgZpgpNo.d.ts +526 -0
- package/esm/ui.d.ts +2 -0
- package/esm/ui.js +3 -0
- package/esm/vue.d.ts +490 -0
- package/esm/vue.js +392 -0
- package/package.json +110 -11
- package/cjs/CalmLensConnection-5Hj3trGr.js +0 -234
- package/cjs/CalmLensUtils-BeIl1N6N.js +0 -699
- package/cjs/CalmLensVersion-BGpB9t4-.js +0 -480
- package/cjs/CalmLensWebhooks-CogUYk8-.js +0 -201
- package/cjs/Classification-BNhgwGEm-DmA9VEuE.d.ts +0 -4806
- package/cjs/TestTriggers-CRKtulyp-vrzEq2wm.d.ts +0 -44
- package/cjs/WebhookPayload-CJoIkGBD.d.ts +0 -11753
- package/esm/CalmLensConnection-BAJdoZHy.js +0 -193
- package/esm/CalmLensUtils-DqniTKJ8.js +0 -574
- package/esm/CalmLensVersion-l_khh4nS.js +0 -415
- package/esm/CalmLensWebhooks-BtrKKLvg.js +0 -148
- package/esm/Classification-BNhgwGEm-DmA9VEuE.d.ts +0 -4806
- package/esm/TestTriggers-CRKtulyp-vrzEq2wm.d.ts +0 -44
- package/esm/WebhookPayload-CJoIkGBD.d.ts +0 -11753
|
@@ -0,0 +1,1326 @@
|
|
|
1
|
+
const require_Jurisdiction_FusEXb4U = require("./Jurisdiction-FusEXb4U-zVs21tDv.js");
|
|
2
|
+
const require_CryptoUtils_B_x8lMIx = require("./CryptoUtils-B_x8lMIx-YBW1-bvL.js");
|
|
3
|
+
let zod = require("zod");
|
|
4
|
+
zod = require_Jurisdiction_FusEXb4U.__toESM(zod, 1);
|
|
5
|
+
// src/contract/TestRegionalActions-DfPCKG4S.js
|
|
6
|
+
/**
|
|
7
|
+
* Marks English text in shared, backend and data modules that the portal shows, so the app's
|
|
8
|
+
* message catalog (packages/app/vite/messageCatalog.ts) extracts it and the portal can translate it
|
|
9
|
+
* where it renders (`useTranslateText()` from `#i18n`). Returns the text unchanged: the API, events,
|
|
10
|
+
* emails and logs keep English. Only a string literal argument is extracted.
|
|
11
|
+
*/
|
|
12
|
+
const msg = (text) => text;
|
|
13
|
+
const CLASSIFICATION_CATEGORIES = [
|
|
14
|
+
"sexual",
|
|
15
|
+
"violence",
|
|
16
|
+
"self-harm",
|
|
17
|
+
"harassment",
|
|
18
|
+
"hate",
|
|
19
|
+
"criminal-activity",
|
|
20
|
+
"personal-information",
|
|
21
|
+
"profanity"
|
|
22
|
+
];
|
|
23
|
+
const MODERATION_QUALIFIER_INFO = {
|
|
24
|
+
"sexual-pornographic-media": {
|
|
25
|
+
category: "sexual",
|
|
26
|
+
kind: "harm",
|
|
27
|
+
harmOption: false,
|
|
28
|
+
displayName: msg("Pornographic images or video"),
|
|
29
|
+
description: msg("An image or video frame depicting explicit sexual activity or exposed sexual anatomy presented primarily for sexual arousal, including drawn, animated or generated adult pornography."),
|
|
30
|
+
exclusions: "Text, non-erotic nudity, medical or educational anatomy, breastfeeding, art without pornographic presentation, swimwear and suggestive content.",
|
|
31
|
+
inputs: ["image"]
|
|
32
|
+
},
|
|
33
|
+
"hate-nazi-symbols-public-display": {
|
|
34
|
+
category: "hate",
|
|
35
|
+
kind: "harm",
|
|
36
|
+
harmOption: false,
|
|
37
|
+
displayName: msg("Public Nazi symbols outside supported context"),
|
|
38
|
+
description: msg("A clearly identifiable Nazi symbol, slogan or salute, such as a Hakenkreuz or SS insignia, displayed or shared publicly, unless it is shown for civic information, opposition to Nazism, reporting, teaching, science, research or art."),
|
|
39
|
+
exclusions: "Religious or cultural swastikas, similar shapes, mentioning a symbol without showing it, and displays for reporting, teaching, counterspeech or art. Fictional styling or a disclaimer alone is not an exception."
|
|
40
|
+
},
|
|
41
|
+
"hate-nazi-insignia-public-display": {
|
|
42
|
+
category: "hate",
|
|
43
|
+
kind: "harm",
|
|
44
|
+
harmOption: false,
|
|
45
|
+
displayName: msg("Public Nazi insignia outside non-promotional depictions"),
|
|
46
|
+
description: msg("A clearly identifiable symbol or insignia of a banned Nazi organisation displayed or shared publicly. Printed, pictorial, stage and film depictions that don't approve or spread the organisation's ideology, and exhibitions opposed to it, don't count."),
|
|
47
|
+
exclusions: "Religious or cultural swastikas, similar shapes, a mention without a display, and non-promotional journalistic, teaching or artistic depictions."
|
|
48
|
+
},
|
|
49
|
+
"hate-nazi-genocide-public-peace": {
|
|
50
|
+
category: "hate",
|
|
51
|
+
kind: "harm",
|
|
52
|
+
harmOption: false,
|
|
53
|
+
displayName: msg("Nazi genocide denial or approval affecting public peace"),
|
|
54
|
+
description: msg("Publicly approving, denying or grossly trivialising the Nazi genocide in a way that can disturb public peace, including antisemitic denial or justification addressed to the public."),
|
|
55
|
+
exclusions: "Mentioning the topic, rejecting denial, accurate history, and reporting, teaching, research or art that quotes someone else's denial. Quotation marks or a label don't excuse the author's own denial."
|
|
56
|
+
},
|
|
57
|
+
"hate-nazi-genocide-denial-or-approval": {
|
|
58
|
+
category: "hate",
|
|
59
|
+
kind: "harm",
|
|
60
|
+
harmOption: false,
|
|
61
|
+
displayName: msg("Nazi genocide denial or approval"),
|
|
62
|
+
description: msg("The author publicly denies, trivialises, approves or justifies the Nazi genocide or Nazi crimes against humanity, including partial denial."),
|
|
63
|
+
exclusions: "Mentioning the topic, accurate history, rejecting denial, and reporting, teaching, research or art that attributes the denial to someone else without adopting it. A disclaimer doesn't excuse the author's own denial."
|
|
64
|
+
},
|
|
65
|
+
"hate-adjudicated-nazi-crimes-denial": {
|
|
66
|
+
category: "hate",
|
|
67
|
+
kind: "harm",
|
|
68
|
+
harmOption: false,
|
|
69
|
+
displayName: msg("Denial of adjudicated Nazi crimes"),
|
|
70
|
+
description: msg("The author publicly disputes Nazi crimes against humanity established by the Nuremberg tribunal or another competent court, including Holocaust denial."),
|
|
71
|
+
exclusions: "Mentioning the topic, accurate history, rejecting denial, and reporting, teaching, research or art that quotes someone else's denial without adopting it. Fictional styling doesn't excuse the author's own denial."
|
|
72
|
+
},
|
|
73
|
+
"violence-high-impact": {
|
|
74
|
+
category: "violence",
|
|
75
|
+
kind: "harm",
|
|
76
|
+
harmOption: false,
|
|
77
|
+
displayName: msg("High-impact violent media"),
|
|
78
|
+
description: msg("Images or video with explicit, high-impact bodily detail, such as dismemberment, exposed organs, gruesome mutilation or prolonged torture, including fictional depictions."),
|
|
79
|
+
exclusions: "Text, minor injuries, moderate violence or blood, harm that happens off screen, and self-inflicted harm without other violence.",
|
|
80
|
+
inputs: ["image"]
|
|
81
|
+
},
|
|
82
|
+
"self-harm-age-restricted": {
|
|
83
|
+
category: "self-harm",
|
|
84
|
+
kind: "harm",
|
|
85
|
+
harmOption: false,
|
|
86
|
+
displayName: msg("Promotion or instruction of self-harm"),
|
|
87
|
+
description: msg("Content that encourages, promotes or gives instructions for suicide, self-injury or disordered eating, rather than depicting or mentioning it. Actionable instructions count even inside a report."),
|
|
88
|
+
exclusions: "Recovery, support and prevention, mentions, incident reports that don't promote it, sharing thoughts without promoting them, and asking for help."
|
|
89
|
+
},
|
|
90
|
+
"personal-information-contact": {
|
|
91
|
+
category: "personal-information",
|
|
92
|
+
kind: "harm",
|
|
93
|
+
displayName: msg("Private contact details"),
|
|
94
|
+
description: msg("Private personal email addresses, phone numbers or other direct contact details, or requests to reveal them."),
|
|
95
|
+
exclusions: "Public business or official contacts, names, broad locations, placeholders and redacted values."
|
|
96
|
+
},
|
|
97
|
+
"personal-information-email": {
|
|
98
|
+
category: "personal-information",
|
|
99
|
+
kind: "harm",
|
|
100
|
+
displayName: msg("Private email addresses"),
|
|
101
|
+
description: msg("A private personal email address, or a request to reveal one."),
|
|
102
|
+
exclusions: "Public business or official addresses, example.com placeholders and redacted addresses."
|
|
103
|
+
},
|
|
104
|
+
"personal-information-phone": {
|
|
105
|
+
category: "personal-information",
|
|
106
|
+
kind: "harm",
|
|
107
|
+
displayName: msg("Private phone numbers"),
|
|
108
|
+
description: msg("A private personal phone or mobile number, or a request to reveal one."),
|
|
109
|
+
exclusions: "Public business or official numbers, redacted values and numbers that aren't phone numbers."
|
|
110
|
+
},
|
|
111
|
+
"personal-information-government-id": {
|
|
112
|
+
category: "personal-information",
|
|
113
|
+
kind: "harm",
|
|
114
|
+
displayName: msg("Government identifiers"),
|
|
115
|
+
description: msg("A personal passport, national identity, national insurance, social security or similar government-issued number, or a request to reveal one."),
|
|
116
|
+
exclusions: "Organisation identifiers, ordinary names or numbers, redacted identifiers and fictional placeholders."
|
|
117
|
+
},
|
|
118
|
+
"personal-information-financial": {
|
|
119
|
+
category: "personal-information",
|
|
120
|
+
kind: "harm",
|
|
121
|
+
displayName: msg("Financial identifiers"),
|
|
122
|
+
description: msg("A private bank account, payment card or other sensitive financial account number, or a request to reveal one."),
|
|
123
|
+
exclusions: "Public business payment details, prices, ordinary numbers, redacted values and placeholders."
|
|
124
|
+
},
|
|
125
|
+
"personal-information-location": {
|
|
126
|
+
category: "personal-information",
|
|
127
|
+
kind: "harm",
|
|
128
|
+
displayName: msg("Precise personal location"),
|
|
129
|
+
description: msg("A home address or a person's current precise location, including coordinates or a live location, or a request to reveal one."),
|
|
130
|
+
exclusions: "Broad locations, public venues not tied to where a person lives or is now, fictional placeholders, redacted values and requests that don't target a precise personal location."
|
|
131
|
+
},
|
|
132
|
+
"personal-information-identifiers": {
|
|
133
|
+
category: "personal-information",
|
|
134
|
+
kind: "harm",
|
|
135
|
+
displayName: msg("Sensitive identifiers"),
|
|
136
|
+
description: msg("Government ID, national insurance, social security, passport, bank account or payment card numbers tied to a person, or requests to reveal them."),
|
|
137
|
+
exclusions: "Names, dates or numbers with no identifier context, organisation identifiers, redacted values and placeholders."
|
|
138
|
+
},
|
|
139
|
+
"personal-information-credentials": {
|
|
140
|
+
category: "personal-information",
|
|
141
|
+
kind: "harm",
|
|
142
|
+
displayName: msg("Credentials and secrets"),
|
|
143
|
+
description: msg("Private passwords, access tokens, API secrets, authentication codes or recovery codes for an account, or requests to reveal them."),
|
|
144
|
+
exclusions: "Usernames alone, advice on creating a strong password, redacted values and sample credentials that don't work."
|
|
145
|
+
},
|
|
146
|
+
"personal-information-request": {
|
|
147
|
+
category: "personal-information",
|
|
148
|
+
kind: "harm",
|
|
149
|
+
displayName: msg("Requests for private details"),
|
|
150
|
+
description: msg("A message or chat turn that asks someone to disclose private contact details, a precise personal location, sensitive identifiers or credentials."),
|
|
151
|
+
exclusions: "General privacy discussion, public business contacts, describing someone else's request, and asking only for a name or broad location."
|
|
152
|
+
},
|
|
153
|
+
"personal-information-self-disclosure": {
|
|
154
|
+
category: "personal-information",
|
|
155
|
+
kind: "target",
|
|
156
|
+
displayName: msg("Own details"),
|
|
157
|
+
description: msg("The person sharing private details says they are their own."),
|
|
158
|
+
exclusions: "Details that don't say whose they are, other people's details, and requests that share no details."
|
|
159
|
+
},
|
|
160
|
+
"personal-information-third-party": {
|
|
161
|
+
category: "personal-information",
|
|
162
|
+
kind: "target",
|
|
163
|
+
displayName: msg("Other people’s details"),
|
|
164
|
+
description: msg("The private details belong to someone other than the person sharing them, or don't say whose they are, such as a filled-in form or record."),
|
|
165
|
+
exclusions: "Details the person sharing them says are their own, and requests that share no details."
|
|
166
|
+
},
|
|
167
|
+
"personal-information-historical": {
|
|
168
|
+
category: "personal-information",
|
|
169
|
+
kind: "context",
|
|
170
|
+
displayName: msg("Historical"),
|
|
171
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
172
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
173
|
+
},
|
|
174
|
+
"personal-information-documentary": {
|
|
175
|
+
category: "personal-information",
|
|
176
|
+
kind: "context",
|
|
177
|
+
displayName: msg("Reporting or documentary"),
|
|
178
|
+
description: msg("Private details explicitly framed as factual reporting or documentation of an actual real-world event, such as a news report, court record or public notice that contains them."),
|
|
179
|
+
exclusions: "Sharing or passing on someone's details, however accurate; telling people to contact, visit or find someone; third-person narration or quotation marks alone; fictional or invented examples."
|
|
180
|
+
},
|
|
181
|
+
"personal-information-educational": {
|
|
182
|
+
category: "personal-information",
|
|
183
|
+
kind: "context",
|
|
184
|
+
displayName: msg("Educational"),
|
|
185
|
+
description: msg("Qualifying content used in a lesson, clinical explanation or academic study."),
|
|
186
|
+
exclusions: "Neutral description alone, or an educational label on a separate harmful request."
|
|
187
|
+
},
|
|
188
|
+
"personal-information-fictional": {
|
|
189
|
+
category: "personal-information",
|
|
190
|
+
kind: "context",
|
|
191
|
+
displayName: msg("Fictional"),
|
|
192
|
+
description: msg("Qualifying content clearly presented as fiction, such as a story, game or illustration."),
|
|
193
|
+
exclusions: "A claim of fiction with nothing in the content to show it, or a reference to a passage that isn't included."
|
|
194
|
+
},
|
|
195
|
+
"personal-information-support-prevention": {
|
|
196
|
+
category: "personal-information",
|
|
197
|
+
kind: "context",
|
|
198
|
+
displayName: msg("Support and prevention"),
|
|
199
|
+
description: msg("Qualifying content shared only to seek or give support, prevent harm, oppose abuse or aid recovery."),
|
|
200
|
+
exclusions: "A separate harmful request or attack, general safety advice with no qualifying content, and neutral description with no support or prevention purpose."
|
|
201
|
+
},
|
|
202
|
+
"profanity-mild": {
|
|
203
|
+
category: "profanity",
|
|
204
|
+
kind: "harm",
|
|
205
|
+
displayName: msg("Mild profanity"),
|
|
206
|
+
description: msg("Mild swear words or exclamations, such as damn or hell used as swearing, in the language they are written in."),
|
|
207
|
+
exclusions: "Literal or religious meanings, strong profanity, mentions of swearing without the words, and ambiguous abbreviations."
|
|
208
|
+
},
|
|
209
|
+
"profanity-strong": {
|
|
210
|
+
category: "profanity",
|
|
211
|
+
kind: "harm",
|
|
212
|
+
displayName: msg("Strong profanity"),
|
|
213
|
+
description: msg("Strong swear words or vulgar expressions, including clearly recognisable disguised spellings, in the language they are written in."),
|
|
214
|
+
exclusions: "Mild exclamations, medical or anatomical terms, innocent words that contain a swear word, mentions of swearing without the words, and ambiguous symbols."
|
|
215
|
+
},
|
|
216
|
+
"profanity-slurs": {
|
|
217
|
+
category: "profanity",
|
|
218
|
+
kind: "harm",
|
|
219
|
+
displayName: msg("Offensive slurs"),
|
|
220
|
+
description: msg("Conventional offensive identity slurs, including quoted or reclaimed uses. This records the word; whether it attacks someone is assessed under Hate."),
|
|
221
|
+
exclusions: "A slur that is referred to but not written, neutral identity terms, and words that only resemble a slur."
|
|
222
|
+
},
|
|
223
|
+
"profanity-obfuscated": {
|
|
224
|
+
category: "profanity",
|
|
225
|
+
kind: "harm",
|
|
226
|
+
displayName: msg("Obfuscated profanity"),
|
|
227
|
+
description: msg("A swear word or offensive slur that remains clearly recognisable despite masking, spacing, character substitutions or deliberate misspelling."),
|
|
228
|
+
exclusions: "Symbols that can't be read as a word, innocent abbreviations, ordinary words or names that happen to contain one, and censored passages that don't show which word was used."
|
|
229
|
+
},
|
|
230
|
+
"profanity-historical": {
|
|
231
|
+
category: "profanity",
|
|
232
|
+
kind: "context",
|
|
233
|
+
displayName: msg("Historical"),
|
|
234
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
235
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
236
|
+
},
|
|
237
|
+
"profanity-documentary": {
|
|
238
|
+
category: "profanity",
|
|
239
|
+
kind: "context",
|
|
240
|
+
displayName: msg("Reporting or documentary"),
|
|
241
|
+
description: msg("Qualifying content explicitly framed as factual reporting, testimony or documentation of actual real-world events or utterances, including a person's own incident report or a report to an authority."),
|
|
242
|
+
exclusions: "Neutral wording, third-person narration or quotation marks alone; fiction and invented teaching examples."
|
|
243
|
+
},
|
|
244
|
+
"profanity-educational": {
|
|
245
|
+
category: "profanity",
|
|
246
|
+
kind: "context",
|
|
247
|
+
displayName: msg("Educational"),
|
|
248
|
+
description: msg("Qualifying content used in a lesson, clinical explanation or academic study."),
|
|
249
|
+
exclusions: "Neutral description alone, or an educational label on a separate harmful request."
|
|
250
|
+
},
|
|
251
|
+
"profanity-fictional": {
|
|
252
|
+
category: "profanity",
|
|
253
|
+
kind: "context",
|
|
254
|
+
displayName: msg("Fictional"),
|
|
255
|
+
description: msg("Qualifying content clearly presented as fiction, such as a story, game or illustration."),
|
|
256
|
+
exclusions: "A claim of fiction with nothing in the content to show it, or a reference to a passage that isn't included."
|
|
257
|
+
},
|
|
258
|
+
"profanity-support-prevention": {
|
|
259
|
+
category: "profanity",
|
|
260
|
+
kind: "context",
|
|
261
|
+
displayName: msg("Support and prevention"),
|
|
262
|
+
description: msg("Qualifying content shared only to seek or give support, prevent harm, oppose abuse or aid recovery."),
|
|
263
|
+
exclusions: "A separate harmful request or attack, general safety advice with no qualifying content, and neutral description with no support or prevention purpose."
|
|
264
|
+
},
|
|
265
|
+
"sexual-nudity": {
|
|
266
|
+
category: "sexual",
|
|
267
|
+
kind: "harm",
|
|
268
|
+
displayName: msg("Nudity"),
|
|
269
|
+
description: msg("Explicitly exposed intimate sexual anatomy, including partially exposed breasts, genitals or buttocks and a pubic area or pubic hair exposed by clothing pulled down or open. Drawn, animated and generated characters count, including creature or anthropomorphic characters drawn with genitals or other sexual anatomy."),
|
|
270
|
+
exclusions: "Swimwear, revealing clothing and diagrams without exposed sexual anatomy, and animals or cartoon characters without drawn sexual anatomy. Exposed anatomy in a medical diagram still counts; its educational context is recorded separately."
|
|
271
|
+
},
|
|
272
|
+
"sexual-activity": {
|
|
273
|
+
category: "sexual",
|
|
274
|
+
kind: "harm",
|
|
275
|
+
displayName: msg("Sexual activity"),
|
|
276
|
+
description: msg("A depicted or described sexual act, including sexual assault. Solo acts count: masturbation, touching or stimulating one's own genitals, and using a sex toy. So do explicitly sexual fetish acts and sexual acts by drawn, animated, generated, creature or anthropomorphic characters."),
|
|
277
|
+
exclusions: "Affection, non-sexual touching, romantic roleplay limited to kissing or touching, which is Suggestive content, and general sexual-health education."
|
|
278
|
+
},
|
|
279
|
+
"sexual-explicit-language": {
|
|
280
|
+
category: "sexual",
|
|
281
|
+
kind: "harm",
|
|
282
|
+
displayName: msg("Explicit sexual language"),
|
|
283
|
+
description: msg("Graphic sexual descriptions or explicitly erotic dialogue."),
|
|
284
|
+
exclusions: "Untargeted profanity, anatomical terms, non-erotic medical or educational language, romantic roleplay limited to kissing or touching, and naming a sex act in passing or in a crude joke."
|
|
285
|
+
},
|
|
286
|
+
"sexual-assault-media": {
|
|
287
|
+
category: "sexual",
|
|
288
|
+
kind: "harm",
|
|
289
|
+
harmOption: false,
|
|
290
|
+
displayName: msg("Sexual-assault images or video"),
|
|
291
|
+
description: msg("Images or video showing a sexual act involving force, coercion or a person who can't consent, including realistic staged, animated or generated depictions. It counts inside reporting, education or support too, and concerns consent to the act, not to sharing the image."),
|
|
292
|
+
exclusions: "Text or captions describing, reporting or discussing an assault; survivor accounts, support or prevention without a depicted assault; aftermath alone; consensual roleplay; ambiguous contact, expressions or nudity.",
|
|
293
|
+
inputs: ["image"]
|
|
294
|
+
},
|
|
295
|
+
"sexual-non-consensual": {
|
|
296
|
+
category: "sexual",
|
|
297
|
+
kind: "harm",
|
|
298
|
+
displayName: msg("Non-consensual sexual content"),
|
|
299
|
+
description: msg("Sexual content depicting or describing non-consensual sexual activity, such as sexual assault, rape or coerced sex presented as sexual or erotic material, including fiction, animation and generated images."),
|
|
300
|
+
exclusions: "Factual reports, survivor accounts, support, prevention and non-graphic discussion that don't present the assault as sexual material, and consensual sexual activity. Sharing a real person's intimate images without consent is Intimate image abuse."
|
|
301
|
+
},
|
|
302
|
+
"sexual-intimate-image-abuse": {
|
|
303
|
+
category: "sexual",
|
|
304
|
+
kind: "harm",
|
|
305
|
+
harmOption: false,
|
|
306
|
+
displayName: msg("Intimate image abuse"),
|
|
307
|
+
description: msg("Intimate images of a real, identifiable person shared, offered, sought or traded without their consent, or threatened to be shared: nudity, sexual acts or sexualised images, including hidden-camera, upskirt, leaked or hacked images, sextortion threats, and sexual deepfakes or digitally undressed images of real people."),
|
|
308
|
+
exclusions: "Consensual adult content, including people sharing their own images or professional adult content; fictional or drawn characters with no real person depicted; non-sexual images; reports, survivor accounts, prevention or support that share no such image and make no threat; mentioning a leak without sharing, offering or seeking the images."
|
|
309
|
+
},
|
|
310
|
+
"sexual-extreme": {
|
|
311
|
+
category: "sexual",
|
|
312
|
+
kind: "harm",
|
|
313
|
+
harmOption: false,
|
|
314
|
+
displayName: msg("Extreme pornography"),
|
|
315
|
+
description: msg("Pornographic content showing or describing sex with an animal or with a dead body, or a sexual act that threatens a person's life or is likely to cause serious injury to the anus, breasts or genitals, including realistic drawn or generated depictions."),
|
|
316
|
+
exclusions: "Consensual adult content without such an act, including bondage, role play or rough play; non-sexual images of animals, death or injury; reports, education, support or discussion that present no such material."
|
|
317
|
+
},
|
|
318
|
+
"sexual-minors": {
|
|
319
|
+
category: "sexual",
|
|
320
|
+
kind: "harm",
|
|
321
|
+
harmOption: false,
|
|
322
|
+
displayName: msg("Sexualised minors"),
|
|
323
|
+
description: msg("Sexual content involving a child or a character presented as a child: nudity, a sexual act, or sexualised posing or focus on the body of someone who clearly appears to be under 18 from childlike body proportions, a stated or obvious age, or a childlike framing such as a school-age character in explicit content. Drawings, animation and generated images count."),
|
|
324
|
+
exclusions: "Adults, including youthful-looking adults and drawn characters with adult bodies and no childlike framing; school uniforms or costumes on adults; non-sexual images or mentions of children; reports, prevention or support about child sexual abuse that present no sexual material. A youthful face, small stature or art style alone doesn't establish a child."
|
|
325
|
+
},
|
|
326
|
+
"sexual-solicitation": {
|
|
327
|
+
category: "sexual",
|
|
328
|
+
kind: "harm",
|
|
329
|
+
displayName: msg("Sexual solicitation"),
|
|
330
|
+
description: msg("A request, offer or advert for sexual services, escorting or a sexual encounter, made by the author or by a participant in a conversation."),
|
|
331
|
+
exclusions: "Adult content promotion, such as a subscription page or explicit media for sale; dating, romance, accepting money and vague offers without sexual content; describing someone else's offer; stating a desire without asking anyone for it."
|
|
332
|
+
},
|
|
333
|
+
"sexual-paid": {
|
|
334
|
+
category: "sexual",
|
|
335
|
+
kind: "target",
|
|
336
|
+
displayName: msg("Paid sexual services"),
|
|
337
|
+
description: msg("The solicitation is for paid or commercial sexual services: escorting, prostitution, a sexual encounter offered or sought for money, gifts or other payment, or advertising such services."),
|
|
338
|
+
exclusions: "An unpaid request or offer for a sexual encounter between adults, and adult content promotion such as a subscription page or explicit media for sale."
|
|
339
|
+
},
|
|
340
|
+
"sexual-adult-promotion": {
|
|
341
|
+
category: "sexual",
|
|
342
|
+
kind: "harm",
|
|
343
|
+
displayName: msg("Adult content promotion"),
|
|
344
|
+
description: msg("The author promotes legal adult sexual content: links to, subscriptions for or sales of pornography, explicit photos or videos, or an adult creator's paid page."),
|
|
345
|
+
exclusions: "Offers or requests for sexual services or an encounter, which are Sexual solicitation; dating, romance and non-sexual paid content; describing someone else's promotion."
|
|
346
|
+
},
|
|
347
|
+
"sexual-revealing-clothing": {
|
|
348
|
+
category: "sexual",
|
|
349
|
+
kind: "harm",
|
|
350
|
+
displayName: msg("Revealing clothing"),
|
|
351
|
+
description: msg("People shown in swimwear, underwear or lingerie-style clothing, or other clothing that exposes much of the body, with no exposed sexual anatomy, sexual act or explicit erotic display. Fitness clothing counts only when it exposes much of the body."),
|
|
352
|
+
exclusions: "Exposed sexual anatomy, including clothing pulled down, open or aside, which is Nudity; sexual acts and explicit erotic display; sexual solicitation or adult content promotion; everyday clothing, sportswear and team kits that cover the torso and thighs; costumes or uniforms that aren't revealing.",
|
|
353
|
+
inputs: ["image"]
|
|
354
|
+
},
|
|
355
|
+
"sexual-suggestive": {
|
|
356
|
+
category: "sexual",
|
|
357
|
+
kind: "harm",
|
|
358
|
+
displayName: msg("Suggestive content"),
|
|
359
|
+
description: msg("Flirtation, innuendo, sexual jokes or suggestive romance, such as kissing, caressing or a suggestive pose, with no sexual act, exposed sexual anatomy or explicit sexual language."),
|
|
360
|
+
exclusions: "A sexual act, exposed sexual anatomy or explicit sexual language; sexual solicitation or adult content promotion; affection or romance without sexual suggestion."
|
|
361
|
+
},
|
|
362
|
+
"sexual-non-erotic-nudity": {
|
|
363
|
+
category: "sexual",
|
|
364
|
+
kind: "context",
|
|
365
|
+
displayName: msg("Non-erotic nudity"),
|
|
366
|
+
description: msg("Exposed anatomy in a non-erotic setting: breastfeeding, childbirth, medical or health care such as post-surgery images or self-examination, protest, or fine art such as a painting or sculpture."),
|
|
367
|
+
exclusions: "Erotic posing or sexual focus, including a person posed with clothing pulled down or open to show intimate anatomy; sexual acts; photographs or generated images labelled as art to show nudity; pornographic drawings; anyone who appears to be a minor. An educational or artistic label alone doesn't make erotic nudity non-erotic."
|
|
368
|
+
},
|
|
369
|
+
"sexual-text": {
|
|
370
|
+
category: "sexual",
|
|
371
|
+
kind: "context",
|
|
372
|
+
displayName: msg("Text"),
|
|
373
|
+
description: msg("The content is text, not an image or video. It is set from the input type and never judged from the content."),
|
|
374
|
+
exclusions: "Images and video, including text shown in them.",
|
|
375
|
+
inputs: ["text"],
|
|
376
|
+
fromInput: true
|
|
377
|
+
},
|
|
378
|
+
"sexual-historical": {
|
|
379
|
+
category: "sexual",
|
|
380
|
+
kind: "context",
|
|
381
|
+
displayName: msg("Historical"),
|
|
382
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
383
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
384
|
+
},
|
|
385
|
+
"sexual-documentary": {
|
|
386
|
+
category: "sexual",
|
|
387
|
+
kind: "context",
|
|
388
|
+
displayName: msg("Reporting or documentary"),
|
|
389
|
+
description: msg("Qualifying content explicitly framed as factual reporting, testimony or documentation of actual real-world events or utterances, including a person's own incident report or a report to an authority."),
|
|
390
|
+
exclusions: "Neutral wording, third-person narration or quotation marks alone; fiction, invented examples, erotic display and adverts; a separate harmful request, attack or endorsement by the author."
|
|
391
|
+
},
|
|
392
|
+
"sexual-educational": {
|
|
393
|
+
category: "sexual",
|
|
394
|
+
kind: "context",
|
|
395
|
+
displayName: msg("Educational"),
|
|
396
|
+
description: msg("Qualifying content presented to teach or inform: a lesson, course or textbook material, a health, safety or clinical explanation, or academic study of the subject."),
|
|
397
|
+
exclusions: "An educational label on a harmful request, working instructions or an endorsement; erotic, graphic or gratuitous detail beyond what the teaching needs; an academic tone alone."
|
|
398
|
+
},
|
|
399
|
+
"sexual-discussion": {
|
|
400
|
+
category: "sexual",
|
|
401
|
+
kind: "context",
|
|
402
|
+
displayName: msg("Non-graphic discussion"),
|
|
403
|
+
description: msg("Qualifying content referenced non-graphically to make or examine an argument, comparison, ethical question or analysis, rather than to perform, endorse, threaten, eroticise or facilitate the harmful act."),
|
|
404
|
+
exclusions: "Graphic or explicit sexual detail; erotic presentation; threats, victim mockery, endorsement, promotion, harmful assistance or instructions, direct harmful requests and sexual solicitation."
|
|
405
|
+
},
|
|
406
|
+
"sexual-fictional": {
|
|
407
|
+
category: "sexual",
|
|
408
|
+
kind: "context",
|
|
409
|
+
displayName: msg("Fictional"),
|
|
410
|
+
description: msg("Qualifying content clearly attributed to an invented character, fictional story, game, illustration, generated image or reenacted scene."),
|
|
411
|
+
exclusions: "Unclear fictional context, and a real-world threat or actionable harmful request presented as fiction."
|
|
412
|
+
},
|
|
413
|
+
"sexual-support-prevention": {
|
|
414
|
+
category: "sexual",
|
|
415
|
+
kind: "context",
|
|
416
|
+
displayName: msg("Sexual harm support or prevention"),
|
|
417
|
+
description: msg("Qualifying content shared only to seek or give support, prevent harm or aid recovery, such as a survivor describing abuse to get help, or counterspeech that rejects an attack or threat. Someone disclosing current harm or risk counts when they are seeking help."),
|
|
418
|
+
exclusions: "Harmful instructions, assistance, advice on hiding harm, targeting or encouragement, including beside a supportive reply."
|
|
419
|
+
},
|
|
420
|
+
"violence-attack": {
|
|
421
|
+
category: "violence",
|
|
422
|
+
kind: "harm",
|
|
423
|
+
displayName: msg("Physical attack"),
|
|
424
|
+
description: msg("A depicted or described physical attack against another person or animal, including a general or statistical statement that people were attacked or assaulted."),
|
|
425
|
+
exclusions: "An injury or death with no attack; a threat, plan or encouragement alone; harm someone does only to themselves."
|
|
426
|
+
},
|
|
427
|
+
"violence-threat": {
|
|
428
|
+
category: "violence",
|
|
429
|
+
kind: "harm",
|
|
430
|
+
displayName: msg("Threat of violence"),
|
|
431
|
+
description: msg("A direct, conditional or clearly implied threat of physical harm against another person or animal."),
|
|
432
|
+
exclusions: "A completed attack, figurative language and threats only against oneself; a hyperbolic urge to hit someone with no weapon, plan or means, which is a Non-severe wish of harm."
|
|
433
|
+
},
|
|
434
|
+
"violence-preparation": {
|
|
435
|
+
category: "violence",
|
|
436
|
+
kind: "harm",
|
|
437
|
+
displayName: msg("Preparation or instructions"),
|
|
438
|
+
description: msg("A plan or request by the author to physically harm another person, or actionable instructions for doing so."),
|
|
439
|
+
exclusions: "A depiction, threat or praise alone; describing someone else's plan; reporting, prevention and lawful safety advice."
|
|
440
|
+
},
|
|
441
|
+
"violence-encouragement": {
|
|
442
|
+
category: "violence",
|
|
443
|
+
kind: "harm",
|
|
444
|
+
displayName: msg("Encouragement of violence"),
|
|
445
|
+
description: msg("The author urges, endorses, praises or promotes physical violence."),
|
|
446
|
+
exclusions: "Reporting, quoting or depicting an attack without endorsing it; condemnation or prevention; advocating lawful self-defence or a state's lawful military or police defence."
|
|
447
|
+
},
|
|
448
|
+
"violence-wish": {
|
|
449
|
+
category: "violence",
|
|
450
|
+
kind: "harm",
|
|
451
|
+
harmOption: false,
|
|
452
|
+
displayName: msg("Non-severe wish of harm"),
|
|
453
|
+
description: msg("The author wishes or hopes that a real person or group suffers non-severe physical harm, such as falling ill or catching a disease, even a serious one such as cancer, feeling pain or having a minor accident, or voices a hyperbolic urge to hit, slap or punch someone, such as “I'd beat his ass”, with no weapon, plan or credible means, without threatening it, planning it or calling on anyone to cause it."),
|
|
454
|
+
exclusions: "Wishing that someone dies, is attacked with a weapon, is seriously or permanently injured or is sexually assaulted; threats, plans, requests or encouragement for others to cause harm; figurative curses such as telling someone to go choke on something; wishing non-physical misfortune, such as losing a job or an election."
|
|
455
|
+
},
|
|
456
|
+
"violence-coded-incitement": {
|
|
457
|
+
category: "violence",
|
|
458
|
+
kind: "harm",
|
|
459
|
+
harmOption: false,
|
|
460
|
+
displayName: msg("Indirect coded incitement"),
|
|
461
|
+
description: msg("The author indirectly incites physical violence through coded language or an allusion whose violent meaning is clear from the context, without an explicit threat, plan, request or instructions."),
|
|
462
|
+
exclusions: "Names, memes, ambiguous allusions and figures of speech without a clear violent meaning; reporting or condemnation; explicit threats, plans, requests or instructions, even when disguised with euphemisms or censored spelling, which are other forms."
|
|
463
|
+
},
|
|
464
|
+
"violence-extremism": {
|
|
465
|
+
category: "violence",
|
|
466
|
+
kind: "harm",
|
|
467
|
+
harmOption: false,
|
|
468
|
+
displayName: msg("Violent extremism"),
|
|
469
|
+
description: msg("Support for terrorism or violent extremism by the author: propaganda, recruitment, fundraising, instructions or praise for a terrorist or violent extremist organisation, its leaders or its attacks, including glorifying attackers as heroes or martyrs; and perpetrator-produced attack footage or manifestos, however they are presented."),
|
|
470
|
+
exclusions: "News, documentary, research, education, history or counterspeech that reports, explains or condemns terrorism without promoting it or reproducing attackers' material; mentioning a group's name; fiction that doesn't promote a real organisation or attack; lawful political movements, protest and military conflict between states."
|
|
471
|
+
},
|
|
472
|
+
"violence-injury": {
|
|
473
|
+
category: "violence",
|
|
474
|
+
kind: "harm",
|
|
475
|
+
harmOption: false,
|
|
476
|
+
displayName: msg("Injury"),
|
|
477
|
+
description: msg("A bodily injury in content that already counts as Violence, such as an injury from an attack or one shown in explicit, disturbing detail. An injury alone never establishes Violence."),
|
|
478
|
+
exclusions: "An injury or medical condition with no attack, death, threat or graphic depiction, however severe; threats, risks, weapons or pain without an injury; figurative language; self-injury alone."
|
|
479
|
+
},
|
|
480
|
+
"violence-violent-death": {
|
|
481
|
+
category: "violence",
|
|
482
|
+
kind: "harm",
|
|
483
|
+
displayName: msg("Violent death"),
|
|
484
|
+
description: msg("A depicted or described death caused by an attack, killing, accident or other physical trauma, or a dead body showing signs of violence. An attacker or intent to harm is not required."),
|
|
485
|
+
exclusions: "A death from illness, old age or an unstated cause; a sudden or untimely death with no attack, accident or trauma stated; threats, death wishes, risks or abstract discussion; figurative language; suicide alone."
|
|
486
|
+
},
|
|
487
|
+
"violence-natural-death": {
|
|
488
|
+
category: "violence",
|
|
489
|
+
kind: "harm",
|
|
490
|
+
displayName: msg("Natural or non-violent death"),
|
|
491
|
+
description: msg("A depicted or described death from natural causes, illness, old age or an unstated cause, including a statement that someone has died or passed away, or a body with no signs of violence. A death is non-violent when no attack, accident or trauma is stated, even if it was sudden, untimely or unexplained."),
|
|
492
|
+
exclusions: "A death caused by an attack, killing, accident or other physical trauma; death wishes, risks or abstract discussion of mortality; figurative language; suicide alone."
|
|
493
|
+
},
|
|
494
|
+
"violence-graphic": {
|
|
495
|
+
category: "violence",
|
|
496
|
+
kind: "harm",
|
|
497
|
+
displayName: msg("Graphic detail"),
|
|
498
|
+
description: msg("Severe bodily injury or death shown or described with explicit disturbing bodily detail, such as exposed organs, dismemberment or gore. In images, visible open wounds and heavy bleeding are graphic too."),
|
|
499
|
+
exclusions: "Threats or mentions of violence without disturbing bodily detail; in text, bleeding, cuts, bruises or other serious injuries without exposed tissue, bone or organs, mutilation or dismemberment; in images, modest blood or minor wounds; injuries that aren't shown; self-injury or suicide alone."
|
|
500
|
+
},
|
|
501
|
+
"violence-decapitation-act": {
|
|
502
|
+
category: "violence",
|
|
503
|
+
kind: "harm",
|
|
504
|
+
harmOption: false,
|
|
505
|
+
displayName: msg("Act of decapitation"),
|
|
506
|
+
description: msg("Visual footage showing a real person’s head being severed from their body: the act is visibly underway or captured as the head separates. Reporting, historical, educational or documentary framing does not remove that depicted act."),
|
|
507
|
+
exclusions: "Text, captions or mentions; a severed head or body shown only afterwards; an act that happens off screen; fictional, staged, animated or generated scenes; clinical dissection.",
|
|
508
|
+
inputs: ["image"]
|
|
509
|
+
},
|
|
510
|
+
"violence-gore": {
|
|
511
|
+
category: "violence",
|
|
512
|
+
kind: "harm",
|
|
513
|
+
displayName: msg("Excessive gore"),
|
|
514
|
+
description: msg("Gruesome bodily harm beyond graphic detail: dismembered, mutilated or decapitated bodies, exposed internal organs or bones, charred human remains, or an animal tortured or killed in gruesome detail."),
|
|
515
|
+
exclusions: "Visible wounds, blood, burns or injuries without gruesome detail, which are Graphic detail; clinical or surgical images in a medical setting; ordinary hunting, fishing or food processing."
|
|
516
|
+
},
|
|
517
|
+
"violence-weapon": {
|
|
518
|
+
category: "violence",
|
|
519
|
+
kind: "harm",
|
|
520
|
+
displayName: msg("Weapon without an attack"),
|
|
521
|
+
description: msg("A firearm, knife or other weapon shown on its own, or carried, held, drawn or aimed with no person or animal visibly on the receiving end, including action poses, poster and game art, hunting and target shooting."),
|
|
522
|
+
exclusions: "A weapon aimed, fired or swung at a visible or identified person or animal, including two people aiming at each other; a visible victim, injury, death or graphic harm; tools, toys or props with no violent association.",
|
|
523
|
+
inputs: ["image"]
|
|
524
|
+
},
|
|
525
|
+
"violence-sport": {
|
|
526
|
+
category: "violence",
|
|
527
|
+
kind: "harm",
|
|
528
|
+
displayName: msg("Combat sport or training"),
|
|
529
|
+
description: msg("Recognizable consensual combat sport or protective training, such as boxing, martial arts, wrestling, fencing or self-defence practice, without graphic bodily detail or abusive conduct."),
|
|
530
|
+
exclusions: "Graphic bodily detail, death, an attack outside the sport, abusive conduct, or a non-consensual fight presented as sport. A non-graphic sports injury doesn't remove the sport context.",
|
|
531
|
+
inputs: ["image"]
|
|
532
|
+
},
|
|
533
|
+
"violence-text": {
|
|
534
|
+
category: "violence",
|
|
535
|
+
kind: "context",
|
|
536
|
+
displayName: msg("Text"),
|
|
537
|
+
description: msg("The content is text, not an image or video. It is set from the input type and never judged from the content."),
|
|
538
|
+
exclusions: "Images and video, including text shown in them.",
|
|
539
|
+
inputs: ["text"],
|
|
540
|
+
fromInput: true
|
|
541
|
+
},
|
|
542
|
+
"violence-historical": {
|
|
543
|
+
category: "violence",
|
|
544
|
+
kind: "context",
|
|
545
|
+
displayName: msg("Historical"),
|
|
546
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
547
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
548
|
+
},
|
|
549
|
+
"violence-documentary": {
|
|
550
|
+
category: "violence",
|
|
551
|
+
kind: "context",
|
|
552
|
+
displayName: msg("Reporting or documentary"),
|
|
553
|
+
description: msg("Qualifying content explicitly framed as factual reporting, testimony or documentation of actual real-world events or utterances, including a person's own incident report or a report to an authority."),
|
|
554
|
+
exclusions: "Neutral wording, third-person narration or quotation marks alone; fiction, invented examples, erotic display and adverts; a separate harmful request, attack or endorsement by the author."
|
|
555
|
+
},
|
|
556
|
+
"violence-educational": {
|
|
557
|
+
category: "violence",
|
|
558
|
+
kind: "context",
|
|
559
|
+
displayName: msg("Educational"),
|
|
560
|
+
description: msg("Qualifying content presented to teach or inform: a lesson, course or textbook material, a health, safety or clinical explanation, or academic study of the subject."),
|
|
561
|
+
exclusions: "An educational label on a harmful request, working instructions or an endorsement; erotic, graphic or gratuitous detail beyond what the teaching needs; an academic tone alone. A request or plan to harm someone or commit a crime is excluded even when a reply answers it informatively."
|
|
562
|
+
},
|
|
563
|
+
"violence-discussion": {
|
|
564
|
+
category: "violence",
|
|
565
|
+
kind: "context",
|
|
566
|
+
displayName: msg("Non-graphic discussion"),
|
|
567
|
+
description: msg("Qualifying content referenced non-graphically to make or examine an argument, comparison, ethical question or analysis, or mentioned in passing, such as recalling that someone was shot, rather than to perform, endorse, threaten, eroticise or facilitate the harmful act."),
|
|
568
|
+
exclusions: "Graphic or explicit sexual detail; erotic presentation; threats, victim mockery, endorsement, promotion, harmful assistance or instructions, direct harmful requests and sexual solicitation. A request or plan to harm someone or commit a crime is excluded even when a reply answers it informatively."
|
|
569
|
+
},
|
|
570
|
+
"violence-fictional": {
|
|
571
|
+
category: "violence",
|
|
572
|
+
kind: "context",
|
|
573
|
+
displayName: msg("Fictional"),
|
|
574
|
+
description: msg("Qualifying content clearly attributed to an invented character, fictional story, game, illustration, generated image or reenacted scene."),
|
|
575
|
+
exclusions: "Unclear fictional context, and a real-world threat or actionable harmful request presented as fiction."
|
|
576
|
+
},
|
|
577
|
+
"violence-fantasy": {
|
|
578
|
+
category: "violence",
|
|
579
|
+
kind: "context",
|
|
580
|
+
displayName: msg("Fantasy or cartoon violence"),
|
|
581
|
+
description: msg("Unrealistic or stylised violence, such as cartoon, fantasy or game combat, slapstick, or defeating creatures, monsters or characters, with no realistic injury or blood."),
|
|
582
|
+
exclusions: "Realistic violence against people, including in a story with clichéd, exaggerated or caricatured characters; realistic blood or injury, torture or sexual violence; any depiction or recreation of a real attack, war crime, genocide, terrorist attack or mass shooting, even when animated or in a game."
|
|
583
|
+
},
|
|
584
|
+
"violence-support-prevention": {
|
|
585
|
+
category: "violence",
|
|
586
|
+
kind: "context",
|
|
587
|
+
displayName: msg("Support or prevention"),
|
|
588
|
+
description: msg("Qualifying content shared only to seek or give support, prevent harm or aid recovery, such as a survivor describing abuse to get help, or counterspeech that rejects an attack or threat. Someone disclosing current harm or risk counts when they are seeking help."),
|
|
589
|
+
exclusions: "Harmful instructions, assistance, advice on hiding harm, targeting or encouragement, including beside a supportive reply."
|
|
590
|
+
},
|
|
591
|
+
"self-harm-thoughts": {
|
|
592
|
+
category: "self-harm",
|
|
593
|
+
kind: "harm",
|
|
594
|
+
displayName: msg("Thoughts or desire"),
|
|
595
|
+
description: msg("Current or recurring thoughts of intentional self-injury or suicide, or an explicitly expressed desire or a stated intention to die by suicide. A hypothetical, conditional or figurative statement, such as I would die for this or I will die on this hill, is not."),
|
|
596
|
+
exclusions: "General sadness, figurative language, statistics, past thoughts that have resolved, and prevention. An image without readable text sharing such thoughts."
|
|
597
|
+
},
|
|
598
|
+
"self-harm-preparation": {
|
|
599
|
+
category: "self-harm",
|
|
600
|
+
kind: "harm",
|
|
601
|
+
displayName: msg("Intent or preparation"),
|
|
602
|
+
description: msg("Expressed intent, preparation or a plan for intentional self-injury or suicide."),
|
|
603
|
+
exclusions: "General distress, an injury without self-directed intent, and reports or prevention without any intent, preparation or plan."
|
|
604
|
+
},
|
|
605
|
+
"self-harm-act": {
|
|
606
|
+
category: "self-harm",
|
|
607
|
+
kind: "harm",
|
|
608
|
+
displayName: msg("Depicted or reported act"),
|
|
609
|
+
description: msg("A depicted or described act of intentional self-injury or suicide."),
|
|
610
|
+
exclusions: "Accidental injuries, healed scars, recovery, and injuries with an unknown cause."
|
|
611
|
+
},
|
|
612
|
+
"self-harm-methods": {
|
|
613
|
+
category: "self-harm",
|
|
614
|
+
kind: "harm",
|
|
615
|
+
displayName: msg("Methods or instructions"),
|
|
616
|
+
description: msg("Actionable methods, requests or practical instructions for intentional self-injury or suicide."),
|
|
617
|
+
exclusions: "Prevention, support, recovery and discussion without harmful methods; naming a means, such as pills or jumping, without how-to detail, an amount, a location or another actionable detail."
|
|
618
|
+
},
|
|
619
|
+
"self-harm-encouragement": {
|
|
620
|
+
category: "self-harm",
|
|
621
|
+
kind: "harm",
|
|
622
|
+
displayName: msg("Encouragement"),
|
|
623
|
+
description: msg("The author urges, endorses, praises or promotes intentional self-injury or suicide."),
|
|
624
|
+
exclusions: "Support, prevention, condemnation, and reporting someone else's encouragement without endorsing it."
|
|
625
|
+
},
|
|
626
|
+
"self-harm-historical": {
|
|
627
|
+
category: "self-harm",
|
|
628
|
+
kind: "context",
|
|
629
|
+
displayName: msg("Historical"),
|
|
630
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
631
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
632
|
+
},
|
|
633
|
+
"self-harm-documentary": {
|
|
634
|
+
category: "self-harm",
|
|
635
|
+
kind: "context",
|
|
636
|
+
displayName: msg("Reporting or documentary"),
|
|
637
|
+
description: msg("Qualifying content explicitly framed as factual reporting, testimony or documentation of actual real-world events or utterances, including a person's own incident report or a report to an authority."),
|
|
638
|
+
exclusions: "Neutral wording, third-person narration or quotation marks alone; fiction, invented examples, erotic display and adverts; a separate harmful request, attack or endorsement by the author."
|
|
639
|
+
},
|
|
640
|
+
"self-harm-educational": {
|
|
641
|
+
category: "self-harm",
|
|
642
|
+
kind: "context",
|
|
643
|
+
displayName: msg("Educational"),
|
|
644
|
+
description: msg("Qualifying content presented to teach or inform: a lesson, course or textbook material, a health, safety or clinical explanation, or academic study of the subject."),
|
|
645
|
+
exclusions: "An educational label on a harmful request, working instructions or an endorsement; erotic, graphic or gratuitous detail beyond what the teaching needs; an academic tone alone."
|
|
646
|
+
},
|
|
647
|
+
"self-harm-fictional": {
|
|
648
|
+
category: "self-harm",
|
|
649
|
+
kind: "context",
|
|
650
|
+
displayName: msg("Fictional"),
|
|
651
|
+
description: msg("Qualifying content clearly attributed to an invented character, fictional story, game, illustration, generated image or reenacted scene."),
|
|
652
|
+
exclusions: "Unclear fictional context, and a real-world threat or actionable harmful request presented as fiction."
|
|
653
|
+
},
|
|
654
|
+
"self-harm-support-prevention": {
|
|
655
|
+
category: "self-harm",
|
|
656
|
+
kind: "context",
|
|
657
|
+
displayName: msg("Support or prevention"),
|
|
658
|
+
description: msg("Qualifying content shared only to seek or give support, prevent harm or aid recovery, such as a survivor describing abuse to get help, or counterspeech that rejects an attack or threat. Someone disclosing current harm or risk counts when they are seeking help."),
|
|
659
|
+
exclusions: "Harmful instructions, assistance, advice on hiding harm, targeting or encouragement, including beside a supportive reply."
|
|
660
|
+
},
|
|
661
|
+
"harassment-abuse": {
|
|
662
|
+
category: "harassment",
|
|
663
|
+
kind: "harm",
|
|
664
|
+
displayName: msg("Insults or humiliation"),
|
|
665
|
+
description: msg("Insults, contemptuous name-calling such as idiot, moron, loser or pathetic, swearing at someone to dismiss or attack them, humiliation or degrading treatment aimed at a person or at a group that is not a protected identity group."),
|
|
666
|
+
exclusions: "Dislike or anger without an attack, such as “I hate you”; criticism of an argument, conduct or competence; untargeted profanity and profane praise; remarks with no identifiable target; a made-up quote illustrating a joke; describing an insult someone else holds; insults about a protected identity group as a whole, which are Hate unless a specific person is also attacked. Satire, sarcasm, mocking nicknames, mild name-calling such as fool or dummy, and joking comparisons are Mild mockery or teasing; threats are Threats or intimidation."
|
|
667
|
+
},
|
|
668
|
+
"harassment-mild": {
|
|
669
|
+
category: "harassment",
|
|
670
|
+
kind: "harm",
|
|
671
|
+
displayName: msg("Mild mockery or teasing"),
|
|
672
|
+
description: msg("Light ridicule, teasing, sarcasm, a mocking nickname or mild name-calling such as fool, dummy or silly, aimed at a person, including a public figure, or at a group that is not a protected identity group (a club, a team’s fans, a political party or its members), without contempt, degradation or threats. Hyperbole or satire about a public figure’s character, conduct or followers is included, and so is a meme whose comparison comes from its picture or a pictured character’s line, such as an animal guarding its “garbage”, when no one is directly called an insulting name. It counts so that a policy can allow or restrict it."),
|
|
673
|
+
exclusions: "Contemptuous name-calling such as idiot, moron, loser or pathetic, degrading insults, slurs, threats, sexual remarks, bullying and victim mockery, which are other forms; name-calling of a protected identity group, which is Hate; criticism of an argument, decision or conduct; self-deprecation and untargeted jokes; affectionate teasing between friends or family; telling someone not to call another person a name."
|
|
674
|
+
},
|
|
675
|
+
"harassment-bullying": {
|
|
676
|
+
category: "harassment",
|
|
677
|
+
kind: "harm",
|
|
678
|
+
displayName: msg("Bullying or abuse"),
|
|
679
|
+
description: msg("Repeated or sustained targeting of a person, ganging up on them, excluding or shutting them out, or abuse or coercive control by a partner, family member or someone else in an ongoing relationship."),
|
|
680
|
+
exclusions: "A single insult or remark, including a one-off demand that someone leave, which is Insults or humiliation; a one-off fight or assault by someone with no ongoing relationship to the victim."
|
|
681
|
+
},
|
|
682
|
+
"harassment-public-target": {
|
|
683
|
+
category: "harassment",
|
|
684
|
+
kind: "target",
|
|
685
|
+
displayName: msg("Aimed at a public figure or group"),
|
|
686
|
+
description: msg("The qualifying harassment is aimed at a public figure (an elected official or political candidate, a celebrity, a person with a large public following or a person in the news for their public role), an organisation or institution, or a group that is not a protected identity group (a club, a team’s fans, a political party or its members), rather than at a private individual."),
|
|
687
|
+
exclusions: "Private individuals, including a named or addressed member of the public, another user, a classmate, a colleague or a family member; any minor, even a well-known one; people in the news only because of something that happened to them; protected identity groups, which are Hate."
|
|
688
|
+
},
|
|
689
|
+
"harassment-threat": {
|
|
690
|
+
category: "harassment",
|
|
691
|
+
kind: "harm",
|
|
692
|
+
displayName: msg("Threats or intimidation"),
|
|
693
|
+
description: msg("A direct, conditional or clearly implied personal threat, or serious abusive or coercive intimidation, against an identifiable person or group. Violent rhetoric between groups belongs under Hate or Violence."),
|
|
694
|
+
exclusions: "Figures of speech; curses, religious condemnation and dismissals such as go to hell or get lost; disagreement or criticism; calling for lawful arrest, prosecution or accountability."
|
|
695
|
+
},
|
|
696
|
+
"harassment-sexual": {
|
|
697
|
+
category: "harassment",
|
|
698
|
+
kind: "harm",
|
|
699
|
+
displayName: msg("Sexual harassment"),
|
|
700
|
+
description: msg("Targeted unwanted sexual remarks, sexual humiliation, coercive advances or sexually abusive intimidation."),
|
|
701
|
+
exclusions: "Consensual sexual dialogue, romance, sexual content not aimed at anyone, and vulgar dismissals with no sexual act, sexual attention or coercion."
|
|
702
|
+
},
|
|
703
|
+
"harassment-encouragement": {
|
|
704
|
+
category: "harassment",
|
|
705
|
+
kind: "harm",
|
|
706
|
+
displayName: msg("Encouraging harassment"),
|
|
707
|
+
description: msg("The author urges, organises, praises or endorses targeted abuse of a person."),
|
|
708
|
+
exclusions: "Reporting or condemning abuse, and calling for lawful accountability."
|
|
709
|
+
},
|
|
710
|
+
"harassment-historical": {
|
|
711
|
+
category: "harassment",
|
|
712
|
+
kind: "context",
|
|
713
|
+
displayName: msg("Historical"),
|
|
714
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
715
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
716
|
+
},
|
|
717
|
+
"harassment-documentary": {
|
|
718
|
+
category: "harassment",
|
|
719
|
+
kind: "context",
|
|
720
|
+
displayName: msg("Reporting or documentary"),
|
|
721
|
+
description: msg("Qualifying content explicitly framed as factual reporting, testimony or documentation of actual real-world events or utterances, including a person's own incident report or a report to an authority."),
|
|
722
|
+
exclusions: "Neutral wording, third-person narration or quotation marks alone; fiction, invented examples, erotic display and adverts; a separate harmful request, attack or endorsement by the author."
|
|
723
|
+
},
|
|
724
|
+
"harassment-educational": {
|
|
725
|
+
category: "harassment",
|
|
726
|
+
kind: "context",
|
|
727
|
+
displayName: msg("Educational"),
|
|
728
|
+
description: msg("Qualifying content used in a lesson, safety explanation, clinical explanation or academic study."),
|
|
729
|
+
exclusions: "An educational label on a direct harmful request or endorsement. Actionable harmful instructions count as instructions even in teaching material."
|
|
730
|
+
},
|
|
731
|
+
"harassment-fictional": {
|
|
732
|
+
category: "harassment",
|
|
733
|
+
kind: "context",
|
|
734
|
+
displayName: msg("Fictional"),
|
|
735
|
+
description: msg("Qualifying harassment between invented characters in a clearly fictional story, comic, cartoon, game or roleplay, such as one character insulting, threatening, bullying or scheming against another, with no real or addressed person as its target."),
|
|
736
|
+
exclusions: "Unclear fictional context: quotation marks, verse, a fragment or third-person narration alone don't make content fiction. Harassment aimed at a real person, the reader or another participant; a story used to attack someone real, such as one mocking a named classmate; memes, satire, caricatures and generated images about real people or groups; photographs of real people, including staged or stock photos."
|
|
737
|
+
},
|
|
738
|
+
"harassment-support-prevention": {
|
|
739
|
+
category: "harassment",
|
|
740
|
+
kind: "context",
|
|
741
|
+
displayName: msg("Awareness, support or prevention"),
|
|
742
|
+
description: msg("Qualifying content presented solely to raise awareness of bullying or abuse, give prevention or safety guidance, or seek or provide support to someone targeted, such as an anti-bullying campaign or a person asking for help."),
|
|
743
|
+
exclusions: "A separate direct attack, advice to retaliate, or an awareness label on content that itself abuses someone. A reported attack shared to get help or prevent abuse is not a separate attack."
|
|
744
|
+
},
|
|
745
|
+
"hate-abuse": {
|
|
746
|
+
category: "hate",
|
|
747
|
+
kind: "harm",
|
|
748
|
+
displayName: msg("Identity-based insults or slurs"),
|
|
749
|
+
description: msg("Identity-based insults or slurs against people, including ones that are quoted or reported."),
|
|
750
|
+
exclusions: "Mentioning an identity, untargeted profanity, and discussing a word without attacking people."
|
|
751
|
+
},
|
|
752
|
+
"hate-slurs": {
|
|
753
|
+
category: "hate",
|
|
754
|
+
kind: "harm",
|
|
755
|
+
displayName: msg("Offensive slurs"),
|
|
756
|
+
description: msg("Identity-based attacks that use a recognised offensive identity slur, including censored or disguised spellings, whether used, quoted, reported, historical, fictional or taught."),
|
|
757
|
+
exclusions: "Neutral identity words, general insults about a people that aren't slurs, reclaimed or in-group use without contempt, and discussing a slur's history or meaning without attacking anyone."
|
|
758
|
+
},
|
|
759
|
+
"hate-dehumanization": {
|
|
760
|
+
category: "hate",
|
|
761
|
+
kind: "harm",
|
|
762
|
+
displayName: msg("Dehumanization"),
|
|
763
|
+
description: msg("The author claims or endorses that people with a protected identity are subhuman, animals, vermin or objects."),
|
|
764
|
+
exclusions: "Literal descriptions, unrelated metaphors, and reporting or condemning someone else's dehumanizing words."
|
|
765
|
+
},
|
|
766
|
+
"hate-inferiority": {
|
|
767
|
+
category: "hate",
|
|
768
|
+
kind: "harm",
|
|
769
|
+
displayName: msg("Inferiority or harmful stereotypes"),
|
|
770
|
+
description: msg("A claim that people are inherently inferior, or a harmful stereotype or generalisation that they are criminal, violent, dangerous, dishonest or immoral, because of a protected identity, including quoted or reported claims."),
|
|
771
|
+
exclusions: "Criticism of beliefs or conduct, and claims about particular people that don't extend to their group."
|
|
772
|
+
},
|
|
773
|
+
"hate-exclusion": {
|
|
774
|
+
category: "hate",
|
|
775
|
+
kind: "harm",
|
|
776
|
+
displayName: msg("Exclusion or discrimination"),
|
|
777
|
+
description: msg("The author advocates or endorses denying rights to, or excluding, people because of a protected identity."),
|
|
778
|
+
exclusions: "Reporting, criticising a policy, and lawful distinctions that attack no identity."
|
|
779
|
+
},
|
|
780
|
+
"hate-symbol": {
|
|
781
|
+
category: "hate",
|
|
782
|
+
kind: "harm",
|
|
783
|
+
displayName: msg("Hate symbol"),
|
|
784
|
+
description: msg("A recognised hate emblem, slogan or gesture, such as a Nazi swastika, including one shown in a news report or anti-hate material, with no other attack on a protected group."),
|
|
785
|
+
exclusions: "Religious or cultural symbols, similar shapes, ambiguous marks, a colour scheme alone, and discussion that shows no hate emblem; dehumanizing depictions, slurs and other attacks, which are other forms.",
|
|
786
|
+
inputs: ["image"]
|
|
787
|
+
},
|
|
788
|
+
"hate-hostility": {
|
|
789
|
+
category: "hate",
|
|
790
|
+
kind: "harm",
|
|
791
|
+
displayName: msg("Stated hatred"),
|
|
792
|
+
description: msg("Hatred, dislike or hostility stated towards a protected identity group as a whole, such as saying “I hate men”, including religious or moral condemnation of a protected identity, such as calling homosexuality a sin, or denying that an identity exists, with no slur, insult or epithet, dehumanization, inferiority claim or harmful stereotype, exclusion or threat. It counts so that a policy can allow or restrict it."),
|
|
793
|
+
exclusions: "Slurs, identity-based insults such as calling a group disgusting, dehumanization, inferiority claims or stereotypes, exclusion and threats, which are other forms; dislike of particular people or of something a group does; sarcastic praise; criticism of beliefs, ideologies or conduct."
|
|
794
|
+
},
|
|
795
|
+
"hate-threat": {
|
|
796
|
+
category: "hate",
|
|
797
|
+
kind: "harm",
|
|
798
|
+
displayName: msg("Threats or incitement"),
|
|
799
|
+
description: msg("The author threatens or endorses serious harm against people because of a protected identity."),
|
|
800
|
+
exclusions: "Threats with no identity motive, reporting or condemning someone else's threat, and calls for lawful accountability."
|
|
801
|
+
},
|
|
802
|
+
"hate-personal": {
|
|
803
|
+
category: "hate",
|
|
804
|
+
kind: "harm",
|
|
805
|
+
harmOption: false,
|
|
806
|
+
displayName: msg("Aimed at a specific person"),
|
|
807
|
+
description: msg("The identity attack is aimed at a specific, identifiable person, such as the person addressed or replied to, a named individual or someone pictured, rather than at a group in general."),
|
|
808
|
+
exclusions: "Attacks on a group as a whole or on unnamed members of it; quoted, reported or historical attacks with no new attack by the author; insults aimed at invented characters in fiction."
|
|
809
|
+
},
|
|
810
|
+
"hate-historical": {
|
|
811
|
+
category: "hate",
|
|
812
|
+
kind: "context",
|
|
813
|
+
displayName: msg("Historical"),
|
|
814
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
815
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
816
|
+
},
|
|
817
|
+
"hate-documentary": {
|
|
818
|
+
category: "hate",
|
|
819
|
+
kind: "context",
|
|
820
|
+
displayName: msg("Reporting or documentary"),
|
|
821
|
+
description: msg("Qualifying content explicitly framed as factual reporting, testimony or documentation of actual real-world events or utterances, including a person's own incident report or a report to an authority."),
|
|
822
|
+
exclusions: "Neutral wording, third-person narration or quotation marks alone; fiction, invented examples, erotic display and adverts; a separate harmful request, attack or endorsement by the author."
|
|
823
|
+
},
|
|
824
|
+
"hate-educational": {
|
|
825
|
+
category: "hate",
|
|
826
|
+
kind: "context",
|
|
827
|
+
displayName: msg("Educational"),
|
|
828
|
+
description: msg("Qualifying content used in a lesson, safety explanation, clinical explanation or academic study."),
|
|
829
|
+
exclusions: "An educational label on a direct harmful request or endorsement. Actionable harmful instructions count as instructions even in teaching material."
|
|
830
|
+
},
|
|
831
|
+
"hate-fictional": {
|
|
832
|
+
category: "hate",
|
|
833
|
+
kind: "context",
|
|
834
|
+
displayName: msg("Fictional"),
|
|
835
|
+
description: msg("Qualifying content clearly attributed to an invented character, fictional story, game, illustration, generated image or reenacted scene."),
|
|
836
|
+
exclusions: "Unclear fictional context, and a real-world threat or actionable harmful request presented as fiction."
|
|
837
|
+
},
|
|
838
|
+
"hate-counterspeech": {
|
|
839
|
+
category: "hate",
|
|
840
|
+
kind: "context",
|
|
841
|
+
displayName: msg("Counterspeech"),
|
|
842
|
+
description: msg("Concrete identity-based attacks quoted, paraphrased or described to reject, challenge or oppose their prejudice, including defending the people targeted and explaining why discriminatory claims are wrong."),
|
|
843
|
+
exclusions: "Quotation, neutral documentation or victim support that doesn't challenge the prejudice; a statement opposing hate beside a separate attack the author makes or endorses."
|
|
844
|
+
},
|
|
845
|
+
"hate-support-prevention": {
|
|
846
|
+
category: "hate",
|
|
847
|
+
kind: "context",
|
|
848
|
+
displayName: msg("Awareness, support or prevention"),
|
|
849
|
+
description: msg("Qualifying content used to raise awareness, give practical prevention or safety guidance, or seek or provide support to people targeted by hate. Challenging a prejudiced claim is assessed separately as Counterspeech; both qualifiers may apply when the material also supports victims or provides prevention guidance."),
|
|
850
|
+
exclusions: "A separate attack or endorsement by the author, or an awareness label on content that itself attacks a protected group. A reported attack used to counter hate is not a separate attack."
|
|
851
|
+
},
|
|
852
|
+
"criminal-activity-demonstration": {
|
|
853
|
+
category: "criminal-activity",
|
|
854
|
+
kind: "harm",
|
|
855
|
+
displayName: msg("Depicted or reported activity"),
|
|
856
|
+
description: msg("A depiction or account of a concrete violent or seriously dangerous criminal act, including a factual report of an actual act. A non-violent offence that endangers no one, such as theft or burglary, does not qualify on its own."),
|
|
857
|
+
exclusions: "Mentioning a topic, everyday objects, policy debate, and accusations or opinions about whether someone committed a crime."
|
|
858
|
+
},
|
|
859
|
+
"criminal-activity-preparation": {
|
|
860
|
+
category: "criminal-activity",
|
|
861
|
+
kind: "harm",
|
|
862
|
+
displayName: msg("Intent or preparation"),
|
|
863
|
+
description: msg("A concrete intent, preparation or plan for a criminal or seriously dangerous act expressed by the author."),
|
|
864
|
+
exclusions: "Vague danger, everyday risk, describing someone else's plan, lawful preparation, and lawful adult alcohol, tobacco, vaping or gambling activity and consensual adult sexual solicitation without separate criminal or seriously dangerous conduct. Threats and wishes of harm without a concrete criminal plan are assessed under Violence."
|
|
865
|
+
},
|
|
866
|
+
"criminal-activity-request": {
|
|
867
|
+
category: "criminal-activity",
|
|
868
|
+
kind: "harm",
|
|
869
|
+
displayName: msg("Requests for assistance"),
|
|
870
|
+
description: msg("A request by the author for help carrying out a concrete criminal or seriously dangerous act, or for help evading detection, consequences or accountability for one, such as how to get away with it. A later refusal does not erase that request."),
|
|
871
|
+
exclusions: "Requests for lawful help, describing someone else's request, prevention, and lawful adult alcohol, tobacco, vaping or gambling activity and consensual adult sexual solicitation without separate criminal or seriously dangerous conduct."
|
|
872
|
+
},
|
|
873
|
+
"criminal-activity-instructions": {
|
|
874
|
+
category: "criminal-activity",
|
|
875
|
+
kind: "harm",
|
|
876
|
+
displayName: msg("Instructions or facilitation"),
|
|
877
|
+
description: msg("Actionable instructions, practical assistance or facilitation for a concrete criminal or seriously dangerous act, including how to evade detection, consequences or accountability for one."),
|
|
878
|
+
exclusions: "Prevention, lawful safety advice, ordinary tools, non-actionable reporting, and lawful adult alcohol, tobacco, vaping or gambling activity and consensual adult sexual solicitation without separate criminal or seriously dangerous conduct."
|
|
879
|
+
},
|
|
880
|
+
"criminal-activity-promotion": {
|
|
881
|
+
category: "criminal-activity",
|
|
882
|
+
kind: "harm",
|
|
883
|
+
displayName: msg("Recruitment or promotion"),
|
|
884
|
+
description: msg("The author recruits for, endorses or promotes a concrete criminal or seriously dangerous act."),
|
|
885
|
+
exclusions: "Reporting, condemnation, lawful advocacy, vague references to danger, and lawful adult alcohol, tobacco, vaping or gambling activity and consensual adult sexual solicitation without separate criminal or seriously dangerous conduct. Threats and wishes of harm without criminal recruitment or a plan are assessed under Violence."
|
|
886
|
+
},
|
|
887
|
+
"criminal-activity-coded-incitement": {
|
|
888
|
+
category: "criminal-activity",
|
|
889
|
+
kind: "harm",
|
|
890
|
+
harmOption: false,
|
|
891
|
+
displayName: msg("Indirect coded incitement"),
|
|
892
|
+
description: msg("The author indirectly incites a concrete violent or seriously dangerous crime through coded language or an allusion whose meaning is clear from the context, without an explicit threat, plan, request or instructions."),
|
|
893
|
+
exclusions: "Ambiguous allusions, bare wishes, reporting and lawful advocacy; explicit threats, plans, requests or instructions, even when disguised with euphemisms or censored spelling, which are other forms."
|
|
894
|
+
},
|
|
895
|
+
"criminal-activity-substances": {
|
|
896
|
+
category: "criminal-activity",
|
|
897
|
+
kind: "harm",
|
|
898
|
+
displayName: msg("Drugs and controlled substances"),
|
|
899
|
+
description: msg("Illegal drugs or controlled substances: their use, preparation, purchase, sale, production or trafficking, including prescription medicines obtained, sold or used outside lawful medical supply."),
|
|
900
|
+
exclusions: "Medication prescribed and used as directed, lawful medical supply, pharmacy, research or educational scenes without illegal-drug use, lawful alcohol and tobacco, and crimes that don't involve drugs. Drug use in reporting, harm reduction or recovery still counts; its context is recorded separately."
|
|
901
|
+
},
|
|
902
|
+
"criminal-activity-grooming": {
|
|
903
|
+
category: "criminal-activity",
|
|
904
|
+
kind: "harm",
|
|
905
|
+
displayName: msg("Grooming and exploitation"),
|
|
906
|
+
description: msg("Manipulation that prepares a child or vulnerable person for sexual exploitation or abuse, such as sexual demands, rewards for sexual compliance, or secrecy, isolation or private-contact tactics with an evident exploitative purpose. Explicit sexual words aren't required. Reported or fictional grooming also counts."),
|
|
907
|
+
exclusions: "Friendly contact, adult relationships, gifts, mentoring, private messages or secrecy alone; general grooming warnings; hair care and animal grooming."
|
|
908
|
+
},
|
|
909
|
+
"criminal-activity-csam": {
|
|
910
|
+
category: "criminal-activity",
|
|
911
|
+
kind: "harm",
|
|
912
|
+
harmOption: false,
|
|
913
|
+
displayName: msg("Child sexual abuse material"),
|
|
914
|
+
description: msg("Child sexual abuse or exploitation material, whether only named or an actual instance of it being created, possessed, viewed, sought, bought, sold, shared, distributed or profited from, including requests and plans. A mention counts so that a policy can restrict it; conduct qualifiers such as Depicted or reported activity and Requests for assistance mark an actual instance. Reported, historical, fictional, educational and preventive instances also count."),
|
|
915
|
+
exclusions: "Adult sexual material and lawful non-sexual images of children. Child abuse that isn't sexual material, and grooming without material, are separate forms.",
|
|
916
|
+
inputs: ["text"]
|
|
917
|
+
},
|
|
918
|
+
"criminal-activity-alcohol": {
|
|
919
|
+
category: "criminal-activity",
|
|
920
|
+
kind: "harm",
|
|
921
|
+
displayName: msg("Alcohol"),
|
|
922
|
+
description: msg("Depicted or concretely described drinking, serving, purchasing, selling, making or advertising alcoholic drinks, including lawful adult activity and actual reported, historical or fictional instances."),
|
|
923
|
+
exclusions: "Crimes involving alcohol, such as drink-driving or supplying minors, which are other forms; the word alcohol alone; health or prevention discussion with no drinking; non-alcoholic drinks, hand sanitiser, disinfectant, laboratory alcohol and medicine; drink names used as names or colours."
|
|
924
|
+
},
|
|
925
|
+
"criminal-activity-tobacco": {
|
|
926
|
+
category: "criminal-activity",
|
|
927
|
+
kind: "harm",
|
|
928
|
+
displayName: msg("Tobacco and vaping"),
|
|
929
|
+
description: msg("Depicted or concretely described smoking, vaping, chewing tobacco, or purchasing, selling, making or advertising tobacco, nicotine or vaping products, including lawful adult activity and actual reported, historical or fictional instances."),
|
|
930
|
+
exclusions: "Crimes involving tobacco, such as selling to minors, which are other forms; health or prevention discussion with no smoking or vaping; nicotine patches or gum used to quit; smoke with no tobacco or vaping source; illegal-drug use without tobacco or vaping."
|
|
931
|
+
},
|
|
932
|
+
"criminal-activity-gambling": {
|
|
933
|
+
category: "criminal-activity",
|
|
934
|
+
kind: "harm",
|
|
935
|
+
displayName: msg("Gambling"),
|
|
936
|
+
description: msg("Depicted or concretely described betting or wagering money or something of real value on an uncertain outcome, casino gambling, paid lotteries, or selling or advertising those services, including lawful adult activity and actual reported, historical or fictional instances."),
|
|
937
|
+
exclusions: "Crimes involving gambling, such as fraud, which are other forms; games, sports, cards or dice without stakes; free competitions; investing; figurative bets; risk or prevention discussion with no gambling."
|
|
938
|
+
},
|
|
939
|
+
"criminal-activity-fraud": {
|
|
940
|
+
category: "criminal-activity",
|
|
941
|
+
kind: "harm",
|
|
942
|
+
displayName: msg("Fraud and scams"),
|
|
943
|
+
description: msg("Fraud, scams or phishing: a deceptive message that seeks money, account access, credentials or personal details, such as an advance-fee or romance scam, a fake prize, invoice or delivery notice, impersonation of a bank or official, or counterfeit goods or payment fraud, whether carried out, planned, requested, taught or promoted."),
|
|
944
|
+
exclusions: "General warnings or prevention advice with no specific scam, genuine requests for payment or details, and crimes without deception for gain. A reported scam or phishing example still counts; its context is recorded separately."
|
|
945
|
+
},
|
|
946
|
+
"criminal-activity-sexual-solicitation": {
|
|
947
|
+
category: "criminal-activity",
|
|
948
|
+
kind: "harm",
|
|
949
|
+
displayName: msg("Sexual solicitation"),
|
|
950
|
+
description: msg("An explicit request, offer or advertisement for consensual adult sexual activity or sexual services, including paid services. This policy category includes solicitation without inferring that it is illegal."),
|
|
951
|
+
exclusions: "Dating, romance, discussion of sex work without solicitation, vague offers without sexual content, and coercion, trafficking, exploitation or sexual activity involving minors."
|
|
952
|
+
},
|
|
953
|
+
"criminal-activity-graffiti": {
|
|
954
|
+
category: "criminal-activity",
|
|
955
|
+
kind: "harm",
|
|
956
|
+
displayName: msg("Graffiti"),
|
|
957
|
+
description: msg("Graffiti, tagging or spray-painted markings on walls, vehicles or other property, or people applying them, shown, planned or requested. Permission is rarely visible, so authorised murals and street art count too."),
|
|
958
|
+
exclusions: "Painting or drawing on canvas, paper or screens; removing or preventing graffiti; other property damage.",
|
|
959
|
+
inputs: ["image"]
|
|
960
|
+
},
|
|
961
|
+
"criminal-activity-historical": {
|
|
962
|
+
category: "criminal-activity",
|
|
963
|
+
kind: "context",
|
|
964
|
+
displayName: msg("Historical"),
|
|
965
|
+
description: msg("Qualifying content explicitly attributed to a real historical event."),
|
|
966
|
+
exclusions: "A date, past tense, an old-looking setting or a historical topic alone; a separate current threat, request or endorsement."
|
|
967
|
+
},
|
|
968
|
+
"criminal-activity-documentary": {
|
|
969
|
+
category: "criminal-activity",
|
|
970
|
+
kind: "context",
|
|
971
|
+
displayName: msg("Reporting or documentary"),
|
|
972
|
+
description: msg("Qualifying content explicitly framed as factual reporting, testimony or documentation of actual real-world events or utterances, including a person's own incident report or a report to an authority."),
|
|
973
|
+
exclusions: "Neutral wording, third-person narration or quotation marks alone; fiction, invented examples, erotic display and adverts; a separate harmful request, attack or endorsement by the author."
|
|
974
|
+
},
|
|
975
|
+
"criminal-activity-educational": {
|
|
976
|
+
category: "criminal-activity",
|
|
977
|
+
kind: "context",
|
|
978
|
+
displayName: msg("Educational"),
|
|
979
|
+
description: msg("Qualifying content used in a lesson, safety explanation, clinical explanation or academic study."),
|
|
980
|
+
exclusions: "A plain factual description with no teaching purpose; an educational label on a direct harmful request or endorsement. Actionable harmful instructions count as instructions even in teaching material. A request or plan to harm someone or commit a crime is excluded even when a reply answers it informatively."
|
|
981
|
+
},
|
|
982
|
+
"criminal-activity-discussion": {
|
|
983
|
+
category: "criminal-activity",
|
|
984
|
+
kind: "context",
|
|
985
|
+
displayName: msg("Non-graphic discussion"),
|
|
986
|
+
description: msg("Qualifying content referenced non-graphically to make or examine an argument, comparison, ethical question or analysis, rather than to perform, endorse, threaten, eroticise or facilitate the harmful act."),
|
|
987
|
+
exclusions: "Graphic or explicit sexual detail; erotic presentation; threats, victim mockery, endorsement, promotion, harmful assistance or instructions, direct harmful requests and sexual solicitation. A request or plan to harm someone or commit a crime is excluded even when a reply answers it informatively."
|
|
988
|
+
},
|
|
989
|
+
"criminal-activity-fictional": {
|
|
990
|
+
category: "criminal-activity",
|
|
991
|
+
kind: "context",
|
|
992
|
+
displayName: msg("Fictional"),
|
|
993
|
+
description: msg("Qualifying content clearly attributed to an invented character, fictional story, game, illustration, generated image or reenacted scene."),
|
|
994
|
+
exclusions: "Unclear fictional context, and a real-world threat or actionable harmful request presented as fiction."
|
|
995
|
+
},
|
|
996
|
+
"criminal-activity-support-prevention": {
|
|
997
|
+
category: "criminal-activity",
|
|
998
|
+
kind: "context",
|
|
999
|
+
displayName: msg("Harm reduction, recovery or prevention"),
|
|
1000
|
+
description: msg("Qualifying content shared only to prevent crime or reduce harm, support victims, oppose a crime or threat, or aid recovery, such as anti-scam guidance describing a real scam, support after fraud or stalking, or harm reduction and addiction recovery for illegal drug use. Generic safety advice alone doesn't establish criminal content."),
|
|
1001
|
+
exclusions: "Practical help, instructions, concealment advice, promotion or sales that facilitate crime; a supportive label on content that itself carries out, requests or encourages the act. Advice to contact support or report a scam is not criminal help."
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
const MODERATION_QUALIFIERS = Object.keys(MODERATION_QUALIFIER_INFO);
|
|
1005
|
+
MODERATION_QUALIFIERS.reduce((groups, qualifier) => {
|
|
1006
|
+
(groups[MODERATION_QUALIFIER_INFO[qualifier].category] ??= []).push(qualifier);
|
|
1007
|
+
return groups;
|
|
1008
|
+
}, {});
|
|
1009
|
+
function getModerationQualifierInfo(qualifier) {
|
|
1010
|
+
return MODERATION_QUALIFIER_INFO[qualifier];
|
|
1011
|
+
}
|
|
1012
|
+
/** Authenticated test inputs can add regional delivery restrictions without inventing evidence. */
|
|
1013
|
+
const TEST_REGIONAL_ACTIONS_SCHEMA = zod.array(zod.object({
|
|
1014
|
+
region: require_Jurisdiction_FusEXb4U.JURISDICTION_SCHEMA.exclude(["global"]),
|
|
1015
|
+
action: zod.enum([
|
|
1016
|
+
"limit",
|
|
1017
|
+
"age-restrict",
|
|
1018
|
+
"block"
|
|
1019
|
+
])
|
|
1020
|
+
}).strict()).max(7).refine((entries) => new Set(entries.map((entry) => entry.region)).size === entries.length, "Choose each region once");
|
|
1021
|
+
// src/contract/TestTriggers-DcArt0Nu.js
|
|
1022
|
+
/** A project's test input key: 32 hexadecimal characters only its members can see. */
|
|
1023
|
+
const TEST_INPUT_KEY_PATTERN = /^[a-f0-9]{32}$/;
|
|
1024
|
+
const TEXT_CODE_SIGNALS = [
|
|
1025
|
+
...CLASSIFICATION_CATEGORIES,
|
|
1026
|
+
"sexual.involving-minors",
|
|
1027
|
+
"harassment.insult",
|
|
1028
|
+
"sexual.adult",
|
|
1029
|
+
"hate.regional-symbol"
|
|
1030
|
+
];
|
|
1031
|
+
/** A 128-bit, domain-separated tag; published samples never contain the project key. */
|
|
1032
|
+
const getTestInputTag = async (kind, signal, testInputKey) => {
|
|
1033
|
+
if (!TEST_INPUT_KEY_PATTERN.test(testInputKey)) throw new TypeError("Invalid test input key");
|
|
1034
|
+
return (await require_CryptoUtils_B_x8lMIx.hmacSha256Hex(testInputKey, `calmlens-test:${kind}:${signal}`)).slice(0, 32);
|
|
1035
|
+
};
|
|
1036
|
+
/** Category shortcuts are presets in the same instance-based format. */
|
|
1037
|
+
function testInputForSignal(signal, kind = "text") {
|
|
1038
|
+
switch (signal) {
|
|
1039
|
+
case "harassment.insult": return TEST_INPUT_PRESETS.limited;
|
|
1040
|
+
case "sexual.adult": return kind === "image" ? TEST_INPUT_PRESETS.adultImage : TEST_INPUT_PRESETS.adultText;
|
|
1041
|
+
case "hate.regional-symbol": return TEST_INPUT_PRESETS.germany;
|
|
1042
|
+
case "sexual.involving-minors": return { instances: [{
|
|
1043
|
+
category: "sexual",
|
|
1044
|
+
qualifiers: ["sexual-minors"]
|
|
1045
|
+
}] };
|
|
1046
|
+
case "violence.graphic": return { instances: [{
|
|
1047
|
+
category: "violence",
|
|
1048
|
+
qualifiers: ["violence-graphic"]
|
|
1049
|
+
}] };
|
|
1050
|
+
default: return TEST_INPUT_SCHEMA.parse({ instances: [{
|
|
1051
|
+
category: signal,
|
|
1052
|
+
qualifiers: []
|
|
1053
|
+
}] });
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
const getImageTestCategories = () => [...TEXT_CODE_SIGNALS];
|
|
1057
|
+
/** Each row is one qualifying instance. Unselected qualifiers are explicitly absent. */
|
|
1058
|
+
const TEST_INPUT_SCHEMA = zod.object({
|
|
1059
|
+
regionalActions: TEST_REGIONAL_ACTIONS_SCHEMA.optional(),
|
|
1060
|
+
unassessedCategories: zod.array(zod.enum(CLASSIFICATION_CATEGORIES)).max(CLASSIFICATION_CATEGORIES.length).optional(),
|
|
1061
|
+
instances: zod.array(zod.object({
|
|
1062
|
+
category: zod.enum(CLASSIFICATION_CATEGORIES),
|
|
1063
|
+
score: zod.number().min(0).max(1).optional(),
|
|
1064
|
+
action: zod.enum([
|
|
1065
|
+
"allow",
|
|
1066
|
+
"limit",
|
|
1067
|
+
"age-restrict",
|
|
1068
|
+
"block"
|
|
1069
|
+
]).optional(),
|
|
1070
|
+
qualifiers: zod.array(zod.enum(MODERATION_QUALIFIERS)).max(64)
|
|
1071
|
+
}).strict().superRefine((instance, context) => {
|
|
1072
|
+
if (new Set(instance.qualifiers).size !== instance.qualifiers.length || instance.qualifiers.some((q) => getModerationQualifierInfo(q).category !== instance.category || "fromInput" in getModerationQualifierInfo(q))) context.addIssue({
|
|
1073
|
+
code: "custom",
|
|
1074
|
+
message: "Choose unique content qualifiers from this category; input-type facts are automatic."
|
|
1075
|
+
});
|
|
1076
|
+
})).max(128)
|
|
1077
|
+
}).strict().superRefine((scenario, context) => {
|
|
1078
|
+
if (scenario.instances.some((instance) => instance.action !== void 0) && scenario.instances.some((instance) => instance.action === void 0)) context.addIssue({
|
|
1079
|
+
code: "custom",
|
|
1080
|
+
message: msg("Set an action for every instance or omit all actions.")
|
|
1081
|
+
});
|
|
1082
|
+
const missing = scenario.unassessedCategories ?? [];
|
|
1083
|
+
if (new Set(missing).size !== missing.length || scenario.instances.some((instance) => missing.includes(instance.category))) context.addIssue({
|
|
1084
|
+
code: "custom",
|
|
1085
|
+
message: msg("An unassessed category cannot also have assessed instances.")
|
|
1086
|
+
});
|
|
1087
|
+
});
|
|
1088
|
+
const TEST_INPUT_PRESETS = {
|
|
1089
|
+
clean: { instances: [] },
|
|
1090
|
+
limited: { instances: [{
|
|
1091
|
+
category: "harassment",
|
|
1092
|
+
qualifiers: ["harassment-abuse"]
|
|
1093
|
+
}] },
|
|
1094
|
+
adultImage: { instances: [{
|
|
1095
|
+
category: "sexual",
|
|
1096
|
+
qualifiers: ["sexual-pornographic-media"]
|
|
1097
|
+
}] },
|
|
1098
|
+
adultText: { instances: [{
|
|
1099
|
+
category: "sexual",
|
|
1100
|
+
qualifiers: ["sexual-explicit-language"]
|
|
1101
|
+
}] },
|
|
1102
|
+
regionalDelivery: {
|
|
1103
|
+
instances: [],
|
|
1104
|
+
regionalActions: [
|
|
1105
|
+
{
|
|
1106
|
+
region: "DE",
|
|
1107
|
+
action: "block"
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
region: "GB",
|
|
1111
|
+
action: "age-restrict"
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
region: "FR",
|
|
1115
|
+
action: "limit"
|
|
1116
|
+
}
|
|
1117
|
+
]
|
|
1118
|
+
},
|
|
1119
|
+
germany: { instances: [{
|
|
1120
|
+
category: "hate",
|
|
1121
|
+
qualifiers: ["hate-symbol", "hate-nazi-symbols-public-display"]
|
|
1122
|
+
}] },
|
|
1123
|
+
mixed: { instances: [{
|
|
1124
|
+
category: "harassment",
|
|
1125
|
+
qualifiers: ["harassment-abuse", "harassment-documentary"]
|
|
1126
|
+
}, {
|
|
1127
|
+
category: "harassment",
|
|
1128
|
+
qualifiers: ["harassment-threat"]
|
|
1129
|
+
}] }
|
|
1130
|
+
};
|
|
1131
|
+
const pattern = /<!calmlens-test ([a-f0-9]{32}) ([A-Za-z0-9_-]+)>/g;
|
|
1132
|
+
const tag = async (payload, key) => (await require_CryptoUtils_B_x8lMIx.hmacSha256Hex(key, `calmlens-test:v1:${payload}`)).slice(0, 32);
|
|
1133
|
+
async function generateTestTextCode(scenario, key) {
|
|
1134
|
+
if (!/^[a-f0-9]{32}$/.test(key)) throw new TypeError("Invalid test input key");
|
|
1135
|
+
const payload = btoa(JSON.stringify(TEST_INPUT_SCHEMA.parse(typeof scenario === "string" ? testInputForSignal(scenario) : scenario))).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
1136
|
+
if (payload.length > 8e3) throw new RangeError("Test scenario is too large");
|
|
1137
|
+
return `<!calmlens-test ${await tag(payload, key)} ${payload}>`;
|
|
1138
|
+
}
|
|
1139
|
+
async function detectTestTrigger(text, key) {
|
|
1140
|
+
if (!/^[a-f0-9]{32}$/.test(key)) return;
|
|
1141
|
+
const matches = [...text.matchAll(pattern)];
|
|
1142
|
+
if (matches.length !== 1) return;
|
|
1143
|
+
const [, signature, payload] = matches[0];
|
|
1144
|
+
if (payload.length > 8e3 || !require_CryptoUtils_B_x8lMIx.timingSafeEqual(signature, await tag(payload, key))) return;
|
|
1145
|
+
try {
|
|
1146
|
+
const parsed = TEST_INPUT_SCHEMA.safeParse(JSON.parse(atob(payload.replaceAll("-", "+").replaceAll("_", "/"))));
|
|
1147
|
+
return parsed.success ? parsed.data : void 0;
|
|
1148
|
+
} catch {
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
/** Category colours are decorative; authenticated instance data determines classification. */
|
|
1153
|
+
const TEST_INPUT_CATEGORY_COLORS = {
|
|
1154
|
+
sexual: [
|
|
1155
|
+
232,
|
|
1156
|
+
80,
|
|
1157
|
+
160
|
|
1158
|
+
],
|
|
1159
|
+
violence: [
|
|
1160
|
+
224,
|
|
1161
|
+
56,
|
|
1162
|
+
64
|
|
1163
|
+
],
|
|
1164
|
+
"self-harm": [
|
|
1165
|
+
24,
|
|
1166
|
+
168,
|
|
1167
|
+
152
|
|
1168
|
+
],
|
|
1169
|
+
harassment: [
|
|
1170
|
+
240,
|
|
1171
|
+
128,
|
|
1172
|
+
48
|
|
1173
|
+
],
|
|
1174
|
+
hate: [
|
|
1175
|
+
144,
|
|
1176
|
+
80,
|
|
1177
|
+
216
|
|
1178
|
+
],
|
|
1179
|
+
"criminal-activity": [
|
|
1180
|
+
224,
|
|
1181
|
+
184,
|
|
1182
|
+
40
|
|
1183
|
+
],
|
|
1184
|
+
"personal-information": [
|
|
1185
|
+
48,
|
|
1186
|
+
128,
|
|
1187
|
+
224
|
|
1188
|
+
],
|
|
1189
|
+
profanity: [
|
|
1190
|
+
136,
|
|
1191
|
+
192,
|
|
1192
|
+
48
|
|
1193
|
+
]
|
|
1194
|
+
};
|
|
1195
|
+
/** One byte per 4px cell, stored in the low RGB bits to preserve the category colour. */
|
|
1196
|
+
async function paintTestImage(scenario, key) {
|
|
1197
|
+
const input = TEST_INPUT_SCHEMA.parse(typeof scenario === "string" ? testInputForSignal(scenario, "image") : scenario);
|
|
1198
|
+
const bytes = new TextEncoder().encode(await generateTestTextCode(input, key));
|
|
1199
|
+
const palette = input.instances.length ? [...new Set(input.instances.map((instance) => instance.category))].map((category) => TEST_INPUT_CATEGORY_COLORS[category]) : [[
|
|
1200
|
+
144,
|
|
1201
|
+
152,
|
|
1202
|
+
160
|
|
1203
|
+
]];
|
|
1204
|
+
const data = new Uint8Array([
|
|
1205
|
+
67,
|
|
1206
|
+
76,
|
|
1207
|
+
84,
|
|
1208
|
+
83,
|
|
1209
|
+
2,
|
|
1210
|
+
bytes.length >> 8,
|
|
1211
|
+
bytes.length & 255,
|
|
1212
|
+
...bytes
|
|
1213
|
+
]);
|
|
1214
|
+
const cells = Math.ceil(Math.sqrt(data.length));
|
|
1215
|
+
const width = cells * 4;
|
|
1216
|
+
const height = width;
|
|
1217
|
+
const rgba = new Uint8Array(width * height * 4);
|
|
1218
|
+
for (let i = 0; i < width * height; i++) {
|
|
1219
|
+
const row = Math.floor(i / width / 4);
|
|
1220
|
+
const cell = row * cells + Math.floor(i % width / 4);
|
|
1221
|
+
const value = data[cell % data.length];
|
|
1222
|
+
const x = cell % cells / (cells - 1);
|
|
1223
|
+
const y = row / (cells - 1);
|
|
1224
|
+
const position = (x * (1 - y) + (1 - x) * y) * (palette.length - 1);
|
|
1225
|
+
const start = Math.floor(position);
|
|
1226
|
+
const blend = position - start;
|
|
1227
|
+
const shade = (value * 73 + 41 & 255) / 255;
|
|
1228
|
+
const color = palette[start].map((channel, index) => {
|
|
1229
|
+
const mixed = channel + (palette[Math.min(start + 1, palette.length - 1)][index] - channel) * blend;
|
|
1230
|
+
return Math.round(mixed * (.65 + shade * .2) + 38 * shade);
|
|
1231
|
+
});
|
|
1232
|
+
rgba.set([
|
|
1233
|
+
color[0] & 248 | value >> 5,
|
|
1234
|
+
color[1] & 248 | value >> 2 & 7,
|
|
1235
|
+
color[2] & 252 | value & 3,
|
|
1236
|
+
255
|
|
1237
|
+
], i * 4);
|
|
1238
|
+
}
|
|
1239
|
+
return {
|
|
1240
|
+
width,
|
|
1241
|
+
height,
|
|
1242
|
+
rgba
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
async function detectTestImage(image, key) {
|
|
1246
|
+
if (!Number.isSafeInteger(image.width) || image.width < 4 || image.width % 4 !== 0 || image.height !== image.width || image.height > 512 || image.rgba.length !== image.width * image.height * 4) return;
|
|
1247
|
+
const legacy = image.rgba[0] === 67 && image.rgba[1] === 188 && image.rgba[2] === 123;
|
|
1248
|
+
const bytes = [];
|
|
1249
|
+
for (let y = 0; y < image.height; y += 4) for (let x = 0; x < image.width; x += 4) {
|
|
1250
|
+
const offset = (y * image.width + x) * 4;
|
|
1251
|
+
const red = image.rgba[offset];
|
|
1252
|
+
const green = image.rgba[offset + 1];
|
|
1253
|
+
const blue = image.rgba[offset + 2];
|
|
1254
|
+
const value = legacy ? red : (red & 7) << 5 | (green & 7) << 2 | blue & 3;
|
|
1255
|
+
if (legacy && (green !== 255 - red || blue !== 123)) return;
|
|
1256
|
+
for (let dy = 0; dy < 4; dy++) for (let dx = 0; dx < 4; dx++) {
|
|
1257
|
+
const pos = ((y + dy) * image.width + x + dx) * 4;
|
|
1258
|
+
if (image.rgba[pos] !== red || image.rgba[pos + 1] !== green || image.rgba[pos + 2] !== blue || image.rgba[pos + 3] !== 255) return;
|
|
1259
|
+
}
|
|
1260
|
+
bytes.push(value);
|
|
1261
|
+
}
|
|
1262
|
+
if (bytes.slice(0, 5).join() !== `67,76,84,83,${legacy ? 1 : 2}`) return;
|
|
1263
|
+
const length = bytes[5] << 8 | bytes[6];
|
|
1264
|
+
if (length > bytes.length - 7) return;
|
|
1265
|
+
return detectTestTrigger(new TextDecoder().decode(new Uint8Array(bytes.slice(7, 7 + length))), key);
|
|
1266
|
+
}
|
|
1267
|
+
Object.defineProperty(exports, "CLASSIFICATION_CATEGORIES", {
|
|
1268
|
+
enumerable: true,
|
|
1269
|
+
get: function() {
|
|
1270
|
+
return CLASSIFICATION_CATEGORIES;
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
Object.defineProperty(exports, "TEST_INPUT_KEY_PATTERN", {
|
|
1274
|
+
enumerable: true,
|
|
1275
|
+
get: function() {
|
|
1276
|
+
return TEST_INPUT_KEY_PATTERN;
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
Object.defineProperty(exports, "TEST_INPUT_PRESETS", {
|
|
1280
|
+
enumerable: true,
|
|
1281
|
+
get: function() {
|
|
1282
|
+
return TEST_INPUT_PRESETS;
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
Object.defineProperty(exports, "detectTestImage", {
|
|
1286
|
+
enumerable: true,
|
|
1287
|
+
get: function() {
|
|
1288
|
+
return detectTestImage;
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
Object.defineProperty(exports, "detectTestTrigger", {
|
|
1292
|
+
enumerable: true,
|
|
1293
|
+
get: function() {
|
|
1294
|
+
return detectTestTrigger;
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
Object.defineProperty(exports, "generateTestTextCode", {
|
|
1298
|
+
enumerable: true,
|
|
1299
|
+
get: function() {
|
|
1300
|
+
return generateTestTextCode;
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1303
|
+
Object.defineProperty(exports, "getImageTestCategories", {
|
|
1304
|
+
enumerable: true,
|
|
1305
|
+
get: function() {
|
|
1306
|
+
return getImageTestCategories;
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
Object.defineProperty(exports, "getTestInputTag", {
|
|
1310
|
+
enumerable: true,
|
|
1311
|
+
get: function() {
|
|
1312
|
+
return getTestInputTag;
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
Object.defineProperty(exports, "paintTestImage", {
|
|
1316
|
+
enumerable: true,
|
|
1317
|
+
get: function() {
|
|
1318
|
+
return paintTestImage;
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
Object.defineProperty(exports, "testInputForSignal", {
|
|
1322
|
+
enumerable: true,
|
|
1323
|
+
get: function() {
|
|
1324
|
+
return testInputForSignal;
|
|
1325
|
+
}
|
|
1326
|
+
});
|