@oxyhq/crowdsource-contracts 0.1.0

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.
Files changed (57) hide show
  1. package/README.md +129 -0
  2. package/dist/case-envelope.d.ts +1130 -0
  3. package/dist/case-envelope.d.ts.map +1 -0
  4. package/dist/case-envelope.js +383 -0
  5. package/dist/case-envelope.js.map +1 -0
  6. package/dist/decisions.d.ts +353 -0
  7. package/dist/decisions.d.ts.map +1 -0
  8. package/dist/decisions.js +198 -0
  9. package/dist/decisions.js.map +1 -0
  10. package/dist/index.d.ts +45 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +61 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/json-schema.d.ts +43 -0
  15. package/dist/json-schema.d.ts.map +1 -0
  16. package/dist/json-schema.js +83 -0
  17. package/dist/json-schema.js.map +1 -0
  18. package/dist/policies.d.ts +286 -0
  19. package/dist/policies.d.ts.map +1 -0
  20. package/dist/policies.js +178 -0
  21. package/dist/policies.js.map +1 -0
  22. package/dist/primitives.d.ts +185 -0
  23. package/dist/primitives.d.ts.map +1 -0
  24. package/dist/primitives.js +231 -0
  25. package/dist/primitives.js.map +1 -0
  26. package/dist/reputation-events.d.ts +349 -0
  27. package/dist/reputation-events.d.ts.map +1 -0
  28. package/dist/reputation-events.js +128 -0
  29. package/dist/reputation-events.js.map +1 -0
  30. package/dist/resources.d.ts +484 -0
  31. package/dist/resources.d.ts.map +1 -0
  32. package/dist/resources.js +436 -0
  33. package/dist/resources.js.map +1 -0
  34. package/dist/reviews.d.ts +276 -0
  35. package/dist/reviews.d.ts.map +1 -0
  36. package/dist/reviews.js +144 -0
  37. package/dist/reviews.js.map +1 -0
  38. package/dist/taxonomy.d.ts +266 -0
  39. package/dist/taxonomy.d.ts.map +1 -0
  40. package/dist/taxonomy.js +282 -0
  41. package/dist/taxonomy.js.map +1 -0
  42. package/dist/webhooks.d.ts +604 -0
  43. package/dist/webhooks.d.ts.map +1 -0
  44. package/dist/webhooks.js +192 -0
  45. package/dist/webhooks.js.map +1 -0
  46. package/package.json +56 -0
  47. package/src/case-envelope.ts +433 -0
  48. package/src/decisions.ts +216 -0
  49. package/src/index.ts +45 -0
  50. package/src/json-schema.ts +89 -0
  51. package/src/policies.ts +203 -0
  52. package/src/primitives.ts +283 -0
  53. package/src/reputation-events.ts +144 -0
  54. package/src/resources.ts +489 -0
  55. package/src/reviews.ts +159 -0
  56. package/src/taxonomy.ts +313 -0
  57. package/src/webhooks.ts +215 -0
