git_policy_cli/standards_review_entry.rs
1//! What:
2//! The log entries of the standards-review shadow run, rendered as the root `mise.toml` task `shadow-review` writes
3//! them.
4//! Why:
5//! `doc/audit/standards-review-gate-shadow.md` already holds that task's entries, and readers and scorers parse them,
6//! so the port writes the same lines; `standards_review_append.rs` appends each entry, whole, to the live log.
7//!
8//! In TS you'd write (pseudocode):
9//! ```ts
10//! entry('- Date:'); entry(` ${new Date().toISOString()}`); // ...
11//! ```
12
13use super::standards_review_request::ROUTE;
14use super::standards_review_input::CAP_LINES;
15use super::standards_review_text::on_one_line;
16
17/// Leading characters of the commit name the log prints.
18pub const SHORT_SHA_LENGTH: usize = 12;
19
20/// What:
21/// Everything one review entry prints.
22/// Why:
23/// The renderer is a pure function of these values, so a test can fix the clock and the elapsed time.
24///
25/// In TS you'd write (pseudocode):
26/// ```ts
27/// type ReviewEntry = { date: string; sha: string; subject: string; codeFiles: number; diffLines: number; truncated: boolean; inputUnits: number; seconds: string; top: string; outcome: string };
28/// ```
29#[derive(Clone, Debug, Eq, PartialEq)]
30pub struct ReviewEntry {
31 /// `toISOString` text of the moment the entry is written.
32 pub date: String,
33 /// Full commit name.
34 pub sha: String,
35 /// Subject line.
36 pub subject: String,
37 /// Code files in the commit.
38 pub code_files: usize,
39 /// Lines of the whole patch.
40 pub diff_lines: usize,
41 /// Whether the patch was over the cap.
42 pub truncated: bool,
43 /// Reported model input length in UTF-16 units.
44 pub input_units: usize,
45 /// One-decimal seconds of the gateway call.
46 pub seconds: String,
47 /// The judged choice, or empty.
48 pub top: String,
49 /// The `Findings kept` line.
50 pub outcome: String,
51}
52
53/// What:
54/// The first `SHORT_SHA_LENGTH` characters of a commit name.
55/// Why:
56/// The log names commits by that prefix.
57///
58/// In TS you'd write (pseudocode):
59/// ```ts
60/// sha.slice(0, 12)
61/// ```
62fn short(sha: &str) -> String {
63 return sha.chars().take(SHORT_SHA_LENGTH).collect();
64}
65
66/// What:
67/// The three-line entry for a commit with no code files.
68/// Why:
69/// Coverage stays visible: every skipped landing leaves a line.
70///
71/// In TS you'd write (pseudocode):
72/// ```ts
73/// entry('- Skipped:'); entry(` ${sha.slice(0, 12)} (no code files):`); entry(` \`${subject}\``);
74/// ```
75pub fn render_skipped(sha: &str, subject: &str) -> String {
76 return format!("- Skipped:\n {} (no code files):\n `{}`\n", short(sha), on_one_line(subject));
77}
78
79/// What:
80/// The review entry, ending in the blank line that separates entries.
81/// Why:
82/// `Named superlinear cost` is the choice for `yes` and `no`, the two-line gesture for `partial`, and `unjudged` for
83/// anything else, as the script prints it.
84///
85/// In TS you'd write (pseudocode):
86/// ```ts
87/// entry('- Date:'); // ... entry('')
88/// ```
89pub fn render_review(entry: &ReviewEntry) -> String {
90 let capped: String = if entry.truncated { format!(", capped at {CAP_LINES}") } else { String::new() };
91 let judged: String = match entry.top.as_str() {
92 "partial" => String::from(" partial (cost gestured as unverified,\n not named)"),
93 "yes" | "no" => format!(" {}", entry.top),
94 _ => String::from(" unjudged"),
95 };
96 return format!(
97 "- Date:\n {date}\n Subject:\n {sha} `{subject}`\n Input size:\n `{files} code files, {lines} diff lines{capped}, luna input {units} chars`\n Reviewer route:\n `{ROUTE}`\n Wall-clock cost:\n {seconds} s\n Named superlinear cost:\n{judged}\n Findings kept:\n `````text\n {outcome}\n `````\n\n",
98 date = entry.date,
99 sha = short(entry.sha.as_str()),
100 subject = on_one_line(entry.subject.as_str()),
101 files = entry.code_files,
102 lines = entry.diff_lines,
103 units = entry.input_units,
104 seconds = entry.seconds,
105 outcome = on_one_line(entry.outcome.as_str()),
106 );
107}
108
109/// Controls stay out of the release executable.
110#[cfg(test)]
111#[path = "standards_review_entry_tests.rs"]
112mod tests;