|
|
@@ -33,19 +33,38 @@ pub(crate) fn parse_bench_json(content: &str) -> Option<(f64, Option<String>, Op
|
|
|
Some((pct, points, ratio))
|
|
|
}
|
|
|
|
|
|
-/// Did this bench cover the full scenario pool? The campaign's hardmode
|
|
|
-/// pool is 88 scenarios × 2 pt = 176 (`max_points` in the JSON). A run
|
|
|
-/// interrupted early writes fewer. Non-bench JSONs → false.
|
|
|
+/// Did this bench run to the end? Decided from the JSON's own metadata,
|
|
|
+/// never from a fixed pool size: the tool stamps `status` (absent on
|
|
|
+/// legacy files) and `total_scenarios` beside `scenario_results`, so
|
|
|
+/// coverage is self-describing for every harness generation (88×2=176 in
|
|
|
+/// the dev-era, 92×2=184 since v2.7.0, whatever comes next). A run
|
|
|
+/// interrupted early either says so in `status` or leaves the results
|
|
|
+/// map shorter than the scenario count.
|
|
|
pub(crate) fn bench_complete(content: &str) -> bool {
|
|
|
- serde_json::from_str::<serde_json::Value>(content)
|
|
|
- .ok()
|
|
|
- .and_then(|v| {
|
|
|
- v.get("scores")?
|
|
|
- .get("max_points")?
|
|
|
- .as_u64()
|
|
|
- .map(|mp| mp == 176)
|
|
|
- })
|
|
|
- .unwrap_or(false)
|
|
|
+ let Ok(v) = serde_json::from_str::<serde_json::Value>(content) else {
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+ let scores = match v.get("scores") {
|
|
|
+ Some(s) if s.is_object() => s,
|
|
|
+ _ => return false,
|
|
|
+ };
|
|
|
+ let covered = match (
|
|
|
+ v.get("total_scenarios").and_then(|x| x.as_u64()),
|
|
|
+ scores
|
|
|
+ .get("scenario_results")
|
|
|
+ .and_then(|x| x.as_object())
|
|
|
+ .map(|m| m.len() as u64),
|
|
|
+ ) {
|
|
|
+ (Some(total), Some(ran)) => ran >= total,
|
|
|
+ _ => true, // no coverage metadata to contradict
|
|
|
+ };
|
|
|
+ match v.get("status").and_then(|x| x.as_str()) {
|
|
|
+ Some("completed") => covered,
|
|
|
+ Some(_) => false,
|
|
|
+ // Legacy files carry no status — a printed final score was
|
|
|
+ // written only by a finished run.
|
|
|
+ None => scores.get("final_score").and_then(|x| x.as_f64()).is_some() && covered,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// First non-empty perf box among the given contents (md first, then log —
|