feat: Phase 2 first port — FlatPlain + CrystalChamber collapse into one op

Jahni closed OPSTACK-DECOMPOSITION 3.1: the slab noise Z term was not
intentional character. Phase 1 also closed — the visual A/B on Maze passed.

Two changes, deliberately together, kept attributable by the test:

1. Design: GetSlabDensity's floor and ceiling noise lose their Z terms. A floor
   height no longer depends on the altitude you sample it from. The ceiling keeps
   its + 3000.0f, which is a decorrelation offset, not a Z term. The world
   re-tunes once — a different slice of the noise field, not a worse one.

2. Refactor: the now-XY-pure function ports to FSlabVoidSource + FGridColumnMod
   plus the three structural ops. BuildSlabStack has NO branch on archetype
   because GetSlabDensity never had one — CrystalChamber is FlatPlain with a
   bigger CeilingRoughness. 8 archetypes -> 7.

SlabEquivalence compares against the reference AS IT IS NOW and runs the whole
battery on both slots, so green means the port is a pure refactor and any visual
delta is attributable to the Z-term removal alone. The attribution comes from the
test, not from splitting it across two builds.

The payoff 3.1 was actually about: FSlabVoidSource::ClassifyBox is exact and needs
no sampling. FBM is contractually [-1,1], so both surfaces live in Z bands with
known bounds — a tile below the floor band is provably solid, a tile between the
bands provably air. ClassifyTile proves zero tiles for these archetypes today.
FGridColumnMod answers Identity when no column reaches the box, which is what lets
the source's AllAir verdict survive the fold.

UNVERIFIED: not compiled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 15:30:26 +02:00
parent 974e795b66
commit 644339def5
9 changed files with 781 additions and 17 deletions
+66
View File
@@ -876,3 +876,69 @@ field rename would show up here.
recognisably the same maze, judged on a screenshot). Then Phase 2, starting with the §3.1 question.
---
## 2026-07-27 — PHASE 1 CLOSED (visual A/B passed). Phase 2 opened: the slab collapse.
**Phase 1's acceptance bar is met.** Jahni built step 3, ticked `bUseOperatorStack` on the Maze
strate and compared: *"it's hard to see with our current maze (which is simple in architecture) but
seems like it's pretty similar, if not entirely similar."* That is §2.6's bar — recognisably the
same maze — and it is worth being precise about how much weight it carries.
**The screenshot is the weakest evidence Phase 1 has, and that is fine, because it was never
carrying the argument.** A simple maze is a poor visual discriminator: "hard to tell apart" is
*exactly* what the measurements already predicted, since **0 of 20 000 samples cross the
isosurface** — no triangle can move. The A/B's job was to catch the class of error the numbers
cannot see (wrong params reaching the stack, wrong strate, wrong wiring), and it did that. The
geometric claim rests on the numbers, and always did.
### Phase 2, first port: FlatPlain + CrystalChamber → ONE op
**§3.1 answered by Jahni: the Z term can go.** So it is gone, and this is the change that makes the
rest worth doing.
**Two separate changes landed together, deliberately, and the test is what keeps them attributable:**
1. **The design change**`GetSlabDensity`'s floor and ceiling noise lost their Z terms
(`WorldZ * FF * 0.05f``0.0f`; `WorldZ * CF * 0.08f + 3000.0f``3000.0f`, keeping the
decorrelation offset). The world **re-tunes once**: a different slice of the noise field means a
different floor/ceiling shape. Not a degradation — a different draw.
2. **The refactor** — the now-XY-pure function ported to `FSlabVoidSource` + `FGridColumnMod`,
plus the three structural ops. Five ops.
`SlabEquivalence` compares the stack against `GetSlabDensity` **as it is now**, so: green ⇒ the port
is a pure refactor ⇒ **any visual delta is attributable to the Z-term removal and nothing else.**
That is why both could go in one build without losing the ability to say which one caused what —
the attribution comes from the test, not from the build order.
**Why this port matters more than its size:** `BuildSlabStack` has **no branch on archetype**,
because `GetSlabDensity` never had one either — CrystalChamber IS FlatPlain with a bigger
`CeilingRoughness`. The test runs the identical battery on both slots, so "two archetypes are one
op" is demonstrated rather than asserted. **8 archetypes → 7.**
**And the perf claim, which is what §3.1 was really about:** `FSlabVoidSource::ClassifyBox` is
**exact and needs no sampling**. `VoxelNoise::FBM` is contractually `[-1,1]`, so both surfaces live
in Z bands with known bounds — a tile below `FloorZ - FloorAmp` is provably solid, a tile strictly
between the bands is provably air. A slab strate is mostly solid rock below its floor, so this
should prove a large fraction of tiles. `ClassifyTile` proves **zero** today. The test prints the
count per archetype; that number is the whole return on the Z term.
`FGridColumnMod` returning `Identity` when no column reaches the box is what lets the source's
`AllAir` survive the fold — otherwise columns would kill every air verdict in the strate.
**UNVERIFIED: none of this is compiled.** Likely error spots, in order:
- `VoxelForgeOpStackSlabTest.cpp` is new — check it is picked up by the module's build.
- The lambda `RunForSlot` captures `World`/`Gen` by reference and calls `AddError`/`TestEqual` on
the test instance; `TestEqual`'s name argument is built with `*FString::Printf(...)`.
- `FGridColumnMod::GetCells` returns a reference to a `thread_local` — intentional (same pattern as
`FLatticeCorridorSource::GetCellEdges`), but it is `const` while mutating the thread_local.
- `static constexpr float ColBlend` used inside `FMath::Max`/comparisons — may need a definition
under older MSVC ODR rules if it is ever odr-used.
- `FSlabGenerationParams` must be complete in `VoxelDensityOpStack.h` (it comes via
`VoxelStrateTypes.h`, already included).
**Next single action:** build, run `VoxelForge.OpStack.SlabEquivalence`, and **read the two
"proved uniform" numbers** — they are the measured payoff of §3.1. Then tick `bUseOperatorStack` on
a FlatPlain or CrystalChamber strate for the visual A/B. Expect the floor/ceiling shape to have
changed from the Z-term removal; the question is whether it still reads as the same *kind* of place.
---