Skip to main content

dkp_core/validate/
gate7.rs

1use crate::{
2    pack::loader::Pack,
3    validate::gates::{CheckResult, GateResult, GateStatus},
4};
5
6/// Gate 7: Evaluation — eval_set.jsonl present and eval_report.json shows no failures.
7pub fn run(pack: &Pack) -> GateResult {
8    if !pack.has_eval_set() {
9        return GateResult {
10            gate: 7,
11            status: GateStatus::Skipped,
12            checks: vec![CheckResult::skip("eval_set.jsonl (optional)")],
13            message: Some("eval_set.jsonl not present; gate 7 skipped".to_string()),
14        };
15    }
16
17    let mut checks = Vec::new();
18
19    // Count eval cases
20    match pack.load_eval_set() {
21        Ok(cases) => checks.push(CheckResult::pass(format!(
22            "eval_set.jsonl: {} cases loaded",
23            cases.len()
24        ))),
25        Err(e) => checks.push(CheckResult::fail("eval_set.jsonl parses", e.to_string())),
26    }
27
28    // Check eval_report.json in build/
29    let report_path = pack.root.join("build").join("eval_report.json");
30    if report_path.exists() {
31        match std::fs::read_to_string(&report_path)
32            .ok()
33            .and_then(|s| serde_json::from_str::<serde_json::Value>(&s).ok())
34        {
35            Some(v) => {
36                let total = v["summary"]["total"].as_u64().unwrap_or(0);
37                let failed = v["summary"]["failed"].as_u64().unwrap_or(0);
38                if failed == 0 {
39                    checks.push(CheckResult::pass(format!(
40                        "eval_report.json: all {total} cases passed"
41                    )));
42                } else {
43                    checks.push(CheckResult::fail(
44                        "eval_report.json",
45                        format!("{failed}/{total} cases failed"),
46                    ));
47                }
48            }
49            None => checks.push(CheckResult::fail(
50                "eval_report.json parses",
51                "could not parse eval_report.json",
52            )),
53        }
54    } else {
55        checks.push(CheckResult::skip(
56            "eval_report.json (run `dkp eval` to generate)",
57        ));
58    }
59
60    let failed = checks.iter().any(|c| c.status == GateStatus::Fail);
61    GateResult {
62        gate: 7,
63        status: if failed {
64            GateStatus::Fail
65        } else {
66            GateStatus::Pass
67        },
68        checks,
69        message: None,
70    }
71}