fix(core): worker-count-dependent tiles near passage support columns (L44); random-camera determinism sweep

L27 added passage support columns, but World::isTileShapeFree only bounded the route and bridge, so tiles
touched by a column could be approved for early native-only generation; depending on scheduling they used
that incomplete field or the compiled one (six LOD0 tiles differed between W1 and W12 at an SW camera near
the arrival mouth). The shape-free proof now includes a conservative envelope for every possible column.
The compiled world is unchanged (the old W1 variant), so no version bump. verify tiers gain a seeded
(SplitMix64 0x4c3434) random-camera W1/W8/W12 sweep across both recipes and several clip settings; it fails
before the fix and passes after. fast/medium/full PASS; cost within noise. Research R11: suspect review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-23 23:00:21 +02:00
1 parent 422dd7761a
commit 036bd530fc
6 files changed
+288 -18

No files matched your search

+126
View File
@@ -50,6 +50,11 @@ CLANG = OUT / "bin" / f"VoxelForgeCoreHeadless-{ROUND_NAME}-clang"
GCC = OUT / "bin" / f"VoxelForgeCoreHeadless-{ROUND_NAME}-gcc"
RENDERER = OUT / "bin" / f"VoxelForgeOffscreenCapture-{ROUND_NAME}-clang"
HASH_RE = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
TILE_HASH_RE = re.compile(
r"^\[PipelineTileHash\] lod=(-?\d+) x=(-?\d+) y=(-?\d+) z=(-?\d+) "
r"density=(0x[0-9a-f]+) mesh=(0x[0-9a-f]+) "
r"payload=(0x[0-9a-f]+) topology=(0x[0-9a-f]+)$", re.M)
CAMERA_SWEEP_SEED = 0x4C3434
RECIPE_RE = re.compile(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", re.M)
@@ -284,6 +289,122 @@ def run_hash_pairs(runner: VerificationRunner,
f"current owner hashes match {baseline.name}; hashes={len(old_hashes)}")
class _SplitMix64:
"""Small fixed-seed generator whose camera sequence is independent of Python random."""
def __init__(self, seed: int):
self.state = seed & 0xffffffffffffffff
def unit(self) -> float:
self.state = (self.state + 0x9e3779b97f4a7c15) & 0xffffffffffffffff
value = self.state
value = ((value ^ (value >> 30)) * 0xbf58476d1ce4e5b9) & 0xffffffffffffffff
value = ((value ^ (value >> 27)) * 0x94d049bb133111eb) & 0xffffffffffffffff
value ^= value >> 31
return (value >> 11) / float(1 << 53)
def between(self, low: float, high: float) -> float:
return low + (high - low) * self.unit()
def seeded_camera_positions(count: int) -> list[tuple[float, float, float, float, float]]:
rng = _SplitMix64(CAMERA_SWEEP_SEED)
positions: list[tuple[float, float, float, float, float]] = []
for index in range(count):
if index == 0:
# Stay in the known failing 8 m tile neighbourhood while still deriving the
# camera from the fixed seed. The negative Y offset keeps it below the 32 m seam.
x = -8.918 + rng.between(-0.02, 0.02)
y = 31.95 - rng.between(0.005, 0.035)
z = -513.083 + rng.between(-0.02, 0.02)
else:
x = rng.between(-900.0, 900.0)
y = rng.between(-900.0, 900.0)
while math.hypot(x + 46.45, y + 472.88) < 320.0:
x = rng.between(-900.0, 900.0)
y = rng.between(-900.0, 900.0)
if index % 2:
z = -256.0 + rng.between(-12.0, 12.0) # SurfaceWorld strate 0.
else:
z = -1536.0 + rng.between(-120.0, 120.0) # FloatingIslands strate 1.
yaw = rng.between(-180.0, 180.0)
pitch = rng.between(-35.0, 35.0)
positions.append((x, y, z, yaw, pitch))
return positions
def parse_tile_hashes(output: str) -> dict[tuple[int, int, int, int], tuple[str, ...]]:
rows: dict[tuple[int, int, int, int], tuple[str, ...]] = {}
for match in TILE_HASH_RE.finditer(output):
key = tuple(int(match.group(i)) for i in range(1, 5))
rows[key] = tuple(match.group(i) for i in range(5, 9))
return rows
def run_random_camera_sweep(runner: VerificationRunner, binaries: tuple[Path, ...],
camera_count: int,
configurations: tuple[tuple[int, int, int], ...]) -> None:
positions = seeded_camera_positions(camera_count)
for binary in binaries:
compiler = compiler_name(binary)
for recipe in ("surface-world", "floating-islands"):
for camera_index, camera in enumerate(positions):
x, y, z, yaw, pitch = camera
camera_flag = f"--camera={x:.6f},{y:.6f},{z:.6f},{yaw:.3f},{pitch:.3f}"
for clip_radius, max_clip_level, max_level in configurations:
settings = (clip_radius, max_clip_level, max_level)
label = (f"random-camera-{compiler}-{recipe}-s{CAMERA_SWEEP_SEED:06x}"
f"-p{camera_index:02d}-r{clip_radius}-c{max_clip_level}-m{max_level}")
signatures: dict[int, dict[tuple[int, int, int, int], tuple[str, ...]]] = {}
for workers in (1, 8, 12):
name = f"{label}-w{workers}"
flags = ["--stream-hash-tiles", camera_flag,
f"--clip-radius={clip_radius}",
f"--max-clip-level={max_clip_level}",
f"--max-level={max_level}", "--render-distance-chunks=0"]
row, output = runner.run_cpp(name, binary, OWNER, recipe, flags,
expected_style=2,
expected_strate_styles={"0": 2, "1": 1},
workers=workers,
layout_path=OUT / "layouts" / f"{name}.json")
row["camera_sweep_seed"] = CAMERA_SWEEP_SEED
row["camera_position_m"] = [round(value, 6) for value in camera[:3]]
row["camera_rotation_degrees"] = [round(value, 3) for value in camera[3:]]
row["sweep_settings"] = {
"clip_radius": clip_radius,
"max_clip_level": max_clip_level,
"max_level": max_level,
}
current = parse_tile_hashes(output)
signatures[workers] = current
whole = re.search(r"^\[PipelineWholeViewHash\] tiles=(\d+)", output, re.M)
expected_rows = int(whole.group(1)) if whole else -1
runner.require(f"{name}:tile-hash-rows",
bool(current) and len(current) == expected_rows,
f"rows={len(current)} expected={expected_rows} settings={settings}")
camera_text = (f"seed=0x{CAMERA_SWEEP_SEED:06x} camera_m="
f"({x:.3f},{y:.3f},{z:.3f}) recipe={recipe} settings={settings}")
for left, right in ((1, 8), (1, 12), (8, 12)):
left_rows, right_rows = signatures[left], signatures[right]
keys = set(left_rows) | set(right_rows)
density_diff = [key for key in keys
if left_rows.get(key, (None,))[0] != right_rows.get(key, (None,))[0]]
mesh_diff = [key for key in keys
if left_rows.get(key, (None, None))[1]
!= right_rows.get(key, (None, None))[1]]
payload_diff = [key for key in keys
if left_rows.get(key, (None, None, None))[2]
!= right_rows.get(key, (None, None, None))[2]]
topology_diff = [key for key in keys
if left_rows.get(key, (None, None, None, None))[3]
!= right_rows.get(key, (None, None, None, None))[3]]
detail = (f"{camera_text} W{left}=W{right} "
f"density_tiles={len(density_diff)} mesh_tiles={len(mesh_diff)} "
f"payload_tiles={len(payload_diff)} topology_tiles={len(topology_diff)} "
f"sample_coords={sorted(density_diff or mesh_diff)[:6]}")
runner.require(f"{label}:W{left}-W{right}",
left_rows == right_rows, detail)
def run_ring(runner: VerificationRunner, *, full: bool) -> None:
script = LINUX37 / "RunRingAuditsL37.py"
audit_inputs = [script,
@@ -604,6 +725,8 @@ def run_medium_suite(runner: VerificationRunner, *, both_compilers: bool = False
run_transitions_and_invariants(runner, binaries)
run_ring(runner, full=True)
run_captures_and_mesh_audits(runner)
run_random_camera_sweep(runner, (CLANG,), 5,
((3, 0, 0), (2, 1, 1), (3, 2, 1)))
def run_gcc_supplement(runner: VerificationRunner) -> None:
@@ -635,6 +758,7 @@ def main() -> int:
owners = run_owner_passages(runner, (CLANG,))
run_regression_controls(runner)
run_hash_pairs(runner, owners)
run_random_camera_sweep(runner, (CLANG,), 3, ((3, 0, 0),))
run_ring(runner, full=False)
elif ARGS.tier == "medium":
run_medium_suite(runner, both_compilers=False)
@@ -643,6 +767,8 @@ def main() -> int:
if not runner.reuse_passed_tier(medium_summary, "medium"):
run_medium_suite(runner, both_compilers=False)
run_gcc_supplement(runner)
run_random_camera_sweep(runner, (GCC,), 5,
((3, 0, 0), (2, 1, 1), (3, 2, 1)))
run_30_cell_determinism(runner)
run_cost_pairs(runner)
# The validated medium summary carries the final canonical capture set.