wip(assembler): round L31 -- FI recipe column audit corrected; recipe-stamped audit runner

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
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-21 14:13:18 +02:00
1 parent 103d8b471e
commit 28069f0d98
23 files changed
+1235 -19

No files matched your search

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""Combine the initial and repeat L31 interleaved cost batches."""
import csv
import statistics
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l31"
sources = (
("first", 0, OUT / "cost-first/cost-runs.csv"),
("repeat", 5, OUT / "cost-runs.csv"),
)
rows = []
for batch, offset, path in sources:
with path.open(newline="", encoding="utf-8") as stream:
for row in csv.DictReader(stream):
row["pair"] = str(int(row["pair"]) + offset)
row["source_batch"] = batch
rows.append(row)
with (OUT / "cost-combined.csv").open("w", newline="", encoding="utf-8") as stream:
writer = csv.DictWriter(stream, fieldnames=(
"recipe", "pair", "build", "whole_view_ready_seconds", "process_elapsed_seconds",
"exit_code", "status", "source_batch"))
writer.writeheader()
writer.writerows(rows)
print("recipe pairs median_l30_s median_l31_s median_change_pct paired_median_pct range_pct")
failed = False
for recipe in ("surface-world", "floating-islands"):
by_build = {
build: [float(row["whole_view_ready_seconds"]) for row in rows
if row["recipe"] == recipe and row["build"] == build]
for build in ("l30", "l31")
}
paired = []
for pair in range(1, 11):
times = {
row["build"]: float(row["whole_view_ready_seconds"])
for row in rows if row["recipe"] == recipe and int(row["pair"]) == pair
}
paired.append((times["l31"] / times["l30"] - 1.0) * 100.0)
median_l30 = statistics.median(by_build["l30"])
median_l31 = statistics.median(by_build["l31"])
median_change = (median_l31 / median_l30 - 1.0) * 100.0
print(f"{recipe} 10 {median_l30:.3f} {median_l31:.3f} {median_change:+.2f} "
f"{statistics.median(paired):+.2f} {min(paired):+.2f}..{max(paired):+.2f}")
failed |= len(by_build["l30"]) != 10 or len(by_build["l31"]) != 10
print(f"[L31CostCombined] pairs_per_recipe=10 runs={len(rows)} "
f"status={'FAIL' if failed else 'PASS'} summary={OUT / 'cost-combined.csv'}")
raise SystemExit(1 if failed or len(rows) != 40 else 0)
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
"""Compare L25 and 24 m crossing hash records for matching recipe/compiler/workers."""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l31"
pattern = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
lines = []
failed = False
for recipe in ("surface-world", "floating-islands"):
for compiler in ("clang", "gcc"):
for workers in (1, 8, 12):
left = pattern.findall((OUT / f"l25-{compiler}-{recipe}-w{workers}.log").read_text())
right = pattern.findall((OUT / f"crossing24-{compiler}-{recipe}-w{workers}.log").read_text())
same = bool(left) and len(left) == 12 and left == right
failed |= not same
lines.append(f"{recipe},{compiler},W{workers},{'MATCH' if same else 'MISMATCH'}")
path = OUT / "determinism-crossing-compare.log"
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
print("\n".join(lines))
print(f"[L31CrossingHashCompare] comparisons={len(lines)} "
f"pass={sum(line.endswith('MATCH') for line in lines)} fail={sum(line.endswith('MISMATCH') for line in lines)}")
raise SystemExit(1 if failed else 0)
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Encode the six requested L31 screenshots as small, pinned JPEGs."""
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
SOURCE = ROOT / "Saved/Linux/l31"
DEST = Path(__file__).resolve().parent / "captures"
DEST.mkdir(parents=True, exist_ok=True)
names = (
"fi-column-top-close-v19",
"fi-column-top-wide-v19",
"fi-column-base-close-v19",
"fi-column-base-wide-v19",
"fi-floor-v19-tint-off",
"fi-floor-v19-tint-on",
)
failed = False
for name in names:
source = SOURCE / f"{name}.png"
destination = DEST / f"{name.removesuffix('-v19').replace('-v19-', '-')}.jpg"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "ffmpeg",
"-y", "-hide_banner", "-loglevel", "error", "-i", str(source),
"-frames:v", "1", "-q:v", "4", str(destination),
]
result = subprocess.run(command, check=False)
size = destination.stat().st_size if destination.exists() else 0
ok = result.returncode == 0 and size <= 300_000
failed |= not ok
print(f"[L31CaptureJPEG] source={source.name} output={destination.name} "
f"bytes={size} status={'PASS' if ok else 'FAIL'}")
raise SystemExit(1 if failed else 0)
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""Measure surface heights and normals on an eastward FI floor radial line."""
import array
import math
import struct
import sys
def read_surface_vertices(path):
vertices = []
with open(path, "rb") as stream:
if stream.read(8) != b"VFMSH001":
raise SystemExit(f"{path}: invalid scene header")
version, voxel_um, count = struct.unpack("<3I", stream.read(12))
stream.read(40)
if version != 1 or count > 100000:
raise SystemExit("unsupported scene")
for _ in range(count):
key = struct.unpack("<4i", stream.read(16))
surface_count, skirt_count, vertex_count, index_count, mask_count = struct.unpack(
"<5I", stream.read(20))
positions = array.array("f")
positions.frombytes(stream.read(vertex_count * 12))
normals = array.array("f")
normals.frombytes(stream.read(vertex_count * 12))
indices = array.array("I")
indices.frombytes(stream.read(index_count * 4))
masks = stream.read(mask_count)
if sys.byteorder != "little":
positions.byteswap()
normals.byteswap()
indices.byteswap()
used = set()
for tri in range(0, index_count, 3):
if masks and masks[tri // 3]:
continue
for index in indices[tri:tri + 3]:
if index < surface_count:
used.add(index)
for index in used:
offset = index * 3
vertices.append((positions[offset], positions[offset + 1],
positions[offset + 2], normals[offset],
normals[offset + 1], normals[offset + 2]))
return voxel_um, vertices
def main():
scene = sys.argv[1]
center_x, center_y = 64.0, -32.0
voxel_um, vertices = read_surface_vertices(scene)
floor = [v for v in vertices if abs(v[2] + 119.5) < 0.05
and math.hypot(v[0] - center_x, v[1] - center_y) <= 16.5]
if not floor:
raise SystemExit("no floor surface vertices near expected FI bedrock top")
mean = tuple(sum(v[index] for v in floor) / len(floor) for index in (3, 4, 5))
normal_rms = math.sqrt(sum(sum((v[index] - mean[axis]) ** 2
for axis, index in enumerate((3, 4, 5)))
for v in floor) / len(floor))
min_z = min(v[2] for v in floor)
max_z = max(v[2] for v in floor)
print(f"[RingNormalField] voxel_um={voxel_um} center_m=({center_x:.3f},{center_y:.3f}) "
f"vertices={len(floor)} height_min_m={min_z:.6f} height_max_m={max_z:.6f} "
f"mean_normal=({mean[0]:.8f},{mean[1]:.8f},{mean[2]:.8f}) "
f"normal_rms={normal_rms:.9f}")
print("[RingNormalRadialLine] radius_m sampled_radius_m height_m nx ny nz")
for radius in range(1, 17):
x, y = center_x + radius, center_y
vertex = min(floor, key=lambda v: (v[0] - x) ** 2 + (v[1] - y) ** 2)
sampled_radius = math.hypot(vertex[0] - center_x, vertex[1] - center_y)
if math.hypot(vertex[0] - x, vertex[1] - y) > 0.5:
raise SystemExit(f"missing near vertex at radius {radius} m")
print(f"{radius:2d} {sampled_radius:.6f} {vertex[2]:.6f} "
f"{vertex[3]:.8f} {vertex[4]:.8f} {vertex[5]:.8f}")
if __name__ == "__main__":
main()
@@ -0,0 +1,241 @@
#!/usr/bin/env python3
"""Rasterize upward mesh triangles into a top-down field height map."""
import argparse
import array
import json
import math
import struct
import sys
Q16 = 1 << 16
MASK64 = (1 << 64) - 1
def trunc_div(numerator, denominator):
return numerator // denominator if numerator >= 0 else -((-numerator) // denominator)
def transition_hash(seed, interface, x, y, z, salt):
value = 14695981039346656037
for word in (seed & 0xffffffff, interface & 0xffffffff,
x & MASK64, y & MASK64, z & MASK64, salt):
for byte in range(8):
value ^= (word >> (byte * 8)) & 0xff
value = (value * 1099511628211) & MASK64
value ^= value >> 30
value = (value * 0xbf58476d1ce4e5b9) & MASK64
value ^= value >> 27
value = (value * 0x94d049bb133111eb) & MASK64
value ^= value >> 31
return ((value >> 32) >> 15) - Q16
def transition_fade(value):
value = max(0, min(Q16, value))
square = value * value // Q16
return square * (3 * Q16 - 2 * value) // Q16
def gradient_height_um(layout, x_um, y_um):
upper = next(item for item in layout["strates"] if item["order"] == 0)
lower = next(item for item in layout["strates"] if item["order"] == 1)
width = upper["transition_width_um"]
cell = max(1_000_000, layout["strate_layout_chunk_size_um"] * 4)
ix = x_um // cell
iy = y_um // cell
tx = transition_fade(((x_um - ix * cell) * Q16) // cell)
ty = transition_fade(((y_um - iy * cell) * Q16) // cell)
def at(dx, dy):
noise = transition_hash(0, upper["strate_index"], ix + dx, iy + dy, 0,
0x47524144)
return noise
def lerp(a, b, t):
return a + trunc_div((b - a) * t, Q16)
low = lerp(lerp(at(0, 0), at(1, 0), tx),
lerp(at(0, 1), at(1, 1), tx), ty)
amplitude_divisor = 256 if upper.get("generator_kind") == "FloatingIslands" else 8
displacement = trunc_div(low * (width // amplitude_divisor), Q16)
seam = upper["bedrock"]["bottom_um"]
thickness = upper["bedrock"]["top_um"] - seam
return seam + displacement + thickness
def read_scene(path):
triangles = []
with open(path, "rb") as stream:
if stream.read(8) != b"VFMSH001":
raise SystemExit(f"{path}: invalid scene header")
version, voxel_um, count = struct.unpack("<3I", stream.read(12))
stream.read(40)
if version != 1 or count > 100000:
raise SystemExit("unsupported scene")
for _ in range(count):
key = struct.unpack("<4i", stream.read(16))
surface_vertices, skirt_count, vertex_count, index_count, mask_count = struct.unpack(
"<5I", stream.read(20))
positions = array.array("f")
positions.frombytes(stream.read(vertex_count * 12))
normals = array.array("f")
normals.frombytes(stream.read(vertex_count * 12))
indices = array.array("I")
indices.frombytes(stream.read(index_count * 4))
masks = stream.read(mask_count)
if sys.byteorder != "little":
positions.byteswap()
normals.byteswap()
indices.byteswap()
for index in range(0, index_count, 3):
if masks and masks[index // 3]:
continue
a, b, c = indices[index:index + 3]
if max(a, b, c) >= surface_vertices:
continue
nz = (normals[a * 3 + 2] + normals[b * 3 + 2]
+ normals[c * 3 + 2]) / 3.0
if nz < 0.35:
continue
vertices = tuple((positions[v * 3], positions[v * 3 + 1],
positions[v * 3 + 2]) for v in (a, b, c))
triangles.append(vertices)
return voxel_um, triangles
def rasterize(triangles, bounds, width, height):
x0, x1, y0, y1 = bounds
values = [None] * (width * height)
sx, sy = width / (x1 - x0), height / (y1 - y0)
for tri in triangles:
(ax, ay, az), (bx, by, bz), (cx, cy, cz) = tri
den = (by - cy) * (ax - cx) + (cx - bx) * (ay - cy)
if abs(den) < 1.0e-12:
continue
left = max(0, int(math.floor((min(ax, bx, cx) - x0) * sx)))
right = min(width - 1, int(math.ceil((max(ax, bx, cx) - x0) * sx)))
top = max(0, int(math.floor((y1 - max(ay, by, cy)) * sy)))
bottom = min(height - 1, int(math.ceil((y1 - min(ay, by, cy)) * sy)))
for py in range(top, bottom + 1):
y = y1 - (py + 0.5) / sy
row = py * width
for px in range(left, right + 1):
x = x0 + (px + 0.5) / sx
u = ((by - cy) * (x - cx) + (cx - bx) * (y - cy)) / den
v = ((cy - ay) * (x - cx) + (ax - cx) * (y - cy)) / den
w = 1.0 - u - v
if min(u, v, w) < -1.0e-6:
continue
z = u * az + v * bz + w * cz
idx = row + px
if values[idx] is None or z > values[idx]:
values[idx] = z
return values
def main():
parser = argparse.ArgumentParser()
parser.add_argument("scene")
parser.add_argument("output_ppm")
parser.add_argument("--bounds", nargs=4, type=float, required=True,
metavar=("XMIN", "XMAX", "YMIN", "YMAX"))
parser.add_argument("--size", nargs=2, type=int, default=(640, 640))
parser.add_argument("--range", nargs=2, type=float, default=(-122.0, -118.0),
metavar=("ZMIN", "ZMAX"))
parser.add_argument("--ring-center", nargs=2, type=float,
metavar=("X", "Y"))
parser.add_argument("--probe-max-radius", type=int, default=16)
parser.add_argument("--layout")
args = parser.parse_args()
voxel_um, triangles = read_scene(args.scene)
width, height = args.size
sx, sy = width / (args.bounds[1] - args.bounds[0]), height / (args.bounds[3] - args.bounds[2])
values = rasterize(triangles, args.bounds, width, height)
finite = sorted(value for value in values if value is not None)
if not finite:
raise SystemExit("no upward-facing field samples in bounds")
low, high = args.range
if high <= low:
raise SystemExit("height range must increase")
stops = ((0.00, (31, 52, 92)), (0.24, (41, 119, 153)),
(0.50, (85, 177, 143)), (0.73, (226, 207, 105)),
(1.00, (181, 71, 49)))
with open(args.output_ppm, "wb") as output:
output.write(f"P6\n{width} {height}\n255\n".encode())
for value in values:
if value is None:
output.write(bytes((18, 22, 30)))
continue
t = max(0.0, min(1.0, (value - low) / (high - low)))
for index in range(len(stops) - 1):
if t <= stops[index + 1][0]:
ta, ca = stops[index]
tb, cb = stops[index + 1]
blend = (t - ta) / (tb - ta)
rgb = tuple(round(ca[c] + blend * (cb[c] - ca[c]))
for c in range(3))
break
else:
rgb = stops[-1][1]
output.write(bytes(rgb))
def quantile(p):
return finite[round((len(finite) - 1) * p)]
print(f"[RingFieldRaster] voxel_um={voxel_um} triangles={len(triangles)} "
f"pixels={len(finite)}/{len(values)} height_min_m={finite[0]:.6f} "
f"height_p05_m={quantile(.05):.6f} height_median_m={quantile(.5):.6f} "
f"height_p95_m={quantile(.95):.6f} height_max_m={finite[-1]:.6f} "
f"height_range_m={finite[-1]-finite[0]:.6f} "
f"map={args.output_ppm}")
if args.ring_center:
cx, cy = args.ring_center
def at_world(x, y):
fx = (x - args.bounds[0]) * sx - 0.5
fy = (args.bounds[3] - y) * sy - 0.5
ix, iy = math.floor(fx), math.floor(fy)
tx, ty = fx - ix, fy - iy
samples = []
for px, py in ((ix, iy), (ix + 1, iy), (ix, iy + 1), (ix + 1, iy + 1)):
if not (0 <= px < width and 0 <= py < height):
return None
value = values[py * width + px]
if value is None:
return None
samples.append(value)
return ((samples[0] * (1 - tx) + samples[1] * tx) * (1 - ty)
+ (samples[2] * (1 - tx) + samples[3] * tx) * ty)
print(f"[RingRadialProbe] center_m=({cx:.3f},{cy:.3f}) "
"radius_m mean_m angular_sd_m min_m max_m samples")
for radius in range(1, args.probe_max_radius + 1):
row = [at_world(cx + radius * math.cos(a * math.tau / 32),
cy + radius * math.sin(a * math.tau / 32))
for a in range(32)]
row = [value for value in row if value is not None]
if row:
mean = sum(row) / len(row)
sd = math.sqrt(sum((value - mean) ** 2 for value in row) / len(row))
print(f" {radius:>2} {mean:.6f} {sd:.6f} {min(row):.6f} "
f"{max(row):.6f} {len(row)}")
if args.layout:
layout = json.load(open(args.layout, encoding="utf-8"))
if next(item for item in layout["strates"] if item["order"] == 0)["transition_mode"] != "Gradient":
raise SystemExit("--layout must describe a Gradient owner interface")
errors = []
for index, actual in enumerate(values):
if actual is None:
continue
px, py = index % width, index // width
x = args.bounds[0] + (px + 0.5) / sx
y = args.bounds[3] - (py + 0.5) / sy
expected = gradient_height_um(layout, round(x * 1_000_000),
round(y * 1_000_000)) / 1_000_000.0
errors.append(actual - expected)
absolute = sorted(abs(error) for error in errors)
rms = math.sqrt(sum(error * error for error in errors) / len(errors))
print(f"[RingGradientMatch] samples={len(errors)} rms_m={rms:.6f} "
f"p95_abs_m={absolute[round((len(absolute)-1)*.95)]:.6f} "
f"max_abs_m={absolute[-1]:.6f} "
"expected=owner-resolved-2d-hash-value-noise")
if __name__ == "__main__":
main()
@@ -0,0 +1,107 @@
# Linux31 report
## FI column finding
The earlier L29/L30 passage table ran SurfaceWorld twice. On the real FloatingIslands recipe, the old column check under-counted connected ends because it treated support at the route foot as the column cap. The route foot is near z = −116 m; the actual lower cap is near z = −122 m, inside native bedrock whose top is z = −119.5 m. The upper caps sit inside anchor-island rock near z = −62 to −69 m. There is no floating column end or unintended gap. The open passage mouth is intentional.
The audit now samples each planned cap against the native density field. Negative density is solid rock. Every main column cap overlaps native rock within 0.25 m. The style 3 short lower cap overlaps within 0.50 m.
| FI style | Cap | Z (m) | Native overlap / samples | Minimum native density |
|---:|---|---:|---:|---:|
| 0 | Main upper / anchor island | −65.846 | 5,051 / 10,005 | −14.761719 |
| 0 | Main lower / bedrock | −122.390 | 6,149 / 12,588 | −8.000000 |
| 1 | Short upper | −61.574 | 9,725 / 11,033 | −23.464844 |
| 1 | Short lower | −75.637 | 3,915 / 11,500 | −15.554688 |
| 1 | Main upper / anchor island | −66.485 | 4,497 / 11,118 | −15.613281 |
| 1 | Main lower / bedrock | −122.416 | 6,673 / 13,735 | −8.000000 |
| 2 | Main upper / anchor island | −68.891 | 3,986 / 8,523 | −15.546875 |
| 2 | Main lower / bedrock | −122.382 | 5,396 / 10,885 | −8.000000 |
| 3 | Short upper | −65.805 | 5,095 / 10,064 | −14.671875 |
| 3 | Short lower | −80.054 | 2,498 / 10,413 | −11.910156 |
| 3 | Main upper / anchor island | −69.478 | 3,902 / 9,985 | −15.597656 |
| 3 | Main lower / bedrock | −122.436 | 6,130 / 12,453 | −8.000000 |
The negative control moves the style 0 lower cap into the air gap at z = −96.390 m: 0/3,120 native overlaps, minimum density +22.273438, and `detected=true`. The audit still catches a genuinely disconnected end.
## Recipe-stamped passage matrix
Each row is checked against the requested and resolved recipe stamp. The columns are capsule blocked/unsupported counts and mouth checks, open-air violations, naturalness, longest uncolumned span / 12.5 m limit, connected column ends, route bindings / failures, and walkability samples.
For all eight FI rows, `FloatingIslandRouteAudit` also passes: 78,064 capsule samples, 0 blocked, 0 unsupported, and 0 grade failures. The runner now asserts both capsule audits.
| Requested → actual | Style | Compiler | Capsule | Open air | Natural | Long bridge | Column ends | Bindings | Walkability |
|---|---:|---|---|---:|---:|---:|---:|---:|---:|
| surface-world → surface-world | 0 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 5642/5642 |
| surface-world → surface-world | 0 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 5642/5642 |
| surface-world → surface-world | 1 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 1490/1490 |
| surface-world → surface-world | 1 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 1490/1490 |
| surface-world → surface-world | 2 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 1545/1545 |
| surface-world → surface-world | 2 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 1545/1545 |
| surface-world → surface-world | 3 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 1495/1495 |
| surface-world → surface-world | 3 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 1 (0 failures) | 1495/1495 |
| floating-islands → floating-islands | 0 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 4.464/12.500 m | 2/2 | 2 (0 failures) | 4000/4000 |
| floating-islands → floating-islands | 0 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 4.464/12.500 m | 2/2 | 2 (0 failures) | 4000/4000 |
| floating-islands → floating-islands | 1 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 3.851/12.500 m | 4/4 | 2 (0 failures) | 1047/1047 |
| floating-islands → floating-islands | 1 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 3.851/12.500 m | 4/4 | 2 (0 failures) | 1047/1047 |
| floating-islands → floating-islands | 2 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 2 (0 failures) | 1135/1135 |
| floating-islands → floating-islands | 2 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 0.000/12.500 m | 2/2 | 2 (0 failures) | 1135/1135 |
| floating-islands → floating-islands | 3 | clang | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 4.243/12.500 m | 4/4 | 2 (0 failures) | 1061/1061 |
| floating-islands → floating-islands | 3 | gcc | 0/0 blocked/unsupported; mouth 2/2 | 0 violations | 1/1 | 4.243/12.500 m | 4/4 | 2 (0 failures) | 1061/1061 |
All 16 rows pass. The runner rejects a recipe mismatch. Its negative control requests SurfaceWorld while the resolved layout is FloatingIslands; the log records `requested=surface-world actual=floating-islands status=FAIL` and the process exits 2. Logs and the machine-readable matrix are under `Saved/Linux/l31/`.
## FI floor lines
The L30 rings persisted with height tint off, so they were geometry. Evaluator v19 reduces FloatingIslands Gradient displacement to `transition_width / 256` (one quarter voxel at the 16 m transition width), and the layout validator uses the same bound. The v18 one-voxel cap still left a 0.251819 m radial height range and a visible contour.
On the east radial line from (64, −32), samples at radii 1–16 m all have height −119.500000 m and normal (0, 0, 1). The extended mesh raster has a 0.000479 m total height range. The readable shader now applies a cubic smooth tint (`t²(3−2t)`). Tint-off and tint-on captures show a flat floor without contour bands.
## Captures and hashes
All six JPEGs are recipe-stamped from FloatingIslands and under 300 KB.
| Capture | Size | SHA-256 |
|---|---:|---|
| [FI column top, close](captures/fi-column-top-close.jpg) | 85,696 B | `6b651655fc2127bb5b3502a1a99c024167db2edc21bfe7241f6335a858bb8575` |
| [FI column top, wide](captures/fi-column-top-wide.jpg) | 67,043 B | `926193affd463492095b97310c62416910e12fc94e75d8548a01ad1f9601b6ec` |
| [FI column bedrock base, close](captures/fi-column-base-close.jpg) | 60,491 B | `3e524e0f6c506413b4b5b29d8835792f8b5240f95787c6a08d12ebe6e46aadd5` |
| [FI column bedrock base, wide](captures/fi-column-base-wide.jpg) | 61,543 B | `27ef1a72874c7f8e257969c5e69d614f336edce84693ee80b98783b9f610a4b2` |
| [FI floor, tint off](captures/fi-floor-tint-off.jpg) | 43,405 B | `41b9180c9696c7025e23009e6efdb2e86ace5900b08c293c92371797f9a8596d` |
| [FI floor, tint on](captures/fi-floor-tint-on.jpg) | 43,405 B | `0672e2ddc93fb6a4fe4f6adfdf4cdee896bdbc90dddfb7cf65050d978f86f32b` |
Evaluator version is 19. Binary SHA-256:
- Clang: `a796d433b7e31fa05abba970dbd486db1a904d13222d9c02b9054c394375e4f7`
- GCC: `c2ed12ddf4db5ce97fcd2d9c8f32e4515a4fba6d36d4d8a4b5fbb07a8ab8ae73`
## Determinism and cost
The L25 command and 24 m crossing each passed 12 cases: Clang and GCC at W1/W8/W12 for both recipes. All 12 hash records per log were stable across compilers and worker counts. SW matches the L30 baseline; FI changes as expected with the v19 geometry. L25 and crossing hashes match for all 12 recipe/compiler/worker combinations.
| Recipe | Full-detail density / mesh / payload / topology | Whole-view density / mesh / payload / topology |
|---|---|---|
| SurfaceWorld | `ace56c8f205238ad / a9c603a1248de6b8 / ea55f1f4fcc6a894 / 5ea7bc78a1b678ae` | `0e8c5af01df96b14 / 70099e89b77811ed / dbce0fdcf6764126 / ddaf81a1228f9b4b` |
| FloatingIslands | `ed550e0c8b182695 / 0e410a8e80a3e7f7 / 0751926f0c67d8a4 / f01208bc2f7841ec` | `52e0b9f95da4291e / 7c6e9e18346278a4 / 59160fe3df02a0ae / ef7f17088fe3253e` |
Cost compared the Clang L31 binary with the L30 `linux30-speed-fade` binary: 10 interleaved pairs per recipe, 40 runs total, with zero cache hits. Combined median whole-view time was 1.772 s → 1.784 s for SW (+0.71%) and 17.468 s → 17.482 s for FI (+0.08%). The second five-pair batch was +1.20% SW and +0.01% FI; the larger early SW deltas settled as runs warmed. The paired medians across all 10 were +1.86% SW and +0.55% FI, within the observed run variation.
## Failed and retried runs
- Five low-clip floor exports (`export-fi-floor.log`, `export-fi-floor-probe.log`, `export-fi-floor-without-mesh.log`, `export-fi-floor-probe-retry.log`, `fi-floor-no-camera-probe.log`) stopped with `std::bad_alloc`. Export succeeded with `--max-clip-level=8 --max-level=0`.
- A first radial analyzer invocation omitted the second `--range` value and was rejected by argparse; it was rerun with both bounds.
- A proof/parity probe used custom camera positions and failed SW parity because the sampled tile set differed from the established default-camera audit. That probe was stopped; the default-camera proof and transition suite passed 16/16.
- The first determinism launch ended before completing the matrix. The full 24-case run passed on retry. A first cost batch had an early SW timing outlier, so five additional interleaved pairs per recipe were run and retained in the combined summary.
- Early capture framing probes cropped the FI axis or placed the camera inside rock. A v19 wide floor view exposed only the export skirt edge; the final centered column and square top-down floor views were used.
- The first GCC build attempt was interrupted at 19 objects and retried successfully. One v18 diagnostic build used the default Standalone build path; those artifacts were removed, and final v19 build outputs are under `Saved/Linux/l31/`.
- Two one-line post-processing commands had quoting/pair-index errors; the checked-in `CompareDeterminismL31.py` and `AggregateCostL31.py` helpers produced the final passing summaries.
No run exceeded 30 minutes or remained stuck for 15 minutes. No Unreal files were edited. Nothing was committed, pushed, or stashed.
## Orchestrator review (Claude)
- Merged as an intermediate step: correct FI column-cap audit (with negative control), a recipe-stamped runner that
rejects mismatches, all 16 recipe/style/compiler rows passing, smooth shader tint, determinism.
- **Not accepted as the final floor fix:** v19 caps the FI Gradient displacement at `width/256` (≈6 cm), which
removes the owner's Gradient transition rather than making it smooth; the floor is now flat (radial
height range 0.0005 m). The real fix is a smooth, non-terraced undulation at the L29 amplitude (≈4 m
peak-to-peak). L32 restores it.
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""Run the recipe-stamped L31 passage audit matrix and reject mislabeled runs."""
import json
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",
}
MARKERS = (
"[ResolvedPassageAuditSummary]",
"[PassageOpenAirAuditSummary]",
"[PassageNaturalnessSummary]",
"[PassageNoLongBridgeAudit]",
"[PassageRockColumnAuditSummary]",
)
rows = []
failed = False
for recipe in ("surface-world", "floating-islands"):
for style in range(4):
data = ROOT / f"Saved/Linux/linux25-owner-{recipe}-style{style}.json"
for compiler, binary in BINARIES.items():
name = f"passage-{recipe}-style{style}-{compiler}"
logfile = OUT / f"{name}.log"
command = [
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, 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)
recipe_ok = stamps == [(recipe, recipe, "PASS")]
markers_ok = all(re.search(re.escape(marker) + r".*status=PASS", text)
for marker in MARKERS)
capsule_ok = bool(re.search(
r"^\[ResolvedPassageAudit\].* blocked=0 support_samples=\d+ "
r"unsupported=0 grade_failures=0 mouth_content=2/2 mouth_radius=2/2 "
r"walkability=PASS$", text, re.M))
island_route_ok = (recipe != "floating-islands" or bool(re.search(
r"^\[FloatingIslandRouteAudit\].* blocked=0 support_samples=\d+ "
r"unsupported=0 grade_failures=0 status=PASS$", text, re.M)))
binding_ok = bool(re.search(
r"\[ResolvedPassageAuditSummary\].*route_bindings=[1-9][0-9]* "
r"route_binding_failures=0 .*status=PASS", text))
walk_ok = "[Walkability] PASS" in text
if recipe == "floating-islands":
control_ok = "[PassageColumnDisconnectedEndControl]" in text and bool(
re.search(r"\[PassageColumnDisconnectedEndControl\].*detected=true", text))
else:
control_ok = True
ok = (result is not None and result.returncode == 0 and recipe_ok
and markers_ok and capsule_ok and island_route_ok and binding_ok
and walk_ok and control_ok)
actual_recipe = stamps[0][1] if len(stamps) == 1 else "MISSING"
rows.append((recipe, actual_recipe, style, compiler, elapsed,
result.returncode if result else "TIMEOUT", ok))
print(f"{name} elapsed={elapsed:.1f}s exit={result.returncode if result else 'TIMEOUT'} "
f"recipe={stamps[0][1] if stamps else 'MISSING'} "
f"capsule={'PASS' if capsule_ok and island_route_ok else 'FAIL'} "
f"column_control={'PASS' if control_ok else 'FAIL'} {'PASS' if ok else 'FAIL'}",
flush=True)
if not ok:
failed = True
summary = OUT / "passage-audit-matrix.csv"
summary.write_text(
"requested_recipe,actual_recipe,style,compiler,elapsed_seconds,exit_code,status\n" +
"".join(f"{requested},{actual},{style},{compiler},{elapsed:.3f},{code},"
f"{'PASS' if ok else 'FAIL'}\n"
for requested, actual, style, compiler, elapsed, code, ok in rows), encoding="utf-8")
control_log = OUT / "recipe-mismatch-control.log"
control_owner = OUT / "recipe-mismatch-control-owner.json"
control_owner_data = json.loads(
(ROOT / "Saved/Linux/linux25-owner-surface-world-style0.json").read_text(encoding="utf-8"))
top_owner_stratum = max(control_owner_data["strates"], key=lambda stratum: stratum["top_chunk_z"])
top_owner_stratum["asset"]["GeneratorType"] = 6 # ECaveGeneratorType::FloatingIslands
control_owner.write_text(json.dumps(control_owner_data, separators=(",", ":")), encoding="utf-8")
control_command = [
str(BINARIES["clang"]),
str(control_owner),
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--clip-radius=3",
"--max-clip-level=8", "--max-level=-1", "--recipe=surface-world",
"--audit-resolved-layout-passages",
]
with control_log.open("w", encoding="utf-8") as stream:
control = subprocess.run(control_command, stdout=stream, stderr=subprocess.STDOUT,
timeout=1800, check=False)
control_text = control_log.read_text(encoding="utf-8", errors="replace")
control_ok = (control.returncode == 2 and
"[WorldAssemblerRecipeAudit] requested=surface-world actual=floating-islands "
"top_generator=FloatingIslands " in control_text and
"floating_islands_stratum=present status=FAIL" in control_text)
print(f"[L31RecipeMismatchControl] requested=surface-world actual=floating-islands "
f"exit={control.returncode} detected={'true' if control_ok else 'false'} "
f"{'PASS' if control_ok else 'FAIL'}", flush=True)
print(f"[L31PassageMatrix] 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 not control_ok or len(rows) != 16 else 0)
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Run five interleaved W12 whole-view pairs against the final L30 binary."""
import re
import statistics
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 = {
"l30": ROOT / "Saved/Linux/l30/bin/VoxelForgeCoreHeadless-linux30-speed-fade",
"l31": OUT / "bin/VoxelForgeCoreHeadless-linux31-clang",
}
ORDERS = (("l30", "l31"), ("l31", "l30"), ("l30", "l31"),
("l31", "l30"), ("l30", "l31"))
READY = re.compile(r"\bwhole_view_ready=([0-9.]+)s")
rows = []
failed = False
for recipe in ("surface-world", "floating-islands"):
for pair, order in enumerate(ORDERS, 1):
for build in order:
name = f"cost-{recipe}-pair{pair}-{build}"
logfile = OUT / f"{name}.log"
command = [
str(BINARIES[build]), str(ROOT / "Standalone/data/owner_world.json"),
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--clip-radius=3",
"--max-clip-level=8", "--max-level=-1", f"--recipe={recipe}",
]
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")
matches = READY.findall(text)
if build == "l31":
stamps = re.findall(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
text, re.M)
actual_recipe = stamps[0][1] if len(stamps) == 1 else "missing"
stamp_ok = stamps == [(recipe, recipe, "PASS")]
else:
configured = re.findall(
r"^\[HeadlessConfig\].*\brecipe=([^\s]+)", text, re.M)
actual_recipe = configured[0] if len(configured) == 1 else "missing"
floating_plan = "[FloatingIslandWorldAssembly]" in text
surface_plan = "[WorldAssemblerPrototype]" in text
plan_matches = ((actual_recipe == "floating-islands" and floating_plan)
or (actual_recipe == "surface-world" and not floating_plan
and surface_plan))
marker = (f"[L31BaselineRecipeAudit] requested={recipe} actual={actual_recipe} "
f"headless_recipe={configured[0] if len(configured) == 1 else 'missing'} "
f"floating_island_plan={'present' if floating_plan else 'absent'} "
f"surface_world_plan={'present' if surface_plan else 'absent'} "
f"status={'PASS' if actual_recipe == recipe and plan_matches else 'FAIL'}\n")
with logfile.open("a", encoding="utf-8") as stream:
stream.write(marker)
text += marker
stamp_ok = (actual_recipe == recipe and plan_matches
and len(configured) == 1)
valid = (result is not None and result.returncode == 0 and len(matches) == 1
and "hash=off" in text and "cache_hits=0" in text)
if build == "l31":
valid = valid and stamp_ok and actual_recipe == recipe
else:
valid = valid and stamp_ok and "status=PASS" in marker
ready = float(matches[0]) if len(matches) == 1 else float("nan")
rows.append((recipe, pair, build, ready, elapsed,
result.returncode if result else "TIMEOUT", valid))
print(f"{recipe} pair={pair} build={build} whole_view_ready={ready:.3f}s "
f"process_elapsed={elapsed:.1f}s {'PASS' if valid else 'FAIL'}", flush=True)
failed |= not valid
summary = OUT / "cost-runs.csv"
summary.write_text(
"recipe,pair,build,whole_view_ready_seconds,process_elapsed_seconds,exit_code,status\n" +
"".join(f"{recipe},{pair},{build},{ready:.6f},{elapsed:.3f},{code},"
f"{'PASS' if ok else 'FAIL'}\n"
for recipe, pair, build, ready, elapsed, code, ok in rows), encoding="utf-8")
for recipe in ("surface-world", "floating-islands"):
by_build = {build: [row[3] for row in rows if row[0] == recipe and row[2] == build]
for build in BINARIES}
l30 = statistics.median(by_build["l30"])
l31 = statistics.median(by_build["l31"])
paired = []
for pair in range(1, 6):
values = {row[2]: row[3] for row in rows if row[0] == recipe and row[1] == pair}
paired.append((values["l31"] - values["l30"]) / values["l30"] * 100.0)
print(f"[L31CostSummary] recipe={recipe} pairs=5 median_l30_s={l30:.3f} "
f"median_l31_s={l31:.3f} median_change_pct={(l31/l30-1)*100.0:+.2f} "
f"paired_change_pct={','.join(f'{value:+.2f}' for value in paired)}", flush=True)
print(f"[L31Cost] runs={len(rows)} status={'FAIL' if failed else 'PASS'} summary={summary}", flush=True)
raise SystemExit(1 if failed or len(rows) != 20 else 0)
@@ -0,0 +1,106 @@
#!/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)
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Run L31 route/proof and transition invariants with recipe-stamped logs."""
import re
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l31"
BINARIES = {
"clang": OUT / "bin/VoxelForgeCoreHeadless-linux31-clang",
"gcc": OUT / "bin/VoxelForgeCoreHeadless-linux31-gcc",
}
rows = []
failed = False
def run(name, binary, data, recipe, extra, checks):
global failed
logfile = OUT / f"{name}.log"
command = [
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}", *extra,
]
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)
stamp_ok = stamps == [(recipe, recipe, "PASS")]
checks_ok = all(check(text) for check in checks)
ok = result is not None and result.returncode == 0 and stamp_ok and checks_ok
rows.append((name, recipe, elapsed, result.returncode if result else "TIMEOUT", ok))
print(f"{name} elapsed={elapsed:.1f}s recipe={stamps[0][1] if stamps else 'MISSING'} "
f"stamp={'PASS' if stamp_ok else 'FAIL'} checks={'PASS' if checks_ok else 'FAIL'} "
f"{'PASS' if ok else 'FAIL'}", flush=True)
failed |= not ok
owner = ROOT / "Standalone/data/owner_world.json"
for recipe in ("surface-world", "floating-islands"):
for compiler, binary in BINARIES.items():
name = f"invariant-route-proof-{recipe}-{compiler}"
run(name, binary, owner, recipe,
["--stream-hash", "--audit-uniform-block-proofs", "--audit-route-parity"],
[lambda text: bool(re.search(
r"^\[RouteParityAudit\].*status=PASS$", text, re.M)),
lambda text: bool(re.search(
r"^\[UniformBlockProofAudit\].*violations=0(?:\s|$)", text, re.M))])
for recipe in ("surface-world", "floating-islands"):
for compiler, binary in BINARIES.items():
for mode in ("hard", "gradient", "interleaved"):
name = f"invariant-transition-{recipe}-{mode}-{compiler}"
run(name, binary, owner, recipe,
[f"--transition-mode={mode}", "--audit-strate-transitions"],
[lambda text: bool(re.search(
r"^\[StrateTransitionAuditSummary\].*hole_columns=0 air_samples=0 .*status=PASS$",
text, re.M)),
lambda text: bool(re.search(
r"^\[StrateTransitionNegativeControls\].*status=PASS$", text, re.M))])
summary = OUT / "invariant-audits.csv"
summary.write_text(
"run,recipe,elapsed_seconds,exit_code,status\n" +
"".join(f"{name},{recipe},{elapsed:.3f},{code},{'PASS' if ok else 'FAIL'}\n"
for name, recipe, elapsed, code, ok in rows),
encoding="utf-8")
print(f"[L31InvariantAudits] 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) != 16 else 0)
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Extract the validated recipe-stamped passage matrix into a compact table."""
import csv
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l31"
rows = []
for recipe in ("surface-world", "floating-islands"):
for style in range(4):
for compiler in ("clang", "gcc"):
name = f"passage-{recipe}-style{style}-{compiler}"
path = OUT / f"{name}.log"
text = path.read_text(encoding="utf-8", errors="replace")
def match(pattern):
found = re.search(pattern, text, re.M)
if not found:
raise SystemExit(f"{path}: missing metric {pattern}")
return found
stamp = match(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=(PASS|FAIL)$")
capsule = match(
r"^\[ResolvedPassageAudit\].*capsule_samples=(\d+) blocked=(\d+) "
r"support_samples=(\d+) unsupported=(\d+) grade_failures=(\d+) "
r"mouth_content=([^ ]+) mouth_radius=([^ ]+) .*$")
air = match(r"^\[PassageOpenAirAuditSummary\].*violations=(\d+).*status=(PASS|FAIL)$")
natural = match(r"^\[PassageNaturalnessSummary\] passed=(\d+)/(\d+).*$")
bridge = match(
r"^\[PassageNoLongBridgeAudit\].*longest_uncolumned_m=([0-9.]+) "
r"threshold_m=([0-9.]+).*$")
column = match(
r"^\[PassageRockColumnAuditSummary\] columns=(\d+) connected_ends=([^ ]+) "
r"short_spans=(\d+) wall_or_support_failures=(\d+).*status=(PASS|FAIL)$")
binding = match(
r"^\[ResolvedPassageAuditSummary\].*route_bindings=(\d+) "
r"route_binding_failures=(\d+).*status=(PASS|FAIL)$")
walk = match(r"^\[Walkability\] PASS (\d+)/(\d+) passage centerline samples")
rows.append({
"requested": stamp.group(1), "actual": stamp.group(2), "stamp": stamp.group(3),
"style": style, "compiler": compiler,
"capsule_samples": int(capsule.group(1)), "blocked": int(capsule.group(2)),
"support_samples": int(capsule.group(3)),
"unsupported": int(capsule.group(4)), "grade_failures": int(capsule.group(5)),
"mouth_content": capsule.group(6), "mouth_radius": capsule.group(7),
"air_violations": int(air.group(1)), "air_status": air.group(2),
"natural_passed": natural.group(1),
"natural_total": natural.group(2),
"longest_uncolumned_m": bridge.group(1), "bridge_threshold_m": bridge.group(2),
"column_count": int(column.group(1)), "connected_ends": column.group(2),
"short_spans": int(column.group(3)), "column_failures": int(column.group(4)),
"route_bindings": int(binding.group(1)),
"binding_failures": int(binding.group(2)),
"walk_samples": int(walk.group(1)), "walk_total": int(walk.group(2)),
"log": path.name,
})
with (OUT / "passage-audit-metrics.csv").open("w", newline="", encoding="utf-8") as stream:
writer = csv.DictWriter(stream, fieldnames=list(rows[0]))
writer.writeheader()
writer.writerows(rows)
lines = [
"| Requested → actual | Style | Compiler | Capsule | Open air | Natural | Long bridge | Column ends | Bindings | Walkability |",
"|---|---:|---|---|---:|---:|---:|---:|---:|---:|",
]
for row in rows:
ok = (row["requested"] == row["actual"] and row["stamp"] == "PASS"
and row["blocked"] == row["unsupported"] == row["grade_failures"] == 0
and row["mouth_content"] == row["mouth_radius"] == "2/2"
and row["air_violations"] == 0 and row["air_status"] == "PASS"
and row["natural_passed"] == row["natural_total"] == "1"
and float(row["longest_uncolumned_m"]) <= float(row["bridge_threshold_m"])
and row["connected_ends"] == f"{2 * row['column_count']}/{2 * row['column_count']}"
and row["column_failures"] == 0 and row["binding_failures"] == 0
and row["route_bindings"] > 0 and row["walk_samples"] == row["walk_total"])
if not ok:
raise SystemExit(f"{row['log']}: metric audit failed")
cells = (
f"{row['blocked']}/{row['unsupported']} blocked/unsupported; mouth 2/2",
f"{row['air_violations']} violations",
f"{row['natural_passed']}/{row['natural_total']}",
f"{float(row['longest_uncolumned_m']):.3f}/{row['bridge_threshold_m']} m",
row["connected_ends"],
f"{row['route_bindings']} (0 failures)",
f"{row['walk_samples']}/{row['walk_total']}",
)
lines.append(f"| {row['requested']} → {row['actual']} | {row['style']} | {row['compiler']} | "
+ " | ".join(cells) + " |")
table = OUT / "passage-audit-table.md"
table.write_text("\n".join(lines) + "\n", encoding="utf-8")
print(f"[L31PassageAuditTable] rows={len(rows)} pass={len(rows)} "
f"csv={OUT / 'passage-audit-metrics.csv'} markdown={table}")
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB