File size: 4,846 Bytes
1d842e3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
baa1d92
1d842e3
 
baa1d92
1d842e3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
baa1d92
1d842e3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
baa1d92
1d842e3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env python3
"""Link a frozen L3 run to its pre-training development evaluation plan."""

from __future__ import annotations

import argparse
import hashlib
import json
from pathlib import Path


def sha256_file(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for block in iter(lambda: handle.read(1024 * 1024), b""):
            digest.update(block)
    return digest.hexdigest()


def load(path: Path, artifact_type: str) -> dict:
    value = json.loads(path.read_text(encoding="utf-8"))
    if value.get("artifact_type") != artifact_type:
        raise ValueError(f"{path} has the wrong artifact_type")
    return value


def resolve_recorded(value: str, receipt_path: Path) -> Path:
    path = Path(value)
    if not path.is_absolute():
        path = receipt_path.parent / path
    return path.resolve()


def portable(path: Path, base: Path) -> str:
    try:
        return str(path.resolve().relative_to(base.resolve()))
    except ValueError:
        return str(path.resolve())


def prepare(args: argparse.Namespace) -> dict:
    build_receipt = load(
        args.bundle_build_receipt, "telen_l3_development_bundle_build"
    )
    training_receipt = load(
        args.training_receipt, "telen_l3_development_pilot"
    )
    if build_receipt.get("authorized") is not True:
        raise ValueError("bundle build receipt is not authorized")
    if training_receipt.get("status") != "completed_development_only":
        raise ValueError("training receipt is incomplete")
    if training_receipt.get("final_test_accessed") is not False:
        raise ValueError("training receipt does not preserve final-test sealing")

    training_manifest = resolve_recorded(
        str(build_receipt["training_manifest"]), args.bundle_build_receipt
    )
    evaluation_plan_path = resolve_recorded(
        str(build_receipt["evaluation_plan"]), args.bundle_build_receipt
    )
    development_queries = resolve_recorded(
        str(build_receipt["development_queries"]), args.bundle_build_receipt
    )
    development_candidates = resolve_recorded(
        str(build_receipt["development_candidates"]), args.bundle_build_receipt
    )
    expected_hashes = {
        training_manifest: build_receipt["training_manifest_sha256"],
        evaluation_plan_path: build_receipt["evaluation_plan_sha256"],
        development_queries: build_receipt["development_queries_sha256"],
        development_candidates: build_receipt["development_candidates_sha256"],
    }
    for path, expected in expected_hashes.items():
        if not path.is_file() or sha256_file(path) != expected:
            raise ValueError(f"frozen build artifact changed: {path}")
    if training_receipt.get("manifest_sha256") != sha256_file(training_manifest):
        raise ValueError("training receipt belongs to another training manifest")
    evaluation_plan = load(
        evaluation_plan_path, "telen_l3_development_evaluation_plan"
    )
    if evaluation_plan.get("final_test_accessed") is not False:
        raise ValueError("evaluation plan does not preserve final-test sealing")
    if (
        evaluation_plan.get("development_queries_sha256")
        != sha256_file(development_queries)
        or evaluation_plan.get("development_candidates_sha256")
        != sha256_file(development_candidates)
    ):
        raise ValueError("evaluation plan input hashes changed")

    args.output.parent.mkdir(parents=True, exist_ok=True)
    files = {
        "training_manifest": training_manifest,
        "training_receipt": args.training_receipt,
        "development_queries": development_queries,
        "development_candidates": development_candidates,
    }
    manifest = {
        "schema_version": 1,
        "artifact_type": "telen_l3_development_evaluation_bundle",
        "pretraining_evaluation_plan": str(evaluation_plan_path),
        "pretraining_evaluation_plan_sha256": sha256_file(evaluation_plan_path),
        "files": {
            name: {
                "path": portable(path, args.output.parent),
                "sha256": sha256_file(path),
            }
            for name, path in files.items()
        },
        "evaluation": evaluation_plan["evaluation"],
    }
    args.output.write_text(
        json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
    )
    return manifest


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--bundle-build-receipt", type=Path, required=True)
    parser.add_argument("--training-receipt", type=Path, required=True)
    parser.add_argument("--output", type=Path, required=True)
    return parser.parse_args()


def main() -> None:
    print(json.dumps(prepare(parse_args()), ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()