#!/usr/bin/env python3 """Split the owner surface strate around a small, opt-in native maze strate.""" from __future__ import annotations import argparse import hashlib import json from pathlib import Path def sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as stream: for block in iter(lambda: stream.read(1024 * 1024), b""): digest.update(block) return digest.hexdigest() def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--owner", type=Path, required=True) parser.add_argument("--out", type=Path, required=True) args = parser.parse_args() root = json.loads(args.owner.read_text(encoding="utf-8")) strates = root.get("strates") if not isinstance(strates, list): raise ValueError("owner input has no strates array") by_index = {int(row.get("index", -1)): row for row in strates if isinstance(row, dict)} if set(by_index) != {0, 1} or len(strates) != 2: raise ValueError("fixture requires the reviewed two-strate owner input") upper, surface = by_index[0], by_index[1] if (int(upper.get("asset", {}).get("GeneratorType", -1)) != 0 or int(surface.get("asset", {}).get("GeneratorType", -1)) != 4): raise ValueError("fixture requires TunnelNetwork over SurfaceWorld") if int(upper.get("passage_config", {}).get("Connections", -1)) != 1: raise ValueError("owner arrival passage count differs from the reviewed input") # Keep both resolved mouths in the small synthetic Maze layer. The authored # owner reach ranges are intentionally broad and can place a synthetic mouth # hundreds of metres beyond a four-chunk prototype layer. upper["passage_config"].update({"ReachMin": 32, "ReachMax": 32}) upper["asset"]["PassageConfig"].update({"ReachMin": 32, "ReachMax": 32}) maze = json.loads(json.dumps(surface)) maze.update({"index": 1, "top_chunk_z": -16, "bottom_chunk_z": -19, "height_chunks": 4}) maze["asset"].update({"StrateName": "L58 Native Lattice Maze", "GeneratorType": 3, "StrateHeightInChunks": 4}) maze["asset"].setdefault("MazeParams", {})["BoundarySealThickness"] = 8 maze["passage_config"]["Connections"] = 1 maze["passage_config"].update({"ReachMin": 32, "ReachMax": 32}) maze["asset"]["PassageConfig"].update({"Connections": 1, "ReachMin": 32, "ReachMax": 32}) lower = json.loads(json.dumps(surface)) lower.update({"index": 2, "top_chunk_z": -20, "bottom_chunk_z": -23, "height_chunks": 4}) lower["asset"].update({"StrateName": "L58 Lower Surface", "GeneratorType": 4, "StrateHeightInChunks": 4}) lower["passage_config"]["Connections"] = 1 lower["asset"]["PassageConfig"]["Connections"] = 1 root["total_strates"] = 3 root["strates"] = [upper, maze, lower] # Keep the legacy passage portals proportional to this compact native # prototype; the owner world remains at its authored scale. root.update({"owner_voxel_size_cm": 6.25, "owner_voxel_size_microns": 62500, "core_voxel_size_cm": 25, "core_voxel_size_microns": 250000, "owner_to_core_length_scale": 0.25}) args.out.parent.mkdir(parents=True, exist_ok=True) args.out.write_text(json.dumps(root, indent=2, sort_keys=True) + "\n", encoding="utf-8") print(f"[LatticeFixtureBuild] source={args.owner} source_sha256={sha256(args.owner)} " f"fixture={args.out} fixture_sha256={sha256(args.out)} " "strates=0:TunnelNetwork,1:Maze[4 chunks],2:SurfaceWorld[60 chunks] " "owner_input_untouched=true status=PASS") return 0 if __name__ == "__main__": raise SystemExit(main())