pub struct IssueRun {
pub issue: i64,
pub title: String,
pub status: Status,
pub pr: Option<String>,
pub rounds: u32,
pub disputes: Vec<Dispute>,
pub filed: Vec<String>,
pub notes: Vec<String>,
}Expand description
The outcome of working one issue, or resuming one PR.
Fields§
§issue: i64§title: String§status: Status§pr: Option<String>§rounds: u32§disputes: Vec<Dispute>§filed: Vec<String>§notes: Vec<String>Implementations§
Source§impl IssueRun
impl IssueRun
Sourcepub fn new(issue: i64, title: impl Into<String>) -> Self
pub fn new(issue: i64, title: impl Into<String>) -> Self
Examples found in repository?
examples/preview.rs (line 161)
35fn main() {
36 let loose = std::env::args().any(|a| a == "--loose");
37 let style = if loose {
38 Style {
39 terse: false,
40 ..Style::default()
41 }
42 } else {
43 Style::default()
44 };
45 if loose {
46 println!("(concision gate OFF: this is what a model would post unedited)");
47 }
48
49 rule("A clean review");
50 println!(
51 "{}",
52 review_comment(
53 "codex",
54 1,
55 &Review {
56 verdict: Verdict::Approve,
57 next_action: NextAction::Merge,
58 summary: "I reviewed the changes on this branch carefully and I am happy to \
59 report that the retry path is correct, the backoff calculation is \
60 sound, and the new test covers the 429 case that the issue described. \
61 I have no objections to this change landing as it stands."
62 .into(),
63 findings: vec![],
64 },
65 &style
66 )
67 );
68
69 rule("A review with real work in it");
70 println!(
71 "{}",
72 review_comment(
73 "codex",
74 2,
75 &Review {
76 verdict: Verdict::ChangesRequested,
77 next_action: NextAction::HandBack,
78 summary: "There is one genuine defect here that should block, along with a \
79 couple of improvements that I do not think need to gate this \
80 particular pull request, and one pre-existing problem I noticed \
81 while reading the surrounding code."
82 .into(),
83 findings: vec![
84 finding(
85 "blocking",
86 "Retry loop never terminates when max_attempts is unset",
87 "I confirmed this by running the 429 test with max_attempts left at its \
88 default of None: the loop spins forever because the guard on line 91 \
89 compares against Some(0) rather than checking for None first. This is \
90 not a theoretical concern, the test hangs and I had to kill it.",
91 "src/net.rs:88",
92 true,
93 ),
94 finding(
95 "non-blocking",
96 "The request timeout is hard coded to thirty seconds",
97 "It would be better if this were configurable, since a slow upstream \
98 will now fail rather than wait, but the previous code had the same \
99 limitation so this is not a regression introduced by the change.",
100 "src/net.rs:44",
101 true,
102 ),
103 finding(
104 "nit",
105 "Log line says \"retrying\" without saying how many attempts remain",
106 "Purely a readability point for whoever is reading the logs at 3am.",
107 "src/net.rs:102",
108 true,
109 ),
110 finding(
111 "blocking",
112 "Config loader swallows a parse error",
113 "Unrelated to this PR, but load_config discards the error from serde and \
114 returns Default::default(), so a typo in the config file is silently \
115 ignored.",
116 "src/config.rs:210",
117 false,
118 ),
119 ],
120 },
121 &style
122 )
123 );
124
125 rule("Answering that review");
126 println!(
127 "{}",
128 disposition_comment(
129 "claude",
130 &ResponseDoc {
131 summary: "One of the two blocking points was right and I have fixed it. I do not \
132 agree with the other and have explained why below rather than changing \
133 working code to make the review go away."
134 .into(),
135 dispositions: vec![],
136 },
137 &["Retry loop never terminates when max_attempts is unset".to_string()],
138 &[
139 "Config loader swallows a parse error. The caller already validates the file \
140 against the schema before load_config is reached, so the discarded error is \
141 unreachable in practice."
142 .to_string()
143 ],
144 &["https://github.com/you/thing/issues/512".to_string()],
145 &style
146 )
147 .unwrap_or_default()
148 );
149
150 rule("The pull request body");
151 println!(
152 "{}",
153 pr_body(
154 478,
155 "Retry a 429 with exponential backoff instead of failing the request.",
156 &style
157 )
158 );
159
160 rule("What a whole run leaves on the PR (the default, one comment)");
161 let mut ended = IssueRun::new(482, "t");
162 ended.disputes = vec![Dispute {
163 title: "Config loader swallows a parse error".into(),
164 reasoning: "the caller validates against the schema before load_config is reached".into(),
165 }];
166 ended.filed = vec![
167 "https://github.com/you/thing/issues/485".into(),
168 "https://github.com/you/thing/issues/486".into(),
169 ];
170 println!(
171 "{}",
172 outcome_comment(
173 &ended,
174 &spar::model::Ledger::new(),
175 &Ending::OutOfRounds,
176 &style
177 )
178 .unwrap_or_default()
179 );
180 println!("\n (and a clean run that filed nothing posts no comment at all)");
181
182 rule("A review of somebody else's pull request (spar review)");
183 let judged = |standing, severity, title: &str, detail: &str, file: &str, by: &str| Judged {
184 finding: finding(severity, title, detail, file, true),
185 raised_by: by.to_string(),
186 standing,
187 counterpoint: None,
188 defence: None,
189 };
190 let mut disputed = judged(
191 Standing::Disputed,
192 "blocking",
193 "Config loader swallows a parse error",
194 "load_config discards the error from serde and returns a default.",
195 "src/config.rs:210",
196 "claude",
197 );
198 disputed.counterpoint =
199 Some("the caller validates against the schema before load_config is reached".into());
200 println!(
201 "{}",
202 verdict_comment(
203 &[
204 judged(
205 Standing::Corroborated,
206 "blocking",
207 "Retry loop never terminates when max_attempts is unset",
208 "Both reviewers reproduced this: the guard on line 91 compares against \
209 Some(0) rather than checking for None, so the 429 test hangs.",
210 "src/net.rs:88",
211 "claude and codex",
212 ),
213 judged(
214 Standing::Confirmed,
215 "non-blocking",
216 "The request timeout is hard coded",
217 "Not a regression, the previous code had the same limitation.",
218 "src/net.rs:44",
219 "codex",
220 ),
221 judged(
222 Standing::Unverified,
223 "nit",
224 "Log line does not say how many attempts remain",
225 "Readability for whoever reads the logs at 3am.",
226 "src/net.rs:102",
227 "claude",
228 ),
229 disputed,
230 judged(
231 Standing::Withdrawn,
232 "blocking",
233 "Off by one in the backoff",
234 "Withdrawn after the other reviewer pointed at the test that covers it.",
235 "src/net.rs:70",
236 "codex",
237 ),
238 ],
239 &style
240 )
241 );
242
243 rule("An issue both reviewers declined");
244 println!(
245 "{}",
246 skip_comment(
247 &SkippedItem {
248 issue: 91,
249 title: "Add a dark mode".into(),
250 reasons: [
251 (
252 "claude".to_string(),
253 "This was already implemented in 1.4 and shipped behind the theme \
254 setting, so there is nothing left to do here."
255 .to_string()
256 ),
257 (
258 "codex".to_string(),
259 "Duplicate of #62, which is still open and has the full discussion."
260 .to_string()
261 ),
262 ]
263 .into_iter()
264 .collect(),
265 },
266 &style
267 )
268 );
269 println!();
270}Trait Implementations§
Source§impl<'de> Deserialize<'de> for IssueRun
impl<'de> Deserialize<'de> for IssueRun
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more
Auto Trait Implementations§
impl Freeze for IssueRun
impl RefUnwindSafe for IssueRun
impl Send for IssueRun
impl Sync for IssueRun
impl Unpin for IssueRun
impl UnsafeUnpin for IssueRun
impl UnwindSafe for IssueRun
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more