"""Audit completed supplemental surface observations without running solvers. Pass the campaign directory containing captures/, focused/, supplemental/ and supplemental_inputs/. Writes surface_audit_checks.json in that directory. This records method invariants and sampled values, not physical acceptance. """ import argparse import csv import hashlib import json import math from pathlib import Path parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("campaign_root", type=Path) ROOT = parser.parse_args().campaign_root.resolve() SUPPLEMENTAL = ROOT / "supplemental" def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest() def rows(path): with path.open() as source: data = list(csv.DictReader(source)) if any(None in r or any(v is None for v in r.values()) for r in data): raise ValueError(f"Malformed CSV row: {path}") return data def metrics(path): data = rows(path) if len({r["metric"] for r in data}) != len(data): raise ValueError(f"Duplicate metric: {path}") return {r["metric"]: float(r["value"]) for r in data} def vector(path): tokens = path.read_text().split() data = list(map(float, tokens[1:])) if len(data) != int(tokens[0]) or not all(map(math.isfinite, data)): raise ValueError(f"Malformed/nonfinite vector: {path}") return data def clean(value): if isinstance(value, dict): return {k: clean(v) for k, v in value.items()} if isinstance(value, list): return [clean(v) for v in value] if isinstance(value, float) and not math.isfinite(value): return None return value provenance = json.loads((SUPPLEMENTAL / "provenance.json").read_text()) derivation = json.loads((ROOT / "supplemental_inputs/between_bounds_derivation.json").read_text()) base = vector(Path(derivation["normalized_base"])) direction = vector(Path(derivation["direction"])) candidate = vector(Path(derivation["candidate"])) if not len(base) == len(direction) == len(candidate): raise ValueError("Midpoint candidate vector dimensions differ") alpha = derivation["alpha"] bounds = metrics(ROOT / "focused/n1_J0p10_iteration_2/frozen_enthalpy_bound.csv") result = { "source_commit": provenance["commit"], "binary_hash_matches": sha(SUPPLEMENTAL / "plateau_diagnostic") == provenance["binary_sha256"], "midpoint": { "alpha": alpha, "vector_size": len(candidate), "maximum_reconstruction_error": max(abs(b + alpha * d - c) for b, d, c in zip(base, direction, candidate)), "candidate_hash_matches": sha(Path(derivation["candidate"])) == derivation["candidate_sha256"], "bounds_match_original_scan": bounds["closure_alpha_h"] == derivation["closure_bound"] and bounds["pressure_alpha_h"] == derivation["pressure_bound"], "strictly_between_bounds": derivation["closure_bound"] < alpha < derivation["pressure_bound"], "exact_arithmetic_midpoint": alpha == 0.5 * (derivation["closure_bound"] + derivation["pressure_bound"]), }, "completed": [], "pending": [], } for case in json.loads((SUPPLEMENTAL / "cases.json").read_text()): case_id = case["id"] manifest = SUPPLEMENTAL / f"{case_id}_run.json" if not manifest.exists(): result["pending"].append(case_id) continue run = json.loads(manifest.read_text()) if "exit_code" not in run: result["pending"].append(case_id) continue folder = SUPPLEMENTAL / case_id args = case["arguments"] physical_path = Path(args[args.index("--probe-state") + 1]) direction_path = Path(args[args.index("--probe-direction") + 1]) capture_index = int(physical_path.parent.name.split("_")[-1]) original_focused = ROOT / "focused" / f"n1_J0p10_iteration_{capture_index}" capture_root = physical_path.parent.parent capture_manifest = json.loads((capture_root.parent / f"{capture_root.name}_run.json").read_text()) summary = metrics(folder / "surface_trace_summary.csv") carrier = rows(folder / "surface_trace_rows.csv") limits = rows(folder / "surface_trace_limits.csv") nodes = rows(folder / "surface_trace_nodes.csv") physical_base = vector(physical_path) normalized_direction = vector(direction_path) capture_metadata = dict(line.split("=", 1) for line in (physical_path.parent / "capture.txt").read_text().splitlines()) replay_alpha = alpha if "between_bounds" in case_id else float(capture_metadata["first_trial_alpha"]) data = { "id": case_id, "exit_code": run["exit_code"], "seconds": run["seconds"], "input_hash_count": len(run["input_state_hashes"]), "input_hash_mismatches": [p for p, h in run["input_state_hashes"].items() if sha(Path(p)) != h], "output_hash_count": len(run["output_hashes"]), "output_hash_mismatches": [p for p, h in run["output_hashes"].items() if sha(folder / p) != h], "unhashed_data_files": sorted(str(p.relative_to(folder)) for p in folder.rglob("*") if p.is_file() and p.suffix in (".txt", ".csv", ".json") and str(p.relative_to(folder)) not in run["output_hashes"]), "auxiliary_capture_input_hashes_match": all(sha(physical_path.parent / name) == capture_manifest["output_hashes"][str((physical_path.parent / name).relative_to(capture_root))] for name in ("normalized_base.txt", "normalized_residual.txt")), "frozen": metrics(folder / "frozen_input_checks.csv"), "frozen_residual_byte_identical_to_original_focus": (folder / "frozen_normalized_residual.txt").read_bytes() == (original_focused / "frozen_normalized_residual.txt").read_bytes(), "enthalpy_bound_byte_identical_to_original_focus": (folder / "frozen_enthalpy_bound.csv").read_bytes() == (original_focused / "frozen_enthalpy_bound.csv").read_bytes(), "direction_copy_byte_identical": direction_path.read_bytes() == (folder / "probe_normalized_correction.txt").read_bytes(), "physical_base_copy_byte_identical": physical_path.read_bytes() == (folder / "frozen_physical_base.txt").read_bytes(), "candidate_replay": rows(folder / "replayed_candidate.csv")[0], "surface_summary": summary, "csv_rows": {p.name: len(rows(p)) for p in sorted(folder.glob("*.csv"))}, "carrier_rows_complete": len(carrier) == int(summary["surface_row_count"]) and {int(r["surface_index"]) for r in carrier} == set(range(len(carrier))), "carrier_reduced_indices_unique": len({r["reduced_h_index"] for r in carrier}) == len(carrier), "carrier_root_offsets_correct": all(int(r["root_index"]) == int(summary["h_root_offset"]) + int(r["reduced_h_index"]) for r in carrier), "carrier_base_matches_physical_input": all(float(r["base_h"]) == physical_base[int(r["root_index"])] for r in carrier), "all_input_carrier_normalized_direction_coefficients_zero": all(normalized_direction[int(r["root_index"])] == 0 for r in carrier), "carrier_unit_step_arithmetic_error": max(abs(float(r["base_h"]) + float(r["direction_dh"]) - float(r["h_plus_dh"])) for r in carrier), "carrier_recomputed": {}, "carrier_summary_differences": {}, "limit_families_complete": {r["family"] for r in limits} == {"closure", "pressure"} and len(limits) == 2, "limit_partition_max_errors": {}, "nodes_by_family": {}, } for name in ("base_h", "direction_dh", "h_plus_dh"): values = [float(r[name]) for r in carrier] data["carrier_recomputed"][name] = { "minimum": min(values), "maximum": max(values), "maximum_absolute": max(map(abs, values)), "norm": math.sqrt(math.fsum(v * v for v in values)), "negative_count": sum(v < 0 for v in values), "nonzero_count": sum(v != 0 for v in values), } data["carrier_summary_differences"][name] = {stat: value - summary[f"{name}_{stat}"] for stat, value in data["carrier_recomputed"][name].items()} for suffix in ("h", "dh", "h_plus_dh"): data["limit_partition_max_errors"][suffix] = max(abs(float(r[f"full_{suffix}"]) - float(r[f"boundary_{suffix}"]) - float(r[f"interior_{suffix}"])) for r in limits) for limit in limits: family = limit["family"] subset = [r for r in nodes if r["family"] == family] data["nodes_by_family"][family] = { "rows": len(subset), "element_matches_limit": all(r["element"] == limit["element"] for r in subset), "node_indices_complete": len(subset) > 0 and len(subset) == int(subset[0]["node_count"]) and {int(r["local_node"]) for r in subset} == set(range(len(subset))), "fe_orders": sorted({int(r["fe_order"]) for r in subset}), "geometry_types": sorted({int(r["geometry_type"]) for r in subset}), "base_minimum": min(float(r["h"]) for r in subset), "union_prediction_minimum": min(float(r["h_plus_alpha_union_dh"]) for r in subset), "unit_step_minimum": min(float(r["h_plus_dh"]) for r in subset), "replay_alpha": replay_alpha, "replay_candidate_nodal_prediction_minimum": min(float(r["h"]) + replay_alpha * float(r["dh"]) for r in subset), "union_prediction_max_arithmetic_error": max(abs(float(r["h"]) + float(r["alpha_union"]) * float(r["dh"]) - float(r["h_plus_alpha_union_dh"])) for r in subset), "unit_step_max_arithmetic_error": max(abs(float(r["h"]) + float(r["dh"]) - float(r["h_plus_dh"])) for r in subset), } result["completed"].append(data) (ROOT / "surface_audit_checks.json").write_text(json.dumps(clean(result), indent=2) + "\n") print(json.dumps({"completed": [r["id"] for r in result["completed"]], "pending": result["pending"]}, indent=2))