Compare commits

..
Author SHA1 Message Date
Fr0zkaandClaude Opus 5.5 7022d02e6e research: slab ownership for passage samples (L128, correct but slower; kept as patch)
Exact one-owner slabs (33,813 samples audited, controls fire), floor/seams/determinism green, routes already
satisfy R > S (S up to 7.9 m). But near-ready 8-21% behind 4041d4b and UE 30 m/s near 40.2 -> 31.5%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-10-30 21:21:24 +01:00
32 changed files with 3904 additions and 0 deletions

No files matched your search

@@ -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/`.
@@ -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 = ["<!doctype html><meta charset='utf-8'>",
"<title>L125 / L128 tunnel capture comparison</title>",
"<style>body{font:14px system-ui;margin:24px;background:#17191d;color:#eee}"
"section{margin:28px 0}h2{font-size:18px}div{display:grid;"
"grid-template-columns:1fr 1fr;gap:12px}img{width:100%;height:auto}"
"p{color:#bbb}</style>",
"<h1>L125 / L128 slab ownership: identical views</h1>"]
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(["<section>", f"<h2>{row['passage']} — {row['station']}</h2>",
f"<p>{row['kind']} · L125 {old['pixel_quality_status']} · "
f"L128 {row['pixel_quality_status']}</p>", "<div>",
f"<figure><figcaption>L125</figcaption><img src='{old_path}'></figure>",
f"<figure><figcaption>L128 slab ownership</figcaption><img src='{new_path}'></figure>",
"</div>", "</section>"])
(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())
@@ -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())
@@ -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())
@@ -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())
@@ -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())
@@ -0,0 +1,188 @@
<!doctype html><meta charset='utf-8'>
<title>L125 / L128 tunnel capture comparison</title>
<style>body{font:14px system-ui;margin:24px;background:#17191d;color:#eee}section{margin:28px 0}h2{font-size:18px}div{display:grid;grid-template-columns:1fr 1fr;gap:12px}img{width:100%;height:auto}p{color:#bbb}</style>
<h1>L125 / L128 slab ownership: identical views</h1>
<section>
<h2>passage/0-1/0 — rock-floor/401.7m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-rock-floor-station-1.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-rock-floor-station-1.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — rock-floor/792.8m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-rock-floor-station-2.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-rock-floor-station-2.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — rock-floor/1634.5m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-rock-floor-station-3.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-rock-floor-station-3.png'></figure>
</div>
</section>
<section>
<h2>passage/1-2/0 — rock-floor/27.0m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-rock-floor-station-1.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-1-2-0-rock-floor-station-1.png'></figure>
</div>
</section>
<section>
<h2>passage/1-2/0 — rock-floor/52.9m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-rock-floor-station-2.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-1-2-0-rock-floor-station-2.png'></figure>
</div>
</section>
<section>
<h2>passage/1-2/0 — rock-floor/78.9m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-rock-floor-station-3.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-1-2-0-rock-floor-station-3.png'></figure>
</div>
</section>
<section>
<h2>passage/2-3/0 — rock-floor/323.4m</h2>
<p>rock-floor-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-rock-floor-station-1.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-2-3-0-rock-floor-station-1.png'></figure>
</div>
</section>
<section>
<h2>passage/2-3/0 — rock-floor/333.4m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-rock-floor-station-2.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-2-3-0-rock-floor-station-2.png'></figure>
</div>
</section>
<section>
<h2>passage/2-3/0 — rock-floor/343.4m</h2>
<p>rock-floor-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-rock-floor-station-3.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-2-3-0-rock-floor-station-3.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — section-1/4m-outside</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-1-4m-outside.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-openair-1-4m-outside.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — section-1/4m-interior-wall</h2>
<p>open-air-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-1-4m-interior-wall.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-openair-1-4m-interior-wall.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — section-2/4m-outside</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-2-4m-outside.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-openair-2-4m-outside.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — section-2/4m-interior-wall</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-2-4m-interior-wall.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-openair-2-4m-interior-wall.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — section-3/4m-outside</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-3-4m-outside.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-openair-3-4m-outside.png'></figure>
</div>
</section>
<section>
<h2>passage/0-1/0 — section-3/4m-interior-wall</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-3-4m-interior-wall.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-0-1-0-openair-3-4m-interior-wall.png'></figure>
</div>
</section>
<section>
<h2>passage/1-2/0 — section-1/4m-outside</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-1-4m-outside.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-1-2-0-openair-1-4m-outside.png'></figure>
</div>
</section>
<section>
<h2>passage/1-2/0 — section-1/4m-interior-wall</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-1-4m-interior-wall.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-1-2-0-openair-1-4m-interior-wall.png'></figure>
</div>
</section>
<section>
<h2>passage/1-2/0 — section-2/4m-outside</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-2-4m-outside.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-1-2-0-openair-2-4m-outside.png'></figure>
</div>
</section>
<section>
<h2>passage/1-2/0 — section-2/4m-interior-wall</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-2-4m-interior-wall.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-1-2-0-openair-2-4m-interior-wall.png'></figure>
</div>
</section>
<section>
<h2>passage/2-3/0 — section-1/4m-outside</h2>
<p>open-air-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-1-4m-outside.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-2-3-0-openair-1-4m-outside.png'></figure>
</div>
</section>
<section>
<h2>passage/2-3/0 — section-1/4m-interior-wall</h2>
<p>open-air-close · L125 low_contrast_geometry_visible · L128 low_contrast_geometry_visible</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-1-4m-interior-wall.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-2-3-0-openair-1-4m-interior-wall.png'></figure>
</div>
</section>
<section>
<h2>passage/2-3/0 — section-2/4m-outside</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-2-4m-outside.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-2-3-0-openair-2-4m-outside.png'></figure>
</div>
</section>
<section>
<h2>passage/2-3/0 — section-2/4m-interior-wall</h2>
<p>open-air-close · L125 pass · L128 pass</p>
<div>
<figure><figcaption>L125</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-2-4m-interior-wall.png'></figure>
<figure><figcaption>L128 slab ownership</figcaption><img src='L128/passage-2-3-0-openair-2-4m-interior-wall.png'></figure>
</div>
</section>
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because it is too large. Load diff