use ostraka_core::gate::Verdict;
pub fn review_prompt(task: &str, diff: &str, marker: &str) -> String {
format!(
"Review the change below against the task it was meant to perform. Judge \
two things: whether it is correct, and whether it stays inside what was \
asked — an unrequested change is a rejection even when it is an \
improvement.\n\n\
Say whatever you need to. End with exactly one line of this form, on a \
line of its own:\n\
{marker} APPROVE\n\
or\n\
{marker} REJECT: <one sentence>\n\n\
Use that marker exactly. An answer without it is read as a rejection, \
and so is an answer with more than one of it.\n\n\
----- task -----\n{task}\n\n\
----- diff -----\n{diff}"
)
}
pub fn verdict_marker(run_id: &str) -> String {
use std::hash::{DefaultHasher, Hash, Hasher};
let mut hasher = DefaultHasher::new();
run_id.hash(&mut hasher);
std::process::id().hash(&mut hasher);
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos()
.hash(&mut hasher);
format!("VERDICT-{:016x}:", hasher.finish())
}
pub fn parse_verdict(output: &str, marker: &str) -> Verdict {
Verdict::parse(output, marker)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_prompt_names_no_vendor_and_no_author() {
let prompt = review_prompt("rename a field", "--- a/x\n+++ b/x", "VERDICT-1:");
for forbidden in ["claude", "codex", "copilot", "gemini", "archon", "ephor"] {
assert!(
!prompt.to_lowercase().contains(forbidden),
"review prompt leaked {forbidden:?}"
);
}
}
#[test]
fn the_reviewer_is_told_what_was_asked() {
let prompt = review_prompt("rename a field", "--- a/x\n+++ b/x", "VERDICT-1:");
assert!(prompt.contains("rename a field"));
assert!(prompt.contains("--- a/x"));
}
#[test]
fn an_empty_answer_is_a_rejection() {
assert!(!parse_verdict("", "VERDICT-1:").is_approve());
}
#[test]
fn the_marker_differs_between_reviews_of_the_same_run() {
assert_ne!(verdict_marker("t1"), verdict_marker("t1"));
assert!(verdict_marker("t1").starts_with("VERDICT-"));
}
}