"""Final evaluation (evaluator host only): loads the hidden oracle for the task, runs its deterministic evaluate.py on the collected deliverables, merges the harness-side reproducibility/contract result, validates the receipt against the public schema, stores it and transitions the run to `evaluated`.""" from __future__ import annotations import importlib.util, json, os, hashlib from .contracts import utcnow ORACLE_ROOT = os.path.expanduser("~/wp29-oracles") WEIGHTS = {"correctness": 0.40, "integrity": 0.20, "reproducibility": 0.15, "reporting": 0.15, "baseline": 0.10} def load_oracle(task_id): d = os.path.join(ORACLE_ROOT, task_id) oracle = json.load(open(os.path.join(d, "oracle.json"))) spec = importlib.util.spec_from_file_location(f"oracle_{task_id.replace('-', '_')}", os.path.join(d, "evaluate.py")) mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod) return oracle, mod, hashlib.sha256(open(os.path.join(d, "oracle.json"), "rb").read()).hexdigest() def validate_receipt(receipt, schema_path): try: import jsonschema jsonschema.validate(receipt, json.load(open(schema_path))); return True, "" except Exception as e: # noqa: BLE001 return False, str(e)[:300] def quality_score(q): return round(sum(WEIGHTS[k] * (q.get(k) or 0.0) for k in WEIGHTS), 4) def evaluate_run(repo, store, run_id, contract_receipt=None) -> dict: m = store.get_run(run_id) rd = os.path.join(repo, "runs", m["split"], run_id); out_dir = os.path.join(rd, "out") oracle, mod, ohash = load_oracle(m["task_id"]) # Evaluators receive a composed workspace (public bundle + the run's collected out/), never the oracle directory. import shutil, tempfile ws = tempfile.mkdtemp(prefix=f"wp29eval_{run_id}_") try: shutil.copytree(os.path.join(repo, "tasks", "public_bundles", m["task_id"]), ws, dirs_exist_ok=True) if os.path.isdir(out_dir): shutil.copytree(out_dir, os.path.join(ws, "out"), dirs_exist_ok=True) receipt = mod.evaluate(os.path.join(ws, "out"), oracle, ws, run_id=run_id) except Exception as e: # noqa: BLE001 receipt = {"task_id": m["task_id"], "run_id": run_id, "evaluator_version": "crashed", "evaluated_utc": utcnow(), "required_criteria": [], "critical_violations": [], "scientific_success": False, "quality_components": {"correctness": 0, "integrity": 0, "reproducibility": None, "reporting": 0, "baseline": 0}, "notes": f"evaluator raised: {e}"} finally: shutil.rmtree(ws, ignore_errors=True) if contract_receipt is None: try: contract_receipt = json.load(open(os.path.join(rd, "contract_receipt.json"))) except Exception: contract_receipt = None # noqa: BLE001 repro = None if contract_receipt: rc = [c for c in contract_receipt.get("checks", []) if c["id"] == "reproducibility"] repro = (1.0 if rc[0]["passed"] else 0.0) if rc else None receipt["quality_components"]["reproducibility"] = repro receipt["quality_score"] = quality_score(receipt["quality_components"]) receipt["oracle_sha256"] = ohash ok, err = validate_receipt(receipt, os.path.join(repo, "evaluators", "public_evaluation_interface", "receipt_schema.json")) receipt["schema_valid"] = ok; receipt["schema_error"] = err txt = json.dumps(receipt, indent=1, sort_keys=True, default=str) receipt["receipt_sha256"] = hashlib.sha256(txt.encode()).hexdigest() path = os.path.join(rd, "evaluation_receipt.json"); open(path, "w").write(json.dumps(receipt, indent=1, sort_keys=True, default=str)) if contract_receipt: json.dump(contract_receipt, open(os.path.join(rd, "contract_receipt.json"), "w"), indent=1) store.add_evaluation(run_id, receipt, contract_receipt) if store.get_run(run_id)["status"] != "evaluated": store.transition(run_id, "evaluated", note="final evaluation stored", evaluation_receipt=os.path.relpath(path, repo)) return receipt