#!/usr/bin/env python3 """Reproduce ABLAQ's courtyard v1.0.1 release and verification evidence. Python 3.10+ (standard library) and Node.js 18+. Place this script beside courtyard-study.v1.py, courtyard-results.v1.csv, courtyard-manifest.v1.json and LICENSE.txt. Download courtyard-model.v1.js too. Usage: python3 -B courtyard-reproduce.v1.py --browser-model courtyard-model.v1.js Writes JSON to standard output. Reads local files only; no network requests. The source model, dataset and current release manifest are not modified. Published supplementary verification code: CC0-1.0; see LICENSE.txt. """ import argparse import contextlib import hashlib import importlib.util import io import json import math from pathlib import Path import platform import subprocess import sys sys.dont_write_bytecode = True PROBES = ( (100, 1, 5, 45, 45), (100, 2, 4, 37, 19), (100, 4, 5, 60, 130), (225, 0.6, 6, 52, 227), (100, 4, 7.5, 15, 71), (100, 1, 2.5, 75, 319), ) KEYS = ("area", "ratio", "height", "altitude", "azimuth") RESOLUTIONS = (40, 80, 160, 320) TOLERANCE = 1e-12 NODE_COMPARE = r""" import fs from 'node:fs'; const file = process.argv[1]; const text = fs.readFileSync(file, 'utf8'); const model = await import('data:text/javascript;base64,' + Buffer.from(text).toString('base64')); const cases = JSON.parse(fs.readFileSync(0, 'utf8')); console.log(JSON.stringify({ node: process.version, results: cases.map(inputs => model.courtyardSunlight(inputs).fraction) })); """ def require(condition, message): if not condition: raise ValueError(message) def sha256(content): return hashlib.sha256(content).hexdigest() def record_file(file): content = file.read_bytes() return {"bytes": len(content), "sha256": sha256(content)} def reproduce(directory, browser_model, node): manifest_file = directory / "courtyard-manifest.v1.json" manifest = json.loads(manifest_file.read_text(encoding="utf-8")) require(manifest["version"] == "1.0.1", "Expected the current v1.0.1 manifest.") expected_paths = { "/assets/courtyard-model.v1.js": browser_model, "/research-data/courtyard-study.v1.py": directory / "courtyard-study.v1.py", "/research-data/courtyard-results.v1.csv": directory / "courtyard-results.v1.csv", "/research-data/LICENSE.txt": directory / "LICENSE.txt", } require(set(manifest["files"]) == set(expected_paths), "Unexpected release file set.") files = {} for route, file in expected_paths.items(): actual = record_file(file) require(actual == manifest["files"][route], "Release hash or size mismatch: " + route) files[route] = actual spec = importlib.util.spec_from_file_location( "ablaq_courtyard_release", expected_paths["/research-data/courtyard-study.v1.py"]) study = importlib.util.module_from_spec(spec) spec.loader.exec_module(study) verification_output = io.StringIO() with contextlib.redirect_stdout(verification_output): study.verify() verification = json.loads(verification_output.getvalue()) require(verification["status"] == "passed", "Original numerical checks failed.") require(verification["checks"] == manifest["verification"]["checks"], "Original check count differs from the release record.") generated = io.StringIO() with contextlib.redirect_stdout(generated): study.write_csv() csv_bytes = generated.getvalue().encode("utf-8") published_csv = expected_paths["/research-data/courtyard-results.v1.csv"].read_bytes() require(csv_bytes == published_csv, "Regenerated CSV differs from the published file.") cases = list(study.cases()) require(len(cases) == manifest["cases"] == 315, "Parameter sweep differs.") published_inputs = {tuple(case[key] for key in KEYS) for case in cases} ray_cases = [] for index, parameters in enumerate(PROBES, start=1): analytical = study.sunlight(*parameters) samples = [] for resolution in RESOLUTIONS: sampled = study.ray_grid(*parameters, n=resolution) error = abs(analytical - sampled) require(error <= 2 / resolution, "Ray-sampling error bound exceeded.") samples.append({ "grid_side": resolution, "rays": resolution * resolution, "sampled_sunlit_fraction": sampled, "absolute_fraction_difference": error, }) ray_cases.append({ "case": index, "inputs": dict(zip(KEYS, parameters)), "in_published_sweep": parameters in published_inputs, "analytical_sunlit_fraction": analytical, "samples": samples, }) ray_maxima = [ {"grid": resolution, "max_absolute_fraction_error": max(case["samples"][i]["absolute_fraction_difference"] for case in ray_cases)} for i, resolution in enumerate(RESOLUTIONS) ] for actual, original in zip(ray_maxima, verification["ray_grid"]): require(actual["grid"] == original["grid"] and abs(actual["max_absolute_fraction_error"] - original["max_absolute_fraction_error"]) <= TOLERANCE, "Detailed ray results differ from the released checker.") for actual, published in zip(ray_maxima, manifest["verification"]["ray_grid"]): require(actual["grid"] == published["grid"] and abs(actual["max_absolute_fraction_error"] - published["max_absolute_fraction_error"]) <= TOLERANCE, "Ray-sampling summary differs from the release manifest.") process = subprocess.run( [node, "--input-type=module", "-e", NODE_COMPARE, str(browser_model.resolve())], input=json.dumps(cases), text=True, capture_output=True, timeout=60) require(process.returncode == 0, "Node.js comparison failed. Check that Node.js 18+ is installed and the model is accessible.") comparison = json.loads(process.stdout) browser_values = comparison["results"] require(len(browser_values) == len(cases) and all(isinstance(v, (float, int)) and math.isfinite(v) for v in browser_values), "Invalid JavaScript comparison results.") differences = [abs(study.sunlight(**case) - value) for case, value in zip(cases, browser_values)] maximum = max(differences) require(maximum <= TOLERANCE, "Python and JavaScript implementations disagree.") require(abs(maximum - manifest["verification"]["browser_python_max_difference"]) <= TOLERANCE, "Implementation comparison differs from the published verification.") worst = differences.index(maximum) files["/research-data/courtyard-manifest.v1.json"] = record_file(manifest_file) files["/research-data/courtyard-reproduce.v1.py"] = record_file(Path(__file__)) return { "format": "ablaq-courtyard-reproduction-v1", "status": "passed", "study": "Courtyard geometry and direct sunlight", "study_version": study.VERSION, "canonical_url": manifest["canonical_url"], "author": "ABLAQ Studios", "environment": {"python": platform.python_version(), "node": comparison["node"]}, "files": files, "dataset": {"cases": len(cases), "matches_published_bytes": True, "sha256": sha256(csv_bytes), "fraction_decimal_places": 8}, "released_checks": verification, "ray_sampling": { "method": "Midpoint floor quadrature, tracing each ray to its first wall.", "scope": "Separate numerical method developed within the same AI-assisted workflow; not external replication.", "configuration_count": len(PROBES), "outside_published_sweep": sum(not case["in_published_sweep"] for case in ray_cases), "comparisons": len(PROBES) * len(RESOLUTIONS), "cases": ray_cases, "maxima": ray_maxima, }, "javascript_python": { "cases": len(cases), "javascript_runtime": "Node.js, executing the published browser module", "max_absolute_fraction_difference": maximum, "acceptance_tolerance": TOLERANCE, "worst_case_inputs": cases[worst], }, "interpretation": "Internal numerical verification of idealized geometry. External peer review, independent scientific replication and field validation are not documented.", } def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--data-dir", type=Path, default=Path(__file__).resolve().parent) parser.add_argument("--browser-model", type=Path, required=True) parser.add_argument("--node", default="node", help="Node.js executable; defaults to node on PATH.") args = parser.parse_args() try: report = reproduce(args.data_dir, args.browser_model, args.node) except (OSError, ValueError, KeyError, AssertionError, subprocess.TimeoutExpired) as error: print("Verification failed: " + str(error), file=sys.stderr) return 1 print(json.dumps(report, indent=2, ensure_ascii=False)) return 0 if __name__ == "__main__": raise SystemExit(main())