"""H2 success check — reveal winning IDs and report MMR overlap. This module is allowed to touch the sealed map (via airgap.reveal). The discovery engine itself never imports anything from here; this is the "after-the-fact" step that judges whether the blind search rediscovered the known biology. """ from __future__ import annotations import json from dataclasses import dataclass from pathlib import Path from airgap import reveal from data_pipeline import schema from validate.h1 import MMR_GENES RESULT_PATH_DEFAULT = schema.PROCESSED_DIR / "h2" / "result.json" @dataclass class H2RevealResult: gene_ids: list[str] gene_symbols: list[str] mmr_recovered: list[str] n_mmr_recovered: int holdout_auroc: float permutation_p: float baseline_holdout_auroc: float def load_result(path: Path | None = None) -> dict: path = path or RESULT_PATH_DEFAULT if not path.exists(): raise FileNotFoundError( f"H2 result not found at {path}. Run `python -m scripts.run_h2` first." ) return json.loads(path.read_text()) def reveal_winner(result: dict | None = None) -> H2RevealResult: """Decode the winning program's opaque IDs and check MMR overlap.""" result = result or load_result() win = result["winning"] gene_ids = list(win["gene_ids"]) symbols = reveal(gene_ids) mmr_set = set(MMR_GENES) recovered = [s for s in symbols if s in mmr_set] return H2RevealResult( gene_ids=gene_ids, gene_symbols=symbols, mmr_recovered=recovered, n_mmr_recovered=len(recovered), holdout_auroc=float(win["holdout_auroc"]), permutation_p=float(win["permutation_p"]), baseline_holdout_auroc=float(result["baseline"]["holdout_auroc"]), )