Adds a density-field floor/wall profile audit along passages near mouths (0.125 m spacing; L23 terraced negative control detected) and a reusable 12-view passage capture set (80 deg FOV, eye height, LOD0, skirts off, capped clip planes). The old blurry mouth shot was camera framing; the L33 entry ledges were tile skirts. Owner world hashes unchanged; 24/24 passage rows, 30/30 determinism, 16/16 invariants; cost within noise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
93 lines
4.5 KiB
Python
93 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Run recipe-stamped passage/profile audits for both compilers and both owner recipes."""
|
|
import re
|
|
import os
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[4]
|
|
OUT = ROOT / "Saved/Linux/l34"
|
|
BINARIES = {
|
|
"clang": OUT / "bin/VoxelForgeCoreHeadless-l34-clang",
|
|
"gcc": OUT / "bin/VoxelForgeCoreHeadless-l34-gcc",
|
|
}
|
|
RUNS = []
|
|
for recipe, filename in (
|
|
("floating-islands", "floating-islands"),
|
|
("surface-world", "surface-world"),
|
|
):
|
|
for style in range(4):
|
|
RUNS.append((f"owner-{filename}-style{style}",
|
|
ROOT / f"Saved/Linux/linux25-owner-{filename}-style{style}.json", recipe))
|
|
for style in range(4):
|
|
RUNS.append((f"upper-sw-fixture-style{style}",
|
|
OUT.parent / "l33/fixtures" / f"sw-upper-tunnel-network-style{style}.json",
|
|
"floating-islands"))
|
|
|
|
RECIPE = re.compile(r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=PASS$", re.M)
|
|
PASSAGE = re.compile(r"^\[ResolvedPassageAudit\].*walkability=PASS$", re.M)
|
|
MOUTH = re.compile(r"^\[PassageMouthProfileAudit\].*status=PASS$", re.M)
|
|
ROUTE = re.compile(r"^\[ResolvedStrateRouteAudit\].*mouth_binding=PASS status=PASS$", re.M)
|
|
CHECKS = (
|
|
r"^\[ResolvedLayoutStrict\] accepted=true issues=0 error=$",
|
|
r"^\[ResolvedLayoutValidatorControls\].*status=PASS$",
|
|
r"^\[PassageMouthProfileNegativeControl\].*source=L23_terraced_geometry.*detected=true$",
|
|
r"^\[PassageMouthProfileSummary\].*l23_terrace_negative_control=DETECTED status=PASS$",
|
|
r"^\[PassageNaturalnessSummary\].*l23_negative_control=DETECTED.*status=PASS$",
|
|
r"^\[PassageOpenAirAuditSummary\].*violations=0.*l24_negative_control=DETECTED status=PASS$",
|
|
r"^\[PassageNoLongBridgeAudit\].*status=PASS$",
|
|
r"^\[PassageRockColumnAuditSummary\].*status=PASS$",
|
|
r"^\[ResolvedPassageAuditSummary\].*route_binding_failures=0 .*status=PASS$",
|
|
r"^\[Walkability\] PASS",
|
|
r"^\[FloorProfileBlend\].*negative_controls=step_detected/slope_detected status=PASS$",
|
|
)
|
|
|
|
rows = []
|
|
failed = False
|
|
for compiler, binary in BINARIES.items():
|
|
for name, data, recipe in RUNS:
|
|
logfile = OUT / f"passage-audit-{name}-{compiler}.log"
|
|
command = [
|
|
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
|
"timeout", "1800s", str(binary), str(data), "--workers=12",
|
|
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
|
"--force-generate", "--clip-radius=3", "--max-clip-level=8", "--max-level=-1",
|
|
f"--recipe={recipe}", "--audit-resolved-layout-passages",
|
|
]
|
|
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=1800, check=False)
|
|
except subprocess.TimeoutExpired:
|
|
result = None
|
|
elapsed = time.monotonic() - started
|
|
output = logfile.read_text(encoding="utf-8", errors="replace")
|
|
stamp_ok = RECIPE.findall(output) == [(recipe, recipe)]
|
|
passages = len(PASSAGE.findall(output))
|
|
mouths = len(MOUTH.findall(output))
|
|
routes = len(ROUTE.findall(output))
|
|
checks_ok = all(re.search(pattern, output, re.M) for pattern in CHECKS)
|
|
ok = (result is not None and result.returncode == 0 and stamp_ok
|
|
and passages >= 1 and mouths == passages and routes >= 1 and checks_ok)
|
|
code = result.returncode if result is not None else "TIMEOUT"
|
|
rows.append((name, recipe, compiler, elapsed, code, passages, mouths, routes, ok))
|
|
failed |= not ok
|
|
print(f"[L34PassageAuditRun] case={name} compiler={compiler} recipe={recipe} "
|
|
f"elapsed={elapsed:.1f}s exit={code} passages={passages} "
|
|
f"profiles={mouths} routes={routes} {'PASS' if ok else 'FAIL'} "
|
|
f"log={logfile}", flush=True)
|
|
|
|
summary = OUT / "passage-audits.csv"
|
|
summary.write_text(
|
|
"case,recipe,compiler,elapsed_seconds,exit_code,passages,mouth_profiles,routes,status\n" +
|
|
"".join(f"{name},{recipe},{compiler},{elapsed:.3f},{code},{passages},{mouths},{routes},"
|
|
f"{'PASS' if ok else 'FAIL'}\n"
|
|
for name, recipe, compiler, elapsed, code, passages, mouths, routes, ok in rows),
|
|
encoding="utf-8")
|
|
print(f"[L34PassageAuditSummary] 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) != 24 else 0)
|