1use mj_core::review::driver::{Resolution, RoleState, RoleStatus, TurnReviewPhase};
4use mj_core::review::lanes::ReviewTier;
5use mj_core::review::verdict::ReviewVerdict;
6
7#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
9#[serde(deny_unknown_fields)]
10pub struct RuntimeReviewView {
11 pub session_id: String,
12 pub tier: ReviewTier,
13 pub phase: TurnReviewPhase,
14 pub roles: Vec<RoleStatus>,
15 pub status: String,
17 pub verdict: Option<VerdictView>,
19}
20
21impl RuntimeReviewView {
22 #[must_use]
25 pub fn is_working(&self) -> bool {
26 matches!(
27 self.phase,
28 TurnReviewPhase::CapturingDelta
29 | TurnReviewPhase::LaunchingReviewer
30 | TurnReviewPhase::Running { .. }
31 | TurnReviewPhase::Forwarding { error: None, .. }
32 )
33 }
34
35 #[must_use]
38 pub fn activity_label(&self) -> Option<&'static str> {
39 match &self.phase {
40 TurnReviewPhase::Resolved(_) => None,
41 TurnReviewPhase::Forwarding { error: None, .. } => Some("Sending findings"),
42 TurnReviewPhase::Forwarding { error: Some(_), .. } => Some("Forward failed"),
43 TurnReviewPhase::Verdict(verdict) => Some(match verdict {
44 ReviewVerdict::Findings { .. } => "Findings",
45 ReviewVerdict::Failed { .. } => "Review failed",
46 ReviewVerdict::Clean => "Review complete",
47 }),
48 TurnReviewPhase::Running { roles }
49 if roles.iter().any(|role| {
50 role.role == mj_core::review::driver::VALIDATOR_ROLE
51 && matches!(role.state, RoleState::Pending | RoleState::Running)
52 }) =>
53 {
54 Some("Validating")
55 }
56 _ => Some("Reviewing"),
57 }
58 }
59}
60
61#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
63#[serde(deny_unknown_fields)]
64pub struct VerdictView {
65 pub kind: VerdictKind,
66 pub text: String,
69 pub allowed: Vec<Resolution>,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
75#[serde(rename_all = "snake_case")]
76pub enum VerdictKind {
77 Clean,
78 Findings,
79 Failed,
80}
81
82#[must_use]
85pub fn role_session_id(primary_session_id: &str, role: &str) -> String {
86 if role == mj_core::review::driver::REVIEWER_ROLE {
87 format!("{primary_session_id}-reviewer")
88 } else {
89 format!("{primary_session_id}-review-{role}")
90 }
91}