diff --git a/AUDIT-2026-07.md b/AUDIT-2026-07.md index e09259f..ba156ac 100644 --- a/AUDIT-2026-07.md +++ b/AUDIT-2026-07.md @@ -263,6 +263,20 @@ and UBT's own doc for that mode: *"FP math isn't IEEE-754 compliant: the compile transform math expressions in ways that might result in differently rounded results from what IEEE-754 requires."* The plugin sets no `FPSemantics` override, so it gets the default. +**⚠️ And the default is not the same default everywhere.** `ClangToolChain.cs` — used by Linux, Mac, +and Windows-with-Clang: + +```csharp +case FPSemanticsMode.Default: // Default to precise FP semantics. +case FPSemanticsMode.Precise: + Arguments.Add("-ffp-contract=off"); +``` + +`VCToolChain` additionally forces `Precise` when the Windows compiler is Clang. So **the same +`FPSemanticsMode.Default` resolves to opposite float models per toolchain**, and Windows/MSVC is the +only imprecise configuration in the engine's defaults. Two builds of identical source are therefore +not merely *permitted* to diverge — they are compiled under different rules. + **Two consequences, one benign and one not:** **Benign — refactors cannot be bit-identical.** The same expression compiled into two translation @@ -292,11 +306,30 @@ stated. is a real desync source, and it will present as rare, unreproducible, geometry-only divergence: approximately the worst bug class to diagnose. +**Calibration, so this isn't over-feared.** In 20,000 Maze samples, **zero** crossed the isosurface +under a 1-ULP perturbation. Divergence would therefore be occasional *single-voxel* surface +differences, not visibly different terrain — sub-voxel, near-certainly imperceptible for +collision-vs-visual mismatch. The case that would genuinely bite is **topological**: a cave +pinch-point that connects on one build and not the other. Rare — but "rare and unreproducible" is +the expensive kind of rare. + +**Even `Precise` everywhere would not buy guaranteed cross-platform bit-identity.** `FMath::Sqrt` is +IEEE-exact and `VoxelNoise`'s hash-gradient core is integer + basic arithmetic, so those are safe. +But `FMath::Sin`/`Cos` (disturbance bridge/ridge angles) route to platform libm, which is not +bit-standardised across OSes. Aligning the FP model closes the large gap, not every gap. + **The knob, if it turns out to matter:** `ModuleRules.FPSemantics = FPSemanticsMode.Precise` in -`VoxelForge.Build.cs` restores IEEE semantics for this module only. **Do not do this speculatively** — -the density path is the plugin's hot loop, `/fp:precise` blocks exactly the vectorisation and -contraction that T2.a's SIMD noise work was chasing, and the cost is unmeasured. It is a decision to -take with a profile in hand and a confirmed cross-platform requirement, not a tidy-up. +`VoxelForge.Build.cs`, module-scoped. Note it would *align Windows with every other platform's +default* rather than being a one-sided cost. **Still do not do this speculatively** — the density +path is the plugin's hot loop, precise semantics block exactly the vectorisation and contraction +T2.a's SIMD noise work was chasing, and the cost is unmeasured. Decision needs a profile in hand and +a confirmed cross-platform requirement. + +**Verification, when it becomes relevant:** the cross-build claim above is *inferred*, not measured — +no Linux build has been made. The cheap decisive test is to compile the plugin once with +`FPSemantics = Precise` on Windows and re-run `VoxelForge.OpStack.MazeEquivalence`: if the residual +454-sample difference vanishes, the FP model is confirmed as the sole cause and the cross-toolchain +risk is real. That is one build, and it settles it. ---