use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ReviewState {
Queued,
Claimed,
Approved,
Rejected,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ReviewOutcome {
Pass,
Fail,
}
impl ReviewOutcome {
pub const fn is_pass(self) -> bool {
matches!(self, Self::Pass)
}
}
pub const MAX_REVIEW_LABELS: usize = 16;
pub const MAX_REVIEW_LABEL_CHARS: usize = 64;
pub const MAX_REVIEW_NOTE_CHARS: usize = 4_000;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HumanReview {
pub id: String,
pub run_id: String,
pub case_run_id: String,
pub state: ReviewState,
pub reason: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reviewer: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decision_note: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
#[serde(default)]
pub labels: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub overall: Option<ReviewOutcome>,
#[serde(default)]
pub sampled: bool,
pub fencing_token: i64,
pub created_at_ms: i64,
pub updated_at_ms: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct EnqueueReviewRequest {
pub run_id: String,
pub case_run_id: String,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ClaimReviewRequest {
#[serde(default = "default_review_lease")]
pub lease_ms: i64,
}
fn default_review_lease() -> i64 {
300_000
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CompleteReviewRequest {
pub review_id: String,
pub fencing_token: i64,
pub approved: bool,
#[serde(default)]
pub note: String,
#[serde(default)]
pub labels: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub overall: Option<ReviewOutcome>,
}
impl CompleteReviewRequest {
pub fn effective_outcome(&self) -> ReviewOutcome {
self.overall.unwrap_or(if self.approved {
ReviewOutcome::Pass
} else {
ReviewOutcome::Fail
})
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ReviewSamplingStrategy {
#[default]
Stratified,
Random,
FailedOnly,
}
pub const MAX_REVIEW_SAMPLE_SIZE: usize = 200;
pub const MAX_REVIEW_STRATA: usize = 256;
fn default_sample_size() -> usize {
30
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct SampleReviewsRequest {
pub run_id: String,
#[serde(default = "default_sample_size")]
pub size: usize,
#[serde(default)]
pub strategy: ReviewSamplingStrategy,
#[serde(default)]
pub seed: u64,
#[serde(default)]
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SampleReviewsResponse {
pub run_id: String,
pub requested: usize,
pub sampled: usize,
pub created: usize,
pub strata: usize,
pub reviews: Vec<HumanReview>,
}