docs: new acceptance bar (peer agreement, not fidelity) — and C1's documented fix is wrong
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>
This commit is contained in:
+68
-2
@@ -75,6 +75,48 @@ Applied consistently at all `SeedF` definitions (`:682`, `:1756`, `:2066`, `:220
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### ⛔ CORRECTION 2026-07-27 — **the fix above is WRONG. Do not apply it.**
|
||||||
|
|
||||||
|
It bounds `SeedF` but leaves the **multiplier** in place, and the multiplier is where the magnitude
|
||||||
|
comes from. `SeedF · 97.7` with `SeedF ≤ 16383` still reaches **1.6e6**, where the float ULP is:
|
||||||
|
|
||||||
|
| | max coord term | ULP there | vs the ~0.02/voxel coordinate step |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `Seed = 1000` today | 9.8e4 | 0.012 | 0.6× — fine |
|
||||||
|
| **audit's proposed fix, worst case** | **1.6e6** | **0.19** | **9.5× — still lattice-snaps** |
|
||||||
|
|
||||||
|
So the "fix" would have made the bug *less catastrophic* while leaving it live, and — worse —
|
||||||
|
**closed the ticket.** It would have cost a build and a world re-roll to discover that mid-range
|
||||||
|
seeds still degrade. (Found by doing the arithmetic before applying it, not after.)
|
||||||
|
|
||||||
|
**The actual fix: bound the OFFSET, not the seed — i.e. delete the multipliers.**
|
||||||
|
|
||||||
|
The `· 7.3f … · 97.7f` multipliers exist only to decorrelate the ~40 noise call sites from each
|
||||||
|
other. That is a *hashing* job, and hashing does it better: give each site its own offset drawn from
|
||||||
|
the full seed entropy, already in final units, with no multiplier to re-inflate it.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// VoxelHash — one definition, so the bound cannot drift per site.
|
||||||
|
// Site-salted, final units, bounded: ULP at 16384 is 0.002 = 10% of a voxel step.
|
||||||
|
FORCEINLINE float SeedOffset(int32 Seed, uint32 Site)
|
||||||
|
{
|
||||||
|
return (float)(Mix((uint32)Seed ^ (Site * 2654435761u)) & 0x3FFF);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`WorldX * SF + SeedF * 83.1f` → `WorldX * SF + VoxelHash::SeedOffset(Seed, kSiteScallopX)`.
|
||||||
|
|
||||||
|
**Why this is strictly better, not just smaller:** bounding `SeedF` alone would squeeze all seeds
|
||||||
|
through 16384 distinct noise offsets *shared across every site*, so two colliding seeds would give
|
||||||
|
identical noise everywhere. Per-site salting means two seeds must collide at **all** ~40 sites to
|
||||||
|
produce the same world — which is never.
|
||||||
|
|
||||||
|
**Scope:** ~40 call sites, mechanical, plus the same bug now inherited by the operator stack
|
||||||
|
(`FSlabVoidSource::SeedF`, `VoxelDensityOpStack.cpp`). Must land in **both** paths in one change, or
|
||||||
|
the equivalence tests will (correctly) scream. **Cost of delay: every archetype ported copies it
|
||||||
|
again.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### C2 — Per-chunk parameter caches have no layout key (stale after live-edit) ⚠️ **real, reproducible**
|
### C2 — Per-chunk parameter caches have no layout key (stale after live-edit) ⚠️ **real, reproducible**
|
||||||
|
|
||||||
`VoxelGenerator.cpp:503-524`:
|
`VoxelGenerator.cpp:503-524`:
|
||||||
@@ -247,7 +289,22 @@ reachable only with a very large origin room *and* short tunnels. Flagging it be
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### C9 — The build uses `/fp:fast`, and the MP plan assumes bit-reproducible terrain ⚠️ **added 2026-07-27, measured not assumed**
|
### C9 — The build uses `/fp:fast`, and the MP plan assumes bit-reproducible terrain 🔴 **NOW THE TOP OPEN RISK — promoted 2026-07-27**
|
||||||
|
|
||||||
|
> **Why this outranks everything else in this document now.** Jahni stated the actual acceptance bar:
|
||||||
|
> *"only having it 99.99% at worst reproducible if two people share the same seed, since everyone
|
||||||
|
> rebuilds it on multiplayer."* That is **precisely and only** the guarantee this entry says
|
||||||
|
> `/fp:fast` weakens. Fidelity to the old world was dropped as a requirement (`§C10`); peer agreement
|
||||||
|
> replaced it as the single bar. **This entry is now load-bearing.**
|
||||||
|
>
|
||||||
|
> **The concrete case to decide:** a **Linux dedicated server** generating collision geometry and nav
|
||||||
|
> against **Windows clients** compiles the same density code under *opposite* float models
|
||||||
|
> (`ClangToolChain` → precise, `VCToolChain` → `/fp:fast`). That is not a theoretical divergence.
|
||||||
|
> Same-platform peers on the same build are fine.
|
||||||
|
>
|
||||||
|
> **The fix is known and blocked:** `FPSemantics = Precise` on this module, which needs the IWYU debt
|
||||||
|
> cleared first (seven headers compile only via the shared PCH). That debt is now worth clearing on
|
||||||
|
> *this* justification rather than on tidiness.
|
||||||
|
|
||||||
Found while chasing a 1-ULP difference between `GetMazeDensity` and its operator-stack port. The
|
Found while chasing a 1-ULP difference between `GetMazeDensity` and its operator-stack port. The
|
||||||
difference survived a full bisect down to code that is character-for-character identical, which
|
difference survived a full bisect down to code that is character-for-character identical, which
|
||||||
@@ -332,7 +389,16 @@ risk is real. That is one build, and it settles it.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### C10 — The op-stack ULP residue: PARKED, with the evidence, 2026-07-27
|
### C10 — The op-stack ULP residue: ~~PARKED~~ **CLOSED PERMANENTLY**, 2026-07-27
|
||||||
|
|
||||||
|
> **⛔ CLOSED, and now provably irrelevant — not merely parked.** Jahni, 2026-07-27: *"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."* This entry measures **old path vs new path**
|
||||||
|
> agreement, and the two paths will never both exist in a shipped world. **No requirement anywhere
|
||||||
|
> in the project depends on this number.** Do not spend another minute on it.
|
||||||
|
>
|
||||||
|
> What survives is the *method* lesson at the bottom of this entry, and the redirect: the
|
||||||
|
> reproducibility that IS required is **`§C9`** — across binaries and platforms, not across refactors.
|
||||||
|
|
||||||
**Status: accepted and closed by decision (Jahni), not by explanation.** Do not reopen this without
|
**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
|
reading the whole entry — five hypotheses have already been measured and refuted, and re-deriving
|
||||||
|
|||||||
@@ -220,6 +220,38 @@ SIMD noise switch required.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 2.6.1 ⚠️ RELAXED FURTHER, 2026-07-27 — resemblance to the old world is NOT a requirement at all
|
||||||
|
|
||||||
|
**Jahni, verbatim:** *"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."*
|
||||||
|
|
||||||
|
**This replaces the "recognisably the same place" bar above.** The requirement is not fidelity to the
|
||||||
|
past — it is **agreement between peers in the present**. Restated as the only two properties that
|
||||||
|
now matter:
|
||||||
|
|
||||||
|
| Property | Required? | Enforced by |
|
||||||
|
|---|---|---|
|
||||||
|
| **Same seed ⇒ same world, on every peer** | **YES — this is the whole bar** | `DensityPurity` within a binary; **`§C9`** across binaries/platforms |
|
||||||
|
| Resemblance to the pre-refactor world | **NO** | nothing; freely re-tunable |
|
||||||
|
| Bit-identity with the archetype `switch` | **NO** | nothing; never compare them |
|
||||||
|
|
||||||
|
**What this changes, concretely:**
|
||||||
|
|
||||||
|
1. **`§C10` is closed, not parked.** It measures old-path vs new-path agreement, and the two paths
|
||||||
|
will never both exist in a shipped world. The residue cannot affect anything Jahni requires.
|
||||||
|
2. **The equivalence tests keep their value, but for a different reason.** They are no longer
|
||||||
|
*fidelity* checks; they are **port-correctness** checks — a transcription slip is still a real
|
||||||
|
bug, and comparing against the old function is the cheapest way to catch one. Read them that way.
|
||||||
|
The hard-fail (isosurface crossing) stays; the ULP grading is now diagnostic only.
|
||||||
|
3. **`§C9` is promoted from a footnote to THE risk.** "Two people share a seed" is exactly the
|
||||||
|
guarantee `/fp:fast` weakens across toolchains, and a Linux dedicated server generating collision
|
||||||
|
geometry against Windows clients is the concrete case.
|
||||||
|
4. **Changes that re-roll the world's noise are no longer expensive.** `§C1` in particular was
|
||||||
|
deferred *only* because it forces a re-tune. That objection is gone.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 3. The contract
|
## 3. The contract
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|||||||
@@ -1059,3 +1059,63 @@ sub-ULP-of-scale deltas. Then `SurfaceWorld` (§5) — biggest payoff, most care
|
|||||||
and the exact-lattice `ClassifyTile` bound must both survive the port.
|
and the exact-lattice `ClassifyTile` bound must both survive the port.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-27 — the acceptance bar changed, and it invalidated the audit's own fix for C1.
|
||||||
|
|
||||||
|
**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."*
|
||||||
|
|
||||||
|
The bar is **peer agreement in the present**, not fidelity to the past. Recorded as
|
||||||
|
`OPSTACK-PLAN §2.6.1`, which supersedes §2.6's "recognisably the same place".
|
||||||
|
|
||||||
|
**Four consequences, all recorded where they will be found:**
|
||||||
|
|
||||||
|
1. **`§C10` closed permanently, not parked.** It measures old-path vs new-path agreement, and the
|
||||||
|
two paths never coexist in a shipped world. No requirement depends on it.
|
||||||
|
2. **The equivalence tests keep their value for a different reason** — they are **port-correctness**
|
||||||
|
checks (a transcription slip is a real bug), not fidelity checks. Hard-fail on isosurface
|
||||||
|
crossings stays; the ULP grading is now diagnostic only.
|
||||||
|
3. **`§C9` promoted to the top open risk.** "Two people share a seed" is exactly what `/fp:fast`
|
||||||
|
weakens across toolchains, and a **Linux dedicated server** generating collision/nav against
|
||||||
|
Windows clients compiles the same density code under *opposite* float models. The fix
|
||||||
|
(`FPSemantics = Precise`) is blocked behind the IWYU debt, which now has a real justification
|
||||||
|
rather than a tidiness one.
|
||||||
|
4. **`§C1` is unblocked** — it was deferred *only* because it re-rolls the world's noise.
|
||||||
|
|
||||||
|
### ⛔ And then C1's documented fix turned out to be wrong
|
||||||
|
|
||||||
|
Before applying the one-liner the audit has carried since it was written, I did its arithmetic:
|
||||||
|
|
||||||
|
```
|
||||||
|
proposed: SeedF bounded to 16383, multiplier * 97.7 KEPT
|
||||||
|
max coord term = 1.6e6 -> ULP = 0.19 -> 9.5x the ~0.02/voxel step
|
||||||
|
```
|
||||||
|
|
||||||
|
**It bounds the seed but not the offset, and the multiplier is where the magnitude comes from.** The
|
||||||
|
fix would have made the bug less catastrophic while leaving it live for mid-range seeds — and, worse,
|
||||||
|
**closed the ticket**. Cost to discover after applying: one build plus a world re-roll.
|
||||||
|
|
||||||
|
**The real fix is to delete the multipliers.** The `· 7.3f … · 97.7f` factors exist only to
|
||||||
|
decorrelate the ~40 noise sites from each other; that is a hashing job, and hashing does it better:
|
||||||
|
`VoxelHash::SeedOffset(Seed, Site)` returns a **site-salted, bounded, final-units** offset. Bounding
|
||||||
|
`SeedF` alone would also funnel every seed through 16384 offsets *shared by all sites*, so two
|
||||||
|
colliding seeds would give identical noise everywhere; per-site salting means two seeds must collide
|
||||||
|
at **all ~40 sites**, which is never.
|
||||||
|
|
||||||
|
**And the op stack has already inherited the bug** — `FSlabVoidSource::SeedF` is a faithful
|
||||||
|
transcription of `const float SeedF = (float)Seed`. It must be fixed in **both** paths in one change
|
||||||
|
or the equivalence tests will correctly scream. **Every further archetype port copies it again**,
|
||||||
|
which is the argument for doing it before `SurfaceWorld` rather than after.
|
||||||
|
|
||||||
|
Corrected in `AUDIT §C1` with the arithmetic, so the wrong fix cannot be applied later from the doc.
|
||||||
|
|
||||||
|
**UNVERIFIED:** nothing new in code this entry — docs only. The C1 fix itself is NOT written; it
|
||||||
|
needs Jahni's go-ahead on scope (~40 sites, re-rolls every world, one build).
|
||||||
|
|
||||||
|
**Next single action — Jahni's call between two:**
|
||||||
|
- **`§C1`** (recommended first): ~40 mechanical sites + the op stack, one build, kills the
|
||||||
|
highest-severity latent bug before more ports copy it.
|
||||||
|
- **`SurfaceWorld`** (`OPSTACK-DECOMPOSITION §5`): the biggest op-stack payoff, most care.
|
||||||
|
|
||||||
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user