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
107 lines
4.8 KiB
Python
107 lines
4.8 KiB
Python
#!/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())
|