@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.
- package/README.md +129 -0
- package/dist/case-envelope.d.ts +1130 -0
- package/dist/case-envelope.d.ts.map +1 -0
- package/dist/case-envelope.js +383 -0
- package/dist/case-envelope.js.map +1 -0
- package/dist/decisions.d.ts +353 -0
- package/dist/decisions.d.ts.map +1 -0
- package/dist/decisions.js +198 -0
- package/dist/decisions.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/json-schema.d.ts +43 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +83 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/policies.d.ts +286 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +178 -0
- package/dist/policies.js.map +1 -0
- package/dist/primitives.d.ts +185 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +231 -0
- package/dist/primitives.js.map +1 -0
- package/dist/reputation-events.d.ts +349 -0
- package/dist/reputation-events.d.ts.map +1 -0
- package/dist/reputation-events.js +128 -0
- package/dist/reputation-events.js.map +1 -0
- package/dist/resources.d.ts +484 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +436 -0
- package/dist/resources.js.map +1 -0
- package/dist/reviews.d.ts +276 -0
- package/dist/reviews.d.ts.map +1 -0
- package/dist/reviews.js +144 -0
- package/dist/reviews.js.map +1 -0
- package/dist/taxonomy.d.ts +266 -0
- package/dist/taxonomy.d.ts.map +1 -0
- package/dist/taxonomy.js +282 -0
- package/dist/taxonomy.js.map +1 -0
- package/dist/webhooks.d.ts +604 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +192 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +56 -0
- package/src/case-envelope.ts +433 -0
- package/src/decisions.ts +216 -0
- package/src/index.ts +45 -0
- package/src/json-schema.ts +89 -0
- package/src/policies.ts +203 -0
- package/src/primitives.ts +283 -0
- package/src/reputation-events.ts +144 -0
- package/src/resources.ts +489 -0
- package/src/reviews.ts +159 -0
- package/src/taxonomy.ts +313 -0
- package/src/webhooks.ts +215 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one reviewer submits (§9.2, §9.3) and how they step away (§4.1).
|
|
3
|
+
*
|
|
4
|
+
* §9.2 splits the form in two — describe the material, then evaluate it against
|
|
5
|
+
* a rule — to reduce anchoring on the reporter's category and to let the same
|
|
6
|
+
* description be reused under different policies. §9.3 then gives one flat
|
|
7
|
+
* result object. Both are true at once: a `ReviewFinding` carries the step-one
|
|
8
|
+
* fields (`code`, `resourceIds`, `severity`, `confidence`) and the step-two
|
|
9
|
+
* fields (`policyRuleIds`), and the enclosing submission carries the step-two
|
|
10
|
+
* verdict (`outcome`, `recommendedActions`). The split is a property of the
|
|
11
|
+
* interface, not of the payload, so it is documented here rather than nested.
|
|
12
|
+
*
|
|
13
|
+
* The submission is `.strict()`, and that is a safety decision, not tidiness.
|
|
14
|
+
* A review belongs to an assignment the server issued; the assignment id comes
|
|
15
|
+
* from the route, the case and the reviewer come from the assignment. If this
|
|
16
|
+
* object tolerated a `caseId`, an `assignmentId` or a `reviewerId`, the day
|
|
17
|
+
* somebody read one of them would be the day a reviewer could vote on a case
|
|
18
|
+
* they were never drawn for — against "nobody chooses the case they review".
|
|
19
|
+
* Strict makes that field impossible rather than merely unused.
|
|
20
|
+
*/
|
|
21
|
+
import { z } from 'zod';
|
|
22
|
+
/**
|
|
23
|
+
* What a single reviewer can conclude.
|
|
24
|
+
*
|
|
25
|
+
* Narrower than §9.6's decision outcomes on purpose. `inconclusive` is what the
|
|
26
|
+
* consensus engine reports when a panel does not agree — a single reviewer
|
|
27
|
+
* cannot fail to agree with themselves, and "the absence of consensus is
|
|
28
|
+
* neither guilt nor innocence" only holds if `inconclusive` is produced by the
|
|
29
|
+
* engine and never voted for. `duplicate`, `escalated` and `superseded` are
|
|
30
|
+
* likewise case-level states, not opinions about material. The plan never
|
|
31
|
+
* enumerates review outcomes; this is that gap resolved toward the invariant.
|
|
32
|
+
*/
|
|
33
|
+
export declare const REVIEW_OUTCOMES: readonly ["violation", "no_violation", "insufficient_context", "content_unavailable"];
|
|
34
|
+
export declare const ReviewOutcomeSchema: z.ZodEnum<{
|
|
35
|
+
violation: "violation";
|
|
36
|
+
no_violation: "no_violation";
|
|
37
|
+
insufficient_context: "insufficient_context";
|
|
38
|
+
content_unavailable: "content_unavailable";
|
|
39
|
+
}>;
|
|
40
|
+
export type ReviewOutcome = z.infer<typeof ReviewOutcomeSchema>;
|
|
41
|
+
/** §9.5 feeds this into `contextFactor`: 1.0 if sufficient, 0.5 otherwise. */
|
|
42
|
+
export declare const CONTEXT_SUFFICIENCIES: readonly ["sufficient", "insufficient"];
|
|
43
|
+
export declare const ContextSufficiencySchema: z.ZodEnum<{
|
|
44
|
+
sufficient: "sufficient";
|
|
45
|
+
insufficient: "insufficient";
|
|
46
|
+
}>;
|
|
47
|
+
export type ContextSufficiency = z.infer<typeof ContextSufficiencySchema>;
|
|
48
|
+
/**
|
|
49
|
+
* One structured finding from one reviewer (§9.3).
|
|
50
|
+
*
|
|
51
|
+
* `resourceIds` is required and non-empty: §9.4 makes the affected resource one
|
|
52
|
+
* of the dimensions consensus is measured on, so a finding that does not say
|
|
53
|
+
* what it is about cannot be agreed with or disagreed with.
|
|
54
|
+
*
|
|
55
|
+
* `policyRuleIds` is optional: step one of the form can complete without step
|
|
56
|
+
* two — a reviewer may classify material accurately and find no rule that
|
|
57
|
+
* covers it, which is exactly the `no_violation`-with-findings case §6.2
|
|
58
|
+
* describes.
|
|
59
|
+
*
|
|
60
|
+
* `context` is §9.2's and §9.4's "excepción", written as §6.2 writes it: beside
|
|
61
|
+
* the code and the severity, because "artistic nudity" is a different
|
|
62
|
+
* description of the material from "nudity" rather than a different verdict
|
|
63
|
+
* about it. Optional, and absence means no exception applies.
|
|
64
|
+
*
|
|
65
|
+
* `confidence` communicates quality and triggers escalation (§9.5). It never
|
|
66
|
+
* weights the vote.
|
|
67
|
+
*/
|
|
68
|
+
export declare const ReviewFindingSchema: z.ZodObject<{
|
|
69
|
+
code: z.ZodEnum<{
|
|
70
|
+
"integrity.spam": "integrity.spam";
|
|
71
|
+
"integrity.scam": "integrity.scam";
|
|
72
|
+
"integrity.fraud": "integrity.fraud";
|
|
73
|
+
"integrity.impersonation": "integrity.impersonation";
|
|
74
|
+
"integrity.coordinated_manipulation": "integrity.coordinated_manipulation";
|
|
75
|
+
"harassment.insult": "harassment.insult";
|
|
76
|
+
"harassment.targeted_abuse": "harassment.targeted_abuse";
|
|
77
|
+
"harassment.sexual_harassment": "harassment.sexual_harassment";
|
|
78
|
+
"harassment.doxxing": "harassment.doxxing";
|
|
79
|
+
"harassment.credible_threat": "harassment.credible_threat";
|
|
80
|
+
"hate.dehumanization": "hate.dehumanization";
|
|
81
|
+
"hate.slur": "hate.slur";
|
|
82
|
+
"hate.incitement": "hate.incitement";
|
|
83
|
+
"hate.protected_targeting": "hate.protected_targeting";
|
|
84
|
+
"violence.graphic": "violence.graphic";
|
|
85
|
+
"violence.threat": "violence.threat";
|
|
86
|
+
"violence.instruction": "violence.instruction";
|
|
87
|
+
"violence.celebration": "violence.celebration";
|
|
88
|
+
"sexual_content.nudity": "sexual_content.nudity";
|
|
89
|
+
"sexual_content.explicit_activity": "sexual_content.explicit_activity";
|
|
90
|
+
"sexual_content.non_consensual": "sexual_content.non_consensual";
|
|
91
|
+
"sexual_content.exploitation": "sexual_content.exploitation";
|
|
92
|
+
"child_safety.sexualization": "child_safety.sexualization";
|
|
93
|
+
"child_safety.grooming": "child_safety.grooming";
|
|
94
|
+
"child_safety.exploitation": "child_safety.exploitation";
|
|
95
|
+
"self_harm.promotion": "self_harm.promotion";
|
|
96
|
+
"self_harm.instruction": "self_harm.instruction";
|
|
97
|
+
"self_harm.imminent_risk": "self_harm.imminent_risk";
|
|
98
|
+
"privacy.personal_information": "privacy.personal_information";
|
|
99
|
+
"privacy.intimate_media": "privacy.intimate_media";
|
|
100
|
+
"privacy.location_exposure": "privacy.location_exposure";
|
|
101
|
+
"commerce.prohibited_item": "commerce.prohibited_item";
|
|
102
|
+
"commerce.counterfeit": "commerce.counterfeit";
|
|
103
|
+
"commerce.misleading_listing": "commerce.misleading_listing";
|
|
104
|
+
"commerce.unsafe_product": "commerce.unsafe_product";
|
|
105
|
+
"platform_abuse.ban_evasion": "platform_abuse.ban_evasion";
|
|
106
|
+
"platform_abuse.report_abuse": "platform_abuse.report_abuse";
|
|
107
|
+
"platform_abuse.automation_abuse": "platform_abuse.automation_abuse";
|
|
108
|
+
"other.policy_specific": "other.policy_specific";
|
|
109
|
+
"other.unclassifiable": "other.unclassifiable";
|
|
110
|
+
}>;
|
|
111
|
+
resourceIds: z.ZodArray<z.ZodString>;
|
|
112
|
+
severity: z.ZodEnum<{
|
|
113
|
+
low: "low";
|
|
114
|
+
medium: "medium";
|
|
115
|
+
high: "high";
|
|
116
|
+
critical: "critical";
|
|
117
|
+
}>;
|
|
118
|
+
context: z.ZodOptional<z.ZodEnum<{
|
|
119
|
+
artistic: "artistic";
|
|
120
|
+
educational: "educational";
|
|
121
|
+
documentary: "documentary";
|
|
122
|
+
newsworthy: "newsworthy";
|
|
123
|
+
satire: "satire";
|
|
124
|
+
counter_speech: "counter_speech";
|
|
125
|
+
medical: "medical";
|
|
126
|
+
consensual: "consensual";
|
|
127
|
+
fictional: "fictional";
|
|
128
|
+
}>>;
|
|
129
|
+
confidence: z.ZodNumber;
|
|
130
|
+
policyRuleIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
131
|
+
}, z.core.$strict>;
|
|
132
|
+
export type ReviewFinding = z.infer<typeof ReviewFindingSchema>;
|
|
133
|
+
/**
|
|
134
|
+
* The body of `POST /v1/reviewer/assignments/{id}/reviews` — §9.3's "result of
|
|
135
|
+
* a review".
|
|
136
|
+
*
|
|
137
|
+
* `recommendedActions` is a list of action tokens here, where a decision's
|
|
138
|
+
* `recommendedActions` are objects that name their target resources. That
|
|
139
|
+
* difference is in the plan (§9.3 versus Appendix B) and is kept: a reviewer
|
|
140
|
+
* recommends a course of action, and the consensus process is what binds an
|
|
141
|
+
* agreed recommendation to the specific resources it applies to.
|
|
142
|
+
*/
|
|
143
|
+
export declare const ReviewSubmissionSchema: z.ZodObject<{
|
|
144
|
+
outcome: z.ZodEnum<{
|
|
145
|
+
violation: "violation";
|
|
146
|
+
no_violation: "no_violation";
|
|
147
|
+
insufficient_context: "insufficient_context";
|
|
148
|
+
content_unavailable: "content_unavailable";
|
|
149
|
+
}>;
|
|
150
|
+
contextSufficiency: z.ZodEnum<{
|
|
151
|
+
sufficient: "sufficient";
|
|
152
|
+
insufficient: "insufficient";
|
|
153
|
+
}>;
|
|
154
|
+
findings: z.ZodArray<z.ZodObject<{
|
|
155
|
+
code: z.ZodEnum<{
|
|
156
|
+
"integrity.spam": "integrity.spam";
|
|
157
|
+
"integrity.scam": "integrity.scam";
|
|
158
|
+
"integrity.fraud": "integrity.fraud";
|
|
159
|
+
"integrity.impersonation": "integrity.impersonation";
|
|
160
|
+
"integrity.coordinated_manipulation": "integrity.coordinated_manipulation";
|
|
161
|
+
"harassment.insult": "harassment.insult";
|
|
162
|
+
"harassment.targeted_abuse": "harassment.targeted_abuse";
|
|
163
|
+
"harassment.sexual_harassment": "harassment.sexual_harassment";
|
|
164
|
+
"harassment.doxxing": "harassment.doxxing";
|
|
165
|
+
"harassment.credible_threat": "harassment.credible_threat";
|
|
166
|
+
"hate.dehumanization": "hate.dehumanization";
|
|
167
|
+
"hate.slur": "hate.slur";
|
|
168
|
+
"hate.incitement": "hate.incitement";
|
|
169
|
+
"hate.protected_targeting": "hate.protected_targeting";
|
|
170
|
+
"violence.graphic": "violence.graphic";
|
|
171
|
+
"violence.threat": "violence.threat";
|
|
172
|
+
"violence.instruction": "violence.instruction";
|
|
173
|
+
"violence.celebration": "violence.celebration";
|
|
174
|
+
"sexual_content.nudity": "sexual_content.nudity";
|
|
175
|
+
"sexual_content.explicit_activity": "sexual_content.explicit_activity";
|
|
176
|
+
"sexual_content.non_consensual": "sexual_content.non_consensual";
|
|
177
|
+
"sexual_content.exploitation": "sexual_content.exploitation";
|
|
178
|
+
"child_safety.sexualization": "child_safety.sexualization";
|
|
179
|
+
"child_safety.grooming": "child_safety.grooming";
|
|
180
|
+
"child_safety.exploitation": "child_safety.exploitation";
|
|
181
|
+
"self_harm.promotion": "self_harm.promotion";
|
|
182
|
+
"self_harm.instruction": "self_harm.instruction";
|
|
183
|
+
"self_harm.imminent_risk": "self_harm.imminent_risk";
|
|
184
|
+
"privacy.personal_information": "privacy.personal_information";
|
|
185
|
+
"privacy.intimate_media": "privacy.intimate_media";
|
|
186
|
+
"privacy.location_exposure": "privacy.location_exposure";
|
|
187
|
+
"commerce.prohibited_item": "commerce.prohibited_item";
|
|
188
|
+
"commerce.counterfeit": "commerce.counterfeit";
|
|
189
|
+
"commerce.misleading_listing": "commerce.misleading_listing";
|
|
190
|
+
"commerce.unsafe_product": "commerce.unsafe_product";
|
|
191
|
+
"platform_abuse.ban_evasion": "platform_abuse.ban_evasion";
|
|
192
|
+
"platform_abuse.report_abuse": "platform_abuse.report_abuse";
|
|
193
|
+
"platform_abuse.automation_abuse": "platform_abuse.automation_abuse";
|
|
194
|
+
"other.policy_specific": "other.policy_specific";
|
|
195
|
+
"other.unclassifiable": "other.unclassifiable";
|
|
196
|
+
}>;
|
|
197
|
+
resourceIds: z.ZodArray<z.ZodString>;
|
|
198
|
+
severity: z.ZodEnum<{
|
|
199
|
+
low: "low";
|
|
200
|
+
medium: "medium";
|
|
201
|
+
high: "high";
|
|
202
|
+
critical: "critical";
|
|
203
|
+
}>;
|
|
204
|
+
context: z.ZodOptional<z.ZodEnum<{
|
|
205
|
+
artistic: "artistic";
|
|
206
|
+
educational: "educational";
|
|
207
|
+
documentary: "documentary";
|
|
208
|
+
newsworthy: "newsworthy";
|
|
209
|
+
satire: "satire";
|
|
210
|
+
counter_speech: "counter_speech";
|
|
211
|
+
medical: "medical";
|
|
212
|
+
consensual: "consensual";
|
|
213
|
+
fictional: "fictional";
|
|
214
|
+
}>>;
|
|
215
|
+
confidence: z.ZodNumber;
|
|
216
|
+
policyRuleIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
217
|
+
}, z.core.$strict>>;
|
|
218
|
+
recommendedActions: z.ZodArray<z.ZodEnum<{
|
|
219
|
+
remove_or_restrict: "remove_or_restrict";
|
|
220
|
+
allow_with_label: "allow_with_label";
|
|
221
|
+
remove: "remove";
|
|
222
|
+
hide: "hide";
|
|
223
|
+
label: "label";
|
|
224
|
+
age_gate: "age_gate";
|
|
225
|
+
reduce_distribution: "reduce_distribution";
|
|
226
|
+
freeze_transaction: "freeze_transaction";
|
|
227
|
+
suspend_user: "suspend_user";
|
|
228
|
+
request_changes: "request_changes";
|
|
229
|
+
allow: "allow";
|
|
230
|
+
restore: "restore";
|
|
231
|
+
no_action: "no_action";
|
|
232
|
+
request_more_context: "request_more_context";
|
|
233
|
+
hold: "hold";
|
|
234
|
+
local_manual_review: "local_manual_review";
|
|
235
|
+
keep_restricted_temporarily: "keep_restricted_temporarily";
|
|
236
|
+
escalate: "escalate";
|
|
237
|
+
no_global_effect: "no_global_effect";
|
|
238
|
+
specialist_queue: "specialist_queue";
|
|
239
|
+
legal_queue: "legal_queue";
|
|
240
|
+
safety_queue: "safety_queue";
|
|
241
|
+
}>>;
|
|
242
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
243
|
+
}, z.core.$strict>;
|
|
244
|
+
export type ReviewSubmission = z.infer<typeof ReviewSubmissionSchema>;
|
|
245
|
+
/**
|
|
246
|
+
* §4.1: a reviewer may declare a conflict, a language they do not have,
|
|
247
|
+
* material too sensitive for them, or context they cannot obtain — "without
|
|
248
|
+
* penalty". These four are the plan's own list, made structured as §10.3 asks.
|
|
249
|
+
*/
|
|
250
|
+
export declare const RECUSAL_REASONS: readonly ["conflict_of_interest", "language", "too_sensitive", "insufficient_context"];
|
|
251
|
+
export declare const RecusalReasonSchema: z.ZodEnum<{
|
|
252
|
+
language: "language";
|
|
253
|
+
insufficient_context: "insufficient_context";
|
|
254
|
+
conflict_of_interest: "conflict_of_interest";
|
|
255
|
+
too_sensitive: "too_sensitive";
|
|
256
|
+
}>;
|
|
257
|
+
export type RecusalReason = z.infer<typeof RecusalReasonSchema>;
|
|
258
|
+
/**
|
|
259
|
+
* The body of `POST /v1/reviewer/assignments/{id}/recuse`.
|
|
260
|
+
*
|
|
261
|
+
* Strict for the same reason as the submission, and with no free-text field
|
|
262
|
+
* beyond a short optional note: a recusal is routing information, and the more
|
|
263
|
+
* it can say about the case, the more it becomes a channel for case content to
|
|
264
|
+
* leak into operational data.
|
|
265
|
+
*/
|
|
266
|
+
export declare const RecusalSubmissionSchema: z.ZodObject<{
|
|
267
|
+
reason: z.ZodEnum<{
|
|
268
|
+
language: "language";
|
|
269
|
+
insufficient_context: "insufficient_context";
|
|
270
|
+
conflict_of_interest: "conflict_of_interest";
|
|
271
|
+
too_sensitive: "too_sensitive";
|
|
272
|
+
}>;
|
|
273
|
+
note: z.ZodOptional<z.ZodString>;
|
|
274
|
+
}, z.core.$strict>;
|
|
275
|
+
export type RecusalSubmission = z.infer<typeof RecusalSubmissionSchema>;
|
|
276
|
+
//# sourceMappingURL=reviews.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviews.d.ts","sourceRoot":"","sources":["../src/reviews.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,uFAKlB,CAAC;AACX,eAAO,MAAM,mBAAmB;;;;;EAA0B,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,yCAA0C,CAAC;AAC7E,eAAO,MAAM,wBAAwB;;;EAAgC,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAO9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA+B/B,CAAC;AACL,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,eAAe,wFAKlB,CAAC;AACX,eAAO,MAAM,mBAAmB;;;;;EAA0B,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;kBAGlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
|
package/dist/reviews.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* What one reviewer submits (§9.2, §9.3) and how they step away (§4.1).
|
|
4
|
+
*
|
|
5
|
+
* §9.2 splits the form in two — describe the material, then evaluate it against
|
|
6
|
+
* a rule — to reduce anchoring on the reporter's category and to let the same
|
|
7
|
+
* description be reused under different policies. §9.3 then gives one flat
|
|
8
|
+
* result object. Both are true at once: a `ReviewFinding` carries the step-one
|
|
9
|
+
* fields (`code`, `resourceIds`, `severity`, `confidence`) and the step-two
|
|
10
|
+
* fields (`policyRuleIds`), and the enclosing submission carries the step-two
|
|
11
|
+
* verdict (`outcome`, `recommendedActions`). The split is a property of the
|
|
12
|
+
* interface, not of the payload, so it is documented here rather than nested.
|
|
13
|
+
*
|
|
14
|
+
* The submission is `.strict()`, and that is a safety decision, not tidiness.
|
|
15
|
+
* A review belongs to an assignment the server issued; the assignment id comes
|
|
16
|
+
* from the route, the case and the reviewer come from the assignment. If this
|
|
17
|
+
* object tolerated a `caseId`, an `assignmentId` or a `reviewerId`, the day
|
|
18
|
+
* somebody read one of them would be the day a reviewer could vote on a case
|
|
19
|
+
* they were never drawn for — against "nobody chooses the case they review".
|
|
20
|
+
* Strict makes that field impossible rather than merely unused.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.RecusalSubmissionSchema = exports.RecusalReasonSchema = exports.RECUSAL_REASONS = exports.ReviewSubmissionSchema = exports.ReviewFindingSchema = exports.ContextSufficiencySchema = exports.CONTEXT_SUFFICIENCIES = exports.ReviewOutcomeSchema = exports.REVIEW_OUTCOMES = void 0;
|
|
24
|
+
const zod_1 = require("zod");
|
|
25
|
+
const primitives_1 = require("./primitives");
|
|
26
|
+
const policies_1 = require("./policies");
|
|
27
|
+
const resources_1 = require("./resources");
|
|
28
|
+
const taxonomy_1 = require("./taxonomy");
|
|
29
|
+
/**
|
|
30
|
+
* What a single reviewer can conclude.
|
|
31
|
+
*
|
|
32
|
+
* Narrower than §9.6's decision outcomes on purpose. `inconclusive` is what the
|
|
33
|
+
* consensus engine reports when a panel does not agree — a single reviewer
|
|
34
|
+
* cannot fail to agree with themselves, and "the absence of consensus is
|
|
35
|
+
* neither guilt nor innocence" only holds if `inconclusive` is produced by the
|
|
36
|
+
* engine and never voted for. `duplicate`, `escalated` and `superseded` are
|
|
37
|
+
* likewise case-level states, not opinions about material. The plan never
|
|
38
|
+
* enumerates review outcomes; this is that gap resolved toward the invariant.
|
|
39
|
+
*/
|
|
40
|
+
exports.REVIEW_OUTCOMES = [
|
|
41
|
+
'violation',
|
|
42
|
+
'no_violation',
|
|
43
|
+
'insufficient_context',
|
|
44
|
+
'content_unavailable',
|
|
45
|
+
];
|
|
46
|
+
exports.ReviewOutcomeSchema = zod_1.z.enum(exports.REVIEW_OUTCOMES);
|
|
47
|
+
/** §9.5 feeds this into `contextFactor`: 1.0 if sufficient, 0.5 otherwise. */
|
|
48
|
+
exports.CONTEXT_SUFFICIENCIES = ['sufficient', 'insufficient'];
|
|
49
|
+
exports.ContextSufficiencySchema = zod_1.z.enum(exports.CONTEXT_SUFFICIENCIES);
|
|
50
|
+
/**
|
|
51
|
+
* One structured finding from one reviewer (§9.3).
|
|
52
|
+
*
|
|
53
|
+
* `resourceIds` is required and non-empty: §9.4 makes the affected resource one
|
|
54
|
+
* of the dimensions consensus is measured on, so a finding that does not say
|
|
55
|
+
* what it is about cannot be agreed with or disagreed with.
|
|
56
|
+
*
|
|
57
|
+
* `policyRuleIds` is optional: step one of the form can complete without step
|
|
58
|
+
* two — a reviewer may classify material accurately and find no rule that
|
|
59
|
+
* covers it, which is exactly the `no_violation`-with-findings case §6.2
|
|
60
|
+
* describes.
|
|
61
|
+
*
|
|
62
|
+
* `context` is §9.2's and §9.4's "excepción", written as §6.2 writes it: beside
|
|
63
|
+
* the code and the severity, because "artistic nudity" is a different
|
|
64
|
+
* description of the material from "nudity" rather than a different verdict
|
|
65
|
+
* about it. Optional, and absence means no exception applies.
|
|
66
|
+
*
|
|
67
|
+
* `confidence` communicates quality and triggers escalation (§9.5). It never
|
|
68
|
+
* weights the vote.
|
|
69
|
+
*/
|
|
70
|
+
exports.ReviewFindingSchema = zod_1.z.strictObject({
|
|
71
|
+
code: taxonomy_1.TaxonomyCodeSchema,
|
|
72
|
+
resourceIds: zod_1.z.array(resources_1.ResourceIdSchema).min(1).max(primitives_1.CONTRACT_LIMITS.RESOURCE_REFS_PER_FINDING_MAX),
|
|
73
|
+
severity: taxonomy_1.SeveritySchema,
|
|
74
|
+
context: taxonomy_1.FindingContextSchema.optional(),
|
|
75
|
+
confidence: primitives_1.UnitIntervalSchema,
|
|
76
|
+
policyRuleIds: zod_1.z.array(policies_1.PolicyRuleIdSchema).max(primitives_1.CONTRACT_LIMITS.POLICY_RULE_IDS_MAX).optional(),
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* The body of `POST /v1/reviewer/assignments/{id}/reviews` — §9.3's "result of
|
|
80
|
+
* a review".
|
|
81
|
+
*
|
|
82
|
+
* `recommendedActions` is a list of action tokens here, where a decision's
|
|
83
|
+
* `recommendedActions` are objects that name their target resources. That
|
|
84
|
+
* difference is in the plan (§9.3 versus Appendix B) and is kept: a reviewer
|
|
85
|
+
* recommends a course of action, and the consensus process is what binds an
|
|
86
|
+
* agreed recommendation to the specific resources it applies to.
|
|
87
|
+
*/
|
|
88
|
+
exports.ReviewSubmissionSchema = zod_1.z
|
|
89
|
+
.strictObject({
|
|
90
|
+
outcome: exports.ReviewOutcomeSchema,
|
|
91
|
+
contextSufficiency: exports.ContextSufficiencySchema,
|
|
92
|
+
findings: zod_1.z.array(exports.ReviewFindingSchema).max(primitives_1.CONTRACT_LIMITS.FINDINGS_MAX),
|
|
93
|
+
recommendedActions: zod_1.z
|
|
94
|
+
.array(taxonomy_1.RecommendedActionSchema)
|
|
95
|
+
.max(primitives_1.CONTRACT_LIMITS.RECOMMENDED_ACTIONS_MAX),
|
|
96
|
+
/**
|
|
97
|
+
* §13.5 and the "sensitive content never reaches logs" invariant apply to
|
|
98
|
+
* this field as much as to the evidence: a note is free text a human wrote
|
|
99
|
+
* while looking at the material, so it is bounded here and must be treated
|
|
100
|
+
* as case content everywhere downstream — never logged, never attested.
|
|
101
|
+
*/
|
|
102
|
+
notes: zod_1.z.string().max(primitives_1.CONTRACT_LIMITS.LONG_TEXT_MAX_LENGTH).optional(),
|
|
103
|
+
})
|
|
104
|
+
.superRefine((review, ctx) => {
|
|
105
|
+
if (review.outcome === 'insufficient_context' && review.contextSufficiency !== 'insufficient') {
|
|
106
|
+
ctx.addIssue({
|
|
107
|
+
code: 'custom',
|
|
108
|
+
path: ['contextSufficiency'],
|
|
109
|
+
message: 'an outcome of insufficient_context requires contextSufficiency "insufficient"',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (review.outcome === 'violation' && review.findings.length === 0) {
|
|
113
|
+
ctx.addIssue({
|
|
114
|
+
code: 'custom',
|
|
115
|
+
path: ['findings'],
|
|
116
|
+
message: 'a violation outcome requires at least one finding',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
/**
|
|
121
|
+
* §4.1: a reviewer may declare a conflict, a language they do not have,
|
|
122
|
+
* material too sensitive for them, or context they cannot obtain — "without
|
|
123
|
+
* penalty". These four are the plan's own list, made structured as §10.3 asks.
|
|
124
|
+
*/
|
|
125
|
+
exports.RECUSAL_REASONS = [
|
|
126
|
+
'conflict_of_interest',
|
|
127
|
+
'language',
|
|
128
|
+
'too_sensitive',
|
|
129
|
+
'insufficient_context',
|
|
130
|
+
];
|
|
131
|
+
exports.RecusalReasonSchema = zod_1.z.enum(exports.RECUSAL_REASONS);
|
|
132
|
+
/**
|
|
133
|
+
* The body of `POST /v1/reviewer/assignments/{id}/recuse`.
|
|
134
|
+
*
|
|
135
|
+
* Strict for the same reason as the submission, and with no free-text field
|
|
136
|
+
* beyond a short optional note: a recusal is routing information, and the more
|
|
137
|
+
* it can say about the case, the more it becomes a channel for case content to
|
|
138
|
+
* leak into operational data.
|
|
139
|
+
*/
|
|
140
|
+
exports.RecusalSubmissionSchema = zod_1.z.strictObject({
|
|
141
|
+
reason: exports.RecusalReasonSchema,
|
|
142
|
+
note: zod_1.z.string().max(primitives_1.CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH).optional(),
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=reviews.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviews.js","sourceRoot":"","sources":["../src/reviews.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAEH,6BAAwB;AAExB,6CAAmE;AACnE,yCAAgD;AAChD,2CAA+C;AAC/C,yCAKoB;AAEpB;;;;;;;;;;GAUG;AACU,QAAA,eAAe,GAAG;IAC7B,WAAW;IACX,cAAc;IACd,sBAAsB;IACtB,qBAAqB;CACb,CAAC;AACE,QAAA,mBAAmB,GAAG,OAAC,CAAC,IAAI,CAAC,uBAAe,CAAC,CAAC;AAG3D,8EAA8E;AACjE,QAAA,qBAAqB,GAAG,CAAC,YAAY,EAAE,cAAc,CAAU,CAAC;AAChE,QAAA,wBAAwB,GAAG,OAAC,CAAC,IAAI,CAAC,6BAAqB,CAAC,CAAC;AAGtE;;;;;;;;;;;;;;;;;;;GAmBG;AACU,QAAA,mBAAmB,GAAG,OAAC,CAAC,YAAY,CAAC;IAChD,IAAI,EAAE,6BAAkB;IACxB,WAAW,EAAE,OAAC,CAAC,KAAK,CAAC,4BAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAAe,CAAC,6BAA6B,CAAC;IAChG,QAAQ,EAAE,yBAAc;IACxB,OAAO,EAAE,+BAAoB,CAAC,QAAQ,EAAE;IACxC,UAAU,EAAE,+BAAkB;IAC9B,aAAa,EAAE,OAAC,CAAC,KAAK,CAAC,6BAAkB,CAAC,CAAC,GAAG,CAAC,4BAAe,CAAC,mBAAmB,CAAC,CAAC,QAAQ,EAAE;CAC/F,CAAC,CAAC;AAGH;;;;;;;;;GASG;AACU,QAAA,sBAAsB,GAAG,OAAC;KACpC,YAAY,CAAC;IACZ,OAAO,EAAE,2BAAmB;IAC5B,kBAAkB,EAAE,gCAAwB;IAC5C,QAAQ,EAAE,OAAC,CAAC,KAAK,CAAC,2BAAmB,CAAC,CAAC,GAAG,CAAC,4BAAe,CAAC,YAAY,CAAC;IACxE,kBAAkB,EAAE,OAAC;SAClB,KAAK,CAAC,kCAAuB,CAAC;SAC9B,GAAG,CAAC,4BAAe,CAAC,uBAAuB,CAAC;IAC/C;;;;;OAKG;IACH,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,4BAAe,CAAC,oBAAoB,CAAC,CAAC,QAAQ,EAAE;CACvE,CAAC;KACD,WAAW,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;IAC3B,IAAI,MAAM,CAAC,OAAO,KAAK,sBAAsB,IAAI,MAAM,CAAC,kBAAkB,KAAK,cAAc,EAAE,CAAC;QAC9F,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,oBAAoB,CAAC;YAC5B,OAAO,EAAE,+EAA+E;SACzF,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,mDAAmD;SAC7D,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAGL;;;;GAIG;AACU,QAAA,eAAe,GAAG;IAC7B,sBAAsB;IACtB,UAAU;IACV,eAAe;IACf,sBAAsB;CACd,CAAC;AACE,QAAA,mBAAmB,GAAG,OAAC,CAAC,IAAI,CAAC,uBAAe,CAAC,CAAC;AAG3D;;;;;;;GAOG;AACU,QAAA,uBAAuB,GAAG,OAAC,CAAC,YAAY,CAAC;IACpD,MAAM,EAAE,2BAAmB;IAC3B,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,4BAAe,CAAC,qBAAqB,CAAC,CAAC,QAAQ,EAAE;CACvE,CAAC,CAAC"}
|