feat(strate): the layout is a set, not a sequence -- and the suite is green
Tier 0. Reordering Settings->StratePool in the editor used to change every world in the game, because Initialize Fisher-Yates shuffled the array in editor order. The pool is now sorted by stable soft-asset path before the shuffle, so the layout is a pure function of (seed, pool contents as a SET). The selection algorithm itself is untouched -- same Fisher-Yates, same cycling, same FixedStrates handling, same Z ranges. Sorting by pointer would have looked right and been load-order dependent, which is the trap here. GeneratePassages walked one sequential FRandomStream across every strate, so changing an early connection count shifted every later passage. Each draw is now a salted VoxelHash of (seed, boundary index, connection index), with the distributions preserved exactly -- ToFloat01 returns [0,1), so Lerp(Min,Max,t) reproduces FRandRange precisely. Codex implemented it and caught a real flaw in my spec: I asked for a test that permutes the pool and asserts the passages match, but once the layout is order-independent that test cannot fail whether or not the passage fix works -- the layout comes out identical, so even the old sequential stream would agree. It added the perturbation that actually bites: change an early connection count and verify every later boundary keeps its own values. It also contradicted me on passage type being randomly drawn. It isn't, and it preserved that. Built VoxelMEditor clean, then ran the suite headless: 16 succeeded, 0 failed, 0 not run. That also closes the thread OPSTACK-HANDOFF.md left open --4d33321and91585eawere built but never re-verified, and both acceptance conditions are now met: violations 0 everywhere (12 of 40 TunnelNetwork tiles proved over 15972 brute-forced voxels), all equivalences green. No revert needed. Expected: every seed now lays out differently than before. Accepted, pre-content-lock. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPUuCtn5zTLui6WybLbkNb
This commit is contained in:
1 parent
a60138b19c
commit
10a8bbc677
5 files changed
+570
-32
No files matched your search
+3
-2
@@ -353,8 +353,8 @@ Maps depth→strate at runtime; owns passages.
|
||||
- `FStrateSlot` (h:84): definition + chunk-Z range + index.
|
||||
| Method | .cpp line | Role |
|
||||
|--------|-----------|------|
|
||||
| `Initialize` | 10 | Builds the stacked layout from settings+seed (fixed slots + shuffled pool), logs every **cave** slot whose operator-stack opt-in is disabled, then `GeneratePassages`. SurfaceWorld is deliberately excluded from that diagnostic because its exact-lattice T1.d path does not depend on the flag. |
|
||||
| `GeneratePassages` | 146 | Deterministic passages between consecutive strates (per-type control points). |
|
||||
| `Initialize` | 10 | Builds the stacked layout from settings+seed (fixed slots + pool sorted by soft-asset path, then unchanged Fisher-Yates shuffle), logs every **cave** slot whose operator-stack opt-in is disabled, then `GeneratePassages`. SurfaceWorld is deliberately excluded from that diagnostic because its exact-lattice T1.d path does not depend on the flag. |
|
||||
| `GeneratePassages` | 146 | Deterministic passages between consecutive strates (per-strate `PassageConfig::Style` control points; auto passages retain the existing `EVoxelPassageType` default); placement and shape values are independently salted hashes of seed + boundary slot + connection index. |
|
||||
| `EvaluateModifierSDF` | 357 | SDF of passages at a point (for carving). Per-chunk `thread_local` shortlist (`PassagesVersion`-stamped) → far chunks return `FLT_MAX` without walking `Passages`. §8.10. |
|
||||
| `AnyPassageNearBox` | — | Conservative sphere-vs-AABB test of every passage's bound against a voxel box (+carve blend pad). Per TILE (ClassifyTile guard), never per voxel. |
|
||||
| `FindSlotIndexForChunkZ` | 427 | Z → layout index. |
|
||||
@@ -453,6 +453,7 @@ The plugin's first tests (`OPSTACK-PLAN.md` Phase 0.5). Run them from the editor
|
||||
| `VoxelForgeOpStackIslandTest.cpp` | `VoxelForge.OpStack.FloatingIslandEquivalence` | The port that runs the stack **backwards** — void + fill vs rock + carve, same classes with the opposite sign. Counts interior-solid and open-void samples separately (on this archetype an aggregate "N solid" is dominated by the seal bands and says nothing about the islands). Counts `AllSolid` and `AllAir` verdicts **separately** too: `AllAir` is the one no cave archetype could ever prove, and it is the entire perf argument here. |
|
||||
| `VoxelForgeOpStackMazeTest.cpp` | `VoxelForge.OpStack.MazeEquivalence` | **Phase 1's load-bearing test.** The 7-op Maze stack vs `GetMazeDensity` over 20k points (aiming for bit-identity; a side-of-iso disagreement is the hard fail), plus purity across workers and brute force on every box verdict the stack emits. Reports how many tiles the stack can prove uniform — today's `ClassifyTile` proves **zero** for any cave archetype. |
|
||||
| `VoxelForgeStrateParamCoverageTest.cpp` | `VoxelForge.Determinism.StrateParamBlendCoverage` | **The X-macro guard** (added 2026-08-17). `FStrateGenerationParams::Lerp` blends the hand-written `VF_STRATE_PARAM_FIELDS` list, **not** the struct — so a field added to one and not the other compiles, tests green, and silently takes its **default** inside every Gradient/Interleaved transition band. This expands the X-macro a **third** way (after LERP and SNAP), into a name list, and diffs it against the struct's UObject reflection. Pure shape test: no fixture, no world, instant. `GExemptFieldNames` is **empty** — every reflected field is covered today, and any exemption must be written down as a decision. Stakes rise with the world composer, which intends to invent parameter sets through this same `Lerp` (`COMPOSER-NOTES.md`). |
|
||||
| `VoxelForgeLayoutOrderIndependenceTest.cpp` | `VoxelForge.Determinism.LayoutOrderIndependence` | Builds a known transient soft-pointer pool, then rebuilds it in original, reversed, and swapped orders. Requires a non-empty layout and passage set, and compares every slot's definition/Z/height plus passage endpoints, radius, type, control geometry, and bounds bit-for-bit. |
|
||||
|
||||
## 4. The density pipeline (most-edited hot path)
|
||||
|
||||
|
||||
Reference in new issue
Block a user