diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/REPORT.md b/Standalone/Research/WorldAssemblerM3/Linux128/REPORT.md
new file mode 100644
index 0000000..8367d31
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/REPORT.md
@@ -0,0 +1,13 @@
+# L128 slab ownership
+
+Base `4041d4b`; branch `wip/l128-slab-ownership`; core version 226. Source stamp: `8682a9a088f0f02357b3b9722cda9b18a5ebce9886a13cba2d114bc0655d8c70`.
+
+Each route body uses half-open frame-plane slabs, so a boundary sample belongs to one segment. The required support is `S = r + max(4.0 + 0.21 + 0.125, 0.75 + 0.21) + 0.05 m`: bore radius plus the larger sweep/relief/corner or shell/relief reach, with a 5 cm audit margin. The largest body support is 7.885 m; the 4.5 m mouth profile reaches 8.885 m and is assigned to transition slabs. Local uniqueness requires curvature radius `R > S` (`κS < 1`). For equal adjacent chord lengths `L` and turn `θ`, this is `L / (2 sin(θ/2)) > S`. Nonlocal mutually-normal centerline pairs must be farther apart than the sum of their supports. Intersections between different passages remain a deterministic field union.
+
+All three owner-world routes pass the body curvature and self-separation checks; no route control points changed. Minimum body curvature radii are 11.565 m (0–1), 14.042 m (1–2), and 8.869 m (2–3), giving at least 0.984 m margin over body support. Route 0–1's 8 tight mouth joints and 5 nonlocal mouth pairs use transitions. The prepared/off-grid query paths share ownership. The audit tested 33,813 support samples: zero missing or duplicate owners, and both negative controls were detected.
+
+The slab projection supplies `s` to the continuous floor profile `h(s)`; round-distance does not choose floor height. Across 459 floor roots at nine stations, the largest adjacent root step was 1.765 mm and the largest absolute station offset was 7.884 mm. Seam audit: 4,900 shared samples, zero mismatches. Fast suite passed (264 checks, 5 diagnostic); walkability passed. Clang and GCC W1/W8/W12 hashes matched across all three datasets. The 23 L125 captures are in `captures/L128/` (19 pass; 4 low-contrast with geometry visible).
+
+**Performance bar failed.** Five interleaved runs per group across all four strates and W8/W12 put LOD0–2 readiness 14.8–28.0% behind L109 and 8.0–20.6% behind `4041d4b`. The five-run 30 m/s UE median also failed versus `4041d4b`: near coverage 31.46% vs 40.22%, moving far holes 5.66% vs 3.46%, p99 tick 12.42 ms vs 10.80 ms, and worst tick 14.35 ms vs 13.27 ms. L128 is not ready.
+
+Linux UE host build succeeded (27/27 actions, `-NoUBA -MaxParallelActions=4`); Unreal ran without `prlimit`. No commit made. Detailed logs are under `Saved/Linux/l128/`.
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/RunL128Captures.py b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128Captures.py
new file mode 100644
index 0000000..1d3c46c
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128Captures.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+"""Render the exact 23 L125 camera views with the L128 slab-ownership candidate."""
+from __future__ import annotations
+
+import importlib.util
+import json
+import math
+import os
+import sys
+from pathlib import Path
+
+sys.dont_write_bytecode = True
+
+ROOT = Path(__file__).resolve().parents[4]
+RESEARCH = Path(__file__).resolve().parent
+CAPTURES = RESEARCH / "captures"
+SAVED = ROOT / "Saved/Linux/l128/captures"
+BASELINE_INDEX = (ROOT / "Standalone/Research/WorldAssemblerM3/Linux125"
+ / "captures/L125/capture-index.json")
+LAYOUT = ROOT / "Saved/Linux/l128/hashes/owner4-surface-world-w12-clang.layout.json"
+CLANG = ROOT / os.environ.get("L128_CAPTURE_CLANG",
+ "Saved/Linux/l128/bin/VoxelForgeCoreHeadless-clang19")
+RENDERER = ROOT / os.environ.get("L128_CAPTURE_RENDERER",
+ "Saved/Linux/l128/bin/VoxelForgeOffscreenCapture-clang19")
+HELPER_PATH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux113/RunL113Captures.py"
+
+SPEC = importlib.util.spec_from_file_location("l113_capture_helpers", HELPER_PATH)
+if SPEC is None or SPEC.loader is None:
+ raise SystemExit("cannot load the verified L113 capture helpers")
+HELPERS = importlib.util.module_from_spec(SPEC)
+SPEC.loader.exec_module(HELPERS)
+HELPERS.RESEARCH = RESEARCH
+HELPERS.CAPTURES = CAPTURES
+HELPERS.SAVED = SAVED
+HELPERS.BINARIES = {"L128": CLANG}
+HELPERS.RENDERERS = {"L128": RENDERER}
+
+
+def main() -> int:
+ if any(not path.is_file() for path in (BASELINE_INDEX, LAYOUT, CLANG, RENDERER)):
+ raise SystemExit("missing L125 camera set, L128 layout, or capture binary")
+ baseline = json.loads(BASELINE_INDEX.read_text(encoding="utf-8"))
+ layout = json.loads(LAYOUT.read_text(encoding="utf-8"))
+ rows = []
+ CAPTURES.mkdir(parents=True, exist_ok=True)
+ SAVED.mkdir(parents=True, exist_ok=True)
+ for view in baseline["captures"]:
+ row = HELPERS.capture("L128", view, layout)
+ row["variant"] = "L128-slab-ownership-v226"
+ if view["kind"] == "rock-floor-close":
+ scene = ROOT / row["scene"]
+ anchor = HELPERS.nearest_surface_anchor(scene, view["target"], margin_m=5.0,
+ preferred_normal=(0.0, 0.0, 1.0), minimum_alignment=0.85)
+ alignment = HELPERS.dot(anchor["normal"], (0.0, 0.0, 1.0))
+ camera_distance = math.dist(row["camera_actual_m"], anchor["position_m"])
+ row.update({"floor_anchor_position_m": anchor["position_m"],
+ "floor_anchor_normal": anchor["normal"],
+ "closeup_camera_to_floor_distance_m": camera_distance,
+ "closeup_floor_normal_alignment": alignment,
+ "verified_upward_floor_normal": alignment >= 0.85})
+ if (not row["verified"] or not 2.0 <= camera_distance <= 3.2
+ or anchor["distance_m"] > 0.25 or alignment < 0.85
+ or row["drawn_triangles"] <= 0
+ or row["pixel_quality_status"] not in
+ ("pass", "low_contrast_geometry_visible")):
+ raise RuntimeError(f"L128 floor close-up failed at {view['name']}")
+ rows.append(row)
+ if len(rows) != len(baseline["captures"]) or len(rows) != 23:
+ raise RuntimeError(f"expected all 23 L125 views, captured {len(rows)}")
+ index = CAPTURES / "L128" / "capture-index.json"
+ index.parent.mkdir(parents=True, exist_ok=True)
+ index.write_text(json.dumps({"captures": rows}, indent=2) + "\n",
+ encoding="utf-8")
+
+ html = [" ",
+ "
L125 / L128 tunnel capture comparison ",
+ "",
+ "L125 / L128 slab ownership: identical views "]
+ old_by_name = {Path(row["capture"]).name: row for row in baseline["captures"]}
+ for row in rows:
+ name = Path(row["capture"]).name
+ old = old_by_name[name]
+ old_path = os.path.relpath(ROOT / "Standalone/Research/WorldAssemblerM3/Linux125"
+ / old["capture"], CAPTURES)
+ new_path = os.path.relpath(RESEARCH / row["capture"], CAPTURES)
+ html.extend(["", f"{row['passage']} — {row['station']} ",
+ f"{row['kind']} · L125 {old['pixel_quality_status']} · "
+ f"L128 {row['pixel_quality_status']}
", "",
+ f"
L125 ",
+ f"
L128 slab ownership ",
+ "
", " "])
+ (CAPTURES / "COMPARE.html").write_text("\n".join(html) + "\n",
+ encoding="utf-8")
+ print(f"[L128Captures] rendered={len(rows)} views index={index.relative_to(ROOT)}",
+ flush=True)
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/RunL128DensityProbe.py b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128DensityProbe.py
new file mode 100644
index 0000000..2fb20c6
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128DensityProbe.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+"""Probe reconstructed tunnel floor roots at the nine L119 stations."""
+from __future__ import annotations
+
+import csv
+import json
+import math
+import os
+import re
+import statistics
+import subprocess
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[4]
+OUT = ROOT / os.environ.get("L128_PROBE_DIR", "Saved/Linux/l128/floor-probe")
+BINARY = ROOT / os.environ.get("L128_PROBE_BINARY",
+ "Saved/Linux/l128/bin/VoxelForgeCoreHeadless-clang19")
+DATA = ROOT / "Standalone/data/owner_world.json"
+SLOPE = re.compile(
+ r"^\[L115DensitySlopeSample\] passage=(\S+) station=(\S+) s_m=([\d.]+) "
+ r".*?planned_floor_m=(-?[\d.]+) root_floor_m=(-?[\d.]+|nan) "
+ r"residual_m=(-?[\d.]+|nan)", re.M)
+
+
+def main() -> int:
+ OUT.mkdir(parents=True, exist_ok=True)
+ log, layout = OUT / "owner4-clang.log", OUT / "layout.json"
+ command = [
+ "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
+ "timeout", "1740s", str(BINARY), str(DATA), "--world-assembler-prototype",
+ "--stream-benchmark", "--stream-pipeline", "--workers=12", "--clip-radius=3",
+ "--max-clip-level=8", "--max-level=8",
+ "--camera=8,16,-372.2626953125,0,0", "--audit-resolved-layout-passages",
+ f"--resolved-layout-output={layout}",
+ ]
+ with log.open("w", encoding="utf-8") as stream:
+ result = subprocess.run(command, cwd=ROOT,
+ env={**os.environ, "VOXELFORGE_L115_DENSITY_PROFILE": "1"},
+ stdout=stream, stderr=subprocess.STDOUT, check=False, timeout=1740)
+ if result.returncode:
+ raise SystemExit(f"density probe failed: {log}; exit={result.returncode}")
+ text = log.read_text(encoding="utf-8", errors="replace")
+ groups: dict[tuple[str, str], list[dict]] = {}
+ for passage, station, distance, planned, root, residual in SLOPE.findall(text):
+ root_value = float(root) if root != "nan" else math.nan
+ residual_value = float(residual) if residual != "nan" else math.nan
+ groups.setdefault((passage, station), []).append({
+ "route_s_m": float(distance), "planned_floor_m": float(planned),
+ "root_floor_m": root_value, "offset_m": residual_value})
+ summary = []
+ with (OUT / "zero-crossing-offsets.csv").open("w", newline="", encoding="utf-8") as stream:
+ writer = csv.DictWriter(stream, fieldnames=("passage", "station", "route_s_m",
+ "planned_floor_m", "root_floor_m", "offset_m"))
+ writer.writeheader()
+ for (passage, station), samples in sorted(groups.items()):
+ samples.sort(key=lambda sample: sample["route_s_m"])
+ for sample in samples:
+ writer.writerow({"passage": passage, "station": station, **sample})
+ finite = [sample["offset_m"] for sample in samples
+ if math.isfinite(sample["offset_m"])]
+ adjacent_steps = [abs(right["offset_m"] - left["offset_m"])
+ for left, right in zip(samples, samples[1:])
+ if math.isfinite(left["offset_m"])
+ and math.isfinite(right["offset_m"])]
+ summary.append({"passage": passage, "station": station,
+ "samples": len(samples), "finite_roots": len(finite),
+ "max_abs_offset_m": max(map(abs, finite)) if finite else None,
+ "max_adjacent_root_step_m": max(adjacent_steps)
+ if adjacent_steps else None,
+ "median_abs_offset_m": statistics.median(map(abs, finite))
+ if finite else None,
+ "p95_abs_offset_m": sorted(map(abs, finite))[
+ min(len(finite)-1, math.ceil(0.95*len(finite))-1)]
+ if finite else None})
+ if not summary or any(item["samples"] != 51 for item in summary):
+ raise RuntimeError("density profile is missing 51-sample route stations")
+ worst_step = max(item["max_adjacent_root_step_m"] or 0.0 for item in summary)
+ if worst_step > 0.003:
+ raise RuntimeError(f"floor root jumps by {worst_step:.6f} m between 0.1 m probes")
+ (OUT / "zero-crossing-summary.json").write_text(
+ json.dumps(summary, indent=2) + "\n", encoding="utf-8")
+ print(f"[L128DensityProbe] exit={result.returncode} stations={len(summary)} "
+ f"log={log.relative_to(ROOT)}", flush=True)
+ return result.returncode
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/RunL128HashMatrix.py b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128HashMatrix.py
new file mode 100644
index 0000000..c886309
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128HashMatrix.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+"""Check Clang/GCC W1/W8/W12 hash determinism for L128."""
+from __future__ import annotations
+
+import json
+import os
+import re
+import subprocess
+import time
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[4]
+OUT = ROOT / os.environ.get("L128_HASH_DIR", "Saved/Linux/l128/hashes")
+DATASETS = {
+ "owner4": ROOT / "Standalone/data/owner_world.json",
+ "owner2": ROOT / "Standalone/data/regression/owner_world_2strate_l61.json",
+}
+BINARIES = {
+ "clang": ROOT / os.environ.get("L128_HASH_CLANG",
+ "Saved/Linux/l128/bin/VoxelForgeCoreHeadless-clang19"),
+ "gcc": ROOT / os.environ.get("L128_HASH_GCC",
+ "Saved/Linux/l128/bin/VoxelForgeCoreHeadless-l128-gcc"),
+}
+HASH = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
+STAMP = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=(\S+)$", re.M)
+
+
+def run(dataset: str, recipe: str, workers: int, compiler: str) -> dict:
+ OUT.mkdir(parents=True, exist_ok=True)
+ label = f"{dataset}-{recipe}-w{workers}-{compiler}"
+ log = OUT / f"{label}.log"
+ layout = OUT / f"{label}.layout.json"
+ command = [
+ "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
+ "timeout", "1740s", str(BINARIES[compiler]), str(DATASETS[dataset]),
+ f"--workers={workers}", "--world-assembler-prototype", "--stream-benchmark",
+ "--stream-pipeline", "--force-generate", "--clip-radius=3",
+ "--max-clip-level=8", "--max-level=8", f"--recipe={recipe}",
+ "--stream-hash", f"--resolved-layout-output={layout}",
+ ]
+ started = time.monotonic()
+ with log.open("w", encoding="utf-8") as stream:
+ result = subprocess.run(command, cwd=ROOT, stdout=stream,
+ stderr=subprocess.STDOUT, check=False, timeout=1740)
+ output = log.read_text(encoding="utf-8", errors="replace")
+ hashes = HASH.findall(output)
+ if result.returncode or len(hashes) != 12:
+ raise SystemExit(f"hash run failed or incomplete: {label}; exit={result.returncode} "
+ f"hashes={len(hashes)} log={log}")
+ row = {"dataset": dataset, "recipe": recipe, "workers": workers,
+ "compiler": compiler, "exit_code": result.returncode, "hashes": hashes,
+ "source_stamp": (STAMP.search(output).group(1)
+ if STAMP.search(output) else None),
+ "elapsed_s": round(time.monotonic() - started, 3),
+ "log": str(log.relative_to(ROOT))}
+ print("[L128HashRun] " + json.dumps(row, sort_keys=True), flush=True)
+ return row
+
+
+def main() -> int:
+ if any(not path.is_file() for path in (*DATASETS.values(), *BINARIES.values())):
+ raise SystemExit("missing L128 hash input")
+ rows = []
+ recipes = {"owner4": ("surface-world",),
+ "owner2": ("surface-world", "floating-islands")}
+ for dataset, dataset_recipes in recipes.items():
+ for recipe in dataset_recipes:
+ for workers in (1, 8, 12):
+ for compiler in ("clang", "gcc"):
+ rows.append(run(dataset, recipe, workers, compiler))
+ (OUT / "runs-partial.json").write_text(
+ json.dumps(rows, indent=2) + "\n", encoding="utf-8")
+ groups = {}
+ for dataset, dataset_recipes in recipes.items():
+ for recipe in dataset_recipes:
+ key = f"{dataset}/{recipe}"
+ group = [row for row in rows if row["dataset"] == dataset
+ and row["recipe"] == recipe]
+ reference = group[0]["hashes"]
+ stable = all(row["hashes"] == reference for row in group)
+ groups[key] = {
+ "all_worker_compiler_hashes_match": stable,
+ "source_stamps": sorted({row["source_stamp"] for row in group}),
+ "runs": [{"workers": row["workers"], "compiler": row["compiler"],
+ "log": row["log"]} for row in group],
+ }
+ if not stable:
+ raise SystemExit(f"determinism mismatch: {key}")
+ summary = {"runs": rows, "groups": groups}
+ (OUT / "summary.json").write_text(json.dumps(summary, indent=2) + "\n",
+ encoding="utf-8")
+ baseline_dir = ROOT / "Standalone/Tools/verify/baselines/owner-hash/canonical"
+ for dataset, recipe, style, baseline_name in (
+ ("owner4", "surface-world", 1,
+ "owner-hash-owner4-surface-world-style1-v226.baseline"),
+ ("owner2", "surface-world", 1,
+ "owner-hash-surface-world-style1-v226.baseline"),
+ ("owner2", "floating-islands", 2,
+ "owner-hash-floating-islands-style2-v226.baseline"),
+ ):
+ canonical = next(row for row in rows if row["dataset"] == dataset
+ and row["recipe"] == recipe and row["workers"] == 12
+ and row["compiler"] == "clang")
+ baseline = baseline_dir / baseline_name
+ baseline.write_text("\n".join(canonical["hashes"]) + "\n",
+ encoding="utf-8")
+ print("[L128HashSummary] " + json.dumps(groups, sort_keys=True), flush=True)
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/RunL128Timing.py b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128Timing.py
new file mode 100644
index 0000000..7276f8b
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128Timing.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+"""Five interleaved L80 readiness runs for L109, 4041d4b and L128."""
+from __future__ import annotations
+
+import json
+import os
+import re
+import statistics
+import subprocess
+import time
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[4]
+OUT = ROOT / os.environ.get("L128_TIMING_DIR", "Saved/Linux/l128/timing")
+DATA = ROOT / "Standalone/data/owner_world.json"
+BINARIES = {
+ "L109": ROOT / "Saved/Linux/l109/bin-final/VoxelForgeCoreHeadless-l109-clang",
+ "4041d4b": ROOT / "Saved/Linux/l127/bin-clang/VoxelForgeCoreHeadless-l127-clang",
+ "L128": ROOT / os.environ.get("L128_CANDIDATE_BINARY",
+ "Saved/Linux/l128/bin/VoxelForgeCoreHeadless-clang19"),
+}
+CAMERAS = {
+ 0: (8.0, 16.0, -372.2626953125),
+ 1: (25.8369140625, 3.19921875, -737.0),
+ 2: (19.166015625, -14.2001953125, -753.3740234375),
+ 3: (-20.0625, -5.068359375, -900.353515625),
+}
+PIPELINE = re.compile(r"^\[StreamPipeline\] (.*)$", re.M)
+FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
+NEAR = re.compile(
+ r"^\[WorldAssemblerNearLODReady\] lods=0-2 tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$",
+ re.M)
+
+
+def run(strate: int, workers: int, version: str, phase: str, replicate: int) -> dict:
+ OUT.mkdir(parents=True, exist_ok=True)
+ label = f"s{strate}-w{workers}-{version}-{phase}{replicate}"
+ log = OUT / f"{label}.log"
+ camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0"
+ command = [
+ "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
+ "timeout", "1740s", str(BINARIES[version]), str(DATA),
+ "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
+ f"--workers={workers}", "--clip-radius=3", "--max-clip-level=8",
+ "--max-level=8", f"--camera={camera}", "--profile-lod-work",
+ "--stream-scheduler-policy=3",
+ ]
+ started = time.monotonic()
+ with log.open("w", encoding="utf-8") as output:
+ result = subprocess.run(command, cwd=ROOT, stdout=output,
+ stderr=subprocess.STDOUT, check=False, timeout=1740)
+ content = log.read_text(encoding="utf-8", errors="replace")
+ pipeline_match, near_match = PIPELINE.search(content), NEAR.search(content)
+ if result.returncode or pipeline_match is None or near_match is None:
+ raise SystemExit(f"readiness run failed or incomplete: {log}; exit={result.returncode}")
+ pipeline = dict(FIELDS.findall(pipeline_match.group(1)))
+ row = {"strate": strate, "workers": workers, "version": version,
+ "phase": phase, "replicate": replicate, "exit_code": result.returncode,
+ "wall_s": round(time.monotonic() - started, 3),
+ "lod02_ready_s": float(near_match.group(3)),
+ "whole_view_ready_s": float(pipeline["whole_view_ready"].removesuffix("s")),
+ "whole_tiles": int(pipeline["whole_tiles"].split("/")[0]),
+ "log": str(log.relative_to(ROOT))}
+ print("[L128TimingRun] " + json.dumps(row, sort_keys=True), flush=True)
+ return row
+
+
+def cpu_idle_percent(interval_s: float = 2.0) -> float:
+ def totals() -> tuple[int, int]:
+ fields = Path("/proc/stat").read_text(encoding="utf-8").splitlines()[0].split()
+ values = [int(value) for value in fields[1:]]
+ return sum(values), values[3] + (values[4] if len(values) > 4 else 0)
+ before_total, before_idle = totals()
+ time.sleep(interval_s)
+ after_total, after_idle = totals()
+ return 100.0 * (after_idle-before_idle) / max(1, after_total-before_total)
+
+
+def main() -> int:
+ if not DATA.is_file() or any(not binary.is_file() for binary in BINARIES.values()):
+ raise SystemExit("missing L109/4041d4b/L128 timing input")
+ OUT.mkdir(parents=True, exist_ok=True)
+ load_1m, idle_pct = os.getloadavg()[0], cpu_idle_percent()
+ uptime = subprocess.run(["uptime"], cwd=ROOT, text=True,
+ capture_output=True, check=True).stdout.strip()
+ top = subprocess.run(["ps", "-eo", "pid,pcpu,comm", "--sort=-pcpu"],
+ cwd=ROOT, text=True, capture_output=True, check=True).stdout
+ (OUT / "machine-load-before.txt").write_text(
+ f"uptime: {uptime}\n1-minute load: {load_1m:.2f}\n"
+ f"2-second CPU idle: {idle_pct:.1f}%\ntop CPU users:\n{top}", encoding="utf-8")
+ print(f"[L128TimingGate] load_1m={load_1m:.2f} cpu_idle_2s={idle_pct:.1f}%",
+ flush=True)
+ if load_1m >= 0.9 or idle_pct < 97.0:
+ raise SystemExit("timing refused: machine is above the quiet-load gate")
+
+ rows = []
+ versions = ("L109", "4041d4b", "L128")
+ for strate in range(4):
+ for workers in (8, 12):
+ for version in versions:
+ run(strate, workers, version, "warmup", 0)
+ for replicate in range(1, 6):
+ offset = (replicate - 1) % len(versions)
+ order = versions[offset:] + versions[:offset]
+ for version in order:
+ rows.append(run(strate, workers, version, "measured", replicate))
+ (OUT / "runs-partial.json").write_text(
+ json.dumps(rows, indent=2) + "\n", encoding="utf-8")
+
+ summary = []
+ for strate in range(4):
+ for workers in (8, 12):
+ item = {"strate": strate, "workers": workers, "replicates": 5}
+ medians = {}
+ for version in versions:
+ group = [row for row in rows if row["strate"] == strate
+ and row["workers"] == workers and row["version"] == version]
+ medians[version] = {}
+ for key in ("lod02_ready_s", "whole_view_ready_s"):
+ values = [row[key] for row in group]
+ medians[version][key] = statistics.median(values)
+ item[f"{version}_{key}_values"] = values
+ item[f"{version}_{key}_median"] = medians[version][key]
+ for comparison in ("L109", "4041d4b"):
+ for key in ("lod02_ready_s", "whole_view_ready_s"):
+ item[f"L128_vs_{comparison}_{key}_delta_pct"] = round(
+ 100.0 * (medians["L128"][key] / medians[comparison][key]-1.0), 2)
+ summary.append(item)
+ (OUT / "summary.json").write_text(
+ json.dumps({"runs": rows, "summary": summary}, indent=2) + "\n",
+ encoding="utf-8")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/RunL128UEMovement.py b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128UEMovement.py
new file mode 100644
index 0000000..2197c0f
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/RunL128UEMovement.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+"""Run five UE 30 m/s movement trials and compare with the L127 4041d4b baseline."""
+from __future__ import annotations
+
+import importlib.util
+import json
+import os
+import re
+import statistics
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[4]
+RESEARCH = ROOT / "Standalone/Research/WorldAssemblerM3"
+OUT = ROOT / "Saved/Linux/l128/ue"
+HOST = Path("/home/jahni/VFHost")
+EDITOR = Path("/home/jahni/UnrealEngine/Engine/Binaries/Linux/UnrealEditor-Cmd")
+MOVEMENT_PATH = RESEARCH / "Linux121/RunL121Movement.py"
+BASELINE_PATH = ROOT / "Saved/Linux/l127/ue/movement-pairs-summary.json"
+
+
+def load_movement_module():
+ spec = importlib.util.spec_from_file_location("l128_movement", MOVEMENT_PATH)
+ if spec is None or spec.loader is None:
+ raise RuntimeError(f"cannot load UE movement runner: {MOVEMENT_PATH}")
+ module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(module)
+ return module
+
+
+def main() -> int:
+ if not BASELINE_PATH.is_file():
+ raise SystemExit(f"missing 4041d4b movement baseline: {BASELINE_PATH}")
+ OUT.mkdir(parents=True, exist_ok=True)
+ module = load_movement_module()
+ module.HOST = HOST
+ module.EDITOR = EDITOR
+ module.OUT = OUT / "movement"
+ module.HOST_SAVED = HOST / "Saved/Linux/l128/host"
+ module.HOST_OUT = HOST / "Plugins/VoxelForge/Saved/Linux/l128/movement"
+ module.RUN_TIMEOUT_S = 1740
+ module.HOST_OUT.mkdir(parents=True, exist_ok=True)
+ os.environ["XDG_CONFIG_HOME"] = str(OUT / "config")
+
+ rows = []
+ for repetition in range(1, 6):
+ row = module.run_unreal("L128", repetition)
+ events = module.parse_events(ROOT / row["trace"])
+ row["supplemental_far_applies_total"] = sum(
+ int(event.get("supplemental_far_applies", 0))
+ for event in events if event.get("type") == "apply_frame")
+ row["supplemental_far_applies_moving"] = sum(
+ int(event.get("supplemental_far_applies", 0))
+ for event in events if event.get("type") == "apply_frame"
+ and float(event.get("speed_cm_s", 0.0)) >= 50.0)
+ if row.get("effective_tile_slots") != 8 or row["supplemental_far_applies_moving"] <= 0:
+ raise SystemExit(f"movement run missed the configured apply lane: {row}")
+ rows.append(row)
+ (OUT / "movement-runs-partial.json").write_text(
+ json.dumps(rows, indent=2, sort_keys=True) + "\n", encoding="utf-8")
+ print("[L128UEMovement] " + json.dumps({
+ key: row[key] for key in (
+ "condition", "repetition", "near_ready_moving_mean_pct",
+ "far_holes_moving_mean_pct", "game_thread_tick_p99_ms",
+ "game_thread_tick_max_ms", "supplemental_far_applies_moving",
+ "wall_s", "trace")}, sort_keys=True), flush=True)
+
+ baseline_doc = json.loads(BASELINE_PATH.read_text(encoding="utf-8"))
+ baseline_rows = [row for row in baseline_doc["runs"]
+ if row["condition"] == "merge"]
+ if len(baseline_rows) != 5:
+ raise SystemExit(f"expected five 4041d4b baseline runs, got {len(baseline_rows)}")
+ metrics = ("near_ready_moving_mean_pct", "far_holes_moving_mean_pct",
+ "game_thread_tick_p99_ms", "game_thread_tick_max_ms")
+ baseline = {metric: statistics.median(row[metric] for row in baseline_rows)
+ for metric in metrics}
+ candidate = {metric: statistics.median(row[metric] for row in rows)
+ for metric in metrics}
+ build_log = (ROOT / "Saved/Linux/l128/build-clang.log").read_text(
+ encoding="utf-8", errors="replace")
+ stamp_match = re.search(r"^Source stamp: (\S+)$", build_log, re.M)
+ if stamp_match is None:
+ raise SystemExit("missing L128 Clang source stamp")
+ summary = {
+ "baseline": {"commit": "4041d4b", "runs": len(baseline_rows),
+ "metrics": baseline},
+ "candidate": {"source_stamp": stamp_match.group(1),
+ "runs": len(rows), "metrics": candidate},
+ "candidate_vs_4041d4b_delta": {
+ metric: candidate[metric] - baseline[metric] for metric in metrics},
+ "bar_pass": candidate["near_ready_moving_mean_pct"]
+ > baseline["near_ready_moving_mean_pct"]
+ and all(candidate[metric] <= baseline[metric] for metric in (
+ "far_holes_moving_mean_pct", "game_thread_tick_p99_ms",
+ "game_thread_tick_max_ms")),
+ }
+ (OUT / "movement-summary.json").write_text(
+ json.dumps({"runs": rows, "summary": summary}, indent=2, sort_keys=True) + "\n",
+ encoding="utf-8")
+ print("[L128UEMovementSummary] " + json.dumps(summary, sort_keys=True), flush=True)
+ if not summary["bar_pass"]:
+ raise SystemExit("L128 UE movement medians missed the 4041d4b coverage/tick bar")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/COMPARE.html b/Standalone/Research/WorldAssemblerM3/Linux128/captures/COMPARE.html
new file mode 100644
index 0000000..6be231f
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/captures/COMPARE.html
@@ -0,0 +1,188 @@
+
+L125 / L128 tunnel capture comparison
+
+L125 / L128 slab ownership: identical views
+
+passage/0-1/0 — rock-floor/401.7m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — rock-floor/792.8m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — rock-floor/1634.5m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/1-2/0 — rock-floor/27.0m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/1-2/0 — rock-floor/52.9m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/1-2/0 — rock-floor/78.9m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/2-3/0 — rock-floor/323.4m
+rock-floor-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible
+
+
L125
+
L128 slab ownership
+
+
+
+passage/2-3/0 — rock-floor/333.4m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/2-3/0 — rock-floor/343.4m
+rock-floor-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — section-1/4m-outside
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — section-1/4m-interior-wall
+open-air-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — section-2/4m-outside
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — section-2/4m-interior-wall
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — section-3/4m-outside
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/0-1/0 — section-3/4m-interior-wall
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/1-2/0 — section-1/4m-outside
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/1-2/0 — section-1/4m-interior-wall
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/1-2/0 — section-2/4m-outside
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/1-2/0 — section-2/4m-interior-wall
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/2-3/0 — section-1/4m-outside
+open-air-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible
+
+
L125
+
L128 slab ownership
+
+
+
+passage/2-3/0 — section-1/4m-interior-wall
+open-air-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible
+
+
L125
+
L128 slab ownership
+
+
+
+passage/2-3/0 — section-2/4m-outside
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
+
+passage/2-3/0 — section-2/4m-interior-wall
+open-air-close · L125 pass · L128 pass
+
+
L125
+
L128 slab ownership
+
+
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/capture-index.json b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/capture-index.json
new file mode 100644
index 0000000..f7cb127
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/capture-index.json
@@ -0,0 +1,1562 @@
+{
+ "captures": [
+ {
+ "name": "passage-0-1-0-rock-floor-station-1",
+ "passage": "passage/0-1/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/401.7m",
+ "camera": [
+ -9.24648786798055,
+ 19.798675033837775,
+ -443.9636296749357
+ ],
+ "target": [
+ -7.026884524505579,
+ 20.857335392121104,
+ -445.66373993191075
+ ],
+ "yaw": 64.50075976736525,
+ "pitch": -34.65771934187305,
+ "focus": [
+ -7.026884524505579,
+ 20.857335392121104,
+ -445.66373993191075
+ ],
+ "center_z": -445.66373993191075,
+ "route_distance_m": 401.6612010038529,
+ "requested_route_distance_m": 401.6612010038529,
+ "route_length_m": 2026.6238040154117,
+ "planned_floor_m": -445.66373993191075,
+ "planned_grade_deg": 10.372328677972732,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-rock-floor-station-1.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-1.vfmesh",
+ "drawn_triangles": 122264,
+ "source_triangles": 146688,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 401.6612010038529,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -9.24648786798055,
+ 19.798675033837775,
+ -443.9636296749357
+ ],
+ "target_actual_m": [
+ -7.026884524505579,
+ 20.857335392121104,
+ -445.66373993191075
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-1-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-1-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-1-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ -7.026885053959959,
+ 20.857335155432953,
+ -445.66374310012867
+ ],
+ "floor_anchor_normal": [
+ 0.16438021494383692,
+ 0.07357583212203939,
+ 0.9836491965444629
+ ],
+ "closeup_camera_to_floor_distance_m": 2.989612610955708,
+ "closeup_floor_normal_alignment": 0.9836491965444629,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-0-1-0-rock-floor-station-2",
+ "passage": "passage/0-1/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/792.8m",
+ "camera": [
+ -0.021280083711839648,
+ -26.43771312964049,
+ -514.3617561596035
+ ],
+ "target": [
+ -2.4714859241065525,
+ -26.227784739959716,
+ -516.0616688299093
+ ],
+ "yaw": -85.10297944703369,
+ "pitch": -34.654210347383824,
+ "focus": [
+ -2.4714859241065525,
+ -26.227784739959716,
+ -516.0616688299093
+ ],
+ "center_z": -516.0616688299093,
+ "route_distance_m": 792.8284020077059,
+ "requested_route_distance_m": 792.8284020077059,
+ "route_length_m": 2026.6238040154117,
+ "planned_floor_m": -516.0616688299093,
+ "planned_grade_deg": 10.367725129664787,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-rock-floor-station-2.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-2.vfmesh",
+ "drawn_triangles": 586094,
+ "source_triangles": 626214,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 792.8284020077059,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -0.021280083711839648,
+ -26.43771312964049,
+ -514.3617561596035
+ ],
+ "target_actual_m": [
+ -2.4714859241065525,
+ -26.227784739959716,
+ -516.0616688299093
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-2-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-2-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-2-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ -2.471476828908,
+ -26.227785976319144,
+ -516.0617189697925
+ ],
+ "floor_anchor_normal": [
+ -0.179115780575022,
+ 0.024140888419756926,
+ 0.9835317761289187
+ ],
+ "closeup_camera_to_floor_distance_m": 2.9895496409822853,
+ "closeup_floor_normal_alignment": 0.9835317761289187,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-0-1-0-rock-floor-station-3",
+ "passage": "passage/0-1/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/1634.5m",
+ "camera": [
+ 15.717287112180728,
+ 19.71739973195528,
+ -665.8352816543407
+ ],
+ "target": [
+ 17.336220092016376,
+ 17.86620742417785,
+ -667.5348848643227
+ ],
+ "yaw": 138.82915885966676,
+ "pitch": -34.64871452830556,
+ "focus": [
+ 17.336220092016376,
+ 17.86620742417785,
+ -667.5348848643227
+ ],
+ "center_z": -667.5348848643227,
+ "route_distance_m": 1634.4566030115589,
+ "requested_route_distance_m": 1634.4566030115589,
+ "route_length_m": 2026.6238040154117,
+ "planned_floor_m": -667.5348848643227,
+ "planned_grade_deg": 10.360515186362372,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-rock-floor-station-3.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-3.vfmesh",
+ "drawn_triangles": 137258,
+ "source_triangles": 166706,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 1634.4566030115589,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 15.717287112180728,
+ 19.71739973195528,
+ -665.8352816543407
+ ],
+ "target_actual_m": [
+ 17.336220092016376,
+ 17.86620742417785,
+ -667.5348848643227
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-3-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-3-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-rock-floor-station-3-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ 17.33622182815858,
+ 17.866205324064538,
+ -667.534869956066
+ ],
+ "floor_anchor_normal": [
+ 0.11463807621472542,
+ -0.13864390562764303,
+ 0.9836848981834071
+ ],
+ "closeup_camera_to_floor_distance_m": 2.9893930396931125,
+ "closeup_floor_normal_alignment": 0.9836848981834071,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-1-2-0-rock-floor-station-1",
+ "passage": "passage/1-2/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/27.0m",
+ "camera": [
+ 15.990262769683945,
+ 2.495369317804175,
+ -736.4846720823747
+ ],
+ "target": [
+ 15.354493464592624,
+ 4.868558240151556,
+ -738.1970266319915
+ ],
+ "yaw": -14.99718988160138,
+ "pitch": -34.875140724394136,
+ "focus": [
+ 15.354493464592624,
+ 4.868558240151556,
+ -738.1970266319915
+ ],
+ "center_z": -738.1970266319915,
+ "route_distance_m": 26.963657939523273,
+ "requested_route_distance_m": 26.963657939523273,
+ "route_length_m": 114.99063175809309,
+ "planned_floor_m": -738.1970266319915,
+ "planned_grade_deg": 10.657740387934142,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-1-2-0-rock-floor-station-1.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-1.vfmesh",
+ "drawn_triangles": 652040,
+ "source_triangles": 719644,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 26.963657939523273,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 15.990262769683945,
+ 2.495369317804175,
+ -736.4846720823747
+ ],
+ "target_actual_m": [
+ 15.354493464592624,
+ 4.868558240151556,
+ -738.1970266319915
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-1-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-1-render.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-1-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ 15.354124807038394,
+ 4.869920275450426,
+ -738.1895881032126
+ ],
+ "floor_anchor_normal": [
+ -0.047307387705878,
+ 0.17883124580074233,
+ 0.9827417751341397
+ ],
+ "closeup_camera_to_floor_distance_m": 2.9916387475909154,
+ "closeup_floor_normal_alignment": 0.9827417751341397,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-1-2-0-rock-floor-station-2",
+ "passage": "passage/1-2/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/52.9m",
+ "camera": [
+ -2.48434493546405,
+ 15.983647301702653,
+ -741.2835409028854
+ ],
+ "target": [
+ -4.76517685476837,
+ 15.070128626649932,
+ -742.995373541633
+ ],
+ "yaw": -111.82708648318167,
+ "pitch": -34.86587426337977,
+ "focus": [
+ -4.76517685476837,
+ 15.070128626649932,
+ -742.995373541633
+ ],
+ "center_z": -742.995373541633,
+ "route_distance_m": 52.927315879046546,
+ "requested_route_distance_m": 52.927315879046546,
+ "route_length_m": 114.99063175809309,
+ "planned_floor_m": -742.995373541633,
+ "planned_grade_deg": 10.645569354114926,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-1-2-0-rock-floor-station-2.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-2.vfmesh",
+ "drawn_triangles": 636134,
+ "source_triangles": 700530,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 52.927315879046546,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -2.48434493546405,
+ 15.983647301702653,
+ -741.2835409028854
+ ],
+ "target_actual_m": [
+ -4.76517685476837,
+ 15.070128626649932,
+ -742.995373541633
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-2-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-2-render.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-2-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ -4.766428465537912,
+ 15.069671584786441,
+ -742.988228337538
+ ],
+ "floor_anchor_normal": [
+ -0.1744301807701029,
+ -0.061608715063684795,
+ 0.9827402903436447
+ ],
+ "closeup_camera_to_floor_distance_m": 2.9915240428933867,
+ "closeup_floor_normal_alignment": 0.9827402903436447,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-1-2-0-rock-floor-station-3",
+ "passage": "passage/1-2/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/78.9m",
+ "camera": [
+ -13.44544511010513,
+ -3.995230772069307,
+ -746.0839041050349
+ ],
+ "target": [
+ -12.287009401722694,
+ -6.161841337747165,
+ -747.7963166548619
+ ],
+ "yaw": 151.8676321960706,
+ "pitch": -34.87617050502889,
+ "focus": [
+ -12.287009401722694,
+ -6.161841337747165,
+ -747.7963166548619
+ ],
+ "center_z": -747.7963166548619,
+ "route_distance_m": 78.89097381856982,
+ "requested_route_distance_m": 78.89097381856982,
+ "route_length_m": 114.99063175809309,
+ "planned_floor_m": -747.7963166548619,
+ "planned_grade_deg": 10.659092990906162,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-1-2-0-rock-floor-station-3.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-3.vfmesh",
+ "drawn_triangles": 580464,
+ "source_triangles": 639368,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 78.89097381856982,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -13.44544511010513,
+ -3.995230772069307,
+ -746.0839041050349
+ ],
+ "target_actual_m": [
+ -12.287009401722694,
+ -6.161841337747165,
+ -747.7963166548619
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-3-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-3-render.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-rock-floor-station-3-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ -12.283352972838873,
+ -6.167679829029396,
+ -747.554756449892
+ ],
+ "floor_anchor_normal": [
+ 0.09692807602747124,
+ -0.15782686841357624,
+ 0.9826981366036961
+ ],
+ "closeup_camera_to_floor_distance_m": 2.8693901200350096,
+ "closeup_floor_normal_alignment": 0.9826981366036961,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-2-3-0-rock-floor-station-1",
+ "passage": "passage/2-3/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/323.4m",
+ "camera": [
+ 6.997568341188331,
+ -14.934306981606339,
+ -869.3796844648476
+ ],
+ "target": [
+ 9.102823911740126,
+ -13.661883549736208,
+ -871.0755965556104
+ ],
+ "yaw": 58.85109570948622,
+ "pitch": -34.583159686285406,
+ "focus": [
+ 9.102823911740126,
+ -13.661883549736208,
+ -871.0755965556104
+ ],
+ "center_z": -871.0755965556104,
+ "route_distance_m": 323.4481319239866,
+ "requested_route_distance_m": 323.4481319239866,
+ "route_length_m": 494.0722798830563,
+ "planned_floor_m": -871.0755965556104,
+ "planned_grade_deg": 10.274530613220444,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-2-3-0-rock-floor-station-1.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-1.vfmesh",
+ "drawn_triangles": 474960,
+ "source_triangles": 502358,
+ "verified": true,
+ "pixel_quality_status": "low_contrast_geometry_visible",
+ "route_distance_actual_m": 323.4481319239866,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 6.997568341188331,
+ -14.934306981606339,
+ -869.3796844648476
+ ],
+ "target_actual_m": [
+ 9.102823911740126,
+ -13.661883549736208,
+ -871.0755965556104
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-1-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-1-render.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-1-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ 9.103799793973732,
+ -13.661094033901383,
+ -871.068656948616
+ ],
+ "floor_anchor_normal": [
+ 0.14021616794161246,
+ 0.11018123609139711,
+ 0.9839713011369495
+ ],
+ "closeup_camera_to_floor_distance_m": 2.9849472681829123,
+ "closeup_floor_normal_alignment": 0.9839713011369495,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-2-3-0-rock-floor-station-2",
+ "passage": "passage/2-3/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/333.4m",
+ "camera": [
+ 14.426607883839745,
+ -8.501776133009574,
+ -871.1605818845352
+ ],
+ "target": [
+ 15.203729308783775,
+ -6.16777561793481,
+ -872.8561420785873
+ ],
+ "yaw": 18.41553205389999,
+ "pitch": -34.576909662847896,
+ "focus": [
+ 15.203729308783775,
+ -6.16777561793481,
+ -872.8561420785873
+ ],
+ "center_z": -872.8561420785873,
+ "route_distance_m": 333.4481319239866,
+ "requested_route_distance_m": 333.4481319239866,
+ "route_length_m": 494.0722798830563,
+ "planned_floor_m": -872.8561420785873,
+ "planned_grade_deg": 10.266334408339132,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-2-3-0-rock-floor-station-2.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-2.vfmesh",
+ "drawn_triangles": 494500,
+ "source_triangles": 524338,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 333.4481319239866,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 14.426607883839745,
+ -8.501776133009574,
+ -871.1605818845352
+ ],
+ "target_actual_m": [
+ 15.203729308783775,
+ -6.16777561793481,
+ -872.8561420785873
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-2-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-2-render.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-2-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ 15.204108325185125,
+ -6.1664350574610705,
+ -872.848494535829
+ ],
+ "floor_anchor_normal": [
+ 0.0468360027958031,
+ 0.17218671405633393,
+ 0.9839502651783747
+ ],
+ "closeup_camera_to_floor_distance_m": 2.9845224063213145,
+ "closeup_floor_normal_alignment": 0.9839502651783747,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-2-3-0-rock-floor-station-3",
+ "passage": "passage/2-3/0",
+ "kind": "rock-floor-close",
+ "station": "rock-floor/343.4m",
+ "camera": [
+ 16.176045301879554,
+ 1.1336183974400118,
+ -872.9426489764151
+ ],
+ "target": [
+ 15.465325445603714,
+ 3.4887437417106955,
+ -874.6379150751349
+ ],
+ "yaw": -16.792543840841383,
+ "pitch": -34.57168620892087,
+ "focus": [
+ 15.465325445603714,
+ 3.4887437417106955,
+ -874.6379150751349
+ ],
+ "center_z": -874.6379150751349,
+ "route_distance_m": 343.4481319239866,
+ "requested_route_distance_m": 343.4481319239866,
+ "route_length_m": 494.0722798830563,
+ "planned_floor_m": -874.6379150751349,
+ "planned_grade_deg": 10.259484647608062,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-2-3-0-rock-floor-station-3.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-3.vfmesh",
+ "drawn_triangles": 485352,
+ "source_triangles": 512660,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 343.4481319239866,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": null,
+ "closeup_target_surface_distance_m": null,
+ "closeup_predicted_target_offset_m": null,
+ "closeup_wall_normal_alignment": null,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 16.176045301879554,
+ 1.1336183974400118,
+ -872.9426489764151
+ ],
+ "target_actual_m": [
+ 15.465325445603714,
+ 3.4887437417106955,
+ -874.6379150751349
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-3-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-3-render.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-rock-floor-station-3-quality.log"
+ ],
+ "floor_anchor_position_m": [
+ 15.464091528009144,
+ 3.4924186701988678,
+ -874.5280427606272
+ ],
+ "floor_anchor_normal": [
+ -0.061689200676463656,
+ 0.16755705537563617,
+ 0.9839304221913991
+ ],
+ "closeup_camera_to_floor_distance_m": 2.9298959629846824,
+ "closeup_floor_normal_alignment": 0.9839304221913991,
+ "verified_upward_floor_normal": true
+ },
+ {
+ "name": "passage-0-1-0-openair-1-4m-outside",
+ "passage": "passage/0-1/0",
+ "kind": "open-air-close",
+ "station": "section-1/4m-outside",
+ "camera": [
+ 13.176702021211483,
+ 7.149068417345486,
+ -374.402
+ ],
+ "target": [
+ 9.197121888971225,
+ 7.5527291301707695,
+ -374.402
+ ],
+ "yaw": -84.20812706837869,
+ "pitch": 0.0,
+ "focus": [
+ 7.272,
+ 7.748,
+ -373.197
+ ],
+ "center_z": -373.197,
+ "open_air_section": 1,
+ "closeup_side": "outside",
+ "closeup_preferred_normal": [
+ 0.9948950330600643,
+ -0.1009151782063209,
+ 0.0
+ ],
+ "camera_target_distance_m": 4.000000000000001,
+ "route_distance_m": 8.3545,
+ "requested_route_distance_m": 8.3545,
+ "route_length_m": 2026.6238040154117,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-openair-1-4m-outside.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-outside.vfmesh",
+ "drawn_triangles": 275333,
+ "source_triangles": 327761,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 8.3545,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 3.999999999999992,
+ "closeup_target_surface_distance_m": 0.794053842406799,
+ "closeup_predicted_target_offset_m": 0.794053842406799,
+ "closeup_wall_normal_alignment": 0.9449803535183738,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 12.920589450293994,
+ 7.974422667153486,
+ -375.0086678277374
+ ],
+ "target_actual_m": [
+ 9.12386703491211,
+ 8.0,
+ -373.75
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-outside-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-outside-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-outside-quality.log"
+ ]
+ },
+ {
+ "name": "passage-0-1-0-openair-1-4m-interior-wall",
+ "passage": "passage/0-1/0",
+ "kind": "open-air-close",
+ "station": "section-1/4m-interior-wall",
+ "camera": [
+ 7.395778712540976,
+ 3.8749008126934172,
+ -374.89997477205173
+ ],
+ "target": [
+ 8.778272394312646,
+ 7.595214286886338,
+ -374.402
+ ],
+ "yaw": 20.38540702862518,
+ "pitch": 7.1515181408188955,
+ "focus": [
+ 7.272,
+ 7.748,
+ -373.197
+ ],
+ "center_z": -373.197,
+ "open_air_section": 1,
+ "closeup_side": "interior-wall",
+ "closeup_preferred_normal": [
+ -0.9948950330600643,
+ 0.1009151782063209,
+ -0.0
+ ],
+ "camera_target_distance_m": 3.9999999999999973,
+ "route_distance_m": 8.3545,
+ "requested_route_distance_m": 8.3545,
+ "route_length_m": 2026.6238040154117,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-openair-1-4m-interior-wall.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-interior-wall.vfmesh",
+ "drawn_triangles": 308012,
+ "source_triangles": 368140,
+ "verified": true,
+ "pixel_quality_status": "low_contrast_geometry_visible",
+ "route_distance_actual_m": 8.3545,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 3.999999999999992,
+ "closeup_target_surface_distance_m": 0.8416597466625043,
+ "closeup_predicted_target_offset_m": 0.8416597466625043,
+ "closeup_wall_normal_alignment": 0.9449803535183738,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 5.327144619530225,
+ 8.025577332846515,
+ -372.4913321722626
+ ],
+ "target_actual_m": [
+ 9.12386703491211,
+ 8.0,
+ -373.75
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-interior-wall-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-interior-wall-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-1-4m-interior-wall-quality.log"
+ ]
+ },
+ {
+ "name": "passage-0-1-0-openair-2-4m-outside",
+ "passage": "passage/0-1/0",
+ "kind": "open-air-close",
+ "station": "section-2/4m-outside",
+ "camera": [
+ 12.814097656232029,
+ 0.949800892309409,
+ -375.51163279923776
+ ],
+ "target": [
+ 8.842807594702599,
+ 1.4281890685821654,
+ -375.51163279923776
+ ],
+ "yaw": -83.1311525734364,
+ "pitch": 0.0,
+ "focus": [
+ 6.603,
+ 1.698,
+ -374.149
+ ],
+ "center_z": -374.149,
+ "open_air_section": 2,
+ "closeup_side": "outside",
+ "closeup_preferred_normal": [
+ 0.9928225153823576,
+ -0.1195970440681891,
+ 0.0
+ ],
+ "camera_target_distance_m": 4.0,
+ "route_distance_m": 14.4925,
+ "requested_route_distance_m": 14.4925,
+ "route_length_m": 2026.6238040154117,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-openair-2-4m-outside.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-outside.vfmesh",
+ "drawn_triangles": 275333,
+ "source_triangles": 327761,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 14.4925,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 3.999999999999995,
+ "closeup_target_surface_distance_m": 1.0963161771133416,
+ "closeup_predicted_target_offset_m": 1.0963161771133416,
+ "closeup_wall_normal_alignment": 0.39413995490510356,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 9.613469253122387,
+ 1.5471847686714795,
+ -379.60073544787906
+ ],
+ "target_actual_m": [
+ 7.959597110748291,
+ 1.0,
+ -376.0
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-outside-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-outside-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-outside-quality.log"
+ ]
+ },
+ {
+ "name": "passage-0-1-0-openair-2-4m-interior-wall",
+ "passage": "passage/0-1/0",
+ "kind": "open-air-close",
+ "station": "section-2/4m-interior-wall",
+ "camera": [
+ 6.939570778854576,
+ -2.1803140897652855,
+ -376.2060303004211
+ ],
+ "target": [
+ 8.388084903173432,
+ 1.4829657169105679,
+ -375.51163279923776
+ ],
+ "yaw": 21.574563086437188,
+ "pitch": 9.997160707081923,
+ "focus": [
+ 6.603,
+ 1.698,
+ -374.149
+ ],
+ "center_z": -374.149,
+ "open_air_section": 2,
+ "closeup_side": "interior-wall",
+ "closeup_preferred_normal": [
+ -0.9928225153823576,
+ 0.1195970440681891,
+ -0.0
+ ],
+ "camera_target_distance_m": 3.999999999999997,
+ "route_distance_m": 14.4925,
+ "requested_route_distance_m": 14.4925,
+ "route_length_m": 2026.6238040154117,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-openair-2-4m-interior-wall.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-interior-wall.vfmesh",
+ "drawn_triangles": 345044,
+ "source_triangles": 414692,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 14.4925,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.000000000000001,
+ "closeup_target_surface_distance_m": 0.7732263275133904,
+ "closeup_predicted_target_offset_m": 0.7732263275133904,
+ "closeup_wall_normal_alignment": 0.286757829360229,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 6.619154002331269,
+ 0.5694445029418322,
+ -372.249825471136
+ ],
+ "target_actual_m": [
+ 7.85216206252137,
+ 1.2143337388310353,
+ -376.0
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-interior-wall-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-interior-wall-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-2-4m-interior-wall-quality.log"
+ ]
+ },
+ {
+ "name": "passage-0-1-0-openair-3-4m-outside",
+ "passage": "passage/0-1/0",
+ "kind": "open-air-close",
+ "station": "section-3/4m-outside",
+ "camera": [
+ -28.32291429976088,
+ -16.444327461849063,
+ -600.6066327992378
+ ],
+ "target": [
+ -25.004026673221745,
+ -14.211619482196229,
+ -600.6066327992378
+ ],
+ "yaw": 56.07018168236039,
+ "pitch": 0.0,
+ "focus": [
+ -22.1,
+ -12.258,
+ -599.244
+ ],
+ "center_z": -599.244,
+ "open_air_section": 3,
+ "closeup_side": "outside",
+ "closeup_preferred_normal": [
+ -0.8297219066347834,
+ -0.5581769949132084,
+ 0.0
+ ],
+ "camera_target_distance_m": 4.000000000000001,
+ "route_distance_m": 1265.3425000000002,
+ "requested_route_distance_m": 1265.3425000000002,
+ "route_length_m": 2026.6238040154117,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-openair-3-4m-outside.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-outside.vfmesh",
+ "drawn_triangles": 151372,
+ "source_triangles": 183724,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 1265.3425000000002,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 3.9999999999999947,
+ "closeup_target_surface_distance_m": 0.06828066292003203,
+ "closeup_predicted_target_offset_m": 0.06828066292003203,
+ "closeup_wall_normal_alignment": 0.9604791479186932,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -28.639699107248397,
+ -15.583356294879769,
+ -601.2437793015765
+ ],
+ "target_actual_m": [
+ -24.95574413685722,
+ -14.176529326299274,
+ -600.5734706737007
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-outside-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-outside-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-outside-quality.log"
+ ]
+ },
+ {
+ "name": "passage-0-1-0-openair-3-4m-interior-wall",
+ "passage": "passage/0-1/0",
+ "kind": "open-air-close",
+ "station": "section-3/4m-interior-wall",
+ "camera": [
+ -26.071689640946218,
+ -10.338278587083852,
+ -601.3036807194
+ ],
+ "target": [
+ -24.774901932566983,
+ -14.057480898923608,
+ -600.6066327992378
+ ],
+ "yaw": 160.77768453528284,
+ "pitch": 10.035712777782798,
+ "focus": [
+ -22.1,
+ -12.258,
+ -599.244
+ ],
+ "center_z": -599.244,
+ "open_air_section": 3,
+ "closeup_side": "interior-wall",
+ "closeup_preferred_normal": [
+ 0.8297219066347834,
+ 0.5581769949132084,
+ -0.0
+ ],
+ "camera_target_distance_m": 4.000000000000005,
+ "route_distance_m": 1265.3425000000002,
+ "requested_route_distance_m": 1265.3425000000002,
+ "route_length_m": 2026.6238040154117,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-0-1-0-openair-3-4m-interior-wall.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-interior-wall.vfmesh",
+ "drawn_triangles": 150614,
+ "source_triangles": 183232,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 1265.3425000000002,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.000000000000011,
+ "closeup_target_surface_distance_m": 0.15815699667954516,
+ "closeup_predicted_target_offset_m": 0.15815699667954516,
+ "closeup_wall_normal_alignment": 0.9379407978793181,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -21.87278031692096,
+ -11.881551644506661,
+ -599.3233300443438
+ ],
+ "target_actual_m": [
+ -24.868945473985846,
+ -14.149254069257264,
+ -600.6946505992728
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-interior-wall-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-interior-wall-render.log",
+ "Saved/Linux/l128/captures/L128/passage-0-1-0-openair-3-4m-interior-wall-quality.log"
+ ]
+ },
+ {
+ "name": "passage-1-2-0-openair-1-4m-outside",
+ "passage": "passage/1-2/0",
+ "kind": "open-air-close",
+ "station": "section-1/4m-outside",
+ "camera": [
+ -4.699079444431819,
+ -4.6537955842685985,
+ -748.15
+ ],
+ "target": [
+ -7.452748333327923,
+ -7.555055250400828,
+ -748.15
+ ],
+ "yaw": -136.49505148095557,
+ "pitch": 0.0,
+ "focus": [
+ -9.518,
+ -9.731,
+ -745.88
+ ],
+ "center_z": -745.88,
+ "open_air_section": 1,
+ "closeup_side": "outside",
+ "closeup_preferred_normal": [
+ 0.688417222224026,
+ 0.7253149165330574,
+ 0.0
+ ],
+ "camera_target_distance_m": 4.000000000000001,
+ "route_distance_m": 83.504,
+ "requested_route_distance_m": 83.504,
+ "route_length_m": 114.99063175809309,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-1-2-0-openair-1-4m-outside.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-outside.vfmesh",
+ "drawn_triangles": 620798,
+ "source_triangles": 684760,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 83.504,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 3.9999999999999654,
+ "closeup_target_surface_distance_m": 0.9023580264896125,
+ "closeup_predicted_target_offset_m": 0.9023580264896125,
+ "closeup_wall_normal_alignment": 0.5604211333378514,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -8.046760432303138,
+ -4.114982136123087,
+ -749.9844534333902
+ ],
+ "target_actual_m": [
+ -8.0,
+ -7.25,
+ -747.5006103515625
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-outside-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-outside-render.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-outside-quality.log"
+ ]
+ },
+ {
+ "name": "passage-1-2-0-openair-1-4m-interior-wall",
+ "passage": "passage/1-2/0",
+ "kind": "open-air-close",
+ "station": "section-1/4m-interior-wall",
+ "camera": [
+ -6.0956279351195075,
+ -11.653774892861163,
+ -748.8673569837389
+ ],
+ "target": [
+ -8.16773669839842,
+ -8.308365466344922,
+ -748.15
+ ],
+ "yaw": -31.773605793127505,
+ "pitch": 10.331275124559749,
+ "focus": [
+ -9.518,
+ -9.731,
+ -745.88
+ ],
+ "center_z": -745.88,
+ "open_air_section": 1,
+ "closeup_side": "interior-wall",
+ "closeup_preferred_normal": [
+ -0.688417222224026,
+ -0.7253149165330574,
+ -0.0
+ ],
+ "camera_target_distance_m": 3.999999999999997,
+ "route_distance_m": 83.504,
+ "requested_route_distance_m": 83.504,
+ "route_length_m": 114.99063175809309,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-1-2-0-openair-1-4m-interior-wall.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-interior-wall.vfmesh",
+ "drawn_triangles": 609749,
+ "source_triangles": 668123,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 83.504,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 3.999999999999999,
+ "closeup_target_surface_distance_m": 0.6509430039577998,
+ "closeup_predicted_target_offset_m": 0.6509430039577998,
+ "closeup_wall_normal_alignment": 0.7808473937095911,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -8.525095579521167,
+ -12.94135557024142,
+ -748.3220319510015
+ ],
+ "target_actual_m": [
+ -8.18421537084871,
+ -8.958641713644115,
+ -748.1744141343152
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-interior-wall-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-interior-wall-render.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-1-4m-interior-wall-quality.log"
+ ]
+ },
+ {
+ "name": "passage-1-2-0-openair-2-4m-outside",
+ "passage": "passage/1-2/0",
+ "kind": "open-air-close",
+ "station": "section-2/4m-outside",
+ "camera": [
+ 6.53817273275958,
+ -4.657210376135293,
+ -752.013
+ ],
+ "target": [
+ 8.159152142647708,
+ -8.31404312493838,
+ -752.013
+ ],
+ "yaw": 156.09352823535562,
+ "pitch": 0.0,
+ "focus": [
+ 9.43,
+ -11.181,
+ -749.743
+ ],
+ "center_z": -749.743,
+ "open_air_section": 2,
+ "closeup_side": "outside",
+ "closeup_preferred_normal": [
+ -0.40524485247203174,
+ 0.9142081872007717,
+ 0.0
+ ],
+ "camera_target_distance_m": 4.0,
+ "route_distance_m": 104.362,
+ "requested_route_distance_m": 104.362,
+ "route_length_m": 114.99063175809309,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-1-2-0-openair-2-4m-outside.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-outside.vfmesh",
+ "drawn_triangles": 584534,
+ "source_triangles": 636994,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 104.362,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.0,
+ "closeup_target_surface_distance_m": 0.5901774459243846,
+ "closeup_predicted_target_offset_m": 0.5901774459243846,
+ "closeup_wall_normal_alignment": 0.9891249705782158,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 6.359624549359488,
+ -5.416552010781576,
+ -752.0616659309658
+ ],
+ "target_actual_m": [
+ 8.5,
+ -8.79556763526633,
+ -752.0293187551489
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-outside-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-outside-render.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-outside-quality.log"
+ ]
+ },
+ {
+ "name": "passage-1-2-0-openair-2-4m-interior-wall",
+ "passage": "passage/1-2/0",
+ "kind": "open-air-close",
+ "station": "section-2/4m-interior-wall",
+ "camera": [
+ 12.438590152225206,
+ -8.574465388721983,
+ -752.7261335058829
+ ],
+ "target": [
+ 8.55317187096847,
+ -9.20292810238377,
+ -752.013
+ ],
+ "yaw": -99.18796190221158,
+ "pitch": 10.269787281460902,
+ "focus": [
+ 9.43,
+ -11.181,
+ -749.743
+ ],
+ "center_z": -749.743,
+ "open_air_section": 2,
+ "closeup_side": "interior-wall",
+ "closeup_preferred_normal": [
+ 0.40524485247203174,
+ -0.9142081872007717,
+ -0.0
+ ],
+ "camera_target_distance_m": 3.9999999999999973,
+ "route_distance_m": 104.362,
+ "requested_route_distance_m": 104.362,
+ "route_length_m": 114.99063175809309,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-1-2-0-openair-2-4m-interior-wall.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-interior-wall.vfmesh",
+ "drawn_triangles": 572250,
+ "source_triangles": 618638,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 104.362,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.000000000000001,
+ "closeup_target_surface_distance_m": 0.353159827911248,
+ "closeup_predicted_target_offset_m": 0.353159827911248,
+ "closeup_wall_normal_alignment": 0.9983988827266467,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ 9.748104215680776,
+ -12.666965794821667,
+ -752.0265932958123
+ ],
+ "target_actual_m": [
+ 8.335827076712103,
+ -8.924626207433736,
+ -752.0074179101423
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-interior-wall-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-interior-wall-render.log",
+ "Saved/Linux/l128/captures/L128/passage-1-2-0-openair-2-4m-interior-wall-quality.log"
+ ]
+ },
+ {
+ "name": "passage-2-3-0-openair-1-4m-outside",
+ "passage": "passage/2-3/0",
+ "kind": "open-air-close",
+ "station": "section-1/4m-outside",
+ "camera": [
+ -3.5840423774965293,
+ -5.521048309862215,
+ -815.8969999999999
+ ],
+ "target": [
+ -5.637732447498513,
+ -8.953592132798093,
+ -815.8969999999999
+ ],
+ "yaw": -149.10792796365394,
+ "pitch": 0.0,
+ "focus": [
+ -7.178,
+ -11.528,
+ -813.627
+ ],
+ "center_z": -813.627,
+ "open_air_section": 1,
+ "closeup_side": "outside",
+ "closeup_preferred_normal": [
+ 0.5134225175004958,
+ 0.8581359557339694,
+ 0.0
+ ],
+ "camera_target_distance_m": 4.0,
+ "route_distance_m": 16.616500000000002,
+ "requested_route_distance_m": 16.616500000000002,
+ "route_length_m": 494.0722798830563,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-2-3-0-openair-1-4m-outside.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-outside.vfmesh",
+ "drawn_triangles": 104612,
+ "source_triangles": 129326,
+ "verified": true,
+ "pixel_quality_status": "low_contrast_geometry_visible",
+ "route_distance_actual_m": 16.616500000000002,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.0000000000000036,
+ "closeup_target_surface_distance_m": 0.29188924025474844,
+ "closeup_predicted_target_offset_m": 0.29188924025474844,
+ "closeup_wall_normal_alignment": 0.6703275045296155,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -3.7918253987505834,
+ -7.16028175130118,
+ -813.227396563761
+ ],
+ "target_actual_m": [
+ -5.7833741859987065,
+ -9.093313475424294,
+ -816.1078690565205
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-outside-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-outside-render.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-outside-quality.log"
+ ]
+ },
+ {
+ "name": "passage-2-3-0-openair-1-4m-interior-wall",
+ "passage": "passage/2-3/0",
+ "kind": "open-air-close",
+ "station": "section-1/4m-interior-wall",
+ "camera": [
+ -3.4141605326349946,
+ -12.659565888737353,
+ -816.5879167710818
+ ],
+ "target": [
+ -6.170971760123668,
+ -9.844849940114793,
+ -815.8969999999999
+ ],
+ "yaw": -44.40454805561343,
+ "pitch": 9.946538162082001,
+ "focus": [
+ -7.178,
+ -11.528,
+ -813.627
+ ],
+ "center_z": -813.627,
+ "open_air_section": 1,
+ "closeup_side": "interior-wall",
+ "closeup_preferred_normal": [
+ -0.5134225175004958,
+ -0.8581359557339694,
+ -0.0
+ ],
+ "camera_target_distance_m": 4.000000000000005,
+ "route_distance_m": 16.616500000000002,
+ "requested_route_distance_m": 16.616500000000002,
+ "route_length_m": 494.0722798830563,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-2-3-0-openair-1-4m-interior-wall.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-interior-wall.vfmesh",
+ "drawn_triangles": 94962,
+ "source_triangles": 118028,
+ "verified": true,
+ "pixel_quality_status": "low_contrast_geometry_visible",
+ "route_distance_actual_m": 16.616500000000002,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.0,
+ "closeup_target_surface_distance_m": 0.41920390486225767,
+ "closeup_predicted_target_offset_m": 0.41920390486225767,
+ "closeup_wall_normal_alignment": 0.740744136337711,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -7.998432705401559,
+ -11.833936581758076,
+ -818.2481168532394
+ ],
+ "target_actual_m": [
+ -5.94757062165508,
+ -9.608161331921629,
+ -815.6327986602337
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-interior-wall-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-interior-wall-render.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-1-4m-interior-wall-quality.log"
+ ]
+ },
+ {
+ "name": "passage-2-3-0-openair-2-4m-outside",
+ "passage": "passage/2-3/0",
+ "kind": "open-air-close",
+ "station": "section-2/4m-outside",
+ "camera": [
+ -4.5562890668466025,
+ 4.648574813628143,
+ -879.7479999999999
+ ],
+ "target": [
+ -7.40869531436283,
+ 7.452817777269203,
+ -879.7479999999999
+ ],
+ "yaw": -45.487830534998494,
+ "pitch": 0.0,
+ "focus": [
+ -9.548,
+ 9.556,
+ -877.478
+ ],
+ "center_z": -877.478,
+ "open_air_section": 2,
+ "closeup_side": "outside",
+ "closeup_preferred_normal": [
+ 0.7131015618790567,
+ -0.7010607409102652,
+ 0.0
+ ],
+ "camera_target_distance_m": 4.000000000000001,
+ "route_distance_m": 374.929,
+ "requested_route_distance_m": 374.929,
+ "route_length_m": 494.0722798830563,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-2-3-0-openair-2-4m-outside.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-outside.vfmesh",
+ "drawn_triangles": 475856,
+ "source_triangles": 504240,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 374.929,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.0,
+ "closeup_target_surface_distance_m": 1.7280841589725482,
+ "closeup_predicted_target_offset_m": 1.7280841589725482,
+ "closeup_wall_normal_alignment": 0.6707889779439669,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -7.47193274788199,
+ 5.182168353356822,
+ -879.6783722112204
+ ],
+ "target_actual_m": [
+ -7.306445568768645,
+ 9.17777802625833,
+ -879.7662205769708
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-outside-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-outside-render.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-outside-quality.log"
+ ]
+ },
+ {
+ "name": "passage-2-3-0-openair-2-4m-interior-wall",
+ "passage": "passage/2-3/0",
+ "kind": "open-air-close",
+ "station": "section-2/4m-interior-wall",
+ "camera": [
+ -11.533986119377625,
+ 6.164550123765492,
+ -880.4395357921604
+ ],
+ "target": [
+ -8.149320771422074,
+ 8.180937668487475,
+ -879.7479999999999
+ ],
+ "yaw": 59.215963829172296,
+ "pitch": 9.955540417812847,
+ "focus": [
+ -9.548,
+ 9.556,
+ -877.478
+ ],
+ "center_z": -877.478,
+ "open_air_section": 2,
+ "closeup_side": "interior-wall",
+ "closeup_preferred_normal": [
+ -0.7131015618790567,
+ 0.7010607409102652,
+ -0.0
+ ],
+ "camera_target_distance_m": 4.000000000000007,
+ "route_distance_m": 374.929,
+ "requested_route_distance_m": 374.929,
+ "route_length_m": 494.0722798830563,
+ "variant": "L128-slab-ownership-v226",
+ "capture": "captures/L128/passage-2-3-0-openair-2-4m-interior-wall.png",
+ "scene": "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-interior-wall.vfmesh",
+ "drawn_triangles": 486480,
+ "source_triangles": 513552,
+ "verified": true,
+ "pixel_quality_status": "pass",
+ "route_distance_actual_m": 374.929,
+ "route_station_adjustment_m": 0.0,
+ "closeup_camera_target_distance_m": 4.0,
+ "closeup_target_surface_distance_m": 1.0286227628002445,
+ "closeup_predicted_target_offset_m": 1.0286227628002445,
+ "closeup_wall_normal_alignment": 0.720019406420326,
+ "fallback_kind": null,
+ "fallback_surface_distance_m": null,
+ "camera_actual_m": [
+ -8.257109087497915,
+ 13.208090205453457,
+ -879.7612149430302
+ ],
+ "target_actual_m": [
+ -8.149320771422074,
+ 9.209558486938477,
+ -879.75
+ ],
+ "logs": [
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-interior-wall-mesh.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-interior-wall-render.log",
+ "Saved/Linux/l128/captures/L128/passage-2-3-0-openair-2-4m-interior-wall-quality.log"
+ ]
+ }
+ ]
+}
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-1-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-1-4m-interior-wall.png
new file mode 100644
index 0000000..1fd88a4
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-1-4m-interior-wall.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-1-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-1-4m-outside.png
new file mode 100644
index 0000000..87570be
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-1-4m-outside.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-2-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-2-4m-interior-wall.png
new file mode 100644
index 0000000..f76e648
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-2-4m-interior-wall.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-2-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-2-4m-outside.png
new file mode 100644
index 0000000..c19fc5f
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-2-4m-outside.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-3-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-3-4m-interior-wall.png
new file mode 100644
index 0000000..6714147
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-3-4m-interior-wall.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-3-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-3-4m-outside.png
new file mode 100644
index 0000000..0975446
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-openair-3-4m-outside.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-1.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-1.png
new file mode 100644
index 0000000..064baf2
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-1.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-2.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-2.png
new file mode 100644
index 0000000..bfa3044
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-2.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-3.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-3.png
new file mode 100644
index 0000000..6782aa6
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-0-1-0-rock-floor-station-3.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-1-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-1-4m-interior-wall.png
new file mode 100644
index 0000000..1000a5f
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-1-4m-interior-wall.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-1-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-1-4m-outside.png
new file mode 100644
index 0000000..b6830ab
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-1-4m-outside.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-2-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-2-4m-interior-wall.png
new file mode 100644
index 0000000..a6be396
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-2-4m-interior-wall.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-2-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-2-4m-outside.png
new file mode 100644
index 0000000..c00f532
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-openair-2-4m-outside.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-1.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-1.png
new file mode 100644
index 0000000..b3b0538
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-1.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-2.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-2.png
new file mode 100644
index 0000000..3a04111
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-2.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-3.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-3.png
new file mode 100644
index 0000000..05fef6b
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-1-2-0-rock-floor-station-3.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-1-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-1-4m-interior-wall.png
new file mode 100644
index 0000000..7e2afa6
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-1-4m-interior-wall.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-1-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-1-4m-outside.png
new file mode 100644
index 0000000..ba8aacc
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-1-4m-outside.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-2-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-2-4m-interior-wall.png
new file mode 100644
index 0000000..a3b5296
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-2-4m-interior-wall.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-2-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-2-4m-outside.png
new file mode 100644
index 0000000..3b4345a
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-openair-2-4m-outside.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-1.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-1.png
new file mode 100644
index 0000000..ccc141f
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-1.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-2.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-2.png
new file mode 100644
index 0000000..37ebff0
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-2.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-3.png b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-3.png
new file mode 100644
index 0000000..43c0fdc
Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux128/captures/L128/passage-2-3-0-rock-floor-station-3.png differ
diff --git a/Standalone/Research/WorldAssemblerM3/Linux128/l128-slab-ownership.patch b/Standalone/Research/WorldAssemblerM3/Linux128/l128-slab-ownership.patch
new file mode 100644
index 0000000..ab93b07
--- /dev/null
+++ b/Standalone/Research/WorldAssemblerM3/Linux128/l128-slab-ownership.patch
@@ -0,0 +1,1596 @@
+diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
+index 95223ef..947f994 100644
+--- a/ARCHITECTURE.md
++++ b/ARCHITECTURE.md
+@@ -2316,6 +2316,37 @@ spatial-property inventory: legacy chunk distances, owner/Core voxel lengths and
+ placement vectors, and other centimetre fields remain in their prior units. The U1 report records
+ the five BuildHost asset values, hashes, and remaining work.
+
++### 8.56 Reach-bounded ownership slabs for prepared passages — World Assembler M3 L128
++
++The support radius varies along the route as `S(s) = r(s) + route_reach + safety`. On the owner
++world's 3.5 m body bore, `S = 3.5 + 4.335 + 0.05 = 7.885 m`; at the 4.5 m mouths, `S = 8.885 m`
++and those joints belong to transition owners. `route_reach = 4.0 m sweep + 0.21 m wall relief +
++0.125 m quarter-corner allowance`; the 0.75 m floor shell and 1 m open-air side wall fit inside
++that conservative reach. For a smooth centreline with curvature `κ`, the plane coordinate
++`g_s(x) = (x - c(s)) · T(s)` is strictly decreasing throughout support when `κS < 1`, or bend
++radius `ρ > S`. On a circular joint with chord length `L` and turn `θ`, the equivalent bound is
++`L / (2 sin(θ/2)) > S`. The audit also checks doubly-critical nonlocal route pairs against the
++sum of their two support radii, since a large local bend radius alone cannot prevent a route from
++folding back across itself.
++
++Each normal body frame owns the half-open region between its start and end tangent planes. The
++outside planes are omitted at the two mouths; tight mouth fans are combined into transition
++owners. When routes meet at a joint, their passage fields remain independent contributors to the
++deterministic union. The same plane predicate filters prepared tile sweeps and exact off-grid
++queries. Floor height remains independent of round-distance selection: `PassageOwnershipFloorT`
++projects onto the owner's XY route segment because authored `h(s)` uses horizontal progress. The
++9-station density probe matches L127's root residuals exactly; across its 0.1 m samples, the
++largest adjacent root change is 1.765 mm.
++
++Planning audits local curvature, nonlocal separation, 33,813 owner-world support probes, and
++negative controls that inject a duplicate claim and a no-owner gap. The owner world has three
++routes; tight joints are handled by mouth transitions and the body passes the support bound. A
++pathological legacy two-strata fixture instead receives one full-route composite owner, keeping
++its established field while retaining one slab claim. Such fallback routes do not use the body-slab
++shortcut. The evaluator version is 226; no
++owner route control points are changed. See
++[`Standalone/Research/WorldAssemblerM3/Linux128/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux128/REPORT.md).
++
+ ## 9. Multiplayer model (listen-server first, dedicated-friendly)
+
+ > **Status: transport is DESIGN ONLY — nothing is networked in-tree yet** (no `Replicated`/`HasAuthority`/RPCs; a
+diff --git a/CODEMAP.md b/CODEMAP.md
+index 56d375f..a59bfb3 100644
+--- a/CODEMAP.md
++++ b/CODEMAP.md
+@@ -1352,6 +1352,17 @@ tunnel-slope version in `VoxelStrateDefinition.cpp`, plus the standalone `VoxelF
+ in `VoxelForgeExploreCommandlet.cpp`. `GetStrateForChunk` still receives layout-chunk Z, not a Core
+ tile index. See `Standalone/Research/WorldAssemblerM3/Unreal1/REPORT.md` for BuildHost evidence.
+
++### 3.38 Prepared passage slab ownership — World Assembler M3 L128
++
++| Symbol | Canonical file | Role |
++|---|---|---|
++| `FSlabReachAudit`, `AuditSlabReach`, `BuildSegments` | `Standalone/Core/include/VoxelForgeCore/PassageSpline.h` | Audits reach-bounded bend curvature, nonlocal route separation, single slab ownership, and injected duplicate/no-owner controls; chooses finite mouth-transition ranges. |
++| `FPassageOwnershipSlab`, `PassageOwnershipSlabOwns`, `PassageOwnershipFloorT` | `Standalone/Core/src/ShapeWorldInternal.h` | Shares half-open slab-plane ownership between exact point queries and prepared tile sweeps; floor-profile `t` uses horizontal route progress independently of round distance, with a frame-plane fallback for vertical segments. Pathological legacy paths use one full-route composite owner. |
++| `PassagePlanSlabAudit` | `Standalone/Core/src/ResolvedLayoutInternal.h` | Fails layout planning when neither the normal slabs nor the validated whole-route composite can provide exactly one owner per support probe. |
++| `WorldAssemblyEvaluatorVersion` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` | Bumped to 226 for slab ownership. |
++
++See ARCHITECTURE §8.56 and [`Standalone/Research/WorldAssemblerM3/Linux128/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux128/REPORT.md).
++
+ ## 4. The density pipeline (most-edited hot path)
+
+ ### 4.1 `GetDensityWithParams` (TunnelNetwork) — VoxelGenerator.cpp:3749
+diff --git a/Standalone/Core/include/VoxelForgeCore/PassageSpline.h b/Standalone/Core/include/VoxelForgeCore/PassageSpline.h
+index 6b61bb9..93dbe2c 100644
+--- a/Standalone/Core/include/VoxelForgeCore/PassageSpline.h
++++ b/Standalone/Core/include/VoxelForgeCore/PassageSpline.h
+@@ -2,10 +2,14 @@
+
+ #include
+ #include
++#include
+ #include
+ #include
++#include
+ #include
++#include
+ #include
++#include
+ #include
+
+ namespace VoxelForgeCore::PassageSpline
+@@ -23,6 +27,32 @@ namespace VoxelForgeCore::PassageSpline
+ double plannedFloorA=0.0,plannedFloorB=0.0;
+ };
+
++ struct FSlabReachAudit
++ {
++ std::size_t upperMouthLastControlSpan=0;
++ std::size_t lowerMouthFirstControlSpan=0;
++ std::size_t upperMouthEndSegment=0;
++ std::size_t upperMouthTransitionEndSegment=0;
++ std::size_t lowerMouthStartSegment=0;
++ std::size_t lowerMouthTransitionStartSegment=0;
++ std::size_t upperTransitionLastControlSpan=0;
++ std::size_t tightMouthJoints=0;
++ std::size_t nonlocalMouthPairs=0;
++ std::size_t bodyCurvatureFailures=0;
++ std::size_t bodySelfOverlapFailures=0;
++ std::size_t ownershipTestSamples=0;
++ std::size_t zeroOwnerSamples=0,multipleOwnerSamples=0;
++ bool ownershipNegativeControlsPass=false;
++ bool usesWholeRouteCompositeSlab=false;
++ std::size_t firstZeroOwnerProbe=std::numeric_limits::max();
++ std::size_t firstZeroOwnerSegment=std::numeric_limits::max();
++ std::array firstZeroOwnerPoint{};
++ double firstZeroOwnerStartSide=0.0,firstZeroOwnerEndSide=0.0;
++ double minimumBodyCurvatureRadiusMetres=std::numeric_limits::infinity();
++ double minimumBodySelfGapMetres=std::numeric_limits::infinity();
++ bool valid=false;
++ };
++
+ inline double KnotSpan(const FPoint& a,const FPoint& b,double unitsPerMetre)
+ {
+ const double dx=(b[0]-a[0])/unitsPerMetre;
+@@ -252,4 +282,626 @@ namespace VoxelForgeCore::PassageSpline
+ }
+ return result;
+ }
++
++ inline FSlabReachAudit ComputeSlabReachAudit(std::span segments,
++ std::size_t routeEndControlIndex,double unitsPerMetre,double routeReachMetres,
++ double safetyMarginMetres=0.05)
++ {
++ FSlabReachAudit result;
++ if(segments.size()<2||!(unitsPerMetre>0.0)||!(routeReachMetres>=0.0))return result;
++ const std::size_t lastRouteSpan=std::min(routeEndControlIndex,
++ segments.back().controlSpan);
++ result.upperMouthLastControlSpan=0;
++ result.lowerMouthFirstControlSpan=lastRouteSpan;
++ struct FStation
++ {
++ std::array position{};
++ double radius=0.0,along=0.0;
++ std::size_t controlSpan=0;
++ };
++ std::vector stations;
++ stations.reserve(segments.size()+1);
++ const auto makeStation=[&](const FPoint& point,double along,std::size_t span)
++ {
++ FStation station;
++ for(std::size_t axis=0;axis<3;++axis)
++ station.position[axis]=point[axis]/unitsPerMetre;
++ station.radius=std::max(0.0,point[3]/unitsPerMetre);
++ station.along=along;
++ station.controlSpan=span;
++ return station;
++ };
++ stations.push_back(makeStation(segments.front().a,segments.front().alongMetres,
++ segments.front().controlSpan));
++ for(const auto& segment:segments)
++ stations.push_back(makeStation(segment.b,
++ segment.alongMetres+segment.lengthMetres,segment.controlSpan));
++ double maximumSupport=0.0,maximumSegmentLength=0.0;
++ for(const auto& station:stations)
++ maximumSupport=std::max(maximumSupport,station.radius
++ +routeReachMetres+safetyMarginMetres);
++ for(const auto& segment:segments)
++ maximumSegmentLength=std::max(maximumSegmentLength,segment.lengthMetres);
++
++ const auto distance=[](const FStation& a,const FStation& b)
++ {
++ double squared=0.0;
++ for(std::size_t axis=0;axis<3;++axis)
++ {const double delta=a.position[axis]-b.position[axis];squared+=delta*delta;}
++ return std::sqrt(squared);
++ };
++ const auto curvatureRadius=[&](std::size_t index)
++ {
++ const auto& a=stations[index-1];
++ const auto& b=stations[index];
++ const auto& c=stations[index+1];
++ const std::array ab={b.position[0]-a.position[0],
++ b.position[1]-a.position[1],b.position[2]-a.position[2]};
++ const std::array bc={c.position[0]-b.position[0],
++ c.position[1]-b.position[1],c.position[2]-b.position[2]};
++ const std::array cross={ab[1]*bc[2]-ab[2]*bc[1],
++ ab[2]*bc[0]-ab[0]*bc[2],ab[0]*bc[1]-ab[1]*bc[0]};
++ const double twiceArea=std::sqrt(cross[0]*cross[0]+cross[1]*cross[1]
++ +cross[2]*cross[2]);
++ return twiceArea>1.0e-12
++ ?distance(a,b)*distance(b,c)*distance(a,c)/(2.0*twiceArea)
++ :std::numeric_limits::infinity();
++ };
++ const auto normalize=[](std::array direction)
++ {
++ const double length=std::sqrt(direction[0]*direction[0]
++ +direction[1]*direction[1]+direction[2]*direction[2]);
++ if(length>1.0e-12)
++ for(double& component:direction)component/=length;
++ return direction;
++ };
++ std::vector> frameTangents(stations.size());
++ std::vector tangentSpacingTolerance(stations.size(),0.0);
++ for(std::size_t frame=0;frame incoming{},outgoing{},tangent{};
++ if(frame>0)
++ for(std::size_t axis=0;axis<3;++axis)
++ incoming[axis]=stations[frame].position[axis]
++ -stations[frame-1].position[axis];
++ if(frame+10&&frame+10)
++ tangentSpacingTolerance[frame]=0.5*(stations[frame].along
++ -stations[frame-1].along);
++ }
++ const auto isDoublyCritical=[&](std::size_t first,std::size_t second)
++ {
++ std::array delta{};
++ for(std::size_t axis=0;axis<3;++axis)
++ delta[axis]=stations[second].position[axis]
++ -stations[first].position[axis];
++ const auto alongTangent=[&](std::size_t frame)
++ {
++ return delta[0]*frameTangents[frame][0]
++ +delta[1]*frameTangents[frame][1]
++ +delta[2]*frameTangents[frame][2];
++ };
++ return std::abs(alongTangent(first))<=tangentSpacingTolerance[first]
++ &&std::abs(alongTangent(second))<=tangentSpacingTolerance[second];
++ };
++ // The signed coordinate to a route frame changes monotonically across a
++ // normal disk while kappa*S < 1, i.e. local support S is below curvature
++ // radius. Global uniqueness additionally requires separating doubly
++ // critical (mutually normal) centerline pairs by their support radii.
++ // Support S is bore radius plus the 4.335 m sweep/relief/corner reach.
++ const auto requiredAt=[&](std::size_t index)
++ {
++ return std::max({stations[index-1].radius,stations[index].radius,
++ stations[index+1].radius})+routeReachMetres+safetyMarginMetres;
++ };
++ constexpr std::size_t MouthSearchControlSpans=8;
++ for(std::size_t index=1;index+1=requiredAt(index))continue;
++ ++result.tightMouthJoints;
++ const std::size_t span=std::min(stations[index].controlSpan,
++ routeEndControlIndex);
++ if(span<=MouthSearchControlSpans)
++ result.upperMouthLastControlSpan=std::max(
++ result.upperMouthLastControlSpan,span+1);
++ else if(span+MouthSearchControlSpans>=routeEndControlIndex)
++ result.lowerMouthFirstControlSpan=std::min(
++ result.lowerMouthFirstControlSpan,span>0?span-1:0);
++ }
++
++ for(std::size_t first=0;first=0.0)continue;
++ const bool upperMouth=a.controlSpan<=MouthSearchControlSpans
++ &&b.controlSpan<=MouthSearchControlSpans;
++ const bool lowerMouth=a.controlSpan+MouthSearchControlSpans
++ >=routeEndControlIndex
++ &&b.controlSpan+MouthSearchControlSpans>=routeEndControlIndex;
++ if(upperMouth)
++ {
++ result.upperMouthLastControlSpan=std::max(
++ result.upperMouthLastControlSpan,b.controlSpan+1);
++ ++result.nonlocalMouthPairs;
++ }
++ else if(lowerMouth)
++ {
++ result.lowerMouthFirstControlSpan=std::min(
++ result.lowerMouthFirstControlSpan,a.controlSpan>0
++ ?a.controlSpan-1:0);
++ ++result.nonlocalMouthPairs;
++ }
++ }
++
++ if(result.upperMouthLastControlSpan>=result.lowerMouthFirstControlSpan)
++ {
++ result.upperMouthLastControlSpan=lastRouteSpan;
++ result.lowerMouthFirstControlSpan=lastRouteSpan;
++ }
++ for(std::size_t index=1;index+1=result.lowerMouthFirstControlSpan;
++ if(mouthOwned)continue;
++ const double radius=curvatureRadius(index);
++ result.minimumBodyCurvatureRadiusMetres=std::min(
++ result.minimumBodyCurvatureRadiusMetres,radius);
++ if(radius=required)continue;
++ if(!isDoublyCritical(first,second))continue;
++ const bool sameUpper=a.controlSpan<=result.upperMouthLastControlSpan
++ &&b.controlSpan<=result.upperMouthLastControlSpan;
++ const bool sameLower=a.controlSpan>=result.lowerMouthFirstControlSpan
++ &&b.controlSpan>=result.lowerMouthFirstControlSpan;
++ if(!sameUpper&&!sameLower)++result.bodySelfOverlapFailures;
++ }
++ struct FTestSlab
++ {
++ std::size_t first=0,end=0;
++ bool hasStartPlane=true,hasEndPlane=true;
++ };
++ std::vector testSlabs;
++ const auto rebuildTestSlabs=[&]()
++ {
++ result.upperMouthEndSegment=std::min(result.upperMouthEndSegment,
++ segments.size());
++ result.lowerMouthStartSegment=segments.size();
++ for(std::size_t index=0;index=result.lowerMouthFirstControlSpan)
++ {result.lowerMouthStartSegment=index;break;}
++ result.upperMouthTransitionEndSegment=std::max(
++ result.upperMouthEndSegment,std::min(segments.size(),
++ result.upperMouthTransitionEndSegment));
++ result.lowerMouthTransitionStartSegment=std::min(
++ result.lowerMouthStartSegment,std::max(
++ result.upperMouthTransitionEndSegment,
++ result.lowerMouthTransitionStartSegment));
++ testSlabs.clear();
++ if(result.upperMouthEndSegment>=result.lowerMouthStartSegment)
++ testSlabs.push_back({0,segments.size(),false,false});
++ else
++ {
++ if(result.upperMouthEndSegment>0)
++ testSlabs.push_back({0,result.upperMouthEndSegment,false,true});
++ if(result.upperMouthEndSegment& point)
++ {
++ if(slab.hasStartPlane)
++ {
++ const std::size_t frame=slab.first;
++ double side=0.0;
++ for(std::size_t axis=0;axis<3;++axis)
++ side+=(point[axis]-stations[frame].position[axis])
++ *frameTangents[frame][axis];
++ if(side<0.0)return false;
++ }
++ if(slab.hasEndPlane)
++ {
++ const std::size_t frame=slab.end;
++ double side=0.0;
++ for(std::size_t axis=0;axis<3;++axis)
++ side+=(point[axis]-stations[frame].position[axis])
++ *frameTangents[frame][axis];
++ if(side>=0.0)return false;
++ }
++ return true;
++ };
++ const auto planeSide=[&](const std::array& point,
++ std::size_t frame)
++ {
++ double side=0.0;
++ for(std::size_t axis=0;axis<3;++axis)
++ side+=(point[axis]-stations[frame].position[axis])
++ *frameTangents[frame][axis];
++ return side;
++ };
++ const auto influences=[&](const FTestSlab& slab,
++ const std::array& point)
++ {
++ for(std::size_t segment=slab.first;segment delta={b.position[0]-a.position[0],
++ b.position[1]-a.position[1],b.position[2]-a.position[2]};
++ const double lengthSq=delta[0]*delta[0]+delta[1]*delta[1]
++ +delta[2]*delta[2];
++ const std::array fromStart={point[0]-a.position[0],
++ point[1]-a.position[1],point[2]-a.position[2]};
++ const double supportAtStart=a.radius+routeReachMetres+safetyMarginMetres;
++ const double supportDelta=b.radius-a.radius;
++ const auto supportsPoint=[&](double t)
++ {
++ const double dx=fromStart[0]-t*delta[0];
++ const double dy=fromStart[1]-t*delta[1];
++ const double dz=fromStart[2]-t*delta[2];
++ const double support=supportAtStart+t*supportDelta;
++ return dx*dx+dy*dy+dz*dz<=support*support+1.0e-9;
++ };
++ if(supportsPoint(0.0)||supportsPoint(1.0))return true;
++ const double quadratic=lengthSq-supportDelta*supportDelta;
++ if(quadratic>1.0e-12)
++ {
++ const double linear=-2.0*(fromStart[0]*delta[0]
++ +fromStart[1]*delta[1]+fromStart[2]*delta[2])
++ -2.0*supportAtStart*supportDelta;
++ const double closest=std::clamp(-linear/(2.0*quadratic),0.0,1.0);
++ if(supportsPoint(closest))return true;
++ }
++ }
++ return false;
++ };
++ const auto slabState=[&](const FTestSlab& slab,
++ const std::array& point)
++ {
++ const bool active=influences(slab,point);
++ return std::array{active,active&&owns(slab,point)};
++ };
++ const auto testOwnershipCrossSection=[&](const std::array& center,
++ const std::array& tangent,double boreRadius,
++ std::size_t probeIndex)
++ {
++ const double probeAlong=probeIndex reference=std::abs(tangent[2])<0.75
++ ?std::array{0.0,0.0,1.0}
++ :std::array{0.0,1.0,0.0};
++ std::array normalA={tangent[1]*reference[2]-tangent[2]*reference[1],
++ tangent[2]*reference[0]-tangent[0]*reference[2],
++ tangent[0]*reference[1]-tangent[1]*reference[0]};
++ normalA=normalize(normalA);
++ const std::array normalB={tangent[1]*normalA[2]-tangent[2]*normalA[1],
++ tangent[2]*normalA[0]-tangent[0]*normalA[2],
++ tangent[0]*normalA[1]-tangent[1]*normalA[0]};
++ const double support=boreRadius+routeReachMetres+safetyMarginMetres;
++ for(std::size_t ring=0;ring<3;++ring)
++ {
++ const double radius=support*static_cast(ring)*0.5;
++ const std::size_t directions=ring==0?1:8;
++ for(std::size_t directionIndex=0;directionIndex(directionIndex)/directions;
++ const double offsetA=radius*std::cos(angle);
++ const double offsetB=radius*std::sin(angle);
++ std::array point=center;
++ for(std::size_t axis=0;axis<3;++axis)
++ point[axis]+=offsetA*normalA[axis]+offsetB*normalB[axis];
++ std::size_t claims=0;
++ std::size_t unownedSegment=std::numeric_limits::max();
++ double unownedStartSide=0.0,unownedEndSide=0.0;
++ if(testSlabs.size()==1&&!testSlabs.front().hasStartPlane
++ &&!testSlabs.front().hasEndPlane)
++ {
++ // A whole-route composite has no ownership boundaries: the
++ // sampled point is within support of its center frame/segment,
++ // so that single unbounded slab owns it by construction.
++ claims=1;
++ }
++ else
++ {
++ const double firstAlong=probeAlong-arcWindow;
++ const double lastAlong=probeAlong+arcWindow;
++ const auto firstSlab=std::lower_bound(testSlabs.begin(),
++ testSlabs.end(),firstAlong,[&](const FTestSlab& slab,
++ double value)
++ {
++ return stations[slab.end].alongfirst].along<=lastAlong;++slab)
++ {
++ const auto state=slabState(*slab,point);
++ if(!state[0])continue;
++ if(state[1])++claims;
++ else if(unownedSegment==std::numeric_limits::max())
++ {
++ unownedSegment=slab->first;
++ if(slab->hasStartPlane)
++ unownedStartSide=planeSide(point,slab->first);
++ if(slab->hasEndPlane)
++ unownedEndSide=planeSide(point,slab->end);
++ }
++ }
++ }
++ ++result.ownershipTestSamples;
++ if(claims==0)++result.zeroOwnerSamples;
++ else if(claims>1)++result.multipleOwnerSamples;
++ if(claims==0&&result.firstZeroOwnerProbe
++ ==std::numeric_limits::max())
++ {
++ result.firstZeroOwnerProbe=probeIndex;
++ result.firstZeroOwnerPoint=point;
++ result.firstZeroOwnerSegment=unownedSegment;
++ result.firstZeroOwnerStartSide=unownedStartSide;
++ result.firstZeroOwnerEndSide=unownedEndSide;
++ }
++ }
++ }
++ };
++ const std::size_t initialUpperMouthLastSpan=result.upperMouthLastControlSpan;
++ const std::size_t initialLowerMouthFirstSpan=result.lowerMouthFirstControlSpan;
++ result.upperTransitionLastControlSpan=initialUpperMouthLastSpan;
++ const auto segmentAfterSpan=[&](std::size_t span)
++ {
++ std::size_t end=0;
++ while(end=initialLowerMouthFirstSpan)
++ {result.lowerMouthTransitionStartSegment=segment;break;}
++ for(std::size_t attempt=0;attempt<=naturalUpperMouthEndSegment;++attempt)
++ {
++ result.upperMouthEndSegment=naturalUpperMouthEndSegment-attempt;
++ result.upperMouthLastControlSpan=result.upperMouthEndSegment>0
++ ?segments[result.upperMouthEndSegment-1].controlSpan:0;
++ result.lowerMouthFirstControlSpan=initialLowerMouthFirstSpan;
++ result.ownershipTestSamples=0;
++ result.zeroOwnerSamples=0;
++ result.multipleOwnerSamples=0;
++ result.firstZeroOwnerProbe=std::numeric_limits::max();
++ result.firstZeroOwnerSegment=std::numeric_limits::max();
++ rebuildTestSlabs();
++ for(std::size_t frame=0;frame center{},tangent{};
++ for(std::size_t axis=0;axis<3;++axis)
++ {
++ center[axis]=(stations[segment].position[axis]
++ +stations[segment+1].position[axis])*0.5;
++ tangent[axis]=frameTangents[segment][axis]
++ +frameTangents[segment+1][axis];
++ }
++ tangent=normalize(tangent);
++ if(tangent[0]==0.0&&tangent[1]==0.0&&tangent[2]==0.0)
++ tangent=frameTangents[segment];
++ testOwnershipCrossSection(center,tangent,
++ 0.5*(stations[segment].radius+stations[segment+1].radius),
++ stations.size()+segment);
++ }
++ if(result.zeroOwnerSamples==0&&result.multipleOwnerSamples==0)break;
++ }
++ const std::size_t controlFrame=std::clamp(
++ result.upperMouthEndSegment,1,segments.size()-1);
++ std::array negativeControlPoint=stations[controlFrame].position;
++ for(std::size_t axis=0;axis<3;++axis)
++ negativeControlPoint[axis]-=0.1*frameTangents[controlFrame][axis];
++ const std::vector duplicateControlSlabs={
++ {0,controlFrame,false,true},{controlFrame,controlFrame+1,false,true}};
++ const std::vector gapControlSlabs={
++ {controlFrame,controlFrame+1,true,false}};
++ const auto ownerCount=[&](const std::vector& slabs,
++ const std::array& point)
++ {
++ std::size_t claims=0;
++ for(const auto& slab:slabs)
++ {
++ const auto state=slabState(slab,point);
++ if(state[0]&&state[1])++claims;
++ }
++ return claims;
++ };
++ result.ownershipNegativeControlsPass=
++ ownerCount(duplicateControlSlabs,negativeControlPoint)==2
++ &&ownerCount(gapControlSlabs,negativeControlPoint)==0;
++ result.bodyCurvatureFailures=0;
++ result.bodySelfOverlapFailures=0;
++ result.minimumBodyCurvatureRadiusMetres=
++ std::numeric_limits::infinity();
++ for(std::size_t index=1;index+1=result.lowerMouthFirstControlSpan)continue;
++ const double radius=curvatureRadius(index);
++ result.minimumBodyCurvatureRadiusMetres=std::min(
++ result.minimumBodyCurvatureRadiusMetres,radius);
++ if(radius=required
++ ||!isDoublyCritical(first,second))continue;
++ const bool sameUpper=a.controlSpan<=result.upperTransitionLastControlSpan
++ &&b.controlSpan<=result.upperTransitionLastControlSpan;
++ const bool sameLower=a.controlSpan>=result.lowerMouthFirstControlSpan
++ &&b.controlSpan>=result.lowerMouthFirstControlSpan;
++ if(!sameUpper&&!sameLower)++result.bodySelfOverlapFailures;
++ }
++ result.usesWholeRouteCompositeSlab=result.bodyCurvatureFailures>0
++ ||result.bodySelfOverlapFailures>0||result.zeroOwnerSamples>0
++ ||result.multipleOwnerSamples>0;
++ if(result.usesWholeRouteCompositeSlab)
++ {
++ // Pathological legacy routes can fold back across themselves. Keep their
++ // established union field by assigning the complete route to one owner;
++ // the normal path retains one slab per safe body segment.
++ testSlabs.assign(1,FTestSlab{0,segments.size(),false,false});
++ result.ownershipTestSamples=0;
++ result.zeroOwnerSamples=0;
++ result.multipleOwnerSamples=0;
++ result.firstZeroOwnerProbe=std::numeric_limits::max();
++ result.firstZeroOwnerSegment=std::numeric_limits::max();
++ for(std::size_t frame=0;frame center{},tangent{};
++ for(std::size_t axis=0;axis<3;++axis)
++ {
++ center[axis]=(stations[segment].position[axis]
++ +stations[segment+1].position[axis])*0.5;
++ tangent[axis]=frameTangents[segment][axis]
++ +frameTangents[segment+1][axis];
++ }
++ tangent=normalize(tangent);
++ if(tangent[0]==0.0&&tangent[1]==0.0&&tangent[2]==0.0)
++ tangent=frameTangents[segment];
++ testOwnershipCrossSection(center,tangent,
++ 0.5*(stations[segment].radius+stations[segment+1].radius),
++ stations.size()+segment);
++ }
++ }
++ if(result.upperMouthEndSegment>=result.lowerMouthStartSegment)
++ result.usesWholeRouteCompositeSlab=true;
++ result.valid=(result.usesWholeRouteCompositeSlab
++ ||(result.bodyCurvatureFailures==0
++ &&result.bodySelfOverlapFailures==0))
++ &&result.zeroOwnerSamples==0&&result.multipleOwnerSamples==0
++ &&result.ownershipNegativeControlsPass;
++ return result;
++ }
++
++ struct FSlabAuditKeyHash
++ {
++ std::size_t operator()(const std::vector& key) const noexcept
++ {
++ std::uint64_t hash=1469598103934665603ULL;
++ for(const std::uint64_t value:key)
++ {
++ hash^=value;
++ hash*=1099511628211ULL;
++ }
++ return static_cast(hash);
++ }
++ };
++
++ inline FSlabReachAudit AuditSlabReach(std::span segments,
++ std::size_t routeEndControlIndex,double unitsPerMetre,double routeReachMetres,
++ double safetyMarginMetres=0.05)
++ {
++ using FCache=std::unordered_map,
++ FSlabReachAudit,FSlabAuditKeyHash>;
++ static FCache cache;
++ static std::mutex cacheMutex;
++ std::vector key;
++ key.reserve(4+segments.size()*11);
++ key.push_back(static_cast(routeEndControlIndex));
++ key.push_back(std::bit_cast(unitsPerMetre));
++ key.push_back(std::bit_cast(routeReachMetres));
++ key.push_back(std::bit_cast(safetyMarginMetres));
++ for(const auto& segment:segments)
++ {
++ for(const double value:segment.a)
++ key.push_back(std::bit_cast(value));
++ for(const double value:segment.b)
++ key.push_back(std::bit_cast(value));
++ key.push_back(std::bit_cast(segment.alongMetres));
++ key.push_back(std::bit_cast(segment.lengthMetres));
++ key.push_back(static_cast(segment.controlSpan));
++ }
++ {
++ std::lock_guard lock(cacheMutex);
++ if(const auto found=cache.find(key);found!=cache.end())return found->second;
++ }
++
++ const FSlabReachAudit result=ComputeSlabReachAudit(segments,
++ routeEndControlIndex,unitsPerMetre,routeReachMetres,safetyMarginMetres);
++ {
++ std::lock_guard lock(cacheMutex);
++ constexpr std::size_t MaximumCachedRoutes=32;
++ if(cache.size()>=MaximumCachedRoutes)cache.clear();
++ const auto [found,inserted]=cache.emplace(std::move(key),result);
++ if(!inserted)return found->second;
++ }
++ return result;
++ }
+ }
+diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
+index dc4ca32..bdc3910 100644
+--- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
++++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
+@@ -494,7 +494,8 @@ namespace VoxelForgeCore
+ // Version 223 projects the floor onto one continuous arc-length profile and groups
+ // dense passage samples into coarse tile candidates. Version 224 keeps the same
+ // continuous floor while relaxing the spline chord tolerance and bounding shell work.
+- inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 225;
++ // Version 226 assigns route samples to reach-bounded slabs, with explicit mouth ownership.
++ inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 226;
+
+ enum class FieldChannel : std::uint32_t
+ {
+diff --git a/Standalone/Core/src/ResolvedLayoutInternal.h b/Standalone/Core/src/ResolvedLayoutInternal.h
+index 5fcb719..fc570c7 100644
+--- a/Standalone/Core/src/ResolvedLayoutInternal.h
++++ b/Standalone/Core/src/ResolvedLayoutInternal.h
+@@ -900,19 +900,22 @@ bool ResolvedLayoutSnapshotV3::finalize(std::string& error)
+ }
+ const std::int64_t playerCenterAboveFloorQ=static_cast(std::llround(
+ 1.13*WorldAssemblySubvoxelsPerVoxel*1000000.0/coreVoxelSizeMicrometres));
+- for(auto& passage:passages)
++ const auto lowerMouthIndexFor=[&](const ResolvedLayoutPassageV1& passage)
+ {
+- passage.lowerMouthControlIndex=passage.controlPoints.empty()?0:passage.controlPoints.size()-1;
+- for(std::size_t i=1;i issues;
+@@ -3239,6 +3242,34 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
+ passage.controlPoints[lowerMouthIndex].positionSubvoxels[2]=lowerMouth[2]
+ +passage.controlPoints[lowerMouthIndex].radiusSubvoxels
+ -playerCenterAboveFloorQ;
++ std::vector slabControls;
++ slabControls.reserve(passage.controlPoints.size());
++ for(const auto& point:passage.controlPoints)
++ slabControls.push_back({static_cast(point.positionSubvoxels[0]),
++ static_cast(point.positionSubvoxels[1]),
++ static_cast(point.positionSubvoxels[2]),
++ static_cast(point.radiusSubvoxels)});
++ constexpr double PassageSlabReachMetres=4.0+0.21+0.125;
++ const auto slabSegments=VoxelForgeCore::PassageSpline::BuildSegments(
++ slabControls,slabControls.size()-1,8.0,qPerMetre,{},0.100);
++ const auto slabAudit=VoxelForgeCore::PassageSpline::AuditSlabReach(
++ slabSegments,lowerMouthIndex,qPerMetre,PassageSlabReachMetres);
++ std::printf("[PassagePlanSlabAudit] id=%s frames=%zu reach_m=%.3f upper_mouth_spans=%zu lower_mouth_spans=%zu upper_end_segment=%zu lower_start_segment=%zu tight_mouth_joints=%zu nonlocal_mouth_pairs=%zu body_min_curvature_m=%.3f body_min_self_gap_m=%.3f body_curvature_failures=%zu body_self_overlap_failures=%zu ownership_test_samples=%zu zero_owners=%zu multiple_owners=%zu ownership_mode=%s negative_controls=%s status=%s\n",
++ passage.stableId.c_str(),slabSegments.size()+1,PassageSlabReachMetres,
++ slabAudit.upperMouthLastControlSpan+1,
++ slabAudit.lowerMouthFirstControlSpan<=lowerMouthIndex
++ ?lowerMouthIndex-slabAudit.lowerMouthFirstControlSpan+1:0,
++ slabAudit.upperMouthEndSegment,slabAudit.lowerMouthStartSegment,
++ slabAudit.tightMouthJoints,slabAudit.nonlocalMouthPairs,
++ slabAudit.minimumBodyCurvatureRadiusMetres,
++ slabAudit.minimumBodySelfGapMetres,slabAudit.bodyCurvatureFailures,
++ slabAudit.bodySelfOverlapFailures,slabAudit.ownershipTestSamples,
++ slabAudit.zeroOwnerSamples,slabAudit.multipleOwnerSamples,
++ slabAudit.usesWholeRouteCompositeSlab?"whole-route-composite":"per-segment",
++ slabAudit.ownershipNegativeControlsPass?"PASS":"FAIL",
++ slabAudit.valid?"PASS":"FAIL");
++ if(!slabAudit.valid)
++ {error=passage.stableId+" route cannot form unique reach-bounded ownership slabs";return false;}
+ layout.passages.push_back(std::move(passage));
+ }
+ }
+@@ -3268,9 +3299,10 @@ ResolvedLayoutValidatorAuditV3 AuditResolvedLayoutValidatorV3()
+ auto base=ResolvedLayoutSnapshotV3{};base.worldIdentity="synthetic";base.ownerVoxelSizeMicrometres=125000;
+ base.coreVoxelSizeMicrometres=250000;base.strates={make("a",0,10000000,0),make("b",1,-2000000,-12000000)};
+ ResolvedLayoutPassageConfigV1 passageConfig;passageConfig.upperStrateIndex=0;passageConfig.connections=1;
+- passageConfig.mouthRadiusSubvoxels=1280;passageConfig.midRadiusSubvoxels=1280;
++ passageConfig.style=0;passageConfig.mouthRadiusSubvoxels=1280;
++ passageConfig.midRadiusSubvoxels=1280;
+ passageConfig.reachMinimumSubvoxels=2048;passageConfig.reachMaximumSubvoxels=2048;
+- passageConfig.distanceMinimumSubvoxels=1024;passageConfig.distanceMaximumSubvoxels=10240;
++ passageConfig.distanceMinimumSubvoxels=1024;passageConfig.distanceMaximumSubvoxels=64*1024;
+ std::string planError;
+ if(!PlanResolvedLayoutPassagesV1(base,19,{passageConfig},planError))
+ result.failures.push_back({"synthetic_passage_plan_failed",planError});
+diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h
+index 517f375..229f57d 100644
+--- a/Standalone/Core/src/ShapeWorldInternal.h
++++ b/Standalone/Core/src/ShapeWorldInternal.h
+@@ -546,13 +546,13 @@ public:
+ return it==ResolvedLayout->strates.end()?nullptr:&*it;
+ }
+
+- void BindResolvedStratumFields()
++ bool BindResolvedStratumFields(std::string& Error)
+ {
+ BoundStratumFields.clear();
+ BoundManagerLayoutChunkWidthVoxels=Owner&&Owner->Manager
+ ?Owner->Manager->GetStrateLayoutChunkWidthVoxels():0.0f;
+ if(!ResolvedLayout||ResolvedLayout->strateLayoutChunkSizeMicrometres<=0)
+- {BuildPassageComposerConstants();return;}
++ return BuildPassageComposerConstants(Error);
+ const int64 ChunkWidthMicrometres=ResolvedLayout->strateLayoutChunkSizeMicrometres;
+ const auto FloorDiv64=[](int64 Value,int64 Divisor)
+ {
+@@ -637,7 +637,7 @@ public:
+ std::sort(BoundStratumFields.begin(),BoundStratumFields.end(),
+ [](const auto& A,const auto& B){return A.BottomChunkZ(1,ResolvedLayout->coreVoxelSizeMicrometres);
+ const double qx=static_cast(X)*Q,qy=static_cast(Y)*Q,
+ qz=static_cast(Z)*Q;
++ const std::array passageQueryPoint={qx,qy,qz};
+ const double shellThickness=FloorShellThicknessMetres*qPerMetre;
+ const auto* passageTileQueries=ActivePassageTileQueries;
+ const bool passageTileScopeMatches=passageTileQueries
+@@ -1289,8 +1290,13 @@ public:
+ double bestFloorCenterDistanceSq=std::numeric_limits::infinity();
+ const auto visitSegment=[&](std::size_t segmentIndex,int)
+ {
+- if(passageProfile)++passageProfile->passageCarveSegmentVisits;
+ const auto& segment=PassageSegmentData[passageIndex][segmentIndex];
++ const auto& ownershipSlabs=PassageOwnershipSlabs[passageIndex];
++ if(segment.ownershipSlabIndex>=ownershipSlabs.size()
++ ||!PassageOwnershipSlabOwns(
++ ownershipSlabs[segment.ownershipSlabIndex],passageQueryPoint))
++ return;
++ if(passageProfile)++passageProfile->passageCarveSegmentVisits;
+ if(segment.lengthSq<=0.0)return;
+ const double projection=(qx-segment.a[0])*segment.delta[0]
+ +(qy-segment.a[1])*segment.delta[1]
+@@ -1303,10 +1309,7 @@ public:
+ const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
+ const double roundDistance=DeterministicSqrt(
+ ex*ex+ey*ey+ez*ez)-radius;
+- const double floorT=segment.horizontalLengthSq>1.0e-12
+- ?(((qx-segment.a[0])*segment.delta[0]
+- +(qy-segment.a[1])*segment.delta[1])
+- /segment.horizontalLengthSq):t;
++ const double floorT=PassageOwnershipFloorT(segment,passageQueryPoint);
+ const double floorTClamped=std::clamp(floorT,0.0,1.0);
+ const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
+ const double floorRadius=segment.radiusA
+@@ -1363,6 +1366,11 @@ public:
+ const auto visitShellSegment=[&](std::size_t segmentIndex,int)
+ {
+ const auto& segment=PassageSegmentData[passageIndex][segmentIndex];
++ const auto& ownershipSlabs=PassageOwnershipSlabs[passageIndex];
++ if(segment.ownershipSlabIndex>=ownershipSlabs.size()
++ ||!PassageOwnershipSlabOwns(
++ ownershipSlabs[segment.ownershipSlabIndex],passageQueryPoint))
++ return;
+ if(segment.lengthSq<=0.0)return;
+ const double projection=(qx-segment.a[0])*segment.delta[0]
+ +(qy-segment.a[1])*segment.delta[1]
+@@ -1374,10 +1382,7 @@ public:
+ const double radius=segment.radiusA+t*segment.radiusDelta;
+ const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
+ const double roundDistance=DeterministicSqrt(ex*ex+ey*ey+ez*ez)-radius;
+- const double floorT=segment.horizontalLengthSq>1.0e-12
+- ?(((qx-segment.a[0])*segment.delta[0]
+- +(qy-segment.a[1])*segment.delta[1])
+- /segment.horizontalLengthSq):t;
++ const double floorT=PassageOwnershipFloorT(segment,passageQueryPoint);
+ const double floorTClamped=std::clamp(floorT,0.0,1.0);
+ const auto& segments=PassageSegmentData[passageIndex];
+ const double floorRadius=segment.radiusA
+@@ -2235,7 +2240,7 @@ public:
+ Scheduler=InScheduler;RoundTunnelsEnabled=bInRoundTunnels;
+ bUseNativeManifestFields=true;
+ UnbinnedSpatialPrimitiveIds.clear();
+- BindResolvedStratumFields();
++ if(!BindResolvedStratumFields(Error))return false;
+ bAnalyticOnly=false;
+ bProfileDetailBand=bInProfileDetailBand;
+ bParallelSignEdgeRepair=bInParallelSignEdgeRepair;
+@@ -2441,7 +2446,7 @@ public:
+ // Analytic pages retain their bounded owner bins for route bookkeeping. Once published,
+ // the Core world binds each page to its base shape as the single density evaluator.
+ bUseNativeManifestFields=true;
+- BindResolvedStratumFields();
++ if(!BindResolvedStratumFields(Error))return false;
+ RoundTunnelsEnabled=bInRoundTunnels;bAnalyticOnly=true;bProfileDetailBand=false;
+ for(int32 A=0;A<3;++A)
+ {
+@@ -2478,8 +2483,11 @@ public:
+ {
+ Owner=&World;WorldAssembly=InWorldAssembly;ResolvedLayout=InResolvedLayout;
+ NativeOnlyMinimum=InMinimum;NativeOnlyMaximum=InMaximum;
+- bUseNativeManifestFields=true;bNativeOnly=true;bAnalyticOnly=true;Built=true;
+- BindResolvedStratumFields();
++ bUseNativeManifestFields=true;bNativeOnly=true;bAnalyticOnly=true;
++ std::string ownershipError;
++ if(!BindResolvedStratumFields(ownershipError))
++ {bNativeOnly=false;bAnalyticOnly=false;Built=false;return;}
++ Built=true;
+ NativeOnlyViolations.store(0,std::memory_order_relaxed);
+ }
+
+@@ -3422,6 +3430,9 @@ private:
+ double floorDepthMetres=0.0,totalPathLengthMetres=0.0;
+ double authoredTotalPathLengthMetres=0.0;
+ std::size_t routeProfileSegmentCount=0;
++ std::size_t upperMouthEndSegment=0,upperMouthTransitionEndSegment=0;
++ std::size_t lowerMouthStartSegment=0,lowerMouthTransitionStartSegment=0;
++ bool wholeRouteCompositeSlab=false;
+ double upperMouthX=0.0,upperMouthY=0.0;
+ double upperMouthPlannedFloor=0.0;
+ double upperMouthTangentX=0.0,upperMouthTangentY=0.0;
+@@ -3431,14 +3442,114 @@ private:
+ struct FPassageSegmentData
+ {
+ std::array a{},b{},delta{};
++ std::array frameStartTangent{},frameEndTangent{};
+ std::array sweepMinimumSubvoxels{},sweepMaximumSubvoxels{};
+ double authoredFloorZA=0.0,authoredFloorZDelta=0.0;
+ double authoredAlongMetres=0.0,authoredLengthMetres=0.0;
+ double radiusA=0.0,radiusB=0.0,radiusDelta=0.0;
+ double lengthSq=0.0,horizontalLengthSq=0.0;
+ double lengthSubvoxels=0.0,horizontalLength=0.0;
++ std::size_t controlSpan=0,ownershipSlabIndex=0;
+ bool routeSegment=false;
+ };
++ struct FPassageOwnershipSlab
++ {
++ std::array startPosition{},endPosition{};
++ std::array startTangent{},endTangent{};
++ std::size_t firstSegment=0,endSegment=0;
++ bool hasStartPlane=true,hasEndPlane=true;
++ };
++ static double PassageOwnershipPlaneSide(
++ const std::array& point,const std::array& origin,
++ const std::array& tangent)
++ {
++ return (point[0]-origin[0])*tangent[0]
++ +(point[1]-origin[1])*tangent[1]
++ +(point[2]-origin[2])*tangent[2];
++ }
++ static bool PassageOwnershipSlabOwns(const FPassageOwnershipSlab& slab,
++ const std::array& point)
++ {
++ return (!slab.hasStartPlane
++ ||PassageOwnershipPlaneSide(point,slab.startPosition,
++ slab.startTangent)>=0.0)
++ &&(!slab.hasEndPlane
++ ||PassageOwnershipPlaneSide(point,slab.endPosition,
++ slab.endTangent)<0.0);
++ }
++ static bool PassageClipBoundsToOwnershipPlane(std::array& minimum,
++ std::array& maximum,const std::array& origin,
++ const std::array& tangent,bool keepPositive)
++ {
++ std::array,8> corners{};
++ std::array sides{};
++ for(std::size_t mask=0;mask clippedMinimum{
++ std::numeric_limits::infinity(),
++ std::numeric_limits::infinity(),
++ std::numeric_limits::infinity()};
++ std::array clippedMaximum{
++ -std::numeric_limits::infinity(),
++ -std::numeric_limits::infinity(),
++ -std::numeric_limits::infinity()};
++ bool hasPoint=false;
++ const auto include=[&](const std::array& point)
++ {
++ hasPoint=true;
++ for(std::size_t axis=0;axis<3;++axis)
++ {
++ clippedMinimum[axis]=std::min(clippedMinimum[axis],point[axis]);
++ clippedMaximum[axis]=std::max(clippedMaximum[axis],point[axis]);
++ }
++ };
++ const auto inside=[&](double side)
++ {return keepPositive?side>=0.0:side<=0.0;};
++ for(std::size_t corner=0;corner0.0)
++ ||(firstSide>0.0&&secondSide<0.0)))continue;
++ const double t=firstSide/(firstSide-secondSide);
++ std::array intersection{};
++ for(std::size_t component=0;component<3;++component)
++ intersection[component]=std::lerp(corners[first][component],
++ corners[second][component],t);
++ include(intersection);
++ }
++ if(!hasPoint)return false;
++ minimum=clippedMinimum;
++ maximum=clippedMaximum;
++ return true;
++ }
++ static double PassageOwnershipFloorT(const FPassageSegmentData& segment,
++ const std::array& point)
++ {
++ // Route floors are authored against horizontal distance along the path.
++ // Ownership remains a 3D plane decision; use XY projection here so a
++ // downhill floor point's vertical offset cannot move h(s) along the route.
++ if(segment.horizontalLengthSq>1.0e-12)
++ return ((point[0]-segment.a[0])*segment.delta[0]
++ +(point[1]-segment.a[1])*segment.delta[1])
++ /segment.horizontalLengthSq;
++ const double fromStart=PassageOwnershipPlaneSide(point,segment.a,
++ segment.frameStartTangent);
++ const double fromEnd=PassageOwnershipPlaneSide(point,segment.b,
++ segment.frameEndTangent);
++ const double denominator=fromStart-fromEnd;
++ if(std::abs(denominator)<=1.0e-12)return 0.0;
++ return fromStart/denominator;
++ }
+ static double PassageFlatFloorDepthSubvoxels(
+ const FPassageComposerConstants& constants,std::size_t segmentIndex,double t,
+ double radiusSubvoxels,double qPerMetre)
+@@ -4587,13 +4698,14 @@ private:
+ return result;
+ }
+
+- void BuildPassageComposerConstants()
++ bool BuildPassageComposerConstants(std::string& Error)
+ {
+ const bool tracePreparation=VF_IsL98PassagePrepareTraceEnabled();
+ const auto preparationStart=tracePreparation
+ ?std::chrono::steady_clock::now():std::chrono::steady_clock::time_point{};
+ PassageComposerConstants.clear();
+ PassageSegmentData.clear();
++ PassageOwnershipSlabs.clear();
+ PassageSegmentOffsets.clear();
+ if(!ResolvedLayout)
+ {
+@@ -4601,10 +4713,11 @@ private:
+ std::printf("[L113PassagePrepare] passages=0 control_spans=0 segments=0 max_spacing_m=8.00 max_chord_error_m=0.025 bytes=0 prepare_ms=%.3f\n",
+ std::chrono::duration(
+ std::chrono::steady_clock::now()-preparationStart).count());
+- return;
++ return true;
+ }
+ PassageComposerConstants.resize(ResolvedLayout->passages.size());
+ PassageSegmentData.resize(ResolvedLayout->passages.size());
++ PassageOwnershipSlabs.resize(ResolvedLayout->passages.size());
+ PassageSegmentOffsets.resize(ResolvedLayout->passages.size()+1,0);
+ constexpr double Q=static_cast(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
+ const double qPerMetre=Q*1000000.0/
+@@ -4670,6 +4783,39 @@ private:
+ const auto sampledSegments=VoxelForgeCore::PassageSpline::BuildSegments(
+ controls,controls.size()-1,PassageSegmentSpacingMetres,qPerMetre,
+ plannedFloorProfile,PassageSegmentChordErrorMetres);
++ constexpr double PassageSlabReachMetres=4.0+0.21+0.125;
++ const auto slabAudit=VoxelForgeCore::PassageSpline::AuditSlabReach(
++ sampledSegments,routeEnd,qPerMetre,PassageSlabReachMetres);
++ constants.upperMouthEndSegment=slabAudit.upperMouthEndSegment;
++ constants.upperMouthTransitionEndSegment=
++ slabAudit.upperMouthTransitionEndSegment;
++ constants.lowerMouthStartSegment=slabAudit.lowerMouthStartSegment;
++ constants.lowerMouthTransitionStartSegment=
++ slabAudit.lowerMouthTransitionStartSegment;
++ constants.wholeRouteCompositeSlab=slabAudit.usesWholeRouteCompositeSlab;
++ std::printf("[PassagePreparedSlabAudit] id=%s frames=%zu reach_m=%.3f upper_end_segment=%zu upper_transition_end_segment=%zu lower_transition_start_segment=%zu lower_start_segment=%zu tight_mouth_joints=%zu nonlocal_mouth_pairs=%zu body_min_curvature_m=%.3f body_min_self_gap_m=%.3f body_curvature_failures=%zu body_self_overlap_failures=%zu ownership_test_samples=%zu zero_owners=%zu multiple_owners=%zu ownership_mode=%s negative_controls=%s first_zero_probe=%zu first_zero_segment=%zu first_zero_point_m=(%.3f,%.3f,%.3f) first_zero_plane_side_m=(%.3f,%.3f) status=%s\n",
++ ResolvedLayout->passages[passageIndex].stableId.c_str(),
++ sampledSegments.size()+1,PassageSlabReachMetres,
++ slabAudit.upperMouthEndSegment,slabAudit.upperMouthTransitionEndSegment,
++ slabAudit.lowerMouthTransitionStartSegment,slabAudit.lowerMouthStartSegment,
++ slabAudit.tightMouthJoints,slabAudit.nonlocalMouthPairs,
++ slabAudit.minimumBodyCurvatureRadiusMetres,
++ slabAudit.minimumBodySelfGapMetres,slabAudit.bodyCurvatureFailures,
++ slabAudit.bodySelfOverlapFailures,slabAudit.ownershipTestSamples,
++ slabAudit.zeroOwnerSamples,slabAudit.multipleOwnerSamples,
++ slabAudit.usesWholeRouteCompositeSlab?"whole-route-composite":"per-segment",
++ slabAudit.ownershipNegativeControlsPass?"PASS":"FAIL",
++ slabAudit.firstZeroOwnerProbe,slabAudit.firstZeroOwnerSegment,
++ slabAudit.firstZeroOwnerPoint[0],slabAudit.firstZeroOwnerPoint[1],
++ slabAudit.firstZeroOwnerPoint[2],slabAudit.firstZeroOwnerStartSide,
++ slabAudit.firstZeroOwnerEndSide,
++ slabAudit.valid?"PASS":"FAIL");
++ if(!slabAudit.valid)
++ {
++ Error=ResolvedLayout->passages[passageIndex].stableId
++ +" route does not have unique reach-bounded ownership slabs";
++ return false;
++ }
+ constexpr double MaximumFloorGradeDegrees=15.0;
+ constexpr double DegreesPerRadian=180.0/3.14159265358979323846;
+ double maximumFloorGradeDegrees=0.0;
+@@ -4739,6 +4885,7 @@ private:
+ for(const auto& raw:rawSegments)
+ {
+ FPassageSegmentData data;
++ data.controlSpan=raw.controlSpan;
+ data.authoredFloorZA=raw.plannedFloorA;
+ data.authoredFloorZDelta=raw.plannedFloorB-raw.plannedFloorA;
+ data.authoredAlongMetres=raw.alongMetres;
+@@ -4794,6 +4941,7 @@ private:
+ preparedSegments*sizeof(FPassageSegmentData),
+ std::chrono::duration(
+ std::chrono::steady_clock::now()-preparationStart).count());
++ return true;
+ }
+
+ void BuildPassageSpatialIndices()
+@@ -4823,6 +4971,78 @@ private:
+ {
+ const std::size_t segmentCount=PassageSegmentData[passageIndex].size();
+ if(segmentCount==0)continue;
++ auto& segments=PassageSegmentData[passageIndex];
++ auto& slabs=PassageOwnershipSlabs[passageIndex];
++ std::vector> frameTangents(segmentCount+1);
++ const auto normalized=[](std::array value)
++ {
++ const double length=std::sqrt(value[0]*value[0]+value[1]*value[1]
++ +value[2]*value[2]);
++ if(length>1.0e-12)
++ for(double& component:value)component/=length;
++ return value;
++ };
++ for(std::size_t frame=0;frame<=segmentCount;++frame)
++ {
++ const std::array incoming=frame>0
++ ?normalized(segments[frame-1].delta):std::array{};
++ const std::array outgoing=frame{};
++ std::array tangent{};
++ if(frame==0)tangent=outgoing;
++ else if(frame==segmentCount)tangent=incoming;
++ else
++ for(std::size_t axis=0;axis<3;++axis)
++ tangent[axis]=incoming[axis]+outgoing[axis];
++ tangent=normalized(tangent);
++ if(tangent[0]==0.0&&tangent[1]==0.0&&tangent[2]==0.0)
++ tangent=frame=end)return;
++ FPassageOwnershipSlab slab;
++ slab.firstSegment=first;slab.endSegment=end;
++ slab.hasStartPlane=first>0;
++ slab.hasEndPlane=end=lowerMouthStart)
++ addOwnershipSlab(0,segmentCount);
++ else
++ {
++ addOwnershipSlab(0,upperMouthEnd);
++ addOwnershipSlab(upperMouthEnd,upperTransitionEnd);
++ for(std::size_t segment=upperTransitionEnd;
++ segment segmentIds(segmentCount);
+ for(std::size_t i=0;i1.0e-9)
++ {
++ std::array direction=prepared.delta;
++ const double inverseLength=1.0/prepared.lengthSubvoxels;
++ for(double& component:direction)component*=inverseLength;
++ const auto tangentCosine=[&](const std::array& tangent)
++ {
++ return std::clamp(direction[0]*tangent[0]
++ +direction[1]*tangent[1]+direction[2]*tangent[2],-1.0,1.0);
++ };
++ const double startCos=tangentCosine(prepared.frameStartTangent);
++ const double endCos=tangentCosine(prepared.frameEndTangent);
++ if(startCos>1.0e-6&&endCos>1.0e-6)
++ {
++ const double alongExtra=localExtent*std::max(
++ std::sqrt(std::max(0.0,1.0-startCos*startCos))/startCos,
++ std::sqrt(std::max(0.0,1.0-endCos*endCos))/endCos);
++ for(std::size_t axis=0;axis<3;++axis)
++ {
++ axisExtent=localExtent*std::sqrt(std::max(0.0,
++ 1.0-direction[axis]*direction[axis]))
++ +alongExtra*std::abs(direction[axis])+0.11;
++ prepared.sweepMinimumSubvoxels[axis]=
++ static_cast(std::floor(
++ (localMinimum[axis]-axisExtent)*Q));
++ prepared.sweepMaximumSubvoxels[axis]=
++ static_cast(std::ceil(
++ (localMaximum[axis]+axisExtent)*Q));
++ }
++ hasTightSweepBounds=true;
++ }
++ }
++ if(!hasTightSweepBounds)
++ {
++ for(std::size_t axis=0;axis<3;++axis)
++ {
++ prepared.sweepMinimumSubvoxels[axis]=static_cast(
++ std::floor((localMinimum[axis]-localExtent)*Q));
++ prepared.sweepMaximumSubvoxels[axis]=static_cast(
++ std::ceil((localMaximum[axis]+localExtent)*Q));
++ }
++ }
++ const auto& slab=slabs[prepared.ownershipSlabIndex];
++ std::array clippedMinimum{},clippedMaximum{};
+ for(std::size_t axis=0;axis<3;++axis)
+ {
+- prepared.sweepMinimumSubvoxels[axis]=static_cast(
+- std::floor((localMinimum[axis]-localExtent)*Q));
+- prepared.sweepMaximumSubvoxels[axis]=static_cast(
+- std::ceil((localMaximum[axis]+localExtent)*Q));
++ clippedMinimum[axis]=static_cast(
++ prepared.sweepMinimumSubvoxels[axis]);
++ clippedMaximum[axis]=static_cast(
++ prepared.sweepMaximumSubvoxels[axis]);
++ }
++ bool clipped=true;
++ if(slab.hasStartPlane)
++ clipped=PassageClipBoundsToOwnershipPlane(clippedMinimum,
++ clippedMaximum,slab.startPosition,slab.startTangent,true);
++ if(clipped&&slab.hasEndPlane)
++ clipped=PassageClipBoundsToOwnershipPlane(clippedMinimum,
++ clippedMaximum,slab.endPosition,slab.endTangent,false);
++ if(!clipped)
++ {
++ prepared.sweepMinimumSubvoxels={1,1,1};
++ prepared.sweepMaximumSubvoxels={0,0,0};
++ }
++ else
++ {
++ for(std::size_t axis=0;axis<3;++axis)
++ {
++ prepared.sweepMinimumSubvoxels[axis]=
++ static_cast(std::floor(clippedMinimum[axis]));
++ prepared.sweepMaximumSubvoxels[axis]=
++ static_cast(std::ceil(clippedMaximum[axis]));
++ }
+ }
+ }
+ const double routeExtent=maximumRadiusSubvoxels/Q+requiredReach+0.01;
+@@ -11433,6 +11724,7 @@ private:
+ std::vector> PassageNearestNodes;
+ std::vector PassageComposerConstants;
+ std::vector> PassageSegmentData;
++ std::vector> PassageOwnershipSlabs;
+ std::vector PassageSegmentOffsets;
+ std::vector PassageProofBounds;
+ std::vector PassageProofNodes;
+@@ -11507,6 +11799,7 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
+ passageSamples.samples.resize(gridSampleCount);
+ const auto& constants=shape_->PassageComposerConstants[passageIndex];
+ const auto& segments=shape_->PassageSegmentData[passageIndex];
++ const auto& ownershipSlabs=shape_->PassageOwnershipSlabs[passageIndex];
+ for(const auto& candidate:candidates)
+ {
+ if(candidate.segmentIndex>=segments.size())continue;
+@@ -11571,11 +11864,86 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
+ if(segmentFirst[0]>segmentLast[0]
+ ||segmentFirst[1]>segmentLast[1]
+ ||segmentFirst[2]>segmentLast[2])continue;
+- for(std::int32_t gz=segmentFirst[2];gz<=segmentLast[2];++gz)
++ if(segment.ownershipSlabIndex>=ownershipSlabs.size())continue;
++ const auto& ownershipSlab=ownershipSlabs[segment.ownershipSlabIndex];
++ std::size_t scanAxis=0;
++ for(std::size_t axis=1;axis<3;++axis)
+ {
+- for(std::int32_t gy=segmentFirst[1];gy<=segmentLast[1];++gy)
+- for(std::int32_t gx=segmentFirst[0];gx<=segmentLast[0];++gx)
++ const double currentScore=std::abs(ownershipSlab.startTangent[axis])
++ +std::abs(ownershipSlab.endTangent[axis]);
++ const double bestScore=std::abs(ownershipSlab.startTangent[scanAxis])
++ +std::abs(ownershipSlab.endTangent[scanAxis]);
++ if(currentScore>bestScore)scanAxis=axis;
++ }
++ const std::size_t rowAxisA=(scanAxis+1)%3;
++ const std::size_t rowAxisB=(scanAxis+2)%3;
++ for(std::int32_t rowB=segmentFirst[rowAxisB];
++ rowB<=segmentLast[rowAxisB];++rowB)
++ {
++ for(std::int32_t rowA=segmentFirst[rowAxisA];
++ rowA<=segmentLast[rowAxisA];++rowA)
+ {
++ std::array gridCoordinates{};
++ gridCoordinates[rowAxisA]=rowA;
++ gridCoordinates[rowAxisB]=rowB;
++ std::int32_t scanFirst=segmentFirst[scanAxis];
++ std::int32_t scanLast=segmentLast[scanAxis];
++ const auto constrainPlane=[&](
++ const std::array& origin,
++ const std::array& tangent,bool keepPositive)
++ {
++ double intercept=-origin[scanAxis]*tangent[scanAxis];
++ for(std::size_t axis=0;axis<3;++axis)
++ {
++ if(axis==scanAxis)continue;
++ const double coordinate=static_cast(
++ sweep->gridMinimumSubvoxels[axis]
++ +static_cast(gridCoordinates[axis])
++ *sweep->stepSubvoxels);
++ intercept+=(coordinate-origin[axis])*tangent[axis];
++ }
++ const double direction=tangent[scanAxis];
++ if(direction==0.0)
++ {
++ if(keepPositive?intercept<0.0:intercept>=0.0)
++ {scanFirst=1;scanLast=0;}
++ return;
++ }
++ const double boundary=-intercept/direction;
++ const double relative=(boundary
++ -sweep->gridMinimumSubvoxels[scanAxis])
++ /sweep->stepSubvoxels;
++ const double clampedRelative=std::clamp(relative,-1.0,
++ static_cast(sweep->dimension)+1.0);
++ if(keepPositive&&direction>0.0)
++ scanFirst=std::max(scanFirst,
++ static_cast(
++ std::ceil(clampedRelative))-1);
++ else if(keepPositive)
++ scanLast=std::min(scanLast,
++ static_cast(
++ std::floor(clampedRelative))+1);
++ else if(direction>0.0)
++ scanLast=std::min(scanLast,
++ static_cast(
++ std::ceil(clampedRelative)));
++ else
++ scanFirst=std::max(scanFirst,
++ static_cast(
++ std::floor(clampedRelative)));
++ };
++ if(ownershipSlab.hasStartPlane)
++ constrainPlane(ownershipSlab.startPosition,
++ ownershipSlab.startTangent,true);
++ if(scanFirst<=scanLast&&ownershipSlab.hasEndPlane)
++ constrainPlane(ownershipSlab.endPosition,
++ ownershipSlab.endTangent,false);
++ for(std::int32_t scan=scanFirst;scan<=scanLast;++scan)
++ {
++ gridCoordinates[scanAxis]=scan;
++ const std::int32_t gx=gridCoordinates[0];
++ const std::int32_t gy=gridCoordinates[1];
++ const std::int32_t gz=gridCoordinates[2];
+ const double qx=static_cast(sweep->gridMinimumSubvoxels[0]
+ +static_cast(gx)*sweep->stepSubvoxels);
+ const double qy=static_cast(sweep->gridMinimumSubvoxels[1]
+@@ -11586,6 +11954,15 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
+ *static_cast(sweep->dimension)+static_cast(gy))
+ *static_cast(sweep->dimension)+static_cast(gx);
+ auto& sample=passageSamples.samples[sampleIndex];
++ // The scan interval was clipped against both ownership planes, with
++ // one grid-step guard. Only its ends can lie outside the exact slab;
++ // keep the exact predicate there and skip two plane dot products for
++ // every interior sample. The plan audit independently checks unique
++ // ownership throughout the full support radius.
++ if((scan==scanFirst||scan==scanLast)
++ &&!FStandaloneShapeWorld::PassageOwnershipSlabOwns(
++ ownershipSlabs[segment.ownershipSlabIndex],{qx,qy,qz}))
++ continue;
+ const double projectionXY=(qx-segment.a[0])*segment.delta[0]
+ +(qy-segment.a[1])*segment.delta[1];
+ const double t=std::clamp((projectionXY
+@@ -11599,8 +11976,8 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
+ ex*ex+ey*ey+ez*ez)-radius;
+ if(profile&&signedDistanceinfluenceSubvoxels+1.0)
+ ++contributingPairCount;
+- const double floorT=segment.horizontalLengthSq>1.0e-12
+- ?projectionXY/segment.horizontalLengthSq:t;
++ const double floorT=FStandaloneShapeWorld::PassageOwnershipFloorT(
++ segment,{qx,qy,qz});
+ const double floorTClamped=std::clamp(floorT,0.0,1.0);
+ const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
+ const double floorRadius=segment.radiusA
+@@ -11612,20 +11989,32 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
+ constants,segments,segmentIndex,floorT,segment,
+ qx,qy,floorDepth,qPerMetre);
+ if(profile)++profileStats_->passageSweepSegmentSamplePairs;
+- if(signedDistance>sweep->influenceSubvoxels)
++ // A normal body slab contains one segment, so it owns the floor
++ // profile directly. Mouth transitions and pathological composite
++ // routes deliberately group segments into one slab and retain their
++ // established nearest-floor tie-break within that owner.
++ if(ownershipSlab.firstSegment==segmentIndex
++ &&ownershipSlab.endSegment==segmentIndex+1)
+ {
+- if(profile)++profileStats_->passageSweepOutsideInfluencePairs;
++ sample.floorCenterZSubvoxels=floorCenterZ;
++ sample.floorDepthSubvoxels=floorDepth;
++ sample.floorT=floorT;
++ sample.floorSegmentIndex=static_cast(segmentIndex);
++ sample.floorCenterDistanceSq=floorCenterDistanceSq;
+ }
+- if(floorCenterDistanceSq(
+- segmentIndex);
++ sample.floorSegmentIndex=static_cast(segmentIndex);
++ sample.floorCenterDistanceSq=floorCenterDistanceSq;
++ }
++ if(signedDistance>sweep->influenceSubvoxels)
++ {
++ if(profile)++profileStats_->passageSweepOutsideInfluencePairs;
+ }
+ // A negative shell distance is possible only when the flattened tube
+ // distance lies in [0, shellThickness]. SmoothMaxDistance is at least
+@@ -11707,12 +12096,13 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
+ sample.hasWallRelief=false;
+ sample.hasExactContribution=true;
+ if(profile)++profileStats_->passageSweepMinimumUpdates;
+- }
++ }
+ }
+ }
+ }
+ }
+ }
++ }
+
+ for(auto& passageSamples:sweep->passages)
+ {
+diff --git a/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-floating-islands-style2-v226.baseline b/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-floating-islands-style2-v226.baseline
+new file mode 100644
+index 0000000..cab68d6
+--- /dev/null
++++ b/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-floating-islands-style2-v226.baseline
+@@ -0,0 +1,12 @@
++[PipelineFullDetailHash] tiles=960 density=0x91931a57a067fd92 mesh=0xa818654be89790ac payload=0x370ff80451105a39 topology=0x06e507557aa70173
++[PipelineWholeViewHash] tiles=2370 density=0x3ce77475b5908860 mesh=0x80d3ca4b215ddb16 payload=0xf838e9c8ece70933 topology=0xdf790ec894e60a20
++[PipelineLODHash] lod=0 tiles=512 density=0x2fd4c78685a43cfe mesh=0x50478cff1c1f8ca0 payload=0x54e48e57e0af26de topology=0x860c011cfdb9833a
++[PipelineLODHash] lod=1 tiles=448 density=0x4b8d9a6dcd2942ad mesh=0x17e89b7087bfe711 payload=0x2389c109eb780db6 topology=0x7eccd4cf560d0630
++[PipelineLODHash] lod=2 tiles=320 density=0xb3e6e0585b0fc92d mesh=0x16c9a82c59e0f3d3 payload=0x1b32fc2e695144de topology=0x89a1eddead8849c1
++[PipelineLODHash] lod=3 tiles=208 density=0xe7c3ce8c79544110 mesh=0xff01589508cbbe69 payload=0xe4370a5d39da57c3 topology=0x2ea4ffeae7c72463
++[PipelineLODHash] lod=4 tiles=240 density=0xfb11591772a3d18e mesh=0xebf2baee8764591b payload=0xe491d7ac9c0061ad topology=0xd618ac33b95ce494
++[PipelineLODHash] lod=5 tiles=144 density=0x2f8b7b7fb1e67258 mesh=0x4cd508cbe97344fd payload=0x2b6e96a6050458c9 topology=0x4ff6d0eda8988573
++[PipelineLODHash] lod=6 tiles=96 density=0x0114a34c8b8d6113 mesh=0xb1fec4d01ae1fa44 payload=0x3e50cfd429b8e950 topology=0x08090c96d15c1618
++[PipelineLODHash] lod=7 tiles=96 density=0x3836ed8cfce73418 mesh=0x40bc6589c5fc1aac payload=0x677349bcae16790f topology=0x36e3aa53192e6a6b
++[PipelineLODHash] lod=8 tiles=306 density=0x144f3c1fd722708b mesh=0xef77b28bf7fd9453 payload=0xe3f47b37fcd61489 topology=0x5a3c73e295494e04
++[PipelineExactQueryHash] probes=9 density=0x7b7c50ac24ccadcc unclamped=0x7b7c50ac24ccadcc detail=0xefcba20c0c70c415 collision=0xe604823a249029bf path=direct-Core-queries
+diff --git a/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-owner4-surface-world-style1-v226.baseline b/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-owner4-surface-world-style1-v226.baseline
+new file mode 100644
+index 0000000..3af58f0
+--- /dev/null
++++ b/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-owner4-surface-world-style1-v226.baseline
+@@ -0,0 +1,12 @@
++[PipelineFullDetailHash] tiles=960 density=0x8351b0410e09bad1 mesh=0x065b56bf31023628 payload=0xa8f438d8c4247999 topology=0x9bb94e8edb2c8dce
++[PipelineWholeViewHash] tiles=2578 density=0xd95e78cea6a82b28 mesh=0xa50dbd869848a6fe payload=0xc78599692cb2e67a topology=0x5274c97954eee2c8
++[PipelineLODHash] lod=0 tiles=512 density=0x1a13bdd0641f3c46 mesh=0x010f1ce532bc0bae payload=0x5c249f31a0e55494 topology=0x5fbad4f63b23eaab
++[PipelineLODHash] lod=1 tiles=448 density=0xb1cdeec444ad72fa mesh=0x0d26924ba452ec23 payload=0xc93967164a6fd098 topology=0x86b8391e622498f0
++[PipelineLODHash] lod=2 tiles=320 density=0x9bca76e9112eb2ad mesh=0x4c4a0c509b59c7e6 payload=0xfb7985d6da664124 topology=0xae622b59ae115234
++[PipelineLODHash] lod=3 tiles=272 density=0x267227f5066ac775 mesh=0x4945616669ae8489 payload=0xf3e83d394410d28e topology=0x56b7e63096340e41
++[PipelineLODHash] lod=4 tiles=272 density=0xb743eb64967bddcd mesh=0xf6b5bd36b0ebfead payload=0xd1284c1540f50636 topology=0x4a6e197e2a1a9500
++[PipelineLODHash] lod=5 tiles=208 density=0x38706b628a74dd17 mesh=0x445b1c7b51489cbb payload=0x713efc66290768f7 topology=0x56486b919146bb1e
++[PipelineLODHash] lod=6 tiles=144 density=0xd53849b2002a1faa mesh=0xaa210abc8498c415 payload=0xd109aef8639706d1 topology=0x61a4d75fbbc35268
++[PipelineLODHash] lod=7 tiles=96 density=0xb0ea9a140275c9cc mesh=0x3ffd8365c8b0ec29 payload=0x3577afb0a2e4a420 topology=0x97530aafde15b7e0
++[PipelineLODHash] lod=8 tiles=306 density=0x8b3d1816799d67a0 mesh=0x80bf554f17700e1e payload=0xccbe22c3333a9c34 topology=0xcb11b28f6b6bcc50
++[PipelineExactQueryHash] probes=9 density=0xf2df67b38b7802df unclamped=0x48b347986345b557 detail=0xefcba20c0c70c415 collision=0x137e8f6c0b03a624 path=direct-Core-queries
+diff --git a/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-surface-world-style1-v226.baseline b/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-surface-world-style1-v226.baseline
+new file mode 100644
+index 0000000..1f591cf
+--- /dev/null
++++ b/Standalone/Tools/verify/baselines/owner-hash/canonical/owner-hash-surface-world-style1-v226.baseline
+@@ -0,0 +1,12 @@
++[PipelineFullDetailHash] tiles=960 density=0xace56c8f205238ad mesh=0xa9c603a1248de6b8 payload=0xea55f1f4fcc6a894 topology=0x5ea7bc78a1b678ae
++[PipelineWholeViewHash] tiles=2370 density=0xb91a65f2b5d23dd1 mesh=0xcb21ea0acbcf7482 payload=0x812c3d1f7ff8d3b8 topology=0xb18b9bc29e243ba2
++[PipelineLODHash] lod=0 tiles=512 density=0xcd6ab28cfa504aca mesh=0xf03dc80a669fca31 payload=0x397aded1c3d2d297 topology=0xb4a1dc84fabc1fe3
++[PipelineLODHash] lod=1 tiles=448 density=0xce6e713828b2a20a mesh=0x1cf408c25d67d18c payload=0x8a2b5d20571c997e topology=0x51cd985fe8e7d100
++[PipelineLODHash] lod=2 tiles=320 density=0xe06c3509977d89df mesh=0x4d81f55877e78bde payload=0x4dff71b395ce032c topology=0x8af5aa065efee965
++[PipelineLODHash] lod=3 tiles=208 density=0x60940ca350c1110a mesh=0xd386632a7d9271c0 payload=0x02e312e98024ef89 topology=0x0a5335eabb257106
++[PipelineLODHash] lod=4 tiles=240 density=0x0be8798407724eaf mesh=0x131c303cbbe51434 payload=0x2a90ecf0a2411ca0 topology=0xe3e054a371152e08
++[PipelineLODHash] lod=5 tiles=144 density=0xf20897ad272103a9 mesh=0x13d00b6253ae1f72 payload=0x0db3880693a962fa topology=0x462bd87a80f15e89
++[PipelineLODHash] lod=6 tiles=96 density=0xc040fcac457d6313 mesh=0x1ed132eeb718fb62 payload=0xcd0214e35577c6e3 topology=0x2c56c69e6fdcfd64
++[PipelineLODHash] lod=7 tiles=96 density=0xc2d419446355fdb8 mesh=0x4ea44452574fc84b payload=0xfd9779bedfc9ae0f topology=0x8948546e770c9b72
++[PipelineLODHash] lod=8 tiles=306 density=0x62db31696f2da831 mesh=0xd373f9e9481532fe payload=0x540a60526e0e3e46 topology=0xc725cb901e6dc335
++[PipelineExactQueryHash] probes=9 density=0xc949c4df2ce6f9d9 unclamped=0xc949c4df2ce6f9d9 detail=0x114c501e2d830d94 collision=0xe6011d3a248d4849 path=direct-Core-queries
+diff --git a/Standalone/Tools/verify/verify.py b/Standalone/Tools/verify/verify.py
+index 5fc1584..895ff60 100644
+--- a/Standalone/Tools/verify/verify.py
++++ b/Standalone/Tools/verify/verify.py
+@@ -122,11 +122,11 @@ RECIPE_RE = re.compile(
+
+ def owner_hash_baseline(recipe: str, style: int) -> tuple[Path, str]:
+ if recipe == "surface-world" and style == 1:
+- return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v225.baseline",
+- "L125-v225-stamped-passage-sweep")
++ return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v226.baseline",
++ "L128-v226-slab-owned-passage-sweep")
+ if recipe == "floating-islands" and style == 2:
+- return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v225.baseline",
+- "L125-v225-stamped-passage-sweep")
++ return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v226.baseline",
++ "L128-v226-slab-owned-passage-sweep")
+ raise VerificationFailure(f"no pinned owner hash baseline for {recipe} style {style}")
+
+