use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::actionability::{Actionability, Address, RemediationUse};
use crate::decimal::Decimal;
use crate::grade::{Grade, PresentWhen};
use crate::ids::{ArtifactId, CalibrationId, DefinitionId};
use crate::limits::DEFINITION_V1;
use crate::schema;
use crate::time::Timestamp;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Definition {
pub schema: String,
pub name: String,
pub version: String,
pub package: String,
pub inputs: Vec<InputDecl>,
#[serde(deserialize_with = "crate::generation::steps")]
pub steps: Vec<StepDecl>,
pub policy: PolicyDecl,
pub limits: LimitsDecl,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub actionability: Option<Actionability>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::screening::present"
)]
#[schemars(with = "crate::screening::Screening")]
pub screening: Option<crate::screening::Screening>,
}
crate::document::versioned_document!(
Definition,
[schema::DEFINITION, schema::DEFINITION_V2],
"rustev.definition/1 or rustev.definition/2",
DEFINITION_V1,
DefinitionId
);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct InputDecl {
pub name: String,
#[serde(rename = "type")]
pub ty: TypeDecl,
pub provenance: Vec<ProvenanceClass>,
pub freshness: Freshness,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub evidence: Option<EvidenceDecl>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub on_disagreement: Option<Disagreement>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum EvidenceDecl {
Graded {
sources: Vec<String>,
caps: Vec<Cap>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Cap {
pub path: String,
pub max_grade: Grade,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Disagreement {
RequireAgreement,
Prefer { sources: Vec<String> },
TreatAsHint { sources: Vec<String> },
Abstain,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "kebab-case")]
pub enum ProvenanceClass {
AuthenticatedAppField,
SystemOfRecord,
UserSupplied,
ThirdParty,
AttributedClaim,
ModelDerived,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Freshness {
MaxAgeMs(u64),
NotRequired,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum TypeDecl {
Bool,
Integer,
Decimal,
Text {
max_bytes: u64,
},
Timestamp,
Enum {
options: Vec<String>,
},
List {
item: Box<TypeDecl>,
max_items: u64,
},
Record {
fields: Vec<FieldDecl>,
#[serde(default, skip_serializing_if = "Option::is_none")]
present_when: Option<PresentWhen>,
},
Nullable {
#[serde(rename = "type")]
ty: Box<TypeDecl>,
},
Map {
key_max_bytes: u64,
value: Box<TypeDecl>,
max_entries: u64,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct FieldDecl {
pub name: String,
#[serde(rename = "type")]
pub ty: TypeDecl,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct StepDecl {
pub id: String,
pub body: StepBody,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum StepBody {
Acquire(crate::acquisition_step::Acquire),
Widen(crate::acquisition_step::Widen),
Exact(ExactDecl),
Semantic(SemanticDecl),
Corroborate(CorroborateDecl),
Generate(Box<crate::generation::Generate>),
Extract(Box<crate::extraction::Extract>),
AcceptModelDerived(Box<crate::extraction::AcceptModelDerived>),
Rank(Box<crate::ranking::Rank>),
Select(Box<crate::ranking::Select>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CorroborateDecl {
pub claim: String,
pub upgrade_to: Grade,
pub by: Vec<Check>,
pub mode: CorroborationMode,
pub on_contradiction: OnContradiction,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Check {
pub predicate: Predicate,
pub on_false: OnFalse,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OnFalse {
Contradicts,
NoEvidence,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CorroborationMode {
All,
Any,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OnContradiction {
Conflict,
TreatAsHint,
Abstain,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ExactDecl {
pub op: String,
pub version: u32,
pub args: Value,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum Operation {
Classify,
Proposition,
Rubric,
Rank,
Generate,
Extract,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum RequiredKind {
Ranking,
Label,
Distribution,
CalibratedProbability,
OrdinalDistribution,
Scores,
ScreenVerdict,
TextRecord,
TypedRecord,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct SemanticDecl {
pub operation: Operation,
pub task: String,
pub question: String,
pub options: Vec<String>,
pub candidates: Candidates,
pub requires: RequiredKind,
pub project: Vec<String>,
pub for_each: Vec<ForEach>,
pub backend: BackendReq,
pub calibration: CalibrationRef,
pub fallback: Fallback,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Candidates {
None,
From(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ForEach {
pub over: String,
pub bind: String,
pub items: ItemSource,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum ItemSource {
None,
List {
list: String,
id_field: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct BackendReq {
pub min_determinism: Determinism,
pub artifact: ArtifactPin,
pub binding: BindingChoice,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum Determinism {
Unspecified,
Tolerance,
Bitwise,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum ArtifactPin {
Any,
Pinned(ArtifactId),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum BindingChoice {
Auto,
Backend(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum CalibrationRef {
None,
Id(CalibrationId),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Fallback {
None,
Unsupported,
Kind {
requires: RequiredKind,
reason: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct LimitsDecl {
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::screening::present"
)]
#[schemars(with = "crate::acquisition_step::AcquisitionBudget")]
pub acquisition: Option<crate::acquisition_step::AcquisitionBudget>,
pub max_semantic_requests: u64,
pub on_excess: ExcessPolicy,
pub max_projection_bytes: u64,
pub distribution_tolerance: Decimal,
pub deadline_ms: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExcessPolicy {
Refuse,
TruncateVisible,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Literal {
Bool(bool),
Integer(i64),
Decimal(Decimal),
Text(String),
Timestamp(Timestamp),
DurationMs(u64),
Enum(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Expr {
Ref(String),
Lit(Literal),
Add {
left: Box<Expr>,
right: Box<Expr>,
},
Sub {
left: Box<Expr>,
right: Box<Expr>,
},
Mul {
left: Box<Expr>,
right: Box<Expr>,
},
Div {
left: Box<Expr>,
right: Box<Expr>,
},
Round {
value: Box<Expr>,
scale: u32,
},
Fx {
amount: Box<Expr>,
from: Box<Expr>,
to: Box<Expr>,
rates: String,
scale: u32,
},
Len(Box<Expr>),
ToDecimal(Box<Expr>),
Graded {
#[serde(rename = "ref")]
reference: String,
require: GradeRequirement,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GradeRequirement {
pub min: Grade,
pub max_age_ms: AgeLimit,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum AgeLimit {
Ms(u64),
NotRequired,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CmpOp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Predicate {
Cmp {
left: Expr,
op: CmpOp,
right: Expr,
},
All(Vec<Predicate>),
Any(Vec<Predicate>),
Not(Box<Predicate>),
Member {
value: Expr,
set: Vec<Literal>,
},
Present(String),
IsConstructed {
#[serde(rename = "ref")]
reference: String,
},
MemberRef {
value: Expr,
set: String,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct PolicyDecl {
pub on_unresolved: Vec<Handler>,
pub rules: Vec<Rule>,
pub adjustments: Vec<Adjustment>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Handler {
pub target: String,
pub reasons: ReasonSet,
pub action: HandlerAction,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum ReasonSet {
Any,
Only(Vec<ReasonKind>),
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum ReasonKind {
MissingEvidence,
StaleEvidence,
InvalidInput,
Abstained,
BackendUnavailable,
InvalidBackendOutput,
BudgetExhausted,
DeadlineExceeded,
Conflict,
Unsupported,
InsufficientGrade,
ScreenUnavailable,
Skipped,
}
impl ReasonKind {
pub const ALL: [ReasonKind; 13] = [
ReasonKind::MissingEvidence,
ReasonKind::StaleEvidence,
ReasonKind::InvalidInput,
ReasonKind::Abstained,
ReasonKind::BackendUnavailable,
ReasonKind::InvalidBackendOutput,
ReasonKind::BudgetExhausted,
ReasonKind::DeadlineExceeded,
ReasonKind::Conflict,
ReasonKind::Unsupported,
ReasonKind::InsufficientGrade,
ReasonKind::ScreenUnavailable,
ReasonKind::Skipped,
];
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum HandlerAction {
Propagate,
Escalate {
reason: String,
},
AsUnmet,
PropagateWith {
remediation: Option<RemediationUse>,
#[serde(default, skip_serializing_if = "Address::is_computed")]
address: Address,
},
NeedsInput {
fields: Vec<String>,
questions: QuestionSelection,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Rule {
pub id: String,
pub when: Cond,
pub then: OutcomeDecl,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum UncalibratedThreshold {
NotDeclared,
Declared { reason: String },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum Cond {
Always,
TopLabel {
step: String,
label: String,
},
MassAtLeast {
step: String,
option: String,
threshold: Decimal,
uncalibrated_threshold: UncalibratedThreshold,
},
TopMassBelow {
step: String,
threshold: Decimal,
uncalibrated_threshold: UncalibratedThreshold,
},
ExpectationAtLeast {
step: String,
value: Decimal,
},
Exact(Predicate),
Empty(String),
Nonempty(String),
All(Vec<Cond>),
Any(Vec<Cond>),
Not(Box<Cond>),
ProvenanceWithin {
#[serde(rename = "ref")]
reference: String,
classes: Vec<ProvenanceClass>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(untagged, deny_unknown_fields)]
pub enum QuestionSelection {
Declared(Vec<String>),
Proposed {
proposed_by: String,
allowed: Vec<String>,
},
}
impl QuestionSelection {
pub fn allowed(&self) -> &[String] {
match self {
Self::Declared(ids) => ids,
Self::Proposed { allowed, .. } => allowed,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum OutcomeDecl {
Propose {
action: String,
params: Vec<ParamDecl>,
},
Escalate {
reason: String,
},
MissingEvidenceFrom {
step: String,
},
NeedsInput {
fields: Vec<String>,
questions: QuestionSelection,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ParamDecl {
pub name: String,
pub value: ParamSource,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum ParamSource {
Ref(String),
Lit(Literal),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Adjustment {
pub id: String,
pub when: Cond,
pub param: String,
pub scale: Vec<String>,
}