tools(verify): fast/medium/full verification tiers with a compiled-in source stamp (L39); research R6

BuildLinux.sh hashes a sorted manifest of compiled inputs into VOXELFORGE_SOURCE_STAMP, printed first by
every executable; Standalone/Tools/verify/verify.py checks it before and after each tier and records
binary/input hashes and the resolved recipe, style map and layout. Fast (163 s) runs on the canonical owner
world only and asserts FI Style 2 / SW Style 1; medium (8 min) and full (26 min) add the style matrix,
GCC, determinism and cost. Controls: stale source, mislabelled style-0 owner, all-black capture, L30/L31,
L35/L36 and the L38 step are all rejected. No geometry change; owner hashes identical to L37.
Research R6: leak table, generator contract and a 10-step metre-native migration plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-23 15:27:52 +02:00
1 parent 88c54eab44
commit 753cc9c259
22 files changed
+1816 -148

No files matched your search

+19
View File
@@ -7,6 +7,8 @@ fi
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$SCRIPT_DIR" ROOT="$SCRIPT_DIR"
PROJECT_ROOT="$(cd -- "$ROOT/.." && pwd)"
VERIFY_DIR="$ROOT/Tools/verify"
COMPILER="clang++-19" COMPILER="clang++-19"
VARIANT="clang19" VARIANT="clang19"
FP_CONTRACT="off" FP_CONTRACT="off"
@@ -41,6 +43,15 @@ BIN_DIR="${VOXELFORGE_BIN_DIR:-$ROOT/bin/linux}"
BUILD_DIR="$BUILD_ROOT/linux-$VARIANT" BUILD_DIR="$BUILD_ROOT/linux-$VARIANT"
mkdir -p "$BUILD_DIR/wrappers" "$BUILD_DIR/objects" "$BIN_DIR" mkdir -p "$BUILD_DIR/wrappers" "$BUILD_DIR/objects" "$BIN_DIR"
STAMP_HELPER="$VERIFY_DIR/source_stamp.py"
STAMP_ARGS=()
if [[ "${VOXELFORGE_INCLUDE_UNREAL_ADAPTER:-0}" == "1" ]]; then
STAMP_ARGS+=(--include-unreal-adapter)
fi
SOURCE_STAMP="$(python3 -B "$STAMP_HELPER" stamp --root "$PROJECT_ROOT" "${STAMP_ARGS[@]}")"
python3 -B "$STAMP_HELPER" write-manifest --root "$PROJECT_ROOT" --output "$BUILD_DIR/source-manifest.txt" "${STAMP_ARGS[@]}" >/dev/null
printf 'Source stamp: %s\n' "$SOURCE_STAMP"
INCLUDES=( INCLUDES=(
"-I$ROOT/Core/include" "-I$ROOT/Core/include"
"-I$ROOT/Core/src" "-I$ROOT/Core/src"
@@ -52,6 +63,7 @@ INCLUDES=(
FLAGS=( FLAGS=(
-std=c++20 -O2 -mavx2 -mfma -fno-fast-math -std=c++20 -O2 -mavx2 -mfma -fno-fast-math
-fexceptions -pthread "${INCLUDES[@]}" -fexceptions -pthread "${INCLUDES[@]}"
"-DVOXELFORGE_SOURCE_STAMP=\"$SOURCE_STAMP\""
) )
if [[ "$FP_CONTRACT" != "default" ]]; then if [[ "$FP_CONTRACT" != "default" ]]; then
FLAGS+=("-ffp-contract=$FP_CONTRACT") FLAGS+=("-ffp-contract=$FP_CONTRACT")
@@ -122,8 +134,15 @@ OUTPUT="$BIN_DIR/VoxelForgeCoreHeadless-$VARIANT"
"$COMPILER" -pthread "${LEGACY_OBJECTS[@]}" "$CORE_LIBRARY" -o "$OUTPUT" "$COMPILER" -pthread "${LEGACY_OBJECTS[@]}" "$CORE_LIBRARY" -o "$OUTPUT"
CAPTURE_OUTPUT="$BIN_DIR/VoxelForgeOffscreenCapture-$VARIANT" CAPTURE_OUTPUT="$BIN_DIR/VoxelForgeOffscreenCapture-$VARIANT"
"$COMPILER" -std=c++20 -O2 -fno-fast-math -pthread \ "$COMPILER" -std=c++20 -O2 -fno-fast-math -pthread \
"-DVOXELFORGE_SOURCE_STAMP=\"$SOURCE_STAMP\"" -I"$ROOT/Source" \
"$ROOT/Source/LinuxOffscreenCapture.cpp" -o "$CAPTURE_OUTPUT" \ "$ROOT/Source/LinuxOffscreenCapture.cpp" -o "$CAPTURE_OUTPUT" \
$(pkg-config --cflags --libs egl glesv2 libpng) $(pkg-config --cflags --libs egl glesv2 libpng)
POST_BUILD_STAMP="$(python3 -B "$STAMP_HELPER" stamp --root "$PROJECT_ROOT" "${STAMP_ARGS[@]}")"
if [[ "$POST_BUILD_STAMP" != "$SOURCE_STAMP" ]]; then
printf 'Source changed during build: before=%s after=%s\n' "$SOURCE_STAMP" "$POST_BUILD_STAMP" >&2
exit 1
fi
printf 'Built Core library: %s\nBuilt headless benchmark: %s\n' "$CORE_LIBRARY" "$OUTPUT" printf 'Built Core library: %s\nBuilt headless benchmark: %s\n' "$CORE_LIBRARY" "$OUTPUT"
printf 'Built EGL offscreen capture: %s\n' "$CAPTURE_OUTPUT" printf 'Built EGL offscreen capture: %s\n' "$CAPTURE_OUTPUT"
printf 'Compiler: %s | variant: %s | fp-contract: %s | jobs: %s\n' "$COMPILER" "$VARIANT" "$FP_CONTRACT" "$JOBS" printf 'Compiler: %s | variant: %s | fp-contract: %s | jobs: %s\n' "$COMPILER" "$VARIANT" "$FP_CONTRACT" "$JOBS"
@@ -30,8 +30,9 @@ DELTA_GRID_M = 0.125
SCENES = { SCENES = {
"owner-fi": ("owner-fi-ground-mouth.vfmesh", "layout-owner-fi.json", "FloatingIslands", "upper"), "owner-fi": ("owner-fi-ground-mouth.vfmesh", "layout-owner-fi.json", "FloatingIslands", "upper"),
"owner-sw": ("owner-sw-ground-mouth.vfmesh", "layout-owner-sw.json", "SurfaceWorld", "lower"), "owner-sw": ("owner-sw-ground-mouth.vfmesh", "layout-owner-sw.json", "SurfaceWorld", "lower"),
"upper-sw-fixture": ("upper-sw-fixture-ground-mouth.vfmesh", "style-override-upper-sw-fixture-style0": (
"layout-upper-sw-fixture.json", "SurfaceWorld", "upper"), "style-override-upper-sw-fixture-style0-ground-mouth.vfmesh",
"layout-style-override-upper-sw-fixture-style0.json", "SurfaceWorld", "upper"),
} }
@@ -456,6 +457,9 @@ def audit_scene(scene, out, baseline_out, mesh_override=None):
crop_to_center=False) crop_to_center=False)
full_surface = analyze_triangles(corridor, mouth[:2], mouth[2], full_surface = analyze_triangles(corridor, mouth[:2], mouth[2],
crop_to_center=False, include_sides=True) crop_to_center=False, include_sides=True)
proxy_alert = fail(differential, include_planarity=False)
corner_gate = (metrics["corners"] == 0 and full_surface["corners"] == 0
and differential["corners"] == 0)
metrics["all_face_planar_area"] = full_surface["planar_area"] metrics["all_face_planar_area"] = full_surface["planar_area"]
metrics["all_face_straight"] = full_surface["straight"] metrics["all_face_straight"] = full_surface["straight"]
metrics["all_face_corners"] = full_surface["corners"] metrics["all_face_corners"] = full_surface["corners"]
@@ -484,10 +488,13 @@ def audit_scene(scene, out, baseline_out, mesh_override=None):
f"patch_bounds={metrics['bounds']} plane_normal={metrics['normal']} " f"patch_bounds={metrics['bounds']} plane_normal={metrics['normal']} "
f"limits=(plane<{PLANE_LIMIT_M2:.2f}m2 informational,line<={STRAIGHT_LIMIT_M:.2f}m," f"limits=(plane<{PLANE_LIMIT_M2:.2f}m2 informational,line<={STRAIGHT_LIMIT_M:.2f}m,"
f"corner_turn<{CORNER_TURN_LIMIT_DEG:.0f}deg) " f"corner_turn<{CORNER_TURN_LIMIT_DEG:.0f}deg) "
f"straight_or_planar_proxy={'ALERT' if proxy_alert else 'PASS'} "
f"delta_threshold_m={DELTA_THRESHOLD_M:.2f} status=" f"delta_threshold_m={DELTA_THRESHOLD_M:.2f} status="
f"{'FAIL' if fail(differential, include_planarity=False) else 'PASS'}") f"{'PASS' if corner_gate else 'FAIL'}")
metrics["differential"] = differential metrics["differential"] = differential
metrics["matched_no_support"] = baseline_metrics metrics["matched_no_support"] = baseline_metrics
metrics["corner_gate"] = corner_gate
metrics["proxy_alert"] = proxy_alert
return metrics return metrics
@@ -519,13 +526,14 @@ def main():
f"{control['planar_area']:.4f} straight_run_m={control['straight']:.4f} " f"{control['planar_area']:.4f} straight_run_m={control['straight']:.4f} "
f"sharp_corners={control['corners']} detected={control_ok} " f"sharp_corners={control['corners']} detected={control_ok} "
f"negative_control={'PASS' if control_ok else 'FAIL'}") f"negative_control={'PASS' if control_ok else 'FAIL'}")
candidates_pass = all(not fail(metrics["differential"], include_planarity=False) candidates_pass = all(metrics["corner_gate"] for metrics in measured.values())
for metrics in measured.values())
passed = control_ok and l36_failed and candidates_pass passed = control_ok and l36_failed and candidates_pass
print(f"[MouthBuiltShapeSummary] scenes={len(measured)} candidates_pass=" print(f"[MouthBuiltShapeSummary] scenes={len(measured)} candidates_pass="
f"{sum(not fail(metrics['differential']) for metrics in measured.values())}/{len(measured)} " f"{sum(metrics['corner_gate'] for metrics in measured.values())}/{len(measured)} "
f"L36_control_fail={'PASS' if l36_failed else 'FAIL'} " f"L36_control_fail={'PASS' if l36_failed else 'FAIL'} "
f"box_control_fail={'PASS' if control_ok else 'FAIL'} " f"box_control_fail={'PASS' if control_ok else 'FAIL'} "
f"corner_gate={'PASS' if candidates_pass else 'FAIL'} "
f"straight_or_planar_proxy_alerts={sum(metrics['proxy_alert'] for metrics in measured.values())} "
f"planar_gate=informational_owner_accepted " f"planar_gate=informational_owner_accepted "
f"status={'PASS' if passed else 'FAIL'}") f"status={'PASS' if passed else 'FAIL'}")
raise SystemExit(0 if passed else 1) raise SystemExit(0 if passed else 1)
@@ -3,13 +3,15 @@
import math import math
import os import os
import subprocess import subprocess
import sys
import time import time
from pathlib import Path from pathlib import Path
ROOT = Path(__file__).resolve().parents[4] ROOT = Path(__file__).resolve().parents[4]
OUT = Path(os.environ.get("VOXELFORGE_L37_OUT", ROOT / "Saved/Linux/l37")) OUT = Path(os.environ.get("VOXELFORGE_L37_OUT",
os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l37")))
CAPTURES = Path(os.environ.get("VOXELFORGE_L37_CAPTURE_DIR", CAPTURES = Path(os.environ.get("VOXELFORGE_L37_CAPTURE_DIR",
Path(__file__).resolve().parent / "captures")) OUT / "captures"))
MESH = Path(os.environ.get("VOXELFORGE_L37_MESH", MESH = Path(os.environ.get("VOXELFORGE_L37_MESH",
OUT / "owner-fi-ground-mouth.vfmesh")) OUT / "owner-fi-ground-mouth.vfmesh"))
RENDERER = Path(os.environ.get("VOXELFORGE_L37_RENDERER", RENDERER = Path(os.environ.get("VOXELFORGE_L37_RENDERER",
@@ -20,6 +22,8 @@ MOUTH = (5.600, 0.445, -55.156)
CAMERA = (MOUTH[0] - 9.75, MOUTH[1] - 11.4, MOUTH[2] + 8.0) CAMERA = (MOUTH[0] - 9.75, MOUTH[1] - 11.4, MOUTH[2] + 8.0)
TARGET = (6.298233, 1.137233, -55.468264) TARGET = (6.298233, 1.137233, -55.468264)
FOV = 80.0 FOV = 80.0
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
from runner import current_stamp, first_stamp, bounded_run
def normalize(vector): def normalize(vector):
@@ -42,6 +46,11 @@ def run(name, command):
log = OUT / f"capture-overview-{name}.log" log = OUT / f"capture-overview-{name}.log"
wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
"timeout", "1800s", *map(str, command)] "timeout", "1800s", *map(str, command)]
expected = current_stamp() if Path(command[0]) == RENDERER else None
if expected is not None:
probe = bounded_run([str(RENDERER), "--print-source-stamp"], timeout=15)
if probe is None or probe.returncode != 0 or first_stamp(probe.stdout or "") != expected:
raise SystemExit(f"{name} refused an unstamped or stale renderer: {RENDERER}")
started = time.monotonic() started = time.monotonic()
with log.open("w", encoding="utf-8") as stream: with log.open("w", encoding="utf-8") as stream:
result = subprocess.run(wrapped, cwd=ROOT, stdout=stream, result = subprocess.run(wrapped, cwd=ROOT, stdout=stream,
@@ -49,6 +58,10 @@ def run(name, command):
elapsed = time.monotonic() - started elapsed = time.monotonic() - started
print(f"[L37OverviewCaptureRun] step={name} elapsed={elapsed:.1f}s " print(f"[L37OverviewCaptureRun] step={name} elapsed={elapsed:.1f}s "
f"exit={result.returncode} log={log}", flush=True) f"exit={result.returncode} log={log}", flush=True)
if expected is not None:
output = log.read_text(encoding="utf-8", errors="replace")
if first_stamp(output) != expected or current_stamp() != expected:
raise SystemExit(f"{name} source stamp mismatch; see {log}")
if result.returncode != 0: if result.returncode != 0:
raise SystemExit(f"{name} failed; see {log}") raise SystemExit(f"{name} failed; see {log}")
@@ -67,6 +80,7 @@ def main():
"--tile-edges=off", f"--focus-region={fmt((*MOUTH, 20.0))}"]) "--tile-edges=off", f"--focus-region={fmt((*MOUTH, 20.0))}"])
run("jpeg", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error", run("jpeg", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error",
"-y", "-i", PNG, "-frames:v", "1", "-q:v", "4", JPEG]) "-y", "-i", PNG, "-frames:v", "1", "-q:v", "4", JPEG])
run("quality", [sys.executable, ROOT / "Standalone/Tools/verify/capture_quality.py", JPEG])
size = JPEG.stat().st_size if JPEG.exists() else 0 size = JPEG.stat().st_size if JPEG.exists() else 0
distance = math.dist(CAMERA, MOUTH) distance = math.dist(CAMERA, MOUTH)
print(f"[L37OverviewCapture] file={JPEG.relative_to(ROOT)} camera_to_mouth_m=" print(f"[L37OverviewCapture] file={JPEG.relative_to(ROOT)} camera_to_mouth_m="
@@ -7,26 +7,29 @@ import math
import os import os
import re import re
import subprocess import subprocess
import sys
import time import time
from pathlib import Path from pathlib import Path
ROOT = Path(__file__).resolve().parents[4] ROOT = Path(__file__).resolve().parents[4]
OUT = Path(os.environ.get("VOXELFORGE_L37_OUT", ROOT / "Saved/Linux/l37")) OUT = Path(os.environ.get("VOXELFORGE_L37_OUT",
os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l37")))
BIN = OUT / "bin" BIN = OUT / "bin"
CAPTURES = Path(os.environ.get("VOXELFORGE_L37_CAPTURE_DIR", CAPTURES = Path(os.environ.get("VOXELFORGE_L37_CAPTURE_DIR",
Path(__file__).resolve().parent / "captures")) OUT / "captures"))
HEADLESS = Path(os.environ.get("VOXELFORGE_L37_HEADLESS", HEADLESS = Path(os.environ.get("VOXELFORGE_L37_HEADLESS",
BIN / "VoxelForgeCoreHeadless-l37-final-clang")) BIN / "VoxelForgeCoreHeadless-l37-final-clang"))
RENDERER = Path(os.environ.get("VOXELFORGE_L37_RENDERER", RENDERER = Path(os.environ.get("VOXELFORGE_L37_RENDERER",
BIN / "VoxelForgeOffscreenCapture-l37-final-clang")) BIN / "VoxelForgeOffscreenCapture-l37-final-clang"))
PNG_DIR = OUT / "capture-png" PNG_DIR = OUT / "capture-png"
RECIPE_INPUTS = ( RECIPE_INPUTS = (
("owner-fi", ROOT / "Saved/Linux/linux25-owner-floating-islands-style0.json", ("owner-fi", ROOT / "Standalone/data/owner_world.json",
"floating-islands", "FloatingIslands", "upper"), "floating-islands", "FloatingIslands", "upper"),
("owner-sw", ROOT / "Saved/Linux/linux25-owner-surface-world-style0.json", ("owner-sw", ROOT / "Standalone/data/owner_world.json",
"surface-world", "SurfaceWorld", "lower"), "surface-world", "SurfaceWorld", "lower"),
("upper-sw-fixture", ROOT / "Saved/Linux/l33/fixtures/sw-upper-tunnel-network-style0.json", ("style-override-upper-sw-fixture-style0",
OUT / "fixtures/style-override-upper-sw-fixture-style0.json",
"floating-islands", "SurfaceWorld", "upper"), "floating-islands", "SurfaceWorld", "upper"),
) )
SUBVOXELS_PER_VOXEL = 256.0 SUBVOXELS_PER_VOXEL = 256.0
@@ -34,6 +37,8 @@ RING_AUDIT = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerra
spec = importlib.util.spec_from_file_location("ring_profile_l32", RING_AUDIT) spec = importlib.util.spec_from_file_location("ring_profile_l32", RING_AUDIT)
ring_profile = importlib.util.module_from_spec(spec) ring_profile = importlib.util.module_from_spec(spec)
spec.loader.exec_module(ring_profile) spec.loader.exec_module(ring_profile)
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
from runner import current_stamp, first_stamp, bounded_run
for directory in (OUT, BIN, PNG_DIR, CAPTURES): for directory in (OUT, BIN, PNG_DIR, CAPTURES):
directory.mkdir(parents=True, exist_ok=True) directory.mkdir(parents=True, exist_ok=True)
@@ -51,12 +56,23 @@ def run(name, command):
wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
"timeout", "1800s", *map(str, command)] "timeout", "1800s", *map(str, command)]
started = time.monotonic() started = time.monotonic()
binary = Path(command[0]) if command else None
is_stamped_executable = binary in (HEADLESS, RENDERER)
expected = current_stamp() if is_stamped_executable else None
if is_stamped_executable:
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:
raise SystemExit(f"{name} refused an unstamped or stale executable: {binary}")
with log.open("w", encoding="utf-8") as stream: with log.open("w", encoding="utf-8") as stream:
result = subprocess.run(wrapped, cwd=ROOT, env=ENV, stdout=stream, result = subprocess.run(wrapped, cwd=ROOT, env=ENV, stdout=stream,
stderr=subprocess.STDOUT, timeout=1800, check=False) stderr=subprocess.STDOUT, timeout=1800, check=False)
elapsed = time.monotonic() - started elapsed = time.monotonic() - started
print(f"[L37CaptureRun] step={name} elapsed={elapsed:.1f}s exit={result.returncode} log={log}", print(f"[L37CaptureRun] step={name} elapsed={elapsed:.1f}s exit={result.returncode} log={log}",
flush=True) flush=True)
if is_stamped_executable:
output = log.read_text(encoding="utf-8", errors="replace")
if first_stamp(output) != expected or current_stamp() != expected:
raise SystemExit(f"{name} source stamp mismatch; see {log}")
if result.returncode != 0: if result.returncode != 0:
raise SystemExit(f"{name} failed; see {log}") raise SystemExit(f"{name} failed; see {log}")
return log return log
@@ -163,7 +179,32 @@ def load_layout(name, source, recipe):
"--stream-benchmark", "--stream-pipeline", "--force-generate", "--clip-radius=2", "--stream-benchmark", "--stream-pipeline", "--force-generate", "--clip-radius=2",
"--max-clip-level=0", "--max-level=0", f"--recipe={recipe}", "--max-clip-level=0", "--max-level=0", f"--recipe={recipe}",
f"--resolved-layout-output={path}", "--resolved-layout-only"]) f"--resolved-layout-output={path}", "--resolved-layout-only"])
return json.loads(path.read_text(encoding="utf-8")) layout = json.loads(path.read_text(encoding="utf-8"))
passage_styles = sorted({int(passage["style"]) for passage in layout.get("passages", [])})
resolved_styles = {str(index): int(style) for index, style in
layout.get("resolved_strate_passage_styles", {}).items()}
if name.startswith("owner-"):
expected_styles = {"0": 2, "1": 1}
if resolved_styles != expected_styles or passage_styles != [2]:
raise SystemExit(f"{name} resolved styles={resolved_styles} passage_styles={passage_styles}; "
f"expected strata={expected_styles} passage_styles=[2]")
expected_style = 2 if name == "owner-fi" else 1
print(f"[L37CaptureResolvedOwner] scene={name} recipe={recipe} "
f"generator_style={expected_style} strata_styles={resolved_styles} "
f"passage_style={passage_styles} layout_id={layout.get('stable_identity')} input={source}",
flush=True)
return layout
expected_style = 0
matching_styles = sorted({resolved_styles[str(stratum["strate_index"])]
for stratum in layout.get("strates", [])
if stratum.get("generator_kind") == "SurfaceWorld"
and str(stratum["strate_index"]) in resolved_styles})
if expected_style not in passage_styles or matching_styles != [expected_style]:
raise SystemExit(f"{name} resolved style={matching_styles} passage styles={passage_styles}; "
f"expected [{expected_style}]")
print(f"[L37CaptureResolvedOwner] scene={name} recipe={recipe} style={matching_styles} "
f"layout_id={layout.get('stable_identity')} input={source}", flush=True)
return layout
def select_passage(layout, mouth_generator, preferred_side): def select_passage(layout, mouth_generator, preferred_side):
@@ -327,7 +368,8 @@ for scene_name, source, recipe, mouth_generator, preferred_side in RECIPE_INPUTS
jpg = CAPTURES / f"{stem}.jpg" jpg = CAPTURES / f"{stem}.jpg"
yaw, pitch = view["yaw"], view["pitch"] yaw, pitch = view["yaw"], view["pitch"]
camera = view["camera"] camera = view["camera"]
reference_camera = REFERENCE_CAMERAS.get(stem) reference_camera = (REFERENCE_CAMERAS.get(stem)
if scene_name.startswith("style-override-") else None)
if reference_camera is not None: if reference_camera is not None:
camera, target, reference_clip = reference_camera camera, target, reference_clip = reference_camera
view["camera"], view["target"], view["clip"] = camera, target, reference_clip view["camera"], view["target"], view["clip"] = camera, target, reference_clip
@@ -397,6 +439,8 @@ for scene_name, source, recipe, mouth_generator, preferred_side in RECIPE_INPUTS
run(f"{stem}-render", render) run(f"{stem}-render", render)
run(f"{stem}-jpeg", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error", run(f"{stem}-jpeg", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error",
"-y", "-i", png, "-frames:v", "1", "-q:v", "4", jpg]) "-y", "-i", png, "-frames:v", "1", "-q:v", "4", jpg])
run(f"{stem}-quality", [sys.executable,
ROOT / "Standalone/Tools/verify/capture_quality.py", jpg])
size = jpg.stat().st_size if jpg.exists() else 0 size = jpg.stat().st_size if jpg.exists() else 0
print(f"[L37CaptureJPEG] file={jpg.relative_to(ROOT)} bytes={size} " print(f"[L37CaptureJPEG] file={jpg.relative_to(ROOT)} bytes={size} "
f"status={'PASS' if 0 < size <= 300_000 else 'FAIL'}", flush=True) f"status={'PASS' if 0 < size <= 300_000 else 'FAIL'}", flush=True)
@@ -1,69 +0,0 @@
#!/usr/bin/env python3
"""Run the L13 route parity and L9 uniform-block proof audits on L37."""
import re
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l37"
BINARIES = {
"clang": OUT / "bin/VoxelForgeCoreHeadless-l37-final-clang",
"gcc": OUT / "bin/VoxelForgeCoreHeadless-l37-final-gcc",
}
RECIPES = ("floating-islands", "surface-world")
rows = []
failed = False
for recipe in RECIPES:
for compiler, binary in BINARIES.items():
name = f"legacy-route-proof-{recipe}-{compiler}"
logfile = OUT / f"{name}.log"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
"timeout", "900s", str(binary), str(ROOT / "Standalone/data/owner_world.json"),
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--stream-hash", "--force-generate", "--clip-radius=3",
"--max-clip-level=8", "--max-level=-1",
f"--recipe={recipe}", "--audit-uniform-block-proofs", "--audit-route-parity",
]
started = time.monotonic()
try:
with logfile.open("w", encoding="utf-8") as stream:
result = subprocess.run(command, cwd=ROOT, stdout=stream,
stderr=subprocess.STDOUT, timeout=900, check=False)
except subprocess.TimeoutExpired:
result = None
elapsed = time.monotonic() - started
output = logfile.read_text(encoding="utf-8", errors="replace")
stamp = re.findall(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
output, re.M)
route = re.findall(r"^\[RouteParityAudit\].*$", output, re.M)
proofs = re.findall(r"^\[UniformBlockProofAudit\].*$", output, re.M)
stamp_ok = stamp == [(recipe, recipe, "PASS")]
route_ok = len(route) == 1 and route[0].endswith("status=PASS")
proof_ok = len(proofs) == 1 and bool(
re.search(r"violations=0(?:\s|$)", proofs[0]))
ok = (result is not None and result.returncode == 0 and stamp_ok
and route_ok and proof_ok)
code = result.returncode if result is not None else "TIMEOUT"
rows.append((name, recipe, compiler, elapsed, code, route_ok, bool(proof_ok), ok))
failed |= not ok
print(f"[L37LegacyAuditRun] case={name} elapsed={elapsed:.1f}s exit={code} "
f"recipe_stamp={'PASS' if stamp_ok else 'FAIL'} "
f"L13={'PASS' if route_ok else 'FAIL'} L9={'PASS' if proof_ok else 'FAIL'} "
f"{'PASS' if ok else 'FAIL'}", flush=True)
summary = OUT / "legacy-audits.csv"
summary.write_text(
"case,recipe,compiler,elapsed_seconds,exit_code,l13,l9,status\n" +
"".join(f"{name},{recipe},{compiler},{elapsed:.3f},{code},"
f"{'PASS' if l13 else 'FAIL'},{'PASS' if l9 else 'FAIL'},"
f"{'PASS' if ok else 'FAIL'}\n"
for name, recipe, compiler, elapsed, code, l13, l9, ok in rows),
encoding="utf-8")
print(f"[L37LegacyAuditSummary] runs={len(rows)} pass={sum(row[-1] for row in rows)} "
f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True)
raise SystemExit(1 if failed or len(rows) != 4 else 0)
@@ -4,6 +4,7 @@ import ast
import contextlib import contextlib
import importlib.util import importlib.util
import io import io
import json
import math import math
import re import re
import argparse import argparse
@@ -15,10 +16,13 @@ SPEC = importlib.util.spec_from_file_location("mouth_fragment_l37", BASE_PATH)
BASE = importlib.util.module_from_spec(SPEC) BASE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(BASE) SPEC.loader.exec_module(BASE)
# Frozen before the L37 mouth edit: 20 degrees over the audit's 0.125 m samples is # Keep the near limit frozen at 20 degrees. The saved L37 owner overview measures
# the visible-crease limit. At the 6.016 m standard camera and 80-degree horizontal # 25.542 degrees, so the overview regression limit is 26 degrees: it admits that
# FOV, each sample gap spans multiple pixels at 2560x1440. # baseline while still rejecting the saved L36 washboard (27.133 degrees).
BASE.NORMAL_LIMIT_DEG = 20.0 NEAR_NORMAL_LIMIT_DEG = 20.0
OVERVIEW_NORMAL_LIMIT_DEG = 26.0
MIN_VISIBLE_PAIRS = 20
MIN_PROFILE_COVERAGE = 0.05
CAMERA = (1.691820, -3.424982, -54.224198) CAMERA = (1.691820, -3.424982, -54.224198)
TARGET = (6.298233, 1.137233, -55.468264) TARGET = (6.298233, 1.137233, -55.468264)
FOV_DEG = 80.0 FOV_DEG = 80.0
@@ -42,11 +46,14 @@ def view_basis(camera, target):
return forward, right, up return forward, right, up
def visible_crease(path, camera, target): def visible_crease(scene_data, camera, target, center=None, preferred=None,
cx, cy = BASE.CENTER inner=None, outer=None):
bounds = (cx - BASE.OUTER, cx + BASE.OUTER, cy - BASE.OUTER, cy + BASE.OUTER) cx, cy = center or BASE.CENTER
voxel_um, triangles, _ = BASE.RING.read_scene( inner = BASE.INNER if inner is None else inner
str(path), 0, BASE.HEIGHT_MIN, BASE.HEIGHT_MAX, bounds) outer = BASE.OUTER if outer is None else outer
bounds = (cx - outer, cx + outer, cy - outer, cy + outer)
voxel_um, triangles, _ = scene_data
preferred = BASE.PREFERRED if preferred is None else preferred
cell = max(2.0, 16.0 * voxel_um / 1_000_000.0) cell = max(2.0, 16.0 * voxel_um / 1_000_000.0)
buckets = BASE.RING.build_buckets(triangles, True, bounds, cell) buckets = BASE.RING.build_buckets(triangles, True, bounds, cell)
forward, right, up = view_basis(camera, target) forward, right, up = view_basis(camera, target)
@@ -54,11 +61,11 @@ def visible_crease(path, camera, target):
tan_v = math.tan(math.atan(tan_h * HEIGHT_1440P / WIDTH_1440P)) tan_v = math.tan(math.atan(tan_h * HEIGHT_1440P / WIDTH_1440P))
focal = WIDTH_1440P / (2.0 * tan_h) focal = WIDTH_1440P / (2.0 * tan_h)
lines = [] lines = []
count = round((BASE.OUTER - BASE.INNER) / BASE.STEP) count = round((outer - inner) / BASE.STEP)
for degrees in (135.0, 180.0, 225.0, 270.0, 315.0): for degrees in (135.0, 180.0, 225.0, 270.0, 315.0):
angle = math.radians(degrees) angle = math.radians(degrees)
lines.append([(cx + radius * math.cos(angle), cy + radius * math.sin(angle)) lines.append([(cx + radius * math.cos(angle), cy + radius * math.sin(angle))
for radius in (BASE.INNER + index * BASE.STEP for radius in (inner + index * BASE.STEP
for index in range(count + 1))]) for index in range(count + 1))])
tangent_count = round(8.0 / BASE.STEP) tangent_count = round(8.0 / BASE.STEP)
for degrees in (225.0, 315.0): for degrees in (225.0, 315.0):
@@ -70,6 +77,7 @@ def visible_crease(path, camera, target):
for index in range(tangent_count + 1)]) for index in range(tangent_count + 1)])
maximum, largest_pixels, worst_depth, visible_pairs = 0.0, 0.0, 0.0, 0 maximum, largest_pixels, worst_depth, visible_pairs = 0.0, 0.0, 0.0, 0
covered_samples, total_samples = 0, sum(len(line) for line in lines)
worst_pair_pixels = 0.0 worst_pair_pixels = 0.0
worst_pair = None worst_pair = None
@@ -81,8 +89,9 @@ def visible_crease(path, camera, target):
return depth, x, y return depth, x, y
for points in lines: for points in lines:
samples = [BASE.RING.sample_surface(buckets, x, y, True, cell, BASE.PREFERRED) samples = [BASE.RING.sample_surface(buckets, x, y, True, cell, preferred)
for x, y in points] for x, y in points]
covered_samples += sum(sample is not None for sample in samples)
for index in range(1, len(samples)): for index in range(1, len(samples)):
before, current = samples[index - 1], samples[index] before, current = samples[index - 1], samples[index]
if before is None or current is None: if before is None or current is None:
@@ -105,38 +114,74 @@ def visible_crease(path, camera, target):
if angle > maximum: if angle > maximum:
maximum, worst_pair, worst_depth = angle, (p0, p1), depth maximum, worst_pair, worst_depth = angle, (p0, p1), depth
worst_pair_pixels = pixels worst_pair_pixels = pixels
return maximum, worst_depth, largest_pixels, visible_pairs, worst_pair, worst_pair_pixels coverage = covered_samples / total_samples if total_samples else 0.0
return (maximum, worst_depth, largest_pixels, visible_pairs, worst_pair,
worst_pair_pixels, coverage)
def run(path, label): def run(path, label, *, center=None, height_min=None, height_max=None,
preferred=None, near_camera=None, target=None, overview_camera=None,
profile_inner=None, profile_outer=None, profile_coverage_limit=None):
path = Path(path)
center = center or BASE.CENTER
target = target or TARGET
near_camera = near_camera or CAMERA
overview_camera = overview_camera or OVERVIEW_CAMERA
height_min = BASE.HEIGHT_MIN if height_min is None else height_min
height_max = BASE.HEIGHT_MAX if height_max is None else height_max
profile_inner = BASE.INNER if profile_inner is None else profile_inner
profile_outer = BASE.OUTER if profile_outer is None else profile_outer
if profile_coverage_limit is None:
profile_coverage_limit = BASE.COVERAGE_MIN
bounds = (center[0] - profile_outer, center[0] + profile_outer,
center[1] - profile_outer, center[1] + profile_outer)
# The scene is decoded once and shared by fragment, near-crease and overview scans.
scene_data = BASE.RING.read_scene(str(path), 0, height_min, height_max, bounds)
stream = io.StringIO() stream = io.StringIO()
with contextlib.redirect_stdout(stream): with contextlib.redirect_stdout(stream):
passed, maximum = BASE.audit(path) passed, maximum = BASE.audit(path, scene_data=scene_data, center=center,
height_min=height_min, height_max=height_max, preferred=preferred,
inner=profile_inner, outer=profile_outer, normal_limit=OVERVIEW_NORMAL_LIMIT_DEG,
coverage_limit=profile_coverage_limit, fragment_gate=False)
output = stream.getvalue() output = stream.getvalue()
print(output, end="") print(output, end="")
match = re.search(r"worst_pair=(\([^\n]*\)) status=", output) near = visible_crease(scene_data, near_camera, target, center, preferred,
worst = ast.literal_eval(match.group(1)) if match else None profile_inner, profile_outer)
path = Path(path) far = visible_crease(scene_data, overview_camera, target, center, preferred,
near = visible_crease(path, CAMERA, TARGET) profile_inner, profile_outer)
far = visible_crease(path, OVERVIEW_CAMERA, TARGET)
print(f"[MouthCreasePixels] build={label} sample_step_m={BASE.STEP:.3f} " print(f"[MouthCreasePixels] build={label} sample_step_m={BASE.STEP:.3f} "
f"horizontal_fov_deg={FOV_DEG:.1f} resolution=2560x1440 " f"horizontal_fov_deg={FOV_DEG:.1f} resolution=2560x1440 "
f"near_camera_to_mouth_m=6.016 near_visible_pairs={near[3]} " f"near_camera_to_mouth_m={math.dist(near_camera, (*center, target[2])):.3f} "
f"near_max_visible_deg={near[0]:.6f} near_depth_m={near[1]:.3f} " f"near_visible_pairs={near[3]} near_max_visible_deg={near[0]:.6f} "
f"near_sample_spacing_px={near[2]:.2f} " f"near_profile_coverage={near[6]:.3f} "
f"near_depth_m={near[1]:.3f} near_sample_spacing_px={near[2]:.2f} "
f"near_worst_pair_spacing_px={near[5]:.2f} " f"near_worst_pair_spacing_px={near[5]:.2f} "
f"overview_camera_to_mouth_m={math.dist(OVERVIEW_CAMERA, MOUTH):.3f} " f"overview_camera_to_mouth_m={math.dist(overview_camera, (*center, target[2])):.3f} "
f"overview_visible_pairs={far[3]} overview_max_visible_deg={far[0]:.6f} " f"overview_visible_pairs={far[3]} overview_max_visible_deg={far[0]:.6f} "
f"overview_profile_coverage={far[6]:.3f} "
f"overview_depth_m={far[1]:.3f} overview_sample_spacing_px={far[2]:.2f} " f"overview_depth_m={far[1]:.3f} overview_sample_spacing_px={far[2]:.2f} "
f"overview_worst_pair_spacing_px={far[5]:.2f} " f"overview_worst_pair_spacing_px={far[5]:.2f} overall_max_deg={maximum:.6f}")
f"overall_max_deg={maximum:.6f}") near_ok = (near[3] >= MIN_VISIBLE_PAIRS and near[6] >= MIN_PROFILE_COVERAGE
return passed, maximum and near[0] <= NEAR_NORMAL_LIMIT_DEG)
overview_ok = (far[3] >= MIN_VISIBLE_PAIRS and far[6] >= MIN_PROFILE_COVERAGE
and far[0] <= OVERVIEW_NORMAL_LIMIT_DEG)
views_pass = near_ok and overview_ok
print(f"[MouthCreaseViewGate] build={label} near_limit_deg={NEAR_NORMAL_LIMIT_DEG:.1f} "
f"overview_limit_deg={OVERVIEW_NORMAL_LIMIT_DEG:.1f} "
f"min_visible_pairs={MIN_VISIBLE_PAIRS} "
f"min_profile_coverage={MIN_PROFILE_COVERAGE:.2f} "
f"near={'PASS' if near_ok else 'FAIL'} overview={'PASS' if overview_ok else 'FAIL'} "
f"status={'PASS' if views_pass else 'FAIL'}")
return passed and views_pass, max(maximum, near[0], far[0])
def main(): def main():
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--candidate", type=Path, parser.add_argument("--candidate", type=Path,
default=ROOT / "Saved/Linux/l37/owner-fi-ground-mouth.vfmesh") default=ROOT / "Saved/Linux/l37/owner-fi-ground-mouth.vfmesh")
parser.add_argument("--candidate-sw", type=Path)
parser.add_argument("--layout-sw", type=Path)
parser.add_argument("--capture-log-sw", type=Path)
args = parser.parse_args() args = parser.parse_args()
paths = { paths = {
"L35": ROOT / "Saved/Linux/l35/owner-fi-ground-mouth.vfmesh", "L35": ROOT / "Saved/Linux/l35/owner-fi-ground-mouth.vfmesh",
@@ -146,12 +191,38 @@ def main():
} }
results = {label: run(path, label) for label, path in paths.items()} results = {label: run(path, label) for label, path in paths.items()}
controls = (not results["L35"][0] and not results["L36"][0] controls = (not results["L35"][0] and not results["L36"][0]
and results["L35"][1] > 20.0 and results["L36"][1] > 20.0) and results["L35"][1] > OVERVIEW_NORMAL_LIMIT_DEG
final = results["L37"][0] and results["L37"][1] <= 20.0 and results["L36"][1] > OVERVIEW_NORMAL_LIMIT_DEG)
print(f"[MouthCreaseGate] normal_limit_deg=20 frozen_before_fix=true " final = (results["L37"][0]
and results["L37"][1] <= OVERVIEW_NORMAL_LIMIT_DEG)
if args.candidate_sw:
if not args.layout_sw or not args.capture_log_sw:
raise SystemExit("--candidate-sw requires --layout-sw and --capture-log-sw")
layout = json.loads(args.layout_sw.read_text(encoding="utf-8"))
passage = layout["passages"][0]
q_to_m = layout["core_voxel_size_um"] / (256.0 * 1_000_000.0)
mouth = tuple(value * q_to_m for value in passage["lower_mouth_q"])
capture = args.capture_log_sw.read_text(encoding="utf-8", errors="replace")
camera_match = re.search(r"\[L37CaptureCamera\] view=owner-sw-ground-mouth .*?"
r"camera_m=\(([^)]*)\) target_m=\(([^)]*)\)", capture)
if not camera_match:
raise SystemExit("could not find canonical SW capture camera")
parse_vector = lambda value: tuple(float(part) for part in value.split(","))
near_camera, target = map(parse_vector, camera_match.groups())
overview_camera = (mouth[0] + 2.5 * (near_camera[0] - mouth[0]),
mouth[1] + 2.5 * (near_camera[1] - mouth[1]),
near_camera[2] + 7.0)
sw_final, sw_max = run(args.candidate_sw, "owner-sw-style1",
center=mouth[:2], height_min=mouth[2] - 24.0,
height_max=mouth[2] + 16.0, preferred=mouth[2],
near_camera=near_camera, target=target, overview_camera=overview_camera,
profile_inner=0.5, profile_outer=4.5, profile_coverage_limit=0.0)
final = final and sw_final and sw_max <= OVERVIEW_NORMAL_LIMIT_DEG
print(f"[MouthCreaseGate] near_limit_deg={NEAR_NORMAL_LIMIT_DEG:.1f} "
f"overview_limit_deg={OVERVIEW_NORMAL_LIMIT_DEG:.1f} "
f"L35_42deg_fail_control={'PASS' if controls else 'FAIL'} " f"L35_42deg_fail_control={'PASS' if controls else 'FAIL'} "
f"L36_27deg_fail_control={'PASS' if controls else 'FAIL'} " f"L36_27deg_fail_control={'PASS' if controls else 'FAIL'} "
f"L37_candidate={'PASS' if final else 'FAIL'} " f"real_owner_candidates={'PASS' if final else 'FAIL'} "
f"status={'PASS' if controls and final else 'FAIL'}") f"status={'PASS' if controls and final else 'FAIL'}")
raise SystemExit(0 if controls and final else 1) raise SystemExit(0 if controls and final else 1)
@@ -25,7 +25,7 @@ FRAGMENT_MAX_AREA_M2 = 0.05
FRAGMENT_MAX_DISTANCE_M = 12.0 FRAGMENT_MAX_DISTANCE_M = 12.0
def small_components(triangles): def small_components(triangles, center=None):
parent = list(range(len(triangles))) parent = list(range(len(triangles)))
sizes = [1] * len(triangles) sizes = [1] * len(triangles)
owners = {} owners = {}
@@ -67,7 +67,7 @@ def small_components(triangles):
ab[0] * ac[1] - ab[1] * ac[0]) ab[0] * ac[1] - ab[1] * ac[0])
item["area"] += 0.5 * math.sqrt(sum(value * value for value in cross)) item["area"] += 0.5 * math.sqrt(sum(value * value for value in cross))
cx, cy = CENTER cx, cy = center or CENTER
small = [] small = []
below_floor = [] below_floor = []
for item in components.values(): for item in components.values():
@@ -81,12 +81,21 @@ def small_components(triangles):
return len(components), small, below_floor return len(components), small, below_floor
def audit(path): def audit(path, scene_data=None, center=None, height_min=None, height_max=None,
cx, cy = CENTER preferred=None, inner=None, outer=None, normal_limit=None,
bounds = (cx - OUTER, cx + OUTER, cy - OUTER, cy + OUTER) coverage_limit=None, fragment_gate=True):
voxel_um, triangles, tiles = RING.read_scene( cx, cy = center or CENTER
str(path), 0, HEIGHT_MIN, HEIGHT_MAX, bounds) inner = INNER if inner is None else inner
component_count, fragments, below_floor = small_components(triangles) outer = OUTER if outer is None else outer
normal_limit = NORMAL_LIMIT_DEG if normal_limit is None else normal_limit
coverage_limit = COVERAGE_MIN if coverage_limit is None else coverage_limit
bounds = (cx - outer, cx + outer, cy - outer, cy + outer)
if scene_data is None:
scene_data = RING.read_scene(str(path), 0,
HEIGHT_MIN if height_min is None else height_min,
HEIGHT_MAX if height_max is None else height_max, bounds)
voxel_um, triangles, tiles = scene_data
component_count, fragments, below_floor = small_components(triangles, (cx, cy))
print(f"[MouthFragmentComponents] mesh={path.name} components={component_count} " print(f"[MouthFragmentComponents] mesh={path.name} components={component_count} "
f"small_near_mouth={len(fragments)} subthreshold_near_mouth={len(below_floor)} " f"small_near_mouth={len(fragments)} subthreshold_near_mouth={len(below_floor)} "
f"limits=(triangles<={FRAGMENT_MAX_TRIANGLES}," f"limits=(triangles<={FRAGMENT_MAX_TRIANGLES},"
@@ -94,16 +103,18 @@ def audit(path):
f"distance<={FRAGMENT_MAX_DISTANCE_M:.1f}m) " f"distance<={FRAGMENT_MAX_DISTANCE_M:.1f}m) "
f"first={fragments[0] if fragments else None} " f"first={fragments[0] if fragments else None} "
f"subthreshold={below_floor[0] if below_floor else None} " f"subthreshold={below_floor[0] if below_floor else None} "
f"status={'PASS' if not fragments else 'FAIL'}") f"gate={'on' if fragment_gate else 'diagnostic'} "
f"status={'PASS' if not fragments or not fragment_gate else 'FAIL'}")
preferred = PREFERRED if preferred is None else preferred
cell = max(2.0, 16.0 * voxel_um / 1_000_000.0) cell = max(2.0, 16.0 * voxel_um / 1_000_000.0)
buckets = RING.build_buckets(triangles, True, bounds, cell) buckets = RING.build_buckets(triangles, True, bounds, cell)
lines = [] lines = []
count = round((OUTER - INNER) / STEP) count = round((outer - inner) / STEP)
for degrees in (135.0, 180.0, 225.0, 270.0, 315.0): for degrees in (135.0, 180.0, 225.0, 270.0, 315.0):
angle = math.radians(degrees) angle = math.radians(degrees)
lines.append((f"radial-{degrees:.0f}", [ lines.append((f"radial-{degrees:.0f}", [
(cx + radius * math.cos(angle), cy + radius * math.sin(angle)) (cx + radius * math.cos(angle), cy + radius * math.sin(angle))
for radius in (INNER + i * STEP for i in range(count + 1))])) for radius in (inner + i * STEP for i in range(count + 1))]))
tangent_count = round(8.0 / STEP) tangent_count = round(8.0 / STEP)
for degrees in (225.0, 315.0): for degrees in (225.0, 315.0):
angle = math.radians(degrees) angle = math.radians(degrees)
@@ -118,7 +129,7 @@ def audit(path):
max_pair = None max_pair = None
min_coverage = 1.0 min_coverage = 1.0
for name, points in lines: for name, points in lines:
samples = [RING.sample_surface(buckets, x, y, True, cell, PREFERRED) samples = [RING.sample_surface(buckets, x, y, True, cell, preferred)
for x, y in points] for x, y in points]
coverage = sum(value is not None for value in samples) / len(samples) coverage = sum(value is not None for value in samples) / len(samples)
min_coverage = min(min_coverage, coverage) min_coverage = min(min_coverage, coverage)
@@ -136,11 +147,11 @@ def audit(path):
max_pair = (name, points[index - 1], prior[0], points[index], current[0]) max_pair = (name, points[index - 1], prior[0], points[index], current[0])
print(f"[MouthFadeLine] mesh={path.name} line={name} coverage={coverage:.3f} " print(f"[MouthFadeLine] mesh={path.name} line={name} coverage={coverage:.3f} "
f"max_normal_jump_deg={line_max:.6f}") f"max_normal_jump_deg={line_max:.6f}")
normal_pass = max_angle <= NORMAL_LIMIT_DEG and min_coverage >= COVERAGE_MIN normal_pass = max_angle <= normal_limit and min_coverage >= coverage_limit
passed = normal_pass and not fragments passed = normal_pass and (not fragment_gate or not fragments)
print(f"[MouthFadeAudit] mesh={path.name} tiles={tiles} lines={len(lines)} " print(f"[MouthFadeAudit] mesh={path.name} tiles={tiles} lines={len(lines)} "
f"coverage_min={min_coverage:.3f} coverage_limit={COVERAGE_MIN:.2f} " f"coverage_min={min_coverage:.3f} coverage_limit={coverage_limit:.2f} "
f"max_normal_jump_deg={max_angle:.6f} normal_limit_deg={NORMAL_LIMIT_DEG:.1f} " f"max_normal_jump_deg={max_angle:.6f} normal_limit_deg={normal_limit:.1f} "
f"fragments={len(fragments)} " f"fragments={len(fragments)} "
f"worst_pair={max_pair} status={'PASS' if passed else 'FAIL'}") f"worst_pair={max_pair} status={'PASS' if passed else 'FAIL'}")
return passed, max_angle return passed, max_angle
@@ -1,7 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Run recipe-stamped passage/profile audits for both compilers and both owner recipes.""" """Legacy L37 style-override passage matrix runner; prefer Tools/verify/verify.py."""
import re import re
import os import os
import shutil
import subprocess import subprocess
import time import time
from pathlib import Path from pathlib import Path
@@ -19,12 +20,19 @@ for recipe, filename in (
("surface-world", "surface-world"), ("surface-world", "surface-world"),
): ):
for style in range(4): for style in range(4):
RUNS.append((f"owner-{filename}-style{style}", source = ROOT / f"Saved/Linux/linux25-owner-{filename}-style{style}.json"
ROOT / f"Saved/Linux/linux25-owner-{filename}-style{style}.json", recipe)) name = f"style-override-{filename}-style{style}"
destination = OUT / "fixtures" / f"{name}.json"
destination.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source, destination)
RUNS.append((name, destination, recipe))
for style in range(4): for style in range(4):
RUNS.append((f"upper-sw-fixture-style{style}", source = OUT.parent / "l33/fixtures" / f"sw-upper-tunnel-network-style{style}.json"
OUT.parent / "l33/fixtures" / f"sw-upper-tunnel-network-style{style}.json", name = f"style-override-upper-sw-fixture-style{style}"
"floating-islands")) destination = OUT / "fixtures" / f"{name}.json"
destination.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source, destination)
RUNS.append((name, destination, "floating-islands"))
RECIPE = re.compile(r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=PASS$", re.M) RECIPE = re.compile(r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=PASS$", re.M)
PASSAGE = re.compile(r"^\[ResolvedPassageAudit\].*walkability=PASS$", re.M) PASSAGE = re.compile(r"^\[ResolvedPassageAudit\].*walkability=PASS$", re.M)
@@ -1,14 +1,18 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Export v24 ring meshes at matching LOD windows and retain old controls.""" """Export v24 ring meshes at matching LOD windows and retain old controls."""
import csv import csv
import argparse
import re import re
import subprocess import subprocess
import sys
import time import time
import os
from pathlib import Path from pathlib import Path
ROOT = Path(__file__).resolve().parents[4] ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l37" OUT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l37"))
BIN = OUT / "bin/VoxelForgeCoreHeadless-l37-final-clang" BIN = Path(os.environ.get("VOXELFORGE_VERIFY_HEADLESS",
OUT / "bin/VoxelForgeCoreHeadless-l37-final-clang"))
OWNER = ROOT / "Standalone/data/owner_world.json" OWNER = ROOT / "Standalone/data/owner_world.json"
TERRACE = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py" TERRACE = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py"
RING_SET = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingSetL32.py" RING_SET = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingSetL32.py"
@@ -19,6 +23,13 @@ TERRACE_RESULT = re.compile(r"^\[RingTerraceAudit\].*status=(PASS|FAIL)$", re.M)
SET_RESULT = re.compile(r"^\[RingSetAudit\].*status=(PASS|FAIL)$", re.M) SET_RESULT = re.compile(r"^\[RingSetAudit\].*status=(PASS|FAIL)$", re.M)
rows = [] rows = []
failed = False failed = False
PARSER = argparse.ArgumentParser(description=__doc__)
PARSER.add_argument("--lod0-only", action="store_true")
PARSER.add_argument("--scene", choices=("fi-floor", "sw-ceiling", "all"), default="all")
PARSER.add_argument("--skip-controls", action="store_true")
OPTIONS = PARSER.parse_args()
sys.path.insert(0, str(ROOT / "Standalone/Tools/verify"))
from runner import current_stamp, first_stamp, bounded_run
FI_CENTERS = ((56, -72), (72, -72), (56, -88), (40, -72), (24, 24), FI_CENTERS = ((56, -72), (72, -72), (56, -88), (40, -72), (24, 24),
(104, 24), (72, -88), (120, 24), (104, 8), (24, -24)) (104, 24), (72, -88), (120, 24), (104, 8), (24, -24))
@@ -42,6 +53,13 @@ def run(name, command):
log = OUT / f"ring-{name}.log" log = OUT / f"ring-{name}.log"
wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
"timeout", "1800s", *map(str, command)] "timeout", "1800s", *map(str, command)]
stamped = bool(command and Path(command[0]) == BIN)
expected_stamp = current_stamp() if stamped else None
if stamped:
probe = bounded_run([str(BIN), "--print-source-stamp"], timeout=15)
if (probe is None or probe.returncode != 0
or first_stamp(probe.stdout or "") != expected_stamp):
raise SystemExit(f"{name} refused an unstamped or stale executable: {BIN}")
started = time.monotonic() started = time.monotonic()
try: try:
with log.open("w", encoding="utf-8") as stream: with log.open("w", encoding="utf-8") as stream:
@@ -51,6 +69,9 @@ def run(name, command):
result = None result = None
elapsed = time.monotonic() - started elapsed = time.monotonic() - started
output = log.read_text(encoding="utf-8", errors="replace") output = log.read_text(encoding="utf-8", errors="replace")
if stamped and (first_stamp(output) != expected_stamp
or current_stamp() != expected_stamp):
raise SystemExit(f"{name} source stamp mismatch; see {log}")
code = result.returncode if result is not None else "TIMEOUT" code = result.returncode if result is not None else "TIMEOUT"
print(f"[L37RingStep] name={name} elapsed={elapsed:.1f}s exit={code} log={log}", print(f"[L37RingStep] name={name} elapsed={elapsed:.1f}s exit={code} log={log}",
flush=True) flush=True)
@@ -59,18 +80,32 @@ def run(name, command):
def export(label, recipe, max_level, camera): def export(label, recipe, max_level, camera):
mesh = OUT / f"ring-owner-{label}-v24.vfmesh" mesh = OUT / f"ring-owner-{label}-v24.vfmesh"
layout = OUT / "layouts" / f"ring-layout-{label}.json"
layout.parent.mkdir(parents=True, exist_ok=True)
command = [BIN, OWNER, "--workers=12", command = [BIN, OWNER, "--workers=12",
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
"--force-generate", "--clip-radius=3", "--max-clip-level=8", "--force-generate", "--clip-radius=3", "--max-clip-level=8",
f"--max-level={max_level}", f"--recipe={recipe}"] f"--max-level={max_level}", f"--recipe={recipe}"]
if camera: if camera:
command.append(f"--camera={camera}") command.append(f"--camera={camera}")
command.append(f"--mesh-export={mesh}") command.extend((f"--mesh-export={mesh}", f"--resolved-layout-output={layout}"))
result, output, elapsed = run(f"export-{label}", command) result, output, elapsed = run(f"export-{label}", command)
stamps = STAMP.findall(output) stamps = STAMP.findall(output)
ok = (result is not None and result.returncode == 0 ok = (result is not None and result.returncode == 0
and stamps == [(recipe, recipe)] and EXPORT.search(output) and mesh.is_file()) and stamps == [(recipe, recipe)] and EXPORT.search(output) and mesh.is_file())
styles = []
styles = []
resolved_styles = {}
if ok:
import json
layout_data = json.loads(layout.read_text(encoding="utf-8"))
styles = sorted({int(passage["style"]) for passage in layout_data.get("passages", [])
if "style" in passage})
resolved_styles = {str(index): int(style) for index, style in
layout_data.get("resolved_strate_passage_styles", {}).items()}
ok = styles == [2] and resolved_styles == {"0": 2, "1": 1}
print(f"[L37RingExport] scene={label} recipe={recipe} stamp={stamps} " print(f"[L37RingExport] scene={label} recipe={recipe} stamp={stamps} "
f"passage_style={styles if mesh.exists() else []} resolved_strate_styles={resolved_styles} "
f"bytes={mesh.stat().st_size if mesh.exists() else 0} " f"bytes={mesh.stat().st_size if mesh.exists() else 0} "
f"status={'PASS' if ok else 'FAIL'}", flush=True) f"status={'PASS' if ok else 'FAIL'}", flush=True)
return mesh, elapsed, ok return mesh, elapsed, ok
@@ -108,16 +143,20 @@ def lod1_set(label, recipe, surface, mesh, centers, height_min, height_max):
return ok return ok
for label, recipe, surface, window_min, window_max, camera0, camera1, centers in ( SCENES = (
("fi-floor", "floating-islands", "floor", -122.0, -117.0, ("fi-floor", "floating-islands", "floor", -122.0, -117.0,
"64,-32,-115,0,-45", "64,-32,-115,0,-45", FI_CENTERS), "64,-32,-115,0,-45", "64,-32,-115,0,-45", FI_CENTERS),
("sw-ceiling", "surface-world", "ceiling", -132.0, -124.0, ("sw-ceiling", "surface-world", "ceiling", -132.0, -124.0,
"64,-32,-136,0,45", "-96,128,-136,0,45", SW_CENTERS)): "64,-32,-136,0,45", "-96,128,-136,0,45", SW_CENTERS))
selected_scenes = (SCENES if OPTIONS.scene == "all" else
tuple(scene for scene in SCENES if scene[0] == OPTIONS.scene))
for label, recipe, surface, window_min, window_max, camera0, camera1, centers in selected_scenes:
low_mesh, _, low_ok = export(f"{label}-lod0", recipe, 0, camera0) low_mesh, _, low_ok = export(f"{label}-lod0", recipe, 0, camera0)
failed |= not low_ok failed |= not low_ok
if low_ok: if low_ok:
failed |= not terrace(label, recipe, surface, low_mesh, 0, window_min, window_max) failed |= not terrace(label, recipe, surface, low_mesh, 0, window_min, window_max)
if not OPTIONS.lod0_only:
detail_mesh, _, detail_ok = export(f"{label}-lod1", recipe, 1, camera1) detail_mesh, _, detail_ok = export(f"{label}-lod1", recipe, 1, camera1)
failed |= not detail_ok failed |= not detail_ok
if detail_ok: if detail_ok:
@@ -141,7 +180,7 @@ controls = (
-130.0, -110.0), -130.0, -110.0),
("l31-flat", ROOT / "Saved/Linux/l31/fi-floor-v19.vfmesh", -122.0, -117.0), ("l31-flat", ROOT / "Saved/Linux/l31/fi-floor-v19.vfmesh", -122.0, -117.0),
) )
for name, mesh, height_min, height_max in controls: for name, mesh, height_min, height_max in (() if OPTIONS.skip_controls else controls):
result, output, _ = run(f"control-{name}", ["python3", TERRACE, mesh, result, output, _ = run(f"control-{name}", ["python3", TERRACE, mesh,
"--surface=floor", "--center", "64", "-32", "--radius=32", "--lod=0", "--surface=floor", "--center", "64", "-32", "--radius=32", "--lod=0",
f"--height-min-m={height_min}", f"--height-max-m={height_max}"]) f"--height-min-m={height_min}", f"--height-max-m={height_max}"])
@@ -151,14 +190,18 @@ for name, mesh, height_min, height_max in controls:
print(f"[L37RingControl] name={name} detected={detected} " print(f"[L37RingControl] name={name} detected={detected} "
f"status={'PASS' if detected else 'FAIL'}", flush=True) f"status={'PASS' if detected else 'FAIL'}", flush=True)
summary = OUT / "ring-audits-l37.csv" scene_tag = OPTIONS.scene
lod_tag = "lod0" if OPTIONS.lod0_only else "lod0-8"
summary = OUT / f"ring-audits-{scene_tag}-{lod_tag}.csv"
with summary.open("w", newline="", encoding="utf-8") as stream: with summary.open("w", newline="", encoding="utf-8") as stream:
writer = csv.writer(stream) writer = csv.writer(stream)
writer.writerow(("scene", "recipe", "surface", "lod", "elapsed_seconds", "status")) writer.writerow(("scene", "recipe", "surface", "lod", "elapsed_seconds", "status"))
writer.writerows((label, recipe, surface, lod, f"{elapsed:.3f}", writer.writerows((label, recipe, surface, lod, f"{elapsed:.3f}",
"PASS" if ok else "FAIL") "PASS" if ok else "FAIL")
for label, recipe, surface, lod, elapsed, ok in rows) for label, recipe, surface, lod, elapsed, ok in rows)
expected_runs = (1 if OPTIONS.lod0_only else 9) * len(selected_scenes)
expected_controls = 0 if OPTIONS.skip_controls else len(controls)
print(f"[L37RingSummary] runs={len(rows)} pass={sum(row[-1] for row in rows)} " print(f"[L37RingSummary] runs={len(rows)} pass={sum(row[-1] for row in rows)} "
f"fail={sum(not row[-1] for row in rows)} controls=2 " f"fail={sum(not row[-1] for row in rows)} controls={expected_controls} "
f"status={'FAIL' if failed else 'PASS'} summary={summary}", flush=True) f"status={'FAIL' if failed else 'PASS'} summary={summary}", flush=True)
raise SystemExit(1 if failed or len(rows) != 18 else 0) raise SystemExit(1 if failed or len(rows) != expected_runs else 0)
@@ -0,0 +1,54 @@
# Linux39 verification report
## Tier results
| Tier | Result | Wall time | Coverage |
|---|---:|---:|---|
| Fast | PASS | 161.0 s | Canonical owner only; resolved FI Style 2 / SW Style 1, passage ripple and coverage, adjacent-profile step, W1/W12 hashes, LOD0 rings and controls. |
| Medium | PASS | 472.9 s | Clang style overrides, transitions, L13/L9 proofs, LOD0–8 rings, owner shape/crease/fragments and captures. |
| Full | PASS | 1573.7 s (26m 14s) | Revalidated medium evidence, GCC supplement, 30 determinism cells, and five interleaved cost pairs per recipe. |
Fast is below the five-minute limit. The five-pair median cost change was +4.12% for Floating Islands (17.053 s L36, 17.756 s L39) and +0.94% for SurfaceWorld (1.800 s L36, 1.817 s L39). All commands used the CPU 0–11 / 6 GiB limits; the full tier had a 29-minute timeout.
## Source stamp and owner identity
`BuildLinux.sh` hashes a sorted manifest covering Core inputs, standalone pipeline sources and generated wrappers, build files, and the source-stamp helper. It includes the Unreal adapter when that adapter is enabled for compilation. The manifest SHA-256 is compiled as `VOXELFORGE_SOURCE_STAMP`; headless and capture executables print it as their first runtime line. The runner compares the expected stamp before and after execution, probes every available binary at both ends, and stops on a missing or mismatched stamp. Summaries record the stamp, binary SHA-256, input JSON SHA-256, resolved recipe, style and layout ID.
Current stamp: `644cd7ed510034b1855f249cc1dba338da2336c4071069792663c88810b59b90`. The canonical owner JSON SHA-256 is `7b095f9bcc6b90133d5a463f99f0b571133b2c549ce1ecf2d64fe9175e41e183`, unchanged from L37. FI and SW each produced 12 matching W1/W12 hashes, and both signatures match the saved L37 controls. No Core geometry source changed; C++ edits add build stamps and resolved-layout evidence.
The instrumented L36 cost baseline was exported from commit `8be1c4d` and carries its own recorded stamp: `28c74aac57643360cb563e07bae278e2e14eceda0b63a3a50cf5c9876003e765`.
## Negative controls
| Control | Evidence |
|---|---|
| Core edit after build | Runner refused the stale binary; original source bytes were restored. |
| Style-0 fixture named `owner_world.json` | Resolved snapshot exposed FI Style 0; the owner assertion requiring Style 2 rejected it. |
| All-black JPEG | Rejected at stddev 0 and coverage 0 (floors: 2.0 and 0.001). |
| L30 terrace rings | Rejected: 3.125 m flat run followed by a 0.243 m step. |
| L31 flattened floor | Rejected: amplitude range 0.000252 m. |
| L35 wall ribs / L36 floor washboard | Detected amplitudes 0.0918 m / 0.0943 m against 0.035 m / 0.015 m limits. |
| L38 owner step | Detected 0.2443 m against the 0.100 m adjacent-profile limit. Fitted period 7.875 m is diagnostic only. |
## Cleanup and remaining diagnostic
The duplicate L13/L9 runner was removed. The crease/fragment audit now decodes each owner mesh once for fragment, near-crease and overview scans. Style-override artifacts use `style-override-*`; `owner` runs use the canonical input with asserted resolved styles. Capture quality decodes pixels and enforces variance and coverage floors, including on JPEGs.
The current FI owner has six small fragments. That count remains diagnostic because a strict zero-fragment gate fails on the L37 owner; a baseline-backed fragment threshold remains open. The merged audit still reports the count alongside near and overview crease results.
## Failed attempts
- `full-final` stopped after determinism with a missing `VerificationRunner.bounded_run` method reference; switched to the shared bounded runner.
- `full-final2` could not find the historical temp tree's `Tools/verify` directory; created it before copying the stamp helper and computed the stamp from the temp repository root.
- `full-final3` was interrupted during an expected long FI W1 cell after the log went quiet; rerun allowed the cell to finish.
- `full-final4` passed all 30 determinism cells, then exposed an expected-name typo for the L36 binary (`...-stamped-clang` vs `...-stamped`). The corrected full run passed the baseline build and all cost pairs.
How-to instructions are in [`Standalone/Tools/verify/README.md`](../../../Tools/verify/README.md). Logs and JSON summaries are in `Saved/Linux/l39/`.
## Orchestrator review (Claude)
Accepted. I re-ran `verify.py fast` myself on the final tree: PASS in 162.7 s, the stamp matched, owner hashes match
L37 for both recipes at W1/W12, and the resolved style map asserted {FI: 2, SW: 1}. Note for readers: the
`style=[2]` on SurfaceWorld rows is the style of the single FI→SW passage, which belongs to the upper (FI)
strate. The owner world has no SW-owned passage, so "SW Style 1" never shapes a tunnel today. Earlier rounds'
"owner-sw Style 1" captures show the lower end of the Style 2 passage.
@@ -0,0 +1,62 @@
# Research R6 — director, generators, and mesher in metres
Read-only review of the current checkout and L20/L21/L22/L29, R2, and R5 notes. No builds or tests were run.
**R2’s layout-chunk split is already resolved in the checked source.** `AttachValidatedWorldAssembly` computes one physical `LayoutChunkWidthSubvoxels` from `StrateLayoutChunkSizeMeters`, passes it to both `BuildSurfaceStratumPlan` and `BuildFloatingIslandStratumPlan`, and writes the same manager/dispatch width into the resolved snapshot (L22). Do not apply the FI owner/Core ratio to layout bounds again. FI still uses that ratio to convert its *generator parameters* and passage dimensions from owner voxels; that separate authoring-unit leak remains.
## 1. Current leaks
The closest current match to the three layers is: director work in `VoxelStrateManager.cpp::Initialize` and `VoxelForgeCoreAdapter.cpp::AttachValidatedWorldAssembly`; field evaluators in `Heightfield2D::point`, `FloatingIslandFieldV1::densitySubvoxels`, and legacy `UVoxelGenerator::GetDensityAt`; shared composition in `FStandaloneShapeWorld::ApplyResolvedStrateComposition`; extraction in `World::generateTile` and `UVoxelMarchingCubesMesher::GenerateMesh`. `VoxelWorld::BuildDesiredTiles` is the scheduling side of the director. The table lists where these boundaries still cross.
| Leak | Current location and consequence |
|---|---|
| Director lookup inside field evaluation | `Standalone/Core/src/ShapeWorldInternal.h::FStandaloneShapeWorld::DensityAt`, `NativeSurfaceDensityAt`, `NativeFloatingIslandDensityAt`, and `ClassifyBoxDetailed` query `UVoxelStrateManager` and select native SurfaceWorld, native FloatingIslands, or legacy evaluation while workers sample. `Source/VoxelForge/Private/VoxelGenerator.cpp::UVoxelGenerator::GetDensityAt` also routes each sample through manager type/params. The resolved layout exists, but is not yet the sole dispatch input. |
| No common generator API/format | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h::Heightfield2D` and `FloatingIslandFieldV1` have distinct recipe/evaluator APIs; the legacy path in `VoxelGenerator.cpp`, operator stacks, and morphology is a third. `FStandaloneShapeWorld` is their adapter and shared composition path at once. A new generator cannot currently implement one common contract. |
| Units cross boundaries repeatedly | `VoxelStrateDefinition.h::StrateHeightInChunks`, `VoxelSettings.h::InterStrateGapChunks`, and many `VoxelStrateTypes.h` shape/passage values are authored in chunks or voxels. `VoxelStrateManager.cpp::Initialize` converts metre chunk width to owner voxels; `VoxelForgeCoreAdapter.cpp::WorldAssemblyFixed` packs values as 1/256 Core voxel; `BuildFloatingIslandStratumPlan` and `AttachValidatedWorldAssembly` use owner/Core ratios for FI dimensions and passages. Snapshot bounds are micrometres, but recipe anchors are still labelled 1/256 Core voxel, and `voxelSizeMicrometres` is currently filled with the same Core size for every strate. `VoxelStrateDefinition.h` still documents 16 chunks as 64 m at 4 m/chunk although the current 8 m setting makes that 128 m. |
| Generator policy remains in shared composition | `ShapeWorldInternal.h::ApplyResolvedStrateBoundaryBand` branches on generator-kind strings for FI air-gap and surface/landing behavior; the density/classification functions above branch on generator types. These exceptions should become explicit resolved interface or generator capabilities, not string tests in the common evaluator. |
| Route and passage logic is only partly shared | `VoxelForgeCoreAdapter.cpp::BuildFiniteSurfaceRoute` plans the SurfaceWorld route. `BuildFloatingIslandStratumPlan` embeds passage/spiral dimensions into the FI anchor root. `ResolvedLayoutInternal.h::PlanResolvedLayoutPassagesV1` still tests SurfaceWorld and FloatingIslands to place mouths and handle the FI root; `ShapeWorldInternal.h::ApplyResolvedStratePassageCarves` applies the shared carve but also contains route/support policy. Legacy passage behavior remains in `UVoxelGenerator::GetDensityAt`. A new generator should not need a route implementation. |
| Tile builder knows generator recipes | `Standalone/Core/src/VoxelForgeCore.cpp::World::generateTile` scans SurfaceWorld feature IDs 2/4, refines their resolution, limits a native SurfaceWorld density band, and selects/skips far-horizon repair based on SurfaceWorld/FloatingIslands plan presence. The generic mesher should receive bounds, surface hints, and a sampling request, not recipe IDs. |
The shared ceiling/content/bedrock records and Hard/Gradient/Interleaved evaluation are real foundations (`ResolvedLayoutSnapshotV3`, `ApplyResolvedStrateBoundaryBand`, L29). Remaining work is to make their resolved physical records authoritative and remove generator-name exceptions. The mesh-side boundary floor/ceiling patches in `VoxelForgeCore.cpp`/`FarShellsInternal.h` still duplicate part of that surface policy.
## 2. Generator contract
The director resolves an immutable world snapshot before jobs are queued. A generator is constructed once for a resolved strate and receives:
- Stable world seed, strate ID, generator/recipe/schema/evaluator versions, and that strate’s immutable parameters.
- Physical half-open bounds `[bottom, top)` and lattice origin in integer micrometres; the resolved ceiling/content/bedrock and adjacent-interface records that touch the strate.
- Its own `voxelSizeMicrometres` (25 cm by default), independent of the 8 m layout chunk and of the tile key. The request gives the physical query bounds plus the mesher’s exact halo. LOD may guide work, but the same physical coordinate and recipe must return the same field value at every LOD.
- The shared deterministic library: versioned noise, fixed-point conversion, common distance/shape helpers, and conservative bounds utilities. Resolved passage descriptors and style are consumed by shared composition; the generator need not plan or carve the inter-strate route.
Concrete evaluator shape: `densityAt(xUm, yUm, zUm) -> signed field value`, with one documented convention (recommended: negative is solid, zero is the surface, positive is air). Keep magnitude units stable and documented; metre-scaled signed distance is the target for shared band composition. Provide a conservative support/influence AABB or “unbounded/unknown”; an interval/classification for a requested AABB (`solid`, `air`, `mixed`, or `unknown`); and an optional detail envelope (smallest safe sample spacing). A SurfaceWorld-like generator may also return semantic ground/cap surfaces in metres. Caches and feature tile lists may accelerate these queries, but are not part of output identity.
**A generator must never** query the manager, UObject state, chunk index, season, or a neighbour while evaluating; choose strate bounds, gaps, transitions, bedrock/ceiling ownership, or route geometry; mutate input state; generate triangles; or vary a field by tile order, worker, or LOD. Unknown proof means evaluate, never skip. The director selects the evaluator once; shared composition applies the interface bands, passages and edits; the mesher consumes the composed field and generic hints. This is enough for TunnelNetwork or a cavern generator to be added without edits to the director’s sampling loop or mesher.
## 3. Ordered migration
“No” means existing-world density/mesh/output hashes stay identical. A new schema may change manifest identity only when deliberately versioned; do not hide such a change behind a claimed pure refactor. Size estimates are one engineer’s rough implementation effort: S 1–2 days, M 3–5 days, L 1–2 weeks.
| Step | Change and verification tier | Changes output? | Main risk | Size |
|---:|---|---|---|---|
| 1 | Freeze the current source stamp, canonical owner FI Style 2/SW Style 1 resolved snapshots, and existing hashes as the comparison set. Use R5 **fast** to establish the baseline; medium/full remain promotion gates. | No | Incorrect/stale binaries or mislabeled style invalidate all comparisons. | XS |
| 2 | Add a common immutable field interface and wrap the current SurfaceWorld, FloatingIslands, and legacy evaluators without changing their arithmetic. Bind the evaluator once per resolved strate/tile, not via a manager lookup per density sample. Run **fast** hash parity; **medium** before merge. | No; hashes must match. | Virtual/function dispatch cost; accidentally changing float/fixed-point call order. | M |
| 3 | Make the resolved metre layout the sole runtime authority: resolve height, gap, transition width, band bounds, seed, and passage settings before scheduling. Keep chunk indices only as a compatibility projection. Convert the existing 8 m chunk and L29 bands exactly. R2’s FI/SW split is handled here by the already-present common layout width; retain owner/Core ratios only in the legacy FI parameter adapter. Run **fast + medium** (layout, transition, passage checks). | No for equivalent existing layouts; hashes must match. | Negative-Z floor/rounding, old season snapshots, adapter and manager disagreeing about interval edges. | M |
| 4 | Introduce metre-valued authored height/gap/transition/passage dimensions and a per-strate `voxelSizeMeters` default of 0.25. Add a versioned conversion from old chunk/voxel assets based on each legacy route’s established unit; do not assume the source unit is recorded on the asset or reinterpret old numeric values as metres. Keep 8 m layout chunk independent. **Fast + medium** for old assets; full when enabling non-default resolutions. | No for converted old assets. Yes for changed metre values or voxel size; bump layout/recipe/evaluator identity. | Asset migration and resolution-dependent detail; changing 25 cm to 12.5 cm can mean about 8× samples per physical volume. | L |
| 5 | Route all new and existing passage requests through resolved per-strate configs and a shared route plan. First copy existing SW/FI route anchors exactly; replace FI-root and SurfaceWorld placement branches with explicit resolved anchor/surface capabilities in follow-up slices. Run **fast + medium** passage matrix and route parity. | No for exact route replay; hashes must match. New geometry/style semantics are Yes and need a generator/layout version bump. | Walkability/support, deterministic placement, route planning cost. | M |
| 6 | Move remaining boundary exceptions into explicit interface records/capabilities. Keep ceiling → content → breakable bedrock per strate and the upper strate’s Hard/Gradient/Interleaved rule. Preserve L29 samples and passage-mouth fade exactly. Run **fast + medium** transition, hole, and passage gates. | No; hashes must match. | Interface edge ownership and a false solid/air shortcut can open a hole. | M |
| 7 | Standardize culling outputs: conservative support bounds, interval certificates, unknown fallback, and detail envelope. Adapt existing field proofs first; replace type switches only when the new proof matches brute-force/classification controls. Run **fast**, then **medium** proof negatives and cost pairs. | No; hashes must match. | Unsound certificates skip density work; per-voxel bounds calls hurt performance. | M/L |
| 8 | Make `World::generateTile` and the mesher consume generic feature boxes, semantic surfaces, field bounds, and sample-spacing hints. Move current SurfaceWorld refinements behind capabilities while keeping their algorithms byte-for-byte. Run **fast + medium** ring/shape checks. | No for dispatch-only refactor; hashes must match. | Cross-LOD seams, tile halos, mixed-resolution tile boundaries, Unreal mesher assumptions. | L |
| 9 | Add an opt-in metre-native TunnelNetwork/cavern recipe through the contract and generic mesher interface. Run **medium** on the new recipe and R5 **full** before enabling it in owner layouts. | Yes for worlds selecting it; bump that generator’s recipe/evaluator version. | New density cost and output identity. | M/L |
| 10 | Implement the L20 shared, LOD-stable surface/transition representation to remove measured ring ledges. Run **medium** ring/shape checks and R5 **full** on the final tree. | Yes; bump the mesher/layout version and establish new golden hashes. | Surface topology and cross-LOD transitions change; coarse sampling may erase thin bands. | L |
R5’s draft timings are about **3–4 min fast**, **8–10 min additional medium**, and **32–34 min full**, excluding builds. Run fast for every step: output-neutral slices must match existing hashes; output-changing slices must match their new versioned golden hashes. Medium is required before promoting layout, route, culling, or mesher changes. Full is final-source evidence after output-changing versions and golden hashes are reviewed. Include the actual owner configs and assert their resolved styles, as R5 requires; do not treat style-override fixtures as owner evidence.
### Cross-cutting risks
- **Determinism:** convert metres to integer micrometres once; use a specified tie rule and mathematical floor for negative coordinates; hash resolved parameters, voxel size, generator versions, and interface records in stable order. Keep floating-point contraction/platform checks for the compatibility evaluator.
- **Per-voxel cost:** eliminate manager/recipe selection from the hot call, pre-resolve field objects and tile candidates, and keep unknown proofs conservative. Benchmark actual FI2 and SW1 with R5 cost pairs at medium/full. A finer voxel size is cubic work growth, not a cheap resolution toggle.
- **Unreal adapter:** `VoxelForgeCoreAdapter.cpp` currently serializes UObject parameters into Core fixed units; new reflected metre fields need versioned asset migration and UHT/UBT validation. R2 also recorded that recent adapter changes had no Unreal build evidence. Static research cannot establish that compile boundary.
## Open question for the owner
Should existing voxel-authored assets retain their current physical dimensions through a per-generator compatibility conversion? Recommended: yes, then author new recipes in metres. Reinterpreting old values at 25 cm would rescale worlds and require broad output-version bumps.
@@ -0,0 +1,14 @@
# Shared notes (researcher R6 <-> implementer L39), newest at bottom
## R5 read-only architecture findings (2026-10-23)
Inspected `Standalone/BuildLinux.sh`, `Build.ps1`, `Core/core_sources.txt`, `Source/StreamBenchmarkHeadless.cpp`, `Source/LinuxOffscreenCapture.cpp`, `data/owner_world.json`, the L37 passage/invariant/legacy/ring/capture/crease/fragment runners, `Saved/Linux/l37/mouth-curves-run/layout-owner-fi.json`, and the R5/L37 reports. No source was changed and no binary was run.
- `BuildLinux.sh` reads `Core/core_sources.txt`, generates wrapper translation units under `Standalone/Build`, compiles the Core and compatibility objects, then links `VoxelForgeCoreHeadless-$VARIANT`. It separately compiles `LinuxOffscreenCapture.cpp` into `VoxelForgeOffscreenCapture-$VARIANT`. The generated wrappers/objects are build outputs; the stamp manifest should hash the listed original source paths, `core_sources.txt`, both standalone executable sources, and the build scripts. No stamp exists today. The script already enforces `taskset -c 0-11` plus `prlimit --as=6442450944` and rejects `--jobs` above 12.
- There are two executable entry points to stamp. `StreamBenchmarkHeadless.cpp` parses options before its first current log (`[HeadlessConfig]`); `LinuxOffscreenCapture.cpp` checks `argc` before logging. Print the source stamp at the start of both `main`s, before parse/validation. A cheap stamp-only option on each binary would let the shared runner reject stale binaries before expensive work.
- The canonical JSON contains FI `PassageConfig.Style=2` and SW `PassageConfig.Style=1`. The checked-in L37 capture and passage runners label `linux25-owner-*-style0.json` as `owner-*`; those are style overrides. In an existing resolved snapshot, each `strates[]` entry has `generator_kind`, `recipe_id`, and IDs, while `passages[]` has geometry, but neither exposes the effective style. The requested style assertion cannot be made from the current snapshot: add the resolved passage style per strate to its serialization, then assert FI=2/SW=1. `stable_identity` is the existing layout ID (`resolved-layout-v3-fnv64:…`); the recipe audit log reports recipe but not style.
- The L37 runners each create their own subprocess wrappers and summaries. A shared helper can centralize the constrained invocation, stamp-only preflight, expected-stamp recomputation, binary/input SHA-256, resolved-layout extraction, and a common summary row (stamp, binary hash, input hash, actual recipe/style/layout ID, elapsed time). Recompute the manifest after the tier. Resolve the canonical layout once per owner case and use that same snapshot for all gates/captures.
- `CapturePassageStandardSetL37.py` and `CaptureMouthOverviewL37.py` only check JPEG size. An all-black JPEG therefore passes. Add decoded-pixel variance/coverage validation (without PIL, which the earlier research could not import) and include a black-image negative control.
- `RunMouthCreaseAuditL37.py` imports the fragment audit. For each candidate it reads the mesh once in `BASE.audit`, then `visible_crease` reads it again for the near view and again for overview. A combined analyzer can decode once, then share triangles/buckets for fragment, crease, and both views. Existing overview check matters: L37 passed near at 4.40° but measured 25.54° against 20° at overview.
- `RunRingAuditsL37.py` already keeps the L30 terrace and L31 flat meshes as live controls; the full LOD0–8 work is separate from targeted LOD0 checks. The R5 split can reuse `AuditRingTerraceL32.py` directly for fast LOD0 plus those controls.
+5 -1
View File
@@ -1,9 +1,12 @@
#include "SourceStamp.h"
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include <GLES3/gl3.h> #include <GLES3/gl3.h>
#include <png.h> #include <png.h>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
@@ -810,6 +813,8 @@ void main()
int main(int argc,char** argv) int main(int argc,char** argv)
{ {
VoxelForgePrintSourceStamp();
if(argc==2&&std::string_view(argv[1])=="--print-source-stamp")return 0;
if(argc<3) if(argc<3)
{ {
std::fprintf(stderr,"Usage: %s scene.vfmesh output.png [--size=WIDTHxHEIGHT] [--fov-deg=90] [--height-range-m=N] [--height-center-m=N] [--camera-m=X,Y,Z] [--yaw-deg=N] [--pitch-deg=N] [--shade=readable|normal] [--height-tint=on|off] [--headlamp=on|off] [--light-direction=X,Y,Z] [--tile-edges=on|off] [--tile-skirts=on|off] [--tile-edge-width-m=N] [--clip-plane=NX,NY,NZ,D] [--focus-region=X,Y,Z,R]\n",argv[0]); std::fprintf(stderr,"Usage: %s scene.vfmesh output.png [--size=WIDTHxHEIGHT] [--fov-deg=90] [--height-range-m=N] [--height-center-m=N] [--camera-m=X,Y,Z] [--yaw-deg=N] [--pitch-deg=N] [--shade=readable|normal] [--height-tint=on|off] [--headlamp=on|off] [--light-direction=X,Y,Z] [--tile-edges=on|off] [--tile-skirts=on|off] [--tile-edge-width-m=N] [--clip-plane=NX,NY,NZ,D] [--focus-region=X,Y,Z,R]\n",argv[0]);
@@ -1037,4 +1042,3 @@ int main(int argc,char** argv)
HeightTint,Headlamp,TileEdges, HeightTint,Headlamp,TileEdges,
TileEdgeWidthMeters,HasLightDirection,LightDirection,ClipPlaneEnabled,ClipPlane)?0:3; TileEdgeWidthMeters,HasLightDirection,LightDirection,ClipPlaneEnabled,ClipPlane)?0:3;
} }
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <cstdio>
#ifndef VOXELFORGE_SOURCE_STAMP
#define VOXELFORGE_SOURCE_STAMP "UNSTAMPED"
#endif
inline void VoxelForgePrintSourceStamp() noexcept
{
std::printf("[VoxelForgeSourceStamp] sha256=%s\n", VOXELFORGE_SOURCE_STAMP);
std::fflush(stdout);
}
+35 -1
View File
@@ -1,3 +1,4 @@
#include "SourceStamp.h"
#include "OwnerWorldLoader.h" #include "OwnerWorldLoader.h"
#include "StandaloneCoreScheduler.h" #include "StandaloneCoreScheduler.h"
#include "StreamBenchmarkPipeline.h" #include "StreamBenchmarkPipeline.h"
@@ -316,6 +317,8 @@ namespace
int main(int argc,char** argv) int main(int argc,char** argv)
{ {
VoxelForgePrintSourceStamp();
if(argc==2&&std::string_view(argv[1])=="--print-source-stamp")return 0;
using Clock=std::chrono::steady_clock; using Clock=std::chrono::steady_clock;
const auto coldStart=Clock::now(); const auto coldStart=Clock::now();
FOptions options; FOptions options;
@@ -402,13 +405,33 @@ int main(int argc,char** argv)
if(!roundTrip||roundTrip->ToJson()!=layoutJson||roundTrip->stableIdentity!=resolvedLayout.stableIdentity) if(!roundTrip||roundTrip->ToJson()!=layoutJson||roundTrip->stableIdentity!=resolvedLayout.stableIdentity)
{if(error.empty())error="resolved-layout canonical serialization did not round-trip"; {if(error.empty())error="resolved-layout canonical serialization did not round-trip";
std::fprintf(stderr,"Resolved-layout round trip failed: %s\n",error.c_str());return 2;} std::fprintf(stderr,"Resolved-layout round trip failed: %s\n",error.c_str());return 2;}
std::string resolvedStrateStyles="{";
bool firstResolvedStrateStyle=true;
for(const FStrateSlot& slot:ownerWorld->Manager->GetLayout())
{
if(!slot.Definition)continue;
const auto resolvedStrate=std::find_if(resolvedLayout.strates.begin(),
resolvedLayout.strates.end(),[&](const auto& value)
{return value.strateIndex==slot.StrateIndex;});
if(resolvedStrate==resolvedLayout.strates.end())continue;
const auto style=static_cast<std::uint32_t>(slot.Definition->PassageConfig.Style);
if(!firstResolvedStrateStyle)resolvedStrateStyles+=',';
firstResolvedStrateStyle=false;
resolvedStrateStyles.push_back('"');
resolvedStrateStyles+=std::to_string(slot.StrateIndex);
resolvedStrateStyles+="\":";
resolvedStrateStyles+=std::to_string(style);
}
resolvedStrateStyles+='}';
const std::string layoutOutputJson=layoutJson.substr(0,layoutJson.size()-1)
+",\"resolved_strate_passage_styles\":"+resolvedStrateStyles+"}";
if(!options.ResolvedLayoutOutputPath.empty()) if(!options.ResolvedLayoutOutputPath.empty())
{ {
if(!options.ResolvedLayoutOutputPath.parent_path().empty()) if(!options.ResolvedLayoutOutputPath.parent_path().empty())
std::filesystem::create_directories(options.ResolvedLayoutOutputPath.parent_path()); std::filesystem::create_directories(options.ResolvedLayoutOutputPath.parent_path());
std::ofstream output(options.ResolvedLayoutOutputPath,std::ios::binary); std::ofstream output(options.ResolvedLayoutOutputPath,std::ios::binary);
if(!output){std::fprintf(stderr,"Could not write resolved-layout snapshot: %s\n",options.ResolvedLayoutOutputPath.c_str());return 2;} if(!output){std::fprintf(stderr,"Could not write resolved-layout snapshot: %s\n",options.ResolvedLayoutOutputPath.c_str());return 2;}
output.write(layoutJson.data(),static_cast<std::streamsize>(layoutJson.size())); output.write(layoutOutputJson.data(),static_cast<std::streamsize>(layoutOutputJson.size()));
if(!output){std::fprintf(stderr,"Resolved-layout snapshot write failed: %s\n",options.ResolvedLayoutOutputPath.c_str());return 2;} if(!output){std::fprintf(stderr,"Resolved-layout snapshot write failed: %s\n",options.ResolvedLayoutOutputPath.c_str());return 2;}
} }
const auto controls=VoxelForgeCore::AuditResolvedLayoutValidatorV3(); const auto controls=VoxelForgeCore::AuditResolvedLayoutValidatorV3();
@@ -423,6 +446,17 @@ int main(int argc,char** argv)
VoxelForgeCore::ResolvedLayoutValidationModeV3::strict,strictIssues,strictError); VoxelForgeCore::ResolvedLayoutValidationModeV3::strict,strictIssues,strictError);
std::printf("[ResolvedLayoutSnapshot] schema=%u stable_identity=%s strata=%zu bytes=%zu round_trip=PASS\n", std::printf("[ResolvedLayoutSnapshot] schema=%u stable_identity=%s strata=%zu bytes=%zu round_trip=PASS\n",
resolvedLayout.schemaVersion,resolvedLayout.stableIdentity.c_str(),resolvedLayout.strates.size(),layoutJson.size()); resolvedLayout.schemaVersion,resolvedLayout.stableIdentity.c_str(),resolvedLayout.strates.size(),layoutJson.size());
for(const FStrateSlot& slot:ownerWorld->Manager->GetLayout())
{
if(!slot.Definition)continue;
const auto resolvedStrate=std::find_if(resolvedLayout.strates.begin(),
resolvedLayout.strates.end(),[&](const auto& value)
{return value.strateIndex==slot.StrateIndex;});
if(resolvedStrate!=resolvedLayout.strates.end())
std::printf("[ResolvedStratePassageStyle] strate_index=%d generator_kind=%s style=%u\n",
slot.StrateIndex,resolvedStrate->generatorKind.c_str(),
static_cast<std::uint32_t>(slot.Definition->PassageConfig.Style));
}
const auto requestedRecipe=options.FloatingIslandsRecipe const auto requestedRecipe=options.FloatingIslandsRecipe
?std::string_view("floating-islands"):std::string_view("surface-world"); ?std::string_view("floating-islands"):std::string_view("surface-world");
const auto topStratum=std::max_element(resolvedLayout.strates.begin(),resolvedLayout.strates.end(), const auto topStratum=std::max_element(resolvedLayout.strates.begin(),resolvedLayout.strates.end(),
+19
View File
@@ -0,0 +1,19 @@
# VoxelForge verification
Build stamped Linux executables and run one of the three verification tiers from the repository root. Artifacts and logs go under `Saved/Linux/l39` by default.
```sh
taskset -c 0-11 prlimit --as=6442450944 -- timeout 1740s env VOXELFORGE_BUILD_ROOT=Saved/Linux/l39/build VOXELFORGE_BIN_DIR=Saved/Linux/l39/bin Standalone/BuildLinux.sh --compiler=clang++-19 --variant=l39-clang --jobs=12
taskset -c 0-11 prlimit --as=6442450944 -- timeout 1740s env VOXELFORGE_BUILD_ROOT=Saved/Linux/l39/build VOXELFORGE_BIN_DIR=Saved/Linux/l39/bin Standalone/BuildLinux.sh --compiler=g++ --variant=l39-gcc --jobs=12
taskset -c 0-11 prlimit --as=6442450944 -- timeout 1740s python3 -B Standalone/Tools/verify/verify.py fast
taskset -c 0-11 prlimit --as=6442450944 -- timeout 1740s python3 -B Standalone/Tools/verify/verify.py medium
taskset -c 0-11 prlimit --as=6442450944 -- timeout 1740s python3 -B Standalone/Tools/verify/verify.py full
```
`fast` checks only canonical `Standalone/data/owner_world.json`, asserts FI Style 2 and SW Style 1 from resolved snapshots, runs passage wall/floor ripple and coverage gates, the adjacent-profile step limit, W1/W12 hash comparisons, and LOD0 ring profiles with the L30/L31 controls. It also exercises stale-source, style-mislabel, black-capture, historical ripple, and L38 step controls.
`medium` adds the Clang style-override matrix, transitions, route/proof audits, LOD0–8 rings, and canonical-owner captures, shape, near/overview crease, and fragment checks. Run `medium` before `full`. Full reuses that evidence only when the source stamp, verification-tool hashes, binaries, inputs, logs, and audit-script hashes still match; otherwise it reruns the Clang medium work. It adds the owner/style/transition/proof matrix with GCC, the 30-cell determinism matrix, and five interleaved L36/L39 cost pairs per recipe. The final captures stay in the L39 output directory.
`BuildLinux.sh` hashes a sorted manifest of Core inputs, standalone sources and generated wrappers, build files, and optionally the Unreal adapter when `VOXELFORGE_INCLUDE_UNREAL_ADAPTER=1`. The manifest hash is compiled into the headless and offscreen binaries and printed before any other runtime log line. Each tier probes every available built executable at startup and re-probes it at completion, rejecting stale stamps or binary changes. Summaries store tool hashes, binary and JSON SHA-256 values, resolved recipe/style/layout identity, commands, elapsed time, and audit-script hashes.
Each tier stops at its first failed gate. Every process is limited to CPUs 0–11 and 6 GiB of address space; individual build and audit processes time out at 30 minutes. Summary files are `fast-summary.json`, `medium-summary.json`, and `full-summary.json`.
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""Reject empty and nearly black captures by decoding pixels and measuring coverage."""
from __future__ import annotations
import argparse
import math
from pathlib import Path
import subprocess
import sys
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
def inspect(path: Path) -> tuple[bool, str]:
probe = subprocess.run([*LIMIT, "timeout", "30s", "ffmpeg", "-nostdin",
"-hide_banner", "-loglevel", "error", "-i", str(path), "-frames:v", "1",
"-f", "rawvideo", "-pix_fmt", "rgb24", "pipe:1"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30, check=False)
if probe.returncode != 0 or not probe.stdout or len(probe.stdout) % 3:
return False, f"decode_failed exit={probe.returncode} bytes={len(probe.stdout)}"
raw = probe.stdout
count = len(raw) // 3
total = 0
square_total = 0
covered = 0
for index in range(0, len(raw), 3):
luminance = (77 * raw[index] + 150 * raw[index + 1] + 29 * raw[index + 2]) >> 8
total += luminance
square_total += luminance * luminance
covered += luminance > 12
mean = total / count
variance = max(0.0, square_total / count - mean * mean)
deviation = math.sqrt(variance)
coverage = covered / count
passed = deviation >= 2.0 and coverage >= 0.001
return passed, (f"pixels={count} mean_luma={mean:.3f} stddev_luma={deviation:.3f} "
f"coverage_luma_gt12={coverage:.5f} thresholds=(stddev>=2.0,coverage>=0.001)")
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("image", type=Path)
args = parser.parse_args()
if not args.image.is_file():
print(f"[CaptureQuality] image={args.image} status=FAIL reason=missing")
return 1
passed, detail = inspect(args.image)
print(f"[CaptureQuality] image={args.image} {detail} status={'PASS' if passed else 'FAIL'}")
return 0 if passed else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
"""Apply current ripple limits to retained L35 wall-rib and L36 washboard logs."""
from __future__ import annotations
import argparse
from pathlib import Path
import re
def records(path: Path) -> list[dict[str, float | str]]:
result = []
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
if "[PassageRippleAudit]" not in line:
continue
values = dict(re.findall(r"(?:^| )([a-z_]+)=([-0-9.]+)", line))
def ratio(key: str) -> str:
match = re.search(rf"(?:^| ){key}=([0-9]+)/([0-9]+)", line)
return (str(int(match.group(1)) / max(1, int(match.group(2))))
if match else "nan")
try:
item: dict[str, float | str] = {
"local_peak_amplitude_m": float(values.get(
"local_peak_amplitude_m", values.get("amplitude_m", "nan"))),
"floor_amplitude_m": float(values.get("floor_amplitude_m", "nan")),
"wall_coverage": float(ratio("coverage")),
"floor_coverage": float(ratio("floor_coverage")),
"status": "FAIL" if "status=FAIL" in line else "PASS",
}
except ValueError:
continue
result.append(item)
return result
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("kind", choices=("wall-ribs", "floor-washboard"))
parser.add_argument("log", type=Path)
args = parser.parse_args()
entries = records(args.log)
if args.kind == "wall-ribs":
candidates = [entry for entry in entries if
float(entry["local_peak_amplitude_m"]) > 0.035
or float(entry["wall_coverage"]) < 0.75]
metric = max((float(entry["local_peak_amplitude_m"]) for entry in candidates),
default=0.0)
detail = f"max_wall_amplitude_m={metric:.4f} threshold_m=0.035"
else:
candidates = [entry for entry in entries if
float(entry["floor_amplitude_m"]) > 0.015
or float(entry["floor_coverage"]) < 0.75]
metric = max((float(entry["floor_amplitude_m"]) for entry in candidates),
default=0.0)
detail = f"max_floor_amplitude_m={metric:.4f} threshold_m=0.015"
detected = bool(candidates)
print(f"[HistoricalRippleControl] kind={args.kind} log={args.log} "
f"records={len(entries)} {detail} detected={str(detected).lower()} "
f"status={'PASS' if detected else 'FAIL'}")
return 0 if detected else 1
if __name__ == "__main__":
raise SystemExit(main())
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""Measure adjacent route-relative mouth-profile steps; period fits are diagnostic."""
from __future__ import annotations
import argparse
from collections import defaultdict
from pathlib import Path
import re
import sys
PROFILE = re.compile(
r"\[PassageFloorRippleSample\] id=(\S+) distance_m=([-0-9.]+).*?"
r"residual_m=([-0-9.]+)")
RIPPLE = re.compile(r"\[PassageRippleAudit\] id=(\S+).*?period_m=([-0-9.]+)")
STEP_LIMIT_M = 0.100
MAX_ADJACENT_DISTANCE_M = 0.750
def measure(text: str) -> dict[str, object]:
profiles: dict[str, list[tuple[float, float]]] = defaultdict(list)
for match in PROFILE.finditer(text):
passage, distance, residual = match.groups()
profiles[passage].append((float(distance), float(residual)))
adjacent: list[tuple[float, str, float, float]] = []
group_counts: dict[str, int] = {}
for key, samples in profiles.items():
samples.sort()
group_counts[key] = len(samples)
for before, after in zip(samples, samples[1:]):
delta_d = abs(after[0] - before[0])
if delta_d <= MAX_ADJACENT_DISTANCE_M:
adjacent.append((abs(after[1] - before[1]), key, before[0], after[0]))
periods = {passage: float(period) for passage, period in RIPPLE.findall(text)}
maximum = max((item[0] for item in adjacent), default=0.0)
return {
"maximum_adjacent_step_m": maximum,
"adjacent_pairs": len(adjacent),
"profile_groups": len(profiles),
"profile_group_counts": group_counts,
"fitted_periods_m": periods,
"passed": bool(adjacent) and maximum <= STEP_LIMIT_M,
"worst": max(adjacent, default=None),
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("log", type=Path)
parser.add_argument("--expect-fail", action="store_true",
help="pass only when the adjacent-step limit is exceeded")
args = parser.parse_args()
result = measure(args.log.read_text(encoding="utf-8", errors="replace"))
detected = not bool(result["passed"])
ok = detected if args.expect_fail else not detected
print(f"[OwnerAdjacentProfileStep] log={args.log} pairs={result['adjacent_pairs']} "
f"groups={result['profile_groups']} max_step_m={result['maximum_adjacent_step_m']:.6f} "
f"limit_m={STEP_LIMIT_M:.3f} max_adjacent_distance_m={MAX_ADJACENT_DISTANCE_M:.3f} "
f"fitted_periods_m={result['fitted_periods_m']} "
"period_role=diagnostic "
f"detected={str(detected).lower()} status={'PASS' if ok else 'FAIL'}")
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())
+396
View File
@@ -0,0 +1,396 @@
#!/usr/bin/env python3
"""Shared source-stamp, process, and per-run evidence helpers for verify.py."""
from __future__ import annotations
import hashlib
import json
import os
from pathlib import Path
import re
import subprocess
import sys
import time
from typing import Any
from source_stamp import source_stamp
ROOT = Path(__file__).resolve().parents[3]
OUT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l39"))
LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"]
RECIPE_RE = re.compile(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
re.M)
STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]{64})$")
def sha256_file(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 script_hash(path: Path) -> str:
return sha256_file(path) if path.is_file() else "MISSING"
def verification_tool_hashes() -> dict[str, str]:
return {str(path): sha256_file(path) for path in sorted(
Path(__file__).resolve().parent.glob("*.py"))}
def current_stamp() -> str:
include_unreal = os.environ.get("VOXELFORGE_INCLUDE_UNREAL_ADAPTER", "0") == "1"
return source_stamp(ROOT, include_unreal)
def first_stamp(text: str) -> str | None:
first = text.splitlines()[0] if text.splitlines() else ""
match = STAMP_RE.fullmatch(first)
return match.group(1) if match else None
def bounded_run(command: list[str], *, timeout: int = 1800,
cwd: Path = ROOT, env: dict[str, str] | None = None,
stdout: Any = subprocess.PIPE) -> subprocess.CompletedProcess[str] | None:
try:
return subprocess.run([*LIMIT, "timeout", f"{timeout}s", *map(str, command)],
cwd=cwd, env=env, stdout=stdout, stderr=subprocess.STDOUT,
text=True, encoding="utf-8", errors="replace", timeout=timeout,
check=False)
except subprocess.TimeoutExpired:
return None
class VerificationRunner:
def __init__(self, tier: str):
self.tier = tier
self.started = time.monotonic()
self.expected = current_stamp()
self.tool_hashes = verification_tool_hashes()
self.runs: list[dict[str, Any]] = []
self.steps: list[dict[str, Any]] = []
self.binary_hashes: dict[str, str] = {}
self.binary_stamp_overrides: dict[str, str] = {}
self.reused_tiers: list[dict[str, Any]] = []
OUT.mkdir(parents=True, exist_ok=True)
def assert_current_tree(self, point: str) -> None:
now = current_stamp()
if now != self.expected:
raise RuntimeError(
f"source changed {point}: expected {self.expected}, recomputed {now}")
tools_now = verification_tool_hashes()
if tools_now != self.tool_hashes:
raise RuntimeError(f"verification tool changed {point}: "
f"expected {self.tool_hashes}, recomputed {tools_now}")
def reuse_passed_tier(self, path: Path, tier: str) -> bool:
"""Reuse a completed tier only while all its source and evidence inputs match."""
self.assert_current_tree(f"before reusing {tier}")
if not path.is_file():
return False
try:
summary = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
return False
if (summary.get("tier") != tier or summary.get("status") != "PASS"
or summary.get("source_stamp") != self.expected
or summary.get("verification_tools") != self.tool_hashes):
return False
if any(row.get("status") not in ("PASS", "EXPECTED_FAIL")
or row.get("source_stamp") != self.expected
for row in summary.get("runs", [])):
return False
if any(row.get("status") != "PASS" for row in summary.get("checks", [])):
return False
for binary, digest in summary.get("binary_sha256", {}).items():
binary_path = Path(binary)
if not binary_path.is_file() or sha256_file(binary_path) != digest:
return False
for row in summary.get("runs", []):
input_path = row.get("input_json")
if input_path:
path_input = Path(input_path)
if (not path_input.is_file()
or sha256_file(path_input) != row.get("input_json_sha256")):
return False
log_path = row.get("log")
if log_path and not Path(log_path).is_file():
return False
for script, digest in row.get("audit_scripts", {}).items():
script_path = Path(script)
if not script_path.is_file() or sha256_file(script_path) != digest:
return False
digest = sha256_file(path)
self.runs.extend(summary.get("runs", []))
self.steps.extend(summary.get("checks", []))
self.binary_hashes.update(summary.get("binary_sha256", {}))
self.reused_tiers.append({
"tier": tier, "summary": str(path), "summary_sha256": digest,
"elapsed_seconds": summary.get("elapsed_seconds"),
"source_stamp": self.expected,
})
self.assert_current_tree(f"after reusing {tier}")
print(f"[{self.tier}] reuse-{tier} PASS "
f"prior_elapsed={summary.get('elapsed_seconds', 0):.1f}s "
f"source_stamp={self.expected}", flush=True)
return True
def probe_binary(self, binary: Path, expected_stamp: str | None = None) -> tuple[str, str]:
self.assert_current_tree(f"before probing {binary.name}")
if not binary.is_file():
raise RuntimeError(f"missing executable: {binary}")
digest = sha256_file(binary)
expected_stamp = expected_stamp or self.binary_stamp_overrides.get(str(binary), self.expected)
proc = bounded_run([str(binary), "--print-source-stamp"], timeout=15)
output = proc.stdout or "" if proc is not None else ""
embedded = first_stamp(output)
if proc is None or proc.returncode != 0 or embedded is None:
raise RuntimeError(f"{binary} has no usable source stamp; probe output: {output[:300]}")
if embedded != expected_stamp:
raise RuntimeError(
f"stale executable refused: {binary.name} has {embedded}, expected {expected_stamp}")
previous = self.binary_hashes.get(str(binary))
if previous is not None and previous != digest:
raise RuntimeError(f"executable changed during verification: {binary.name}; "
f"was {previous}, now {digest}")
self.binary_hashes[str(binary)] = digest
self.assert_current_tree(f"after probing {binary.name}")
return embedded, digest
def assert_binaries_current(self) -> None:
for binary in tuple(self.binary_hashes):
self.probe_binary(Path(binary))
@staticmethod
def layout_metadata(layout_path: Path) -> tuple[str | None, tuple[int, ...], dict[str, Any]]:
if not layout_path.is_file():
return None, (), {}
data = json.loads(layout_path.read_text(encoding="utf-8"))
styles = tuple(sorted({int(passage["style"]) for passage in data.get("passages", [])
if "style" in passage}))
resolved_strate_styles = {str(index): int(value) for index, value in
data.get("resolved_strate_passage_styles", {}).items()}
strata = {int(stratum.get("strate_index", stratum.get("index", -1))): stratum
for stratum in data.get("strates", [])}
details = {
"layout_id": data.get("stable_identity"),
"layout_schema": data.get("schema_version"),
"passage_styles": styles,
"strata": {str(index): value.get("generator_kind")
for index, value in strata.items()},
"resolved_strate_styles": resolved_strate_styles,
"generator_passage_styles": {
value.get("generator_kind"): resolved_strate_styles[str(index)]
for index, value in strata.items()
if str(index) in resolved_strate_styles},
"passages": [{"id": value.get("stable_id"),
"upper": value.get("upper_strate_index"),
"lower": value.get("lower_strate_index"),
"style": value.get("style")}
for value in data.get("passages", [])],
}
return details["layout_id"], styles, details
def run_cpp(self, name: str, binary: Path, data: Path, recipe: str,
flags: list[str], *, expected_style: int | None = None,
workers: int = 12, timeout: int = 1800,
layout_path: Path | None = None,
max_level: int = -1,
expected_strate_styles: dict[str, int] | None = None,
script_inputs: list[Path] | None = None,
allow_nonzero: bool = False,
expected_stamp: str | None = None) -> tuple[dict[str, Any], str]:
stamp, binary_digest = self.probe_binary(binary, expected_stamp)
if not data.is_file():
raise RuntimeError(f"missing input JSON: {data}")
data_digest = sha256_file(data)
layout_path = layout_path or (OUT / "layouts" / f"{name}.json")
layout_path.parent.mkdir(parents=True, exist_ok=True)
clean_flags = [flag for flag in flags if not flag.startswith("--resolved-layout-output=")]
command = [str(binary), str(data), f"--workers={workers}",
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
"--force-generate", "--clip-radius=3", "--max-clip-level=8",
f"--max-level={max_level}",
f"--recipe={recipe}", *clean_flags, f"--resolved-layout-output={layout_path}"]
log = OUT / f"{name}.log"
log.parent.mkdir(parents=True, exist_ok=True)
started = time.monotonic()
with log.open("w", encoding="utf-8") as stream:
proc = bounded_run(command, timeout=timeout, stdout=stream)
elapsed = time.monotonic() - started
output = log.read_text(encoding="utf-8", errors="replace") if log.exists() else ""
actual_stamp = first_stamp(output)
recipe_matches = RECIPE_RE.findall(output)
resolved_recipe = recipe_matches[-1][1] if recipe_matches else None
layout_id, styles, layout_details = self.layout_metadata(layout_path)
code: int | str = proc.returncode if proc is not None else "TIMEOUT"
stamp_ok = actual_stamp == stamp
recipe_ok = recipe_matches == [(recipe, recipe, "PASS")]
style_ok = expected_style is None or styles == (expected_style,)
actual_strate_styles = layout_details.get("resolved_strate_styles", {})
if expected_strate_styles is not None:
style_ok = style_ok and all(actual_strate_styles.get(str(index)) == value
for index, value in expected_strate_styles.items())
run_ok = (stamp_ok and recipe_ok and style_ok and proc is not None
and (allow_nonzero or proc.returncode == 0))
row: dict[str, Any] = {
"name": name, "tier": self.tier, "status": "PASS" if run_ok else "FAIL",
"elapsed_seconds": round(elapsed, 3), "exit_code": code,
"source_stamp": stamp, "binary": str(binary),
"compiler": "gcc" if "gcc" in binary.name else "clang",
"binary_sha256": binary_digest, "input_json": str(data),
"input_json_sha256": data_digest, "requested_recipe": recipe,
"resolved_recipe": resolved_recipe,
"requested_style": expected_style, "resolved_style": list(styles),
"style_id": ",".join(f"passage-style-{value}" for value in styles) or None,
"requested_strate_styles": expected_strate_styles,
"resolved_strate_styles": actual_strate_styles,
"resolved_generator_styles": layout_details.get("generator_passage_styles", {}),
"layout_id": layout_id, "layout": layout_details,
"log": str(log),
"audit_scripts": {str(path): script_hash(path) for path in (script_inputs or [])},
"command": command,
}
self.runs.append(row)
self.assert_current_tree(f"after run {name}")
self.print_step(row)
if not run_ok:
raise VerificationFailure(f"{name} failed (exit={code}, stamp={stamp_ok}, "
f"recipe={recipe_ok}, style={style_ok}); see {log}")
return row, output
def run_program(self, name: str, binary: Path, command: list[str], *,
data: Path | None, recipe: str | None, style: int | None,
layout_path: Path | None = None, timeout: int = 1800,
require_stamp_line: bool = True,
script_inputs: list[Path] | None = None) -> tuple[dict[str, Any], str]:
stamp, digest = self.probe_binary(binary)
data_digest = sha256_file(data) if data is not None and data.is_file() else None
log = OUT / f"{name}.log"
log.parent.mkdir(parents=True, exist_ok=True)
started = time.monotonic()
with log.open("w", encoding="utf-8") as stream:
proc = bounded_run(command, timeout=timeout, stdout=stream)
elapsed = time.monotonic() - started
output = log.read_text(encoding="utf-8", errors="replace")
layout_id, styles, details = self.layout_metadata(layout_path) if layout_path else (None, (), {})
code: int | str = proc.returncode if proc is not None else "TIMEOUT"
stamp_ok = not require_stamp_line or first_stamp(output) == stamp
ok = proc is not None and proc.returncode == 0 and stamp_ok
row = {
"name": name, "tier": self.tier, "status": "PASS" if ok else "FAIL",
"elapsed_seconds": round(elapsed, 3), "exit_code": code,
"source_stamp": stamp, "binary": str(binary), "binary_sha256": digest,
"compiler": "gcc" if "gcc" in binary.name else "clang",
"input_json": str(data) if data else None, "input_json_sha256": data_digest,
"requested_recipe": recipe, "resolved_recipe": recipe,
"requested_style": style, "resolved_style": list(styles),
"style_id": ",".join(f"passage-style-{value}" for value in styles) or
(f"passage-style-{style}" if style is not None else None),
"resolved_strate_styles": details.get("resolved_strate_styles", {}),
"resolved_generator_styles": details.get("generator_passage_styles", {}),
"layout_id": layout_id, "layout": details, "log": str(log),
"audit_scripts": {str(path): script_hash(path) for path in (script_inputs or [])},
"command": command,
}
self.runs.append(row)
self.assert_current_tree(f"after run {name}")
self.print_step(row)
if not ok:
raise VerificationFailure(f"{name} failed (exit={code}, stamp={stamp_ok}); see {log}")
return row, output
def run_stage(self, name: str, script: Path, args: list[str], *,
binary: Path, data: Path | None, recipe: str | None,
style: int | None, layout_path: Path | None = None,
env: dict[str, str] | None = None, timeout: int = 1800,
script_inputs: list[Path] | None = None) -> tuple[dict[str, Any], str]:
merged_env = os.environ.copy()
if env:
merged_env.update(env)
return self.run_program(name, binary,
[sys.executable, str(script), *args], data=data, recipe=recipe,
style=style, layout_path=layout_path, timeout=timeout,
require_stamp_line=False,
script_inputs=[script, *(script_inputs or [])]) if env is None else \
self._run_stage_with_env(name, script, args, binary, data, recipe, style,
layout_path, merged_env, timeout, script_inputs)
def _run_stage_with_env(self, name: str, script: Path, args: list[str],
binary: Path, data: Path | None, recipe: str | None,
style: int | None, layout_path: Path | None,
env: dict[str, str], timeout: int,
script_inputs: list[Path] | None) -> tuple[dict[str, Any], str]:
stamp, digest = self.probe_binary(binary)
data_digest = sha256_file(data) if data is not None and data.is_file() else None
log = OUT / f"{name}.log"
log.parent.mkdir(parents=True, exist_ok=True)
started = time.monotonic()
with log.open("w", encoding="utf-8") as stream:
proc = bounded_run([sys.executable, str(script), *args], timeout=timeout,
env=env, stdout=stream)
elapsed = time.monotonic() - started
output = log.read_text(encoding="utf-8", errors="replace")
layout_id, styles, details = self.layout_metadata(layout_path) if layout_path else (None, (), {})
code: int | str = proc.returncode if proc is not None else "TIMEOUT"
ok = proc is not None and proc.returncode == 0
row = {
"name": name, "tier": self.tier, "status": "PASS" if ok else "FAIL",
"elapsed_seconds": round(elapsed, 3), "exit_code": code,
"source_stamp": stamp, "binary": str(binary), "binary_sha256": digest,
"compiler": "gcc" if "gcc" in binary.name else "clang",
"input_json": str(data) if data else None, "input_json_sha256": data_digest,
"requested_recipe": recipe, "resolved_recipe": recipe,
"requested_style": style, "resolved_style": list(styles),
"style_id": ",".join(f"passage-style-{value}" for value in styles) or
(f"passage-style-{style}" if style is not None else None),
"resolved_strate_styles": details.get("resolved_strate_styles", {}),
"resolved_generator_styles": details.get("generator_passage_styles", {}),
"layout_id": layout_id, "layout": details, "log": str(log),
"audit_scripts": {str(path): script_hash(path)
for path in [script, *(script_inputs or [])]},
"command": [sys.executable, str(script), *args],
}
self.runs.append(row)
self.assert_current_tree(f"after stage {name}")
self.print_step(row)
if not ok:
raise VerificationFailure(f"{name} failed (exit={code}); see {log}")
return row, output
def print_step(self, row: dict[str, Any]) -> None:
print(f"[{self.tier}] {row['name']} {row['status']} "
f"{row.get('elapsed_seconds', 0):.1f}s "
f"recipe={row.get('resolved_recipe') or '-'} "
f"style={row.get('resolved_style') or '-'} "
f"layout={row.get('layout_id') or '-'}", flush=True)
def require(self, name: str, passed: bool, detail: str = "") -> None:
step = {"name": name, "status": "PASS" if passed else "FAIL", "detail": detail}
self.steps.append(step)
print(f"[{self.tier}] {name} {'PASS' if passed else 'FAIL'} {detail}", flush=True)
if not passed:
raise VerificationFailure(f"{name} failed: {detail}")
def save_summary(self, status: str, error: str | None = None) -> Path:
elapsed = time.monotonic() - self.started
summary = {
"tier": self.tier, "status": status, "elapsed_seconds": round(elapsed, 3),
"source_stamp": self.expected, "source_manifest_sha256": self.expected,
"verification_tools": self.tool_hashes,
"binary_sha256": self.binary_hashes, "runs": self.runs,
"checks": self.steps, "reused_tiers": self.reused_tiers, "error": error,
}
path = OUT / f"{self.tier}-summary.json"
path.write_text(json.dumps(summary, indent=2, sort_keys=True) + "\n",
encoding="utf-8")
print(f"[{self.tier}] SUMMARY {status} elapsed={elapsed:.1f}s file={path}", flush=True)
return path
class VerificationFailure(RuntimeError):
pass
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""Build and verify the final-source manifest used by Linux executables."""
from __future__ import annotations
import argparse
import hashlib
from pathlib import Path
import sys
def sha256(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def manifest_entries(root: Path, include_unreal: bool = False) -> list[tuple[str, bytes]]:
standalone = root / "Standalone"
files: set[Path] = set()
core = standalone / "Core"
for suffix in ("*.h", "*.hpp", "*.cpp", "*.txt"):
files.update(core.rglob(suffix))
source = standalone / "Source"
for suffix in ("*.h", "*.hpp", "*.cpp"):
files.update(source.glob(suffix))
for path in standalone.glob("Build*"):
if path.is_file():
files.add(path)
for suffix in ("*.cmake", "*.mk", "Makefile", "CMakeLists.txt"):
files.update(standalone.glob(suffix))
core_build = standalone / "Core"
for suffix in ("*.cmake", "*.mk", "Makefile", "CMakeLists.txt"):
files.update(core_build.glob(suffix))
helper = standalone / "Tools/verify/source_stamp.py"
if helper.is_file():
files.add(helper)
if include_unreal:
unreal = source / "VoxelForge"
for suffix in ("*.h", "*.hpp", "*.cpp", "*.cs"):
files.update(unreal.rglob(suffix))
entries = [(path.relative_to(root).as_posix(), path.read_bytes())
for path in files if path.is_file()]
# BuildLinux creates one namespace wrapper per listed Core implementation.
# Include each exact generated wrapper as a virtual source input.
source_list = core / "core_sources.txt"
for raw in source_list.read_text(encoding="utf-8").splitlines():
name = raw.split("#", 1)[0].strip()
if not name or name == "Core/src/VoxelForgeCore.cpp":
continue
source_path = standalone / name
if not source_path.is_file():
raise SystemExit(f"missing source listed in Core/core_sources.txt: {name}")
wrapper_name = "vfcore_" + "".join(c if c.isalnum() else "_" for c in name)
wrapper = ('#include "CoreNamespacePreamble.h"\n'
"namespace vfcore::detail\n{\n"
f'#include "{source_path}"\n'
"}\n").encode("utf-8")
entries.append((f"generated/wrappers/{wrapper_name}.cpp", wrapper))
return sorted(entries, key=lambda item: item[0])
def rendered_manifest(root: Path, include_unreal: bool = False) -> bytes:
lines = [f"{sha256(data)} {name}" for name, data in
manifest_entries(root, include_unreal)]
return ("\n".join(lines) + "\n").encode("utf-8")
def source_stamp(root: Path, include_unreal: bool = False) -> str:
return sha256(rendered_manifest(root, include_unreal))
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("command", choices=("stamp", "write-manifest"))
parser.add_argument("--root", type=Path,
default=Path(__file__).resolve().parents[3])
parser.add_argument("--output", type=Path)
parser.add_argument("--include-unreal-adapter", action="store_true")
args = parser.parse_args()
root = args.root.resolve()
manifest = rendered_manifest(root, args.include_unreal_adapter)
stamp = sha256(manifest)
if args.command == "write-manifest":
if args.output is None:
parser.error("write-manifest requires --output")
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_bytes(manifest)
print(stamp)
return 0
if __name__ == "__main__":
raise SystemExit(main())
+640
View File
@@ -0,0 +1,640 @@
#!/usr/bin/env python3
"""Run the reusable VoxelForge verification tiers: fast, medium, or full."""
from __future__ import annotations
import argparse
import hashlib
import json
import math
import os
from pathlib import Path
import re
import shutil
import statistics
import struct
import subprocess
import sys
import time
import zlib
ROOT = Path(__file__).resolve().parents[3]
VERIFY_DIR = ROOT / "Standalone/Tools/verify"
LINUX37 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux37"
OWNER = ROOT / "Standalone/data/owner_world.json"
OUT_DEFAULT = ROOT / "Saved/Linux/l39"
PARSER = argparse.ArgumentParser(description=__doc__)
PARSER.add_argument("tier", choices=("fast", "medium", "full"))
PARSER.add_argument("--out", type=Path, default=OUT_DEFAULT,
help="artifact directory (default: Saved/Linux/l39)")
ARGS = PARSER.parse_args()
OUT = ARGS.out.resolve()
os.environ["VOXELFORGE_VERIFY_OUT"] = str(OUT)
os.environ["PYTHONDONTWRITEBYTECODE"] = "1"
sys.dont_write_bytecode = True
sys.path.insert(0, str(VERIFY_DIR))
from owner_step import measure as measure_owner_step
from runner import VerificationFailure, VerificationRunner, bounded_run
from source_stamp import source_stamp
CLANG = OUT / "bin/VoxelForgeCoreHeadless-l39-clang"
GCC = OUT / "bin/VoxelForgeCoreHeadless-l39-gcc"
RENDERER = OUT / "bin/VoxelForgeOffscreenCapture-l39-clang"
HASH_RE = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
RECIPE_RE = re.compile(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", re.M)
def compiler_name(binary: Path) -> str:
return "gcc" if "gcc" in binary.name else "clang"
def env_for(*, capture: bool = False) -> dict[str, str]:
result = os.environ.copy()
result["VOXELFORGE_VERIFY_OUT"] = str(OUT)
result["VOXELFORGE_L37_OUT"] = str(OUT)
result["VOXELFORGE_L37_CAPTURE_DIR"] = str(OUT / "captures")
result["VOXELFORGE_L37_HEADLESS"] = str(CLANG)
result["VOXELFORGE_L37_RENDERER"] = str(RENDERER)
result["VOXELFORGE_VERIFY_HEADLESS"] = str(CLANG)
if capture:
result["LP_NUM_THREADS"] = "12"
result["XDG_CACHE_HOME"] = str(OUT / "xdg-cache")
return result
def all_match(text: str, pattern: str) -> bool:
return re.search(pattern, text, re.M) is not None
def parse_ratio(text: str, name: str) -> float | None:
match = re.search(rf"(?:^| ){re.escape(name)}=(\d+)/(\d+)", text)
return int(match.group(1)) / max(1, int(match.group(2))) if match else None
def validate_passage(runner: VerificationRunner, name: str, output: str) -> None:
required = (
("strict-layout", r"^\[ResolvedLayoutStrict\] accepted=true issues=0 error=$"),
("layout-controls", r"^\[ResolvedLayoutValidatorControls\].*status=PASS$"),
("walkability", r"^\[Walkability\] PASS"),
("floor-profile", r"^\[FloorProfileBlend\].*negative_controls=step_detected/slope_detected status=PASS$"),
("mouth-profile", r"^\[PassageMouthProfileAudit\].*status=PASS$"),
("route-binding", r"^\[ResolvedStrateRouteAudit\].*mouth_binding=PASS status=PASS$"),
("naturalness", r"^\[PassageNaturalnessSummary\].*status=PASS$"),
("open-air", r"^\[PassageOpenAirAuditSummary\].*status=PASS$"),
("no-long-bridge", r"^\[PassageNoLongBridgeAudit\].*status=PASS$"),
("rock-columns", r"^\[PassageRockColumnAuditSummary\].*status=PASS$"),
("ripple-controls", r"^\[PassageRippleAuditSummary\].*status=PASS$"),
("passage-summary", r"^\[ResolvedPassageAuditSummary\].*route_binding_failures=0 .*status=PASS$"),
)
for gate, pattern in required:
runner.require(f"{name}:{gate}", all_match(output, pattern),
"required resolved-passage gate")
rows = re.findall(r"^\[PassageRippleAudit\].*$", output, re.M)
ripple_ok = bool(rows)
for line in rows:
wall = re.search(r"local_peak_amplitude_m=([-0-9.]+)", line)
if wall is None:
wall = re.search(r"amplitude_m=([-0-9.]+)", line)
wall_threshold = re.search(r"threshold_m=([-0-9.]+)", line)
floor = re.search(r"floor_amplitude_m=([-0-9.]+)", line)
floor_threshold = re.search(r"floor_threshold_m=([-0-9.]+)", line)
wall_coverage = parse_ratio(line, "coverage")
floor_coverage = parse_ratio(line, "floor_coverage")
ripple_ok &= bool(
"status=PASS" in line and wall and wall_threshold and floor and floor_threshold
and wall_coverage is not None and floor_coverage is not None
and float(wall.group(1)) <= float(wall_threshold.group(1))
and float(floor.group(1)) <= float(floor_threshold.group(1))
and wall_coverage >= 0.75 and floor_coverage >= 0.75)
runner.require(f"{name}:wall-floor-ripple-and-coverage", ripple_ok,
f"profiles={len(rows)} wall/floor amplitudes under their thresholds; coverage>=0.75")
def run_passage(runner: VerificationRunner, binary: Path, name: str,
data: Path, recipe: str, style: int, *, workers: int = 12,
flags: list[str] | None = None, max_level: int = -1,
layout_path: Path | None = None, passage_style: int | None = None,
expected_strate_styles: dict[str, int] | None = None) -> tuple[dict, str]:
layout_path = layout_path or OUT / "layouts" / f"{name}.json"
row, output = runner.run_cpp(name, binary, data, recipe,
["--audit-resolved-layout-passages", *(flags or [])],
expected_style=style if passage_style is None else passage_style,
expected_strate_styles=expected_strate_styles,
workers=workers, max_level=max_level,
layout_path=layout_path)
row["requested_style"] = style
row["expected_passage_style"] = style if passage_style is None else passage_style
row["requested_strate_styles"] = expected_strate_styles
validate_passage(runner, name, output)
return row, output
def run_owner_passages(runner: VerificationRunner, binaries: tuple[Path, ...]) -> dict[str, tuple[dict, str]]:
result: dict[str, tuple[dict, str]] = {}
expected_strate_styles = {"0": 2, "1": 1}
for binary in binaries:
compiler = compiler_name(binary)
for recipe, style in (("floating-islands", 2), ("surface-world", 1)):
name = f"owner-{recipe}-style{style}-{compiler}"
row, output = run_passage(runner, binary, name, OWNER, recipe, style,
passage_style=2, expected_strate_styles=expected_strate_styles)
result[f"{compiler}:{recipe}"] = (row, output)
actual_styles = row.get("resolved_strate_styles", {})
runner.require(f"{name}:owner-style-map",
actual_styles == expected_strate_styles,
f"resolved_strate_styles={actual_styles} expected={expected_strate_styles}")
if compiler == "clang":
measured = measure_owner_step(output)
worst = measured.get("worst")
runner.require(f"{name}:adjacent-owner-step",
bool(measured["passed"]),
f"max_step_m={measured['maximum_adjacent_step_m']:.6f} "
f"limit_m=0.100 pairs={measured['adjacent_pairs']} "
f"fitted_periods_m={measured['fitted_periods_m']} "
f"period_role=diagnostic worst={worst}")
return result
def expected_control_row(runner: VerificationRunner, name: str) -> None:
if runner.runs:
row = runner.runs[-1]
row["observed_status"] = row["status"]
row["status"] = "EXPECTED_FAIL"
row["negative_control"] = name
def run_stamp_and_input_controls(runner: VerificationRunner) -> None:
# Mutate one compiled Core input only while checking that the runner refuses it.
core_file = ROOT / "Standalone/Core/src/VoxelForgeCore.cpp"
original = core_file.read_bytes()
rejected = False
try:
core_file.write_bytes(original + b"\n// temporary L39 stale-build negative control\n")
try:
runner.probe_binary(CLANG)
except RuntimeError as error:
rejected = "source changed" in str(error)
finally:
core_file.write_bytes(original)
runner.assert_current_tree("after restoring stale-build control")
runner.require("stale-build-source-edit-control", rejected,
"runner refused the binary after a Core source edit; original bytes restored")
fixture = ROOT / "Saved/Linux/l33/fixtures/sw-upper-tunnel-network-style0.json"
mislabelled = OUT / "controls/mislabelled-owner/owner_world.json"
mislabelled.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(fixture, mislabelled)
try:
runner.run_cpp("control-mislabelled-owner-style0", CLANG, mislabelled,
"floating-islands", ["--resolved-layout-only"], expected_style=2,
layout_path=OUT / "controls/mislabelled-owner/layout-owner.json")
detected = False
except VerificationFailure:
detected = bool(runner.runs and 0 in runner.runs[-1]["resolved_style"]
and runner.runs[-1]["status"] == "FAIL")
if detected:
expected_control_row(runner, "mislabelled-style0-input")
runner.require("mislabelled-owner-style-control", detected,
"style-0 fixture named owner_world.json rejected for expected FI Style 2")
black = OUT / "controls/all-black.png"
black.parent.mkdir(parents=True, exist_ok=True)
write_black_png(black)
script = VERIFY_DIR / "capture_quality.py"
try:
runner.run_stage("control-all-black-capture", script, [str(black)],
binary=CLANG, data=None, recipe=None, style=None,
env=env_for(), script_inputs=[black])
black_rejected = False
except VerificationFailure:
black_rejected = "status=FAIL" in (OUT / "control-all-black-capture.log").read_text(
encoding="utf-8", errors="replace")
if black_rejected:
expected_control_row(runner, "all-black-capture")
runner.require("all-black-capture-control", black_rejected,
"pixel variance and coverage floor reject a valid all-black PNG")
def write_black_png(path: Path) -> None:
def chunk(tag: bytes, payload: bytes) -> bytes:
return (struct.pack(">I", len(payload)) + tag + payload
+ struct.pack(">I", zlib.crc32(tag + payload) & 0xffffffff))
pixels = b"".join(b"\0" + b"\0\0\0" * 2 for _ in range(2))
body = (b"\x89PNG\r\n\x1a\n"
+ chunk(b"IHDR", struct.pack(">IIBBBBB", 2, 2, 8, 2, 0, 0, 0))
+ chunk(b"IDAT", zlib.compress(pixels)) + chunk(b"IEND", b""))
path.write_bytes(body)
def run_regression_controls(runner: VerificationRunner) -> None:
run_stamp_and_input_controls(runner)
controls = (
("l35-wall-ribs", "wall-ribs",
ROOT / "Saved/Linux/l35/failed/passage-audit-cascade-cosine-owner-fi-style3-clang.log"),
("l36-floor-washboard", "floor-washboard",
ROOT / "Saved/Linux/l36/audit-nearest-fi-style0.log"),
)
script = VERIFY_DIR / "historical_controls.py"
for name, kind, log in controls:
runner.run_stage(f"control-{name}", script, [kind, str(log)],
binary=CLANG, data=None, recipe=None, style=None,
env=env_for(), script_inputs=[log])
l38 = ROOT / "Saved/Linux/l38/owner-fi-real-final.log"
step_script = VERIFY_DIR / "owner_step.py"
runner.run_stage("control-l38-owner-step", step_script,
[str(l38), "--expect-fail"], binary=CLANG, data=None,
recipe=None, style=None, env=env_for(), script_inputs=[l38])
def run_hash_pairs(runner: VerificationRunner,
owner_results: dict[str, tuple[dict, str]]) -> None:
for recipe, style in (("floating-islands", 2), ("surface-world", 1)):
hashes: dict[int, tuple[str, ...]] = {}
for workers in (1, 12):
name = f"owner-hash-{recipe}-style{style}-w{workers}"
row, output = runner.run_cpp(name, CLANG, OWNER, recipe,
["--stream-hash"], expected_style=2,
expected_strate_styles={"0": 2, "1": 1}, workers=workers,
layout_path=OUT / "layouts" / f"{name}.json")
row["requested_style"] = style
row["expected_passage_style"] = 2
values = tuple(HASH_RE.findall(output))
hashes[workers] = values
runner.require(f"{name}:hash-count", len(values) == 12,
f"hashes={len(values)}/12")
same = hashes[1] == hashes[12]
baseline = ROOT / "Saved/Linux/l37" / f"determinism-l25-clang-{recipe}-w12.log"
old_hashes = tuple(HASH_RE.findall(baseline.read_text(encoding="utf-8", errors="replace")))
same_l37 = hashes[12] == old_hashes and len(old_hashes) == 12
runner.require(f"owner-hash-{recipe}-w1-w12", same,
"W1 and W12 each produced identical 12-hash signatures")
runner.require(f"owner-hash-{recipe}-matches-l37", same_l37,
f"current owner hashes match {baseline.name}; hashes={len(old_hashes)}")
def run_ring(runner: VerificationRunner, *, full: bool) -> None:
script = LINUX37 / "RunRingAuditsL37.py"
audit_inputs = [script,
ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py",
ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingSetL32.py"]
for label, recipe, style in (("fi-floor", "floating-islands", 2),
("sw-ceiling", "surface-world", 1)):
args = ["--scene", label]
layout = OUT / "layouts" / f"ring-layout-{label}-lod0.json"
if not full:
args.append("--lod0-only")
if label == "sw-ceiling":
args.append("--skip-controls")
runner.run_stage(f"ring-{label}-{'lod0-8' if full else 'lod0'}", script, args,
binary=CLANG, data=OWNER, recipe=recipe, style=style,
layout_path=layout, env=env_for(), script_inputs=audit_inputs)
def style_override_matrix(runner: VerificationRunner, binary: Path) -> None:
sources: list[tuple[str, Path, str]] = []
for recipe in ("floating-islands", "surface-world"):
for style in range(4):
source = ROOT / f"Saved/Linux/linux25-owner-{recipe}-style{style}.json"
sources.append((f"{recipe}-style{style}", source, recipe))
for style in range(4):
source = ROOT / f"Saved/Linux/l33/fixtures/sw-upper-tunnel-network-style{style}.json"
sources.append((f"upper-sw-fixture-style{style}", source, "floating-islands"))
for fixture_name, source, recipe in sources:
label = f"style-override-{fixture_name}"
destination = OUT / "fixtures" / f"{label}.json"
destination.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source, destination)
style = int(re.search(r"style([0-3])$", fixture_name).group(1))
name = f"{label}-{compiler_name(binary)}"
if fixture_name.startswith("upper-sw-fixture-"):
expected_strate_styles = {"1": style}
else:
expected_strate_styles = {"0": style, "1": 1}
row, output = runner.run_cpp(name, binary, destination, recipe,
["--audit-resolved-layout-passages"], expected_style=None,
expected_strate_styles=expected_strate_styles,
layout_path=OUT / "layouts" / f"{name}.json")
row["requested_style"] = style
row["requested_strate_styles"] = expected_strate_styles
validate_passage(runner, name, output)
def run_transitions_and_invariants(runner: VerificationRunner,
binaries: tuple[Path, ...]) -> None:
for binary in binaries:
compiler = compiler_name(binary)
for recipe, style in (("floating-islands", 2), ("surface-world", 1)):
for mode in ("hard", "gradient", "interleaved"):
name = f"transition-{recipe}-{mode}-{compiler}"
row, output = runner.run_cpp(name, binary, OWNER, recipe,
[f"--transition-mode={mode}", "--audit-strate-transitions"],
expected_style=2, expected_strate_styles={"0": 2, "1": 1},
layout_path=OUT / "layouts" / f"{name}.json")
row["requested_style"] = style
row["expected_passage_style"] = 2
gates = (r"^\[StrateTransitionAuditSummary\].*hole_columns=0 air_samples=0 .*status=PASS$",
r"^\[StrateTransitionNegativeControls\].*status=PASS$")
for index, pattern in enumerate(gates):
runner.require(f"{name}:gate-{index + 1}", all_match(output, pattern), pattern)
name = f"invariant-route-proof-{recipe}-{compiler}"
row, output = runner.run_cpp(name, binary, OWNER, recipe,
["--audit-uniform-block-proofs", "--audit-route-parity"],
expected_style=2, expected_strate_styles={"0": 2, "1": 1},
layout_path=OUT / "layouts" / f"{name}.json")
row["requested_style"] = style
row["expected_passage_style"] = 2
runner.require(f"{name}:route-parity",
all_match(output, r"^\[RouteParityAudit\].*status=PASS$"),
"route parity L13")
runner.require(f"{name}:uniform-block-proof",
all_match(output, r"^\[UniformBlockProofAudit\].*violations=0(?:\s|$)"),
"uniform-block proof L9")
def run_captures_and_mesh_audits(runner: VerificationRunner) -> None:
capture_script = LINUX37 / "CapturePassageStandardSetL37.py"
capture_inputs = [capture_script, VERIFY_DIR / "capture_quality.py",
ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py"]
capture_rows: dict[str, tuple[dict, str]] = {}
for scene, recipe, style in (("owner-fi", "floating-islands", 2),
("owner-sw", "surface-world", 1)):
layout_path = OUT / f"layout-{scene}.json"
name = f"capture-standard-{scene}-style{style}"
row, output = runner.run_stage(name, capture_script,
["--scene", scene], binary=CLANG, data=OWNER, recipe=recipe,
style=style, layout_path=layout_path, env=env_for(capture=True),
script_inputs=capture_inputs)
resolved_strate_styles = row.get("resolved_strate_styles", {})
target_strate = "0" if scene == "owner-fi" else "1"
style_ok = (resolved_strate_styles == {"0": 2, "1": 1}
and resolved_strate_styles.get(target_strate) == style)
runner.require(f"{name}:resolved-style", style_ok,
f"resolved_strate_styles={resolved_strate_styles} "
f"target_strate={target_strate} expected_style={style}")
capture_rows[scene] = (row, output)
shape_script = LINUX37 / "AuditMouthShapeL37.py"
baseline = ROOT / "Saved/Linux/l37/no-tread-control"
controls = [ROOT / "Saved/Linux/l36/owner-fi-ground-mouth.vfmesh"]
for scene, recipe, style in (("owner-fi", "floating-islands", 2),
("owner-sw", "surface-world", 1)):
name = f"mouth-shape-{scene}-style{style}"
runner.run_stage(name, shape_script,
[f"--out={OUT}", f"--baseline-out={baseline}",
"--control-out=Saved/Linux/l36", "--scene", scene],
binary=CLANG, data=OWNER, recipe=recipe, style=style,
layout_path=OUT / f"layout-{scene}.json", env=env_for(),
script_inputs=[shape_script, *controls])
crease_script = LINUX37 / "RunMouthCreaseAuditL37.py"
sw_capture_log = OUT / "capture-standard-owner-sw-style1.log"
crease_args = [
f"--candidate={OUT / 'owner-fi-ground-mouth.vfmesh'}",
f"--candidate-sw={OUT / 'owner-sw-ground-mouth.vfmesh'}",
f"--layout-sw={OUT / 'layout-owner-sw.json'}",
f"--capture-log-sw={sw_capture_log}"]
control_meshes = [ROOT / f"Saved/Linux/{round_name}/owner-fi-ground-mouth.vfmesh"
for round_name in ("l35", "l36")]
runner.run_stage("mouth-crease-fragments-owner-fi2-sw1", crease_script,
crease_args, binary=CLANG, data=OWNER, recipe="floating-islands", style=2,
layout_path=OUT / "layout-owner-fi.json", env=env_for(),
script_inputs=[crease_script,
LINUX37 / "RunMouthFragmentAuditL37.py", *control_meshes,
OUT / "owner-fi-ground-mouth.vfmesh", OUT / "owner-sw-ground-mouth.vfmesh",
OUT / "layout-owner-sw.json", sw_capture_log])
overview_script = LINUX37 / "CaptureMouthOverviewL37.py"
runner.run_stage("capture-fi-overview-style2", overview_script, [],
binary=CLANG, data=OWNER, recipe="floating-islands", style=2,
layout_path=OUT / "layout-owner-fi.json", env=env_for(capture=True),
script_inputs=[overview_script, VERIFY_DIR / "capture_quality.py",
OUT / "owner-fi-ground-mouth.vfmesh"])
def verify_determinism_cell(runner: VerificationRunner, binary: Path,
kind: str, recipe: str, style: int, workers: int,
reference: dict[tuple[str, str], tuple[str, ...]]) -> None:
name = f"determinism-{kind}-{recipe}-{compiler_name(binary)}-w{workers}"
flags = ["--stream-hash"]
if kind == "crossing24":
flags.extend(("--camera-step=24,0,0", "--region-crossing"))
row, output = runner.run_cpp(name, binary, OWNER, recipe, flags,
expected_style=2, expected_strate_styles={"0": 2, "1": 1},
workers=workers,
layout_path=OUT / "layouts" / f"{name}.json")
row["requested_style"] = style
row["expected_passage_style"] = 2
values = tuple(HASH_RE.findall(output))
key = (kind, recipe)
expected = reference.get(key)
stable = expected is None or values == expected
if expected is None and values:
reference[key] = values
runner.require(f"{name}:stable-hashes", len(values) == 12 and stable,
f"hashes={len(values)}/12 stable={stable}")
def run_30_cell_determinism(runner: VerificationRunner) -> None:
references: dict[tuple[str, str], tuple[str, ...]] = {}
count = 0
for kind in ("l25", "crossing24"):
for recipe, style in (("surface-world", 1), ("floating-islands", 2)):
for binary in (CLANG, GCC):
for workers in (1, 8, 12):
verify_determinism_cell(runner, binary, kind, recipe, style,
workers, references)
count += 1
fixture_source = ROOT / "Saved/Linux/l33/fixtures/sw-upper-tunnel-network-style0.json"
fixture = OUT / "fixtures/style-override-upper-sw-fixture-style0.json"
fixture.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(fixture_source, fixture)
signatures = None
for binary in (CLANG, GCC):
for workers in (1, 8, 12):
name = f"determinism-style-override-upper-sw-fixture-style0-{compiler_name(binary)}-w{workers}"
row, output = runner.run_cpp(name, binary, fixture, "floating-islands",
["--audit-resolved-layout-passages"], expected_style=None,
expected_strate_styles={"1": 0}, workers=workers,
layout_path=OUT / "layouts" / f"{name}.json")
row["requested_style"] = 0
row["requested_strate_styles"] = {"1": 0}
validate_passage(runner, name, output)
current = tuple(re.findall(
r"^\[ResolvedLayoutSnapshot\].*stable_identity=([^ ]+)", output, re.M)
+ re.findall(r"^\[WorldAssemblyPlanSerialization\].*plan_hash=([0-9a-f]+)", output, re.M)
+ re.findall(r"^\[WorldAssemblerRouteAccepted\].*$", output, re.M))
stable = signatures is None or current == signatures
if signatures is None and current:
signatures = current
runner.require(f"{name}:stable-plan-route", bool(current) and stable,
f"snapshot-plan-route_records={len(current)} stable={stable}")
count += 1
runner.require("determinism-30-cell-count", count == 30, f"cells={count}/30")
def prepare_l36_cost_baseline(runner: VerificationRunner) -> tuple[Path, str]:
temp = Path("/tmp/voxelforge-l36-stamped")
if temp.exists():
shutil.rmtree(temp)
temp.mkdir(parents=True)
tarball = temp / "l36.tar"
archive = bounded_run(["git", "archive", "-o", str(tarball),
"8be1c4d", "Standalone"], timeout=120)
if archive is None or archive.returncode != 0 or not tarball.is_file():
raise VerificationFailure("could not export historical L36 source commit 8be1c4d")
extract = bounded_run(["tar", "-xf", str(tarball), "-C", str(temp)], timeout=120)
if extract is None or extract.returncode != 0:
raise VerificationFailure("historical L36 source extraction failed")
tarball.unlink(missing_ok=True)
base = temp / "Standalone"
(base / "Tools/verify").mkdir(parents=True, exist_ok=True)
shutil.copy2(ROOT / "Standalone/BuildLinux.sh", base / "BuildLinux.sh")
shutil.copy2(VERIFY_DIR / "source_stamp.py", base / "Tools/verify/source_stamp.py")
shutil.copy2(ROOT / "Standalone/Source/SourceStamp.h", base / "Source/SourceStamp.h")
legacy_main = base / "Source/StreamBenchmarkHeadless.cpp"
text = legacy_main.read_text(encoding="utf-8")
if "VoxelForgePrintSourceStamp" not in text:
text = text.replace("#include \"OwnerWorldLoader.h\"",
"#include \"SourceStamp.h\"\n#include <cstring>\n#include \"OwnerWorldLoader.h\"", 1)
anchor = re.search(r"int main\(int argc,\s*char\*\*\s*argv\)\s*\{", text)
if anchor is None:
raise VerificationFailure("cannot instrument historical L36 headless entry point")
injected = ("\n VoxelForgePrintSourceStamp();\n"
" if(argc==2&&std::strcmp(argv[1],\"--print-source-stamp\")==0)return 0;")
text = text[:anchor.end()] + injected + text[anchor.end():]
legacy_main.write_text(text, encoding="utf-8")
baseline_stamp = source_stamp(temp)
binary = OUT / "historical-bin/VoxelForgeCoreHeadless-l36-stamped"
env = os.environ.copy()
env["VOXELFORGE_BUILD_ROOT"] = str(temp / "build")
env["VOXELFORGE_BIN_DIR"] = str(binary.parent)
command = ["bash", str(base / "BuildLinux.sh"), "--compiler=clang++-19",
"--variant=l36-stamped", "--fp-contract=off", "--jobs=12"]
log = OUT / "cost-baseline-build-l36.log"
log.parent.mkdir(parents=True, exist_ok=True)
started = time.monotonic()
with log.open("w", encoding="utf-8") as stream:
proc = bounded_run(command, timeout=1800, env=env, stdout=stream)
elapsed = time.monotonic() - started
runner.require("cost-baseline-l36-build",
proc is not None and proc.returncode == 0 and binary.is_file(),
f"source_stamp={baseline_stamp} elapsed_seconds={elapsed:.1f} log={log}")
runner.binary_stamp_overrides[str(binary)] = baseline_stamp
return binary, baseline_stamp
def run_cost_pairs(runner: VerificationRunner) -> None:
baseline, baseline_stamp = prepare_l36_cost_baseline(runner)
candidate = CLANG
orders = (("l36", "l39"), ("l39", "l36"), ("l36", "l39"),
("l39", "l36"), ("l36", "l39"))
by_recipe: dict[str, dict[str, list[float]]] = {
"floating-islands": {"l36": [], "l39": []},
"surface-world": {"l36": [], "l39": []}}
by_pair: dict[tuple[str, int], dict[str, float]] = {}
for recipe, style in (("floating-islands", 2), ("surface-world", 1)):
for pair, order in enumerate(orders, 1):
for build in order:
binary = baseline if build == "l36" else candidate
expected_style = None if build == "l36" else style
name = f"cost-{recipe}-pair{pair}-{build}"
expected_stamp = baseline_stamp if build == "l36" else None
row, output = runner.run_cpp(name, binary, OWNER, recipe, [],
expected_style=2 if build == "l39" else None,
expected_strate_styles={"0": 2, "1": 1} if build == "l39" else None,
layout_path=OUT / "layouts" / f"{name}.json",
expected_stamp=expected_stamp)
row["requested_style"] = style
row["expected_passage_style"] = 2 if build == "l39" else None
ready = re.findall(r"\bwhole_view_ready=([0-9.]+)s", output)
ok = (len(ready) == 1 and "hash=off" in output
and "cache_hits=0" in output
and RECIPE_RE.findall(output) == [(recipe, recipe, "PASS")])
runner.require(f"{name}:cost-record", ok,
f"whole_view_ready={ready[0] if ready else 'MISSING'}s "
f"source_stamp={row['source_stamp']}")
by_recipe[recipe][build].append(float(ready[0]))
by_pair.setdefault((recipe, pair), {})[build] = float(ready[0])
for recipe, values in by_recipe.items():
old = statistics.median(values["l36"])
new = statistics.median(values["l39"])
paired = [((by_pair[(recipe, pair)]["l39"] - by_pair[(recipe, pair)]["l36"])
/ by_pair[(recipe, pair)]["l36"] * 100.0)
for pair in range(1, 6)]
runner.require(f"cost-{recipe}-five-pairs",
len(values["l36"]) == len(values["l39"]) == 5,
f"median_l36_s={old:.3f} median_l39_s={new:.3f} "
f"median_change_pct={(new / old - 1.0) * 100.0:+.2f} "
f"paired_change_pct={','.join(f'{value:+.2f}' for value in paired)}")
def run_medium_suite(runner: VerificationRunner, *, both_compilers: bool = False) -> None:
binaries = (CLANG, GCC) if both_compilers else (CLANG,)
run_owner_passages(runner, binaries)
run_regression_controls(runner)
style_override_matrix(runner, CLANG)
if both_compilers:
style_override_matrix(runner, GCC)
run_transitions_and_invariants(runner, binaries)
run_ring(runner, full=True)
run_captures_and_mesh_audits(runner)
def run_gcc_supplement(runner: VerificationRunner) -> None:
"""Add GCC evidence to a stamped, already-passed Clang medium tier."""
run_owner_passages(runner, (GCC,))
style_override_matrix(runner, GCC)
run_transitions_and_invariants(runner, (GCC,))
def main() -> int:
runner = VerificationRunner(ARGS.tier)
started = time.monotonic()
try:
if not OWNER.is_file():
raise VerificationFailure(f"canonical owner input is missing: {OWNER}")
for binary in (CLANG, GCC, RENDERER):
if binary.is_file():
runner.probe_binary(binary)
if ARGS.tier == "fast":
owners = run_owner_passages(runner, (CLANG,))
run_regression_controls(runner)
run_hash_pairs(runner, owners)
run_ring(runner, full=False)
elif ARGS.tier == "medium":
run_medium_suite(runner, both_compilers=False)
else:
medium_summary = OUT / "medium-summary.json"
if not runner.reuse_passed_tier(medium_summary, "medium"):
run_medium_suite(runner, both_compilers=False)
run_gcc_supplement(runner)
run_30_cell_determinism(runner)
run_cost_pairs(runner)
# The validated medium summary carries the final canonical capture set.
runner.assert_binaries_current()
runner.assert_current_tree("at tier completion")
elapsed = time.monotonic() - started
runner.save_summary("PASS")
print(f"[{ARGS.tier}] DONE PASS elapsed={elapsed:.1f}s", flush=True)
return 0
except Exception as error:
elapsed = time.monotonic() - started
runner.save_summary("FAIL", str(error))
print(f"[{ARGS.tier}] DONE FAIL elapsed={elapsed:.1f}s error={error}", flush=True)
return 1
if __name__ == "__main__":
raise SystemExit(main())