@@ -0,0 +1,266 @@
1
+ /**
2
+ * The universal classification layer (§6.1, §6.3).
3
+ *
4
+ * §6.1 separates three layers and warns that mixing them makes the service
5
+ * unusable across applications with different rules. This module is the FIRST
6
+ * layer only — "what does the material contain or represent?" — and it belongs
7
+ * to CrowdSource. Whether that content violates anything is the second layer
8
+ * (`policies.ts`, per tenant) and whether it should move global trust is the
9
+ * third (`reputation-events.ts`). Nothing here may encode a single tenant's
10
+ * vocabulary.
11
+ *
12
+ * The code list is CLOSED. `other.policy_specific` and `other.unclassifiable`
13
+ * are the escape hatches the plan provides for material that does not fit; an
14
+ * open string would let a tenant mint private codes, which is precisely the
15
+ * cross-application comparability §6.1 exists to protect. Adding a code is an
16
+ * additive change that bumps `UNIVERSAL_TAXONOMY_VERSION`, and §6.4 requires
17
+ * every decision to record the version it was classified under, so historical
18
+ * decisions keep meaning what they meant.
19
+ */
20
+ import { z } from 'zod';
21
+ /** §6.3 families. */
22
+ export declare const TAXONOMY_FAMILIES: readonly ["integrity", "harassment", "hate", "violence", "sexual_content", "child_safety", "self_harm", "privacy", "commerce", "platform_abuse", "other"];
23
+ export declare const TaxonomyFamilySchema: z.ZodEnum<{
24
+ integrity: "integrity";
25
+ harassment: "harassment";
26
+ hate: "hate";
27
+ violence: "violence";
28
+ sexual_content: "sexual_content";
29
+ child_safety: "child_safety";
30
+ self_harm: "self_harm";
31
+ privacy: "privacy";
32
+ commerce: "commerce";
33
+ platform_abuse: "platform_abuse";
34
+ other: "other";
35
+ }>;
36
+ export type TaxonomyFamily = z.infer<typeof TaxonomyFamilySchema>;
37
+ /**
38
+ * §6.3, grouped.
39
+ *
40
+ * §9.4 requires consensus on the "main taxonomic family", not only on the exact
41
+ * code, so the grouping is part of the contract rather than something the
42
+ * consensus engine re-derives from string prefixes.
43
+ */
44
+ export declare const TAXONOMY_CODES_BY_FAMILY: Readonly<{
45
+ readonly integrity: readonly ["integrity.spam", "integrity.scam", "integrity.fraud", "integrity.impersonation", "integrity.coordinated_manipulation"];
46
+ readonly harassment: readonly ["harassment.insult", "harassment.targeted_abuse", "harassment.sexual_harassment", "harassment.doxxing", "harassment.credible_threat"];
47
+ readonly hate: readonly ["hate.dehumanization", "hate.slur", "hate.incitement", "hate.protected_targeting"];
48
+ readonly violence: readonly ["violence.graphic", "violence.threat", "violence.instruction", "violence.celebration"];
49
+ readonly sexual_content: readonly ["sexual_content.nudity", "sexual_content.explicit_activity", "sexual_content.non_consensual", "sexual_content.exploitation"];
50
+ readonly child_safety: readonly ["child_safety.sexualization", "child_safety.grooming", "child_safety.exploitation"];
51
+ readonly self_harm: readonly ["self_harm.promotion", "self_harm.instruction", "self_harm.imminent_risk"];
52
+ readonly privacy: readonly ["privacy.personal_information", "privacy.intimate_media", "privacy.location_exposure"];
53
+ readonly commerce: readonly ["commerce.prohibited_item", "commerce.counterfeit", "commerce.misleading_listing", "commerce.unsafe_product"];
54
+ readonly platform_abuse: readonly ["platform_abuse.ban_evasion", "platform_abuse.report_abuse", "platform_abuse.automation_abuse"];
55
+ readonly other: readonly ["other.policy_specific", "other.unclassifiable"];
56
+ }>;
57
+ export declare const UNIVERSAL_TAXONOMY_CODES: readonly ["integrity.spam", "integrity.scam", "integrity.fraud", "integrity.impersonation", "integrity.coordinated_manipulation", "harassment.insult", "harassment.targeted_abuse", "harassment.sexual_harassment", "harassment.doxxing", "harassment.credible_threat", "hate.dehumanization", "hate.slur", "hate.incitement", "hate.protected_targeting", "violence.graphic", "violence.threat", "violence.instruction", "violence.celebration", "sexual_content.nudity", "sexual_content.explicit_activity", "sexual_content.non_consensual", "sexual_content.exploitation", "child_safety.sexualization", "child_safety.grooming", "child_safety.exploitation", "self_harm.promotion", "self_harm.instruction", "self_harm.imminent_risk", "privacy.personal_information", "privacy.intimate_media", "privacy.location_exposure", "commerce.prohibited_item", "commerce.counterfeit", "commerce.misleading_listing", "commerce.unsafe_product", "platform_abuse.ban_evasion", "platform_abuse.report_abuse", "platform_abuse.automation_abuse", "other.policy_specific", "other.unclassifiable"];
58
+ export declare const TaxonomyCodeSchema: z.ZodEnum<{
59
+ "integrity.spam": "integrity.spam";
60
+ "integrity.scam": "integrity.scam";
61
+ "integrity.fraud": "integrity.fraud";
62
+ "integrity.impersonation": "integrity.impersonation";
63
+ "integrity.coordinated_manipulation": "integrity.coordinated_manipulation";
64
+ "harassment.insult": "harassment.insult";
65
+ "harassment.targeted_abuse": "harassment.targeted_abuse";
66
+ "harassment.sexual_harassment": "harassment.sexual_harassment";
67
+ "harassment.doxxing": "harassment.doxxing";
68
+ "harassment.credible_threat": "harassment.credible_threat";
69
+ "hate.dehumanization": "hate.dehumanization";
70
+ "hate.slur": "hate.slur";
71
+ "hate.incitement": "hate.incitement";
72
+ "hate.protected_targeting": "hate.protected_targeting";
73
+ "violence.graphic": "violence.graphic";
74
+ "violence.threat": "violence.threat";
75
+ "violence.instruction": "violence.instruction";
76
+ "violence.celebration": "violence.celebration";
77
+ "sexual_content.nudity": "sexual_content.nudity";
78
+ "sexual_content.explicit_activity": "sexual_content.explicit_activity";
79
+ "sexual_content.non_consensual": "sexual_content.non_consensual";
80
+ "sexual_content.exploitation": "sexual_content.exploitation";
81
+ "child_safety.sexualization": "child_safety.sexualization";
82
+ "child_safety.grooming": "child_safety.grooming";
83
+ "child_safety.exploitation": "child_safety.exploitation";
84
+ "self_harm.promotion": "self_harm.promotion";
85
+ "self_harm.instruction": "self_harm.instruction";
86
+ "self_harm.imminent_risk": "self_harm.imminent_risk";
87
+ "privacy.personal_information": "privacy.personal_information";
88
+ "privacy.intimate_media": "privacy.intimate_media";
89
+ "privacy.location_exposure": "privacy.location_exposure";
90
+ "commerce.prohibited_item": "commerce.prohibited_item";
91
+ "commerce.counterfeit": "commerce.counterfeit";
92
+ "commerce.misleading_listing": "commerce.misleading_listing";
93
+ "commerce.unsafe_product": "commerce.unsafe_product";
94
+ "platform_abuse.ban_evasion": "platform_abuse.ban_evasion";
95
+ "platform_abuse.report_abuse": "platform_abuse.report_abuse";
96
+ "platform_abuse.automation_abuse": "platform_abuse.automation_abuse";
97
+ "other.policy_specific": "other.policy_specific";
98
+ "other.unclassifiable": "other.unclassifiable";
99
+ }>;
100
+ export type TaxonomyCode = z.infer<typeof TaxonomyCodeSchema>;
101
+ /**
102
+ * The version of the code list above.
103
+ *
104
+ * §6.4: every decision records the taxonomy version it was decided under, and a
105
+ * policy update never silently rewrites history. Keeping the constant in the
106
+ * same module as the codes is what makes that possible — the two cannot drift.
107
+ * The value is the one the plan uses in Appendix B and §11.6.
108
+ */
109
+ export declare const UNIVERSAL_TAXONOMY_VERSION = "2026.1";
110
+ /** The family a code belongs to. */
111
+ export declare function taxonomyFamilyOf(code: TaxonomyCode): TaxonomyFamily;
112
+ /** §9.4 / §11.8 severity scale. */
113
+ export declare const SEVERITIES: readonly ["low", "medium", "high", "critical"];
114
+ export declare const SeveritySchema: z.ZodEnum<{
115
+ low: "low";
116
+ medium: "medium";
117
+ high: "high";
118
+ critical: "critical";
119
+ }>;
120
+ export type Severity = z.infer<typeof SeveritySchema>;
121
+ /**
122
+ * How far a finding reaches.
123
+ *
124
+ * §11.6 and Appendix B use `oxy_network`; §11.7.5 additionally names
125
+ * `identity_integrity` as a scope that may produce an Oxy Trust effect. The
126
+ * plan never names the third value — the one that means "this matters to the
127
+ * application and stops there" — even though §6.5's entire argument is that
128
+ * most local restrictions must NOT become global sanctions. `application_local`
129
+ * is the contract's name for it and is the ONE token in this package invented
130
+ * rather than quoted. Modelling it as an absent field instead would make
131
+ * §11.7.5 a presence check, which fails open.
132
+ */
133
+ export declare const FINDING_SCOPES: readonly ["application_local", "oxy_network", "identity_integrity"];
134
+ export declare const FindingScopeSchema: z.ZodEnum<{
135
+ application_local: "application_local";
136
+ oxy_network: "oxy_network";
137
+ identity_integrity: "identity_integrity";
138
+ }>;
139
+ export type FindingScope = z.infer<typeof FindingScopeSchema>;
140
+ /**
141
+ * Scopes that §11.7.5 allows to reach Oxy Trust.
142
+ *
143
+ * Exported as its own schema so `reputation-events.ts` states the rule in the
144
+ * type rather than re-checking it at runtime.
145
+ */
146
+ export declare const REPUTATION_ELIGIBLE_FINDING_SCOPES: readonly ["oxy_network", "identity_integrity"];
147
+ export declare const ReputationEligibleFindingScopeSchema: z.ZodEnum<{
148
+ oxy_network: "oxy_network";
149
+ identity_integrity: "identity_integrity";
150
+ }>;
151
+ export type ReputationEligibleFindingScope = z.infer<typeof ReputationEligibleFindingScopeSchema>;
152
+ /**
153
+ * Who a finding attributes conduct to.
154
+ *
155
+ * Appendix B and §11.6 use `author`. §11.11 and §11.12 describe confirmed
156
+ * report abuse and confirmed review abuse producing conduct effects of their
157
+ * own, which is where the other two values come from. There is deliberately no
158
+ * `unknown`: attribution exists to name a principal, and §11.7.4 will not let
159
+ * an effect land without a binding proof for that principal anyway.
160
+ */
161
+ export declare const FINDING_ATTRIBUTIONS: readonly ["author", "reporter", "reviewer"];
162
+ export declare const FindingAttributionSchema: z.ZodEnum<{
163
+ author: "author";
164
+ reporter: "reporter";
165
+ reviewer: "reviewer";
166
+ }>;
167
+ export type FindingAttribution = z.infer<typeof FindingAttributionSchema>;
168
+ /**
169
+ * What CrowdSource may recommend an application do.
170
+ *
171
+ * The plan writes action tokens in two places. §6.2, §9.3, §10.7 and Appendix B
172
+ * recommend `remove_or_restrict` and `allow_with_label`; §7.6 tabulates, per
173
+ * decision outcome, the actions an application may take in response. They are
174
+ * the same vocabulary seen from the two ends of one exchange, so the contract
175
+ * carries the union as one closed list — otherwise a recommendation and the
176
+ * enforcement that answers it would not be comparable, and §7.6's requirement
177
+ * that an application "record what it did and why" would compare apples to
178
+ * pears.
179
+ *
180
+ * §7.6's outcome→action table is NOT reproduced as a constraint. It bounds what
181
+ * an application may do in response to an outcome, not what a jury may
182
+ * recommend — Appendix B recommends `remove_or_restrict`, which does not appear
183
+ * in §7.6's `violation` row at all. Binding the two would reject the plan's own
184
+ * reference decision.
185
+ */
186
+ export declare const RECOMMENDED_ACTIONS: readonly ["remove_or_restrict", "allow_with_label", "remove", "hide", "label", "age_gate", "reduce_distribution", "freeze_transaction", "suspend_user", "request_changes", "allow", "restore", "no_action", "request_more_context", "hold", "local_manual_review", "keep_restricted_temporarily", "escalate", "no_global_effect", "specialist_queue", "legal_queue", "safety_queue"];
187
+ export declare const RecommendedActionSchema: z.ZodEnum<{
188
+ remove_or_restrict: "remove_or_restrict";
189
+ allow_with_label: "allow_with_label";
190
+ remove: "remove";
191
+ hide: "hide";
192
+ label: "label";
193
+ age_gate: "age_gate";
194
+ reduce_distribution: "reduce_distribution";
195
+ freeze_transaction: "freeze_transaction";
196
+ suspend_user: "suspend_user";
197
+ request_changes: "request_changes";
198
+ allow: "allow";
199
+ restore: "restore";
200
+ no_action: "no_action";
201
+ request_more_context: "request_more_context";
202
+ hold: "hold";
203
+ local_manual_review: "local_manual_review";
204
+ keep_restricted_temporarily: "keep_restricted_temporarily";
205
+ escalate: "escalate";
206
+ no_global_effect: "no_global_effect";
207
+ specialist_queue: "specialist_queue";
208
+ legal_queue: "legal_queue";
209
+ safety_queue: "safety_queue";
210
+ }>;
211
+ export type RecommendedAction = z.infer<typeof RecommendedActionSchema>;
212
+ /**
213
+ * The context that makes a classification not mean what it usually means —
214
+ * §9.2's and §9.4's "excepción", §6.2's `context`.
215
+ *
216
+ * §6.2's worked example is where this field comes from and what fixes its
217
+ * shape: the jury's finding is `sexual_content.nudity, severity = medium,
218
+ * context = artistic`, and it is that qualifier — not the code and not the
219
+ * severity — that turns the same classification into a violation under one
220
+ * application's policy and not under another's. It therefore belongs to layer
221
+ * one, beside the code: a reviewer describes what the material IS, and
222
+ * "artistic nudity" is a different description from "nudity".
223
+ *
224
+ * §9.4 makes it one of the six dimensions consensus is measured on, which is
225
+ * the reason it must be a CLOSED list. Two reviewers who both answer
226
+ * `no_violation` but for incompatible reasons — one because the material is
227
+ * documentary, one because they think the rule does not cover it at all — have
228
+ * not agreed about the material, and a free-text field could not tell the two
229
+ * apart. An open token would also be a channel for case content to reach a
230
+ * decision record, which §13.5 forbids.
231
+ *
232
+ * Only `artistic` is the plan's own word. The rest are the exception vocabulary
233
+ * every published moderation policy shares, and they are named here rather than
234
+ * left to a tenant because layer one is CrowdSource's (§6.1) — a tenant that
235
+ * could mint its own exception tokens would make findings incomparable across
236
+ * applications, which is exactly what §6.1 exists to prevent. Absence means no
237
+ * exception applies, which is the safe direction: a finding with no exception
238
+ * stands as classified.
239
+ */
240
+ export declare const FINDING_CONTEXTS: readonly ["artistic", "educational", "documentary", "newsworthy", "satire", "counter_speech", "medical", "consensual", "fictional"];
241
+ export declare const FindingContextSchema: z.ZodEnum<{
242
+ artistic: "artistic";
243
+ educational: "educational";
244
+ documentary: "documentary";
245
+ newsworthy: "newsworthy";
246
+ satire: "satire";
247
+ counter_speech: "counter_speech";
248
+ medical: "medical";
249
+ consensual: "consensual";
250
+ fictional: "fictional";
251
+ }>;
252
+ export type FindingContext = z.infer<typeof FindingContextSchema>;
253
+ /**
254
+ * A tenant's advance classification of how exposing the material is.
255
+ *
256
+ * The plan names exactly one value — `standard`, in Appendix A — and §7.5
257
+ * clearly implies at least one more (categories that never reach a community
258
+ * jury). Rather than invent the rest, this stays an open lowercase token: it is
259
+ * a HINT (§5.2: "never shown as a verdict"), the authoritative
260
+ * `sensitivity_class` is computed by triage server-side (§12.8), and access to
261
+ * sensitive material is gated on that computed class, never on what the tenant
262
+ * asserted. Closing this list is a product decision that has not been made.
263
+ */
264
+ export declare const SensitivityHintSchema: z.ZodString;
265
+ export type SensitivityHint = z.infer<typeof SensitivityHintSchema>;
266
+ //# sourceMappingURL=taxonomy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomy.d.ts","sourceRoot":"","sources":["../src/taxonomy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,qBAAqB;AACrB,eAAO,MAAM,iBAAiB,2JAYpB,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAA4B,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAwElE;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;EAY1B,CAAC;AAEZ,eAAO,MAAM,wBAAwB,qiCAY3B,CAAC;AAEX,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAmC,CAAC;AACnE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,WAAW,CAAC;AAEnD,oCAAoC;AACpC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CAGnE;AAED,mCAAmC;AACnC,eAAO,MAAM,UAAU,gDAAiD,CAAC;AACzE,eAAO,MAAM,cAAc;;;;;EAAqB,CAAC;AACjD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,qEAAsE,CAAC;AAClG,eAAO,MAAM,kBAAkB;;;;EAAyB,CAAC;AACzD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,kCAAkC,gDAAiD,CAAC;AACjG,eAAO,MAAM,oCAAoC;;;EAA6C,CAAC;AAC/F,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,6CAA8C,CAAC;AAChF,eAAO,MAAM,wBAAwB;;;;EAA+B,CAAC;AACrE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,mBAAmB,sXAuBtB,CAAC;AAEX,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;EAA8B,CAAC;AACnE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,gBAAgB,qIAUnB,CAAC;AACX,eAAO,MAAM,oBAAoB;;;;;;;;;;EAA2B,CAAC;AAC7D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,aAIwB,CAAC;AAC3D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,282 @@
1
+ "use strict";
2
+ /**
3
+ * The universal classification layer (§6.1, §6.3).
4
+ *
5
+ * §6.1 separates three layers and warns that mixing them makes the service
6
+ * unusable across applications with different rules. This module is the FIRST
7
+ * layer only — "what does the material contain or represent?" — and it belongs
8
+ * to CrowdSource. Whether that content violates anything is the second layer
9
+ * (`policies.ts`, per tenant) and whether it should move global trust is the
10
+ * third (`reputation-events.ts`). Nothing here may encode a single tenant's
11
+ * vocabulary.
12
+ *
13
+ * The code list is CLOSED. `other.policy_specific` and `other.unclassifiable`
14
+ * are the escape hatches the plan provides for material that does not fit; an
15
+ * open string would let a tenant mint private codes, which is precisely the
16
+ * cross-application comparability §6.1 exists to protect. Adding a code is an
17
+ * additive change that bumps `UNIVERSAL_TAXONOMY_VERSION`, and §6.4 requires
18
+ * every decision to record the version it was classified under, so historical
19
+ * decisions keep meaning what they meant.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.SensitivityHintSchema = exports.FindingContextSchema = exports.FINDING_CONTEXTS = exports.RecommendedActionSchema = exports.RECOMMENDED_ACTIONS = exports.FindingAttributionSchema = exports.FINDING_ATTRIBUTIONS = exports.ReputationEligibleFindingScopeSchema = exports.REPUTATION_ELIGIBLE_FINDING_SCOPES = exports.FindingScopeSchema = exports.FINDING_SCOPES = exports.SeveritySchema = exports.SEVERITIES = exports.UNIVERSAL_TAXONOMY_VERSION = exports.TaxonomyCodeSchema = exports.UNIVERSAL_TAXONOMY_CODES = exports.TAXONOMY_CODES_BY_FAMILY = exports.TaxonomyFamilySchema = exports.TAXONOMY_FAMILIES = void 0;
23
+ exports.taxonomyFamilyOf = taxonomyFamilyOf;
24
+ const zod_1 = require("zod");
25
+ /** §6.3 families. */
26
+ exports.TAXONOMY_FAMILIES = [
27
+ 'integrity',
28
+ 'harassment',
29
+ 'hate',
30
+ 'violence',
31
+ 'sexual_content',
32
+ 'child_safety',
33
+ 'self_harm',
34
+ 'privacy',
35
+ 'commerce',
36
+ 'platform_abuse',
37
+ 'other',
38
+ ];
39
+ exports.TaxonomyFamilySchema = zod_1.z.enum(exports.TAXONOMY_FAMILIES);
40
+ const INTEGRITY_CODES = [
41
+ 'integrity.spam',
42
+ 'integrity.scam',
43
+ 'integrity.fraud',
44
+ 'integrity.impersonation',
45
+ 'integrity.coordinated_manipulation',
46
+ ];
47
+ const HARASSMENT_CODES = [
48
+ 'harassment.insult',
49
+ 'harassment.targeted_abuse',
50
+ 'harassment.sexual_harassment',
51
+ 'harassment.doxxing',
52
+ 'harassment.credible_threat',
53
+ ];
54
+ const HATE_CODES = [
55
+ 'hate.dehumanization',
56
+ 'hate.slur',
57
+ 'hate.incitement',
58
+ 'hate.protected_targeting',
59
+ ];
60
+ const VIOLENCE_CODES = [
61
+ 'violence.graphic',
62
+ 'violence.threat',
63
+ 'violence.instruction',
64
+ 'violence.celebration',
65
+ ];
66
+ const SEXUAL_CONTENT_CODES = [
67
+ 'sexual_content.nudity',
68
+ 'sexual_content.explicit_activity',
69
+ 'sexual_content.non_consensual',
70
+ 'sexual_content.exploitation',
71
+ ];
72
+ const CHILD_SAFETY_CODES = [
73
+ 'child_safety.sexualization',
74
+ 'child_safety.grooming',
75
+ 'child_safety.exploitation',
76
+ ];
77
+ const SELF_HARM_CODES = [
78
+ 'self_harm.promotion',
79
+ 'self_harm.instruction',
80
+ 'self_harm.imminent_risk',
81
+ ];
82
+ const PRIVACY_CODES = [
83
+ 'privacy.personal_information',
84
+ 'privacy.intimate_media',
85
+ 'privacy.location_exposure',
86
+ ];
87
+ const COMMERCE_CODES = [
88
+ 'commerce.prohibited_item',
89
+ 'commerce.counterfeit',
90
+ 'commerce.misleading_listing',
91
+ 'commerce.unsafe_product',
92
+ ];
93
+ const PLATFORM_ABUSE_CODES = [
94
+ 'platform_abuse.ban_evasion',
95
+ 'platform_abuse.report_abuse',
96
+ 'platform_abuse.automation_abuse',
97
+ ];
98
+ const OTHER_CODES = ['other.policy_specific', 'other.unclassifiable'];
99
+ /**
100
+ * §6.3, grouped.
101
+ *
102
+ * §9.4 requires consensus on the "main taxonomic family", not only on the exact
103
+ * code, so the grouping is part of the contract rather than something the
104
+ * consensus engine re-derives from string prefixes.
105
+ */
106
+ exports.TAXONOMY_CODES_BY_FAMILY = Object.freeze({
107
+ integrity: INTEGRITY_CODES,
108
+ harassment: HARASSMENT_CODES,
109
+ hate: HATE_CODES,
110
+ violence: VIOLENCE_CODES,
111
+ sexual_content: SEXUAL_CONTENT_CODES,
112
+ child_safety: CHILD_SAFETY_CODES,
113
+ self_harm: SELF_HARM_CODES,
114
+ privacy: PRIVACY_CODES,
115
+ commerce: COMMERCE_CODES,
116
+ platform_abuse: PLATFORM_ABUSE_CODES,
117
+ other: OTHER_CODES,
118
+ });
119
+ exports.UNIVERSAL_TAXONOMY_CODES = [
120
+ ...INTEGRITY_CODES,
121
+ ...HARASSMENT_CODES,
122
+ ...HATE_CODES,
123
+ ...VIOLENCE_CODES,
124
+ ...SEXUAL_CONTENT_CODES,
125
+ ...CHILD_SAFETY_CODES,
126
+ ...SELF_HARM_CODES,
127
+ ...PRIVACY_CODES,
128
+ ...COMMERCE_CODES,
129
+ ...PLATFORM_ABUSE_CODES,
130
+ ...OTHER_CODES,
131
+ ];
132
+ exports.TaxonomyCodeSchema = zod_1.z.enum(exports.UNIVERSAL_TAXONOMY_CODES);
133
+ /**
134
+ * The version of the code list above.
135
+ *
136
+ * §6.4: every decision records the taxonomy version it was decided under, and a
137
+ * policy update never silently rewrites history. Keeping the constant in the
138
+ * same module as the codes is what makes that possible — the two cannot drift.
139
+ * The value is the one the plan uses in Appendix B and §11.6.
140
+ */
141
+ exports.UNIVERSAL_TAXONOMY_VERSION = '2026.1';
142
+ /** The family a code belongs to. */
143
+ function taxonomyFamilyOf(code) {
144
+ const [family] = code.split('.');
145
+ return exports.TaxonomyFamilySchema.parse(family);
146
+ }
147
+ /** §9.4 / §11.8 severity scale. */
148
+ exports.SEVERITIES = ['low', 'medium', 'high', 'critical'];
149
+ exports.SeveritySchema = zod_1.z.enum(exports.SEVERITIES);
150
+ /**
151
+ * How far a finding reaches.
152
+ *
153
+ * §11.6 and Appendix B use `oxy_network`; §11.7.5 additionally names
154
+ * `identity_integrity` as a scope that may produce an Oxy Trust effect. The
155
+ * plan never names the third value — the one that means "this matters to the
156
+ * application and stops there" — even though §6.5's entire argument is that
157
+ * most local restrictions must NOT become global sanctions. `application_local`
158
+ * is the contract's name for it and is the ONE token in this package invented
159
+ * rather than quoted. Modelling it as an absent field instead would make
160
+ * §11.7.5 a presence check, which fails open.
161
+ */
162
+ exports.FINDING_SCOPES = ['application_local', 'oxy_network', 'identity_integrity'];
163
+ exports.FindingScopeSchema = zod_1.z.enum(exports.FINDING_SCOPES);
164
+ /**
165
+ * Scopes that §11.7.5 allows to reach Oxy Trust.
166
+ *
167
+ * Exported as its own schema so `reputation-events.ts` states the rule in the
168
+ * type rather than re-checking it at runtime.
169
+ */
170
+ exports.REPUTATION_ELIGIBLE_FINDING_SCOPES = ['oxy_network', 'identity_integrity'];
171
+ exports.ReputationEligibleFindingScopeSchema = zod_1.z.enum(exports.REPUTATION_ELIGIBLE_FINDING_SCOPES);
172
+ /**
173
+ * Who a finding attributes conduct to.
174
+ *
175
+ * Appendix B and §11.6 use `author`. §11.11 and §11.12 describe confirmed
176
+ * report abuse and confirmed review abuse producing conduct effects of their
177
+ * own, which is where the other two values come from. There is deliberately no
178
+ * `unknown`: attribution exists to name a principal, and §11.7.4 will not let
179
+ * an effect land without a binding proof for that principal anyway.
180
+ */
181
+ exports.FINDING_ATTRIBUTIONS = ['author', 'reporter', 'reviewer'];
182
+ exports.FindingAttributionSchema = zod_1.z.enum(exports.FINDING_ATTRIBUTIONS);
183
+ /**
184
+ * What CrowdSource may recommend an application do.
185
+ *
186
+ * The plan writes action tokens in two places. §6.2, §9.3, §10.7 and Appendix B
187
+ * recommend `remove_or_restrict` and `allow_with_label`; §7.6 tabulates, per
188
+ * decision outcome, the actions an application may take in response. They are
189
+ * the same vocabulary seen from the two ends of one exchange, so the contract
190
+ * carries the union as one closed list — otherwise a recommendation and the
191
+ * enforcement that answers it would not be comparable, and §7.6's requirement
192
+ * that an application "record what it did and why" would compare apples to
193
+ * pears.
194
+ *
195
+ * §7.6's outcome→action table is NOT reproduced as a constraint. It bounds what
196
+ * an application may do in response to an outcome, not what a jury may
197
+ * recommend — Appendix B recommends `remove_or_restrict`, which does not appear
198
+ * in §7.6's `violation` row at all. Binding the two would reject the plan's own
199
+ * reference decision.
200
+ */
201
+ exports.RECOMMENDED_ACTIONS = [
202
+ 'remove_or_restrict',
203
+ 'allow_with_label',
204
+ 'remove',
205
+ 'hide',
206
+ 'label',
207
+ 'age_gate',
208
+ 'reduce_distribution',
209
+ 'freeze_transaction',
210
+ 'suspend_user',
211
+ 'request_changes',
212
+ 'allow',
213
+ 'restore',
214
+ 'no_action',
215
+ 'request_more_context',
216
+ 'hold',
217
+ 'local_manual_review',
218
+ 'keep_restricted_temporarily',
219
+ 'escalate',
220
+ 'no_global_effect',
221
+ 'specialist_queue',
222
+ 'legal_queue',
223
+ 'safety_queue',
224
+ ];
225
+ exports.RecommendedActionSchema = zod_1.z.enum(exports.RECOMMENDED_ACTIONS);
226
+ /**
227
+ * The context that makes a classification not mean what it usually means —
228
+ * §9.2's and §9.4's "excepción", §6.2's `context`.
229
+ *
230
+ * §6.2's worked example is where this field comes from and what fixes its
231
+ * shape: the jury's finding is `sexual_content.nudity, severity = medium,
232
+ * context = artistic`, and it is that qualifier — not the code and not the
233
+ * severity — that turns the same classification into a violation under one
234
+ * application's policy and not under another's. It therefore belongs to layer
235
+ * one, beside the code: a reviewer describes what the material IS, and
236
+ * "artistic nudity" is a different description from "nudity".
237
+ *
238
+ * §9.4 makes it one of the six dimensions consensus is measured on, which is
239
+ * the reason it must be a CLOSED list. Two reviewers who both answer
240
+ * `no_violation` but for incompatible reasons — one because the material is
241
+ * documentary, one because they think the rule does not cover it at all — have
242
+ * not agreed about the material, and a free-text field could not tell the two
243
+ * apart. An open token would also be a channel for case content to reach a
244
+ * decision record, which §13.5 forbids.
245
+ *
246
+ * Only `artistic` is the plan's own word. The rest are the exception vocabulary
247
+ * every published moderation policy shares, and they are named here rather than
248
+ * left to a tenant because layer one is CrowdSource's (§6.1) — a tenant that
249
+ * could mint its own exception tokens would make findings incomparable across
250
+ * applications, which is exactly what §6.1 exists to prevent. Absence means no
251
+ * exception applies, which is the safe direction: a finding with no exception
252
+ * stands as classified.
253
+ */
254
+ exports.FINDING_CONTEXTS = [
255
+ 'artistic',
256
+ 'educational',
257
+ 'documentary',
258
+ 'newsworthy',
259
+ 'satire',
260
+ 'counter_speech',
261
+ 'medical',
262
+ 'consensual',
263
+ 'fictional',
264
+ ];
265
+ exports.FindingContextSchema = zod_1.z.enum(exports.FINDING_CONTEXTS);
266
+ /**
267
+ * A tenant's advance classification of how exposing the material is.
268
+ *
269
+ * The plan names exactly one value — `standard`, in Appendix A — and §7.5
270
+ * clearly implies at least one more (categories that never reach a community
271
+ * jury). Rather than invent the rest, this stays an open lowercase token: it is
272
+ * a HINT (§5.2: "never shown as a verdict"), the authoritative
273
+ * `sensitivity_class` is computed by triage server-side (§12.8), and access to
274
+ * sensitive material is gated on that computed class, never on what the tenant
275
+ * asserted. Closing this list is a product decision that has not been made.
276
+ */
277
+ exports.SensitivityHintSchema = zod_1.z
278
+ .string()
279
+ .min(1)
280
+ .max(40)
281
+ .regex(/^[a-z][a-z0-9_]*$/, 'must be a lowercase token');
282
+ //# sourceMappingURL=taxonomy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomy.js","sourceRoot":"","sources":["../src/taxonomy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AA6IH,4CAGC;AA9ID,6BAAwB;AAExB,qBAAqB;AACR,QAAA,iBAAiB,GAAG;IAC/B,WAAW;IACX,YAAY;IACZ,MAAM;IACN,UAAU;IACV,gBAAgB;IAChB,cAAc;IACd,WAAW;IACX,SAAS;IACT,UAAU;IACV,gBAAgB;IAChB,OAAO;CACC,CAAC;AAEE,QAAA,oBAAoB,GAAG,OAAC,CAAC,IAAI,CAAC,yBAAiB,CAAC,CAAC;AAG9D,MAAM,eAAe,GAAG;IACtB,gBAAgB;IAChB,gBAAgB;IAChB,iBAAiB;IACjB,yBAAyB;IACzB,oCAAoC;CAC5B,CAAC;AAEX,MAAM,gBAAgB,GAAG;IACvB,mBAAmB;IACnB,2BAA2B;IAC3B,8BAA8B;IAC9B,oBAAoB;IACpB,4BAA4B;CACpB,CAAC;AAEX,MAAM,UAAU,GAAG;IACjB,qBAAqB;IACrB,WAAW;IACX,iBAAiB;IACjB,0BAA0B;CAClB,CAAC;AAEX,MAAM,cAAc,GAAG;IACrB,kBAAkB;IAClB,iBAAiB;IACjB,sBAAsB;IACtB,sBAAsB;CACd,CAAC;AAEX,MAAM,oBAAoB,GAAG;IAC3B,uBAAuB;IACvB,kCAAkC;IAClC,+BAA+B;IAC/B,6BAA6B;CACrB,CAAC;AAEX,MAAM,kBAAkB,GAAG;IACzB,4BAA4B;IAC5B,uBAAuB;IACvB,2BAA2B;CACnB,CAAC;AAEX,MAAM,eAAe,GAAG;IACtB,qBAAqB;IACrB,uBAAuB;IACvB,yBAAyB;CACjB,CAAC;AAEX,MAAM,aAAa,GAAG;IACpB,8BAA8B;IAC9B,wBAAwB;IACxB,2BAA2B;CACnB,CAAC;AAEX,MAAM,cAAc,GAAG;IACrB,0BAA0B;IAC1B,sBAAsB;IACtB,6BAA6B;IAC7B,yBAAyB;CACjB,CAAC;AAEX,MAAM,oBAAoB,GAAG;IAC3B,4BAA4B;IAC5B,6BAA6B;IAC7B,iCAAiC;CACzB,CAAC;AAEX,MAAM,WAAW,GAAG,CAAC,uBAAuB,EAAE,sBAAsB,CAAU,CAAC;AAE/E;;;;;;GAMG;AACU,QAAA,wBAAwB,GAAG,MAAM,CAAC,MAAM,CAAC;IACpD,SAAS,EAAE,eAAe;IAC1B,UAAU,EAAE,gBAAgB;IAC5B,IAAI,EAAE,UAAU;IAChB,QAAQ,EAAE,cAAc;IACxB,cAAc,EAAE,oBAAoB;IACpC,YAAY,EAAE,kBAAkB;IAChC,SAAS,EAAE,eAAe;IAC1B,OAAO,EAAE,aAAa;IACtB,QAAQ,EAAE,cAAc;IACxB,cAAc,EAAE,oBAAoB;IACpC,KAAK,EAAE,WAAW;CACV,CAAC,CAAC;AAEC,QAAA,wBAAwB,GAAG;IACtC,GAAG,eAAe;IAClB,GAAG,gBAAgB;IACnB,GAAG,UAAU;IACb,GAAG,cAAc;IACjB,GAAG,oBAAoB;IACvB,GAAG,kBAAkB;IACrB,GAAG,eAAe;IAClB,GAAG,aAAa;IAChB,GAAG,cAAc;IACjB,GAAG,oBAAoB;IACvB,GAAG,WAAW;CACN,CAAC;AAEE,QAAA,kBAAkB,GAAG,OAAC,CAAC,IAAI,CAAC,gCAAwB,CAAC,CAAC;AAGnE;;;;;;;GAOG;AACU,QAAA,0BAA0B,GAAG,QAAQ,CAAC;AAEnD,oCAAoC;AACpC,SAAgB,gBAAgB,CAAC,IAAkB;IACjD,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,4BAAoB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,mCAAmC;AACtB,QAAA,UAAU,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC;AAC5D,QAAA,cAAc,GAAG,OAAC,CAAC,IAAI,CAAC,kBAAU,CAAC,CAAC;AAGjD;;;;;;;;;;;GAWG;AACU,QAAA,cAAc,GAAG,CAAC,mBAAmB,EAAE,aAAa,EAAE,oBAAoB,CAAU,CAAC;AACrF,QAAA,kBAAkB,GAAG,OAAC,CAAC,IAAI,CAAC,sBAAc,CAAC,CAAC;AAGzD;;;;;GAKG;AACU,QAAA,kCAAkC,GAAG,CAAC,aAAa,EAAE,oBAAoB,CAAU,CAAC;AACpF,QAAA,oCAAoC,GAAG,OAAC,CAAC,IAAI,CAAC,0CAAkC,CAAC,CAAC;AAG/F;;;;;;;;GAQG;AACU,QAAA,oBAAoB,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;AACnE,QAAA,wBAAwB,GAAG,OAAC,CAAC,IAAI,CAAC,4BAAoB,CAAC,CAAC;AAGrE;;;;;;;;;;;;;;;;;GAiBG;AACU,QAAA,mBAAmB,GAAG;IACjC,oBAAoB;IACpB,kBAAkB;IAClB,QAAQ;IACR,MAAM;IACN,OAAO;IACP,UAAU;IACV,qBAAqB;IACrB,oBAAoB;IACpB,cAAc;IACd,iBAAiB;IACjB,OAAO;IACP,SAAS;IACT,WAAW;IACX,sBAAsB;IACtB,MAAM;IACN,qBAAqB;IACrB,6BAA6B;IAC7B,UAAU;IACV,kBAAkB;IAClB,kBAAkB;IAClB,aAAa;IACb,cAAc;CACN,CAAC;AAEE,QAAA,uBAAuB,GAAG,OAAC,CAAC,IAAI,CAAC,2BAAmB,CAAC,CAAC;AAGnE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACU,QAAA,gBAAgB,GAAG;IAC9B,UAAU;IACV,aAAa;IACb,aAAa;IACb,YAAY;IACZ,QAAQ;IACR,gBAAgB;IAChB,SAAS;IACT,YAAY;IACZ,WAAW;CACH,CAAC;AACE,QAAA,oBAAoB,GAAG,OAAC,CAAC,IAAI,CAAC,wBAAgB,CAAC,CAAC;AAG7D;;;;;;;;;;GAUG;AACU,QAAA,qBAAqB,GAAG,OAAC;KACnC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,EAAE,CAAC;KACP,KAAK,CAAC,mBAAmB,EAAE,2BAA2B,CAAC,CAAC"}