use crate::{
ActorId, ArtifactId, AssetId, Key, LineageId, OperationId, RunId, WorkContract, WorkItemId,
WorkspaceId,
};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RunSession {
pub provider: String,
pub session: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub turn: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub provenance: Option<Box<RunProvenance>>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RunProvenance {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requested_model: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub observed_model: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub runtime_version: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub configuration_digest: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Observation {
Managed,
ReportedOnly,
}
impl Observation {
#[must_use]
pub fn word(self) -> &'static str {
match self {
Self::Managed => "managed",
Self::ReportedOnly => "reported_only",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("unknown observation {0:?}; expected managed or reported_only")]
pub struct ObservationParseError(String);
impl std::str::FromStr for Observation {
type Err = ObservationParseError;
fn from_str(word: &str) -> Result<Self, Self::Err> {
[Self::Managed, Self::ReportedOnly]
.into_iter()
.find(|mode| mode.word() == word)
.ok_or_else(|| ObservationParseError(word.into()))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
pub enum RunSource {
GitCommit {
asset: AssetId,
commit: String,
},
Artifact {
artifact: ArtifactId,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ExactSource {
pub asset: AssetId,
pub commit: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub artifact: Option<ArtifactId>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RunStart {
pub id: RunId,
pub work: WorkItemId,
pub executor: ActorId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent: Option<RunId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub session: Option<RunSession>,
pub observation: Observation,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub sources: Vec<RunSource>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub observed_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ContractObservation {
pub workspace_id: WorkspaceId,
pub lineage_id: LineageId,
pub revision: u64,
pub work_key: Key,
pub prior_submissions: u32,
pub contract: WorkContract,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RunRecord {
pub id: RunId,
pub work: WorkItemId,
pub executor: ActorId,
pub recorded_by: ActorId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent: Option<RunId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub session: Option<RunSession>,
pub observation: Observation,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub sources: Vec<RunSource>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub exact_sources: Vec<ExactSource>,
pub contract: ContractObservation,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub observed_started_at: Option<DateTime<Utc>>,
pub started_at: DateTime<Utc>,
}
impl RunRecord {
#[must_use]
pub fn request(&self) -> RunStart {
RunStart {
id: self.id,
work: self.work,
executor: self.executor.clone(),
parent: self.parent,
session: self.session.clone(),
observation: self.observation,
sources: self.sources.clone(),
observed_at: self.observed_started_at,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RunLink {
pub run: RunId,
pub operation: OperationId,
pub work: WorkItemId,
pub linked_by: ActorId,
pub linked_at: DateTime<Utc>,
}