feat: height-space operator family — SurfaceWorld step 1, and C10 is solved
Maze and Slab now report BIT-IDENTICAL: FPSemantics = Precise, set for cross-platform play, dissolved the ULP residue. Hypothesis 3 had the right mechanism all along — under /fp:fast the compiler transforms by surrounding context with no isolable axis, which is exactly why five one-variable experiments all came back negative. Removing the permission removed the difference. Nobody solved C10; C9 got fixed for an unrelated reason and C10 fell out of it. SurfaceWorld step 1 forced an architectural decision. DECOMPOSITION section 5 notes the height ops operate on Z values rather than density, then lists them as children of FHeightfieldSource. Writing them made the consequence unavoidable: they do not fit IVoxelDensityOp. No input Z (they produce one), XY-pure per column rather than per voxel, and they write neither channel. Forcing them in would need a per-voxel channel for a column property, or one opaque op — section 2.5's failure mode. So height space gets its own contract: VoxelHeightOp.h (FVoxelHeightSample with Height + Relief, IVoxelHeightOp, FVoxelHeightStack) and five ops. Relief is the original's M — produced by the structural source, consumed by the terrace gate. Section 0.1 found density needed a second channel; this found terrain needs a second space. The type system now forbids for free what AUDIT 6.3 warns about: a height stack cannot hold Z-dependent data because there is no Z in the signature. Deliberately staged — this touches nothing on the density path. If height space had not decomposed cleanly, it shows up here for one test rather than after building the adapter, the column cache integration and the dispatch on top. The test runs twice; the second pass is load-bearing because the F20 terrain ops are off by default, so a defaults-only run leaves all four modifiers untested. It also brute-forces MaxDisplacement, since a false bound would later be a hole. ComputeSurfaceTerrainZ moved private -> public for the test, same justification as GetSlabDensity. Old declaration removed. UNVERIFIED: not compiled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -361,6 +361,28 @@ FOverhangShelfMod Union ⚠️ per-voxel, NOT XY-pure — the
|
||||
[structural post ×4]
|
||||
```
|
||||
|
||||
> ### ⚠️ RESOLVED 2026-07-27 — the height ops needed a SECOND OP FAMILY, not a sub-list
|
||||
>
|
||||
> This section says the height ops *"operate on Z values in the column, not on density"* and then
|
||||
> lists them as children of `FHeightfieldSource`. Writing them made the consequence unavoidable:
|
||||
> **they do not fit `IVoxelDensityOp` at all.** Its signature is `Eval(x, y, z, FVoxelOpSample&)` —
|
||||
> per voxel, density + SDF. A height op has **no input Z** (it produces one), is XY-pure (once per
|
||||
> column), and writes neither channel.
|
||||
>
|
||||
> The two ways to force it were both bad: a per-voxel third channel for what is a **column**
|
||||
> property, or collapsing all five into one opaque op — `OPSTACK-PLAN §2.5`'s explicit failure mode.
|
||||
>
|
||||
> **So height space got its own contract: `VoxelHeightOp.h`** (`FVoxelHeightSample` with
|
||||
> `Height` + `Relief`, `IVoxelHeightOp`, `FVoxelHeightStack`). Same lesson as `§0.1`, one step
|
||||
> further: §0.1 found that density needed a second *channel*; this found that terrain needs a second
|
||||
> *space*. Verified by `VoxelForge.OpStack.SurfaceHeightEquivalence` before anything was built on
|
||||
> top of it — deliberately, so a wrong answer would have cost one test rather than a whole port.
|
||||
>
|
||||
> **Bonus the type system gives for free:** a height stack cannot contain Z-dependent data, because
|
||||
> there is no Z in the signature to put there. `AUDIT §6.3` warns that Z-dependent data smuggled into
|
||||
> `FSurfaceColumn` silently corrupts every chunk in the vertical stack and that `ValidateDeterminism`
|
||||
> would not catch it. Here the *type* forbids it rather than a convention.
|
||||
|
||||
**Critical distinction the port must preserve:** the height ops (`FCliffHeightMod` and friends)
|
||||
operate on **Z values in the column**, not on density. They are XY-pure and belong in
|
||||
`PrepareChunk`/the column cache. `FOverhangShelfMod` operates per voxel and re-samples the
|
||||
|
||||
Reference in New Issue
Block a user