docs: park the ULP residue as AUDIT C10; strip the diagnostic scaffolding
Jahni's call to pin it and move on, and the right one -- six builds spent and the information stopped being worth the cost. The final run closed it as far as it can be: SDFs identical everywhere (counted unconditionally, 0 differ), yet two character-identical carve implementations in the SAME translation unit fed a provably identical input differ by 1 ULP on 126/5000. That is only possible if they compile to different instruction sequences, which /fp:fast permits based on surrounding context with no single isolable axis. Hypothesis 3 was right about the mechanism and wrong about every clean variable proposed for it, which is why four well-designed isolation tests came back negative. AUDIT C10 records the observation, what is proven (SDF bit-exact 126/126, zero isosurface crossings), the five refuted hypotheses in a table so nobody repeats them at a build each, why the settling experiment is blocked (shared-PCH / IWYU debt), and the rule that actually matters: never run both density paths in one world and never compare them for equality. That is NOT a client-desync risk -- within a binary the field is proven bit-pure and every peer runs the same path -- the cross-platform concern is C9, which stands on its own. Corrected OPSTACK-PLAN 2.6 and C9: my earlier "/fp:fast across translation units" explanation was measurably wrong and is removed rather than softened. MazeEquivalence keeps the permanent value (equivalence with ULP grading, window-invariance, box-verdict brute force) and drops the verbatim copy, three-way, bisect, inlining and constness experiments. Phase 1 closed: Maze decomposes into 7 ops, SDF bit-exact, 0 isosurface crossings, window-invariant, and 23 of 60 tiles proved uniform where ClassifyTile proves zero. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+56
-6
@@ -279,12 +279,11 @@ 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
|
||||
units may reassociate differently, worth ~1 ULP. So "the port reproduces the original exactly" is
|
||||
not an achievable bar for the op-stack work, and `OPSTACK-PLAN §2.6`'s bar (recognisably the same
|
||||
*place*, judged on a screenshot) was the right call for reasons beyond the ones it gave. The
|
||||
acceptance criterion is now encoded in `VoxelForge.OpStack.MazeEquivalence`: **hard-fail on any
|
||||
isosurface crossing, tolerate ULP-scale deltas, warn on anything larger.**
|
||||
**Benign — refactors are not bit-identical in practice.** See `§C10` for the measured detail: the
|
||||
Maze port reproduces the original's SDF *bit for bit* but its final density differs by 1-2 ULP on
|
||||
~2% of samples, with zero isosurface crossings. The acceptance criterion is encoded in
|
||||
`VoxelForge.OpStack.MazeEquivalence`: **hard-fail on any isosurface crossing, tolerate ULP-scale
|
||||
deltas, warn on anything larger.**
|
||||
|
||||
**Not benign — `ARCHITECTURE §9.1`'s multiplayer model rests on this.** The plan is "replicate the
|
||||
seed + layout + diff, never the geometry; every peer regenerates identically." That guarantee is
|
||||
@@ -333,6 +332,57 @@ risk is real. That is one build, and it settles it.
|
||||
|
||||
---
|
||||
|
||||
### C10 — The op-stack ULP residue: PARKED, with the evidence, 2026-07-27
|
||||
|
||||
**Status: accepted and closed by decision (Jahni), not by explanation.** Do not reopen this without
|
||||
reading the whole entry — five hypotheses have already been measured and refuted, and re-deriving
|
||||
them costs a build each.
|
||||
|
||||
**The observation.** `VoxelForge.OpStack.MazeEquivalence`: the ported Maze operator stack differs
|
||||
from `GetMazeDensity` on ~2% of samples (454/20000) by 1-2 ULP. Deterministic — same samples, same
|
||||
delta, same coordinates on every run.
|
||||
|
||||
**What is PROVEN by measurement, and is the reason this is benign:**
|
||||
|
||||
- **Zero isosurface crossings out of 20000.** Not one triangle would move. The two are
|
||||
*geometrically identical*.
|
||||
- **The SDF is reproduced BIT FOR BIT** — 126/126 of the mismatches, and `stack SDF != verbatim SDF`
|
||||
counted unconditionally came back **0**. So the lattice sweep, the edge hashes, the `{-1,0}³`
|
||||
node set and `VoxelSDF::Capsule` are all exactly correct. The port has no logic error in the part
|
||||
that shapes the world.
|
||||
- The entire difference is born in the final SDF→density conversion, amplified because `Blend - Sdf`
|
||||
cancels catastrophically at the edge of the blend shell.
|
||||
|
||||
**What was tested and REFUTED** (each cost a build; listed so nobody repeats them):
|
||||
|
||||
| # | Hypothesis | Refuted by |
|
||||
|---|---|---|
|
||||
| 1 | `FVector` float→double→float round-trip in the noise coords | identical result after the change |
|
||||
| 2 | A transcription slip in the roughness window / carve blend / octaves | a four-stage bisect: residue survives into `corridors + carve ONLY` |
|
||||
| 3 | `/fp:fast` reassociating across **translation units** | three-way test: generator TU == test TU exactly (0 differ) |
|
||||
| 4 | Different **inlining context** (virtual call vs straight-line) | `FORCEINLINE` vs `FORCENOINLINE` in one TU: 0 differ |
|
||||
| 5 | **Compile-time-constant** `Blend` vs runtime member | const and runtime forms bit-identical to each other; both miss the verbatim on the same 126 |
|
||||
|
||||
**Where that leaves it.** Two carve implementations, character-identical, in the **same translation
|
||||
unit**, fed a **provably identical** input, produce outputs differing by 1 ULP on 126 of 5000. For
|
||||
deterministic code that is only possible if they compile to different instruction sequences — which
|
||||
is exactly what `/fp:fast` permits, based on surrounding context, with no single isolable axis. So
|
||||
hypothesis 3 was right about the *mechanism* and wrong about every clean variable proposed for it.
|
||||
|
||||
**The one experiment that would settle it** is building this module with
|
||||
`FPSemantics = FPSemanticsMode.Precise`. **It is blocked**: doing so costs VoxelForge the engine's
|
||||
shared PCH and exposes ~30 missing includes across seven files (see the note in `VoxelForge.Build.cs`).
|
||||
Clearing that IWYU debt is worth doing on its own terms; it is not worth doing to chase 1 ULP.
|
||||
|
||||
**The operational rule that DOES matter, and is the real takeaway:**
|
||||
**never run the archetype `switch` and the operator stack in the same world, and never compare their
|
||||
outputs for equality.** A half-migrated strate would produce a seam. This is **not** a client-desync
|
||||
risk — within one binary the field is proven bit-pure across threads and query order
|
||||
(`VoxelForge.Determinism.DensityPurity`) and every peer runs the same path. The genuine
|
||||
cross-platform concern is `§C9`, which stands independently.
|
||||
|
||||
---
|
||||
|
||||
### Threading — what's *right*, for the record
|
||||
|
||||
Worth stating plainly, because it's the part that's easy to get wrong and this doesn't:
|
||||
|
||||
Reference in New Issue
Block a user