wip(assembler): round L19 -- strate ceilings closed at every LOD; ledges diagnosed

The shared boundary-cap path now emits a cap wherever the field is solid just below a strate's
configured top (it previously required a solid-to-air crossing there) and checks a 5x5 perimeter
grid before suppressing a fallback cap. Strict audit: 0 misses / 0 edge gaps, LOD0-8.
farHorizonVersion 3 -> 4. SurfaceWorld LOD0-2, full detail and exact queries unchanged; 28/28
matrix plus 14/14 crossing; route parity and proofs pass.
Ledges: the lower stratum's terrain at the FI/SW interface, seen through the FI void, sampled at
0.5/1/2 m at LOD1-3 (up to 1.5 m / 7.7 m ring steps). Fix deferred to the units/layers round.

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-20 08:46:29 +02:00
1 parent dcf0763ec5
commit 811c4b7b17
23 files changed
+698 -17

No files matched your search

+13
View File
@@ -1856,6 +1856,19 @@ un-inset to match the Unreal adapter. Versions 1 and 2 retain their serialized t
SurfaceWorld's field and output hashes remain unchanged. See
[`Standalone/Research/WorldAssemblerM3/Linux18/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux18/REPORT.md).
### 8.38 Closed shared boundary ceilings and LOD sampling audit — World Assembler L19
`AppendStratumBoundaryCeilings` fills a candidate cell when the authoritative field is solid just
inside that strate's configured upper boundary. It does not require the raw field to cross back to
air above the boundary: the ceiling itself closes the strate even when the field continues solid
through that plane. This avoids isolated holes where a coarse lattice node has no zero crossing.
`FFarMeshColumnIndex::HasDownwardCellCoverage` still suppresses a fallback quad only after its
interior and perimeter probes all hit the existing downward face. The L19 `farHorizonVersion` is 4
for this shared boundary-cap change; hashes remain direct at LOD0–3 and salted at LOD4–8. No density
query, stratum position, scale, or asynchronous route changes. The strict LOD0–8 roof and paired-edge
audit and the matched before/after captures are in
[`Standalone/Research/WorldAssemblerM3/Linux19/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux19/REPORT.md).
## 9. Multiplayer model (listen-server first, dedicated-friendly)
> **Status: transport is DESIGN ONLY — nothing is networked in-tree yet** (no `Replicated`/`HasAuthority`/RPCs; a
@@ -1096,11 +1096,11 @@ namespace VoxelForgeCore
// LOD8-only planar horizon interior grid; zero follows the MC step, 128 restores S9.
// Grille interieure LOD8 seulement; zero suit la maille MC, 128 restaure S9.
std::int32_t lod8HorizonInteriorStepVoxels = 0;
// Bump when the distant cap representation changes. LOD4-8 mesh hashes are salted;
// density and LOD0-3 hashes remain unchanged.
// Incremente quand le plafond lointain change. Les hashes LOD4-8 incluent cette version;
// densite et hashes LOD0-3 restent inchanges.
std::uint32_t farHorizonVersion = 3;
// Bump when shared stratum-boundary caps or the distant horizon representation changes.
// LOD4-8 mesh hashes are salted; density and LOD0-3 keep their direct identities.
// Incremente quand les plafonds partages ou l'horizon lointain changent.
// Les hashes de maillage LOD4-8 incluent cette version; LOD0-3 gardent leur identite directe.
std::uint32_t farHorizonVersion = 4;
// Linux research controls for reproducing L5 negative controls. Defaults preserve output.
std::uint32_t diagnosticGlobalOctaveDrop = 0;
std::uint32_t diagnosticCellStride = 1;
+17 -12
View File
@@ -894,7 +894,11 @@ struct FFarMeshColumnIndex
bool HasDownwardCellCoverage(double X0,double Y0,double X1,double Y1,
double Z,double Tolerance) const
{
constexpr double Samples[3]={0.125,0.5,0.875};
// Probe the perimeter as well as the interior: sparse interior-only probes can
// incorrectly hide a missing ceiling quad at an MC grid vertex.
// Sonder le perimetre et l'interieur: des sondes seulement interieures peuvent
// masquer un carre de plafond manquant sur un sommet de la grille MC.
constexpr double Samples[5]={0.0,0.25,0.5,0.75,1.0};
for(const double V:Samples)for(const double U:Samples)
{
const double X=X0+(X1-X0)*U;
@@ -1185,7 +1189,7 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
struct FCandidate
{
FStandaloneShapeWorld::FResolvedStratumBounds Bounds;
std::vector<uint8> Crossing;
std::vector<uint8> SolidBelow;
};
std::vector<FCandidate> Candidates;
for(const FStrateSlot& Slot:World.Manager->GetLayout())
@@ -1197,21 +1201,22 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
||Candidate.Bounds.TopZ>Origin.Z+Extent+1.0e-6)continue;
const double Epsilon=std::min(0.5,Candidate.Bounds.SealThickness*0.25);
if(Epsilon<=0.0)continue;
Candidate.Crossing.resize(static_cast<std::size_t>(GridSide)*GridSide,0);
bool AnyCrossing=false;
Candidate.SolidBelow.resize(static_cast<std::size_t>(GridSide)*GridSide,0);
bool AnySolidBelow=false;
for(int32 Y=0;Y<GridSide;++Y)for(int32 X=0;X<GridSide;++X)
{
const double WorldX=Origin.X+X*GridStep;
const double WorldY=Origin.Y+Y*GridStep;
const float Below=Shape.DensityAt(static_cast<float>(WorldX),static_cast<float>(WorldY),
static_cast<float>(Candidate.Bounds.TopZ-Epsilon));
const float Above=Shape.DensityAt(static_cast<float>(WorldX),static_cast<float>(WorldY),
static_cast<float>(Candidate.Bounds.TopZ+Epsilon));
const bool bCrosses=std::isfinite(Below)&&std::isfinite(Above)&&Below<0.0f&&Above>0.0f;
Candidate.Crossing[static_cast<std::size_t>(Y*GridSide+X)]=bCrosses?1:0;
AnyCrossing=AnyCrossing||bCrosses;
// The shared upper boundary closes the stratum even where its raw field stays
// solid above the configured top. A zero-crossing test leaves holes there.
// Le plafond partage ferme la strate meme si le champ reste solide au-dessus.
const bool bSolidBelow=std::isfinite(Below)&&Below<0.0f;
Candidate.SolidBelow[static_cast<std::size_t>(Y*GridSide+X)]=bSolidBelow?1:0;
AnySolidBelow=AnySolidBelow||bSolidBelow;
}
if(AnyCrossing)Candidates.push_back(std::move(Candidate));
if(AnySolidBelow)Candidates.push_back(std::move(Candidate));
}
if(Candidates.empty())return;
@@ -1248,8 +1253,8 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
{
const std::size_t I00=static_cast<std::size_t>(Y*GridSide+X);
const std::size_t I10=I00+1,I01=I00+GridSide,I11=I01+1;
if(!Candidate.Crossing[I00]||!Candidate.Crossing[I10]
||!Candidate.Crossing[I01]||!Candidate.Crossing[I11])continue;
if(!Candidate.SolidBelow[I00]||!Candidate.SolidBelow[I10]
||!Candidate.SolidBelow[I01]||!Candidate.SolidBelow[I11])continue;
const double CellX0=Origin.X+X*GridStep,CellY0=Origin.Y+Y*GridStep;
const double CellX1=CellX0+GridStep,CellY1=CellY0+GridStep;
// Suppress a coincident plane only when it covers the full cell. A hit at just the
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Render matched L19 review captures from the L18 and L19 scene exports."""
import os
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
CAPTURE = ROOT / "Standalone/bin/linux/VoxelForgeOffscreenCapture-linux19-clang"
BEFORE = ROOT / "Standalone/Research/WorldAssemblerM3/Linux18/exports"
AFTER = ROOT / "Saved/Linux/l19-diagnostics"
OUT = ROOT / "Standalone/Research/WorldAssemblerM3/Linux19/captures"
PNG_OUT = ROOT / "Saved/Linux/l19-captures-temp"
LOGS = ROOT / "Saved/Linux/l19-diagnostics"
OUT.mkdir(parents=True, exist_ok=True)
PNG_OUT.mkdir(parents=True, exist_ok=True)
env = os.environ.copy()
env["LP_NUM_THREADS"] = "12"
env["XDG_CACHE_HOME"] = str(ROOT / "Saved/Linux/mesa-cache")
views = [
("floating-islands-flat-square-before", BEFORE / "floating-islands-flat-square.vfmesh",
(-11.612444, -118.221237, -19.8452), 0, 0, True),
("floating-islands-flat-square-after", AFTER / "floating-islands-flat-square-after.vfmesh",
(-11.612444, -118.221237, -19.8452), 0, 0, True),
("floating-islands-owner-angle-before", BEFORE / "floating-islands-island-view.vfmesh",
(-22, -19, -22.8), 0, -4, True),
("floating-islands-owner-angle-after", AFTER / "floating-islands-island-view-after.vfmesh",
(-22, -19, -22.8), 0, -4, True),
("floating-islands-owner-ground-before", AFTER / "floating-islands-owner-ground-before.vfmesh",
(-6.3, -19.06, -21.0), 0, -4, True),
("floating-islands-owner-ground-after", AFTER / "floating-islands-owner-ground-after.vfmesh",
(-6.3, -19.06, -21.0), 0, -4, True),
("floating-islands-ceiling-up-after", AFTER / "floating-islands-island-view-after.vfmesh",
(-22, -19, -22.8), 0, 80, True),
("surface-world-l1-spawn-before", BEFORE / "surface-world-l1-spawn.vfmesh",
(0, -35, -487.94), 0, -22, False),
("surface-world-l1-spawn-after", AFTER / "surface-world-l1-spawn-after.vfmesh",
(0, -35, -487.94), 0, -22, False),
("surface-world-horizon-before", BEFORE / "surface-world-l1-spawn.vfmesh",
(0, -35, -487.94), 0, 0, False),
("surface-world-horizon-after", AFTER / "surface-world-l1-spawn-after.vfmesh",
(0, -35, -487.94), 0, 0, False),
("surface-world-rings-above-before", BEFORE / "surface-world-l1-spawn.vfmesh",
(0, -35, -280), 0, -90, True),
("surface-world-rings-above-after", AFTER / "surface-world-l1-spawn-after.vfmesh",
(0, -35, -280), 0, -90, True),
]
for name, scene, camera, yaw, pitch, tile_edges in views:
if not scene.exists():
raise SystemExit(f"missing scene: {scene}")
png = PNG_OUT / f"{name}.png"
jpg = OUT / f"{name}.jpg"
render_log = LOGS / f"{name}-render.log"
convert_log = LOGS / f"{name}-jpeg.log"
command = [str(CAPTURE), str(scene), str(png), "--size=1600x900",
"--shade=readable", f"--tile-edges={'on' if tile_edges else 'off'}",
"--tile-edge-width-m=0.15", "--camera-m="+",".join(map(str, camera)),
f"--yaw-deg={yaw}", f"--pitch-deg={pitch}"]
with render_log.open("w", encoding="utf-8") as stream:
subprocess.run(command, cwd=ROOT, env=env, stdout=stream,
stderr=subprocess.STDOUT, check=True)
ffmpeg = ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error", "-y",
"-i", str(png), "-frames:v", "1", "-q:v", "4", str(jpg)]
with convert_log.open("w", encoding="utf-8") as stream:
subprocess.run(ffmpeg, cwd=ROOT, env=env, stdout=stream,
stderr=subprocess.STDOUT, check=True)
if jpg.stat().st_size > 300_000:
raise SystemExit(f"{jpg.name} exceeds the 300 KB review limit")
print(f"[Capture] {jpg.relative_to(ROOT)} bytes={jpg.stat().st_size} status=PASS", flush=True)
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""Strict L19 audit of FloatingIslands roof coverage at every LOD."""
import array
import collections
import math
import struct
import sys
def read_exact(stream, size):
data = stream.read(size)
if len(data) != size:
raise EOFError(f"wanted {size} bytes, got {len(data)}")
return data
def height_at(triangles, x, y, preferred_z):
best = None
for (x0, y0, z0), (x1, y1, z1), (x2, y2, z2) in triangles:
den = (y1-y2)*(x0-x2)+(x2-x1)*(y0-y2)
if abs(den) < 1.0e-10:
continue
a = ((y1-y2)*(x-x2)+(x2-x1)*(y-y2))/den
b = ((y2-y0)*(x-x2)+(x0-x2)*(y-y2))/den
c = 1.0-a-b
if min(a,b,c) >= -1.0e-5:
z = a*z0+b*z1+c*z2
if best is None or abs(z-preferred_z) < abs(best-preferred_z):
best = z
return best
def quantile(values, fraction):
if not values:
return math.nan
ordered = sorted(values)
return ordered[math.floor(fraction*(len(ordered)-1))]
if len(sys.argv) != 3:
raise SystemExit("usage: CeilingContinuity.py scene.vfmesh expected-cap-plane-metres")
scene_path = sys.argv[1]
root_z = float(sys.argv[2])
tiles = {}
voxel_size_m = None
with open(scene_path, "rb") as stream:
if read_exact(stream, 8) != b"VFMSH001":
raise SystemExit("invalid VFMSH001 scene")
version, voxel_um, tile_count = struct.unpack("<3I", read_exact(stream, 12))
camera = struct.unpack("<3d", read_exact(stream, 24))
yaw, pitch = struct.unpack("<2d", read_exact(stream, 16))
voxel_size_m = voxel_um/1_000_000.0
for _ in range(tile_count):
key = struct.unpack("<4i", read_exact(stream, 16))
surface_vertices, skirt_count, vertex_count, index_count, mask_count = struct.unpack(
"<5I", read_exact(stream, 20))
positions = array.array("f")
positions.frombytes(read_exact(stream, vertex_count*12))
normals = array.array("f")
normals.frombytes(read_exact(stream, vertex_count*12))
indices = array.array("I")
indices.frombytes(read_exact(stream, index_count*4))
masks = read_exact(stream, mask_count)
if sys.byteorder != "little":
positions.byteswap()
normals.byteswap()
indices.byteswap()
extent = 32*(1 << key[3])*voxel_size_m
z0, z1 = key[2]*extent, (key[2]+1)*extent
ceiling = []
for triangle in range(index_count//3):
if masks and masks[triangle] != 0:
continue
a,b,c = indices[triangle*3:triangle*3+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.65:
continue
points = tuple((positions[v*3],positions[v*3+1],positions[v*3+2])
for v in (a,b,c))
center_z = sum(point[2] for point in points)/3.0
if abs(center_z-root_z) <= 1.0:
ceiling.append(points)
tiles[key] = {
"extent": extent, "x0": key[0]*extent, "y0": key[1]*extent,
"x1": (key[0]+1)*extent, "y1": (key[1]+1)*extent,
"z0": z0, "z1": z1, "ceiling": ceiling,
}
by_lod = collections.defaultdict(dict)
for key, tile in tiles.items():
if tile["z0"] <= root_z+1.0 and tile["z1"] >= root_z-1.0:
by_lod[key[3]][key] = tile
print(f"scene={scene_path} version={version} voxel_um={voxel_um} tiles={tile_count} "
f"camera_m={camera} yaw={yaw} pitch={pitch} expected_cap_m={root_z:.9f}")
print("lod zband_tiles cap_tiles missing_tiles cap_triangles face_z_m_p05/median/p95 "
"tile_samples hit_samples max_abs_root_delta_cm shared_edges expected_edge_samples "
"paired_edge_samples edge_gaps edge_delta_cm_median/p95/max")
all_pass = True
all_misses = []
for lod in range(9):
target = by_lod[lod]
cap_tiles = {key: tile for key,tile in target.items() if tile["ceiling"]}
face_z = [point[2] for tile in cap_tiles.values() for tri in tile["ceiling"]
for point in tri]
deltas = []
sample_count = 0
hit_count = 0
for key,tile in target.items():
if not tile["ceiling"]:
continue
for iy in range(16):
for ix in range(16):
x = tile["x0"]+(ix+0.5)*tile["extent"]/16
y = tile["y0"]+(iy+0.5)*tile["extent"]/16
sample_count += 1
height = height_at(tile["ceiling"],x,y,root_z)
if height is not None:
hit_count += 1
deltas.append(abs(height-root_z)*100.0)
else:
all_misses.append((lod,key,ix,iy,x,y))
edge_deltas = []
edge_count = 0
edge_gaps = 0
edge_gap_samples = 0
for key,a in cap_tiles.items():
x,y,z,level = key
for neighbor_key,axis in (((x+1,y,z,level),"x"),((x,y+1,z,level),"y")):
b = cap_tiles.get(neighbor_key)
if b is None:
continue
edge_count += 1
epsilon = min(0.02,a["extent"]*1.0e-4)
matched = 0
for index in range(33):
t = (index+0.5)/33
if axis == "x":
fixed = a["x1"]
varying = a["y0"]+(a["y1"]-a["y0"])*t
za = height_at(a["ceiling"],fixed-epsilon,varying,root_z)
zb = height_at(b["ceiling"],fixed+epsilon,varying,root_z)
else:
fixed = a["y1"]
varying = a["x0"]+(a["x1"]-a["x0"])*t
za = height_at(a["ceiling"],varying,fixed-epsilon,root_z)
zb = height_at(b["ceiling"],varying,fixed+epsilon,root_z)
if za is not None and zb is not None:
edge_deltas.append(abs(za-zb)*100.0)
matched += 1
edge_gap_samples += 33-matched
if matched != 33:
edge_gaps += 1
missing = len(target)-len(cap_tiles)
max_root = max(deltas) if deltas else math.nan
print(f"{lod} {len(target)} {len(cap_tiles)} {missing} "
f"{sum(len(tile['ceiling']) for tile in cap_tiles.values())} "
f"{quantile(face_z,.05):.6f}/{quantile(face_z,.5):.6f}/{quantile(face_z,.95):.6f} "
f"{sample_count} {hit_count} {max_root:.3f} {edge_count} {edge_count*33} {len(edge_deltas)} "
f"{edge_gaps} {quantile(edge_deltas,.5):.3f}/{quantile(edge_deltas,.95):.3f}/"
f"{max(edge_deltas) if edge_deltas else math.nan:.3f}")
if target and (missing or hit_count != sample_count or edge_gap_samples):
all_pass = False
for lod,key,ix,iy,x,y in all_misses:
print(f" miss lod={lod} key={key} sample=({ix},{iy}) xy_m=({x:.6f},{y:.6f})")
print(f"[CeilingContinuityL19] total_misses={len(all_misses)} "
f"result={'PASS' if all_pass else 'FAIL'} criteria=LOD0-8 every 16x16 interior ray hits; "
"every shared same-LOD edge sample has paired hits")
raise SystemExit(0 if all_pass else 1)
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""Check deterministic matrices and protected SurfaceWorld identities against L14."""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
MATRIX = ROOT / "Saved/Linux/l19-matrix"
CROSSING = ROOT / "Saved/Linux/l19-crossing"
ROW = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
LOD = re.compile(r"^\[PipelineLODHash\] lod=(\d+) .*$", re.M)
failed = []
def stable_rows(path):
rows = ROW.findall(path.read_text(encoding="utf-8", errors="replace"))
full = next((row for row in rows if row.startswith("[PipelineFullDetailHash]")), None)
exact = next((row for row in rows if row.startswith("[PipelineExactQueryHash]")), None)
lods = {int(match.group(1)): match.group(0) for match in LOD.finditer(
path.read_text(encoding="utf-8", errors="replace"))}
return rows, full, exact, {level: lods.get(level) for level in range(3)}
for compiler in ("clang-off", "gcc-default"):
baseline_name = "clang-off" if compiler == "clang-off" else "gcc-default"
baseline = ROOT / f"Saved/Linux/l14-final-hash-sw-{baseline_name}-w12-r5.log"
expected = stable_rows(baseline)
logs = sorted(MATRIX.glob(f"surface-world-{compiler}-w*-r*.log"))
if len(logs) != 7:
failed.append(f"matrix {compiler}: expected 7 rows, found {len(logs)}")
for path in logs:
actual = stable_rows(path)
if len(actual[0]) != 12 or actual[1:] != expected[1:]:
failed.append(f"protected SurfaceWorld mismatch: {path.name}")
crossing_baseline_name = "clang" if compiler == "clang-off" else "gcc"
crossing_baseline = ROOT / f"Saved/Linux/l14-final-crossing-24m-{crossing_baseline_name}-w12.log"
expected_crossing = stable_rows(crossing_baseline)
crossing_logs = sorted(CROSSING.glob(f"{compiler}-w*-r*.log"))
if len(crossing_logs) != 7:
failed.append(f"crossing {compiler}: expected 7 rows, found {len(crossing_logs)}")
for path in crossing_logs:
actual = stable_rows(path)
if len(actual[0]) != 12 or actual[1:] != expected_crossing[1:]:
failed.append(f"protected crossing identity mismatch: {path.name}")
print(f"[L19ProtectedHashGate] SurfaceWorld LOD0-2, full-detail, and exact query hashes "
f"result={'FAIL' if failed else 'PASS'}")
for failure in failed:
print(f"[L19HashMismatch] {failure}")
raise SystemExit(1 if failed else 0)
@@ -0,0 +1,123 @@
# Linux19 — FloatingIslands ceiling and LOD ledges
**Status:** The ceiling is now closed at every LOD. The lower-terrain ledges are diagnosed but remain visible: the required change affects protected SurfaceWorld LOD2 output, so I stopped before changing it and asked for your decision.
## Findings and changes
The ceiling holes came from two checks in the shared boundary-cap path. It required density to cross from solid just below a strate's configured top to air just above it. Some of the field remains solid above that top, so the old test omitted those cap cells. The duplicate-cap check also sampled only inside each cell and could miss partial perimeter coverage. The path now emits a cap wherever the field is solid just below the configured top, and checks a 5×5 grid including the perimeter before suppressing a fallback cap.
The ledges are real upward-facing, non-skirt terrain triangles from the lower SurfaceWorld stratum visible below the FloatingIslands stratum. The combined recipe log identifies the SurfaceWorld field as strate index 1, chunks −16…−79, built from the owner surface parameters and biome map; the FloatingIslands plan is index 0, chunks 0…−15. At the worst LOD1→2 sample, the fine mesh is at z=−60.497 m and the coarse mesh at z=−61.996 m (149.862 cm apart). The LOD2→3 maximum is 773.318 cm, at z=−73.080 m versus −65.347 m.
The ring probe excludes skirts and masked triangles. The far-ground refinement routine only runs at LOD4 and above, so it cannot cause the LOD1→2 or LOD2→3 steps. Density dispatch is coordinate-based rather than LOD-based; the meshes sample that field on progressively coarser grids (0.5 m, 1 m, and 2 m at LOD1–3). The evidence points to resolution-dependent surface extraction of the lower SurfaceWorld terrain near the strate transition, not a different LOD recipe or a ceiling triangle. The L13 route audit also found no page/native or exact-query mismatches. The owner’s lower-stratum reading is supported.
SurfaceWorld at its L1 spawn has small L1→2 and L2→3 median differences, but it has larger outliers at farther rings: L3→4 reaches 1,190.974 cm, and L4→5 reaches 491.570 cm. Those high far-ring values are in the table below; the matched spawn, horizon, and above-ring captures are byte-identical before and after.
I did not change the ledge geometry. The most direct fix needs to change SurfaceWorld LOD2, which your rule protects pending an owner decision. The pending question is whether to allow that change.
The shared Core fix changes the recipe output identity version from `farHorizonVersion` 3 to 4. It changes no density query, stratum position, scale, or async route. No Unreal files were edited.
## Ring tables
Values are median / p95 / maximum absolute edge-height difference in cm, then the probe's no-hit edge count. `Before → after` is identical for every row because this round changed the ceiling path, not the lower upward-facing terrain.
### FloatingIslands camera
| LOD edge | Edges / samples | Before (cm; gaps) | After (cm; gaps) |
|---|---:|---:|---:|
| 0→1 | 0 / 0 | — | — |
| 1→2 | 33 / 231 | 147.141 / 148.403 / 149.862; 0 | 147.141 / 148.403 / 149.862; 0 |
| 2→3 | 49 / 308 | 128.603 / 200.789 / 773.318; 8 | 128.603 / 200.789 / 773.318; 8 |
| 3→4 | 64 / 277 | 3.269 / 47.774 / 188.531; 27 | 3.269 / 47.774 / 188.531; 27 |
| 4→5 | 72 / 544 | 29.992 / 124.373 / 443.482; 6 | 29.992 / 124.373 / 443.482; 6 |
| 5→6 | 64 / 266 | 12.234 / 127.224 / 536.573; 32 | 12.234 / 127.224 / 536.573; 32 |
| 6→7 | 32 / 264 | 29.013 / 301.752 / 42,624.479; 0 | 29.013 / 301.752 / 42,624.479; 0 |
| 7→8 | 64 / 275 | 83.843 / 1,225.416 / 3,755.407; 32 | 83.843 / 1,225.416 / 3,755.407; 32 |
### SurfaceWorld L1 spawn camera
| LOD edge | Edges / samples | Before (cm; gaps) | After (cm; gaps) |
|---|---:|---:|---:|
| 0→1 | 46 / 288 | 0.178 / 0.594 / 1.171; 10 | 0.178 / 0.594 / 1.171; 10 |
| 1→2 | 32 / 288 | 1.419 / 4.990 / 10.438; 0 | 1.419 / 4.990 / 10.438; 0 |
| 2→3 | 34 / 256 | 2.179 / 12.648 / 35.355; 2 | 2.179 / 12.648 / 35.355; 2 |
| 3→4 | 40 / 265 | 5.099 / 35.999 / 1,190.974; 5 | 5.099 / 35.999 / 1,190.974; 5 |
| 4→5 | 58 / 270 | 0.235 / 3.694 / 491.570; 14 | 0.235 / 3.694 / 491.570; 14 |
| 5→6 | 65 / 266 | 12.234 / 127.224 / 536.573; 33 | 12.234 / 127.224 / 536.573; 33 |
| 6→7 | 41 / 269 | 28.238 / 291.861 / 945.477; 7 | 28.238 / 291.861 / 945.477; 7 |
| 7→8 | 32 / 275 | 83.843 / 1,225.416 / 3,755.407; 0 | 83.843 / 1,225.416 / 3,755.407; 0 |
## Ceiling continuity
The strict audit casts 16×16 interior rays per tile and pairs every shared same-LOD edge sample. Before the fix it found three LOD1 interior misses, one LOD2 interior miss, and 10 unpaired LOD1 perimeter samples. After the fix it found zero misses and zero edge gaps at all LODs.
| LOD | Cap tiles | Interior hits | Paired edge samples | Max root delta (cm) | Misses / gaps |
|---:|---:|---:|---:|---:|---:|
| 0 | 64/64 | 16,384/16,384 | 3,696/3,696 | 0 | 0 / 0 |
| 1 | 48/48 | 12,288/12,288 | 2,376/2,376 | 0 | 0 / 0 |
| 2 | 48/48 | 12,288/12,288 | 2,376/2,376 | 0.025 | 0 / 0 |
| 3 | 48/48 | 12,288/12,288 | 2,376/2,376 | 0.025 | 0 / 0 |
| 4 | 48/48 | 12,288/12,288 | 2,376/2,376 | 0 | 0 / 0 |
| 5 | 48/48 | 12,288/12,288 | 2,376/2,376 | 0 | 0 / 0 |
| 6 | 48/48 | 12,288/12,288 | 2,376/2,376 | 0 | 0 / 0 |
| 7 | 48/48 | 12,288/12,288 | 2,376/2,376 | 0 | 0 / 0 |
| 8 | 153/153 | 39,168/39,168 | 8,976/8,976 | 0 | 0 / 0 |
Full output is in `Saved/Linux/l19-diagnostics/fi_roof_after.log`; the pre-fix strict audit is `Saved/Linux/l19-diagnostics/baseline-fi-ceiling-strict.log`.
## Hashes and audits
Clang 19 (`-ffp-contract=off`) and GCC 14 (default) passed 28/28 runs: FI and SW, W1/W8/W12, with W12 repeated five times. The 24 m crossing passed 14/14 runs, with 12 matching hash rows each; its W1/W8/W12×5 hashes also matched the L14 compiler-specific references. The protected SurfaceWorld hash gate passed across the matrix and crossing. SurfaceWorld LOD0–2, full-detail, and exact-query hashes match L14 across the matrix and crossing; the representative W12 LOD3 hash also matches. LOD4–8 mesh/payload/topology hashes include the version-4 salt, and the tested captures show no visible SW change.
Representative Clang W12 hashes (density / mesh / payload / topology):
| Output | Full detail | Whole view |
|---|---|---|
| FloatingIslands | `43034299d33f2536 / a41e8353ec4bbe9c / cd0e3e15eef827b0 / 0b3c3f13cc1d6f8a` | `00bc3607a7839854 / 4baa66127c2b0892 / e11ef05e851a1517 / 1278bc4b1fffb869` |
| SurfaceWorld | `0ee0579bd15cbbe4 / 32e5d4964d610fee / 1932b96ee4b1d910 / 69743c6bad3447dc` | `c10697a8f48380c7 / 4197fc1072f0ff58 / 7b3e616ec9459851 / c879e35592bf33e5` |
SurfaceWorld LOD0–2 hashes (density / mesh / payload / topology):
| LOD | Hash |
|---:|---|
| 0 | `769f2a706d585a72 / 33eeeb39fa443816 / 645621a1d968983f / c2457ed905036c9d` |
| 1 | `69cc5a5c0a2c60af / b48335f5410c57d5 / d15c5480162ab8ba / feca1bd025823604` |
| 2 | `85deed5683a77202 / 53469895987aeea2 / e55f8ae7e1532033 / d5feb12a0e85c09b` |
Exact queries: FI density/unclamped `87e5c0dbf9ee9ee2`; SW density/unclamped `e4d4a8eb95b35933`; both detail `efcba20c0c70c415`, collision `e604823a249029bf`.
L13 route parity passed in all four audit runs (both recipes, both compilers), with zero mismatches. FI checked 782,026 exact-query samples; SW checked 910,651. L9 proof audits reported zero violations: FI 9,192 blocks / 12,234,552 samples; SW 27,479 / 36,574,549 samples. Full logs are in `Saved/Linux/l19-audits/`.
L3 FP-contract preamble/self-test, L4 `FLazy`, L7 shared cache, L9/L12 proofs, L11 readiness and crash handling, L13 route binding, the L18 shared ceiling, `ARCHITECTURE.md` §8.10, and the CLAUDE.md async rules remain intact. The only source edits are in shared Core; the only architecture addition is §8.38.
## Captures
Every JPEG is at most 50 KiB (limit 300 KB). `floating-islands-owner-ground-after.jpg` is the low view across the FI ground, matching the owner's angle. SurfaceWorld spawn, horizon, and above-ring before/after JPEGs are byte-identical.
- FI: `captures/floating-islands-flat-square-before.jpg`, `captures/floating-islands-flat-square-after.jpg`, `captures/floating-islands-owner-angle-before.jpg`, `captures/floating-islands-owner-angle-after.jpg`, `captures/floating-islands-owner-ground-before.jpg`, `captures/floating-islands-owner-ground-after.jpg`, `captures/floating-islands-ceiling-up-after.jpg`.
- SW: `captures/surface-world-l1-spawn-before.jpg`, `captures/surface-world-l1-spawn-after.jpg`, `captures/surface-world-horizon-before.jpg`, `captures/surface-world-horizon-after.jpg`, `captures/surface-world-rings-above-before.jpg`, `captures/surface-world-rings-above-after.jpg`.
## Failed and retried runs
- The pre-fix strict FI ceiling audit failed as expected: 4 interior misses and 10 unpaired LOD1 edge samples. The earlier loose report had counted only the 3 LOD1 interior misses. The final strict audit passed.
- A ceiling audit was mistakenly run on the ordinary SW terrain export; it reported 47,837 non-roof ray misses. That was the wrong target for this audit and was discarded.
- The first continuity-audit attempt was interrupted before results. `/usr/bin/time` was unavailable (exit 127); the repository `MeasureBuild.py` wrapper was used instead.
- The first FI auto-camera export used clip radius 0 / max LOD 0 and exited with `std::bad_alloc` (1.710 s, peak RSS 2,151,292 KiB). Retrying at radius 3 / LOD8 / W12 succeeded (10.786 s, peak RSS 597,976 KiB).
- An exploratory native-heightfield refinement extension did not change the FI L1→2 or L2→3 ring values and was reverted. A temporary debug probe/build used to inspect the ceiling field was also removed before the final build.
- The first hash-gate run happened before crossing logs existed and failed for zero crossing rows. After the 24 m crossing completed, the gate passed.
- The first SW ring probe did not inherit the CPU affinity limit; it was rerun under `taskset -c 0-11`, and the constrained table is unchanged.
- `renice -n 0` was denied by the environment. Runs stayed at inherited nice level 5 (below normal priority); the governor was left unchanged at `powersave`.
No build or run exceeded 15 minutes or 30 minutes. All final builds and run children used CPUs 0–11, at most 12 workers, `LP_NUM_THREADS=12` for llvmpipe, and the 6 GiB address-space cap. Peak RSS was 903,324 KiB (GCC build); the matrix, crossing, audits, roof audit, and captures peaked at 583,180, 550,832, 857,964, 541,972, and 510,680 KiB respectively. The outer matrix took 343.684 s; the crossing took 46.354 s. Governor: `powersave`.
**Owner note:** The FI ceiling now closes cleanly at z=+4 m. The visible ledges are lower SurfaceWorld terrain and are a real LOD sampling mismatch, not skirts. SurfaceWorld L1→2 and L2→3 agree closely at the spawn, but its far rings have larger outliers. The ledge fix needs permission to change SurfaceWorld LOD2; no such mesh change is included here. Nothing was committed, pushed, or stashed.
## Orchestrator review (Claude)
- Merged. The ceiling specks seen in L18's flat-square capture are gone in the L19 capture (checked by me),
and the strict audit reads 0 misses / 0 gaps at all LODs. SurfaceWorld LOD0–2, full-detail and exact
queries are unchanged; the far mesh hashes carry the `farHorizonVersion` 3→4 salt, with byte-identical
captures.
- Luna correctly stopped at the protected SurfaceWorld LOD2 rule. Ledge decision: the defect is at the
strate interface (lower stratum top near z≈−60…−73 m, sampled on 0.5/1/2 m grids at LOD1–3), which is
where the two chunk-unit conventions meet. It goes into L20 (the units/layers design round) as its
concrete test case, rather than being patched alone first.
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""Run the L9 uniform-block proof and L13 route parity audits."""
import os
import signal
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l19-audits"
OUT.mkdir(parents=True, exist_ok=True)
if not os.sched_getaffinity(0).issubset(set(range(12))):
raise SystemExit("run under taskset -c 0-11")
BINARIES = {
"clang-off": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-linux19-clang",
"gcc-default": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-linux19-gcc",
}
RECIPES = {
"floating-islands": ("-22,-19,-22.8,0,-4", "--recipe=floating-islands"),
"surface-world": ("0,-35,-487.94,0,-22", "--recipe=surface-world"),
}
passed = True
for recipe, (camera, recipe_flag) in RECIPES.items():
for compiler, binary in BINARIES.items():
name = f"{recipe}-{compiler}"
logfile = OUT / f"{name}.log"
command = ["prlimit", "--as=6442450944", "--", str(binary),
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",
"--workers=12", f"--camera={camera}", recipe_flag,
"--audit-uniform-block-proofs", "--audit-route-parity"]
started = time.monotonic()
peak_rss = 0
timed_out = False
with logfile.open("w", encoding="utf-8") as stream:
process = subprocess.Popen(command, stdout=stream, stderr=subprocess.STDOUT,
start_new_session=True)
while process.poll() is None:
pending, seen = [process.pid], set()
while pending:
pid = pending.pop()
if pid in seen:
continue
seen.add(pid)
try:
pending.extend(int(value) for value in
Path(f"/proc/{pid}/task/{pid}/children").read_text().split())
for line in Path(f"/proc/{pid}/status").read_text().splitlines():
if line.startswith("VmRSS:"):
peak_rss = max(peak_rss, int(line.split()[1]))
break
except (FileNotFoundError, PermissionError, ProcessLookupError, ValueError):
pass
if time.monotonic() - started > 900:
os.killpg(process.pid, signal.SIGTERM)
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
process.wait()
timed_out = True
passed = False
break
time.sleep(0.1)
code = process.wait()
elapsed = time.monotonic() - started
log = logfile.read_text(encoding="utf-8", errors="replace")
route_lines = [line for line in log.splitlines() if line.startswith("[RouteParityAudit]")]
proof_lines = [line for line in log.splitlines() if line.startswith("[UniformBlockProofAudit]")]
route_ok = bool(route_lines) and route_lines[-1].endswith("status=PASS")
proof_ok = bool(proof_lines) and "violations=0" in proof_lines[-1]
ok = code == 0 and not timed_out and route_ok and proof_ok
passed &= ok
print(f"[AuditRun] {name} exit={code} seconds={elapsed:.3f} peak_rss_kib={peak_rss} "
f"route={route_ok} proofs={proof_ok} status={'PASS' if ok else 'FAIL'}", flush=True)
print(f"[AuditSummary] rows={len(RECIPES)*len(BINARIES)} expected=4 "
f"result={'PASS' if passed else 'FAIL'} path={OUT}", flush=True)
raise SystemExit(0 if passed else 1)
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Run the L19 24 m SurfaceWorld crossing hash matrix."""
import os
import re
import signal
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l19-crossing"
OUT.mkdir(parents=True, exist_ok=True)
if not os.sched_getaffinity(0).issubset(set(range(12))):
raise SystemExit("run under taskset -c 0-11")
BINARIES = {
"clang-off": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-linux19-clang",
"gcc-default": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-linux19-gcc",
}
PATTERN = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
RUNS = [(1, 1), (8, 1), (12, 1), (12, 2), (12, 3), (12, 4), (12, 5)]
passed = True
for compiler, binary in BINARIES.items():
reference = None
for workers, repeat in RUNS:
name = f"{compiler}-w{workers}-r{repeat}"
logfile = OUT / f"{name}.log"
command = ["prlimit", "--as=6442450944", "--", str(binary),
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",
f"--workers={workers}", "--camera=0,-35,-487.94,0,-22",
"--camera-step=24,0,0", "--region-crossing", "--recipe=surface-world"]
started = time.monotonic()
peak_rss = 0
timed_out = False
with logfile.open("w", encoding="utf-8") as stream:
process = subprocess.Popen(command, stdout=stream, stderr=subprocess.STDOUT,
start_new_session=True)
while process.poll() is None:
pending, seen = [process.pid], set()
while pending:
pid = pending.pop()
if pid in seen:
continue
seen.add(pid)
try:
pending.extend(int(value) for value in
Path(f"/proc/{pid}/task/{pid}/children").read_text().split())
for line in Path(f"/proc/{pid}/status").read_text().splitlines():
if line.startswith("VmRSS:"):
peak_rss = max(peak_rss, int(line.split()[1]))
break
except (FileNotFoundError, PermissionError, ProcessLookupError, ValueError):
pass
if time.monotonic() - started > 900:
os.killpg(process.pid, signal.SIGTERM)
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
process.wait()
timed_out = True
passed = False
break
time.sleep(0.1)
code = process.wait()
elapsed = time.monotonic() - started
hashes = PATTERN.findall(logfile.read_text(encoding="utf-8", errors="replace"))
ok = code == 0 and not timed_out and len(hashes) == 12
if reference is None:
reference = hashes
elif hashes != reference:
ok = False
print(f"[CrossingMismatch] {name}", flush=True)
passed &= ok
print(f"[CrossingRun] {name} exit={code} seconds={elapsed:.3f} "
f"peak_rss_kib={peak_rss} hash_rows={len(hashes)} "
f"status={'PASS' if ok else 'FAIL'}", flush=True)
print(f"[CrossingSummary] rows={len(BINARIES)*len(RUNS)} expected=14 "
f"result={'PASS' if passed else 'FAIL'} path={OUT}", flush=True)
raise SystemExit(0 if passed else 1)
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""Run the L19 W1/W8/W12 x5 matrix under inherited taskset limits."""
import os
import re
import signal
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l19-matrix"
OUT.mkdir(parents=True, exist_ok=True)
if not os.sched_getaffinity(0).issubset(set(range(12))):
raise SystemExit("run under taskset -c 0-11")
BINARIES = {
"clang-off": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-linux19-clang",
"gcc-default": ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-linux19-gcc",
}
RECIPES = {
"floating-islands": "-22,-19,-22.8,0,-4",
"surface-world": "0,-35,-487.94,0,-22",
}
PATTERN = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
RUNS = [(1, 1), (8, 1), (12, 1), (12, 2), (12, 3), (12, 4), (12, 5)]
passed = True
for recipe, camera in RECIPES.items():
for compiler, binary in BINARIES.items():
if not binary.exists():
raise SystemExit(f"missing binary: {binary}")
reference = None
for workers, repeat in RUNS:
name = f"{recipe}-{compiler}-w{workers}-r{repeat}"
logfile = OUT / f"{name}.log"
command = ["prlimit", "--as=6442450944", "--", str(binary),
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", f"--workers={workers}", f"--camera={camera}",
f"--recipe={recipe}"]
started = time.monotonic()
peak_rss = 0
timed_out = False
with logfile.open("w", encoding="utf-8") as stream:
process = subprocess.Popen(command, stdout=stream, stderr=subprocess.STDOUT,
start_new_session=True)
while process.poll() is None:
pending, seen = [process.pid], set()
while pending:
pid = pending.pop()
if pid in seen:
continue
seen.add(pid)
try:
pending.extend(int(value) for value in
Path(f"/proc/{pid}/task/{pid}/children").read_text().split())
for line in Path(f"/proc/{pid}/status").read_text().splitlines():
if line.startswith("VmRSS:"):
peak_rss = max(peak_rss, int(line.split()[1]))
break
except (FileNotFoundError, PermissionError, ProcessLookupError, ValueError):
pass
if time.monotonic() - started > 900:
os.killpg(process.pid, signal.SIGTERM)
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
process.wait()
timed_out = True
passed = False
break
time.sleep(0.1)
code = process.wait()
elapsed = time.monotonic() - started
hashes = PATTERN.findall(logfile.read_text(encoding="utf-8", errors="replace"))
ok = code == 0 and not timed_out and len(hashes) == 12
if reference is None:
reference = hashes
elif hashes != reference:
ok = False
print(f"[MatrixMismatch] {name}", flush=True)
passed &= ok
print(f"[MatrixRun] {name} exit={code} seconds={elapsed:.3f} "
f"peak_rss_kib={peak_rss} hash_rows={len(hashes)} "
f"status={'PASS' if ok else 'FAIL'}", flush=True)
print(f"[MatrixSummary] rows={len(RECIPES)*len(BINARIES)*len(RUNS)} expected=28 "
f"result={'PASS' if passed else 'FAIL'} path={OUT}", flush=True)
raise SystemExit(0 if passed else 1)
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB