Merge branch 'wip/l141-liminal' into wip/combined
No files matched your search
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build three standalone liminal SurfaceWorld fixtures from the owner input."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA",
|
||||
ROOT / "Standalone/data/owner_world.json"))
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l141"))
|
||||
|
||||
FLAT_FIELD = {
|
||||
"version": 1,
|
||||
"kind": "flatField",
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT / "fixtures")
|
||||
args = parser.parse_args()
|
||||
args.out.mkdir(parents=True, exist_ok=True)
|
||||
base = json.loads(OWNER.read_text(encoding="utf-8"))
|
||||
|
||||
flat = dict(base)
|
||||
flat["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
flat["motif_family_override"] = {
|
||||
"version": 1,
|
||||
"strate_index": 0,
|
||||
"placement_policy": "seed,strate,stable_id",
|
||||
"motifs": [
|
||||
{
|
||||
"stable_id": "liminal/oversized-familiar-monolith-v1",
|
||||
"kind": "cappedCylinder",
|
||||
"radius_m": 1.6,
|
||||
"height_m": 26.0,
|
||||
"route_side_offset_m": 42.0,
|
||||
"placement_radius_m": 0.0,
|
||||
"fillet_radius_m": 0.6,
|
||||
"blend_width_m": 1.2,
|
||||
"minimum_spacing_m": 0.0,
|
||||
"yaw_quarter_turns": 0,
|
||||
"attachment": "seated_floor",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
hills = dict(base)
|
||||
hills["surface_profile_override"] = {
|
||||
"version": 1,
|
||||
"kind": "periodicHills",
|
||||
"amplitude_x_m": 2.2,
|
||||
"amplitude_y_m": 2.2,
|
||||
"wavelength_x_m": 80.0,
|
||||
"wavelength_y_m": 80.0,
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
|
||||
road = dict(base)
|
||||
road["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
road["liminal_road_override"] = {
|
||||
"stable_id": "liminal/raised-road-v1",
|
||||
"strate_index": 0,
|
||||
"position_xy_m": [240.0, 180.0],
|
||||
"half_extents_m": [32.5, 3.0, 0.75],
|
||||
"deck_height_above_field_m": 22.0,
|
||||
"yaw_quarter_turns": 0,
|
||||
}
|
||||
|
||||
for name, fixture in (("flatField-monolith", flat),
|
||||
("periodicHills", hills),
|
||||
("raised-road", road)):
|
||||
path = args.out / f"liminal-{name}.json"
|
||||
path.write_text(json.dumps(fixture, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"[L141Fixture] name={name} file={path} status=PASS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,389 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run L141 prototype determinism checks and create eye-level/wide captures."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l141"))
|
||||
CAPTURE_DEFAULT = Path(__file__).resolve().parent / "captures"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
Q_PER_METRE = 1024.0
|
||||
FOG_COLOR = "0.66,0.73,0.77"
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import bounded_run, current_stamp, first_stamp
|
||||
|
||||
|
||||
def fmt(values) -> str:
|
||||
return ",".join(f"{value:.6f}" for value in values)
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def run_step(name: str, command: list[object], log: Path, *, env: dict[str, str],
|
||||
stamped: bool = False, timeout_seconds: int = 1740) -> str:
|
||||
expected_stamp = current_stamp() if stamped else None
|
||||
if stamped:
|
||||
binary = Path(str(command[0]))
|
||||
probe = bounded_run([str(binary), "--print-source-stamp"], timeout=15)
|
||||
if probe is None or probe.returncode != 0 or first_stamp(probe.stdout or "") != expected_stamp:
|
||||
raise RuntimeError(f"{name} refused a stale executable: {binary}")
|
||||
started = time.monotonic()
|
||||
log.parent.mkdir(parents=True, exist_ok=True)
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, f"timeout", f"{timeout_seconds}s",
|
||||
*map(str, command)], cwd=ROOT, env=env,
|
||||
stdout=stream, stderr=subprocess.STDOUT,
|
||||
timeout=timeout_seconds + 5, check=False)
|
||||
elapsed = time.monotonic() - started
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
print(f"[L141Run] step={name} elapsed_s={elapsed:.3f} exit={result.returncode} log={log}",
|
||||
flush=True)
|
||||
if stamped and (first_stamp(output) != expected_stamp or current_stamp() != expected_stamp):
|
||||
raise RuntimeError(f"{name} source stamp mismatch; see {log}")
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"{name} failed; see {log}")
|
||||
return output
|
||||
|
||||
|
||||
def route_frame(manifest_path: Path) -> tuple[tuple[float, float, float],
|
||||
tuple[float, float, float]]:
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
strata = [entry for entry in manifest["plan"]["strates"]
|
||||
if entry.get("route") and len(entry["route"]) >= 2]
|
||||
if not strata:
|
||||
raise RuntimeError(f"no planned SurfaceWorld route in {manifest_path}")
|
||||
route = strata[0]["route"]
|
||||
points = [tuple(float(value) / Q_PER_METRE for value in item["position_q"])
|
||||
for item in route]
|
||||
lengths = [math.dist(a, b) for a, b in zip(points, points[1:])]
|
||||
total = sum(lengths)
|
||||
if total <= 1.0e-6:
|
||||
raise RuntimeError(f"degenerate planned route in {manifest_path}")
|
||||
|
||||
def at(distance: float) -> tuple[float, float, float]:
|
||||
remaining = max(0.0, min(total, distance))
|
||||
for index, (a, b, length) in enumerate(zip(points, points[1:], lengths)):
|
||||
if remaining <= length or index == len(lengths) - 1:
|
||||
if length <= 1.0e-9:
|
||||
return b
|
||||
t = remaining / length
|
||||
return tuple(a[axis] + (b[axis] - a[axis]) * t for axis in range(3))
|
||||
remaining -= length
|
||||
return points[-1]
|
||||
|
||||
center = at(total * 0.5)
|
||||
before, after = at(total * 0.5 - 1.0), at(total * 0.5 + 1.0)
|
||||
dx, dy = after[0] - before[0], after[1] - before[1]
|
||||
length = math.hypot(dx, dy)
|
||||
if length <= 1.0e-9:
|
||||
raise RuntimeError(f"degenerate route tangent in {manifest_path}")
|
||||
return center, (dx / length, dy / length, 0.0)
|
||||
|
||||
|
||||
def camera_angles(camera, target) -> tuple[float, float]:
|
||||
dx, dy, dz = (target[index] - camera[index] for index in range(3))
|
||||
return math.degrees(math.atan2(dx, dy)), math.degrees(math.atan2(dz, math.hypot(dx, dy)))
|
||||
|
||||
|
||||
def point_toward(camera, target) -> tuple[float, ...]:
|
||||
yaw, pitch = camera_angles(camera, target)
|
||||
return (*camera, yaw, pitch)
|
||||
|
||||
|
||||
def stamp(layout: dict, stable_id: str) -> dict:
|
||||
for record in layout.get("stamps", []):
|
||||
if record.get("stable_id") == stable_id:
|
||||
return record
|
||||
raise RuntimeError(f"missing resolved stamp {stable_id}")
|
||||
|
||||
|
||||
def make_views(name: str, manifest_path: Path, layout_path: Path):
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
center, tangent = route_frame(manifest_path)
|
||||
tx, ty, _ = tangent
|
||||
nx, ny = -ty, tx
|
||||
base_height = manifest["recipe"]["surface_profile"]["h0_q"] / Q_PER_METRE
|
||||
if name == "flatField-monolith":
|
||||
monolith = stamp(layout, "liminal/oversized-familiar-monolith-v1")
|
||||
sx, sy, _ = (value / 1.0e6 for value in monolith["position_um"])
|
||||
floor = monolith["floor_um"] / 1.0e6
|
||||
eye_camera = (sx - tx * 36.0, sy - ty * 36.0, floor + 1.6)
|
||||
eye_target = (sx, sy, floor + 10.5)
|
||||
wide_camera = (sx - tx * 42.0 - nx * 18.0,
|
||||
sy - ty * 42.0 - ny * 18.0, floor + 42.0)
|
||||
wide_target = (sx, sy, floor + 8.0)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 20),
|
||||
"wide": (wide_camera, wide_target, 24),
|
||||
"height_center": floor,
|
||||
"height_range": 38.0,
|
||||
}
|
||||
if name == "periodicHills":
|
||||
# Route points are capsule centers: +0.72 m places the view at 1.60 m above ground.
|
||||
eye_camera = (center[0], center[1], center[2] + 0.72)
|
||||
eye_target = (center[0] - tx * 45.0, center[1] - ty * 45.0,
|
||||
center[2] + 0.72)
|
||||
wide_camera = (center[0] - tx * 20.0 - nx * 20.0,
|
||||
center[1] - ty * 20.0 - ny * 20.0, center[2] + 34.0)
|
||||
wide_target = (center[0] - tx * 45.0, center[1] - ty * 45.0,
|
||||
center[2] + 0.72)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 20),
|
||||
"wide": (wide_camera, wide_target, 28),
|
||||
"height_center": base_height,
|
||||
"height_range": 5.0,
|
||||
}
|
||||
road = stamp(layout, "liminal/raised-road-v1")
|
||||
rx, ry, rz = (value / 1.0e6 for value in road["position_um"])
|
||||
half_length, half_width, half_thickness = (
|
||||
value / 1.0e6 for value in road["half_extents_um"])
|
||||
deck = rz + half_thickness
|
||||
eye_camera = (rx - half_length + 14.0, ry, deck + 1.6)
|
||||
eye_target = (rx + half_length, ry, base_height)
|
||||
wide_camera = (rx, ry - 28.0, deck + 24.0)
|
||||
wide_target = (rx + 4.0, ry, base_height + 4.0)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 24),
|
||||
"wide": (wide_camera, wide_target, 26),
|
||||
"height_center": base_height + 11.0,
|
||||
"height_range": 32.0,
|
||||
"road_deck": deck,
|
||||
"road_width": 2.0 * half_width,
|
||||
}
|
||||
|
||||
|
||||
def headless_command(binary: Path, fixture: Path, camera, mesh: Path,
|
||||
manifest: Path, layout: Path, workers: int,
|
||||
clip_radius: int, *, hash_tiles: bool = False,
|
||||
audit_road: bool = False, max_level: int = 0) -> list[object]:
|
||||
command: list[object] = [binary, fixture, f"--workers={workers}",
|
||||
"--seed=0", "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", f"--clip-radius={clip_radius}",
|
||||
f"--max-clip-level={max_level}",
|
||||
f"--max-level={max_level}", "--render-distance-chunks=0",
|
||||
f"--camera={fmt(point_toward(camera, (camera[0], camera[1] + 1.0, camera[2])))}",
|
||||
f"--mesh-export={mesh}", f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
if hash_tiles:
|
||||
command.append("--stream-hash-tiles")
|
||||
if audit_road:
|
||||
command.append("--audit-liminal-road-walk")
|
||||
return command
|
||||
|
||||
|
||||
def determinism_digest(output: str, manifest_path: Path,
|
||||
layout_path: Path) -> tuple[str, str, str]:
|
||||
tile_hashes = sorted(line for line in output.splitlines()
|
||||
if line.startswith("[PipelineTileHash] "))
|
||||
if not manifest_path.is_file() or not layout_path.is_file() or not tile_hashes:
|
||||
raise RuntimeError("determinism run omitted manifest, layout or per-tile hashes")
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
manifest_digest = (manifest["content_hash"],manifest["recipe"]["content_hash"],
|
||||
manifest["plan"]["content_hash"])
|
||||
return ("|".join(manifest_digest),layout["stable_identity"],"\n".join(tile_hashes))
|
||||
|
||||
|
||||
def run_determinism(name: str, fixture: Path, view, *, binaries: dict[str, Path],
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
camera, _, _ = view["eye"]
|
||||
clip_radius = 1
|
||||
max_clip = 0
|
||||
baseline = None
|
||||
cells = 0
|
||||
for compiler, workers in ((compiler, workers)
|
||||
for compiler in ("clang", "gcc")
|
||||
for workers in (1, 8, 12)):
|
||||
tag = f"{name}-{compiler}-w{workers}"
|
||||
run_dir = out / "determinism" / tag
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
mesh = run_dir / "feature.vfmesh"
|
||||
manifest = run_dir / "manifest.json"
|
||||
layout = run_dir / "layout.json"
|
||||
command = headless_command(binaries[compiler], fixture,camera,mesh,manifest,
|
||||
layout,workers,max_clip,hash_tiles=True)
|
||||
output = run_step(tag,command,out/"logs"/f"determinism-{tag}.log",
|
||||
env=env,stamped=True)
|
||||
digest = determinism_digest(output,manifest,layout)
|
||||
if baseline is None:
|
||||
baseline = digest
|
||||
elif digest != baseline:
|
||||
raise RuntimeError(f"{name} diverged at {compiler} W{workers}; see determinism logs")
|
||||
cells += 1
|
||||
print(f"[L141Determinism] fixture={name} compiler_worker_cells={cells} identical=yes status=PASS",
|
||||
flush=True)
|
||||
|
||||
|
||||
def export_and_capture(name: str, fixture: Path, views: dict, *,
|
||||
headless: Path, renderer: Path, out: Path,
|
||||
artifact_dir: Path, env: dict[str, str]) -> None:
|
||||
for view_name in ("eye", "wide"):
|
||||
camera, target, clip_radius = views[view_name]
|
||||
clip_radius = min(clip_radius,7)
|
||||
stem = f"{name}-{view_name}"
|
||||
mesh = out / "capture-meshes" / f"{stem}.vfmesh"
|
||||
manifest = out / "capture-manifests" / f"{stem}.json"
|
||||
layout = out / "capture-layouts" / f"{stem}.json"
|
||||
png = out / "capture-png" / f"{stem}.png"
|
||||
image = artifact_dir / f"{stem}.jpg"
|
||||
for path in (mesh,manifest,layout,png,image):
|
||||
path.parent.mkdir(parents=True,exist_ok=True)
|
||||
command = headless_command(headless,fixture,camera,mesh,manifest,layout,12,
|
||||
clip_radius,max_level=0)
|
||||
output = run_step(f"capture-{stem}-export",command,
|
||||
out/"logs"/f"capture-{stem}-export.log",env=env,stamped=True)
|
||||
if not mesh.is_file() or mesh.stat().st_size == 0:
|
||||
raise RuntimeError(f"{stem} produced an empty mesh")
|
||||
yaw, pitch = camera_angles(camera,target)
|
||||
height_center = views["height_center"]
|
||||
height_range = views["height_range"]
|
||||
renderer_command = [renderer,mesh,png,"--size=1600x900","--fov-deg=72",
|
||||
f"--camera-m={fmt(camera)}",f"--yaw-deg={yaw:.6f}",
|
||||
f"--pitch-deg={pitch:.6f}","--tile-skirts=off","--shade=readable",
|
||||
"--headlamp=off","--height-tint=on",f"--height-center-m={height_center:.6f}",
|
||||
f"--height-range-m={height_range:.6f}","--light-direction=-0.42,-0.58,0.70",
|
||||
"--fog=on","--fog-start-m=30","--fog-end-m=105",f"--fog-color={FOG_COLOR}"]
|
||||
run_step(f"capture-{stem}-render",renderer_command,
|
||||
out/"logs"/f"capture-{stem}-render.log",env=env,stamped=True)
|
||||
run_step(f"capture-{stem}-jpeg",["ffmpeg","-nostdin","-hide_banner","-loglevel",
|
||||
"error","-y","-i",png,"-frames:v","1","-q:v","4",image],
|
||||
out/"logs"/f"capture-{stem}-jpeg.log",env=env)
|
||||
quality = run_step(f"capture-{stem}-quality",
|
||||
[sys.executable,ROOT/"Standalone/Tools/verify/capture_quality.py",image],
|
||||
out/"logs"/f"capture-{stem}-quality.log",env=env)
|
||||
if "[CaptureQuality]" not in quality or not image.is_file() \
|
||||
or image.stat().st_size > 300_000:
|
||||
raise RuntimeError(f"{stem} capture failed quality or size checks")
|
||||
eye_height = "1.600m" if view_name == "eye" else "wide"
|
||||
print(f"[L141Capture] fixture={name} view={view_name} eye_height={eye_height} "
|
||||
f"camera_m=({fmt(camera)}) target_m=({fmt(target)}) bytes={image.stat().st_size} "
|
||||
f"sha256={sha256(image)} status=PASS",flush=True)
|
||||
|
||||
|
||||
def run_road_walk_audit(fixture: Path, view, *, headless: Path,
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
camera = view["eye"][0]
|
||||
run_dir = out / "road-walk-audit"
|
||||
run_dir.mkdir(parents=True,exist_ok=True)
|
||||
output = run_step("road-walk-audit",headless_command(headless,fixture,camera,
|
||||
run_dir/"audit.vfmesh",run_dir/"manifest.json",run_dir/"layout.json",12,1,
|
||||
audit_road=True),out/"logs"/"road-walk-audit.log",env=env,stamped=True)
|
||||
if not re.search(r"\[LiminalRoadWalkAudit\].*status=PASS",output):
|
||||
raise RuntimeError("raised road failed the Core capsule walk audit")
|
||||
|
||||
|
||||
def measure_near_ready(fixture: Path, views: dict, *, headless: Path,
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
uptime = subprocess.run(["uptime"],cwd=ROOT,capture_output=True,text=True,check=True).stdout.strip()
|
||||
load_match = re.search(r"load average:\s*([0-9.]+)",uptime)
|
||||
if not load_match or float(load_match.group(1)) >= 1.5:
|
||||
raise RuntimeError(f"near-ready timing requires a quiet machine: {uptime}")
|
||||
print(f"[L141TimingEnvironment] window=one W12 run after one warmup uptime='{uptime}' "
|
||||
f"status=PASS",flush=True)
|
||||
camera = views["eye"][0]
|
||||
warm_dir = out / "near-ready" / "warmup"
|
||||
timed_dir = out / "near-ready" / "measured"
|
||||
warm_dir.mkdir(parents=True,exist_ok=True)
|
||||
timed_dir.mkdir(parents=True,exist_ok=True)
|
||||
|
||||
def command(directory: Path) -> list[object]:
|
||||
return [headless,fixture,"--workers=12","--world-assembler-prototype",
|
||||
"--seed=0","--stream-benchmark","--stream-pipeline","--force-generate",
|
||||
"--clip-radius=1","--max-clip-level=2","--max-level=2",
|
||||
"--render-distance-chunks=0",
|
||||
f"--camera={fmt(point_toward(camera,(camera[0],camera[1]+1.0,camera[2])))}",
|
||||
f"--world-assembler-manifest-output={directory/'manifest.json'}",
|
||||
f"--resolved-layout-output={directory/'layout.json'}"]
|
||||
|
||||
run_step("near-ready-warmup",command(warm_dir),
|
||||
out/"logs"/"near-ready-warmup.log",env=env,stamped=True)
|
||||
output = run_step("near-ready-measured",command(timed_dir),
|
||||
out/"logs"/"near-ready-measured.log",env=env,stamped=True)
|
||||
match = re.search(r"^\[WorldAssemblerNearLODPipelineReady\] lods=0-2 "
|
||||
r"tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$",output,re.M)
|
||||
if not match or match.group(1)!=match.group(2):
|
||||
raise RuntimeError("near-ready run did not complete the full LOD 0-2 set")
|
||||
print(f"[L141NearReady] window=one W12 run after one warmup clip_radius=1 "
|
||||
f"tiles={match.group(1)}/{match.group(2)} cold_ready_s={match.group(3)} status=PASS",
|
||||
flush=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT)
|
||||
parser.add_argument("--artifact-dir", type=Path, default=CAPTURE_DEFAULT)
|
||||
parser.add_argument("--headless-clang", type=Path, required=True)
|
||||
parser.add_argument("--headless-gcc", type=Path, required=True)
|
||||
parser.add_argument("--renderer", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
out = args.out.resolve()
|
||||
artifact_dir = args.artifact_dir.resolve()
|
||||
fixture_dir = out / "fixtures"
|
||||
for directory in (out,fixture_dir,artifact_dir):
|
||||
directory.mkdir(parents=True,exist_ok=True)
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(out)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT/"Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(out/"xdg-cache")
|
||||
run_step("build-fixtures",[sys.executable,
|
||||
ROOT/"Standalone/Research/WorldAssemblerM3/Linux141/BuildL141Fixtures.py",
|
||||
f"--out={fixture_dir}"],out/"logs"/"build-fixtures.log",env=env)
|
||||
|
||||
binaries = {"clang":args.headless_clang.resolve(),"gcc":args.headless_gcc.resolve()}
|
||||
fixtures = {
|
||||
"flatField-monolith":fixture_dir/"liminal-flatField-monolith.json",
|
||||
"periodicHills":fixture_dir/"liminal-periodicHills.json",
|
||||
"raised-road":fixture_dir/"liminal-raised-road.json",
|
||||
}
|
||||
probed = {}
|
||||
for name,fixture in fixtures.items():
|
||||
probe_dir=out/"plan-probes"/name
|
||||
probe_dir.mkdir(parents=True,exist_ok=True)
|
||||
camera=(0.0,0.0,-500.0)
|
||||
output=run_step(f"plan-probe-{name}",headless_command(binaries["clang"],fixture,
|
||||
camera,probe_dir/"probe.vfmesh",probe_dir/"manifest.json",
|
||||
probe_dir/"layout.json",12,1),out/"logs"/f"plan-probe-{name}.log",
|
||||
env=env,stamped=True)
|
||||
if "[WorldAssemblerFullManifest]" not in output:
|
||||
raise RuntimeError(f"{name} probe omitted its full plan manifest")
|
||||
probed[name]=make_views(name,probe_dir/"manifest.json",probe_dir/"layout.json")
|
||||
|
||||
for name,fixture in fixtures.items():
|
||||
run_determinism(name,fixture,probed[name],binaries=binaries,out=out,env=env)
|
||||
run_road_walk_audit(fixtures["raised-road"],probed["raised-road"],
|
||||
headless=binaries["clang"],out=out,env=env)
|
||||
for name,fixture in fixtures.items():
|
||||
export_and_capture(name,fixture,probed[name],headless=binaries["clang"],
|
||||
renderer=args.renderer.resolve(),out=out,artifact_dir=artifact_dir,env=env)
|
||||
measure_near_ready(fixtures["raised-road"],probed["raised-road"],
|
||||
headless=binaries["clang"],out=out,env=env)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L141Capture] status=FAIL error={error}",file=sys.stderr,flush=True)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,40 @@
|
||||
# L141 — first liminal layer
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
The standalone fixtures and six captures are ready for review. The flat field has one oversized capped-cylinder monolith. The road is a 65 m `fillDais` platform, 6 m wide, with its deck 22 m above a flat field. Fog supplies the road's cloud-sea backdrop in these standalone images.
|
||||
|
||||
The `periodicHills` fixture uses the validated 80 m periods and 2.2 m amplitudes on both axes. Its field repeats exactly, but these captures show one broad rise rather than hills repeating to the horizon. The validated period is longer than the 56 m eye-level capture radius; the wider full-detail capture exceeded Core's 160-million-node interval bound. Smaller periods fail the existing profile validator. A capture extent that trims vertical tiles independently from horizontal tiles is the next useful step; this round leaves the Core profile limits unchanged.
|
||||
|
||||
## Changes
|
||||
|
||||
- Reused Core's `flatField`, `periodicHills`, `fillMonolith`, and `fillDais` support. Added standalone fixture inputs and runners in `BuildL141Fixtures.py` and `CaptureL141.py`.
|
||||
- Added `liminal_road_override` as a standalone adapter to the existing free-placement `fillDais` stamp, plus `--audit-liminal-road-walk`. The walk audit samples the Core field with the existing capsule sampler and checks width and grade.
|
||||
- Added optional distance fog to `LinuxOffscreenCapture` for the screenshots. The fog is capture-only; Unreal cloud rendering remains Unreal-side.
|
||||
- No evaluator change or Unreal `Source/` change. Owner output hashes match their pinned L130/v227 canonical rows in the fast tier.
|
||||
|
||||
## Measurements
|
||||
|
||||
- Determinism: each fixture matched across Clang and GCC at W1, W8, and W12 (six cells per fixture). The matrix used LOD0, clip radius 1; each cell compares recipe/plan hashes, resolved-layout identity, and per-tile hashes. Individual logs are in `Saved/Linux/l141/logs/determinism-*.log`.
|
||||
- Raised-road capsule walk: 127 stations, 8,001 capsule samples, zero blocked samples, zero unsupported stations, 6.000 m width against a 0.680 m capsule diameter, and 0.000° grade. See `Saved/Linux/l141/logs/road-walk-audit.log`.
|
||||
- Near-ready: one W12 LOD0–2 sample after one warm-up, clip radius 1, 139/139 tiles. The measured `cold_ready_s` was **0.173886 s**. The window was one run after one warm-up; `uptime` showed a 1-minute load average of 1.31 and no other build was running. See `Saved/Linux/l141/logs/near-ready-measured.log`.
|
||||
- Each capture is 1600×900 and passed `capture_quality.py`. Eye views place the camera 1.6 m above the field or road deck. Camera coordinates and image hashes are recorded in the capture runner output; export and render logs are under `Saved/Linux/l141/logs/`.
|
||||
|
||||
## Checks
|
||||
|
||||
- Clang 19 and GCC standalone builds passed with FP contraction off, four jobs, and source stamp `0a2828c398aa62870690667901d44f2daf5b1a5547b9640da6dbb01df721af8b`.
|
||||
- `python3 Standalone/Tools/verify/verify.py fast --out Saved/Linux/l141 --overall-timeout 1740` passed in 285.7 s. Owner SurfaceWorld and FloatingIslands W1/W12 canonical hashes matched the L130/v227 baselines.
|
||||
- Fixture determinism, dedicated road walk audit, six standalone captures, and all six image-quality checks passed.
|
||||
- Python bytecode compilation and `git diff --check` passed.
|
||||
- An exploratory broad `--audit-resolved-layout-passages` invocation also ran unrelated passage ripple checks and reported 2/3 passage ripple records passing, with `passage/1-2/0` failing. The focused liminal road audit passes; no legacy threshold was changed.
|
||||
- No Unreal build was run because no Unreal `Source/` file changed. No timing matrix was requested or run.
|
||||
|
||||
## Remaining risk
|
||||
|
||||
The hill screenshots do not yet show multiple full repeats to the horizon. The profile itself is exactly periodic; the standalone capture volume is too short at the current full-detail safety bound. The raised road is geometric and walk-audited, while its clouds are represented by fog in the capture renderer.
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 33 KiB |
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the L142 liminal pictures and walk-audit controls."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA",
|
||||
ROOT / "Standalone/data/owner_world.json"))
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l142"))
|
||||
|
||||
FLAT_FIELD = {
|
||||
"version": 1,
|
||||
"kind": "flatField",
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT / "fixtures")
|
||||
args = parser.parse_args()
|
||||
args.out.mkdir(parents=True, exist_ok=True)
|
||||
base = json.loads(OWNER.read_text(encoding="utf-8"))
|
||||
|
||||
monolith = dict(base)
|
||||
monolith["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
monolith["motif_family_override"] = {
|
||||
"version": 1,
|
||||
"strate_index": 0,
|
||||
"placement_policy": "seed,strate,stable_id",
|
||||
"motifs": [{
|
||||
"stable_id": "liminal/oversized-familiar-monolith-v1",
|
||||
"kind": "cappedCylinder",
|
||||
"radius_m": 1.6,
|
||||
"height_m": 26.0,
|
||||
"route_side_offset_m": 42.0,
|
||||
"placement_radius_m": 0.0,
|
||||
"fillet_radius_m": 0.6,
|
||||
"blend_width_m": 1.2,
|
||||
"minimum_spacing_m": 0.0,
|
||||
"yaw_quarter_turns": 0,
|
||||
"attachment": "seated_floor",
|
||||
}],
|
||||
}
|
||||
|
||||
hills = dict(base)
|
||||
hills["surface_profile_override"] = {
|
||||
"version": 1,
|
||||
"kind": "periodicHills",
|
||||
"amplitude_x_m": 2.2,
|
||||
"amplitude_y_m": 2.2,
|
||||
"wavelength_x_m": 80.0,
|
||||
"wavelength_y_m": 80.0,
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
|
||||
road_override = {
|
||||
"stable_id": "liminal/road-clouds-v2",
|
||||
"strate_index": 0,
|
||||
"start_xy_m": [120.0, 340.0],
|
||||
"path_length_m": 360.0,
|
||||
"curve_control_offset_m": 84.0,
|
||||
"deck_height_above_field_m": 44.0,
|
||||
"rise_control_m": 22.0,
|
||||
"half_width_m": 4.0,
|
||||
"half_thickness_m": 1.0,
|
||||
"sample_spacing_m": 2.0,
|
||||
"support_spacing_m": 24.0,
|
||||
"support_radius_m": 0.55,
|
||||
}
|
||||
road = dict(base)
|
||||
road["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
road["liminal_road_override"] = dict(road_override)
|
||||
|
||||
short_control = dict(base)
|
||||
short_control["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
short_override = dict(road_override)
|
||||
short_override["path_length_m"] = 180.0
|
||||
short_control["liminal_road_override"] = short_override
|
||||
|
||||
pillars = dict(base)
|
||||
pillars["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
pillars["liminal_pillar_grid_override"] = {
|
||||
"stable_id": "liminal/horizon-pillar-grid-v1",
|
||||
"strate_index": 0,
|
||||
"center_xy_m": [700.0, 800.0],
|
||||
"rows": 15,
|
||||
"columns": 15,
|
||||
"spacing_m": 76.0,
|
||||
"radius_m": 5.5,
|
||||
"height_m": 40.0,
|
||||
}
|
||||
|
||||
fixtures = (
|
||||
("flatField-monolith", monolith),
|
||||
("periodicHills", hills),
|
||||
("road-in-clouds", road),
|
||||
("road-short-control", short_control),
|
||||
("pillar-grid", pillars),
|
||||
)
|
||||
for name, fixture in fixtures:
|
||||
path = args.out / f"liminal-{name}.json"
|
||||
path.write_text(json.dumps(fixture, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"[L142Fixture] name={name} file={path} status=PASS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,433 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run L142 liminal determinism checks, walk audits and multi-LOD captures."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l142"))
|
||||
CAPTURE_DEFAULT = Path(__file__).resolve().parent / "captures"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
Q_PER_METRE = 1024.0
|
||||
FOG_COLOR = "0.66,0.73,0.77"
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import bounded_run, current_stamp, first_stamp
|
||||
|
||||
|
||||
def fmt(values) -> str:
|
||||
return ",".join(f"{value:.6f}" for value in values)
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def run_step(name: str, command: list[object], log: Path, *, env: dict[str, str],
|
||||
stamped: bool = False, timeout_seconds: int = 1740,
|
||||
expected_exit: int = 0) -> str:
|
||||
expected_stamp = current_stamp() if stamped else None
|
||||
if stamped:
|
||||
binary = Path(str(command[0]))
|
||||
probe = bounded_run([str(binary), "--print-source-stamp"], timeout=15)
|
||||
if probe is None or probe.returncode != 0 or first_stamp(probe.stdout or "") != expected_stamp:
|
||||
raise RuntimeError(f"{name} refused a stale executable: {binary}")
|
||||
started = time.monotonic()
|
||||
log.parent.mkdir(parents=True, exist_ok=True)
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, f"timeout", f"{timeout_seconds}s",
|
||||
*map(str, command)], cwd=ROOT, env=env,
|
||||
stdout=stream, stderr=subprocess.STDOUT,
|
||||
timeout=timeout_seconds + 5, check=False)
|
||||
elapsed = time.monotonic() - started
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
print(f"[L142Run] step={name} elapsed_s={elapsed:.3f} exit={result.returncode} log={log}",
|
||||
flush=True)
|
||||
if stamped and (first_stamp(output) != expected_stamp or current_stamp() != expected_stamp):
|
||||
raise RuntimeError(f"{name} source stamp mismatch; see {log}")
|
||||
if result.returncode != expected_exit:
|
||||
raise RuntimeError(f"{name} exit={result.returncode}, expected={expected_exit}; see {log}")
|
||||
return output
|
||||
|
||||
|
||||
def route_frame(manifest_path: Path) -> tuple[tuple[float, float, float],
|
||||
tuple[float, float, float]]:
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
strata = [entry for entry in manifest["plan"]["strates"]
|
||||
if entry.get("route") and len(entry["route"]) >= 2]
|
||||
if not strata:
|
||||
raise RuntimeError(f"no planned SurfaceWorld route in {manifest_path}")
|
||||
route = strata[0]["route"]
|
||||
points = [tuple(float(value) / Q_PER_METRE for value in item["position_q"])
|
||||
for item in route]
|
||||
lengths = [math.dist(a, b) for a, b in zip(points, points[1:])]
|
||||
total = sum(lengths)
|
||||
if total <= 1.0e-6:
|
||||
raise RuntimeError(f"degenerate planned route in {manifest_path}")
|
||||
|
||||
def at(distance: float) -> tuple[float, float, float]:
|
||||
remaining = max(0.0, min(total, distance))
|
||||
for index, (a, b, length) in enumerate(zip(points, points[1:], lengths)):
|
||||
if remaining <= length or index == len(lengths) - 1:
|
||||
if length <= 1.0e-9:
|
||||
return b
|
||||
t = remaining / length
|
||||
return tuple(a[axis] + (b[axis] - a[axis]) * t for axis in range(3))
|
||||
remaining -= length
|
||||
return points[-1]
|
||||
|
||||
center = at(total * 0.5)
|
||||
before, after = at(total * 0.5 - 1.0), at(total * 0.5 + 1.0)
|
||||
dx, dy = after[0] - before[0], after[1] - before[1]
|
||||
length = math.hypot(dx, dy)
|
||||
if length <= 1.0e-9:
|
||||
raise RuntimeError(f"degenerate route tangent in {manifest_path}")
|
||||
return center, (dx / length, dy / length, 0.0)
|
||||
|
||||
|
||||
def camera_angles(camera, target) -> tuple[float, float]:
|
||||
dx, dy, dz = (target[index] - camera[index] for index in range(3))
|
||||
return math.degrees(math.atan2(dx, dy)), math.degrees(math.atan2(dz, math.hypot(dx, dy)))
|
||||
|
||||
|
||||
def point_toward(camera, target) -> tuple[float, ...]:
|
||||
yaw, pitch = camera_angles(camera, target)
|
||||
return (*camera, yaw, pitch)
|
||||
|
||||
|
||||
def stamp(layout: dict, stable_id: str) -> dict:
|
||||
for record in layout.get("stamps", []):
|
||||
if record.get("stable_id") == stable_id:
|
||||
return record
|
||||
raise RuntimeError(f"missing resolved stamp {stable_id}")
|
||||
|
||||
|
||||
def make_views(name: str, manifest_path: Path, layout_path: Path):
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
center, tangent = route_frame(manifest_path)
|
||||
tx, ty, _ = tangent
|
||||
nx, ny = -ty, tx
|
||||
base_height = manifest["recipe"]["surface_profile"]["h0_q"] / Q_PER_METRE
|
||||
if name == "flatField-monolith":
|
||||
monolith = stamp(layout, "liminal/oversized-familiar-monolith-v1")
|
||||
sx, sy, _ = (value / 1.0e6 for value in monolith["position_um"])
|
||||
floor = monolith["floor_um"] / 1.0e6
|
||||
eye_camera = (sx - tx * 36.0, sy - ty * 36.0, floor + 1.6)
|
||||
eye_target = (sx, sy, floor + 10.5)
|
||||
wide_camera = (sx - tx * 42.0 - nx * 18.0,
|
||||
sy - ty * 42.0 - ny * 18.0, floor + 42.0)
|
||||
wide_target = (sx, sy, floor + 8.0)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 20),
|
||||
"wide": (wide_camera, wide_target, 24),
|
||||
"height_center": floor,
|
||||
"height_range": 38.0,
|
||||
}
|
||||
if name == "periodicHills":
|
||||
# Route points are capsule centers: +0.72 m places the view at 1.60 m above ground.
|
||||
eye_camera = (center[0], center[1], center[2] + 0.72)
|
||||
eye_target = (center[0] - tx * 360.0, center[1] - ty * 360.0,
|
||||
center[2] + 0.72)
|
||||
wide_camera = (center[0] - tx * 36.0 - nx * 28.0,
|
||||
center[1] - ty * 36.0 - ny * 28.0, center[2] + 30.0)
|
||||
wide_target = (center[0] - tx * 310.0, center[1] - ty * 310.0,
|
||||
center[2] + 0.72)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 20),
|
||||
"wide": (wide_camera, wide_target, 28),
|
||||
"height_center": base_height,
|
||||
"height_range": 6.0,
|
||||
}
|
||||
if name == "road-in-clouds":
|
||||
deck = sorted((row for row in layout.get("stamps", [])
|
||||
if row.get("stable_id", "").startswith("liminal/road-clouds-v2/deck/")),
|
||||
key=lambda row: row["stable_id"])
|
||||
if len(deck) < 2:
|
||||
raise RuntimeError("road layout has no resolved swept platform chain")
|
||||
points = [tuple(value / 1.0e6 for value in row["position_um"])
|
||||
for row in deck]
|
||||
tops = [point[2] + row["half_extents_um"][2] / 1.0e6
|
||||
for point, row in zip(points, deck)]
|
||||
index = max(1, len(points) // 12)
|
||||
camera_dx = points[index + 1][0] - points[index - 1][0]
|
||||
camera_dy = points[index + 1][1] - points[index - 1][1]
|
||||
camera_tangent_length = math.hypot(camera_dx, camera_dy)
|
||||
camera_tx, camera_ty = (camera_dx / camera_tangent_length,
|
||||
camera_dy / camera_tangent_length)
|
||||
camera_nx, camera_ny = -camera_ty, camera_tx
|
||||
eye_camera = (points[index][0] + camera_nx * 3.2,
|
||||
points[index][1] + camera_ny * 3.2, tops[index] + 1.6)
|
||||
eye_target = (points[index][0] + camera_tx * 90.0 + camera_nx * 60.0,
|
||||
points[index][1] + camera_ty * 90.0 + camera_ny * 60.0,
|
||||
tops[index] - 44.0)
|
||||
middle = len(points) // 2
|
||||
dx = points[middle + 1][0] - points[middle - 1][0]
|
||||
dy = points[middle + 1][1] - points[middle - 1][1]
|
||||
tangent_length = math.hypot(dx, dy)
|
||||
tx, ty = dx / tangent_length, dy / tangent_length
|
||||
nx, ny = -ty, tx
|
||||
wide_target_index = min(len(points) - 1, middle + 30)
|
||||
wide_camera = (points[middle][0] - tx * 35.0 + nx * 30.0,
|
||||
points[middle][1] - ty * 35.0 + ny * 30.0,
|
||||
tops[middle] + 25.0)
|
||||
wide_target = (points[wide_target_index][0], points[wide_target_index][1],
|
||||
tops[wide_target_index] - 5.0)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 3),
|
||||
"wide": (wide_camera, wide_target, 3),
|
||||
"height_center": base_height + 23.0,
|
||||
"height_range": 60.0,
|
||||
"road_deck": tops[middle],
|
||||
"road_width": 2.0 * deck[middle]["half_extents_um"][1] / 1.0e6,
|
||||
}
|
||||
if name == "pillar-grid":
|
||||
pillars = [row for row in layout.get("stamps", [])
|
||||
if row.get("stable_id", "").startswith("liminal/horizon-pillar-grid-v1/pillar/")]
|
||||
if len(pillars) < 9:
|
||||
raise RuntimeError("pillar-grid layout has too few resolved supports")
|
||||
xs = [row["position_um"][0] / 1.0e6 for row in pillars]
|
||||
ys = [row["position_um"][1] / 1.0e6 for row in pillars]
|
||||
floor = min((row["position_um"][2] - row["half_extents_um"][2]) / 1.0e6
|
||||
for row in pillars)
|
||||
cx, cy = (min(xs) + max(xs)) * 0.5, (min(ys) + max(ys)) * 0.5
|
||||
eye_camera = (min(xs) - 78.0, cy, floor + 1.6)
|
||||
eye_target = (max(xs) + 90.0, cy, floor + 1.6)
|
||||
wide_camera = (cx - 280.0, cy - 420.0, floor + 230.0)
|
||||
wide_target = (cx, cy, floor + 6.0)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 3),
|
||||
"wide": (wide_camera, wide_target, 3),
|
||||
"height_center": floor + 12.0,
|
||||
"height_range": 42.0,
|
||||
}
|
||||
raise RuntimeError(f"no capture framing for fixture {name}")
|
||||
|
||||
|
||||
def headless_command(binary: Path, fixture: Path, camera, mesh: Path,
|
||||
manifest: Path, layout: Path, workers: int,
|
||||
clip_radius: int, *, hash_tiles: bool = False,
|
||||
audit_road: bool = False, max_level: int = 0,
|
||||
far_lods: bool = False,
|
||||
max_clip_override: int | None = None) -> list[object]:
|
||||
max_clip_level = (max_clip_override if max_clip_override is not None else
|
||||
8 if far_lods else max_level)
|
||||
command: list[object] = [binary, fixture, f"--workers={workers}",
|
||||
"--seed=0", "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", f"--clip-radius={clip_radius}",
|
||||
f"--max-clip-level={max_clip_level}",
|
||||
f"--max-level={max_level}", "--render-distance-chunks=0",
|
||||
f"--camera={fmt(point_toward(camera, (camera[0], camera[1] + 1.0, camera[2])))}",
|
||||
f"--mesh-export={mesh}", f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
if hash_tiles:
|
||||
command.append("--stream-hash-tiles")
|
||||
if audit_road:
|
||||
command.append("--audit-liminal-road-walk")
|
||||
return command
|
||||
|
||||
|
||||
def determinism_digest(output: str, manifest_path: Path,
|
||||
layout_path: Path) -> tuple[str, str, str]:
|
||||
tile_hashes = sorted(line for line in output.splitlines()
|
||||
if line.startswith("[PipelineTileHash] "))
|
||||
if not manifest_path.is_file() or not layout_path.is_file() or not tile_hashes:
|
||||
raise RuntimeError("determinism run omitted manifest, layout or per-tile hashes")
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
manifest_digest = (manifest["content_hash"],manifest["recipe"]["content_hash"],
|
||||
manifest["plan"]["content_hash"])
|
||||
return ("|".join(manifest_digest),layout["stable_identity"],"\n".join(tile_hashes))
|
||||
|
||||
|
||||
def run_determinism(name: str, fixture: Path, view, *, binaries: dict[str, Path],
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
camera, _, _ = view["eye"]
|
||||
clip_radius = 1
|
||||
max_clip = 0
|
||||
baseline = None
|
||||
cells = 0
|
||||
for compiler, workers in ((compiler, workers)
|
||||
for compiler in ("clang", "gcc")
|
||||
for workers in (1, 8, 12)):
|
||||
tag = f"{name}-{compiler}-w{workers}"
|
||||
run_dir = out / "determinism" / tag
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
mesh = run_dir / "feature.vfmesh"
|
||||
manifest = run_dir / "manifest.json"
|
||||
layout = run_dir / "layout.json"
|
||||
command = headless_command(binaries[compiler], fixture,camera,mesh,manifest,
|
||||
layout,workers,max_clip,hash_tiles=True)
|
||||
output = run_step(tag,command,out/"logs"/f"determinism-{tag}.log",
|
||||
env=env,stamped=True)
|
||||
digest = determinism_digest(output,manifest,layout)
|
||||
if baseline is None:
|
||||
baseline = digest
|
||||
elif digest != baseline:
|
||||
raise RuntimeError(f"{name} diverged at {compiler} W{workers}; see determinism logs")
|
||||
cells += 1
|
||||
print(f"[L142Determinism] fixture={name} compiler_worker_cells={cells} identical=yes status=PASS",
|
||||
flush=True)
|
||||
|
||||
|
||||
def export_and_capture(name: str, fixture: Path, views: dict, *,
|
||||
headless: Path, renderer: Path, out: Path,
|
||||
artifact_dir: Path, env: dict[str, str]) -> None:
|
||||
for view_name in ("eye", "wide"):
|
||||
camera, target, clip_radius = views[view_name]
|
||||
clip_radius = min(clip_radius,3)
|
||||
stem = f"{name}-{view_name}"
|
||||
mesh = out / "capture-meshes" / f"{stem}.vfmesh"
|
||||
manifest = out / "capture-manifests" / f"{stem}.json"
|
||||
layout = out / "capture-layouts" / f"{stem}.json"
|
||||
png = out / "capture-png" / f"{stem}.png"
|
||||
image = artifact_dir / f"{stem}.jpg"
|
||||
for path in (mesh,manifest,layout,png,image):
|
||||
path.parent.mkdir(parents=True,exist_ok=True)
|
||||
command = headless_command(headless,fixture,camera,mesh,manifest,layout,12,
|
||||
clip_radius,max_level=-1,far_lods=True,
|
||||
max_clip_override=(2 if name == "road-in-clouds" and view_name == "wide"
|
||||
else 3 if name == "road-in-clouds" else None))
|
||||
output = run_step(f"capture-{stem}-export",command,
|
||||
out/"logs"/f"capture-{stem}-export.log",env=env,stamped=True)
|
||||
if not mesh.is_file() or mesh.stat().st_size == 0:
|
||||
raise RuntimeError(f"{stem} produced an empty mesh")
|
||||
yaw, pitch = camera_angles(camera,target)
|
||||
height_center = views["height_center"]
|
||||
height_range = views["height_range"]
|
||||
if name == "road-in-clouds":
|
||||
fog_start,fog_end,fog_color=(24,260,"0.88,0.93,0.95")
|
||||
elif name == "pillar-grid":
|
||||
fog_start,fog_end,fog_color=220,1250,"0.82,0.88,0.91"
|
||||
elif name == "periodicHills":
|
||||
fog_start,fog_end,fog_color=210,1000,"0.78,0.84,0.88"
|
||||
else:
|
||||
fog_start,fog_end,fog_color=30,105,FOG_COLOR
|
||||
renderer_command = [renderer,mesh,png,"--size=1600x900","--fov-deg=72",
|
||||
f"--camera-m={fmt(camera)}",f"--yaw-deg={yaw:.6f}",
|
||||
f"--pitch-deg={pitch:.6f}","--tile-skirts=on","--shade=readable",
|
||||
"--headlamp=off","--height-tint=on",f"--height-center-m={height_center:.6f}",
|
||||
f"--height-range-m={height_range:.6f}","--light-direction=-0.42,-0.58,0.70",
|
||||
"--fog=on",f"--fog-start-m={fog_start}",f"--fog-end-m={fog_end}",
|
||||
f"--fog-color={fog_color}"]
|
||||
run_step(f"capture-{stem}-render",renderer_command,
|
||||
out/"logs"/f"capture-{stem}-render.log",env=env,stamped=True)
|
||||
run_step(f"capture-{stem}-jpeg",["ffmpeg","-nostdin","-hide_banner","-loglevel",
|
||||
"error","-y","-i",png,"-frames:v","1","-q:v","4",image],
|
||||
out/"logs"/f"capture-{stem}-jpeg.log",env=env)
|
||||
quality = run_step(f"capture-{stem}-quality",
|
||||
[sys.executable,ROOT/"Standalone/Tools/verify/capture_quality.py",image],
|
||||
out/"logs"/f"capture-{stem}-quality.log",env=env)
|
||||
if "[CaptureQuality]" not in quality or not image.is_file() \
|
||||
or image.stat().st_size > 300_000:
|
||||
raise RuntimeError(f"{stem} capture failed quality or size checks")
|
||||
eye_height = "1.600m" if view_name == "eye" else "wide"
|
||||
print(f"[L142Capture] fixture={name} view={view_name} eye_height={eye_height} "
|
||||
f"camera_m=({fmt(camera)}) target_m=({fmt(target)}) bytes={image.stat().st_size} "
|
||||
f"sha256={sha256(image)} status=PASS",flush=True)
|
||||
|
||||
|
||||
def run_road_walk_audit(fixture: Path, view, *, headless: Path,
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
camera = view["eye"][0]
|
||||
run_dir = out / "road-walk-audit"
|
||||
run_dir.mkdir(parents=True,exist_ok=True)
|
||||
output = run_step("road-walk-audit",headless_command(headless,fixture,camera,
|
||||
run_dir/"audit.vfmesh",run_dir/"manifest.json",run_dir/"layout.json",12,1,
|
||||
audit_road=True),out/"logs"/"road-walk-audit.log",env=env,stamped=True)
|
||||
if not re.search(r"\[LiminalRoadWalkAudit\].*status=PASS",output):
|
||||
raise RuntimeError("raised road failed the Core capsule walk audit")
|
||||
|
||||
|
||||
def run_road_short_negative_control(fixture: Path, view, *, headless: Path,
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
camera = view["eye"][0]
|
||||
run_dir = out / "road-short-negative-control"
|
||||
run_dir.mkdir(parents=True,exist_ok=True)
|
||||
output = run_step("road-short-negative-control",
|
||||
headless_command(headless,fixture,camera,run_dir/"control.vfmesh",
|
||||
run_dir/"manifest.json",run_dir/"layout.json",12,1,audit_road=True),
|
||||
out/"logs"/"road-short-negative-control.log",env=env,stamped=True,
|
||||
expected_exit=14)
|
||||
match = re.search(r"\[LiminalRoadWalkAudit\].*path_length_m=([0-9.]+).*status=FAIL",output)
|
||||
if not match or float(match.group(1)) >= 300.0:
|
||||
raise RuntimeError("short-road negative control did not falsify the length gate")
|
||||
print(f"[L142RoadNegativeControl] path_length_m={match.group(1)} "
|
||||
"expected=FAIL status=PASS",flush=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT)
|
||||
parser.add_argument("--artifact-dir", type=Path, default=CAPTURE_DEFAULT)
|
||||
parser.add_argument("--headless-clang", type=Path, required=True)
|
||||
parser.add_argument("--headless-gcc", type=Path, required=True)
|
||||
parser.add_argument("--renderer", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
out = args.out.resolve()
|
||||
artifact_dir = args.artifact_dir.resolve()
|
||||
fixture_dir = out / "fixtures"
|
||||
for directory in (out,fixture_dir,artifact_dir):
|
||||
directory.mkdir(parents=True,exist_ok=True)
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(out)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT/"Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(out/"xdg-cache")
|
||||
run_step("build-fixtures",[sys.executable,
|
||||
ROOT/"Standalone/Research/WorldAssemblerM3/Linux142/BuildL142Fixtures.py",
|
||||
f"--out={fixture_dir}"],out/"logs"/"build-fixtures.log",env=env)
|
||||
|
||||
binaries = {"clang":args.headless_clang.resolve(),"gcc":args.headless_gcc.resolve()}
|
||||
fixtures = {
|
||||
"flatField-monolith":fixture_dir/"liminal-flatField-monolith.json",
|
||||
"periodicHills":fixture_dir/"liminal-periodicHills.json",
|
||||
"road-in-clouds":fixture_dir/"liminal-road-in-clouds.json",
|
||||
"pillar-grid":fixture_dir/"liminal-pillar-grid.json",
|
||||
}
|
||||
probed = {}
|
||||
for name,fixture in fixtures.items():
|
||||
probe_dir=out/"plan-probes"/name
|
||||
probe_dir.mkdir(parents=True,exist_ok=True)
|
||||
camera=(0.0,0.0,-500.0)
|
||||
output=run_step(f"plan-probe-{name}",headless_command(binaries["clang"],fixture,
|
||||
camera,probe_dir/"probe.vfmesh",probe_dir/"manifest.json",
|
||||
probe_dir/"layout.json",12,1),out/"logs"/f"plan-probe-{name}.log",
|
||||
env=env,stamped=True)
|
||||
if "[WorldAssemblerFullManifest]" not in output:
|
||||
raise RuntimeError(f"{name} probe omitted its full plan manifest")
|
||||
probed[name]=make_views(name,probe_dir/"manifest.json",probe_dir/"layout.json")
|
||||
|
||||
for name,fixture in fixtures.items():
|
||||
run_determinism(name,fixture,probed[name],binaries=binaries,out=out,env=env)
|
||||
run_road_walk_audit(fixtures["road-in-clouds"],probed["road-in-clouds"],
|
||||
headless=binaries["clang"],out=out,env=env)
|
||||
run_road_short_negative_control(fixture_dir/"liminal-road-short-control.json",
|
||||
probed["road-in-clouds"],headless=binaries["clang"],out=out,env=env)
|
||||
for name,fixture in fixtures.items():
|
||||
export_and_capture(name,fixture,probed[name],headless=binaries["clang"],
|
||||
renderer=args.renderer.resolve(),out=out,artifact_dir=artifact_dir,env=env)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L142Capture] status=FAIL error={error}",file=sys.stderr,flush=True)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,46 @@
|
||||
# L142 — liminal pass 2
|
||||
|
||||
| Hills: eye height | Hills: wide |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
| Road: eye height | Road: wide |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
| Pillar grid: eye height | Pillar grid: wide |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
| Monolith: eye height | Monolith: wide |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
## Result
|
||||
|
||||
The wide hill capture shows the validated 80 m repeating profile continuing across the horizon. The capture now streams LOD 0–8; the profile period and validator are unchanged.
|
||||
|
||||
The road is a cubic swept path made from overlapping solid deck segments, not a chain of platform stamps. The earlier platform chain produced top steps; the swept deck passes the surface-sampled walk audit. Its wide view is capped at LOD 2 to keep the deck legible, so that frame shows a local section; the full route length is measured by the audit.
|
||||
|
||||
The R47 addition is a 15×15 grid of identical pillars, spaced 76 m apart across a 1,064 m span. The monolith eye and wide views are retained as the first liminal slice.
|
||||
|
||||
## Measurements
|
||||
|
||||
- **Road:** 376.827 m horizontal path length, 8.000 m width, and 12.061° maximum sampled surface grade against the 15° limit. The deck rises and falls along the cubic profile. It has 17 supports at about 24 m spacing; the flat cloud floor is 44 m below the deck centerline (about 45 m below the walking surface), with pale fog in both views.
|
||||
- **Walk audit:** 901 surface stations at no more than 0.5 m spacing; 56,763 capsule samples; 0 blocked samples, 0 unsupported samples across 5,871 support probes, 0 grade failures, and 0 missed surface probes. The 180 m short-road control measured 210.341 m and failed the 300 m gate as expected.
|
||||
- **Capture quality:** all eight fixtures/views passed the image-quality gate at 1600×900. Hills and pillars stream through LOD 8; road eye and wide views use caps 3 and 2 respectively.
|
||||
- **Determinism:** the monolith, hills, road, and pillar fixtures each matched across Clang and GCC at W1, W8, and W12 (six compiler/worker cells per fixture), on source stamp `72f239e9534faa27e3796fe29207403b190558403841aeebc87d8e75e98e34c7`.
|
||||
|
||||
## Checks
|
||||
|
||||
- Clang 19 and GCC builds passed with floating-point contraction off, four build jobs, and the L142 source stamp.
|
||||
- `Standalone/Tools/verify/verify.py fast --out Saved/Linux/l142 --overall-timeout 1740` passed. Both current owner fixtures produced all 12 canonical hash rows matching the pinned L130-v227 baseline; W1 and W12 also matched each other.
|
||||
- The fast summary retains non-gating differences against older L46/L53 diagnostic baselines; the current pinned L130 canonical checks pass.
|
||||
- The L142 capture runner passed the walk audit, the short-road negative control, all four determinism comparisons, and all eight image-quality checks. Final logs are in `Saved/Linux/l142/logs/`.
|
||||
- No Unreal build or performance timing matrix was run. No Unreal `Source/` files changed. The inherited single-run near-ready timing step was removed from this picture-and-geometry runner rather than treated as a timing result.
|
||||
|
||||
## Remaining limits
|
||||
|
||||
The road wide capture frames a local section at LOD 2 to retain a continuous deck; the 376.827 m length is established by the full-route walk audit. Captures use the standalone Linux renderer rather than an Unreal viewport.
|
||||
|
||||
Changed Unreal `Source/` files: none.
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 39 KiB |
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the L143 liminal pictures and walk-audit controls."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA",
|
||||
ROOT / "Standalone/data/owner_world.json"))
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l143"))
|
||||
|
||||
FLAT_FIELD = {
|
||||
"version": 1,
|
||||
"kind": "flatField",
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT / "fixtures")
|
||||
args = parser.parse_args()
|
||||
args.out.mkdir(parents=True, exist_ok=True)
|
||||
base = json.loads(OWNER.read_text(encoding="utf-8"))
|
||||
|
||||
monolith = dict(base)
|
||||
monolith["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
monolith["motif_family_override"] = {
|
||||
"version": 1,
|
||||
"strate_index": 0,
|
||||
"placement_policy": "seed,strate,stable_id",
|
||||
"motifs": [{
|
||||
"stable_id": "liminal/oversized-familiar-monolith-v1",
|
||||
"kind": "cappedCylinder",
|
||||
"radius_m": 1.6,
|
||||
"height_m": 26.0,
|
||||
"route_side_offset_m": 42.0,
|
||||
"placement_radius_m": 0.0,
|
||||
"fillet_radius_m": 0.6,
|
||||
"blend_width_m": 1.2,
|
||||
"minimum_spacing_m": 0.0,
|
||||
"yaw_quarter_turns": 0,
|
||||
"attachment": "seated_floor",
|
||||
}],
|
||||
}
|
||||
|
||||
hills = dict(base)
|
||||
hills["surface_profile_override"] = {
|
||||
"version": 1,
|
||||
"kind": "periodicHills",
|
||||
"amplitude_x_m": 2.2,
|
||||
"amplitude_y_m": 2.2,
|
||||
"wavelength_x_m": 80.0,
|
||||
"wavelength_y_m": 80.0,
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
|
||||
road_override = {
|
||||
"stable_id": "liminal/road-clouds-v2",
|
||||
"strate_index": 0,
|
||||
"start_xy_m": [120.0, 340.0],
|
||||
"path_length_m": 360.0,
|
||||
"curve_control_offset_m": 84.0,
|
||||
"deck_height_above_field_m": 44.0,
|
||||
"rise_control_m": 22.0,
|
||||
"half_width_m": 4.0,
|
||||
"half_thickness_m": 1.0,
|
||||
"sample_spacing_m": 1.0,
|
||||
"support_spacing_m": 24.0,
|
||||
"support_radius_m": 0.55,
|
||||
}
|
||||
road = dict(base)
|
||||
road["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
road["liminal_road_override"] = dict(road_override)
|
||||
|
||||
short_control = dict(base)
|
||||
short_control["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
short_override = dict(road_override)
|
||||
short_override["path_length_m"] = 180.0
|
||||
short_control["liminal_road_override"] = short_override
|
||||
|
||||
pillars = dict(base)
|
||||
pillars["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
pillars["liminal_pillar_grid_override"] = {
|
||||
"stable_id": "liminal/horizon-pillar-grid-v1",
|
||||
"strate_index": 0,
|
||||
"center_xy_m": [700.0, 800.0],
|
||||
"rows": 15,
|
||||
"columns": 15,
|
||||
"spacing_m": 76.0,
|
||||
"radius_m": 5.5,
|
||||
"height_m": 40.0,
|
||||
}
|
||||
|
||||
fixtures = (
|
||||
("flatField-monolith", monolith),
|
||||
("periodicHills", hills),
|
||||
("road-in-clouds", road),
|
||||
("road-short-control", short_control),
|
||||
("pillar-grid", pillars),
|
||||
)
|
||||
for name, fixture in fixtures:
|
||||
path = args.out / f"liminal-{name}.json"
|
||||
path.write_text(json.dumps(fixture, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"[L143Fixture] name={name} file={path} status=PASS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,463 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run L143 liminal determinism checks, walk audits and multi-LOD captures."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l143"))
|
||||
CAPTURE_DEFAULT = Path(__file__).resolve().parent / "captures"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
Q_PER_METRE = 1024.0
|
||||
FOG_COLOR = "0.66,0.73,0.77"
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import bounded_run, current_stamp, first_stamp
|
||||
|
||||
|
||||
def fmt(values) -> str:
|
||||
return ",".join(f"{value:.6f}" for value in values)
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def run_step(name: str, command: list[object], log: Path, *, env: dict[str, str],
|
||||
stamped: bool = False, timeout_seconds: int = 1740,
|
||||
expected_exit: int = 0) -> str:
|
||||
expected_stamp = current_stamp() if stamped else None
|
||||
if stamped:
|
||||
binary = Path(str(command[0]))
|
||||
probe = bounded_run([str(binary), "--print-source-stamp"], timeout=15)
|
||||
if probe is None or probe.returncode != 0 or first_stamp(probe.stdout or "") != expected_stamp:
|
||||
raise RuntimeError(f"{name} refused a stale executable: {binary}")
|
||||
started = time.monotonic()
|
||||
log.parent.mkdir(parents=True, exist_ok=True)
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, f"timeout", f"{timeout_seconds}s",
|
||||
*map(str, command)], cwd=ROOT, env=env,
|
||||
stdout=stream, stderr=subprocess.STDOUT,
|
||||
timeout=timeout_seconds + 5, check=False)
|
||||
elapsed = time.monotonic() - started
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
print(f"[L143Run] step={name} elapsed_s={elapsed:.3f} exit={result.returncode} log={log}",
|
||||
flush=True)
|
||||
if stamped and (first_stamp(output) != expected_stamp or current_stamp() != expected_stamp):
|
||||
raise RuntimeError(f"{name} source stamp mismatch; see {log}")
|
||||
if result.returncode != expected_exit:
|
||||
raise RuntimeError(f"{name} exit={result.returncode}, expected={expected_exit}; see {log}")
|
||||
return output
|
||||
|
||||
|
||||
def route_frame(manifest_path: Path) -> tuple[tuple[float, float, float],
|
||||
tuple[float, float, float]]:
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
strata = [entry for entry in manifest["plan"]["strates"]
|
||||
if entry.get("route") and len(entry["route"]) >= 2]
|
||||
if not strata:
|
||||
raise RuntimeError(f"no planned SurfaceWorld route in {manifest_path}")
|
||||
route = strata[0]["route"]
|
||||
points = [tuple(float(value) / Q_PER_METRE for value in item["position_q"])
|
||||
for item in route]
|
||||
lengths = [math.dist(a, b) for a, b in zip(points, points[1:])]
|
||||
total = sum(lengths)
|
||||
if total <= 1.0e-6:
|
||||
raise RuntimeError(f"degenerate planned route in {manifest_path}")
|
||||
|
||||
def at(distance: float) -> tuple[float, float, float]:
|
||||
remaining = max(0.0, min(total, distance))
|
||||
for index, (a, b, length) in enumerate(zip(points, points[1:], lengths)):
|
||||
if remaining <= length or index == len(lengths) - 1:
|
||||
if length <= 1.0e-9:
|
||||
return b
|
||||
t = remaining / length
|
||||
return tuple(a[axis] + (b[axis] - a[axis]) * t for axis in range(3))
|
||||
remaining -= length
|
||||
return points[-1]
|
||||
|
||||
center = at(total * 0.5)
|
||||
before, after = at(total * 0.5 - 1.0), at(total * 0.5 + 1.0)
|
||||
dx, dy = after[0] - before[0], after[1] - before[1]
|
||||
length = math.hypot(dx, dy)
|
||||
if length <= 1.0e-9:
|
||||
raise RuntimeError(f"degenerate route tangent in {manifest_path}")
|
||||
return center, (dx / length, dy / length, 0.0)
|
||||
|
||||
|
||||
def camera_angles(camera, target) -> tuple[float, float]:
|
||||
dx, dy, dz = (target[index] - camera[index] for index in range(3))
|
||||
return math.degrees(math.atan2(dx, dy)), math.degrees(math.atan2(dz, math.hypot(dx, dy)))
|
||||
|
||||
|
||||
def point_toward(camera, target) -> tuple[float, ...]:
|
||||
yaw, pitch = camera_angles(camera, target)
|
||||
return (*camera, yaw, pitch)
|
||||
|
||||
|
||||
def stamp(layout: dict, stable_id: str) -> dict:
|
||||
for record in layout.get("stamps", []):
|
||||
if record.get("stable_id") == stable_id:
|
||||
return record
|
||||
raise RuntimeError(f"missing resolved stamp {stable_id}")
|
||||
|
||||
|
||||
def make_views(name: str, manifest_path: Path, layout_path: Path):
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
center, tangent = route_frame(manifest_path)
|
||||
tx, ty, _ = tangent
|
||||
nx, ny = -ty, tx
|
||||
base_height = manifest["recipe"]["surface_profile"]["h0_q"] / Q_PER_METRE
|
||||
if name == "flatField-monolith":
|
||||
monolith = stamp(layout, "liminal/oversized-familiar-monolith-v1")
|
||||
sx, sy, _ = (value / 1.0e6 for value in monolith["position_um"])
|
||||
floor = monolith["floor_um"] / 1.0e6
|
||||
eye_camera = (sx - tx * 36.0, sy - ty * 36.0, floor + 1.6)
|
||||
eye_target = (sx, sy, floor + 10.5)
|
||||
wide_camera = (sx - tx * 42.0 - nx * 18.0,
|
||||
sy - ty * 42.0 - ny * 18.0, floor + 42.0)
|
||||
wide_target = (sx, sy, floor + 8.0)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 20),
|
||||
"wide": (wide_camera, wide_target, 24),
|
||||
"height_center": floor,
|
||||
"height_range": 38.0,
|
||||
}
|
||||
if name == "periodicHills":
|
||||
# Route points are capsule centers: +0.72 m places the view at 1.60 m above ground.
|
||||
eye_camera = (center[0], center[1], center[2] + 0.72)
|
||||
eye_target = (center[0] - tx * 360.0, center[1] - ty * 360.0,
|
||||
center[2] + 0.72)
|
||||
wide_camera = (center[0] - tx * 36.0 - nx * 28.0,
|
||||
center[1] - ty * 36.0 - ny * 28.0, center[2] + 30.0)
|
||||
wide_target = (center[0] - tx * 310.0, center[1] - ty * 310.0,
|
||||
center[2] + 0.72)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 20),
|
||||
"wide": (wide_camera, wide_target, 28),
|
||||
"height_center": base_height,
|
||||
"height_range": 6.0,
|
||||
}
|
||||
if name == "road-in-clouds":
|
||||
deck = stamp(layout,"liminal/road-clouds-v2/deck/000")
|
||||
path_um = deck.get("sweep_path_um", [])
|
||||
if len(path_um) < 2:
|
||||
raise RuntimeError("road layout has no resolved continuous swept path")
|
||||
points = [tuple(value / 1.0e6 for value in point) for point in path_um]
|
||||
half_thickness = deck["half_extents_um"][2] / 1.0e6
|
||||
top = lambda point: point[2] + half_thickness
|
||||
index = max(1, len(points) // 12)
|
||||
camera_dx = points[index + 1][0] - points[index - 1][0]
|
||||
camera_dy = points[index + 1][1] - points[index - 1][1]
|
||||
camera_tangent_length = math.hypot(camera_dx, camera_dy)
|
||||
camera_tx, camera_ty = (camera_dx / camera_tangent_length,
|
||||
camera_dy / camera_tangent_length)
|
||||
camera_nx, camera_ny = -camera_ty, camera_tx
|
||||
half_width = deck["half_extents_um"][1] / 1.0e6
|
||||
eye_target_index = min(len(points) - 1, index + 25)
|
||||
eye_camera = (points[index][0] + camera_nx * (half_width + 2.0),
|
||||
points[index][1] + camera_ny * (half_width + 2.0),
|
||||
top(points[index]) + 1.6)
|
||||
eye_target = (points[eye_target_index][0] + camera_nx * (half_width - 0.4),
|
||||
points[eye_target_index][1] + camera_ny * (half_width - 0.4),
|
||||
top(points[eye_target_index]) + 0.3)
|
||||
middle = len(points) // 2
|
||||
dx = points[middle + 1][0] - points[middle - 1][0]
|
||||
dy = points[middle + 1][1] - points[middle - 1][1]
|
||||
tangent_length = math.hypot(dx, dy)
|
||||
tx, ty = dx / tangent_length, dy / tangent_length
|
||||
nx, ny = -ty, tx
|
||||
wide_target_index = min(len(points) - 1, middle + 30)
|
||||
wide_camera = (points[middle][0] - tx * 35.0 + nx * 30.0,
|
||||
points[middle][1] - ty * 35.0 + ny * 30.0,
|
||||
top(points[middle]) + 25.0)
|
||||
wide_target = (points[wide_target_index][0], points[wide_target_index][1],
|
||||
top(points[wide_target_index]) - 5.0)
|
||||
cloud_camera = (points[middle][0] - tx * 18.0 + nx * 12.0,
|
||||
points[middle][1] - ty * 18.0 + ny * 12.0,
|
||||
base_height + 1.6)
|
||||
cloud_target = (points[middle][0] + tx * 8.0,
|
||||
points[middle][1] + ty * 8.0,
|
||||
points[middle][2] - half_thickness * 0.35)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 3),
|
||||
"wide": (wide_camera, wide_target, 3),
|
||||
"cloud-up": (cloud_camera, cloud_target, 3),
|
||||
"height_center": base_height + 23.0,
|
||||
"height_range": 60.0,
|
||||
"road_deck": top(points[middle]),
|
||||
"road_width": 2.0 * half_width,
|
||||
}
|
||||
if name == "pillar-grid":
|
||||
pillars = [row for row in layout.get("stamps", [])
|
||||
if row.get("stable_id", "").startswith("liminal/horizon-pillar-grid-v1/pillar/")]
|
||||
if len(pillars) < 9:
|
||||
raise RuntimeError("pillar-grid layout has too few resolved supports")
|
||||
xs = [row["position_um"][0] / 1.0e6 for row in pillars]
|
||||
ys = [row["position_um"][1] / 1.0e6 for row in pillars]
|
||||
floor = min((row["position_um"][2] - row["half_extents_um"][2]) / 1.0e6
|
||||
for row in pillars)
|
||||
cx, cy = (min(xs) + max(xs)) * 0.5, (min(ys) + max(ys)) * 0.5
|
||||
eye_camera = (min(xs) - 78.0, cy, floor + 1.6)
|
||||
eye_target = (max(xs) + 90.0, cy, floor + 1.6)
|
||||
wide_camera = (cx - 280.0, cy - 420.0, floor + 230.0)
|
||||
wide_target = (cx, cy, floor + 6.0)
|
||||
return {
|
||||
"eye": (eye_camera, eye_target, 3),
|
||||
"wide": (wide_camera, wide_target, 3),
|
||||
"height_center": floor + 12.0,
|
||||
"height_range": 42.0,
|
||||
}
|
||||
raise RuntimeError(f"no capture framing for fixture {name}")
|
||||
|
||||
|
||||
def headless_command(binary: Path, fixture: Path, camera, mesh: Path,
|
||||
manifest: Path, layout: Path, workers: int,
|
||||
clip_radius: int, *, hash_tiles: bool = False,
|
||||
audit_road: bool = False, max_level: int = 0,
|
||||
far_lods: bool = False,
|
||||
max_clip_override: int | None = None) -> list[object]:
|
||||
max_clip_level = (max_clip_override if max_clip_override is not None else
|
||||
8 if far_lods else max_level)
|
||||
command: list[object] = [binary, fixture, f"--workers={workers}",
|
||||
"--seed=0", "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", f"--clip-radius={clip_radius}",
|
||||
f"--max-clip-level={max_clip_level}",
|
||||
f"--max-level={max_level}", "--render-distance-chunks=0",
|
||||
f"--camera={fmt(point_toward(camera, (camera[0], camera[1] + 1.0, camera[2])))}",
|
||||
f"--mesh-export={mesh}", f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
if hash_tiles:
|
||||
command.append("--stream-hash-tiles")
|
||||
if audit_road:
|
||||
command.append("--audit-liminal-road-walk")
|
||||
return command
|
||||
|
||||
|
||||
def determinism_digest(output: str, manifest_path: Path,
|
||||
layout_path: Path) -> tuple[str, str, str]:
|
||||
tile_hashes = sorted(line for line in output.splitlines()
|
||||
if line.startswith("[PipelineTileHash] "))
|
||||
if not manifest_path.is_file() or not layout_path.is_file() or not tile_hashes:
|
||||
raise RuntimeError("determinism run omitted manifest, layout or per-tile hashes")
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
manifest_digest = (manifest["content_hash"],manifest["recipe"]["content_hash"],
|
||||
manifest["plan"]["content_hash"])
|
||||
return ("|".join(manifest_digest),layout["stable_identity"],"\n".join(tile_hashes))
|
||||
|
||||
|
||||
def run_determinism(name: str, fixture: Path, view, *, binaries: dict[str, Path],
|
||||
out: Path, env: dict[str, str], max_level: int = 0,
|
||||
far_lods: bool = False, max_clip_override: int | None = None) -> None:
|
||||
camera, _, _ = view["eye"]
|
||||
clip_radius = 1
|
||||
max_clip = 0
|
||||
baseline = None
|
||||
cells = 0
|
||||
for compiler, workers in ((compiler, workers)
|
||||
for compiler in ("clang", "gcc")
|
||||
for workers in (1, 8, 12)):
|
||||
tag = f"{name}-{compiler}-w{workers}"
|
||||
run_dir = out / "determinism" / tag
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
mesh = run_dir / "feature.vfmesh"
|
||||
manifest = run_dir / "manifest.json"
|
||||
layout = run_dir / "layout.json"
|
||||
command = headless_command(binaries[compiler], fixture,camera,mesh,manifest,
|
||||
layout,workers,max_clip,hash_tiles=True,max_level=max_level,
|
||||
far_lods=far_lods,max_clip_override=max_clip_override)
|
||||
output = run_step(tag,command,out/"logs"/f"determinism-{tag}.log",
|
||||
env=env,stamped=True)
|
||||
digest = determinism_digest(output,manifest,layout)
|
||||
if baseline is None:
|
||||
baseline = digest
|
||||
elif digest != baseline:
|
||||
raise RuntimeError(f"{name} diverged at {compiler} W{workers}; see determinism logs")
|
||||
cells += 1
|
||||
print(f"[L143Determinism] fixture={name} compiler_worker_cells={cells} identical=yes status=PASS",
|
||||
flush=True)
|
||||
|
||||
|
||||
def export_and_capture(name: str, fixture: Path, views: dict, *,
|
||||
headless: Path, renderer: Path, out: Path,
|
||||
artifact_dir: Path, env: dict[str, str]) -> None:
|
||||
view_names = ("eye", "wide", "cloud-up") if name == "road-in-clouds" else ("eye", "wide")
|
||||
for view_name in view_names:
|
||||
camera, target, clip_radius = views[view_name]
|
||||
clip_radius = min(clip_radius,3)
|
||||
stem = f"{name}-{view_name}"
|
||||
mesh = out / "capture-meshes" / f"{stem}.vfmesh"
|
||||
manifest = out / "capture-manifests" / f"{stem}.json"
|
||||
layout = out / "capture-layouts" / f"{stem}.json"
|
||||
png = out / "capture-png" / f"{stem}.png"
|
||||
image = artifact_dir / f"{stem}.jpg"
|
||||
for path in (mesh,manifest,layout,png,image):
|
||||
path.parent.mkdir(parents=True,exist_ok=True)
|
||||
command = headless_command(headless,fixture,camera,mesh,manifest,layout,12,
|
||||
clip_radius,max_level=-1,far_lods=True,
|
||||
max_clip_override=2 if name == "road-in-clouds" else None)
|
||||
output = run_step(f"capture-{stem}-export",command,
|
||||
out/"logs"/f"capture-{stem}-export.log",env=env,stamped=True)
|
||||
if not mesh.is_file() or mesh.stat().st_size == 0:
|
||||
raise RuntimeError(f"{stem} produced an empty mesh")
|
||||
yaw, pitch = camera_angles(camera,target)
|
||||
height_center = views["height_center"]
|
||||
height_range = views["height_range"]
|
||||
if name == "road-in-clouds":
|
||||
fog_start,fog_end,fog_color=(24,260,"0.88,0.93,0.95")
|
||||
elif name == "pillar-grid":
|
||||
fog_start,fog_end,fog_color=220,1250,"0.82,0.88,0.91"
|
||||
elif name == "periodicHills":
|
||||
fog_start,fog_end,fog_color=210,1000,"0.78,0.84,0.88"
|
||||
else:
|
||||
fog_start,fog_end,fog_color=30,105,FOG_COLOR
|
||||
renderer_command = [renderer,mesh,png,"--size=1600x900","--fov-deg=72",
|
||||
f"--camera-m={fmt(camera)}",f"--yaw-deg={yaw:.6f}",
|
||||
f"--pitch-deg={pitch:.6f}","--tile-skirts=on","--shade=readable",
|
||||
"--headlamp=off","--height-tint=on",f"--height-center-m={height_center:.6f}",
|
||||
f"--height-range-m={height_range:.6f}","--light-direction=-0.42,-0.58,0.70",
|
||||
"--fog=on",f"--fog-start-m={fog_start}",f"--fog-end-m={fog_end}",
|
||||
f"--fog-color={fog_color}"]
|
||||
run_step(f"capture-{stem}-render",renderer_command,
|
||||
out/"logs"/f"capture-{stem}-render.log",env=env,stamped=True)
|
||||
run_step(f"capture-{stem}-jpeg",["ffmpeg","-nostdin","-hide_banner","-loglevel",
|
||||
"error","-y","-i",png,"-frames:v","1","-q:v","4",image],
|
||||
out/"logs"/f"capture-{stem}-jpeg.log",env=env)
|
||||
quality = run_step(f"capture-{stem}-quality",
|
||||
[sys.executable,ROOT/"Standalone/Tools/verify/capture_quality.py",image],
|
||||
out/"logs"/f"capture-{stem}-quality.log",env=env)
|
||||
if "[CaptureQuality]" not in quality or not image.is_file() \
|
||||
or image.stat().st_size > 300_000:
|
||||
raise RuntimeError(f"{stem} capture failed quality or size checks")
|
||||
eye_height = "1.600m" if view_name in ("eye", "cloud-up") else "wide"
|
||||
print(f"[L143Capture] fixture={name} view={view_name} eye_height={eye_height} "
|
||||
f"camera_m=({fmt(camera)}) target_m=({fmt(target)}) bytes={image.stat().st_size} "
|
||||
f"sha256={sha256(image)} status=PASS",flush=True)
|
||||
|
||||
|
||||
def run_road_walk_audit(fixture: Path, view, *, headless: Path,
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
camera = view["eye"][0]
|
||||
run_dir = out / "road-walk-audit"
|
||||
run_dir.mkdir(parents=True,exist_ok=True)
|
||||
output = run_step("road-walk-audit",headless_command(headless,fixture,camera,
|
||||
run_dir/"audit.vfmesh",run_dir/"manifest.json",run_dir/"layout.json",12,1,
|
||||
audit_road=True),out/"logs"/"road-walk-audit.log",env=env,stamped=True)
|
||||
if not re.search(r"\[LiminalRoadWalkAudit\].*status=PASS",output):
|
||||
raise RuntimeError("raised road failed the Core capsule walk audit")
|
||||
|
||||
|
||||
def run_road_short_negative_control(fixture: Path, view, *, headless: Path,
|
||||
out: Path, env: dict[str, str]) -> None:
|
||||
camera = view["eye"][0]
|
||||
run_dir = out / "road-short-negative-control"
|
||||
run_dir.mkdir(parents=True,exist_ok=True)
|
||||
output = run_step("road-short-negative-control",
|
||||
headless_command(headless,fixture,camera,run_dir/"control.vfmesh",
|
||||
run_dir/"manifest.json",run_dir/"layout.json",12,1,audit_road=True),
|
||||
out/"logs"/"road-short-negative-control.log",env=env,stamped=True,
|
||||
expected_exit=14)
|
||||
match = re.search(r"\[LiminalRoadWalkAudit\].*path_length_m=([0-9.]+).*status=FAIL",output)
|
||||
if not match or float(match.group(1)) >= 300.0:
|
||||
raise RuntimeError("short-road negative control did not falsify the length gate")
|
||||
print(f"[L143RoadNegativeControl] path_length_m={match.group(1)} "
|
||||
"expected=FAIL status=PASS",flush=True)
|
||||
|
||||
|
||||
def retain_unchanged_captures(artifact_dir: Path) -> None:
|
||||
reference_dir = Path(__file__).resolve().parents[1] / "Linux142" / "captures"
|
||||
for name in ("flatField-monolith", "periodicHills"):
|
||||
for view in ("eye", "wide"):
|
||||
filename = f"{name}-{view}.jpg"
|
||||
source, destination = reference_dir / filename, artifact_dir / filename
|
||||
if not source.is_file():
|
||||
raise RuntimeError(f"missing L142 reference capture {source}")
|
||||
shutil.copy2(source,destination)
|
||||
if sha256(source) != sha256(destination):
|
||||
raise RuntimeError(f"unchanged reference capture copy differs: {filename}")
|
||||
print(f"[L143Capture] fixture={name} view={view} retained_from=Linux142 "
|
||||
f"sha256={sha256(destination)} status=PASS",flush=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT)
|
||||
parser.add_argument("--artifact-dir", type=Path, default=CAPTURE_DEFAULT)
|
||||
parser.add_argument("--headless-clang", type=Path, required=True)
|
||||
parser.add_argument("--headless-gcc", type=Path, required=True)
|
||||
parser.add_argument("--renderer", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
out = args.out.resolve()
|
||||
artifact_dir = args.artifact_dir.resolve()
|
||||
fixture_dir = out / "fixtures"
|
||||
for directory in (out,fixture_dir,artifact_dir):
|
||||
directory.mkdir(parents=True,exist_ok=True)
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(out)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT/"Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(out/"xdg-cache")
|
||||
run_step("build-fixtures",[sys.executable,
|
||||
ROOT/"Standalone/Research/WorldAssemblerM3/Linux143/BuildL143Fixtures.py",
|
||||
f"--out={fixture_dir}"],out/"logs"/"build-fixtures.log",env=env)
|
||||
|
||||
binaries = {"clang":args.headless_clang.resolve(),"gcc":args.headless_gcc.resolve()}
|
||||
fixtures = {
|
||||
"flatField-monolith":fixture_dir/"liminal-flatField-monolith.json",
|
||||
"periodicHills":fixture_dir/"liminal-periodicHills.json",
|
||||
"road-in-clouds":fixture_dir/"liminal-road-in-clouds.json",
|
||||
"pillar-grid":fixture_dir/"liminal-pillar-grid.json",
|
||||
}
|
||||
probed = {}
|
||||
for name,fixture in fixtures.items():
|
||||
probe_dir=out/"plan-probes"/name
|
||||
probe_dir.mkdir(parents=True,exist_ok=True)
|
||||
camera=(0.0,0.0,-500.0)
|
||||
output=run_step(f"plan-probe-{name}",headless_command(binaries["clang"],fixture,
|
||||
camera,probe_dir/"probe.vfmesh",probe_dir/"manifest.json",
|
||||
probe_dir/"layout.json",12,1),out/"logs"/f"plan-probe-{name}.log",
|
||||
env=env,stamped=True)
|
||||
if "[WorldAssemblerFullManifest]" not in output:
|
||||
raise RuntimeError(f"{name} probe omitted its full plan manifest")
|
||||
probed[name]=make_views(name,probe_dir/"manifest.json",probe_dir/"layout.json")
|
||||
|
||||
for name,fixture in fixtures.items():
|
||||
run_determinism(name,fixture,probed[name],binaries=binaries,out=out,env=env)
|
||||
run_determinism("pillar-grid-far-lod",fixtures["pillar-grid"],probed["pillar-grid"],
|
||||
binaries=binaries,out=out,env=env,max_level=-1,far_lods=True,max_clip_override=8)
|
||||
run_road_walk_audit(fixtures["road-in-clouds"],probed["road-in-clouds"],
|
||||
headless=binaries["clang"],out=out,env=env)
|
||||
run_road_short_negative_control(fixture_dir/"liminal-road-short-control.json",
|
||||
probed["road-in-clouds"],headless=binaries["clang"],out=out,env=env)
|
||||
retain_unchanged_captures(artifact_dir)
|
||||
for name in ("road-in-clouds", "pillar-grid"):
|
||||
fixture=fixtures[name]
|
||||
export_and_capture(name,fixture,probed[name],headless=binaries["clang"],
|
||||
renderer=args.renderer.resolve(),out=out,artifact_dir=artifact_dir,env=env)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L143Capture] status=FAIL error={error}",file=sys.stderr,flush=True)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,64 @@
|
||||
# L143 — liminal polish
|
||||
|
||||
## Captures
|
||||
|
||||
### Road
|
||||
|
||||
Eye-height:
|
||||
|
||||

|
||||
|
||||
Wide:
|
||||
|
||||

|
||||
|
||||
Looking up from the cloud floor:
|
||||
|
||||

|
||||
|
||||
### Pillar grid
|
||||
|
||||
Eye-height:
|
||||
|
||||

|
||||
|
||||
Wide:
|
||||
|
||||

|
||||
|
||||
### Kept from L142
|
||||
|
||||
These four captures are byte-identical to L142.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Result
|
||||
|
||||
The road is one continuous swept deck, and the distant pillar silhouettes remain complete and consistent. The monolith and periodic hills were retained unchanged.
|
||||
|
||||
## Changes and causes
|
||||
|
||||
- The road edge broke where independently capped deck segments overlapped. The road now resolves to one swept-deck stamp with a shared cubic-Hermite centerline and continuous cross-section; the centerline is sampled at 1 m spacing (361 points). The 8 m deck is 376.829 m long and retains 17 support posts. The sweep path is serialized in stamp-vocabulary V5.
|
||||
- Pillars disappeared or narrowed when the coarse marching-cubes lattice skipped their cross-section. The pillar stamp's interval proof is unsupported, so it conservatively kept tiles but did not protect the mesh from undersampling. At LOD4 the sample spacing is 32 voxels (8 m), already greater than the 5.5 m pillar radius; spacing rises to 64 and 128 voxels at LOD5 and LOD6. The shared meshing path now emits deterministic 24-sided capped-cylinder proxies for regular `fillPillar` stamps once the sample step exceeds their radius or half-height. The same rule applies outside the liminal fixture. The radial approximation error for this fixture is about 4.7 cm, below one 25 cm voxel.
|
||||
|
||||
## Measurements
|
||||
|
||||
- Road walk audit covered the full 376.829 m route at 1,081 surface stations, with 68,103 capsule samples and 7,096 support samples: 0 blocked, 0 unsupported, 0 grade failures, and 0 surface misses. Measured maximum grade was 8.512° against a 15° limit; deck width was 8 m against a 3 m minimum. `road-short-negative-control` failed the walk audit as expected at 210.351 m.
|
||||
- Determinism covered five fixtures—monolith, periodic hills, road, pillar grid, and far-LOD pillar grid—across Clang/GCC and W1/W8/W12 (six compiler/worker cells per fixture). All five reported identical outputs.
|
||||
- Clang and GCC builds passed on source stamp `1baa3a711f7f96df2e70fc93579f41ad0b0211eb42fcb51dabf522e33d888877`. The capture runner and capture-quality checks passed for all requested views.
|
||||
- Fast tier passed in 292.3 s. Its pinned L130-v227 reach-unit owner hashes match exactly: 12/12 rows for each owner fixture, with W1 and W12 identical. Historical L46/L53 hash comparisons remain diagnostic-only and are not the current owner-hash gate.
|
||||
|
||||
## Checks and limits
|
||||
|
||||
- Passed: road audit and short-road negative control; five-fixture Clang/GCC determinism; Clang and GCC builds; capture quality; fast tier; `git diff --check`.
|
||||
- Not run: Unreal build (no Unreal `Source/` files changed) and L80 performance timing (this round made no performance claim).
|
||||
- The coarse proxy is limited to regular `fillPillar` stamps; irregular pillars and other stamp kinds continue through their existing SDF path. The proxy was exercised at LOD4–6 in the pillar-grid captures.
|
||||
- Unreal `Source/` files changed: none. Changed standalone source files: `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, `Standalone/Core/src/ResolvedLayoutInternal.h`, `Standalone/Core/src/ShapeWorldInternal.h`, `Standalone/Core/src/VoxelForgeCore.cpp`, `Standalone/Source/StreamBenchmarkHeadless.cpp`, `Standalone/Source/StreamBenchmarkPipeline.h`, and `Standalone/Source/WorldAssemblyPrototype.h`.
|
||||
|
||||
Detailed logs are in `Saved/Linux/l143/`; the capture and audit transcript is `Saved/Linux/l143/logs/capture-runner.log`, the walk audit is `Saved/Linux/l143/logs/road-walk-audit.log`, and the fast-tier summary is `Saved/Linux/l143/fast-summary.json`.
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the 3-strata composed Core.Liminal.Field fixture."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA",
|
||||
ROOT / "Standalone/data/owner_world.json"))
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l144"))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT / "fixtures")
|
||||
args = parser.parse_args()
|
||||
args.out.mkdir(parents=True, exist_ok=True)
|
||||
world = json.loads(OWNER.read_text(encoding="utf-8"))
|
||||
if len(world.get("strates", [])) < 3:
|
||||
raise SystemExit("owner fixture needs at least three authored strate slots")
|
||||
|
||||
world["strates"] = world["strates"][:3]
|
||||
world["total_strates"] = 3
|
||||
world["settings_asset"]["TotalStrates"] = 3
|
||||
world["settings_asset"]["FixedStrates"] = world["settings_asset"]["FixedStrates"][:3]
|
||||
# Keep the resolved arrival near the departure depth. The owner's 5000-unit
|
||||
# reach clamps to liminal bedrock on most seeds and leaves no field floor.
|
||||
world["strates"][0]["passage_config"]["ReachMin"] = 1536
|
||||
world["strates"][0]["passage_config"]["ReachMax"] = 1792
|
||||
world["surface_profile_override"] = {
|
||||
"version": 1,
|
||||
"kind": "flatField",
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
middle = world["strates"][1]
|
||||
middle["asset"]["GeneratorType"] = 4 # ECaveGeneratorType::SurfaceWorld
|
||||
middle["asset"]["StrateName"] = "Liminal Field"
|
||||
# Keep the departure mouth 24–32 m above liminal bedrock so every variant
|
||||
# has room for its floor, road landing and support footings.
|
||||
middle["passage_config"]["ReachMin"] = 192
|
||||
middle["passage_config"]["ReachMax"] = 256
|
||||
world["core_liminal_field"] = {
|
||||
"version": 1,
|
||||
"strate_index": int(middle["index"]),
|
||||
"variant_policy": "seed_modulo_4",
|
||||
}
|
||||
|
||||
output = args.out / "core-liminal-field-3-strata.json"
|
||||
output.write_text(json.dumps(world, separators=(",", ":")) + "\n", encoding="utf-8")
|
||||
print(f"[L144Fixture] path={output} strates=SurfaceWorld,Core.Liminal.Field,TunnelNetwork status=PASS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Capture the four seed-selected Core.Liminal.Field v1 variants."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
HERE = Path(__file__).resolve().parent
|
||||
OUT = ROOT / "Saved/Linux/l144"
|
||||
CAPTURES = HERE / "captures"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
Q_PER_METRE = 1024.0
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import bounded_run, current_stamp, first_stamp
|
||||
|
||||
|
||||
def fmt(values) -> str:
|
||||
return ",".join(f"{value:.6f}" for value in values)
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def run_step(name: str, command: list[object], log: Path, env: dict[str, str],
|
||||
stamped: bool = False) -> str:
|
||||
expected_stamp = current_stamp() if stamped else None
|
||||
if stamped:
|
||||
binary = Path(str(command[0]))
|
||||
probe = bounded_run([str(binary), "--print-source-stamp"], timeout=15)
|
||||
if probe is None or probe.returncode != 0 \
|
||||
or first_stamp(probe.stdout or "") != expected_stamp:
|
||||
raise RuntimeError(f"{name} refused a stale executable: {binary}")
|
||||
started = time.monotonic()
|
||||
log.parent.mkdir(parents=True, exist_ok=True)
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, "timeout", "1740s", *map(str, command)],
|
||||
cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT,
|
||||
timeout=1745, check=False)
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
elapsed = time.monotonic() - started
|
||||
print(f"[L144Run] step={name} elapsed_s={elapsed:.3f} exit={result.returncode} log={log}",
|
||||
flush=True)
|
||||
if stamped and (first_stamp(output) != expected_stamp
|
||||
or current_stamp() != expected_stamp):
|
||||
raise RuntimeError(f"{name} source stamp mismatch; see {log}")
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"{name} exit={result.returncode}; see {log}")
|
||||
return output
|
||||
|
||||
|
||||
def camera_angles(camera, target):
|
||||
dx, dy, dz = (target[i] - camera[i] for i in range(3))
|
||||
return math.degrees(math.atan2(dx, dy)), math.degrees(
|
||||
math.atan2(dz, math.hypot(dx, dy)))
|
||||
|
||||
|
||||
def route_views(manifest_path: Path, layout_path: Path, name: str):
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
plan = next(row for row in manifest["plan"]["strates"]
|
||||
if row["strate_index"] == 1 and row.get("liminal_field", {}).get("version") == 1)
|
||||
points = [tuple(value / Q_PER_METRE for value in row["position_q"])
|
||||
for row in plan["route"]]
|
||||
first, second = points[0], points[1]
|
||||
dx, dy = second[0] - first[0], second[1] - first[1]
|
||||
length = math.hypot(dx, dy)
|
||||
if length <= 1.0e-6:
|
||||
raise RuntimeError("Core.Liminal.Field arrival tangent is degenerate")
|
||||
tx, ty = dx / length, dy / length
|
||||
eye_camera = (first[0] - tx * 1.5, first[1] - ty * 1.5, first[2] + 1.6)
|
||||
third = points[min(2, len(points) - 1)]
|
||||
dx, dy = third[0] - first[0], third[1] - first[1]
|
||||
tangent_length = math.hypot(dx, dy)
|
||||
tx, ty = dx / tangent_length, dy / tangent_length
|
||||
dz_per_metre = (third[2] - first[2]) / tangent_length
|
||||
eye_target = (first[0] + tx * 40.0, first[1] + ty * 40.0,
|
||||
first[2] + dz_per_metre * 40.0 + 1.6)
|
||||
|
||||
middle = len(points) // 2
|
||||
before, center, after = points[middle - 1], points[middle], points[middle + 1]
|
||||
dx, dy = after[0] - before[0], after[1] - before[1]
|
||||
length = math.hypot(dx, dy)
|
||||
if length <= 1.0e-6:
|
||||
raise RuntimeError("Core.Liminal.Field wide-view tangent is degenerate")
|
||||
tx, ty = dx / length, dy / length
|
||||
nx, ny = -ty, tx
|
||||
floor = plan["liminal_field"]["floor_height_q"] / Q_PER_METRE
|
||||
if name == "flatField-monolith":
|
||||
monolith = next(row for row in layout.get("stamps", [])
|
||||
if row.get("stable_id") == "core/liminal-field/monolith/000")
|
||||
monolith_center = tuple(value / 1.0e6 for value in monolith["position_um"])
|
||||
floor = monolith_center[2] - monolith["half_extents_um"][2] / 1.0e6
|
||||
wide_camera = (monolith_center[0] - tx * 30.0 + nx * 18.0,
|
||||
monolith_center[1] - ty * 30.0 + ny * 18.0, floor + 25.0)
|
||||
wide_target = monolith_center
|
||||
elif name == "periodicHills":
|
||||
wide_camera = (center[0] - 20.0, center[1] - 25.0, floor + 10.0)
|
||||
wide_target = (center[0] + 10.0, center[1] + 8.0, floor + 1.0)
|
||||
elif name == "pillar-grid":
|
||||
pillars = [row for row in layout.get("stamps", [])
|
||||
if row.get("stable_id", "").startswith("core/liminal-field/pillars/")]
|
||||
if not pillars:
|
||||
raise RuntimeError("pillar-grid layout has no resolved grid stamps")
|
||||
pairs = []
|
||||
for i, first_pillar in enumerate(pillars):
|
||||
for second_pillar in pillars[i + 1:]:
|
||||
a = first_pillar["position_um"]
|
||||
b = second_pillar["position_um"]
|
||||
dx, dy = (b[0] - a[0]) / 1.0e6, (b[1] - a[1]) / 1.0e6
|
||||
separation = math.hypot(dx, dy)
|
||||
if 60.0 <= separation <= 90.0:
|
||||
mx = (a[0] + b[0]) / 2.0e6
|
||||
my = (a[1] + b[1]) / 2.0e6
|
||||
pairs.append((math.hypot(mx - center[0], my - center[1]),
|
||||
mx, my, dx / separation, dy / separation,
|
||||
(a[2] + b[2]) / 2.0e6,
|
||||
first_pillar["half_extents_um"][2] / 1.0e6))
|
||||
if not pairs:
|
||||
raise RuntimeError("pillar-grid has no neighboring resolved columns")
|
||||
_, mx, my, tx, ty, pillar_z, half_height = min(pairs)
|
||||
floor = pillar_z - half_height
|
||||
nx, ny = -ty, tx
|
||||
wide_camera = (center[0] - tx * 20.0 + nx * 25.0,
|
||||
center[1] - ty * 20.0 + ny * 25.0, center[2] + 8.0)
|
||||
wide_target = (center[0], center[1], floor + 2.0)
|
||||
else:
|
||||
wide_camera = (center[0] - tx * 20.0 + nx * 25.0,
|
||||
center[1] - ty * 20.0 + ny * 25.0, center[2] + 8.0)
|
||||
wide_target = (center[0], center[1], floor + 2.0)
|
||||
return {"eye": (eye_camera, eye_target), "wide": (wide_camera, wide_target)}
|
||||
|
||||
|
||||
def capture_variant(seed: int, name: str, *, headless: Path, renderer: Path,
|
||||
fixture: Path, env: dict[str, str]):
|
||||
stem = f"core-liminal-{name}-seed{seed:02d}"
|
||||
plan_dir = OUT / "capture-plans" / stem
|
||||
plan_dir.mkdir(parents=True, exist_ok=True)
|
||||
manifest = plan_dir / "manifest.json"
|
||||
layout = plan_dir / "layout.json"
|
||||
command = [headless, fixture, "--workers=1", f"--seed={seed}",
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", "--clip-radius=1", "--max-clip-level=0", "--max-level=0",
|
||||
"--render-distance-chunks=0", "--camera=0,0,-540,0,0",
|
||||
f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
output = run_step(f"plan-{stem}", command, OUT / "logs" / f"capture-{stem}-plan.log",
|
||||
env, stamped=True)
|
||||
if "[CoreLiminalFieldDraw]" not in output:
|
||||
raise RuntimeError(f"{stem} plan omitted its Core liminal deck")
|
||||
views = route_views(manifest, layout, name)
|
||||
for view, (eye, target) in views.items():
|
||||
work = OUT / "captures" / f"{stem}-{view}"
|
||||
work.mkdir(parents=True, exist_ok=True)
|
||||
view_manifest = work / "manifest.json"
|
||||
view_layout = work / "layout.json"
|
||||
mesh = work / "world.vfmesh"
|
||||
yaw, pitch = camera_angles(eye, target)
|
||||
camera = (*eye, yaw, pitch)
|
||||
view_clip_radius = (5 if view == "wide" and name in {
|
||||
"flatField-monolith", "periodicHills"} else
|
||||
3)
|
||||
command = [headless, fixture, "--workers=12", f"--seed={seed}",
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", f"--clip-radius={view_clip_radius}",
|
||||
"--max-clip-level=0", "--max-level=0",
|
||||
"--render-distance-chunks=0", "--capture-skip-walkability",
|
||||
f"--camera={fmt(camera)}", f"--mesh-export={mesh}",
|
||||
f"--world-assembler-manifest-output={view_manifest}",
|
||||
f"--resolved-layout-output={view_layout}"]
|
||||
output = run_step(f"export-{stem}-{view}", command,
|
||||
OUT / "logs" / f"capture-{stem}-{view}-export.log", env, stamped=True)
|
||||
if "[CoreLiminalFieldDraw]" not in output or not mesh.is_file() \
|
||||
or mesh.stat().st_size == 0:
|
||||
raise RuntimeError(f"{stem}-{view} export omitted its Core liminal deck or mesh")
|
||||
png = work / f"{view}.png"
|
||||
image = CAPTURES / f"{stem}-{view}.jpg"
|
||||
fog = {
|
||||
"flatField-monolith": (30, 180, "0.66,0.73,0.77", -708.0, 46.0),
|
||||
"periodicHills": (140, 850, "0.78,0.84,0.88", -720.0, 14.0),
|
||||
"road-over-cloud-floor": (24, 420, "0.88,0.93,0.95", -720.0, 65.0),
|
||||
"pillar-grid": (180, 1200, "0.82,0.88,0.91", -720.0, 80.0),
|
||||
}[name]
|
||||
fog_start, fog_end, fog_color, height_center, height_range = fog
|
||||
render = [renderer, mesh, png, "--size=1600x900", "--fov-deg=72",
|
||||
f"--camera-m={fmt(eye)}", f"--yaw-deg={yaw:.6f}", f"--pitch-deg={pitch:.6f}",
|
||||
"--tile-skirts=on", "--shade=readable", "--headlamp=off", "--height-tint=on",
|
||||
f"--height-center-m={height_center:.6f}", f"--height-range-m={height_range:.6f}",
|
||||
"--light-direction=-0.42,-0.58,0.70", "--fog=on", f"--fog-start-m={fog_start}",
|
||||
f"--fog-end-m={fog_end}", f"--fog-color={fog_color}"]
|
||||
run_step(f"render-{stem}-{view}", render,
|
||||
OUT / "logs" / f"capture-{stem}-{view}-render.log", env, stamped=True)
|
||||
run_step(f"jpeg-{stem}-{view}", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel",
|
||||
"error", "-y", "-i", png, "-frames:v", "1", "-q:v", "4", image],
|
||||
OUT / "logs" / f"capture-{stem}-{view}-jpeg.log", env)
|
||||
run_step(f"quality-{stem}-{view}", [sys.executable,
|
||||
ROOT / "Standalone/Tools/verify/capture_quality.py", image],
|
||||
OUT / "logs" / f"capture-{stem}-{view}-quality.log", env)
|
||||
print(f"[L144Capture] variant={name} seed={seed} view={view} "
|
||||
f"eye_height={'1.600m' if view == 'eye' else 'wide'} bytes={image.stat().st_size} "
|
||||
f"sha256={sha256(image)} status=PASS", flush=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
headless = ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-clang19"
|
||||
renderer = ROOT / "Standalone/bin/linux/VoxelForgeOffscreenCapture-clang19"
|
||||
fixture = OUT / "fixtures/core-liminal-field-3-strata.json"
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(OUT)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT / "Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(OUT / "xdg-cache")
|
||||
CAPTURES.mkdir(parents=True, exist_ok=True)
|
||||
variants = ("flatField-monolith", "periodicHills",
|
||||
"road-over-cloud-floor", "pillar-grid")
|
||||
selected = set(os.environ.get("L144_CAPTURE_VARIANTS", "").split(","))
|
||||
for seed, name in enumerate(variants):
|
||||
if selected and name not in selected:
|
||||
continue
|
||||
capture_variant(seed, name, headless=headless, renderer=renderer,
|
||||
fixture=fixture, env=env)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L144Capture] status=FAIL error={error}", file=sys.stderr, flush=True)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,44 @@
|
||||
# Linux144 — Core.Liminal.Field v1
|
||||
|
||||
| Variant (seed) | Arrival at eye height | Wide view |
|
||||
|---|---|---|
|
||||
| Flat field + monolith (0) |  |  |
|
||||
| Repeating hills (1) |  |  |
|
||||
| Road over cloud floor (2) |  |  |
|
||||
| Pillar grid (3) |  |  |
|
||||
|
||||
**Result: stopped at the mouth-join gate; this is not ready to ship.** The new `Core.Liminal.Field` v1 recipe plans and draws all four seed-selected looks between fixed mouths. In the final composed probe, three of four seeds failed one of their two passage interfaces, and all four failed the liminal walk audit. The requested eight-seed-per-variant matrix was not run after the stop condition was reached.
|
||||
|
||||
## What changed
|
||||
|
||||
- Added one data-driven recipe, `Core.Liminal.Field` v1. `seed % 4` selects flat field with monolith, repeating hills, road over cloud floor, or pillar grid.
|
||||
- The liminal plan binds the existing `passage/0-1/0` arrival and `passage/1-2/0` departure as fixed endpoints. It draws an 8-point route deck and structural supports; the road variant uses that deck as its route. The pillar variant resolved 221 grid pillars after route clearance.
|
||||
- Added a three-strata fixture: Surface World → liminal → Tunnel Network. `BuildL144Fixtures.py` and `CaptureL144.py` reproduce the fixture and the eight captures.
|
||||
|
||||
## Composed probe
|
||||
|
||||
The final composed audit window was one run for each seed 0–3 at W1, using Clang 19 source stamp `8acbb7c3dfdb0484100d3d55036db20743ce76d74097b69362bb7d1a1c1d6302`. These are audit counts, not timing comparisons.
|
||||
|
||||
| Variant | Passage interfaces passed | Liminal walk audit | Passage shell / seam audit | Liminal negative control |
|
||||
|---|---:|---|---|---|
|
||||
| Flat field + monolith, seed 0 | 1/2 — FAIL | 222 blocked samples, 7 grade failures — FAIL | PASS | altered departure rejected — PASS |
|
||||
| Repeating hills, seed 1 | 2/2; composed summary FAIL | 1 blocked sample — FAIL | PASS | altered departure rejected — PASS |
|
||||
| Road over cloud floor, seed 2 | 1/2 — FAIL | 3 blocked samples — FAIL | FAIL, 1 floor violation | altered departure rejected — PASS |
|
||||
| Pillar grid, seed 3 | 1/2 — FAIL | 289 blocked samples, 9 grade failures — FAIL | PASS | altered departure rejected — PASS |
|
||||
|
||||
The three partial passage-interface failures reached the requested stop threshold. Every liminal walk probe reported zero unsupported samples and zero structural-support failures; support alone therefore does not explain the blocked routes. The top Surface World route audit passed all four seeds. Passage naturalness and mouth-profile negative controls also detected their injected faults in all four logs.
|
||||
|
||||
## Captures and limits
|
||||
|
||||
All eight 1600×900 images passed `capture_quality.py`. Arrival cameras are 1.6 m above the fixed arrival mouth and look along the route. Capture exports used `--capture-skip-walkability` to preserve render evidence despite the failing composed audits; this flag was not used for the audit runs. The wide pillar view shows the overhead deck and one support rather than a legible field of grid columns, and the other images also expose the current route/deck defects.
|
||||
|
||||
No additional geometry change was attempted after the three-interface-failure threshold. Earlier diagnostics found the short terminal secant exaggerated the mouth grade; widening the tangent probe interval did not make the final composed walk pass. It remains unproven which combination of terminal connector geometry and nearby field solids accounts for the blocked capsule samples.
|
||||
|
||||
## Checks
|
||||
|
||||
- Clang 19 headless build completed; the final audit and capture executables report the source stamp above.
|
||||
- Four composed probes ran at W1, one seed per variant. Planning/drawing and the per-audit results are in `Saved/Linux/l144/logs/probe8-seed00.log` through `probe8-seed03.log`.
|
||||
- Eight capture quality checks passed. `git diff --check` passed.
|
||||
- Not run after the stop gate: eight seeds per variant, GCC or W8/W12 determinism, owner canonical-hash comparison, fast tier, and one near-ready run. No performance timing window was collected.
|
||||
|
||||
Changed Unreal `Source/` files: none. Changed standalone sources include `StreamBenchmarkHeadless.cpp`, `StreamBenchmarkPipeline.h`, and `WorldAssemblyPrototype.h`.
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the 3-strata composed Core.Liminal.Field v2 fixture."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA",
|
||||
ROOT / "Standalone/data/owner_world.json"))
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l145"))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT / "fixtures")
|
||||
args = parser.parse_args()
|
||||
args.out.mkdir(parents=True, exist_ok=True)
|
||||
world = json.loads(OWNER.read_text(encoding="utf-8"))
|
||||
if len(world.get("strates", [])) < 3:
|
||||
raise SystemExit("owner fixture needs at least three authored strate slots")
|
||||
|
||||
world["strates"] = world["strates"][:3]
|
||||
world["total_strates"] = 3
|
||||
world["settings_asset"]["TotalStrates"] = 3
|
||||
world["settings_asset"]["FixedStrates"] = world["settings_asset"]["FixedStrates"][:3]
|
||||
# Keep the resolved arrival near the departure depth. The owner's 5000-unit
|
||||
# reach clamps to liminal bedrock on most seeds and leaves no field floor.
|
||||
world["strates"][0]["passage_config"]["ReachMin"] = 1536
|
||||
world["strates"][0]["passage_config"]["ReachMax"] = 1792
|
||||
world["surface_profile_override"] = {
|
||||
"version": 1,
|
||||
"kind": "flatField",
|
||||
"minimum_arena_clearance_m": 0.0,
|
||||
}
|
||||
middle = world["strates"][1]
|
||||
middle["asset"]["GeneratorType"] = 4 # ECaveGeneratorType::SurfaceWorld
|
||||
middle["asset"]["StrateName"] = "Liminal Field"
|
||||
# Keep the departure mouth 24–32 m above liminal bedrock so every variant
|
||||
# has room for its floor, road landing and support footings.
|
||||
middle["passage_config"]["ReachMin"] = 192
|
||||
middle["passage_config"]["ReachMax"] = 256
|
||||
world["core_liminal_field"] = {
|
||||
"version": 2,
|
||||
"strate_index": int(middle["index"]),
|
||||
"variant_policy": "seed_modulo_4",
|
||||
}
|
||||
|
||||
output = args.out / "core-liminal-field-3-strata.json"
|
||||
output.write_text(json.dumps(world, separators=(",", ":")) + "\n", encoding="utf-8")
|
||||
print(f"[L145Fixture] path={output} strates=SurfaceWorld,Core.Liminal.Field,TunnelNetwork status=PASS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Capture one arrival-mouth eye view per Core.Liminal.Field v2 variant."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
HERE = Path(__file__).resolve().parent
|
||||
OUT = ROOT / "Saved/Linux/l145"
|
||||
CAPTURES = HERE / "captures"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
Q_PER_METRE = 1024.0
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import bounded_run, current_stamp, first_stamp
|
||||
|
||||
|
||||
def fmt(values) -> str:
|
||||
return ",".join(f"{value:.6f}" for value in values)
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def run_step(name: str, command: list[object], log: Path, env: dict[str, str],
|
||||
stamped: bool = False) -> str:
|
||||
expected_stamp = current_stamp() if stamped else None
|
||||
if stamped:
|
||||
binary = Path(str(command[0]))
|
||||
probe = bounded_run([str(binary), "--print-source-stamp"], timeout=15)
|
||||
if probe is None or probe.returncode != 0 \
|
||||
or first_stamp(probe.stdout or "") != expected_stamp:
|
||||
raise RuntimeError(f"{name} refused a stale executable: {binary}")
|
||||
started = time.monotonic()
|
||||
log.parent.mkdir(parents=True, exist_ok=True)
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, "timeout", "1740s", *map(str, command)],
|
||||
cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT,
|
||||
timeout=1745, check=False)
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
elapsed = time.monotonic() - started
|
||||
print(f"[L145Run] step={name} elapsed_s={elapsed:.3f} exit={result.returncode} log={log}",
|
||||
flush=True)
|
||||
if stamped and (first_stamp(output) != expected_stamp
|
||||
or current_stamp() != expected_stamp):
|
||||
raise RuntimeError(f"{name} source stamp mismatch; see {log}")
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"{name} exit={result.returncode}; see {log}")
|
||||
return output
|
||||
|
||||
|
||||
def camera_angles(camera, target):
|
||||
dx, dy, dz = (target[i] - camera[i] for i in range(3))
|
||||
return math.degrees(math.atan2(dx, dy)), math.degrees(
|
||||
math.atan2(dz, math.hypot(dx, dy)))
|
||||
|
||||
|
||||
def route_views(manifest_path: Path, layout_path: Path, name: str):
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
plan = next(row for row in manifest["plan"]["strates"]
|
||||
if row["strate_index"] == 1 and row.get("liminal_field", {}).get("version") == 2)
|
||||
points = [tuple(value / Q_PER_METRE for value in row["position_q"])
|
||||
for row in plan["route"]]
|
||||
first, second = points[0], points[1]
|
||||
dx, dy = second[0] - first[0], second[1] - first[1]
|
||||
length = math.hypot(dx, dy)
|
||||
if length <= 1.0e-6:
|
||||
raise RuntimeError("Core.Liminal.Field arrival tangent is degenerate")
|
||||
tx, ty = dx / length, dy / length
|
||||
eye_camera = (first[0] - tx * 1.5, first[1] - ty * 1.5, first[2] + 1.6)
|
||||
third = points[min(2, len(points) - 1)]
|
||||
dx, dy = third[0] - first[0], third[1] - first[1]
|
||||
tangent_length = math.hypot(dx, dy)
|
||||
tx, ty = dx / tangent_length, dy / tangent_length
|
||||
dz_per_metre = (third[2] - first[2]) / tangent_length
|
||||
eye_target = (first[0] + tx * 40.0, first[1] + ty * 40.0,
|
||||
first[2] + dz_per_metre * 40.0 + 1.6)
|
||||
|
||||
middle = len(points) // 2
|
||||
before, center, after = points[middle - 1], points[middle], points[middle + 1]
|
||||
dx, dy = after[0] - before[0], after[1] - before[1]
|
||||
length = math.hypot(dx, dy)
|
||||
if length <= 1.0e-6:
|
||||
raise RuntimeError("Core.Liminal.Field wide-view tangent is degenerate")
|
||||
tx, ty = dx / length, dy / length
|
||||
nx, ny = -ty, tx
|
||||
floor = plan["liminal_field"]["floor_height_q"] / Q_PER_METRE
|
||||
if name == "flatField-monolith":
|
||||
monolith = next(row for row in layout.get("stamps", [])
|
||||
if row.get("stable_id") == "core/liminal-field/monolith/000")
|
||||
monolith_center = tuple(value / 1.0e6 for value in monolith["position_um"])
|
||||
floor = monolith_center[2] - monolith["half_extents_um"][2] / 1.0e6
|
||||
wide_camera = (monolith_center[0] - tx * 30.0 + nx * 18.0,
|
||||
monolith_center[1] - ty * 30.0 + ny * 18.0, floor + 25.0)
|
||||
wide_target = monolith_center
|
||||
elif name == "periodicHills":
|
||||
wide_camera = (center[0] - 20.0, center[1] - 25.0, floor + 10.0)
|
||||
wide_target = (center[0] + 10.0, center[1] + 8.0, floor + 1.0)
|
||||
elif name == "pillar-grid":
|
||||
pillars = [row for row in layout.get("stamps", [])
|
||||
if row.get("stable_id", "").startswith("core/liminal-field/pillars/")]
|
||||
if not pillars:
|
||||
raise RuntimeError("pillar-grid layout has no resolved grid stamps")
|
||||
pairs = []
|
||||
for i, first_pillar in enumerate(pillars):
|
||||
for second_pillar in pillars[i + 1:]:
|
||||
a = first_pillar["position_um"]
|
||||
b = second_pillar["position_um"]
|
||||
dx, dy = (b[0] - a[0]) / 1.0e6, (b[1] - a[1]) / 1.0e6
|
||||
separation = math.hypot(dx, dy)
|
||||
if 60.0 <= separation <= 90.0:
|
||||
mx = (a[0] + b[0]) / 2.0e6
|
||||
my = (a[1] + b[1]) / 2.0e6
|
||||
pairs.append((math.hypot(mx - center[0], my - center[1]),
|
||||
mx, my, dx / separation, dy / separation,
|
||||
(a[2] + b[2]) / 2.0e6,
|
||||
first_pillar["half_extents_um"][2] / 1.0e6))
|
||||
if not pairs:
|
||||
raise RuntimeError("pillar-grid has no neighboring resolved columns")
|
||||
_, mx, my, tx, ty, pillar_z, half_height = min(pairs)
|
||||
floor = pillar_z - half_height
|
||||
nx, ny = -ty, tx
|
||||
wide_camera = (center[0] - tx * 20.0 + nx * 25.0,
|
||||
center[1] - ty * 20.0 + ny * 25.0, center[2] + 8.0)
|
||||
wide_target = (center[0], center[1], floor + 2.0)
|
||||
else:
|
||||
wide_camera = (center[0] - tx * 20.0 + nx * 25.0,
|
||||
center[1] - ty * 20.0 + ny * 25.0, center[2] + 8.0)
|
||||
wide_target = (center[0], center[1], floor + 2.0)
|
||||
return {"eye": (eye_camera, eye_target), "wide": (wide_camera, wide_target)}
|
||||
|
||||
|
||||
def capture_variant(seed: int, name: str, *, headless: Path, renderer: Path,
|
||||
fixture: Path, env: dict[str, str]):
|
||||
stem = f"core-liminal-{name}-seed{seed:02d}"
|
||||
plan_dir = OUT / "capture-plans" / stem
|
||||
plan_dir.mkdir(parents=True, exist_ok=True)
|
||||
manifest = plan_dir / "manifest.json"
|
||||
layout = plan_dir / "layout.json"
|
||||
command = [headless, fixture, "--workers=1", f"--seed={seed}",
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", "--clip-radius=1", "--max-clip-level=0", "--max-level=0",
|
||||
"--render-distance-chunks=0", "--camera=0,0,-540,0,0",
|
||||
f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
output = run_step(f"plan-{stem}", command, OUT / "logs" / f"capture-{stem}-plan.log",
|
||||
env, stamped=True)
|
||||
if "[CoreLiminalFieldDraw]" not in output:
|
||||
raise RuntimeError(f"{stem} plan omitted its Core liminal deck")
|
||||
views = route_views(manifest, layout, name)
|
||||
for view, (eye, target) in {"eye": views["eye"]}.items():
|
||||
work = OUT / "captures" / f"{stem}-{view}"
|
||||
work.mkdir(parents=True, exist_ok=True)
|
||||
view_manifest = work / "manifest.json"
|
||||
view_layout = work / "layout.json"
|
||||
mesh = work / "world.vfmesh"
|
||||
yaw, pitch = camera_angles(eye, target)
|
||||
camera = (*eye, yaw, pitch)
|
||||
view_clip_radius = (5 if view == "wide" and name in {
|
||||
"flatField-monolith", "periodicHills"} else
|
||||
3)
|
||||
command = [headless, fixture, "--workers=12", f"--seed={seed}",
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", f"--clip-radius={view_clip_radius}",
|
||||
"--max-clip-level=0", "--max-level=0",
|
||||
"--render-distance-chunks=0", "--capture-skip-walkability",
|
||||
f"--camera={fmt(camera)}", f"--mesh-export={mesh}",
|
||||
f"--world-assembler-manifest-output={view_manifest}",
|
||||
f"--resolved-layout-output={view_layout}"]
|
||||
output = run_step(f"export-{stem}-{view}", command,
|
||||
OUT / "logs" / f"capture-{stem}-{view}-export.log", env, stamped=True)
|
||||
if "[CoreLiminalFieldDraw]" not in output or not mesh.is_file() \
|
||||
or mesh.stat().st_size == 0:
|
||||
raise RuntimeError(f"{stem}-{view} export omitted its Core liminal deck or mesh")
|
||||
png = work / f"{view}.png"
|
||||
image = CAPTURES / f"{stem}-{view}.jpg"
|
||||
fog = {
|
||||
"flatField-monolith": (30, 180, "0.66,0.73,0.77", -708.0, 46.0),
|
||||
"periodicHills": (140, 850, "0.78,0.84,0.88", -720.0, 14.0),
|
||||
"road-over-cloud-floor": (24, 420, "0.88,0.93,0.95", -720.0, 65.0),
|
||||
"pillar-grid": (180, 1200, "0.82,0.88,0.91", -720.0, 80.0),
|
||||
}[name]
|
||||
fog_start, fog_end, fog_color, height_center, height_range = fog
|
||||
render = [renderer, mesh, png, "--size=1600x900", "--fov-deg=72",
|
||||
f"--camera-m={fmt(eye)}", f"--yaw-deg={yaw:.6f}", f"--pitch-deg={pitch:.6f}",
|
||||
"--tile-skirts=on", "--shade=readable", "--headlamp=off", "--height-tint=on",
|
||||
f"--height-center-m={height_center:.6f}", f"--height-range-m={height_range:.6f}",
|
||||
"--light-direction=-0.42,-0.58,0.70", "--fog=on", f"--fog-start-m={fog_start}",
|
||||
f"--fog-end-m={fog_end}", f"--fog-color={fog_color}"]
|
||||
run_step(f"render-{stem}-{view}", render,
|
||||
OUT / "logs" / f"capture-{stem}-{view}-render.log", env, stamped=True)
|
||||
run_step(f"jpeg-{stem}-{view}", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel",
|
||||
"error", "-y", "-i", png, "-frames:v", "1", "-q:v", "4", image],
|
||||
OUT / "logs" / f"capture-{stem}-{view}-jpeg.log", env)
|
||||
run_step(f"quality-{stem}-{view}", [sys.executable,
|
||||
ROOT / "Standalone/Tools/verify/capture_quality.py", image],
|
||||
OUT / "logs" / f"capture-{stem}-{view}-quality.log", env)
|
||||
print(f"[L145Capture] variant={name} seed={seed} view={view} "
|
||||
f"eye_height={'1.600m' if view == 'eye' else 'wide'} bytes={image.stat().st_size} "
|
||||
f"sha256={sha256(image)} status=PASS", flush=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
headless = ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-l145-clang"
|
||||
renderer = ROOT / "Standalone/bin/linux/VoxelForgeOffscreenCapture-l145-clang"
|
||||
fixture = OUT / "fixtures/core-liminal-field-3-strata.json"
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(OUT)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT / "Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(OUT / "xdg-cache")
|
||||
CAPTURES.mkdir(parents=True, exist_ok=True)
|
||||
variants = ("flatField-monolith", "periodicHills",
|
||||
"road-over-cloud-floor", "pillar-grid")
|
||||
selected = set(os.environ.get("L145_CAPTURE_VARIANTS", "").split(","))
|
||||
for seed, name in enumerate(variants):
|
||||
if selected and name not in selected:
|
||||
continue
|
||||
capture_variant(seed, name, headless=headless, renderer=renderer,
|
||||
fixture=fixture, env=env)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L145Capture] status=FAIL error={error}", file=sys.stderr, flush=True)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,51 @@
|
||||
# Linux145 — Core.Liminal.Field v2 landing pads
|
||||
|
||||
**Result: endpoint landing pads alone did not make the liminal join solvable.** The pads bind the passage mouth to certified ground and remove grade failures in the final seed 5 probe, but the passage capsule still intersects native Surface World terrain about 29 m from the departure pad. This matches R48's warning that a pad must cover the approach and tube exclusion envelope; stop here and use a bounded joint plan.
|
||||
|
||||
## What changed
|
||||
|
||||
- Added an opt-in landing-pad record to resolved strata: stable ID, arrival/departure role, position, floor height, Q16 approach direction, clearance, support depth, and a certification bit. The passage planner validates the record and binds the endpoint and tangent to it. Empty pad lists are omitted from canonical serialization, preserving legacy owner layouts and hashes.
|
||||
- Added `Core.Liminal.Field` v2 pads on the field profile: flat ground, hill/valley profile, road endpoints, and pillar-grid clearings. Its layer route connects the pads; the road uses that route as its road centerline.
|
||||
- Added an uncertified-pad negative control. Corrected the ripple audit to retain each valid sample's actual route distance across masked gaps; a 5 m synthetic gap control now confirms that the measurement detects a 5.8 cm ripple and rejects the same smooth cubic control.
|
||||
- Fixed the composed audit's footing placement so it counts actual structural supports. No Unreal `Source/` files changed.
|
||||
|
||||
## Count first: failure cause
|
||||
|
||||
L144's fixed-mouth route already showed both end-connector grade and capsule blockage. For the flat-field seed 0 probe, the liminal route had 222 blocked capsule samples and 7 grade failures, with no unsupported samples or structural-support failures. Pillar-grid seed 3 had 289 blocked samples and 9 grade failures. In the separate seed 5 audit, interface 1–2 had 10 blocked passage-capsule samples and the liminal route had 9 blocked samples, both with zero grade failures. These results say support alone was not the cause; the fixed endpoint geometry sometimes made the approach too steep, while other cases had occupied space at the join. [L144 report](../Linux144/REPORT.md); logs: `Saved/Linux/l144/logs/probe8-seed00.log`, `probe8-seed03.log`, `audit-seed05.log`.
|
||||
|
||||
The pad experiment removed the endpoint-grade part in seed 5, but not the occupied-space part:
|
||||
|
||||
| Probe | Passage 1–2 capsule | Grade / support | Shell | Liminal route |
|
||||
|---|---:|---|---|---|
|
||||
| L144 seed 5, fixed mouths | 10 blocked | 0 grade failures; 0 unsupported | not the failing gate | 9 blocked; 0 grade failures |
|
||||
| L145 seed 5, 45 m ground margin | 140 blocked; 20 interior shell violations | 0 grade failures; 0 unsupported | FAIL | PASS |
|
||||
| L145 seed 5, final 20 m ground margin | 289 blocked | 0 grade failures; 0 unsupported | PASS | PASS |
|
||||
|
||||
The final L145 Clang W1 probe (source stamp `82e3b58c…`) certified both pads. The departure pad was `(12, 0, -716.451) m`, with floor `-717.581 m`, 6 m clearance, and 2 m support depth. Yet the interface-1–2 passage reported 289/50,904 capsule samples blocked, with 0/4,040 unsupported and 0 grade failures. A blocked sample at `(-16.087, 2.915, -722.743) m` had native density `-3.629` and composed density `-0.162`; it is about 29 m from the departure pad. The sample is inside the passage tube, so the layer's field remains solid across the approach even though its pad itself is certified. The lower interface, both shell audits, both ripple audits, and the liminal walk audit passed; the final composed passage summary failed and seam audit did not run for this seed. See `Saved/Linux/l145/logs/audit-seed05-clang-w1.log`.
|
||||
|
||||
For the 45 m attempt, the original seed 0–4 Clang W1 probes passed their composed gates, then seed 5 failed. The seed 5 log was overwritten by the final 20 m rerun; its counts above are from that earlier run. The corrected ripple fitter also removed a false 5.99 cm reading caused by compressing masked samples: at 45 m, seed 0 measured 2.87 cm after retaining route distances. These are probe results, not timing measurements.
|
||||
|
||||
The third repeated seed 5 failure reaches the requested stop condition. This does not show that a full candidate-and-approach contract is impossible; it shows the tested endpoint-only pad contract is too weak. The passage planner needs to choose a candidate while checking the full capsule approach and tube against the layer field, as R48 recommends.
|
||||
|
||||
## Captures
|
||||
|
||||
One 1.6 m eye-height capture was rendered at each arrival pad. All four passed `capture_quality.py`; mesh export used `--capture-skip-walkability`, so these images show appearance and are not walkability evidence.
|
||||
|
||||
| Variant | Capture |
|
||||
|---|---|
|
||||
| Flat field + monolith |  |
|
||||
| Repeating hills |  |
|
||||
| Road over cloud floor |  |
|
||||
| Pillar grid |  |
|
||||
|
||||
## Checks
|
||||
|
||||
- Clang 19 headless and offscreen-capture binaries reported the final source stamp. Four arrival captures passed quality checks.
|
||||
- Fast tier passed on the final source: `Saved/Linux/l145/fast/fast-summary.json` (280.8 s tier duration). The initial default-output attempt refused a stale L42 binary before tests started; rerunning into the isolated L145 output directory with the current L145 binary passed.
|
||||
- Owner canonical hash checks passed: Surface World style 1 and Floating Islands style 2 each matched all 12 pinned L130-v227 rows at W1 and W12, and each recipe's W1/W12 rows matched. These exercise the no-pad owner path.
|
||||
- `git diff --check` passed.
|
||||
- The landing-pad composed matrix stopped at seed 5 after the repeated failure. It did not complete 8 seeds per variant (32 runs). Clang/GCC W1/W8/W12 identity for the liminal fixture was not run. Final-source seeds 0–4 were not rerun after the margin returned to 20 m. No performance timing was collected.
|
||||
|
||||
Changed standalone files: `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, `Standalone/Core/src/ResolvedLayoutInternal.h`, `Standalone/Core/src/WorldAssemblerInternal.h`, `Standalone/Source/StreamBenchmarkHeadless.cpp`, `Standalone/Source/StreamBenchmarkPipeline.h`, and `Standalone/Source/WorldAssemblyPrototype.h`.
|
||||
|
||||
Remaining risk: the current pad record certifies a local landing and direction, not an approach corridor. A future joint planner must reserve/check the full capsule and tube against the layer before finalizing pad choice and passage geometry.
|
||||
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run L145's composed liminal audits and the worker/compiler identity matrix."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l145"
|
||||
FIXTURE = OUT / "fixtures/core-liminal-field-3-strata.json"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
AUDIT_FLAGS = ("--audit-resolved-layout-passages", "--audit-liminal-road-walk",
|
||||
"--audit-passage-tile-seams")
|
||||
VARIANTS = ("flatField-monolith", "periodicHills",
|
||||
"road-over-cloud-floor", "pillar-grid")
|
||||
PASSAGE_RE = re.compile(r"^\[ResolvedPassageAudit\].*walkability=PASS$", re.M)
|
||||
SHELL_RE = re.compile(r"^\[PassageShellAudit\].*status=PASS$", re.M)
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import current_stamp, first_stamp
|
||||
|
||||
|
||||
def parse_seeds(value: str) -> list[int]:
|
||||
result: set[int] = set()
|
||||
for token in value.split(","):
|
||||
token = token.strip()
|
||||
if not token:
|
||||
continue
|
||||
if "-" in token:
|
||||
first, last = (int(part) for part in token.split("-", 1))
|
||||
if first > last:
|
||||
raise argparse.ArgumentTypeError(f"reversed seed range: {token}")
|
||||
result.update(range(first, last + 1))
|
||||
else:
|
||||
result.add(int(token))
|
||||
if not result or min(result) < 0:
|
||||
raise argparse.ArgumentTypeError("seeds must be nonnegative and nonempty")
|
||||
return sorted(result)
|
||||
|
||||
|
||||
def validate_audit(output: str, seed: int, compiler: str, workers: int) -> None:
|
||||
checks = {
|
||||
"landing-pad negative control":
|
||||
"[LandingPadNegativeControl] uncertified_rejected=true status=PASS" in output,
|
||||
"passage walk audits": len(PASSAGE_RE.findall(output)) == 2,
|
||||
"passage shell audits": len(SHELL_RE.findall(output)) == 2,
|
||||
"passage ripple audits": len(re.findall(
|
||||
r"^\[PassageRippleAudit\].*status=PASS$", output, re.M)) == 2,
|
||||
"masked ripple sampling controls": len(re.findall(
|
||||
r"^\[PassageRippleSamplingControl\].*status=PASS$", output, re.M)) == 2,
|
||||
"passage shell summary": bool(re.search(
|
||||
r"^\[PassageShellAuditSummary\].*status=PASS$", output, re.M)),
|
||||
"liminal walk audit": bool(re.search(
|
||||
r"^\[LiminalLayerWalkAudit\].*status=PASS$", output, re.M)),
|
||||
"liminal negative control":
|
||||
"[LiminalLayerNegativeControl] altered_departure_rejected=true status=PASS" in output,
|
||||
"passage summary": bool(re.search(
|
||||
r"^\[ResolvedPassageAuditSummary\].*status=PASS$", output, re.M)),
|
||||
"seam audit": bool(re.search(
|
||||
r"^\[PassageTileSeamAudit\].*status=PASS$", output, re.M)),
|
||||
}
|
||||
failed = [name for name, passed in checks.items() if not passed]
|
||||
if failed:
|
||||
raise RuntimeError(
|
||||
f"seed={seed} compiler={compiler} workers={workers} failed checks: "
|
||||
+ ", ".join(failed))
|
||||
|
||||
|
||||
def run_audit(seed: int, compiler: str, workers: int, *, audit: bool = True) -> dict:
|
||||
binary = ROOT / f"Standalone/bin/linux/VoxelForgeCoreHeadless-l145-{compiler}"
|
||||
if not binary.is_file():
|
||||
raise RuntimeError(f"missing binary: {binary}")
|
||||
expected_stamp = current_stamp()
|
||||
probe = subprocess.run([str(binary), "--print-source-stamp"], cwd=ROOT,
|
||||
capture_output=True, text=True, timeout=15, check=False)
|
||||
if probe.returncode != 0 or first_stamp(probe.stdout) != expected_stamp:
|
||||
raise RuntimeError(f"stale executable: {binary}")
|
||||
|
||||
tag = f"seed{seed:02d}-{compiler}-w{workers}"
|
||||
log = OUT / "logs" / f"audit-{tag}.log"
|
||||
manifest = OUT / "manifests" / f"audit-{tag}.json"
|
||||
layout = OUT / "layouts" / f"audit-{tag}.json"
|
||||
manifest.parent.mkdir(parents=True, exist_ok=True)
|
||||
layout.parent.mkdir(parents=True, exist_ok=True)
|
||||
command = [str(binary), str(FIXTURE), f"--workers={workers}",
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", "--clip-radius=1", "--max-clip-level=0", "--max-level=0",
|
||||
"--render-distance-chunks=0", "--camera=0,0,-540,0,0", f"--seed={seed}",
|
||||
f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
if audit:
|
||||
command.extend(AUDIT_FLAGS)
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(OUT)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT / "Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(OUT / "xdg-cache")
|
||||
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, "timeout", "1740s", *command],
|
||||
cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT,
|
||||
timeout=1745, check=False)
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"{tag} exit={result.returncode}; see {log}")
|
||||
if first_stamp(output) != expected_stamp or current_stamp() != expected_stamp:
|
||||
raise RuntimeError(f"{tag} source stamp changed during run; see {log}")
|
||||
if audit:
|
||||
validate_audit(output, seed, compiler, workers)
|
||||
if not manifest.is_file() or not layout.is_file():
|
||||
raise RuntimeError(f"{tag} omitted canonical manifest or layout")
|
||||
manifest_value = json.loads(manifest.read_text(encoding="utf-8"))
|
||||
layout_value = json.loads(layout.read_text(encoding="utf-8"))
|
||||
identity = {
|
||||
"seed": seed,
|
||||
"variant": VARIANTS[seed % len(VARIANTS)],
|
||||
"compiler": compiler,
|
||||
"workers": workers,
|
||||
"manifest_hash": manifest_value["content_hash"],
|
||||
"resolved_layout_identity": layout_value["stable_identity"],
|
||||
"log": str(log.relative_to(ROOT)),
|
||||
"elapsed_s": round(time.monotonic() - started, 3),
|
||||
"audited": audit,
|
||||
}
|
||||
print(f"[L145AuditRun] seed={seed} variant={identity['variant']} compiler={compiler} "
|
||||
f"workers={workers} manifest={identity['manifest_hash']} "
|
||||
f"layout={identity['resolved_layout_identity']} "
|
||||
f"elapsed_s={identity['elapsed_s']:.3f} status=PASS", flush=True)
|
||||
return identity
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--seeds", default="0-31", type=parse_seeds,
|
||||
help="audit seeds, e.g. 0-31 or 0,1,2,3")
|
||||
parser.add_argument("--determinism", action="store_true",
|
||||
help="also compare seed 0 on Clang/GCC at W1/W8/W12")
|
||||
parser.add_argument("--only-determinism", action="store_true",
|
||||
help="run only the Clang/GCC seed-0 W1/W8/W12 identity matrix")
|
||||
args = parser.parse_args()
|
||||
if not FIXTURE.is_file():
|
||||
raise SystemExit(f"missing fixture: {FIXTURE}; run BuildL145Fixtures.py first")
|
||||
|
||||
records = []
|
||||
if not args.only_determinism:
|
||||
for seed in args.seeds:
|
||||
records.append(run_audit(seed, "clang", 1))
|
||||
if args.determinism or args.only_determinism:
|
||||
matrix = [run_audit(0, compiler, workers)
|
||||
for compiler in ("clang", "gcc") for workers in (1, 8, 12)]
|
||||
identities = {(row["manifest_hash"], row["resolved_layout_identity"])
|
||||
for row in matrix}
|
||||
if len(identities) != 1:
|
||||
raise RuntimeError(f"Clang/GCC W1/W8/W12 identity mismatch: {matrix}")
|
||||
records.extend(matrix)
|
||||
|
||||
summary = {
|
||||
"audit_seeds": args.seeds if not args.only_determinism else [],
|
||||
"variant_counts": {
|
||||
name: sum(1 for seed in args.seeds if seed % len(VARIANTS) == index)
|
||||
for index, name in enumerate(VARIANTS)
|
||||
} if not args.only_determinism else {},
|
||||
"records": records,
|
||||
"determinism_pass": bool(args.determinism or args.only_determinism),
|
||||
"status": "PASS",
|
||||
}
|
||||
summary_path = OUT / "audit-matrix-summary.json"
|
||||
summary_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
summary_path.write_text(json.dumps(summary, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"[L145AuditMatrix] records={len(records)} summary={summary_path} status=PASS",
|
||||
flush=True)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L145AuditMatrix] status=FAIL error={error}", file=sys.stderr, flush=True)
|
||||
raise SystemExit(1)
|
||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,46 @@
|
||||
# L146 report
|
||||
|
||||
**Result:** No production fix is retained. The cause is measured: the liminal route fill pass runs after the passage carve and makes part of the bore solid again. The new passage-interior capsule audit catches the seed-5 defect. After three fixes cleared the bore but failed the liminal road support gate, work stopped as required by `AGENTS.md`.
|
||||
|
||||
## Root cause
|
||||
|
||||
Measured at `(-16.087, 2.915, -722.743) m`, seed 5, Clang W1, composed L145 fixture:
|
||||
|
||||
- Before passage composition, density was `-3.62890625`.
|
||||
- The passage SDF reported `union_distance_m=-0.879889786`; carving changed density to `+3.51955914` (air).
|
||||
- The subsequent liminal route stamp changed it to `-0.16169475` (solid).
|
||||
|
||||
The diagnostic directly identifies the post-carve route-fill pass as the cause. The resolved route/deck geometry indicates the fill overlaps the bore there; that specific deck overlap is inferred from the layout. The half-pipe/open-air path, carve reach, and carve blend are not the cause at this sample: the passage carver ran and produced positive air density before the route stamp.
|
||||
|
||||
Trace: `Saved/Linux/l146/logs/diagnostic-seed05-clang-w1.log`.
|
||||
|
||||
## Fix attempts
|
||||
|
||||
All were temporary and have been reverted; production composition and evaluator version remain at L145 / v227.
|
||||
|
||||
1. Move fill stamps before passage carving: passage probes cleared, but the liminal road had 29 unsupported stations.
|
||||
2. Suppress route fills inside the passage interior: same result, 29 unsupported stations.
|
||||
3. Reroute the southern deck around the crossing: passage probes cleared, but 28 road stations remained unsupported.
|
||||
|
||||
The three seed-5 runs are `probe-seed05-clang-w1.log`, `probe-masked-seed05-clang-w1.log`, and `route-seed05-clang-w1.log` under `Saved/Linux/l146/logs/`.
|
||||
|
||||
The shared premise that changing stamp order or locally moving the deck could preserve both bore air and road support failed twice. The route adjustment also failed the support gate, so no fourth fix was attempted.
|
||||
|
||||
## Audit and checks
|
||||
|
||||
`StreamBenchmarkPipeline.h` now classifies each tested player-capsule sample against its passage interior and requires zero solid interior samples. A no-passage negative control uses the same interior classification and must detect solid samples for every passage.
|
||||
|
||||
On the final source, the seed-5 audit measured 50,904 interior capsule samples and 289 solid samples for passage 1-2. Both negative controls detected solid interior samples (165,769 and 49,612). The shell summary passed with zero floor or wall violations, and the liminal road audit passed. The composed passage audit exited 10 as expected because the new interior-air gate detected the defect.
|
||||
|
||||
The final-source evidence is `Saved/Linux/l146/logs/audit-seed05-clang-w1.log`.
|
||||
|
||||
- Clang W1 final-source build: passed; log `Saved/Linux/l146/fast/logs/build-fast-clang-final.log`.
|
||||
- Fast verification tier: passed in 362.5 s; summary `Saved/Linux/l146/fast/fast-summary.json`.
|
||||
- Owner canonical v227 hash rows: passed for both pinned owner worlds; W1 and W12 signatures matched.
|
||||
- `git diff --check`: passed.
|
||||
- The 32-run pad matrix and the liminal Clang/GCC W1/W8/W12 matrix were not run because the three-failed-fix stop condition was reached. The 16-seed cave-planner sweep is not on this branch.
|
||||
- No Unreal `Source/` files changed.
|
||||
|
||||
## Remaining risk
|
||||
|
||||
The seed-5 passage interior remains partly solid in production. A new design must define how route floor support and passage air share their overlap before changing composition again. No passage-composition change or owner hash change is retained.
|
||||
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run L146's composed liminal audits and the worker/compiler identity matrix."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l146"
|
||||
FIXTURE = OUT / "fixtures/core-liminal-field-3-strata.json"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
AUDIT_FLAGS = ("--audit-resolved-layout-passages", "--audit-liminal-road-walk",
|
||||
"--audit-passage-tile-seams")
|
||||
VARIANTS = ("flatField-monolith", "periodicHills",
|
||||
"road-over-cloud-floor", "pillar-grid")
|
||||
PASSAGE_RE = re.compile(r"^\[ResolvedPassageAudit\].*walkability=PASS$", re.M)
|
||||
SHELL_RE = re.compile(r"^\[PassageShellAudit\].*status=PASS$", re.M)
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import current_stamp, first_stamp
|
||||
|
||||
|
||||
def parse_seeds(value: str) -> list[int]:
|
||||
result: set[int] = set()
|
||||
for token in value.split(","):
|
||||
token = token.strip()
|
||||
if not token:
|
||||
continue
|
||||
if "-" in token:
|
||||
first, last = (int(part) for part in token.split("-", 1))
|
||||
if first > last:
|
||||
raise argparse.ArgumentTypeError(f"reversed seed range: {token}")
|
||||
result.update(range(first, last + 1))
|
||||
else:
|
||||
result.add(int(token))
|
||||
if not result or min(result) < 0:
|
||||
raise argparse.ArgumentTypeError("seeds must be nonnegative and nonempty")
|
||||
return sorted(result)
|
||||
|
||||
|
||||
def validate_audit(output: str, seed: int, compiler: str, workers: int) -> None:
|
||||
checks = {
|
||||
"landing-pad negative control":
|
||||
"[LandingPadNegativeControl] uncertified_rejected=true status=PASS" in output,
|
||||
"passage walk audits": len(PASSAGE_RE.findall(output)) == 2,
|
||||
"passage interior capsule audit": len(re.findall(
|
||||
r"^\[ResolvedPassageAudit\].*passage_interior_capsule_samples=[1-9]\d* "
|
||||
r"passage_interior_solid_samples=0 interior_air=PASS .*walkability=PASS$",
|
||||
output, re.M)) == 2,
|
||||
"passage interior negative controls": len(re.findall(
|
||||
r"^\[ResolvedPassageInteriorNegativeControl\].*interior_solid_samples=[1-9]\d* "
|
||||
r"detected=true status=PASS$", output, re.M)) == 2,
|
||||
"passage interior audit summary": bool(re.search(
|
||||
r"^\[PassageInteriorCapsuleAuditSummary\].*status=PASS$", output, re.M)),
|
||||
"passage shell audits": len(SHELL_RE.findall(output)) == 2,
|
||||
"passage ripple audits": len(re.findall(
|
||||
r"^\[PassageRippleAudit\].*status=PASS$", output, re.M)) == 2,
|
||||
"masked ripple sampling controls": len(re.findall(
|
||||
r"^\[PassageRippleSamplingControl\].*status=PASS$", output, re.M)) == 2,
|
||||
"passage shell summary": bool(re.search(
|
||||
r"^\[PassageShellAuditSummary\].*status=PASS$", output, re.M)),
|
||||
"liminal walk audit": bool(re.search(
|
||||
r"^\[LiminalLayerWalkAudit\].*status=PASS$", output, re.M)),
|
||||
"liminal negative control":
|
||||
"[LiminalLayerNegativeControl] altered_departure_rejected=true status=PASS" in output,
|
||||
"passage summary": bool(re.search(
|
||||
r"^\[ResolvedPassageAuditSummary\].*status=PASS$", output, re.M)),
|
||||
"seam audit": bool(re.search(
|
||||
r"^\[PassageTileSeamAudit\].*status=PASS$", output, re.M)),
|
||||
}
|
||||
failed = [name for name, passed in checks.items() if not passed]
|
||||
if failed:
|
||||
raise RuntimeError(
|
||||
f"seed={seed} compiler={compiler} workers={workers} failed checks: "
|
||||
+ ", ".join(failed))
|
||||
|
||||
|
||||
def run_audit(seed: int, compiler: str, workers: int, *, audit: bool = True) -> dict:
|
||||
binary = OUT / "fast/bin" / f"VoxelForgeCoreHeadless-fast-{compiler}"
|
||||
if not binary.is_file():
|
||||
raise RuntimeError(f"missing binary: {binary}")
|
||||
expected_stamp = current_stamp()
|
||||
probe = subprocess.run([str(binary), "--print-source-stamp"], cwd=ROOT,
|
||||
capture_output=True, text=True, timeout=15, check=False)
|
||||
if probe.returncode != 0 or first_stamp(probe.stdout) != expected_stamp:
|
||||
raise RuntimeError(f"stale executable: {binary}")
|
||||
|
||||
tag = f"seed{seed:02d}-{compiler}-w{workers}"
|
||||
log = OUT / "logs" / f"audit-{tag}.log"
|
||||
manifest = OUT / "manifests" / f"audit-{tag}.json"
|
||||
layout = OUT / "layouts" / f"audit-{tag}.json"
|
||||
manifest.parent.mkdir(parents=True, exist_ok=True)
|
||||
layout.parent.mkdir(parents=True, exist_ok=True)
|
||||
command = [str(binary), str(FIXTURE), f"--workers={workers}",
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", "--clip-radius=1", "--max-clip-level=0", "--max-level=0",
|
||||
"--render-distance-chunks=0", "--camera=0,0,-540,0,0", f"--seed={seed}",
|
||||
f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
if audit:
|
||||
command.extend(AUDIT_FLAGS)
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(OUT)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT / "Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(OUT / "xdg-cache")
|
||||
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, "timeout", "1740s", *command],
|
||||
cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT,
|
||||
timeout=1745, check=False)
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"{tag} exit={result.returncode}; see {log}")
|
||||
if first_stamp(output) != expected_stamp or current_stamp() != expected_stamp:
|
||||
raise RuntimeError(f"{tag} source stamp changed during run; see {log}")
|
||||
if audit:
|
||||
validate_audit(output, seed, compiler, workers)
|
||||
if not manifest.is_file() or not layout.is_file():
|
||||
raise RuntimeError(f"{tag} omitted canonical manifest or layout")
|
||||
manifest_value = json.loads(manifest.read_text(encoding="utf-8"))
|
||||
layout_value = json.loads(layout.read_text(encoding="utf-8"))
|
||||
identity = {
|
||||
"seed": seed,
|
||||
"variant": VARIANTS[seed % len(VARIANTS)],
|
||||
"compiler": compiler,
|
||||
"workers": workers,
|
||||
"manifest_hash": manifest_value["content_hash"],
|
||||
"resolved_layout_identity": layout_value["stable_identity"],
|
||||
"log": str(log.relative_to(ROOT)),
|
||||
"elapsed_s": round(time.monotonic() - started, 3),
|
||||
"audited": audit,
|
||||
}
|
||||
print(f"[L146AuditRun] seed={seed} variant={identity['variant']} compiler={compiler} "
|
||||
f"workers={workers} manifest={identity['manifest_hash']} "
|
||||
f"layout={identity['resolved_layout_identity']} "
|
||||
f"elapsed_s={identity['elapsed_s']:.3f} status=PASS", flush=True)
|
||||
return identity
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--seeds", default="0-31", type=parse_seeds,
|
||||
help="audit seeds, e.g. 0-31 or 0,1,2,3")
|
||||
parser.add_argument("--determinism", action="store_true",
|
||||
help="also compare seed 0 on Clang/GCC at W1/W8/W12")
|
||||
parser.add_argument("--only-determinism", action="store_true",
|
||||
help="run only the Clang/GCC seed-0 W1/W8/W12 identity matrix")
|
||||
args = parser.parse_args()
|
||||
if not FIXTURE.is_file():
|
||||
raise SystemExit(f"missing fixture: {FIXTURE}; build the L145 liminal fixture first")
|
||||
|
||||
records = []
|
||||
if not args.only_determinism:
|
||||
for seed in args.seeds:
|
||||
records.append(run_audit(seed, "clang", 1))
|
||||
if args.determinism or args.only_determinism:
|
||||
matrix = [run_audit(0, compiler, workers)
|
||||
for compiler in ("clang", "gcc") for workers in (1, 8, 12)]
|
||||
identities = {(row["manifest_hash"], row["resolved_layout_identity"])
|
||||
for row in matrix}
|
||||
if len(identities) != 1:
|
||||
raise RuntimeError(f"Clang/GCC W1/W8/W12 identity mismatch: {matrix}")
|
||||
records.extend(matrix)
|
||||
|
||||
summary = {
|
||||
"audit_seeds": args.seeds if not args.only_determinism else [],
|
||||
"variant_counts": {
|
||||
name: sum(1 for seed in args.seeds if seed % len(VARIANTS) == index)
|
||||
for index, name in enumerate(VARIANTS)
|
||||
} if not args.only_determinism else {},
|
||||
"records": records,
|
||||
"determinism_pass": bool(args.determinism or args.only_determinism),
|
||||
"status": "PASS",
|
||||
}
|
||||
summary_path = OUT / "l146-audit-matrix-summary.json"
|
||||
summary_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
summary_path.write_text(json.dumps(summary, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"[L146AuditMatrix] records={len(records)} summary={summary_path} status=PASS",
|
||||
flush=True)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L146AuditMatrix] status=FAIL error={error}", file=sys.stderr, flush=True)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build four standalone liminal geometry fixtures and their capsule-walk specs."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA",
|
||||
ROOT / "Standalone/data/owner_world.json"))
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l161"))
|
||||
FLAT_FIELD = {"version": 1, "kind": "flatField", "minimum_arena_clearance_m": 0.0}
|
||||
|
||||
|
||||
def stamp(stamps: list[dict], stable_id: str, kind: str, x: float, y: float,
|
||||
z: float, half: tuple[float, float, float], *, yaw: int = 0,
|
||||
steps: int | None = None) -> None:
|
||||
row = {
|
||||
"stable_id": stable_id,
|
||||
"kind": kind,
|
||||
"anchor_xy_m": [x, y],
|
||||
"z_offset_m": z,
|
||||
"half_extents_m": list(half),
|
||||
"yaw_quarter_turns": yaw,
|
||||
}
|
||||
if steps is not None:
|
||||
row["step_count"] = steps
|
||||
stamps.append(row)
|
||||
|
||||
|
||||
def fixture(name: str, stamps: list[dict], walk_points: list[tuple[float, float, float]],
|
||||
doors: list[dict], *, center: tuple[float, float], wide_camera: tuple[float, float, float],
|
||||
eye_camera: tuple[float, float, float], eye_target_offset: tuple[float, float, float],
|
||||
wide_target_offset: tuple[float, float, float],
|
||||
eye_clip: int, wide_clip: int) -> tuple[str, dict, dict]:
|
||||
root = json.loads(OWNER.read_text(encoding="utf-8"))
|
||||
root["surface_profile_override"] = dict(FLAT_FIELD)
|
||||
root["liminal_stamp_fixture_override"] = {
|
||||
"version": 1,
|
||||
"strate_index": 0,
|
||||
"stamps": stamps,
|
||||
}
|
||||
walk = {
|
||||
"version": 1,
|
||||
"path_points_offset_m": [list(point) for point in walk_points],
|
||||
"door_prefixes": doors,
|
||||
}
|
||||
views = {
|
||||
"center_xy_m": list(center),
|
||||
"eye_camera_offset_m": list(eye_camera),
|
||||
"wide_camera_offset_m": list(wide_camera),
|
||||
"eye_target_offset_m": list(eye_target_offset),
|
||||
"wide_target_offset_m": list(wide_target_offset),
|
||||
"eye_clip_radius": eye_clip,
|
||||
"wide_clip_radius": wide_clip,
|
||||
}
|
||||
return name, root, {"walk": walk, "views": views}
|
||||
|
||||
|
||||
def pool_rooms() -> tuple[str, dict, dict]:
|
||||
stamps: list[dict] = []
|
||||
cx, cy, cell, cells = 520.0, 440.0, 20.0, 7
|
||||
half = cell * cells * 0.5
|
||||
wall_height, wall_half_thickness = 9.0, 1.2
|
||||
for line in range(cells + 1):
|
||||
offset = (line - cells * 0.5) * cell
|
||||
stamp(stamps, f"liminal/pool-rooms-v1/00-wall-x/{line:02d}", "fillBox",
|
||||
cx + offset, cy, wall_height * 0.5,
|
||||
(wall_half_thickness, half, wall_height * 0.5))
|
||||
stamp(stamps, f"liminal/pool-rooms-v1/00-wall-y/{line:02d}", "fillBox",
|
||||
cx, cy + offset, wall_height * 0.5,
|
||||
(half, wall_half_thickness, wall_height * 0.5))
|
||||
for row in range(cells):
|
||||
y = cy + (row - (cells - 1) * 0.5) * cell
|
||||
for line in range(cells + 1):
|
||||
x = cx + (line - cells * 0.5) * cell
|
||||
stamp(stamps, f"liminal/pool-rooms-v1/01-doorway-x/{row:02d}-{line:02d}",
|
||||
"carveArch", x, y + 7.0, 4.0, (3.6, 1.55, 4.0), yaw=1)
|
||||
stamp(stamps, f"liminal/pool-rooms-v1/01-doorway-y/{line:02d}-{row:02d}",
|
||||
"carveArch", cx + (row - (cells - 1) * 0.5) * cell,
|
||||
cy + (line - cells * 0.5) * cell, 4.0,
|
||||
(3.6, 1.55, 4.0))
|
||||
for row in range(cells):
|
||||
y = cy + (row - (cells - 1) * 0.5) * cell
|
||||
for column in range(cells):
|
||||
x = cx + (column - (cells - 1) * 0.5) * cell
|
||||
stamp(stamps, f"liminal/pool-rooms-v1/02-roof/{row:02d}-{column:02d}",
|
||||
"fillBox", x, y, 9.4, (10.0, 10.0, 0.5))
|
||||
stamp(stamps, f"liminal/pool-rooms-v1/03-skylight/{row:02d}-{column:02d}",
|
||||
"carveBox", x, y, 9.4, (5.5, 5.5, 1.0))
|
||||
stamp(stamps, f"liminal/pool-rooms-v1/04-basin/{row:02d}-{column:02d}",
|
||||
"carveBox", x, y, -1.0, (5.5, 5.5, 1.5))
|
||||
path_y = cy + 7.0
|
||||
walk = [(-half - 2.0 + cx, path_y, 0.88), (half + 2.0 + cx, path_y, 0.88)]
|
||||
doors = [
|
||||
{"prefix": "liminal/pool-rooms-v1/01-doorway-x/", "width_axis": 0,
|
||||
"minimum_width_m": 1.5},
|
||||
{"prefix": "liminal/pool-rooms-v1/01-doorway-y/", "width_axis": 0,
|
||||
"minimum_width_m": 1.5},
|
||||
]
|
||||
return fixture("pool-rooms", stamps, walk, doors, center=(cx, cy),
|
||||
wide_camera=(-60.0, 7.0, 3.0), eye_camera=(-40.0, 7.0, 1.6),
|
||||
eye_target_offset=(60.0, 7.0, 0.8),
|
||||
wide_target_offset=(65.0, 7.0, 1.2), eye_clip=4, wide_clip=7)
|
||||
|
||||
|
||||
def backrooms(width: float = 4.0, name: str = "backrooms-grid") -> tuple[str, dict, dict]:
|
||||
stamps: list[dict] = []
|
||||
cx, cy, cell, cells = 820.0, 420.0, 18.0, 7
|
||||
half, wall_half = cell * cells * 0.5, 1.2
|
||||
wall_height = 5.5
|
||||
for line in range(cells + 1):
|
||||
offset = (line - cells * 0.5) * cell
|
||||
stamp(stamps, f"liminal/backrooms-grid-v1/00-wall-x/{line:02d}", "fillBox",
|
||||
cx + offset, cy, wall_height * 0.5,
|
||||
(wall_half, half, wall_height * 0.5))
|
||||
stamp(stamps, f"liminal/backrooms-grid-v1/00-wall-y/{line:02d}", "fillBox",
|
||||
cx, cy + offset, wall_height * 0.5,
|
||||
(half, wall_half, wall_height * 0.5))
|
||||
door_half = width * 0.5
|
||||
for row in range(cells):
|
||||
y = cy + (row - (cells - 1) * 0.5) * cell
|
||||
for line in range(cells + 1):
|
||||
x = cx + (line - cells * 0.5) * cell
|
||||
stamp(stamps, f"liminal/backrooms-grid-v1/01-door-x/{row:02d}-{line:02d}",
|
||||
"carveBox", x, y, 1.25, (1.6, door_half, 1.25))
|
||||
stamp(stamps, f"liminal/backrooms-grid-v1/01-door-y/{line:02d}-{row:02d}",
|
||||
"carveBox", cx + (row - (cells - 1) * 0.5) * cell,
|
||||
cy + (line - cells * 0.5) * cell, 1.25,
|
||||
(door_half, 1.6, 1.25))
|
||||
stamp(stamps, "liminal/backrooms-grid-v1/02-ceiling", "fillBox",
|
||||
cx, cy, 5.9, (half, half, 0.5))
|
||||
walk = [(cx - half - 2.0, cy, 0.88), (cx + half + 2.0, cy, 0.88)]
|
||||
doors = [
|
||||
{"prefix": "liminal/backrooms-grid-v1/01-door-x/", "width_axis": 1,
|
||||
"minimum_width_m": 1.5},
|
||||
{"prefix": "liminal/backrooms-grid-v1/01-door-y/", "width_axis": 0,
|
||||
"minimum_width_m": 1.5},
|
||||
]
|
||||
return fixture(name, stamps, walk, doors, center=(cx, cy),
|
||||
wide_camera=(-42.0, -6.0, 1.6), eye_camera=(-54.0, 0.0, 1.6),
|
||||
eye_target_offset=(102.0, 0.0, 1.6),
|
||||
wide_target_offset=(80.0, 20.0, 0.0), eye_clip=6, wide_clip=6)
|
||||
|
||||
|
||||
def nowhere_stairs() -> tuple[str, dict, dict]:
|
||||
stamps: list[dict] = []
|
||||
cx, cy = 300.0, -760.0
|
||||
stamp(stamps, "liminal/staircase-nowhere-v1/00-stair", "fillSteps",
|
||||
cx, cy, 6.0, (32.0, 4.0, 6.0), steps=64)
|
||||
stamp(stamps, "liminal/staircase-nowhere-v1/04-landing", "fillBox",
|
||||
cx + 40.5, cy, 11.5, (9.0, 4.5, 0.5))
|
||||
stamp(stamps, "liminal/staircase-nowhere-v1/02-arch-wall", "fillBox",
|
||||
cx + 38.0, cy, 7.5, (1.2, 6.5, 7.5))
|
||||
stamp(stamps, "liminal/staircase-nowhere-v1/03-doorway-arch", "carveArch",
|
||||
cx + 38.0, cy, 7.0, (5.0, 5.0, 7.0), yaw=1)
|
||||
# Begin high enough to clear the first riser with the audit capsule, then
|
||||
# walk the same ascending staircase through the arch and onto the landing.
|
||||
points = [(cx - 32.5, cy, 0.88 + 12.0 / 64.0 + 0.05)]
|
||||
tread, rise = 64.0 / 64, 12.0 / 64
|
||||
for index in range(64):
|
||||
points.append((cx - 32.0 + (index + 0.5) * tread,
|
||||
cy, 0.88 + (index + 1) * rise + 0.05))
|
||||
points.extend([(cx + 34.0, cy, 12.93), (cx + 38.0, cy, 12.93),
|
||||
(cx + 44.0, cy, 12.93)])
|
||||
doors = [{"prefix": "liminal/staircase-nowhere-v1/03-doorway-arch", "width_axis": 0,
|
||||
"minimum_width_m": 1.5}]
|
||||
return fixture("staircase-to-nowhere", stamps, points, doors, center=(cx, cy),
|
||||
wide_camera=(-8.0, -32.0, 36.0), eye_camera=(10.0, 0.0, 9.7),
|
||||
eye_target_offset=(38.0, 0.0, 13.6),
|
||||
wide_target_offset=(42.0, 0.0, 11.0), eye_clip=4, wide_clip=6)
|
||||
|
||||
|
||||
def terraced_hills() -> tuple[str, dict, dict]:
|
||||
stamps: list[dict] = []
|
||||
cx, cy, rows, spacing = -520.0, -500.0, 9, 96.0
|
||||
half_run, half_width, half_rise, steps = 48.0, 40.0, 8.0, 80
|
||||
for row in range(rows):
|
||||
y = cy + (row - (rows - 1) * 0.5) * spacing
|
||||
stamp(stamps, f"liminal/terraced-hills-v1/ridge/{row:02d}/rise-west",
|
||||
"fillSteps", cx - half_run, y, half_rise,
|
||||
(half_run, half_width, half_rise), steps=steps)
|
||||
stamp(stamps, f"liminal/terraced-hills-v1/ridge/{row:02d}/rise-east",
|
||||
"fillSteps", cx + half_run, y, half_rise,
|
||||
(half_run, half_width, half_rise), yaw=2, steps=steps)
|
||||
points = [(cx - 100.0, cy, 0.93)]
|
||||
tread, rise = (2.0 * half_run) / steps, (2.0 * half_rise) / steps
|
||||
for index in range(steps):
|
||||
points.append((cx - 2.0 * half_run + (index + 0.5) * tread,
|
||||
cy, 0.93 + (index + 1) * rise))
|
||||
for index in reversed(range(steps)):
|
||||
points.append((cx + 2.0 * half_run - (index + 0.5) * tread,
|
||||
cy, 0.93 + (index + 1) * rise))
|
||||
points.append((cx + 100.0, cy, 0.93))
|
||||
return fixture("terraced-hills", stamps, points, [], center=(cx, cy),
|
||||
wide_camera=(-40.0, 0.0, 20.0), eye_camera=(-60.0, 0.0, 7.8),
|
||||
eye_target_offset=(0.0, 0.0, 14.5),
|
||||
wide_target_offset=(100.0, 0.0, -10.0), eye_clip=4, wide_clip=3)
|
||||
|
||||
|
||||
def write(path: Path, value: dict) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(value, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT / "fixtures")
|
||||
args = parser.parse_args()
|
||||
args.out.mkdir(parents=True, exist_ok=True)
|
||||
specs = args.out / "walk-specs"
|
||||
fixtures = [pool_rooms(), backrooms(), nowhere_stairs(), terraced_hills()]
|
||||
fixtures.append(backrooms(width=1.2, name="backrooms-narrow-control"))
|
||||
for name, world, metadata in fixtures:
|
||||
write(args.out / f"liminal-{name}.json", world)
|
||||
write(specs / f"{name}.json", metadata["walk"])
|
||||
write(args.out / "views" / f"{name}.json", metadata["views"])
|
||||
print(f"[L161Fixture] name={name} stamps="
|
||||
f"{len(world['liminal_stamp_fixture_override']['stamps'])} status=PASS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,320 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run L161 stamp-fixture determinism, walk audits and two-view captures."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l161"))
|
||||
CAPTURE_DEFAULT = Path(__file__).resolve().parent / "captures"
|
||||
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
|
||||
Q_PER_METRE = 1024.0
|
||||
FOG_COLOR = "0.78,0.84,0.87"
|
||||
|
||||
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
|
||||
from runner import current_stamp, first_stamp
|
||||
|
||||
|
||||
def fmt(values) -> str:
|
||||
return ",".join(f"{value:.6f}" for value in values)
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def run_step(name: str, command: list[object], log: Path, *, env: dict[str, str],
|
||||
stamped: bool = False, expected_exit: int = 0,
|
||||
timeout_seconds: int = 1740) -> str:
|
||||
expected_stamp = current_stamp() if stamped else None
|
||||
if stamped:
|
||||
probe = subprocess.run([str(command[0]), "--print-source-stamp"], cwd=ROOT,
|
||||
capture_output=True, text=True, timeout=15, check=False)
|
||||
if probe.returncode != 0 or first_stamp(probe.stdout) != expected_stamp:
|
||||
raise RuntimeError(f"{name} refused a stale executable: {command[0]}")
|
||||
log.parent.mkdir(parents=True, exist_ok=True)
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run([*LIMIT, "timeout", f"{timeout_seconds}s",
|
||||
*map(str, command)], cwd=ROOT, env=env, stdout=stream,
|
||||
stderr=subprocess.STDOUT, timeout=timeout_seconds + 5, check=False)
|
||||
elapsed = time.monotonic() - started
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
print(f"[L161Run] step={name} elapsed_s={elapsed:.3f} exit={result.returncode} log={log}",
|
||||
flush=True)
|
||||
if stamped and (first_stamp(output) != expected_stamp or current_stamp() != expected_stamp):
|
||||
raise RuntimeError(f"{name} source stamp mismatch; see {log}")
|
||||
if result.returncode != expected_exit:
|
||||
raise RuntimeError(f"{name} exit={result.returncode}, expected={expected_exit}; see {log}")
|
||||
return output
|
||||
|
||||
|
||||
def camera_for(view: dict, floor: float, name: str, kind: str) -> tuple[float, float, float]:
|
||||
center_x, center_y = view["center_xy_m"]
|
||||
offset = view[f"{kind}_camera_offset_m"]
|
||||
z = floor + offset[2]
|
||||
if name == "backrooms-grid" or name == "backrooms-narrow-control":
|
||||
z = floor + offset[2]
|
||||
return center_x + offset[0], center_y + offset[1], z
|
||||
|
||||
|
||||
def target_for(view: dict, floor: float, name: str, kind: str) -> tuple[float, float, float]:
|
||||
center_x, center_y = view["center_xy_m"]
|
||||
offset = view[f"{kind}_target_offset_m"]
|
||||
return center_x + offset[0], center_y + offset[1], floor + offset[2]
|
||||
|
||||
|
||||
def headless_command(binary: Path, fixture: Path, camera, mesh: Path,
|
||||
manifest: Path, layout: Path, workers: int, clip_radius: int,
|
||||
*, max_level: int = 0, hash_tiles: bool = False,
|
||||
audit_path: Path | None = None) -> list[object]:
|
||||
command: list[object] = [binary, fixture, f"--workers={workers}", "--seed=0",
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--force-generate", f"--clip-radius={clip_radius}",
|
||||
f"--max-clip-level={max_level}", f"--max-level={max_level}",
|
||||
"--render-distance-chunks=0",
|
||||
f"--camera={fmt((*camera, 0.0, 0.0))}", f"--mesh-export={mesh}",
|
||||
f"--world-assembler-manifest-output={manifest}",
|
||||
f"--resolved-layout-output={layout}"]
|
||||
if hash_tiles:
|
||||
command.append("--stream-hash-tiles")
|
||||
if audit_path is not None:
|
||||
command.append(f"--audit-liminal-stamp-walk={audit_path}")
|
||||
return command
|
||||
|
||||
|
||||
def digest(output: str, manifest_path: Path, layout_path: Path) -> tuple[str, str, str]:
|
||||
tile_hashes = sorted(line for line in output.splitlines()
|
||||
if line.startswith("[PipelineTileHash] "))
|
||||
if not manifest_path.is_file() or not layout_path.is_file() or not tile_hashes:
|
||||
raise RuntimeError("determinism run omitted manifest, resolved layout or tile hashes")
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
layout = json.loads(layout_path.read_text(encoding="utf-8"))
|
||||
manifest_digest = "|".join((manifest["content_hash"],
|
||||
manifest["recipe"]["content_hash"], manifest["plan"]["content_hash"]))
|
||||
return manifest_digest, layout["stable_identity"], "\n".join(tile_hashes)
|
||||
|
||||
|
||||
def write_walk_audit(spec_path: Path, manifest_path: Path, audit_path: Path) -> None:
|
||||
spec = json.loads(spec_path.read_text(encoding="utf-8"))
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
surface = manifest["recipe"]["surface_profile"]
|
||||
floor = surface["h0_q"] / Q_PER_METRE
|
||||
lines = ["# P records are world metres; doorway width axes use the resolved stamp's local extents."]
|
||||
for gate in spec["door_prefixes"]:
|
||||
lines.append(f"D {gate['prefix']} {gate['width_axis']} {gate['minimum_width_m']:.6f}")
|
||||
for x, y, z_offset in spec["path_points_offset_m"]:
|
||||
lines.append(f"P {x:.6f} {y:.6f} {floor + z_offset:.6f}")
|
||||
audit_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
audit_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def camera_angles(camera, target) -> tuple[float, float]:
|
||||
dx, dy, dz = (target[index] - camera[index] for index in range(3))
|
||||
return math.degrees(math.atan2(dx, dy)), math.degrees(math.atan2(dz, math.hypot(dx, dy)))
|
||||
|
||||
|
||||
def build_plan(binary: Path, name: str, fixture: Path, view: dict,
|
||||
out: Path, env: dict[str, str]) -> tuple[Path, Path, dict, dict]:
|
||||
run_dir = out / "plan-probes" / name
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
manifest, layout = run_dir / "manifest.json", run_dir / "layout.json"
|
||||
mesh = run_dir / "probe.vfmesh"
|
||||
camera = (view["center_xy_m"][0], view["center_xy_m"][1], -500.0)
|
||||
output = run_step(f"plan-{name}", headless_command(binary, fixture, camera,
|
||||
mesh, manifest, layout, 12, 1), out / "logs" / f"plan-{name}.log",
|
||||
env=env, stamped=True)
|
||||
if "[LiminalStampFixtureResolved] vocabulary=7" not in output:
|
||||
raise RuntimeError(f"{name} did not resolve with stamp vocabulary 7")
|
||||
if not manifest.is_file() or not layout.is_file():
|
||||
raise RuntimeError(f"{name} plan probe omitted its outputs")
|
||||
manifest_value = json.loads(manifest.read_text(encoding="utf-8"))
|
||||
layout_value = json.loads(layout.read_text(encoding="utf-8"))
|
||||
return manifest, layout, manifest_value, layout_value
|
||||
|
||||
|
||||
def run_determinism(name: str, fixture: Path, view: dict, floor: float,
|
||||
binaries: dict[str, Path], out: Path, env: dict[str, str]) -> None:
|
||||
camera = camera_for(view, floor, name, "eye")
|
||||
baseline = None
|
||||
for compiler in ("clang", "gcc"):
|
||||
for workers in (1, 8, 12):
|
||||
tag = f"{name}-{compiler}-w{workers}"
|
||||
run_dir = out / "determinism" / tag
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
mesh, manifest, layout = (run_dir / "fixture.vfmesh",
|
||||
run_dir / "manifest.json", run_dir / "layout.json")
|
||||
output = run_step(tag, headless_command(binaries[compiler], fixture,
|
||||
camera, mesh, manifest, layout, workers, 1,
|
||||
hash_tiles=True), out / "logs" / f"determinism-{tag}.log",
|
||||
env=env, stamped=True)
|
||||
result = digest(output, manifest, layout)
|
||||
if baseline is None:
|
||||
baseline = result
|
||||
elif result != baseline:
|
||||
raise RuntimeError(f"{name} diverged at {compiler} W{workers}; see determinism logs")
|
||||
print(f"[L161Determinism] fixture={name} compiler_worker_cells=6 identical=yes status=PASS",
|
||||
flush=True)
|
||||
|
||||
|
||||
def run_walk_audit(name: str, fixture: Path, view: dict, floor: float,
|
||||
spec: Path, binary: Path, out: Path, env: dict[str, str],
|
||||
*, expected_exit: int = 0) -> str:
|
||||
camera = camera_for(view, floor, name, "eye")
|
||||
run_dir = out / "walk-audits" / name
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
manifest = run_dir / "manifest.json"
|
||||
layout = run_dir / "layout.json"
|
||||
mesh = run_dir / "audit.vfmesh"
|
||||
audit_path = run_dir / "walk.path"
|
||||
# Use a fixture-specific manifest, so the path uses the exact authored floor height.
|
||||
plan = out / "plan-probes" / name / "manifest.json"
|
||||
if not plan.is_file():
|
||||
raise RuntimeError(f"{name} has no resolved manifest for its walk audit")
|
||||
write_walk_audit(spec, plan, audit_path)
|
||||
output = run_step(f"walk-{name}", headless_command(binary, fixture, camera,
|
||||
mesh, manifest, layout, 12, 1, audit_path=audit_path),
|
||||
out / "logs" / f"walk-{name}.log", env=env, stamped=True,
|
||||
expected_exit=expected_exit)
|
||||
expected_status = "FAIL" if expected_exit else "PASS"
|
||||
if not re.search(rf"\[LiminalStampWalkAudit\].*status={expected_status}\b", output):
|
||||
raise RuntimeError(f"{name} walk audit did not report expected {expected_status}")
|
||||
return output
|
||||
|
||||
|
||||
def capture(name: str, fixture: Path, view: dict, floor: float, *, kind: str,
|
||||
binary: Path, renderer: Path, out: Path, artifact_dir: Path,
|
||||
env: dict[str, str]) -> None:
|
||||
camera = camera_for(view, floor, name, kind)
|
||||
target = target_for(view, floor, name, kind)
|
||||
clip_radius = int(view[f"{kind}_clip_radius"])
|
||||
max_level = 1 if name == "terraced-hills" and kind == "wide" else 0
|
||||
stem = f"{name}-{kind}"
|
||||
run_dir = out / "captures" / stem
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
mesh, manifest, layout = (run_dir / "capture.vfmesh",
|
||||
run_dir / "manifest.json", run_dir / "layout.json")
|
||||
png = run_dir / "capture.png"
|
||||
image = artifact_dir / f"{stem}.jpg"
|
||||
output = run_step(f"capture-export-{stem}", headless_command(binary,
|
||||
fixture, camera, mesh, manifest, layout, 12, clip_radius,
|
||||
max_level=max_level), out / "logs" / f"capture-export-{stem}.log",
|
||||
env=env, stamped=True)
|
||||
if not mesh.is_file() or mesh.stat().st_size == 0:
|
||||
raise RuntimeError(f"{stem} produced an empty mesh")
|
||||
yaw, pitch = camera_angles(camera, target)
|
||||
if name == "backrooms-grid":
|
||||
fog_start, fog_end, fog_color = 90, 500, "0.82,0.83,0.76"
|
||||
elif name == "pool-rooms":
|
||||
fog_start, fog_end, fog_color = 90, 480, "0.76,0.84,0.87"
|
||||
elif name == "staircase-to-nowhere":
|
||||
fog_start, fog_end, fog_color = 110, 700, "0.78,0.84,0.87"
|
||||
else:
|
||||
fog_start, fog_end, fog_color = 160, 1050, "0.78,0.84,0.89"
|
||||
renderer_command = [renderer, mesh, png, "--size=1600x900", "--fov-deg=72",
|
||||
f"--camera-m={fmt(camera)}", f"--yaw-deg={yaw:.6f}",
|
||||
f"--pitch-deg={pitch:.6f}", "--tile-skirts=on", "--shade=readable",
|
||||
"--headlamp=off", "--height-tint=on",
|
||||
f"--height-center-m={floor + 3.0:.6f}", "--height-range-m=30.0",
|
||||
"--light-direction=-0.42,-0.58,0.70", "--fog=on",
|
||||
f"--fog-start-m={fog_start}", f"--fog-end-m={fog_end}",
|
||||
f"--fog-color={fog_color}"]
|
||||
run_step(f"capture-render-{stem}", renderer_command,
|
||||
out / "logs" / f"capture-render-{stem}.log", env=env, stamped=True)
|
||||
run_step(f"capture-jpeg-{stem}", ["ffmpeg", "-nostdin", "-hide_banner",
|
||||
"-loglevel", "error", "-y", "-i", png, "-frames:v", "1", "-q:v", "4", image],
|
||||
out / "logs" / f"capture-jpeg-{stem}.log", env=env)
|
||||
quality = run_step(f"capture-quality-{stem}", [sys.executable,
|
||||
ROOT / "Standalone/Tools/verify/capture_quality.py", image],
|
||||
out / "logs" / f"capture-quality-{stem}.log", env=env)
|
||||
if "[CaptureQuality]" not in quality or not image.is_file() or image.stat().st_size > 300_000:
|
||||
raise RuntimeError(f"{stem} failed image quality or size checks")
|
||||
print(f"[L161Capture] fixture={name} view={kind} camera_m=({fmt(camera)}) "
|
||||
f"target_m=({fmt(target)}) bytes={image.stat().st_size} "
|
||||
f"sha256={sha256(image)} status=PASS", flush=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=OUT_DEFAULT)
|
||||
parser.add_argument("--artifact-dir", type=Path, default=CAPTURE_DEFAULT)
|
||||
parser.add_argument("--headless-clang", type=Path, required=True)
|
||||
parser.add_argument("--headless-gcc", type=Path, required=True)
|
||||
parser.add_argument("--renderer", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
out, artifact_dir = args.out.resolve(), args.artifact_dir.resolve()
|
||||
fixture_dir = out / "fixtures"
|
||||
for directory in (out, fixture_dir, artifact_dir):
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
env = os.environ.copy()
|
||||
env["VOXELFORGE_VERIFY_OUT"] = str(out)
|
||||
env["VOXELFORGE_OWNER_DATA"] = str(ROOT / "Standalone/data/owner_world.json")
|
||||
env["LP_NUM_THREADS"] = "12"
|
||||
env["XDG_CACHE_HOME"] = str(out / "xdg-cache")
|
||||
run_step("build-fixtures", [sys.executable,
|
||||
Path(__file__).resolve().parent / "BuildL161Fixtures.py",
|
||||
f"--out={fixture_dir}"], out / "logs" / "build-fixtures.log", env=env)
|
||||
|
||||
binaries = {"clang": args.headless_clang.resolve(), "gcc": args.headless_gcc.resolve()}
|
||||
fixtures = {name: fixture_dir / f"liminal-{name}.json" for name in
|
||||
("pool-rooms", "backrooms-grid", "staircase-to-nowhere", "terraced-hills")}
|
||||
views = {}
|
||||
floors = {}
|
||||
for name, fixture_path in fixtures.items():
|
||||
view = json.loads((fixture_dir / "views" / f"{name}.json").read_text(encoding="utf-8"))
|
||||
manifest_path, _, manifest, layout = build_plan(binaries["clang"], name,
|
||||
fixture_path, view, out, env)
|
||||
view["center_xy_m"] = view["center_xy_m"]
|
||||
floors[name] = manifest["recipe"]["surface_profile"]["h0_q"] / Q_PER_METRE
|
||||
if layout["stamp_vocabulary_version"] != 7 or not layout["stamps"]:
|
||||
raise RuntimeError(f"{name} plan lacks resolved vocabulary-7 stamps")
|
||||
write_walk_audit(fixture_dir / "walk-specs" / f"{name}.json",
|
||||
manifest_path, out / "walk-audits" / name / "walk.path")
|
||||
views[name] = view
|
||||
print(f"[L161Plan] fixture={name} stamps={len(layout['stamps'])} "
|
||||
f"floor_m={floors[name]:.3f} layout={layout['stable_identity']} status=PASS")
|
||||
|
||||
for name, fixture_path in fixtures.items():
|
||||
run_walk_audit(name, fixture_path, views[name], floors[name],
|
||||
fixture_dir / "walk-specs" / f"{name}.json", binaries["clang"], out, env)
|
||||
run_determinism(name, fixture_path, views[name], floors[name], binaries, out, env)
|
||||
|
||||
narrow_name = "backrooms-narrow-control"
|
||||
narrow_fixture = fixture_dir / f"liminal-{narrow_name}.json"
|
||||
narrow_view = json.loads((fixture_dir / "views" / f"{narrow_name}.json").read_text(encoding="utf-8"))
|
||||
narrow_manifest, _, narrow_manifest_value, _ = build_plan(binaries["clang"],
|
||||
narrow_name, narrow_fixture, narrow_view, out, env)
|
||||
narrow_floor = narrow_manifest_value["recipe"]["surface_profile"]["h0_q"] / Q_PER_METRE
|
||||
run_walk_audit(narrow_name, narrow_fixture, narrow_view, narrow_floor,
|
||||
fixture_dir / "walk-specs" / f"{narrow_name}.json", binaries["clang"],
|
||||
out, env, expected_exit=14)
|
||||
print("[L161DoorwayNegativeControl] width_m=1.200 minimum_m=1.500 expected=FAIL status=PASS")
|
||||
|
||||
for name, fixture_path in fixtures.items():
|
||||
for kind in ("eye", "wide"):
|
||||
capture(name, fixture_path, views[name], floors[name], kind=kind,
|
||||
binary=binaries["clang"], renderer=args.renderer.resolve(), out=out,
|
||||
artifact_dir=artifact_dir, env=env)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[L161Capture] status=FAIL error={error}", file=sys.stderr, flush=True)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,31 @@
|
||||
# L161 — More liminal looks
|
||||
|
||||
| Look | Eye height | Wide |
|
||||
|---|---|---|
|
||||
| Pool rooms |  |  |
|
||||
| Backrooms grid |  |  |
|
||||
| Staircase to nowhere |  |  |
|
||||
| Terraced hills |  |  |
|
||||
|
||||
## Result
|
||||
|
||||
Four standalone SurfaceWorld fixtures resolve from the shared stamp vocabulary. They use repeated rooms and basins, a doorway grid, a freestanding stair and arch, and nine stepped ridges. This round authored no inter-strate passages or owner content.
|
||||
|
||||
## Changes
|
||||
|
||||
- Stamp vocabulary v7 adds `fillBox`, `carveBox`, and `fillSteps`; the existing `carveArch` is reused. The new kinds are opt-in.
|
||||
- Added a flat-field liminal stamp-fixture override and a capsule walk audit with doorway-width gates. The audit checks support, collision, grade, and authored opening widths.
|
||||
- Fixtures contain 275 pool-room stamps, 129 backrooms stamps, 4 staircase/arch stamps, and 18 terrace stamps.
|
||||
|
||||
## Verification
|
||||
|
||||
- Clang 19 and GCC 14 builds passed with FP contraction off. Both binaries carry source stamp `8e9e114c1357`.
|
||||
- Each fixture matched across Clang/GCC at W1, W8, and W12: manifest, resolved-layout identity, and tile hashes were identical in all six cells.
|
||||
- Positive capsule audits passed. Pool doorways measured 7.2 m, backrooms doorways 4.0 m, and the arch opening 10.0 m. The narrow 1.2 m backrooms control failed the 1.5 m minimum as expected. The terrace walk had zero blocked samples, unsupported samples, or grade failures.
|
||||
- All eight 1600×900 captures passed image quality checks; files are 25.3–58.4 KB. Capture and audit logs are under `Saved/Linux/l161/logs/`.
|
||||
- Fast tier passed: 273 checks in 346.6 s. Both owner generators matched their pinned L130/v227 canonical baselines exactly (12/12 rows), and W1/W12 signatures matched. Summary: `Saved/Linux/l161/fast-tier/fast-summary.json`.
|
||||
- `git diff --check` passed. No Unreal `Source/` files changed; no Unreal build or medium/full verification tier was run.
|
||||
|
||||
## Remaining risk
|
||||
|
||||
The captures show untextured geometry with simple fog. The terraced wide capture uses clip radius 3 and max LOD 1 to stay within the standalone shape-build bound, so the long-range horizon read still needs an art review.
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 57 KiB |
@@ -0,0 +1,36 @@
|
||||
# VoxelForge — research R48 (read-only): who owns the tunnel mouth?
|
||||
|
||||
You are a researcher. **Read only:** don't edit, create or delete any file, and don't build, run or test anything.
|
||||
Read code, reports and design docs. Be thorough, verify by hand, and mark each claim [CODE] file:line, [MEASURED]
|
||||
report, or [INFERENCE]. This checkout (`Saved/Linux/r48-tree`) is branch `wip/l134-cave-planner` at `4f93f3f`.
|
||||
|
||||
## The problem
|
||||
|
||||
Inter-strate passages (tunnels between layers) are planned first, and each layer's content is planned afterwards
|
||||
around their fixed mouths and tubes.
|
||||
- **Tunnel Network** (L134–L138) works, because caves are carved into rock and can bend to the mouths.
|
||||
- **Vertical Shafts** (L139): 15/16 seeds pass; seed 2 fails the shell and seams at the arrival mouth. Three local
|
||||
geometry fixes failed.
|
||||
- **Floating Islands** (L133 twice, then L140): 0/16 seeds pass.
|
||||
- In 14 of 16 seeds, no island arrangement clears the fixed tubes and reaches both mouth heights.
|
||||
- One seed has a composed collision.
|
||||
- Wall ripple is 6–7 cm against the 3.5 cm limit on the passages.
|
||||
|
||||
Read the L133, L139 and L140 reports and patches in `Standalone/Research/WorldAssemblerM3/`.
|
||||
|
||||
## Questions
|
||||
|
||||
1. Where and in what order are passages and layer contents planned (adapter, `ResolvedLayoutInternal.h`, the
|
||||
passage planner, the island and cave planners)? What does each stage fix that later stages must obey?
|
||||
2. Which designs would make mouths solvable by construction for every layer type? For example:
|
||||
- **content first:** the layer plans its landing spots, and passages are routed to target them;
|
||||
- **negotiated:** passages reserve a mouth landing region, and every layer planner must provide support there,
|
||||
a "landing pad" contract;
|
||||
- **a joint plan:** a corridor and the island anchors are solved together.
|
||||
For each: what changes, the risks (determinism, the existing audits, the passage smoothness/ripple work), and the
|
||||
size.
|
||||
3. Why does ripple fail at 6–7 cm on the upper passages with native islands (and in L67)? Is it the passage, or the
|
||||
host field under it?
|
||||
4. Recommend one design, with steps and the evidence that would prove or kill it.
|
||||
|
||||
Write plain Markdown, ≤ ~1,200 words.
|
||||
@@ -0,0 +1,43 @@
|
||||
# R48 read only — who owns the tunnel mouth?
|
||||
|
||||
**The passage planner currently chooses the mouth.** Floating Islands then has to fit its islands and walk route around fixed tubes; caves can instead carve toward them. L140’s fixed tube layout left no valid island plan for most seeds. [CODE] `Standalone/Core/src/ResolvedLayoutInternal.h:3699–3792`; [MEASURED] `Standalone/Research/WorldAssemblerM3/Linux140/REPORT.md:15–19`
|
||||
|
||||
## 1. Planning order and constraints
|
||||
|
||||
There are two adapter paths, so there isn’t one universal order today:
|
||||
|
||||
- The geometry only adapter builds strata and passage configs, plans passages, then resolves authored Core geometry. [CODE] `Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:1455–1585`
|
||||
- The validated assembly path can build a manifest, including an imported Floating Islands plan, before creating the resolved layout. It copies plan anchors into that layout, then calls the passage planner. [CODE] `Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:1621–1685, 1950–2019, 2021–2041`
|
||||
- L140’s kept patch changes the Floating Islands path: first resolve the fixed passage layout, then plan islands around those passages and export the resulting anchors. The patch is not applied in the R48 source: the current adapter still calls `PlanFloatingIslandCluster` without a resolved layout. [CODE] `Standalone/Research/WorldAssemblerM3/Linux140/l140-fi-around-tunnels.patch:102–219`; `Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:893–987`
|
||||
|
||||
`PlanResolvedLayoutPassagesV1` sorts the strata, uses existing route anchors where present, otherwise chooses seeded mouths, and builds passage control points with radii. Once resolved, those mouths and tubes are inputs to later planners. [CODE] `Standalone/Core/src/ResolvedLayoutInternal.h:3699–3792, 3820–3874, 4713–4819`
|
||||
|
||||
The generic island planner lays out seeded island centers and a route without seeing the passage layout. L133’s alternate planner bound endpoints, but did not plan against both full passage volumes. Its composed walk still had collisions and unsupported route points. [CODE] `Standalone/Core/src/FloatingIslandsInternal.h:1991–2050, 2166–2233`; historical patch `Linux133/l133-native-fi-v9.patch` in Git commit `f8cba7c:79–134`; [MEASURED] `Linux133/REPORT.md` in that commit:3–7
|
||||
|
||||
The cavern planner reads incoming and outgoing passages and requires them to exist, except for a Vertical Shafts basal terminal. Caves can carve through host rock to reach those mouths; L134’s default composed route passed, while L139 still failed the shell and seam checks at seed 2’s incoming mouth after three local geometry attempts. [CODE] `Standalone/Core/src/ResolvedLayoutInternal.h:2344–2359`; [MEASURED] `Linux134/REPORT.md:3–7`; `Linux139/REPORT.md:5–8, 43–52, 89–91`
|
||||
|
||||
## 2. Design choices
|
||||
|
||||
- **Content first:** each layer produces supported landing candidates and a connected approach; the passage planner chooses compatible candidates and routes to them. This can solve the fixed-height problem by letting the tunnel target viable terrain. It requires every layer type to provide reliable candidates, stable ordering and tie breaks, and passage rerouting; changed routes must still pass the existing grade, shell, seam, and ripple audits. **Size: medium to large.** [INFERENCE]
|
||||
|
||||
- **Negotiated landing pad:** the passage reserves a landing region and the layer guarantees support there. A point or pad contract alone is too weak: L140 checked five support probes, yet 14 seeds had no arrangement clearing the fixed tubes or could not reach both mouth heights. A useful contract must cover the capsule approach and passage exclusion envelope too. That grows toward a joint plan. **Size: medium for a pad; large for a full approach and clearance contract.** [MEASURED] `Linux140/REPORT.md:7, 15–17`; [INFERENCE]
|
||||
|
||||
- **Joint plan:** choose passage geometry and layer anchors together. This gives the solver room to avoid the fixed-tube infeasibility seen in L140, but costs the most: bounded deterministic search, new planner interfaces, and careful preservation of passage smoothness and audit behavior. A bounded search only guarantees feasibility within its candidate space. **Size: large.** [MEASURED] `Linux140/REPORT.md:17`; [INFERENCE]
|
||||
|
||||
## 3. Why ripple reaches 6–7 cm
|
||||
|
||||
The ripple audit samples the **composed field** passed as `Shape`, at `pose.radius − 0.18 m`, then estimates wall radius as that sample radius plus the average signed density. It cubic-detrends each 32 m window, preserving authored radius variation. Thus the result includes both the passage’s radius profile and any host-field effect on the sampled wall; it is not a passage-only measurement. [CODE] `Standalone/Source/StreamBenchmarkPipeline.h:4186–4239, 4414–4432, 4941–4944`
|
||||
|
||||
L67 traced a prior gauge error: omitting `pose.radius` hid an authored-radius beat. The corrected gauge found a 4.77 cm beat at 7.06 m and measured 7.27 cm on passage 1–2. L140 measured 6.22–7.19 cm on its upper passages with native islands. [MEASURED] `Linux67/REPORT.md:64–79`; `Linux140/REPORT.md:15–19`
|
||||
|
||||
The evidence shows that passage-radius variation alone is enough to explain a failure at this scale; it does not isolate how much native island density adds or masks. L140’s shell-preserving composition change still failed the unchanged ripple gate. [INFERENCE] `Linux140/l140-fi-around-tunnels.patch:912–924`; [MEASURED] `Linux140/REPORT.md:15–19`
|
||||
|
||||
## 4. Recommendation
|
||||
|
||||
**Use a bounded pairwise joint plan.** Have each layer planner publish certified landing candidates with capsule support and approach constraints. Let the passage planner choose compatible ports and route geometry together, then check the complete tube and composed layer before finalizing the resolved layout. Start with Floating Islands; preserve cave planners’ ability to carve to selected ports. [INFERENCE]
|
||||
|
||||
Keep candidate generation and tie breaking seed-stable, and finalize the layout identity only after the selected mouths, tubes, and content anchors are known. Keep the existing thresholds unchanged. [CODE] `Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:2021–2041`; [INFERENCE]
|
||||
|
||||
The design passes if all 16 seeds clear the existing route, support, shell, seam, grade, mouth-profile, and 3.5 cm ripple gates, with matching Clang/GCC W1/W8/W12 hashes. Separately compare ripple on the same tube in a smooth host field and in the composed field; that isolates passage-profile ripple from host-field contribution. Kill the design if joint movement still leaves seeds infeasible, or if the passage-only profile fails ripple. [INFERENCE]
|
||||
|
||||
L133’s report and patch were absent from the R48 working tree; I read them from Git commit `f8cba7c`. No files were changed, and I did not build or run tests. [MEASURED]
|
||||