File size: 1,780 Bytes
0fff343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
"""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"]),
    )