1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8pub enum ObjectiveKind {
9 BugFix,
10 Refactor,
11 SafetyHardening,
12 Performance,
13 Exploration,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ObjectivePolicy {
19 pub kind: ObjectiveKind,
20 pub correctness_weight: f64,
22 pub novelty_weight: f64,
24 pub stability_weight: f64,
26 pub allow_scalarization: bool,
28 pub min_trials_for_stability: u32,
30}
31
32impl ObjectivePolicy {
33 pub fn bug_fix() -> Self {
35 Self {
36 kind: ObjectiveKind::BugFix,
37 correctness_weight: 0.85,
38 novelty_weight: 0.05,
39 stability_weight: 0.10,
40 allow_scalarization: true,
41 min_trials_for_stability: 3,
42 }
43 }
44
45 pub fn refactor() -> Self {
47 Self {
48 kind: ObjectiveKind::Refactor,
49 correctness_weight: 0.70,
50 novelty_weight: 0.20,
51 stability_weight: 0.10,
52 allow_scalarization: true,
53 min_trials_for_stability: 3,
54 }
55 }
56
57 pub fn safety() -> Self {
59 Self {
60 kind: ObjectiveKind::SafetyHardening,
61 correctness_weight: 0.90,
62 novelty_weight: 0.0,
63 stability_weight: 0.10,
64 allow_scalarization: true,
65 min_trials_for_stability: 5,
66 }
67 }
68
69 pub fn performance() -> Self {
71 Self {
72 kind: ObjectiveKind::Performance,
73 correctness_weight: 0.60,
74 novelty_weight: 0.10,
75 stability_weight: 0.30,
76 allow_scalarization: false, min_trials_for_stability: 5,
78 }
79 }
80
81 pub fn exploration() -> Self {
83 Self {
84 kind: ObjectiveKind::Exploration,
85 correctness_weight: 0.50,
86 novelty_weight: 0.40,
87 stability_weight: 0.10,
88 allow_scalarization: false, min_trials_for_stability: 1,
90 }
91 }
92
93 pub fn compute_weighted_total(
95 &self,
96 correctness: f64,
97 novelty: f64,
98 stability: Option<f64>,
99 trial_count: u32,
100 ) -> Option<f64> {
101 if !self.allow_scalarization {
102 return None;
103 }
104
105 let stability_val = if trial_count >= self.min_trials_for_stability {
106 stability.unwrap_or(0.0)
107 } else {
108 0.0 };
110
111 Some(
112 self.correctness_weight * correctness
113 + self.novelty_weight * novelty
114 + self.stability_weight * stability_val,
115 )
116 }
117}
118
119impl Default for ObjectivePolicy {
120 fn default() -> Self {
121 Self::refactor()
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
127#[serde(rename_all = "snake_case")]
128pub enum ComparabilityClass {
129 ComparableCore,
131 PatchOnlyDiagnostic,
133 Informational,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct PlannedCheck {
140 pub check_kind: crate::exec::backend::CheckKind,
141 pub comparability: ComparabilityClass,
142 pub config_override: bool,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct PatchExecutionPlan {
149 pub checks: Vec<PlannedCheck>,
150 pub frozen: bool,
151}
152
153impl PatchExecutionPlan {
154 pub fn cargo_default() -> Self {
156 Self {
157 checks: vec![
158 PlannedCheck {
159 check_kind: crate::exec::backend::CheckKind::Fmt,
160 comparability: ComparabilityClass::ComparableCore,
161 config_override: false,
162 },
163 PlannedCheck {
164 check_kind: crate::exec::backend::CheckKind::Clippy,
165 comparability: ComparabilityClass::ComparableCore,
166 config_override: false,
167 },
168 PlannedCheck {
169 check_kind: crate::exec::backend::CheckKind::Test,
170 comparability: ComparabilityClass::ComparableCore,
171 config_override: false,
172 },
173 ],
174 frozen: true,
175 }
176 }
177
178 pub fn comparable_checks(&self) -> Vec<&PlannedCheck> {
180 self.checks
181 .iter()
182 .filter(|c| c.comparability == ComparabilityClass::ComparableCore)
183 .collect()
184 }
185}