File size: 3,414 Bytes
2ff3288
3d74b10
2ff3288
3d74b10
 
 
 
2ff3288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3d74b10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ff3288
 
3d74b10
2ff3288
3d74b10
 
 
 
 
2ff3288
3d74b10
2ff3288
 
 
3d74b10
2ff3288
3d74b10
2ff3288
 
 
 
 
 
 
 
 
 
 
3d74b10
2ff3288
 
 
 
 
 
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/env python3
"""Compute the representation-validation readiness gate from real artifacts.

This does NOT invent labels or treat fallback fingerprints as POM. It inspects
the on-disk benchmark artifacts and reports whether each readiness check is
genuinely satisfied. Safe to rerun: output is deterministic apart from
``generated_at``. Never overwrites benchmark manifests/results.
"""
from __future__ import annotations

import argparse
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

ROOT = Path(__file__).resolve().parents[1]


def write_json(path: Path, value: Any) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(value, indent=2, sort_keys=True) + "\n")


def _read(path: Path) -> Any:
    try:
        return json.loads(path.read_text())
    except Exception:
        return None


def real_pom_available() -> bool:
    man = _read(ROOT / "artifacts/pom/pom_manifest.json")
    emb = ROOT / "artifacts/pom/pom_embeddings.npy"
    if not (man and emb.exists()):
        return False
    # genuine pretrained weights only; fallback-generated assets are rejected
    src = json.dumps(man).lower()
    return ("openpom" in src or "v1.0.0" in src) and "fallback" not in src


def ablation_complete() -> bool:
    res = _read(ROOT / "artifacts/representation_ablation/ablation_results.json")
    if not res:
        return False
    txt = json.dumps(res)
    return "morgan" in txt and "real_pom" in txt


def triplet_count_positive() -> bool:
    f = ROOT / "data/benchmarks/substitution_triplets/triplets.jsonl"
    if not f.exists():
        return False
    return sum(1 for line in f.read_text().splitlines() if line.strip()) > 0


def prospective_count_ok() -> bool:
    f = ROOT / "data/benchmarks/prospective_formulas/formulas.jsonl"
    if not f.exists():
        return False
    n = sum(1 for line in f.read_text().splitlines() if line.strip())
    return 30 <= n <= 50


def prospective_labels_sequestered() -> bool:
    f = ROOT / "data/benchmarks/prospective_formulas/labels.sequestered.json"
    if not f.exists():
        return False
    return "evaluation_only" in f.read_text()


def evaluate(now: str) -> dict[str, Any]:
    checks = {
        "real_pom_available": real_pom_available(),
        "ablation_complete": ablation_complete(),
        "triplet_count_positive": triplet_count_positive(),
        "prospective_formula_count_30_to_50": prospective_count_ok(),
        "prospective_labels_sequestered": prospective_labels_sequestered(),
    }
    ready = all(checks.values())
    gate = {
        "schema_version": 1,
        "generated_at": now,
        "ready_for_training": ready,
        "checks": checks,
        "decision": "READY_FOR_TRAINING" if ready else "DO_NOT_TRAIN",
        "blockers": [name for name, passed in checks.items() if not passed],
    }
    write_json(ROOT / "artifacts/training_readiness.json", gate)
    return gate


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--timestamp", help="ISO-8601 timestamp for reproducible freezing")
    args = parser.parse_args()
    now = args.timestamp or datetime.now(timezone.utc).isoformat()
    gate = evaluate(now)
    print(json.dumps(gate, indent=2, sort_keys=True))
    return 0 if gate["ready_for_training"] else 2


if __name__ == "__main__":
    raise SystemExit(main())