VoxelHash::Cell/Pair, legacy Cellular3D and the shared Core cellular hash added 0x7FFFFFFF to a signed int32 before casting to uint32; overflow is undefined, so Clang and GCC placed cave passage 1 differently (first differing sample at LOD1 tile (0,64,-512)). The bias is now done in unsigned arithmetic, in both the standalone copy and the Unreal plugin header (Source/VoxelForge/Public/VoxelCaveMorphology.h). Native caves, motifs and lattice now stream LOD0-8 with skirts and cross-level transitions. New verify.py --speed-matrix runs every generator on one asserted-identical view (5 interleaved runs): motifs 1.33, profiles 1.30-1.32, caves 1.41, natural SW 1.67, lattice 1.70, FI 4.93 s whole view. fast/medium/full PASS, Clang/GCC peer hashes equal. Research R29 (open-edge ledge) and R30 (compiler-divergence suspects). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
6.7 KiB
Linux 60 report
Result and root cause
The continuation is green. The full tier and speed matrix passed after fixing signed-overflow undefined behavior in the shared voxel hash.
The first differing density was LOD1 tile (0,64,-512), step 2, sample order 23,658 at (64,82,-476). Before the fix, Clang returned -4.0078125 (0xc0804000) and GCC returned -4.125 (0xc0840000). The sample follows the mesher's LOD X8/boundary scalar path into DensityAtLattice and the compiled analytic TunnelNetwork field. Its upstream cave passage placement comes from UVoxelStrateManager::GeneratePassages → PassageRandom01 → VoxelHash::Cell(i,c,seed).
VoxelHash::Cell added 0x7fffffff to a signed cell coordinate before casting to uint32; connection c=1 overflowed int32, so the compiler-dependent hash changed the passage coordinates and cave geometry. The trace showed passage pair (0,1) diverging, followed by all 21 control points of passage 1. The fix performs the bias in unsigned arithmetic in Cell, Pair, legacy Cellular3D, and the shared Core cellular hash. It does not quantize density. After the fix both compilers produced the same pair (0,1) coordinates, the same 44 passage points, and 0xc0804000 at the first sample. The evaluator version is now 211.
Before/after traces are in Saved/Linux/l60/diag/caves-{clang,gcc}-probe.log and Saved/Linux/l60/diag/cache/fullcache-{clang,gcc}.log.
Far LOD support and seam checks
All full-view fixtures use max level -1, clip radius 3, and max clip level 8. All three generators streamed LOD0–8 with skirts.
- Caves: X8 and Z-run gates detect caves in manager and resolved stratum mappings, then use scalar lattice sampling for cave samples. Clang/GCC cave tile hashes match at W1/W8/W12, including random views at LOD1–2. The cave-mouth transition crossed levels 0–8 (432 entering tiles).
- Motifs: The fixed motif field streams through the existing rings, caps, and skirts. The monolith transition crossed levels 0–8 (295 entering tiles); whole-surface foot, cap, and platform-edge audits passed.
- Lattice: The fixture selects native lattice stratum 1 and uses the existing ring and skirt path. The helix transition crossed levels 0–8 (380 entering tiles); field, interval, reachability, and shape-free audits passed.
Hard, gradient, and interleaved stratum transitions passed with zero hole columns and zero air samples. Far-LOD cave, motif, and lattice JPEG captures passed their audits and are under 300 KB.
Comparable speed matrix
verify.py full --speed-matrix ran five interleaved repetitions per generator, rotating generator order. Every run used camera (-12,-118,-20 m), rotation (0°,0°), clip radius 3, max clip level 8, max level -1, camera step 24 m, 12 workers, and shared column cache. The stage asserted the shared HeadlessConfig fields, whole-view and per-LOD tile-count ranges, and stable counts across repetitions. It passed for all eight generators. Every listed tile count occurred in all five runs; timings are medians from the final full run.
| Generator | Tiles | Whole view (s) | First tile (s) | Near ring (s) | Moving p50 (ms) | Moving p95 (ms) |
|---|---|---|---|---|---|---|
| Natural SW | 2,130 | 1.669 | 0.502 | 0.519 | 63.971 | 119.891 |
| periodicHills | 1,986 | 1.311 | 0.454 | 0.479 | 60.267 | 115.648 |
| mirroredRelief | 1,986 | 1.317 | 0.471 | 0.490 | 60.568 | 115.474 |
| flatField | 1,986 | 1.303 | 0.465 | 0.485 | 60.627 | 117.144 |
| Floating Islands | 2,130 | 4.926 | 0.817 | 0.977 | 528.939 | 871.290 |
| Caves | 2,130 | 1.408 | 0.489 | 0.507 | 61.099 | 118.508 |
| Motifs | 1,986 | 1.326 | 0.476 | 0.493 | 60.107 | 116.104 |
| Lattice | 2,130 | 1.701 | 0.539 | 0.561 | 69.572 | 137.585 |
Full run records and common config are in Saved/Linux/l60/speed-matrix.json.
Captures
Saved/Linux/l60/captures/caves-far-lod.jpg— 16,642 bytes; SHA-25655f8d3d2de76541e9f1c1d09b771af40bfbb37b1ce5afc0b2f70419b84ed71a3Saved/Linux/l60/captures/motifs-far-lod.jpg— 24,926 bytes; SHA-256bfc5d8ddebc3706fedd6108653b4777fac4bac44e71f60c8e58b3508c14c3aa6Saved/Linux/l60/captures/lattice-far-lod.jpg— 30,714 bytes; SHA-256c261728e48975f01c712e31594b4284eede289b73e793e6204b78cb8ff2a2947
Hashes and tiers
Clang 19 and GCC 14 builds used FP contraction off and 12 jobs. Final source stamp and source-manifest SHA-256: 902a0d8e45f895d1b53c0a86999adee5598ff77e1752aa7ea90397520cf7b82d.
- Clang headless:
dcf6286bcecac382f9cce2458e7c327485e9b8b993c3d544e627a8fc964947fa - GCC headless:
be86f90f993ba27bfde235e0850ea783298396dc03456360cf4bb3fd4815988b - Offscreen capture:
b8f7a441c0a41be6ebd61721ff903832a51291df7a886e669b9084d84441d4c5
| Tier | Status | Checks / runs | Elapsed |
|---|---|---|---|
| Fast | PASS before hash fix | 453 / 113 | 335.7 s |
| Medium | PASS before hash fix | 968 / 289 | 1,559.1 s |
| Full continuation trial 1 | FAIL: stale binary stamp; no checks ran | — | 0.0 s |
| Full continuation trial 2 | PASS on source stamp 914af3... |
2,304 / 660 | 3,256.9 s |
| Full continuation trial 3 | PASS on final source stamp, including speed matrix | 2,304 / 660 | 3,260.6 s |
Fast and medium were not rerun as standalone tiers after the hash change; the passing full run executed their checks at the current source stamp.
Trials and failed runs
The prior L60 work used 15 trials. This continuation used 3 of its 10-trial budget. Trial 1 stopped before checks because it found stale Clang/GCC executables. Trial 2 passed, then the final source review restored the mesher's existing <bit> include and changed the source stamp, so trial 3 rebuilt and reran full against the exact final source. The pre-fix trial 15 had failed peer determinism on the same six LOD1 and eight LOD2 tile keys across four seeded views. Trial 3 had no failed checks; negative controls reported expected failures.
Orchestrator review (Claude)
Accepted. The stamp matches the final Clang and GCC builds (902a0d8e…); full PASS, including the speed matrix.
The root cause is a real cross-platform determinism bug: VoxelHash::Cell/Pair/Cellular3D added
0x7FFFFFFF to a signed int32 (signed overflow is undefined behaviour), so passage placement became
compiler-dependent. The same code lives in the Unreal plugin (Source/VoxelForge/Public/VoxelCaveMorphology.h,
identical to the standalone copy before the fix), and only the standalone copy had been fixed. I applied the identical
fix to the plugin header and confirmed the two copies match. MSVC typically wraps there, so the owner's existing
worlds are most likely unchanged, but this needs his Windows build. No other signed-bias pattern remains in Source/
or Core. The comparable speed matrix is now a standing verify.py full --speed-matrix stage.