1use serde::{Deserialize, Serialize};
14use serde_json::Value;
15
16use crate::actionability::{Actionability, Address, RemediationUse};
17use crate::decimal::Decimal;
18use crate::grade::{Grade, PresentWhen};
19use crate::ids::{ArtifactId, CalibrationId, DefinitionId};
20use crate::limits::DEFINITION_V1;
21use crate::schema;
22use crate::time::Timestamp;
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
26#[serde(deny_unknown_fields)]
27pub struct Definition {
28 pub schema: String,
29 pub name: String,
30 pub version: String,
32 pub package: String,
33 pub inputs: Vec<InputDecl>,
34 #[serde(deserialize_with = "crate::generation::steps")]
35 pub steps: Vec<StepDecl>,
36 pub policy: PolicyDecl,
37 pub limits: LimitsDecl,
38 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub actionability: Option<Actionability>,
42 #[serde(
44 default,
45 skip_serializing_if = "Option::is_none",
46 deserialize_with = "crate::screening::present"
47 )]
48 #[schemars(with = "crate::screening::Screening")]
49 pub screening: Option<crate::screening::Screening>,
50}
51
52crate::document::versioned_document!(
53 Definition,
54 [schema::DEFINITION, schema::DEFINITION_V2],
55 "rustev.definition/1 or rustev.definition/2",
56 DEFINITION_V1,
57 DefinitionId
58);
59
60#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
62#[serde(deny_unknown_fields)]
63pub struct InputDecl {
64 pub name: String,
65 #[serde(rename = "type")]
66 pub ty: TypeDecl,
67 pub provenance: Vec<ProvenanceClass>,
69 pub freshness: Freshness,
70 #[serde(default, skip_serializing_if = "Option::is_none")]
73 pub evidence: Option<EvidenceDecl>,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub on_disagreement: Option<Disagreement>,
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
82#[serde(rename_all = "snake_case", deny_unknown_fields)]
83pub enum EvidenceDecl {
84 Graded {
85 sources: Vec<String>,
87 caps: Vec<Cap>,
89 },
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
93#[serde(deny_unknown_fields)]
94pub struct Cap {
95 pub path: String,
96 pub max_grade: Grade,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
102#[serde(rename_all = "snake_case", deny_unknown_fields)]
103pub enum Disagreement {
104 RequireAgreement,
105 Prefer { sources: Vec<String> },
106 TreatAsHint { sources: Vec<String> },
107 Abstain,
108}
109
110#[derive(
112 Debug,
113 Clone,
114 Copy,
115 PartialEq,
116 Eq,
117 PartialOrd,
118 Ord,
119 Hash,
120 Serialize,
121 Deserialize,
122 schemars::JsonSchema,
123)]
124#[serde(rename_all = "kebab-case")]
125pub enum ProvenanceClass {
126 AuthenticatedAppField,
127 SystemOfRecord,
128 UserSupplied,
129 ThirdParty,
130 AttributedClaim,
131 ModelDerived,
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
136#[serde(rename_all = "snake_case", deny_unknown_fields)]
137pub enum Freshness {
138 MaxAgeMs(u64),
139 NotRequired,
140}
141
142#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
144#[serde(rename_all = "snake_case", deny_unknown_fields)]
145pub enum TypeDecl {
146 Bool,
147 Integer,
148 Decimal,
149 Text {
150 max_bytes: u64,
151 },
152 Timestamp,
153 Enum {
154 options: Vec<String>,
155 },
156 List {
157 item: Box<TypeDecl>,
158 max_items: u64,
159 },
160 Record {
161 fields: Vec<FieldDecl>,
162 #[serde(default, skip_serializing_if = "Option::is_none")]
164 present_when: Option<PresentWhen>,
165 },
166 Nullable {
169 #[serde(rename = "type")]
170 ty: Box<TypeDecl>,
171 },
172 Map {
174 key_max_bytes: u64,
175 value: Box<TypeDecl>,
176 max_entries: u64,
177 },
178}
179
180#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
181#[serde(deny_unknown_fields)]
182pub struct FieldDecl {
183 pub name: String,
184 #[serde(rename = "type")]
185 pub ty: TypeDecl,
186}
187
188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
190#[serde(deny_unknown_fields)]
191pub struct StepDecl {
192 pub id: String,
193 pub body: StepBody,
194}
195
196#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
197#[serde(rename_all = "snake_case", deny_unknown_fields)]
198pub enum StepBody {
199 Acquire(crate::acquisition_step::Acquire),
200 Widen(crate::acquisition_step::Widen),
201 Exact(ExactDecl),
202 Semantic(SemanticDecl),
203 Corroborate(CorroborateDecl),
205 Generate(Box<crate::generation::Generate>),
206 Extract(Box<crate::extraction::Extract>),
207 AcceptModelDerived(Box<crate::extraction::AcceptModelDerived>),
208}
209
210#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
212#[serde(deny_unknown_fields)]
213pub struct CorroborateDecl {
214 pub claim: String,
216 pub upgrade_to: Grade,
218 pub by: Vec<Check>,
220 pub mode: CorroborationMode,
221 pub on_contradiction: OnContradiction,
222}
223
224#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
225#[serde(deny_unknown_fields)]
226pub struct Check {
227 pub predicate: Predicate,
228 pub on_false: OnFalse,
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
232#[serde(rename_all = "snake_case")]
233pub enum OnFalse {
234 Contradicts,
235 NoEvidence,
236}
237
238#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
239#[serde(rename_all = "snake_case")]
240pub enum CorroborationMode {
241 All,
242 Any,
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
246#[serde(rename_all = "snake_case")]
247pub enum OnContradiction {
248 Conflict,
249 TreatAsHint,
250 Abstain,
251}
252
253#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
258#[serde(deny_unknown_fields)]
259pub struct ExactDecl {
260 pub op: String,
261 pub version: u32,
262 pub args: Value,
263}
264
265#[derive(
267 Debug,
268 Clone,
269 Copy,
270 PartialEq,
271 Eq,
272 PartialOrd,
273 Ord,
274 Hash,
275 Serialize,
276 Deserialize,
277 schemars::JsonSchema,
278)]
279#[serde(rename_all = "snake_case")]
280pub enum Operation {
281 Classify,
282 Proposition,
283 Rubric,
284 Rank,
285 Generate,
286 Extract,
287}
288
289#[derive(
291 Debug,
292 Clone,
293 Copy,
294 PartialEq,
295 Eq,
296 PartialOrd,
297 Ord,
298 Hash,
299 Serialize,
300 Deserialize,
301 schemars::JsonSchema,
302)]
303#[serde(rename_all = "snake_case")]
304pub enum RequiredKind {
305 Label,
306 Distribution,
307 CalibratedProbability,
308 OrdinalDistribution,
309 Scores,
310 ScreenVerdict,
311 TextRecord,
312 TypedRecord,
313}
314
315#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
317#[serde(deny_unknown_fields)]
318pub struct SemanticDecl {
319 pub operation: Operation,
320 pub task: String,
322 pub question: String,
324 pub options: Vec<String>,
327 pub candidates: Candidates,
329 pub requires: RequiredKind,
330 pub project: Vec<String>,
332 pub for_each: Vec<ForEach>,
334 pub backend: BackendReq,
335 pub calibration: CalibrationRef,
336 pub fallback: Fallback,
337}
338
339#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
340#[serde(rename_all = "snake_case", deny_unknown_fields)]
341pub enum Candidates {
342 None,
343 From(String),
344}
345
346#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
348#[serde(deny_unknown_fields)]
349pub struct ForEach {
350 pub over: String,
352 pub bind: String,
354 pub items: ItemSource,
356}
357
358#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
359#[serde(rename_all = "snake_case", deny_unknown_fields)]
360pub enum ItemSource {
361 None,
362 List {
364 list: String,
365 id_field: String,
366 },
367}
368
369#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
371#[serde(deny_unknown_fields)]
372pub struct BackendReq {
373 pub min_determinism: Determinism,
374 pub artifact: ArtifactPin,
375 pub binding: BindingChoice,
376}
377
378#[derive(
380 Debug,
381 Clone,
382 Copy,
383 PartialEq,
384 Eq,
385 PartialOrd,
386 Ord,
387 Hash,
388 Serialize,
389 Deserialize,
390 schemars::JsonSchema,
391)]
392#[serde(rename_all = "snake_case")]
393pub enum Determinism {
394 Unspecified,
395 Tolerance,
396 Bitwise,
397}
398
399#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
400#[serde(rename_all = "snake_case", deny_unknown_fields)]
401pub enum ArtifactPin {
402 Any,
403 Pinned(ArtifactId),
404}
405
406#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
408#[serde(rename_all = "snake_case", deny_unknown_fields)]
409pub enum BindingChoice {
410 Auto,
411 Backend(String),
412}
413
414#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
415#[serde(rename_all = "snake_case", deny_unknown_fields)]
416pub enum CalibrationRef {
417 None,
418 Id(CalibrationId),
419}
420
421#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
423#[serde(rename_all = "snake_case", deny_unknown_fields)]
424pub enum Fallback {
425 None,
426 Unsupported,
428 Kind {
430 requires: RequiredKind,
431 reason: String,
432 },
433}
434
435#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
437#[serde(deny_unknown_fields)]
438pub struct LimitsDecl {
439 #[serde(
441 default,
442 skip_serializing_if = "Option::is_none",
443 deserialize_with = "crate::screening::present"
444 )]
445 #[schemars(with = "crate::acquisition_step::AcquisitionBudget")]
446 pub acquisition: Option<crate::acquisition_step::AcquisitionBudget>,
447 pub max_semantic_requests: u64,
448 pub on_excess: ExcessPolicy,
449 pub max_projection_bytes: u64,
450 pub distribution_tolerance: Decimal,
452 pub deadline_ms: u64,
454}
455
456#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
457#[serde(rename_all = "snake_case")]
458pub enum ExcessPolicy {
459 Refuse,
460 TruncateVisible,
461}
462
463#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
465#[serde(rename_all = "snake_case", deny_unknown_fields)]
466pub enum Literal {
467 Bool(bool),
468 Integer(i64),
469 Decimal(Decimal),
470 Text(String),
471 Timestamp(Timestamp),
472 DurationMs(u64),
473 Enum(String),
474}
475
476#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
481#[serde(rename_all = "snake_case", deny_unknown_fields)]
482pub enum Expr {
483 Ref(String),
484 Lit(Literal),
485 Add {
486 left: Box<Expr>,
487 right: Box<Expr>,
488 },
489 Sub {
490 left: Box<Expr>,
491 right: Box<Expr>,
492 },
493 Mul {
495 left: Box<Expr>,
496 right: Box<Expr>,
497 },
498 Div {
500 left: Box<Expr>,
501 right: Box<Expr>,
502 },
503 Round {
505 value: Box<Expr>,
506 scale: u32,
507 },
508 Fx {
510 amount: Box<Expr>,
511 from: Box<Expr>,
512 to: Box<Expr>,
513 rates: String,
514 scale: u32,
515 },
516 Len(Box<Expr>),
518 ToDecimal(Box<Expr>),
520 Graded {
523 #[serde(rename = "ref")]
524 reference: String,
525 require: GradeRequirement,
526 },
527}
528
529#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
531#[serde(deny_unknown_fields)]
532pub struct GradeRequirement {
533 pub min: Grade,
534 pub max_age_ms: AgeLimit,
535}
536
537#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
538#[serde(rename_all = "snake_case", deny_unknown_fields)]
539pub enum AgeLimit {
540 Ms(u64),
541 NotRequired,
542}
543
544#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
545#[serde(rename_all = "snake_case")]
546pub enum CmpOp {
547 Eq,
548 Ne,
549 Lt,
550 Le,
551 Gt,
552 Ge,
553}
554
555#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
557#[serde(rename_all = "snake_case", deny_unknown_fields)]
558pub enum Predicate {
559 Cmp {
560 left: Expr,
561 op: CmpOp,
562 right: Expr,
563 },
564 All(Vec<Predicate>),
565 Any(Vec<Predicate>),
566 Not(Box<Predicate>),
567 Member {
568 value: Expr,
569 set: Vec<Literal>,
570 },
571 Present(String),
573 IsConstructed {
575 #[serde(rename = "ref")]
576 reference: String,
577 },
578 MemberRef {
581 value: Expr,
582 set: String,
583 },
584}
585
586#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
588#[serde(deny_unknown_fields)]
589pub struct PolicyDecl {
590 pub on_unresolved: Vec<Handler>,
591 pub rules: Vec<Rule>,
592 pub adjustments: Vec<Adjustment>,
593}
594
595#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
597#[serde(deny_unknown_fields)]
598pub struct Handler {
599 pub target: String,
601 pub reasons: ReasonSet,
602 pub action: HandlerAction,
603}
604
605#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
606#[serde(rename_all = "snake_case", deny_unknown_fields)]
607pub enum ReasonSet {
608 Any,
609 Only(Vec<ReasonKind>),
610}
611
612#[derive(
614 Debug,
615 Clone,
616 Copy,
617 PartialEq,
618 Eq,
619 PartialOrd,
620 Ord,
621 Hash,
622 Serialize,
623 Deserialize,
624 schemars::JsonSchema,
625)]
626#[serde(rename_all = "snake_case")]
627pub enum ReasonKind {
628 MissingEvidence,
629 StaleEvidence,
630 InvalidInput,
631 Abstained,
632 BackendUnavailable,
633 InvalidBackendOutput,
634 BudgetExhausted,
635 DeadlineExceeded,
636 Conflict,
637 Unsupported,
638 InsufficientGrade,
640 ScreenUnavailable,
641 Skipped,
643}
644
645impl ReasonKind {
646 pub const ALL: [ReasonKind; 13] = [
647 ReasonKind::MissingEvidence,
648 ReasonKind::StaleEvidence,
649 ReasonKind::InvalidInput,
650 ReasonKind::Abstained,
651 ReasonKind::BackendUnavailable,
652 ReasonKind::InvalidBackendOutput,
653 ReasonKind::BudgetExhausted,
654 ReasonKind::DeadlineExceeded,
655 ReasonKind::Conflict,
656 ReasonKind::Unsupported,
657 ReasonKind::InsufficientGrade,
658 ReasonKind::ScreenUnavailable,
659 ReasonKind::Skipped,
660 ];
661}
662
663#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
664#[serde(rename_all = "snake_case", deny_unknown_fields)]
665pub enum HandlerAction {
666 Propagate,
668 Escalate {
669 reason: String,
670 },
671 AsUnmet,
674 PropagateWith {
677 remediation: Option<RemediationUse>,
678 #[serde(default, skip_serializing_if = "Address::is_computed")]
679 address: Address,
680 },
681 NeedsInput {
683 fields: Vec<String>,
684 questions: Vec<String>,
685 },
686}
687
688#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
689#[serde(deny_unknown_fields)]
690pub struct Rule {
691 pub id: String,
692 pub when: Cond,
693 pub then: OutcomeDecl,
694}
695
696#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
698#[serde(rename_all = "snake_case", deny_unknown_fields)]
699pub enum UncalibratedThreshold {
700 NotDeclared,
701 Declared { reason: String },
702}
703
704#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
706#[serde(rename_all = "snake_case", deny_unknown_fields)]
707pub enum Cond {
708 Always,
709 TopLabel {
710 step: String,
711 label: String,
712 },
713 MassAtLeast {
714 step: String,
715 option: String,
716 threshold: Decimal,
717 uncalibrated_threshold: UncalibratedThreshold,
718 },
719 TopMassBelow {
720 step: String,
721 threshold: Decimal,
722 uncalibrated_threshold: UncalibratedThreshold,
723 },
724 ExpectationAtLeast {
725 step: String,
726 value: Decimal,
727 },
728 Exact(Predicate),
729 Empty(String),
730 Nonempty(String),
731 All(Vec<Cond>),
732 Any(Vec<Cond>),
733 Not(Box<Cond>),
734 ProvenanceWithin {
737 #[serde(rename = "ref")]
738 reference: String,
739 classes: Vec<ProvenanceClass>,
740 },
741}
742
743#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
745#[serde(rename_all = "snake_case", deny_unknown_fields)]
746pub enum OutcomeDecl {
747 Propose {
748 action: String,
749 params: Vec<ParamDecl>,
750 },
751 Escalate {
752 reason: String,
753 },
754 MissingEvidenceFrom {
756 step: String,
757 },
758 NeedsInput {
760 fields: Vec<String>,
761 questions: Vec<String>,
762 },
763}
764
765#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
766#[serde(deny_unknown_fields)]
767pub struct ParamDecl {
768 pub name: String,
769 pub value: ParamSource,
770}
771
772#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
773#[serde(rename_all = "snake_case", deny_unknown_fields)]
774pub enum ParamSource {
775 Ref(String),
776 Lit(Literal),
777}
778
779#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
781#[serde(deny_unknown_fields)]
782pub struct Adjustment {
783 pub id: String,
784 pub when: Cond,
785 pub param: String,
786 pub scale: Vec<String>,
787}