fix(correctness): cold-audit fixes -- tile-cache determinism bug, cache identities, lifetimes

Correctness round on AUDIT-COLD-2026-09-14.md (Codex; key fixes reviewed by me).

#7 (determinism, introduced by the tile-cache work): the refetch guard in GetDensityAt now
rebuilds on `bTileCacheContext != CP_UsesTileCacheWindow` or when the worker-local stack/core were
moved into a cache entry (`CP_ActiveTunnelDensityCache != nullptr`). A cache miss can no longer
evaluate a moved-from, empty operator stack. Test (VoxelForgeCorrectnessRoundTest): the pre-fix
binary CRASHED in the context-switch case (negative control); the fixed binary passes with 0/5
coarse and fine mismatches, and warm vs fresh origin-tile meshes are identical.

Also fixed, each with a focused test that passes:
- #3/#8: worker diff/surface/biome caches carry owner/layer identity (no cross-world reuse);
  #9: the shaft key gains LedgeSpacing/LedgeDepth and the island key BoundarySealThickness;
  #14: clearing passages bumps PassagesVersion; #21: HasAnyModInChunkRange is proportional to
  the queried range (the sealed-rock proof calls it per candidate).
- #1: the density-volume fill thread is paused/drained with generation; #2: each content manager
  joins its own decoration tasks before destruction; #15: non-finite/invalid modification
  geometry is rejected; #20: zero-width transition blend is guarded at runtime.
- Also #4-#6, #10-#13, #16-#18, #22. #19 is valid C++20 and unchanged.

Verified: canonical export b3e5f4c3..9b377; capability 20,830 / 10,909; fresh trace 841/841
identical, 0 origin-column mismatches; static mesher calls 18,078,130. Performance: two pairs
disagree in sign, and the means are final -2.5% static / -0.8% moving; no repeatable regression.

Known and NOT caused by this round: ClassifyTileSoundness and PassageLandsInOpenSpace were already
failing (15/17 in the grouped suite). Queued for investigation.

Ledger: first determinism launch hit the DDC fatal (crash folder 57DB6ADC, 23:21); the retry
exited 1 on the two known failures; one malformed multi-test launch was inconclusive; one
malformed trace launch was stopped; one launch with an unquoted project path found no test and its
retry passed. Everything else passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
Fr0zkaandClaude Opus 5 committed 2026-09-15 00:29:46 +02:00
1 parent 39c306b524
commit 8879045627
14 files changed
+1365 -139

No files matched your search

@@ -120,6 +120,11 @@ public:
* future rebuild — this patches the LIVE instances. Returns how many were removed. Game-thread. */
int32 RemoveDecorationsInSphere(const FVector& WorldCenter, float WorldRadius);
/** Invalidate decoration regions after a terrain edit. Existing regions and in-flight builds are
* discarded together, so an old worker result cannot resurrect pre-edit content; the next update
* rebuilds the desired cells from the edited density field. Game-thread. */
void InvalidateDecorationBuilds();
/** Destroy all spawned content (decorations + water). Regenerate / season reset. Bumps the deco
* epoch so any in-flight march tasks' results are discarded. */
void ClearAll();
@@ -179,6 +184,9 @@ private:
FPlacementProfile Profile; // representative profile (mesh + HISM render tuning: cull/shadow) —
// may be a decoration entry's OR a companion's (F7).
TArray<FTransform> Xforms;
int32 SourceEntryIdx = INT32_MAX;
int32 SourceCompanionIdx = INT32_MAX;
int32 SourceSubIdx = INT32_MAX;
};
// A non-instanced actor placement, spawned when the region is applied.
struct FRegionActorSpawn
@@ -287,6 +295,7 @@ private:
void ClearAllDecorations();
void DrainDecoResults(); // discard every queued march result
static void ResetGridBuildState(FDecoGrid& G); // drop builds/queues (loaded regions untouched)
void JoinDecorationTasks(); // real per-manager lifetime join
// Region size in cells, clamped (>=1). Cell↔region math lives in file-static helpers in the .cpp.
int32 RegionSize() const;
@@ -353,10 +362,18 @@ private:
// Set in BeginDestroy; worker tasks check it before touching us.
std::atomic<bool> bShuttingDown{false};
// Per-manager task count. A process-global count would make one world's shutdown wait on
// another world's decoration work and cannot prove this manager's UObject is safe to tear down.
std::atomic<int32> ActiveDecorationTasks{0};
// Streaming state. INT_MIN sentinels force a full rebuild on the first update / after ClearAll.
FIntPoint LastDecoCell = FIntPoint(INT32_MIN, INT32_MIN);
int32 LastStrateIndex = INT32_MIN;
int32 LastNearRadius = INT32_MIN;
int32 LastFarRadius = INT32_MIN;
int32 LastNearSpacing = INT32_MIN;
int32 LastFarSpacing = INT32_MIN;
int32 LastRegionSize = INT32_MIN;
// Shared strate context for the current update (recomputed each UpdateDecorations; the launch step
// copies the PODs into each task). Same for both grids — a strate is a horizontal slab.