#!/usr/bin/env python3 """Measure factual Java 26.2 movement through a pinned local official runtime. Requires the cache prepared by catalog_generate.py and an existing Java 25 JDK. Does not download assets or start a Minecraft server. See measurement_scope in the generated fixture for the precise boundary of the original-runtime probe. """ from pathlib import Path import argparse import hashlib import json import os import subprocess import zipfile ROOT = Path(__file__).resolve().parents[1] SOURCE_SHA1 = "823e2250d24b3ddac457a60c92a6a941943fcd6a" def digest(path, algorithm="sha256"): with path.open("rb") as source: return hashlib.file_digest(source, algorithm).hexdigest() def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--java", type=Path, required=True) parser.add_argument("--cache", type=Path, default=ROOT / "artifacts/catalog-cache") parser.add_argument("--output", type=Path, default=ROOT / "artifacts/catalog-cache/physics-reference.json") args = parser.parse_args() cache = args.cache.resolve() source = cache / "server.jar" if digest(source, "sha1") != SOURCE_SHA1: raise SystemExit("The official source JAR does not match the pinned Java 26.2 hash") executable = cache / "versions/26.2/server-26.2.jar" with zipfile.ZipFile(source) as bundle: with bundle.open("META-INF/versions/26.2/server-26.2.jar") as embedded: expected = hashlib.file_digest(embedded, "sha256").hexdigest() if digest(executable) != expected: raise SystemExit("The cached executable differs from the verified official bundle") classpath = os.pathsep.join(map(str, [executable, *sorted((cache / "libraries").rglob("*.jar"))])) java = args.java.resolve() script = ROOT / "scripts/physics_reference.java" measured = cache / "physics-measurements.json" commands = [ [str(java.with_name("javac")), "-cp", classpath, "-d", str(cache), str(script)], [str(java), "-Xmx1G", "-cp", str(cache) + os.pathsep + classpath, "physics_reference", str(measured)], ] with (cache / "physics-measurements.log").open("w") as log: for command in commands: result = subprocess.run(command, cwd=cache, stdout=log, stderr=subprocess.STDOUT) if result.returncode: raise SystemExit(f"Reference probe failed. Read {cache / 'physics-measurements.log'}") fixture = json.loads(measured.read_text()) fixture["provenance"] = { "source_url": f"https://piston-data.mojang.com/v1/objects/{SOURCE_SHA1}/server.jar", "source_sha1": SOURCE_SHA1, "source_sha256": digest(source), "executable_sha256": digest(executable), "probe_sha256": digest(script), "command": "python3 scripts/measure_physics.py --java /path/to/java25/bin/java --output crates/shacraft-physics/tests/fixtures/java26.2.json", "java": subprocess.run([str(java), "-version"], text=True, capture_output=True, check=True).stderr.strip(), } args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(json.dumps(fixture, indent=2) + "\n") print(f"Wrote {args.output}") if __name__ == "__main__": main()