On the real FloatingIslands recipe, column caps sit inside anchor-island rock and native bedrock; the old check sampled the route foot. The audit now samples each planned cap against the native field (negative control: a cap moved into air is detected). The audit runner records requested vs actual recipe and exits on mismatch. All 16 passage rows (4 styles x 2 recipes x 2 compilers) pass. The readable shader uses a smooth tint. Interim: FI Gradient displacement capped at width/256 (flat floor, no contour rings); restoring real undulation is L32. Evaluator 19. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
107 lines
4.6 KiB
Python
107 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Re-run the L25 hash command and 24 m crossing on the L31 compiler matrix."""
|
|
import re
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[4]
|
|
OUT = ROOT / "Saved/Linux/l31"
|
|
OUT.mkdir(parents=True, exist_ok=True)
|
|
BINARIES = {
|
|
"clang": OUT / "bin/VoxelForgeCoreHeadless-linux31-clang",
|
|
"gcc": OUT / "bin/VoxelForgeCoreHeadless-linux31-gcc",
|
|
}
|
|
HASH_PATTERN = re.compile(
|
|
r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
|
|
rows = []
|
|
failed = False
|
|
candidate_reference = {}
|
|
fi_hash_changes = {"l25": False, "crossing24": False}
|
|
|
|
|
|
def hashes(path):
|
|
return HASH_PATTERN.findall(path.read_text(encoding="utf-8", errors="replace"))
|
|
|
|
|
|
def run(kind, compiler, recipe, workers):
|
|
global failed
|
|
name = f"{kind}-{compiler}-{recipe}-w{workers}"
|
|
logfile = OUT / f"{name}.log"
|
|
command = [
|
|
str(BINARIES[compiler]), str(ROOT / "Standalone/data/owner_world.json"),
|
|
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
|
"--stream-hash", "--force-generate", "--clip-radius=3", "--max-clip-level=8",
|
|
"--far-horizon-lod8-step=0", f"--workers={workers}", f"--recipe={recipe}",
|
|
]
|
|
if kind == "crossing24":
|
|
command.extend(("--camera-step=24,0,0", "--region-crossing"))
|
|
started = time.monotonic()
|
|
try:
|
|
with logfile.open("w", encoding="utf-8") as stream:
|
|
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT,
|
|
timeout=1800, check=False)
|
|
except subprocess.TimeoutExpired:
|
|
result = None
|
|
elapsed = time.monotonic() - started
|
|
text = logfile.read_text(encoding="utf-8", errors="replace")
|
|
stamps = re.findall(
|
|
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
|
|
text, re.M)
|
|
current = hashes(logfile)
|
|
# The normal L30 log stem is ringfix-hash; crossing uses ringfix-crossing24.
|
|
baseline = ROOT / "Saved/Linux/l30" / (
|
|
f"ringfix-crossing24-{compiler}-{recipe}-w{workers}.log" if kind == "crossing24"
|
|
else f"ringfix-hash-{compiler}-{recipe}-w{workers}.log")
|
|
reference = hashes(baseline) if baseline.is_file() else []
|
|
key = (kind, recipe)
|
|
prior = candidate_reference.get(key)
|
|
stable = prior is None or current == prior
|
|
if prior is None and current:
|
|
candidate_reference[key] = current
|
|
baseline_match = bool(reference) and current == reference
|
|
baseline_changed = bool(reference) and current != reference
|
|
if recipe == "surface-world":
|
|
baseline_ok = baseline_match
|
|
comparison = "MATCH" if baseline_match else "MISMATCH"
|
|
else:
|
|
baseline_ok = baseline_changed
|
|
comparison = "EXPECTED_CHANGE" if baseline_changed else "UNCHANGED_OR_MISSING"
|
|
fi_hash_changes[kind] |= baseline_changed
|
|
ok = (result is not None and result.returncode == 0
|
|
and stamps == [(recipe, recipe, "PASS")]
|
|
and "hash=on" in text and len(current) == 12 and stable and baseline_ok)
|
|
rows.append((kind, recipe, compiler, workers, elapsed,
|
|
result.returncode if result else "TIMEOUT", len(current), ok))
|
|
print(f"{name} elapsed={elapsed:.1f}s recipe={stamps[0][1] if stamps else 'MISSING'} "
|
|
f"hashes={len(current)} "
|
|
f"L30={comparison} candidate_stable={'yes' if stable else 'no'} "
|
|
f"{'PASS' if ok else 'FAIL'}", flush=True)
|
|
if not ok:
|
|
failed = True
|
|
|
|
|
|
for kind in ("l25", "crossing24"):
|
|
for recipe in ("surface-world", "floating-islands"):
|
|
for compiler in ("clang", "gcc"):
|
|
for workers in (1, 8, 12):
|
|
run("crossing24" if kind == "crossing24" else "l25", compiler, recipe, workers)
|
|
|
|
summary = OUT / "determinism.csv"
|
|
summary.write_text(
|
|
"kind,recipe,compiler,workers,elapsed_seconds,exit_code,hash_rows,status\n" +
|
|
"".join(f"{kind},{recipe},{compiler},{workers},{elapsed:.3f},{code},{count},"
|
|
f"{'PASS' if ok else 'FAIL'}\n"
|
|
for kind, recipe, compiler, workers, elapsed, code, count, ok in rows),
|
|
encoding="utf-8")
|
|
for kind, changed in fi_hash_changes.items():
|
|
if not changed:
|
|
failed = True
|
|
print(f"[L31ExpectedGeometryHashChange] kind={kind} detected=false FAIL", flush=True)
|
|
else:
|
|
print(f"[L31ExpectedGeometryHashChange] kind={kind} detected=true PASS", flush=True)
|
|
print(f"[L31Determinism] 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)
|