Jahni: "I do not need your work to be identical or near identical to what I had
before, only having it 99.99% at worst reproducible if two people share the same
seed, since everyone rebuilds it on multiplayer."
Recorded as OPSTACK-PLAN 2.6.1, superseding 2.6's "recognisably the same place".
Consequences, each recorded where it will be found:
- C10 closed permanently rather than parked: it measures old-path vs new-path
agreement and the two never coexist in a shipped world.
- The equivalence tests keep their value as PORT-CORRECTNESS checks, not fidelity
checks. Isosurface hard-fail stays; ULP grading is diagnostic only.
- C9 promoted to top open risk. "Two people share a seed" is exactly what /fp:fast
weakens across toolchains, and a Linux dedicated server against Windows clients
compiles the density path under opposite float models. FPSemantics = Precise is
the fix and the IWYU debt now blocks something that matters.
- C1 unblocked: it was deferred only because it re-rolls the world's noise.
Then, doing C1's arithmetic before applying its documented one-liner: THE FIX IS
WRONG. It bounds SeedF but keeps the * 97.7 multiplier, so the coordinate term
still reaches 1.6e6 where the ULP is 0.19 — 9.5x the ~0.02/voxel step. It would
have left the bug live for mid-range seeds while closing the ticket.
The real fix deletes the multipliers: they only decorrelate the ~40 noise sites,
which is a hashing job. VoxelHash::SeedOffset(Seed, Site) gives a site-salted,
bounded, final-units offset. Bounding SeedF alone would also funnel every seed
through 16384 offsets shared by all sites; per-site salting requires a collision at
all ~40 sites instead.
The op stack has already inherited the bug via FSlabVoidSource, so it must land in
both paths at once — and every further port copies it again.
Docs only; the C1 fix is not written.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
The bisect settled it. The difference survives every stage removal down to
"corridors + carve ONLY", which is character-for-character transcribed code, so
it is not in anything the decomposition added.
Cause, read out of the engine rather than assumed (VCToolChain.cs):
case FPSemanticsMode.Default: // Default is imprecise FP semantics.
case FPSemanticsMode.Imprecise: Arguments.Add("/fp:fast"); break;
with UBT's own doc: "the compiler is allowed to transform math expressions in
ways that might result in differently rounded results". Identical source in two
translation units may reassociate differently, worth ~1 ULP. It shows up on
exactly the ~2% of samples inside the SDF blend shell, where Blend - Sdf
catastrophically cancels; outside it Carve is exactly 0 or 1 and both agree.
So MazeEquivalence now grades what it can actually assert:
- hard fail : any isosurface crossing (geometry moves)
- info : differences at ULP scale (the unavoidable floor)
- warn : anything larger, which IS port drift, and runs the bisect
A test that warns on every port would get ignored by the port that matters.
Recorded in OPSTACK-PLAN 2.6, and as AUDIT C9 for the part that outlives this
refactor: ARCHITECTURE 9.1's "every peer regenerates identically" holds only
between bit-identical binaries under /fp:fast. Fine for one build on one
platform; a real desync source for a Linux server plus Windows clients both
regenerating authoritative geometry. The FPSemantics::Precise knob exists but
must not be turned speculatively -- it blocks the vectorisation T2.a was chasing,
on the hot loop, for an unmeasured cost.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phase 0.5 and the Phase 1 skeleton marked WRITTEN / NOT COMPILED (not "done" --
the gates are not met until the tests actually run). Section 8 independent fixes
2, 5 and 6 ticked. Section 9 "Resume here" now says BUILD.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AUDIT P1: every markdown design doc except CODEMAP.md was untracked, so
ARCHITECTURE / AUDIT / OPSTACK-PLAN / fable-idea / REVIEW_FINDINGS lived
only on disk. Replaces the single !CODEMAP.md exception with !*.md.
Also makes OPSTACK-PROGRESS.md commits actually record something, which
the unattended crash-safety discipline depends on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>