fix: reports 500, NaN scores, hypothesis dedup blocking
Reports 500 (Internal Server Error): - app.py: Replace NaN/Infinity->null before json.loads() in both /reports and /api/runs routes. Old summary.json files with invalid NaN are now handled transparently. - reports/writer.py: Added _safe_val() helper using math.isfinite(). All summary.json values now use safe rounding (NaN->0, Inf->0). No new hypotheses (optimizer stops after 1 iter): - optimizer_loop.py: Changed dedup from DB-wide history to session-scoped (self.session_tested_deltas). Previous runs from old sessions no longer block new hypothesis proposals. - Each tested hypothesis is tracked within the session only. Result: optimizer now runs multiple iterations, scores are valid numbers, reports page loads without 500.
This commit is contained in:
@@ -94,13 +94,23 @@ def history():
|
||||
@app.route("/reports/")
|
||||
def reports_index():
|
||||
"""Reports browser page — fixes the 404 on the Reports button."""
|
||||
import json, re
|
||||
runs = []
|
||||
for run_dir in sorted(REPORTS_DIR.iterdir(), reverse=True) if REPORTS_DIR.exists() else []:
|
||||
if not run_dir.is_dir():
|
||||
continue
|
||||
summary = run_dir / "summary.json"
|
||||
if summary.exists():
|
||||
import json
|
||||
try:
|
||||
runs.append(json.loads(summary.read_text()))
|
||||
txt = summary.read_text(encoding="utf-8")
|
||||
# Fix legacy NaN values (invalid JSON) written before the fix
|
||||
txt = re.sub(r'\bNaN\b', 'null', txt)
|
||||
txt = re.sub(r'\bInfinity\b', 'null', txt)
|
||||
data = json.loads(txt)
|
||||
# Replace None scores with 0 for display
|
||||
data["score"] = data.get("score") or 0
|
||||
data["score_delta"] = data.get("score_delta") or 0
|
||||
runs.append(data)
|
||||
except Exception:
|
||||
pass
|
||||
return render_template("reports_index.html", runs=runs[:100])
|
||||
@@ -114,14 +124,22 @@ def reports_file(filename):
|
||||
|
||||
@app.route("/api/runs")
|
||||
def runs_list():
|
||||
import json, re
|
||||
runs = []
|
||||
if REPORTS_DIR.exists():
|
||||
for run_dir in sorted(REPORTS_DIR.iterdir(), reverse=True):
|
||||
if not run_dir.is_dir():
|
||||
continue
|
||||
summary = run_dir / "summary.json"
|
||||
if summary.exists():
|
||||
import json
|
||||
try:
|
||||
runs.append(json.loads(summary.read_text()))
|
||||
txt = summary.read_text(encoding="utf-8")
|
||||
txt = re.sub(r'\bNaN\b', 'null', txt)
|
||||
txt = re.sub(r'\bInfinity\b', 'null', txt)
|
||||
data = json.loads(txt)
|
||||
data["score"] = data.get("score") or 0
|
||||
data["score_delta"] = data.get("score_delta") or 0
|
||||
runs.append(data)
|
||||
except Exception:
|
||||
pass
|
||||
return jsonify(runs[:50])
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+4
-3
@@ -66,6 +66,7 @@ class OptimizerLoop:
|
||||
self.current_run_id: Optional[str] = None
|
||||
self.score_history: list[dict] = []
|
||||
self.run_start_ts: Optional[float] = None
|
||||
self.session_tested_deltas: list[dict] = [] # dedup within this session only
|
||||
|
||||
with open(config_path) as f:
|
||||
self.cfg = yaml.safe_load(f)
|
||||
@@ -177,12 +178,11 @@ class OptimizerLoop:
|
||||
self._emit("log", {"level": "warn", "msg": "No actionable findings. Stopping."})
|
||||
break
|
||||
|
||||
# Mutation proposals
|
||||
recent_deltas = store.get_recent_param_deltas(cfg["mutation"]["dedup_lookback_runs"])
|
||||
# Mutation proposals — only dedup within this session
|
||||
hypotheses = mutator.propose(
|
||||
findings=findings,
|
||||
current_params=current_params,
|
||||
recent_deltas=recent_deltas,
|
||||
recent_deltas=self.session_tested_deltas,
|
||||
max_proposals=cfg["mutation"]["max_hypotheses_per_cycle"],
|
||||
)
|
||||
|
||||
@@ -249,6 +249,7 @@ class OptimizerLoop:
|
||||
hypothesis=hyp, baseline_score=current_metrics.composite_score)
|
||||
|
||||
store.update_hypothesis_status(hyp.hypothesis_id, "tested", run_id)
|
||||
self.session_tested_deltas.append(hyp.param_delta) # track for session dedup
|
||||
|
||||
if iteration_best is None or test_metrics.composite_score > iteration_best.composite_score:
|
||||
iteration_best = test_metrics
|
||||
|
||||
Reference in New Issue
Block a user