codetether_agent/rlm/oracle/
batch_write.rs1use std::fs::File;
14use std::io::{BufWriter, Write};
15use std::path::Path;
16
17use anyhow::Result;
18
19use super::batch::{BatchValidationStats, SplitWriteStats};
20use super::record::OracleTraceRecord;
21
22impl BatchValidationStats {
23 pub fn write_jsonl_split(&self, out_dir: &str, prefix: &str) -> Result<SplitWriteStats> {
36 let dir = Path::new(out_dir);
37 std::fs::create_dir_all(dir)?;
38
39 let paths = BucketPaths::new(dir, prefix);
40 write_bucket(&paths.golden, &self.golden, "golden")?;
41 write_bucket(&paths.consensus, &self.consensus, "consensus")?;
42 write_reason_bucket(&paths.failed, &self.failed, "failed")?;
43 write_reason_bucket(&paths.unverified, &self.unverified, "unverified")?;
44
45 Ok(paths.into_stats(self))
46 }
47}
48
49struct BucketPaths {
50 golden: std::path::PathBuf,
51 consensus: std::path::PathBuf,
52 failed: std::path::PathBuf,
53 unverified: std::path::PathBuf,
54}
55
56impl BucketPaths {
57 fn new(dir: &Path, prefix: &str) -> Self {
58 Self {
59 golden: dir.join(format!("{prefix}.golden.jsonl")),
60 consensus: dir.join(format!("{prefix}.consensus.jsonl")),
61 failed: dir.join(format!("{prefix}.failed.jsonl")),
62 unverified: dir.join(format!("{prefix}.unverified.jsonl")),
63 }
64 }
65
66 fn into_stats(self, b: &BatchValidationStats) -> SplitWriteStats {
67 SplitWriteStats {
68 golden_path: self.golden.to_string_lossy().into(),
69 consensus_path: self.consensus.to_string_lossy().into(),
70 failed_path: self.failed.to_string_lossy().into(),
71 unverified_path: self.unverified.to_string_lossy().into(),
72 golden_count: b.golden.len(),
73 consensus_count: b.consensus.len(),
74 failed_count: b.failed.len(),
75 unverified_count: b.unverified.len(),
76 }
77 }
78}
79
80fn write_bucket(
81 path: &Path,
82 traces: &[super::trace_types::ValidatedTrace],
83 verdict: &str,
84) -> Result<()> {
85 let mut w = BufWriter::new(File::create(path)?);
86 for trace in traces {
87 let rec = OracleTraceRecord {
88 verdict: verdict.to_string(),
89 reason: None,
90 agreement_ratio: None,
91 trace: trace.clone(),
92 };
93 writeln!(w, "{}", serde_json::to_string(&rec)?)?;
94 }
95 w.flush()?;
96 Ok(())
97}
98
99fn write_reason_bucket(
100 path: &Path,
101 items: &[(super::trace_types::ValidatedTrace, String)],
102 verdict: &str,
103) -> Result<()> {
104 let mut w = BufWriter::new(File::create(path)?);
105 for (trace, reason) in items {
106 let rec = OracleTraceRecord {
107 verdict: verdict.to_string(),
108 reason: Some(reason.clone()),
109 agreement_ratio: None,
110 trace: trace.clone(),
111 };
112 writeln!(w, "{}", serde_json::to_string(&rec)?)?;
113 }
114 w.flush()?;
115 Ok(())
116}