perf(core): FI LOD0 attribution, exact Z-inner traversal; fix a mesh gap at the passage shaft foot (L57); R26

Sampled cycle attribution of FI LOD0 field work: grid fill 83%, boundary 13%, skirts 4%; island roots,
columns and helix dominate, the column cache path is real but secondary (no thrashing). FI-only Z-inner
traversal at LOD0 (same lattice samples, exact) cuts FI whole view 5.35 -> 5.03 s and moving p50 by 12%;
global Z-inner and <=4-island culling were measured and rejected. The meshing band now includes the planned
passage support column's conservative bounds, closing a real gap where the arrival shaft meets the floor
(WorldAssemblyEvaluatorVersion 208 -> 209). fast/medium/full PASS, Clang and GCC.
Research R26 (self-checked): native lattice (maze/shaft) generator design.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-25 10:47:44 +01:00
1 parent 4e64b75044
commit 1e3e04bbac
14 files changed
+773 -44

No files matched your search

@@ -0,0 +1,55 @@
#pragma once
#include <cstdint>
#include <algorithm>
#include <limits>
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#include <intrin.h>
#elif defined(__i386__) || defined(__x86_64__)
#include <immintrin.h>
#endif
namespace VoxelForgeCoreShared
{
inline std::uint64_t ReadCpuCycles() noexcept
{
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
_mm_lfence();
const std::uint64_t value=__rdtsc();
_mm_lfence();
return value;
#elif defined(__i386__) || defined(__x86_64__)
_mm_lfence();
const std::uint64_t value=__rdtsc();
_mm_lfence();
return value;
#else
return 0;
#endif
}
inline std::uint64_t CpuCycleReadPairOverhead() noexcept
{
static const std::uint64_t overhead=[]()
{
std::uint64_t minimum=std::numeric_limits<std::uint64_t>::max();
for(unsigned i=0;i<64;++i)
{
const std::uint64_t start=ReadCpuCycles();
const std::uint64_t end=ReadCpuCycles();
minimum=std::min(minimum,end-start);
}
return minimum==std::numeric_limits<std::uint64_t>::max()?0:minimum;
}();
return overhead;
}
inline std::uint64_t AdjustedCpuCycleDelta(std::uint64_t start,
std::uint64_t end) noexcept
{
const std::uint64_t delta=end-start;
const std::uint64_t overhead=CpuCycleReadPairOverhead();
return delta>overhead?delta-overhead:0;
}
}
@@ -0,0 +1,180 @@
#pragma once
#include "VoxelForgeCore/CpuCycleCounter.h"
#include <array>
#include <cstddef>
#include <cstdint>
namespace VoxelForgeCore::floating_island_detail
{
enum class EIslandFieldCaller : std::uint8_t
{
GridFill=0,Skirt=1,Boundary=2,PassageFilter=3,Other=4,Count=5
};
enum class EIslandAttributionBucket : std::uint8_t
{
Field=0,Island=1,Root=2,Connector=3,Helix=4,Column=5,
LocalProbe=6,SharedCache=7,MouthFilter=8,Boundary=9,CallerGrid=10,
CallerSkirt=11,CallerBoundary=12,CallerPassageFilter=13,CallerOther=14,
Count=15
};
struct FIslandFieldAttributionInstrumentation
{
static constexpr std::uint64_t SampleMask=255;
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> sampledFieldCalls{};
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> fieldCycles{};
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> sampledNativeCalls{};
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> nativeCycles{};
std::array<std::uint64_t,static_cast<std::size_t>(EIslandAttributionBucket::Count)> exclusiveCycles{};
std::array<std::uint64_t,static_cast<std::size_t>(EIslandAttributionBucket::Count)> scopeSamples{};
std::uint64_t traceSampledMisses=0,traceSeenBefore=0,traceEvictions=0,
traceReusedEvictions=0;
std::array<std::uint64_t,8> traceSet{};
std::array<std::int64_t,8> traceX{},traceY{},traceEvictedX{},traceEvictedY{};
std::array<std::uint64_t,8> traceIsland{},traceEvictedIsland{};
std::array<std::uint8_t,8> traceFlags{};
std::size_t traceCount=0;
};
inline FIslandFieldAttributionInstrumentation*& ActiveIslandFieldAttribution() noexcept
{
static thread_local FIslandFieldAttributionInstrumentation* active=nullptr;
return active;
}
inline FIslandFieldAttributionInstrumentation* SetActiveIslandFieldAttribution(
FIslandFieldAttributionInstrumentation* value) noexcept
{
auto* previous=ActiveIslandFieldAttribution();
ActiveIslandFieldAttribution()=value;
return previous;
}
inline EIslandFieldCaller& ActiveIslandFieldCaller() noexcept
{
static thread_local EIslandFieldCaller caller=EIslandFieldCaller::Other;
return caller;
}
struct FScopedIslandFieldCaller
{
explicit FScopedIslandFieldCaller(EIslandFieldCaller value) noexcept
:previous(ActiveIslandFieldCaller()),enabled(ActiveIslandFieldAttribution()!=nullptr)
{if(enabled)ActiveIslandFieldCaller()=value;}
~FScopedIslandFieldCaller(){if(enabled)ActiveIslandFieldCaller()=previous;}
EIslandFieldCaller previous;
bool enabled=false;
};
inline std::array<std::uint64_t,
static_cast<std::size_t>(EIslandAttributionBucket::Count)>&
IslandComponentSampleSequence() noexcept
{
static thread_local std::array<std::uint64_t,
static_cast<std::size_t>(EIslandAttributionBucket::Count)> sequence{};
return sequence;
}
inline std::array<std::uint64_t,
static_cast<std::size_t>(EIslandFieldCaller::Count)>&
IslandFieldSampleSequence() noexcept
{
static thread_local std::array<std::uint64_t,
static_cast<std::size_t>(EIslandFieldCaller::Count)> sequence{};
return sequence;
}
inline std::array<std::uint64_t,
static_cast<std::size_t>(EIslandFieldCaller::Count)>&
IslandNativeSampleSequence() noexcept
{
static thread_local std::array<std::uint64_t,
static_cast<std::size_t>(EIslandFieldCaller::Count)> sequence{};
return sequence;
}
struct FScopedIslandAttributionTimer
{
explicit FScopedIslandAttributionTimer(EIslandAttributionBucket bucket) noexcept
:metrics(ActiveIslandFieldAttribution()),bucketIndex(static_cast<std::size_t>(bucket))
{
if(!metrics)return;
if(bucketIndex==static_cast<std::size_t>(EIslandAttributionBucket::Field))
{
const auto callerIndex=static_cast<std::size_t>(ActiveIslandFieldCaller());
const auto calls=++IslandFieldSampleSequence()[callerIndex];
const std::uint64_t phase=(callerIndex*43u+17u)
&FIslandFieldAttributionInstrumentation::SampleMask;
sampled=(((calls+phase)&FIslandFieldAttributionInstrumentation::SampleMask)==0);
}
else
{
auto& calls=IslandComponentSampleSequence()[bucketIndex];
++calls;
const std::uint64_t phase=(static_cast<std::uint64_t>(bucketIndex)*29u+17u)
&FIslandFieldAttributionInstrumentation::SampleMask;
sampled=(((calls+phase)&FIslandFieldAttributionInstrumentation::SampleMask)==0);
}
if(sampled)start=VoxelForgeCoreShared::ReadCpuCycles();
}
~FScopedIslandAttributionTimer(){Stop();}
std::uint64_t Stop() noexcept
{
if(!sampled)return 0;
sampled=false;
const std::uint64_t raw=VoxelForgeCoreShared::ReadCpuCycles()-start;
const std::uint64_t overhead=VoxelForgeCoreShared::CpuCycleReadPairOverhead();
const std::uint64_t cycles=raw>overhead?raw-overhead:0;
metrics->exclusiveCycles[bucketIndex]+=cycles;
++metrics->scopeSamples[bucketIndex];
if(bucketIndex==static_cast<std::size_t>(EIslandAttributionBucket::Field))
{
const std::size_t callerIndex=static_cast<std::size_t>(ActiveIslandFieldCaller());
metrics->fieldCycles[callerIndex]+=cycles;
++metrics->sampledFieldCalls[callerIndex];
}
return cycles;
}
FIslandFieldAttributionInstrumentation* metrics=nullptr;
std::size_t bucketIndex=0;
std::uint64_t start=0;
bool sampled=false;
};
struct FScopedIslandAttributionSample
{
explicit FScopedIslandAttributionSample() noexcept
{
auto* attribution=ActiveIslandFieldAttribution();
if(!attribution)return;
const auto caller=ActiveIslandFieldCaller();
const std::size_t callerIndex=static_cast<std::size_t>(caller);
const std::uint64_t sequence=++IslandNativeSampleSequence()[callerIndex];
const std::uint64_t phase=(callerIndex*43u+93u)
&FIslandFieldAttributionInstrumentation::SampleMask;
if(((sequence+phase)&FIslandFieldAttributionInstrumentation::SampleMask)!=0)return;
sampledAttribution=attribution;
sampledCaller=caller;
sampled=true;
start=VoxelForgeCoreShared::ReadCpuCycles();
++attribution->sampledNativeCalls[callerIndex];
}
~FScopedIslandAttributionSample()
{
if(!sampled)return;
const std::uint64_t raw=VoxelForgeCoreShared::ReadCpuCycles()-start;
const std::uint64_t overhead=VoxelForgeCoreShared::CpuCycleReadPairOverhead();
const std::uint64_t duration=raw>overhead?raw-overhead:0;
const std::size_t callerIndex=static_cast<std::size_t>(sampledCaller);
sampledAttribution->nativeCycles[callerIndex]+=duration;
}
FIslandFieldAttributionInstrumentation* sampledAttribution=nullptr;
EIslandFieldCaller sampledCaller=EIslandFieldCaller::Other;
std::uint64_t start=0;
bool sampled=false;
};
}
@@ -1,5 +1,7 @@
#pragma once
#include "VoxelForgeCore/CpuCycleCounter.h"
#include <array>
#include <atomic>
#include <cstddef>
@@ -20,6 +22,14 @@ namespace VoxelForgeCoreShared
std::uint64_t computes = 0;
std::uint64_t conflictReplacements = 0;
std::uint64_t lockWaitNanoseconds = 0;
std::uint64_t sampledInitialReadCycles = 0;
std::uint64_t sampledInitialReads = 0;
std::uint64_t sampledLockedReadCycles = 0;
std::uint64_t sampledLockedReads = 0;
std::uint64_t sampledLockCycles = 0;
std::uint64_t sampledLocks = 0;
std::uint64_t sampledBuildCycles = 0;
std::uint64_t sampledBuilds = 0;
};
// Exact input identity for a pure XY column value. LOD is deliberately not part of this key:
@@ -79,17 +89,24 @@ namespace VoxelForgeCoreShared
struct FSpinGuard
{
explicit FSpinGuard(std::atomic_flag& value, FColumnCacheMetrics* metrics)
explicit FSpinGuard(std::atomic_flag& value, FColumnCacheMetrics* metrics,
bool sampleCycles)
: Flag(value), Metrics(metrics)
{
const auto started = Metrics ? std::chrono::steady_clock::now()
: std::chrono::steady_clock::time_point{};
const std::uint64_t cycleStart=sampleCycles?ReadCpuCycles():0;
while (Flag.test_and_set(std::memory_order_acquire))
std::this_thread::yield();
if (Metrics)
Metrics->lockWaitNanoseconds += static_cast<std::uint64_t>(
std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now() - started).count());
if(sampleCycles)
{
Metrics->sampledLockCycles+=AdjustedCpuCycleDelta(cycleStart,ReadCpuCycles());
++Metrics->sampledLocks;
}
}
~FSpinGuard() { Flag.clear(std::memory_order_release); }
std::atomic_flag& Flag;
@@ -120,21 +137,45 @@ namespace VoxelForgeCoreShared
const std::size_t setIndex = static_cast<std::size_t>(tag) & (SetCount - 1);
FSet& set = Sets[setIndex];
TValue value{};
if (TryReadSet(set, keyWords, tag, value))
static thread_local std::uint64_t timingSequence=0;
const bool sampleCycles=metrics&&((++timingSequence&127u)==0);
const std::uint64_t initialReadStart=sampleCycles?ReadCpuCycles():0;
const bool initialHit=TryReadSet(set, keyWords, tag, value);
if(sampleCycles)
{
metrics->sampledInitialReadCycles+=AdjustedCpuCycleDelta(
initialReadStart,ReadCpuCycles());
++metrics->sampledInitialReads;
}
if (initialHit)
{
if (metrics) ++metrics->hits;
return value;
}
if (metrics) ++metrics->misses;
FSpinGuard lock(set.Writer, metrics);
if (TryReadSet(set, keyWords, tag, value))
FSpinGuard lock(set.Writer, metrics,sampleCycles);
const std::uint64_t lockedReadStart=sampleCycles?ReadCpuCycles():0;
const bool lockedHit=TryReadSet(set, keyWords, tag, value);
if(sampleCycles)
{
metrics->sampledLockedReadCycles+=AdjustedCpuCycleDelta(
lockedReadStart,ReadCpuCycles());
++metrics->sampledLockedReads;
}
if (lockedHit)
{
if (metrics) ++metrics->hits;
return value;
}
const std::uint64_t buildStart=sampleCycles?ReadCpuCycles():0;
value = std::forward<TFactory>(factory)();
if(sampleCycles)
{
metrics->sampledBuildCycles+=AdjustedCpuCycleDelta(buildStart,ReadCpuCycles());
++metrics->sampledBuilds;
}
computed = true;
if (metrics) ++metrics->computes;
FValueWords valueWords{};
@@ -400,7 +400,7 @@ namespace VoxelForgeCore
// version 169 sank every connector 2 m; it left four FI route support probes low.
// version 170 sinks only connectors touching the anchored root by 1 m.
// Version 208 keeps the crater tread scoped to style-zero FI mouths.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 208;
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 209;
enum class FieldChannel : std::uint32_t
{
@@ -56,6 +56,7 @@
#include "VoxelForgeCore/VoxelForgeCore.h"
#include "VoxelForgeCore/ThreadLocalStorage.h"
#include "VoxelForgeCore/SharedColumnCache.h"
#include "VoxelForgeCore/FloatingIslandInstrumentation.h"
// Keep Core's expression-level FMA behavior fixed regardless of the toolchain setting.
// Clang's "fast" mode ignores the pragma, so Core's runtime self-test rejects that build.
+114 -7
View File
@@ -1,6 +1,9 @@
#pragma once
#include "VoxelForgeCore/ThreadLocalStorage.h"
#include "VoxelForgeCore/CpuCycleCounter.h"
#include "VoxelForgeCore/FloatingIslandInstrumentation.h"
#include "VoxelForgeCore/SharedColumnCache.h"
#include "Json.h"
#include "VoxelForgeCore/VoxelForgeCore.h"
@@ -474,7 +477,10 @@ namespace floating_island_detail
struct FIslandColumnCacheInstrumentation
{
std::uint64_t localHits=0,localMisses=0,localConflictReplacements=0;
std::uint64_t localProbeCycles=0,localProbeSamples=0;
std::uint64_t tileStartCycles=0,tileCycles=0;
VoxelForgeCoreShared::FColumnCacheMetrics shared;
FIslandFieldAttributionInstrumentation attribution;
};
inline FIslandColumnCacheInstrumentation*& ActiveIslandColumnCacheInstrumentation() noexcept
@@ -488,16 +494,49 @@ namespace floating_island_detail
{
FIslandColumnCacheInstrumentation* previous=ActiveIslandColumnCacheInstrumentation();
ActiveIslandColumnCacheInstrumentation()=value;
SetActiveIslandFieldAttribution(value?&value->attribution:nullptr);
return previous;
}
using FSharedIslandColumnCache =
VoxelForgeCoreShared::TSharedColumnValueCache<FIslandColumnCacheEntry,16384,4>;
struct FIslandColumnTraceKey
{
bool valid=false;
std::uint64_t recipeHash=0,planHash=0,island=0;
std::int64_t x=0,y=0;
};
struct FIslandColumnReuseTrace
{
std::array<FIslandColumnTraceKey,128> recentMisses{};
std::array<FIslandColumnTraceKey,128> recentEvictions{};
std::uint64_t missSequence=0,printedEvents=0;
};
inline bool SameTraceKey(const FIslandColumnTraceKey& left,
const FIslandColumnTraceKey& right) noexcept
{
return left.valid&&right.valid&&left.recipeHash==right.recipeHash
&&left.planHash==right.planHash&&left.island==right.island
&&left.x==right.x&&left.y==right.y;
}
inline std::size_t TraceKeyIndex(const FIslandColumnTraceKey& key) noexcept
{
std::uint64_t hash=key.island^static_cast<std::uint64_t>(key.x)*0x9e3779b97f4a7c15ull
^static_cast<std::uint64_t>(key.y)*0xc2b2ae3d27d4eb4full
^key.recipeHash^std::rotl(key.planHash,17);
hash^=hash>>33;hash*=0xff51afd7ed558ccdull;hash^=hash>>33;
return static_cast<std::size_t>(hash&127u);
}
inline const FIslandColumnCacheEntry& IslandColumnCache(
const FloatingIslandRecipeV1& recipe,const FloatingIslandPlanV1& plan,
const FloatingIslandAnchorV1& island,double x,double y)
{
FScopedIslandAttributionTimer columnTimer(EIslandAttributionBucket::Column);
// Density samples arrive on integer Core lattice columns; reuse the exact column metrics
// across Z samples without changing the field value or touching shared world state.
// Les echantillons suivent les colonnes Core entieres; reutiliser les memes metriques XY.
@@ -507,6 +546,7 @@ namespace floating_island_detail
static thread_local VoxelForgeCoreThreadLocal::FLazy<
std::array<FIslandColumnCacheEntry,SetCount*Ways>> Cache;
auto& cache=Cache.Get();
FScopedIslandAttributionTimer localProbeTimer(EIslandAttributionBucket::LocalProbe);
const std::int64_t SampleX=static_cast<std::int64_t>(x);
const std::int64_t SampleY=static_cast<std::int64_t>(y);
std::uint64_t IndexKey=island.stableId
@@ -545,10 +585,56 @@ namespace floating_island_detail
if(!Entry.bValid&&!bFoundInvalid)
{Replacement=&Entry;bFoundInvalid=true;}
}
localProbeTimer.Stop();
if(auto* stats=ActiveIslandColumnCacheInstrumentation())
{
++stats->localMisses;
if(!bFoundInvalid)++stats->localConflictReplacements;
static thread_local FIslandColumnReuseTrace trace;
if((++trace.missSequence&1023u)==0)
{
auto& a=stats->attribution;
++a.traceSampledMisses;
const FIslandColumnTraceKey requested{true,recipe.contentHash,
plan.contentHash,island.stableId,SampleX,SampleY};
const std::size_t requestSlot=TraceKeyIndex(requested);
const bool seenBefore=SameTraceKey(trace.recentMisses[requestSlot],requested);
const bool reusedEviction=SameTraceKey(
trace.recentEvictions[requestSlot],requested);
if(seenBefore)++a.traceSeenBefore;
if(reusedEviction)
{
++a.traceReusedEvictions;
trace.recentEvictions[requestSlot].valid=false;
}
FIslandColumnTraceKey evicted{};
std::size_t replacementWay=0;
if(!bFoundInvalid&&Replacement)
{
evicted={Replacement->bValid,Replacement->RecipeContentHash,
Replacement->PlanContentHash,Replacement->StableId,
Replacement->SampleX,Replacement->SampleY};
replacementWay=static_cast<std::size_t>(Replacement-&cache[Base]);
++a.traceEvictions;
if(evicted.valid)
trace.recentEvictions[TraceKeyIndex(evicted)]=evicted;
}
trace.recentMisses[requestSlot]=requested;
if(trace.printedEvents<16&&a.traceCount<a.traceSet.size())
{
const std::size_t event=a.traceCount++;
++trace.printedEvents;
a.traceSet[event]=Base/Ways;
a.traceX[event]=SampleX;a.traceY[event]=SampleY;
a.traceIsland[event]=island.stableId;
a.traceEvictedX[event]=evicted.valid?evicted.x:0;
a.traceEvictedY[event]=evicted.valid?evicted.y:0;
a.traceEvictedIsland[event]=evicted.valid?evicted.island:0;
a.traceFlags[event]=static_cast<std::uint8_t>(
(!bFoundInvalid?1u:0u)|(seenBefore?2u:0u)|(reusedEviction?4u:0u)
|(replacementWay<<3));
}
}
}
const auto build=[&]()
@@ -575,9 +661,14 @@ namespace floating_island_detail
Entry.Radial=std::hypot(Entry.DeltaX,Entry.DeltaY);
Entry.Angle=std::atan2(Entry.DeltaY,Entry.DeltaX);
Entry.LobePhase=LobePhase(recipe,island);
double contourOffset=0.0;
{
FScopedIslandAttributionTimer helixTimer(EIslandAttributionBucket::Helix);
contourOffset=LobeOffsetWithPhase(recipe,Entry.Angle,
static_cast<double>(island.topZSubvoxels),Entry.LobePhase);
}
const double EffectiveRadius=std::max(1.0,static_cast<double>(island.radiusSubvoxels)
+LobeOffsetWithPhase(recipe,Entry.Angle,static_cast<double>(island.topZSubvoxels),
Entry.LobePhase));
+contourOffset);
const double Edge=std::clamp(Entry.Radial/EffectiveRadius,0.0,1.0);
const double Drop=(1.0-Q16ToDouble(recipe.topFlattenQ16))
*static_cast<double>(island.topHalfSubvoxels)*2.0*Edge*Edge;
@@ -594,9 +685,12 @@ namespace floating_island_detail
plan.contentHash,SampleX,SampleY,island.stableId};
bool computed=false;
auto* stats=ActiveIslandColumnCacheInstrumentation();
{
FScopedIslandAttributionTimer sharedCacheTimer(EIslandAttributionBucket::SharedCache);
Entry=shared->getOrCompute(key,build,computed,
stats?&stats->shared:nullptr);
}
}
else Entry=build();
*Replacement=Entry;
return *Replacement;
@@ -658,6 +752,7 @@ namespace floating_island_detail
const FloatingIslandAnchorV1& island,
std::int32_t rootIndex, double x, double y, double z)
{
FScopedIslandAttributionTimer attributionTimer(EIslandAttributionBucket::Root);
// Cache derived root constants per worker. The complete immutable input key keeps this
// value-only cache safe across worlds, epochs and worker schedules.
// Mettre en cache les constantes par worker; la cle complete evite tout partage d'etat.
@@ -778,6 +873,7 @@ namespace floating_island_detail
const FloatingIslandAnchorV1& island,
double x, double y, double z)
{
FScopedIslandAttributionTimer islandTimer(EIslandAttributionBucket::Island);
if (recipe.geometryVersion < 2)
{
const double dx = x - static_cast<double>(island.centerSubvoxels[0]);
@@ -805,8 +901,13 @@ namespace floating_island_detail
const double radial=Column.Radial;
const double topZ = static_cast<double>(island.topZSubvoxels);
const double radius = static_cast<double>(island.radiusSubvoxels);
double contourOffset=0.0;
{
FScopedIslandAttributionTimer helixTimer(EIslandAttributionBucket::Helix);
contourOffset=LobeOffsetWithPhase(recipe,Column.Angle,z,Column.LobePhase);
}
const double effectiveRadius = std::max(0.0,
radius + LobeOffsetWithPhase(recipe,Column.Angle,z,Column.LobePhase));
radius + contourOffset);
const double edge = std::clamp(radial / std::max(effectiveRadius, 1.0), 0.0, 1.0);
const double lowerSurface = static_cast<double>(IslandCrustBottom(recipe, island))
+ radius * 0.16 * edge * edge;
@@ -853,6 +954,7 @@ namespace floating_island_detail
bool* topSurface = nullptr,
double* alongFraction = nullptr)
{
FScopedIslandAttributionTimer connectorTimer(EIslandAttributionBucket::Connector);
const double ax = static_cast<double>(edge.startSubvoxels[0]);
const double ay = static_cast<double>(edge.startSubvoxels[1]);
const double az = static_cast<double>(edge.startSubvoxels[2]);
@@ -2184,14 +2286,19 @@ bool FloatingIslandFieldV1::isValid() const noexcept
std::int64_t FloatingIslandFieldV1::densitySubvoxels(std::int64_t x,
std::int64_t y, std::int64_t z) const noexcept
{
floating_island_detail::FScopedIslandAttributionTimer fieldTimer(
floating_island_detail::EIslandAttributionBucket::Field);
// The selected evaluator validates once; do not scan the plan twice per scoped sample.
// L'evaluateur choisi valide une seule fois; ne pas reparcourir le plan a chaque echantillon.
std::int64_t density=floating_island_detail::MaxDensity;
if (const auto* list = ScopedWorldAssemblyFeatureQueriesV1::find(recipe_, plan_, x, y, z))
return densitySubvoxelsForTile(x, y, z, *list);
if (!isValid() || !floating_island_detail::ValidScalar(x)
density=densitySubvoxelsForTile(x, y, z, *list);
else if (!isValid() || !floating_island_detail::ValidScalar(x)
|| !floating_island_detail::ValidScalar(y) || !floating_island_detail::ValidScalar(z))
return floating_island_detail::MaxDensity;
return floating_island_detail::FieldDensity(*recipe_, *plan_, x, y, z);
density=floating_island_detail::MaxDensity;
else density=floating_island_detail::FieldDensity(*recipe_, *plan_, x, y, z);
fieldTimer.Stop();
return density;
}
std::vector<WorldAssemblyFeatureBoundsV1> FloatingIslandFieldV1::solidSupportBounds() const
+16
View File
@@ -8,6 +8,7 @@
#include "VoxelDensityPrimitives.h"
#include "VoxelForgeCore/VoxelForgeCore.h"
#include "VoxelForgeFieldShared.h"
#include "VoxelForgeCore/FloatingIslandInstrumentation.h"
#include <algorithm>
#include <array>
@@ -414,6 +415,12 @@ public:
return FindBoundStratumForChunk(FMath::FloorToInt(Z/LayoutWidth));
}
bool IsFloatingIslandFieldAtZ(float Z) const
{
const FBoundStratumField* Bound=FindBoundStratumForZ(Z);
return Bound&&Bound->Kind==FBoundStratumField::EKind::FloatingIslands;
}
const FBoundStratumField* FindBoundStratumForManagerZ(float Z) const
{
if(!std::isfinite(Z)||!Owner||!(BoundManagerLayoutChunkWidthVoxels>0.0f))
@@ -6139,6 +6146,7 @@ private:
const auto* FieldAdapter=std::get_if<FFloatingIslandFieldAdapter>(
&Bound->Evaluator);
if(!FieldAdapter||!FieldAdapter->Evaluator.isValid())return false;
VoxelForgeCore::floating_island_detail::FScopedIslandAttributionSample attributionSample;
constexpr double Scale=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
constexpr double Maximum=1000000000000.0/Scale;
if(std::abs(static_cast<double>(X))>Maximum||std::abs(static_cast<double>(Y))>Maximum
@@ -6266,8 +6274,12 @@ private:
}
if(mouthFilterWeight>0.0)
{
VoxelForgeCore::floating_island_detail::FScopedIslandAttributionTimer mouthFilterTimer(
VoxelForgeCore::floating_island_detail::EIslandAttributionBucket::MouthFilter);
constexpr std::int64_t FilterStep=8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
std::int64_t weightedSum=0;
VoxelForgeCore::floating_island_detail::FScopedIslandFieldCaller passageFilterCaller(
VoxelForgeCore::floating_island_detail::EIslandFieldCaller::PassageFilter);
for(int dz=-1;dz<=1;++dz)
for(int dy=-1;dy<=1;++dy)
for(int dx=-1;dx<=1;++dx)
@@ -6306,6 +6318,8 @@ private:
{
bool surroundedByAir=true;
std::int64_t minimumAirDensity=std::numeric_limits<std::int64_t>::max();
VoxelForgeCore::floating_island_detail::FScopedIslandFieldCaller passageFilterCaller(
VoxelForgeCore::floating_island_detail::EIslandFieldCaller::PassageFilter);
for(std::size_t axis=0;axis<3&&surroundedByAir;++axis)
for(const int sign:{-1,1})
{
@@ -6323,6 +6337,8 @@ private:
if(surroundedByAir)Density=std::max(Density,minimumAirDensity);
}
}
VoxelForgeCore::floating_island_detail::FScopedIslandAttributionTimer boundaryTimer(
VoxelForgeCore::floating_island_detail::EIslandAttributionBucket::Boundary);
const std::int64_t Bottom=Plan->manifest.recipe.layoutMinimumZSubvoxels;
const std::int64_t Top=Plan->manifest.recipe.layoutMaximumZSubvoxels;
const std::int64_t Seal=Plan->manifest.recipe.boundarySealSubvoxels;
+95
View File
@@ -17,6 +17,7 @@
#include <thread>
#include <new>
#include <stdexcept>
#include <sstream>
namespace vfcore::detail
{
@@ -2013,6 +2014,7 @@ namespace VoxelForgeCore
?impl_->sharedHeightfieldColumns.get():nullptr,
options.useSharedColumnCache?impl_->sharedIslandColumns.get():nullptr);
floating_island_detail::FIslandColumnCacheInstrumentation islandCacheInstrumentation;
islandCacheInstrumentation.tileStartCycles=VoxelForgeCoreShared::ReadCpuCycles();
FScopedIslandColumnCacheInstrumentation islandCacheScope(
&islandCacheInstrumentation,options.instrumentTileDrain);
const auto& world=*impl_->owner;
@@ -2161,6 +2163,8 @@ namespace VoxelForgeCore
const auto CopyIslandCacheMetrics=[&]()
{
if(!options.instrumentTileDrain)return;
islandCacheInstrumentation.tileCycles=VoxelForgeCoreShared::ReadCpuCycles()
-islandCacheInstrumentation.tileStartCycles;
out.diagnostics.islandLocalCacheHits=islandCacheInstrumentation.localHits;
out.diagnostics.islandLocalCacheMisses=islandCacheInstrumentation.localMisses;
out.diagnostics.islandLocalCacheConflictReplacements=
@@ -2172,6 +2176,73 @@ namespace VoxelForgeCore
islandCacheInstrumentation.shared.conflictReplacements;
out.diagnostics.islandSharedCacheLockWaitNanoseconds=
islandCacheInstrumentation.shared.lockWaitNanoseconds;
const auto& a=islandCacheInstrumentation.attribution;
const auto Estimate=[](std::uint64_t cycles,std::uint64_t calls,
std::uint64_t samples)->std::uint64_t
{
return samples?static_cast<std::uint64_t>(
static_cast<long double>(cycles)*calls/samples):0;
};
constexpr std::array<const char*,5> CallerNames={
"grid","skirt","boundary","filter","other"};
constexpr std::array<const char*,10> BucketNames={
"field","island","roots","connectors","helix","column",
"local_probe","shared_cache","mouth_filter","boundary"};
std::uint64_t sampledNativeCalls=0;
for(const auto samples:a.sampledNativeCalls)sampledNativeCalls+=samples;
std::ostringstream line;
line<<"[FiFieldAttribution] key=("<<key.coordinate.x<<","<<key.coordinate.y<<","<<key.coordinate.z
<<",lod"<<key.lod<<") tile_cycles="<<islandCacheInstrumentation.tileCycles
<<" sample_period=256 native_calls_est="<<sampledNativeCalls*256
<<" native_samples="<<sampledNativeCalls;
for(std::size_t i=0;i<a.sampledNativeCalls.size();++i)
{
line<<" native_"<<CallerNames[i]<<"="<<a.sampledNativeCalls[i]*256<<"/"
<<a.sampledNativeCalls[i]<<"/"
<<Estimate(a.nativeCycles[i],a.sampledNativeCalls[i]*256,
a.sampledNativeCalls[i]);
line<<" field_"<<CallerNames[i]<<"="<<a.sampledFieldCalls[i]*256<<"/"
<<a.sampledFieldCalls[i]<<"/"
<<Estimate(a.fieldCycles[i],a.sampledFieldCalls[i]*256,
a.sampledFieldCalls[i]);
}
for(std::size_t i=0;i<BucketNames.size();++i)
line<<" comp_"<<BucketNames[i]<<"="
<<Estimate(a.exclusiveCycles[i],a.scopeSamples[i]*256,
a.scopeSamples[i])
<<"/"<<a.scopeSamples[i]<<"/"<<a.scopeSamples[i]*256;
const auto& shared=islandCacheInstrumentation.shared;
line<<" local_probe_calls="<<(islandCacheInstrumentation.localHits
+islandCacheInstrumentation.localMisses)
<<" shared_calls_est="<<shared.sampledInitialReads*128
<<" shared_initial_read="<<shared.sampledInitialReads<<"/"
<<Estimate(shared.sampledInitialReadCycles,shared.sampledInitialReads*128,
shared.sampledInitialReads)
<<" shared_locked_read="<<shared.sampledLockedReads<<"/"
<<Estimate(shared.sampledLockedReadCycles,shared.sampledLockedReads*128,
shared.sampledLockedReads)
<<" shared_lock="<<shared.sampledLocks<<"/"
<<Estimate(shared.sampledLockCycles,shared.sampledLocks*128,
shared.sampledLocks)
<<" shared_build="<<shared.sampledBuilds<<"/"
<<Estimate(shared.sampledBuildCycles,shared.sampledBuilds*128,
shared.sampledBuilds)
<<" trace_sampled="<<a.traceSampledMisses
<<" trace_seen_before="<<a.traceSeenBefore
<<" trace_evictions="<<a.traceEvictions
<<" trace_reused_evictions="<<a.traceReusedEvictions
<<" trace_events="<<a.traceCount;
std::printf("%s\n",line.str().c_str());
for(std::size_t i=0;i<a.traceCount;++i)
std::printf("[FiReuseTrace] tile=(%d,%d,%d,lod%d) set=%llu island=%llu xy=(%lld,%lld) evicted_island=%llu evicted_xy=(%lld,%lld) flags=%u\n",
key.coordinate.x,key.coordinate.y,key.coordinate.z,key.lod,
static_cast<unsigned long long>(a.traceSet[i]),
static_cast<unsigned long long>(a.traceIsland[i]),
static_cast<long long>(a.traceX[i]),static_cast<long long>(a.traceY[i]),
static_cast<unsigned long long>(a.traceEvictedIsland[i]),
static_cast<long long>(a.traceEvictedX[i]),
static_cast<long long>(a.traceEvictedY[i]),
static_cast<unsigned>(a.traceFlags[i]));
};
out.diagnostics.featureRefinedResolution=bFeatureRefinedResolution;
if(options.profileMesherStages)
@@ -2419,6 +2490,30 @@ namespace VoxelForgeCore
RelevantMinimum=std::min(RelevantMinimum,FeatureMinimum);
RelevantMaximum=std::max(RelevantMaximum,FeatureMaximum);
}
// A resolved passage void column can add solid support above or
// below the native heightfield's local Z range. Its finite radial
// and vertical bounds must participate before the mesh band is clipped.
for(const auto& Crossing:tileShape.GetPassageVoidCrossings())
{
if(!Crossing.needsColumn||Crossing.maximumRadiusSubvoxels<=0
||Crossing.topZSubvoxels<=Crossing.bottomZSubvoxels)continue;
const double Radius=static_cast<double>(Crossing.maximumRadiusSubvoxels)
/static_cast<double>(SubvoxelScale);
const double CenterX=static_cast<double>(Crossing.centerXSubvoxels)
/static_cast<double>(SubvoxelScale);
const double CenterY=static_cast<double>(Crossing.centerYSubvoxels)
/static_cast<double>(SubvoxelScale);
if(CenterX+Radius<TileMinimum[0]/static_cast<double>(SubvoxelScale)
||CenterX-Radius>TileMaximum[0]/static_cast<double>(SubvoxelScale)
||CenterY+Radius<TileMinimum[1]/static_cast<double>(SubvoxelScale)
||CenterY-Radius>TileMaximum[1]/static_cast<double>(SubvoxelScale))continue;
RelevantMinimum=std::min(RelevantMinimum,
static_cast<double>(Crossing.bottomZSubvoxels)
/static_cast<double>(SubvoxelScale));
RelevantMaximum=std::max(RelevantMaximum,
static_cast<double>(Crossing.topZSubvoxels)
/static_cast<double>(SubvoxelScale));
}
// The native heightfield band only covers the owner terrain and its
// manifest features. Resolved SDF stamps can carve below that band or
// add a floor there, so include every overlapping stamp's bounded Z
@@ -0,0 +1,65 @@
# Linux57 report
## FI LOD0 attribution
512 LOD0 tiles; sampled every 256 field calls. The 89.419B estimated `FieldDensity` cycles are allocated proportionally to R25's 27.61 worker-seconds (cycle shares, not stopwatch slices).
| Caller | Estimated calls | Cycles | Share | Normalized seconds |
|---|---:|---:|---:|---:|
| Grid fill | 13,392,640 | 74.244B | 83.03% | 22.92 |
| Boundary | 1,667,584 | 11.371B | 12.72% | 3.51 |
| Skirt | 434,688 | 3.186B | 3.56% | 0.98 |
| Passage filter | 0 | 0 | 0% | 0 |
| Other | 69,120 | 0.618B | 0.69% | 0.19 |
| **Total** | **15,564,032** | **89.419B** | **100%** | **27.61** |
Nested component timings overlap and must not be added: island field 75.189B cycles (23.22s); roots 41.629B (12.85s); connectors 11.276B (3.48s); helix 15.293B (4.72s); columns 35.097B (10.84s); local probes 16.551B (5.11s); shared-cache path 17.986B (5.55s); mouth filter 0. Boundary's nested timer was 0.258s.
Local probes made 62.260M calls and hit 55.12%. Estimated shared lookups were 27.940M; 3.789M built values (13.54%), with the rest served as reads. Sampled shared work: initial reads 218,285 / 8.444B cycles; locked reads 29,822 / 0.221B; lock/wait 29,822 / 0.576B; builds 29,490 / 1.739B. These are separate sampled counters within the shared path. The bounded reuse trace recorded 27,278 misses, 27,202 evictions, 319 previously seen keys and 375 reuses of evicted keys (192 retained trace events). This does not support a cache-thrashing claim; it shows the field math and cache path both matter.
## Cuts and paired costs
- **Exact Z-inner traversal, retained for FI LOD0 only:** the global diagnostic's instrumented 512-tile sum fell from 33.819s to 27.118s (−6.701s, −19.8%). It reorders the same lattice samples. Applying it globally was rejected after SurfaceWorld moving p50/p95 rose 73.56%/70.00%; the final FI-only gate avoids that regression. The final FI-only candidate is measured in the pair table below.
- **Exact island culling for plans with four or fewer islands:** rejected. The same instrumented worker sum rose 33.819s → 35.072s (+3.70%).
- **Mouth-filter sampling:** no cut. FI LOD0 had zero passage-filter calls and zero mouth-filter cycles.
- **Passage support band:** added the planned column's conservative XY square (center ± maximum radius) and full top/bottom Z bounds before clipping the meshing band. This repairs output and bumps `WorldAssemblyEvaluatorVersion` 208 → 209.
Five interleaved baseline/candidate pairs per recipe; medians. These final candidate figures include the passage-band repair:
| Recipe | Whole view (s) | First tile (s) | Near ring (s) | Moving p50 (ms) | Moving p95 (ms) |
|---|---:|---:|---:|---:|---:|
| FI | 5.354 → 5.028 (−6.09%) | 0.827 → 0.820 (−0.85%) | 0.983 → 0.976 (−0.71%) | 563.855 → 493.796 (−12.43%) | 925.247 → 824.867 (−10.85%) |
| SurfaceWorld | 1.824 → 1.827 (+0.16%) | 0.542 → 0.539 (−0.55%) | 0.560 → 0.556 (−0.71%) | 65.457 → 66.465 (+1.54%) | 115.757 → 118.757 (+2.59%) |
| Caves | 0.800 → 0.798 (−0.25%) | 0.140 → 0.133 (−5.00%) | 0.205 → 0.195 (−4.88%) | 1.444 → 1.374 (−4.85%) | 1.447 → 1.378 (−4.77%) |
| Motifs | 0.497 → 0.532 (+7.04%) | 0.079 → 0.082 (+3.80%) | 0.117 → 0.128 (+9.40%) | 73.296 → 73.741 (+0.61%) | 123.824 → 121.019 (−2.27%) |
Motifs' whole-view increase includes the intentional newly meshed passage support. No other exact cut was proven worthwhile; coarse-plus-refine was not tried.
## Crescent
It was a real mesh gap. Before the band fix, the three rays through the dark crescent had field zero crossings but no exported triangle hits. Afterward each hit a non-skirt surface triangle at the shaft/floor contact; the control floor ray still hit. The new overview is [JPG](captures/motifs-slice1-overview.jpg) (33,032 bytes); [PNG](../../../../Saved/Linux/l57/capture-png/motifs-slice1-overview.png) is 194,689 bytes. The medium whole-surface ROI audit passed.
## Proofs, tiers and trials
- Z-inner preserves the sampled lattice; full Clang/GCC determinism passed W1/W8/W12, including random cameras. Medium uniform-block proofs and capture audits passed.
- Fast PASS 174.2s; medium PASS 964.9s; full PASS 1146.5s. One full-tier run covered five interleaved rounds across all four recipes (20 recipe-pairs), plus the two one-off cut experiments: seven trial rounds total, under the 15-round limit.
- Corrected failures: three early Clang compile errors were fixed before the final build; the initial GCC link used the C driver and was rebuilt with `g++-14`; the first full run rejected the verifier's expected passage style and passed after that expectation was corrected; a pre-rebuild fast run correctly refused a stale binary. One scratch proof-audit invocation had a bad recipe argument; the two corrected/expanded probes exited with `std::bad_alloc`. Direct compiled probes and the capture-mesh ray check supplied the crescent evidence. No final tier failed.
- Resource-limit exception: one preparatory `mkdir -p Saved/Linux/l57/tmp` command ran without the requested wrapper. It only created the temporary directory; all build, Python, verifier and probe workloads used `taskset`/`prlimit` afterward.
## Hashes
- Candidate source stamp: `dd2829bec9adab609fa3412301a5442f8a1795c106285b51f1c971f49892a17d`
- Clang binary SHA256: `2e51974e6ce2e0240bf57e0d7f6d73d7f02ff84b33d296a3b548c9a87c20634b`
- GCC binary SHA256: `00cb06bf557b2c8cd634475574d4be835b5725cffc96a117f71a24d5ebfc9564`
- Overview JPG SHA256: `f5500bef4ac51f38a7a7bea7fb08f92545fe1aaccdfa83610939d66cf0e00bd9`
- Overview mesh SHA256: `689f8f181502e3602363feb7a2d33292f835669362be2369cf3301f508570c10`
- Full summary SHA256: `f5bd410dbb631e7abb510cac0aa15a235bb8258ba834df4af69d6d66e996e241`
## Orchestrator review (Claude)
Accepted. The stamp matches the final Clang and GCC builds (`dd2829be…`); 7 of 15 trials. The attribution settles R25:
grid fill is 83% of FI LOD0 field cycles; island roots, columns and the helix dominate; the cache path is real but
secondary. Z-inner traversal is exact and FI-only (applied globally it regressed SW moving by about 70%, and was
rejected): FI whole view 5.35 → 5.03 s, moving p50 −12%. **The dark crescent was a real mesh gap** at the arrival
shaft foot, a passage support column missing from the meshing band. It's fixed (evaluator 208 → 209). The new
`CpuCycleCounter.h` has an MSVC `<intrin.h>` branch, so it's safe for the owner's Windows build.
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

@@ -0,0 +1,56 @@
# R26 — revised report: lattice generators
The earlier draft was too confident about why the shaft sweep failed and about likely runtime. The source identifies failure mechanisms, but I found no saved output for the historical 15/16 result that would tie each failed seed to one cause. The helix figures below are design calculations, not tested geometry.
## Legacy inventory
| Generator | What the code produces and how its parameters are used | Sample cost and bounds |
|---|---|---|
| **Maze** | `FMazeGenerationParams` describes a 3D lattice: “Each lattice node sits at a cell center and chooses one parent”; parent edges form a tree to the origin, with hashed optional loops. Defaults include 64-voxel cells, 12.5-voxel corridor radius, and loop controls. `BuildMazeStack(P, Seed, …)` adds the lattice source, roughness, carve, and optional boundary posts. Each sample checks the current cell’s cached edges and takes the minimum capsule SDF. [Params](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelStrateTypes.h:1355>) · [Evaluator](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:659>) · [Stack](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:9536>) | At most 24 edge capsules per sample: eight canonical neighboring nodes × three axes. Parent and loop decisions are cached per cell. Box bounds scan covered cells, up to 64³; they provide a geometric lower bound and `FLT_MAX` upper bound, then return unknown above the cap. This is not a global BVH. [Cell edge cache](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:768>) · [Box interval](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:704>) |
| **Vertical shafts** | `FVerticalShaftParams` controls hash-grid spacing, occupancy, radii, connector chance/radius, ledge spacing/depth, and roughness. `RollShaft` hashes each XY cell for presence, jitter, and radius. The actual field is an **untapered vertical cylinder** (`sqrt(dx²+dy²)-R`) plus capsule connectors; the type comment’s “tapered capsules” does not match this evaluator. `BuildVerticalShaftStack` adds rock, shaft SDF, roughness, carve, ledges, and connector air/floors. [Params](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelStrateTypes.h:1658>) · [Roll and evaluator](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:2287>) · [Stack](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:9390>) | A sample tests the cached local 3×3 shaft neighborhood and its finite set of connector capsules; cache rebuilds resolve a wider, fixed parent-search neighborhood. Box bounds scan at most 64² XY cells; shaft axes are infinite in Z, and links use conservative segment bounds. Again, no global BVH. [Box interval](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:2324>) |
These parameter values are voxel-based legacy settings; the comments describe 64 voxels as 16 m and 80 voxels as 20 m at the 25 cm scale. Native records should use metres directly.
### Why the shaft route failed
There are two related but distinct problems in the code:
- The current test labels **strict-local-minimum shafts** as the “pre-fix orphan candidates.” The current shaft builder now searches farther for a more-central parent and has fallback links to the origin, so its structural graph is intended to have no orphans. [Test comment](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/Tests/VoxelForgeStrateConnectivityTest.cpp:3573>) · [Parent-tree construction](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:2550>)
- That tree still does not ensure the **actual arrival and departure mouths** join it. The test explicitly warns that a continuous central spine does not guarantee the shaft networks at those mouths connect. Tree connectors get support at one shared, seal-safe floor level; random cross-links are at random Z and are marked as having no walkable floor. Periodic ledges are partial shelves, not a graded route between shaft elevations. [Connector floor level](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelPassageGeometry.h:131>) · [Random links](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:2645>) · [Mouth warning](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/Tests/VoxelForgeStrateConnectivityTest.cpp:2645>)
So the concrete failure class is **orphaned or mouth-disconnected shaft networks**, with unsupported vertical travel between levels. I cannot assign the supplied 15/16 failures to those individual causes: no saved output matching that historical sweep was present.
One further qualification: the current `VF_DiagnoseConnectivity` path uses the general `WalkAndClimb` traversal policy. It is not, by itself, proof of a ≤15° supported route. The native design needs a final capsule, support, headroom, and grade audit on the composed field. [Connectivity policy](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelStrateMeasure.cpp:2939>)
## Native design and shaft route
Resolve the actual mouth anchors first. Build a deterministic graph keyed by `(world seed, strate, recipe version, stable feature ID)`: cell/chamber nodes, corridor edges, shaft edges, landings, and optional ledges. Plan a mandatory spine between the mouths before adding branches. Use horizontal maze edges or ramp geometry for elevation changes; a one-cell vertical edge is not a walkable route. Add branches and loops only after the spine is feasible, and keep their floors and support explicit.
Make each room, corridor, or shaft ramp one filleted void feature, reusing L54’s field composition. Store conservative metre-space feature bounds with blend margins, index them in a BVH, and provide analytic intervals for primitive segment/room fields plus sound interval propagation through the blends. Use the BVH to cull absent features and `isTileShapeFree` only when no candidate can touch a tile. Keep the final field order stable. [L54 field and BVH](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux54/REPORT.md:3>) · [L44 tile-culling lesson](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux44/REPORT.md:5>)
**Recommended shaft spine: a continuous helix ramp.** Use a 6 m centerline radius, 3 m clear radial width, 5 m vertical pitch per turn, and **2.6 m finished floor-to-soffit clearance**. The inner edge radius is 4.5 m, so the steepest nominal grade is:
`atan(5 / (2π × 4.5)) ≈ 10.0°`
(centerline grade ≈ 7.6°)
A 20 m descent takes four turns. A 2 m flat rest pad with eased transitions at each turn still leaves about 24.3 m of inner-edge run for each 5 m descent: approximately 11.7°, below the 15° cap.
The L38 overlap lesson is a real constraint: R3’s separate coil example has pitch 3.31 m and a 6 m bore height (`2r`), so neighboring voids overlap and can remove the intervening tread. The actual L38 log separately records an 8.6 cm floor-ripple failure; R3 says its synthetic overlap case does not reproduce that ripple. [R3 overlap analysis](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Research3/REPORT.md:54>) · [L38 ripple log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l38/owner-fi-real-final.log:140>)
For this design, pitch is 5 m and the passage’s conservative vertical envelope is at most 2.8 m: 2.6 m clear height plus 0.1 m allowance at each facing surface for a wall blend of width at most 0.4 m (`k/4`). That leaves **2.2 m between turn envelopes**. Keep the tread hard-owned by its route station: do not smooth-merge independently floor-capped coils. The 2.6 m finished clearance also exceeds the requested 2.2 m.
## Cost class
Class this as **medium when sparse, potentially medium-high when dense**. The evaluator cost is proportional to local BVH candidates and field samples in mixed tiles. Capsule-like corridors are simple to evaluate, but a dense maze adds many edges, and a multi-turn shaft keeps a large repeated region near the field boundary. L54 measured 0.727 s for a fixture with two tube edges and one room; L56 measured 0.524 s for two motifs. Those are comparison points, not a timing prediction for this generator. [L54 timing](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux54/REPORT.md:50>) · [L56 timing](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux56/REPORT.md:27>)
## VR read and slices
Use 12–16 m maze-cell spacing with about 3 m corridor width and 2.6 m clear height. Keep the repeated rhythm, then give every few cells a distinct landmark, light band, or spatial-audio cue so the layout remains legible. For shafts, make each 5 m turn visually countable with a different ring cue and views into the central depth; guard the open edge. Exposed vertical space may cause vertigo, which is acceptable to note. Meta’s current guidance cautions against spiral stair motion and recommends gentle slopes, orientation support, and comfort options; retain an optional teleport or bypass where the layout allows. [Meta locomotion guidance](https://developers.meta.com/vr/design/locomotion-virtual-environments/) · [Meta best practices](https://developers.meta.com/vr/design/locomotion-best-practices/)
1. **Maze spine:** one route between actual mouths, no optional branches. Verify deterministic IDs, BVH bounds, interval soundness, no endpoint snaps, capsule support, ≥2.2 m headroom, and ≤15° grade. Capture an eye-level junction and a cutaway showing the route.
2. **Shaft spine:** integrate the four-turn helix above. Verify the final field at fine resolution for support, grade, headroom, and turn separation; include negative controls with undersized pitch and a disconnected mouth. Capture from the ramp, looking up and down, plus a side cutaway showing all four turns.
3. **Topology and cost:** add optional branches and loops, then measure sparse and dense cases against L54/L56. Verify branches cannot sever the required route and that tiles outside feature bounds are culled. Capture one branch landmark and the route overview.
**Uncertainty:** I did not rerun or rebuild anything, and the proposed helix has not been validated in the field. The old 15/16 result is user-supplied; I found neither its saved sweep output nor per-seed failure diagnoses. The old voxel-to-metre scale also varies across legacy assets.
**Owner question:** Is a roughly 21 m outer shaft diameter acceptable for the first 20 m, four-turn descent prototype?
@@ -0,0 +1,38 @@
# VoxelForge R26 — lattice generator family
## Legacy inventory
| Family | Generator and output | Per-sample work and bounds |
|---|---|---|
| **Maze** | [`BuildMazeStack`](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:9536>) composes solid rock, `FLatticeCorridorSource`, three-octave SDF roughness, and carving. The deterministic 3D lattice has origin-directed parent edges plus optional loops. Parameters include cell size, corridor radius, roughness, and boundary seal. | Hot path: floor to the containing cell and test up to 24 cached corridor capsules; roughness noise runs near the corridor surface. A cache miss rebuilds up to 24 edge decisions. Its box propagation scans up to 64³ cells and returns a geometric lower bound with an unbounded upper bound; oversized queries become unknown. No feature BVH. [Parameters](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelStrateTypes.h:1355>) · [source and bounds](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:659>) |
| **Vertical shafts** | [`BuildVerticalShaftStack`](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:9390>) composes rock, hash-placed full-height shafts and connector capsules, roughness and carving, periodic partial ledges, connector air/floor modifiers, and optional structural posts. Parameters include shaft spacing/radii, connector radius, ledge spacing/depth, roughness, and seal. | Hot path checks the local 3×3 shaft neighborhood and its connector capsules, then applies roughness, ledge, and connector operations. A cell-cache rebuild does the broader hash-grid and parent-link work. Box propagation scans up to 64² XY cells and also returns a lower bound with an unbounded upper bound; it has no BVH. [Parameters](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelStrateTypes.h:1658>) · [field](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:2252>) · [ledge and connector modifiers](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelDensityOpStack.cpp:2693>) |
These are code-level cost descriptions, not legacy per-sample benchmarks; I found no comparable timing for either generator.
## Native design and shaft walkability
Add a native lattice recipe with immutable, stable-ID graph records resolved from `(seed, strate, recipe version, cell, feature ID)`. Put the **required spine between the actual resolved arrival and departure anchors first**. Use a finite graph search to choose its cells and edges; A* is a standard option for this [graph-search problem](https://www.cs.auckland.ac.nz/courses/compsci709s2c/resources/Mike.d/astarNilsson.pdf). Add branches and loops only after that spine exists. Attach branches to it, and give any navigable dead end a supported landing or a clear return path.
Represent each room, corridor, and shaft as one filleted void feature with a stable ID. Reuse L54’s analytic SDF construction: cap each void against its floor with smooth-max, then union voids; L54 used a 2.4 m smooth width and measured a 0.702 m composed fillet. Keep route floors out of roughness displacement. [L54 field and fillet](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux54/REPORT.md:5>) [L54 construction details](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux54/REPORT.md:19>)
Store dimensions, floor profiles, blend widths, and padded bounds in the native resolved layout, following the existing micrometre-based cavern records. Build a BVH over bounds that include blend, floor support, and any bounded roughness. Use exact primitive intervals where available, propagate sound intervals through the composed field, and return unknown when a bound cannot be proven. Reuse the cave candidate lookup, field-classification, and tile-shape-free path; the BVH culls absent features, while interval proofs decide whether a tile is all air or solid. [Cavern records](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h:855>) · [BVH](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:3743>) · [interval classification](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:5125>) · [`isTileShapeFree`](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/VoxelForgeCore.cpp:1423>)
**The shaft route must not depend on falling.** The historical note reports arrival-to-departure failures on 15 of 16 seeds. The code’s diagnosis explains the structural gap: a large connected origin-spine component still does not guarantee that shaft networks at the measured passage mouths join. A full-height air column is not standing support; periodic one-sided ledges and sparse horizontal links do not establish a continuous route. [Connectivity diagnosis](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/Tests/VoxelForgeStrateConnectivityTest.cpp:2647>) [Landing-point constraints](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelCaveMorphology.cpp:6063>)
For a walkable descent without custom gravity, make the shaft a view well around a **continuous ramp**: a helix or broad switchbacks between landings. Enforce `|rise| / horizontal run ≤ tan(15°)` on every route segment. For example, a 4 m rise needs at least 14.9 m of horizontal run; a 4 m-radius helix rises 4 m per 25.1 m turn, about 9°. Verify the final composed field with a capsule flood fill from the actual mouths, plus local grade, support, and headroom checks—the method L54 used for caves. [L54 route audit](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux54/REPORT.md:21>)
## Cost and VR read
**Performance class: medium; unmeasured.** Use the measured L54 cave whole-view time (0.727 s) and L56 motif time (0.524 s) as comparison points, not forecasts. [Caves](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux54/REPORT.md:50>) · [Motifs](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux56/REPORT.md:27>) Capsule and cylinder fields are simpler per active feature than L54’s curved edges, but a dense lattice, many ramps, and broad mixed regions can outweigh that. Sparse BVH candidates and tight intervals are the main cost controls.
For an initial scale, try a maze pitch near 16 m, 3.5–5 m clear corridors, and a shaft spacing near 20 m; those pitch values match the legacy defaults’ documented Core scale. Repeat a consistent grid rhythm, then vary a few junctions and landmark bays so it reads as a maze rather than a featureless corridor set. Pair local junction markers with an occasional global landmark; a recent VR wayfinding study reports that landmark usefulness varies with navigation strategy. [Wayfinding study](https://www.sciencedirect.com/science/article/pii/S0272494425001446)
For shafts, expose the central void and repeated landing tiers, with visible handrails and human-scale references. Treat vertigo as an intended effect to assess, not a reason to drop the design: a 42-person VR height study found increased distress and physiological responses on an exposed platform up to 40 m, strongest among participants with greater height intolerance. [Study](https://pubmed.ncbi.nlm.nih.gov/35095450/) Keep the walking route clear and forward-readable; Meta’s guidance recommends gentle slopes, distant walls, and spatial sound cues for orientation. [Meta locomotion guidance](https://developers.meta.com/vr/design/locomotion-best-practices/)
## Slices and verification
1. **Maze slice:** a small multi-level lattice with the real arrival-to-departure spine, one optional branch, and one loop. Check deterministic layouts, interval soundness against brute-force samples, BVH candidates, tile-shape coverage, and final-field capsule reachability with grade ≤15°. Capture an eye-height junction view and a high oblique cutaway showing the route and repeated cells.
2. **Shaft slice:** two or three shaft cells joined by one helix or switchback descent. Run the same checks, then repeat the mouth-to-mouth walkability audit across the historical 16-seed matrix. Capture the ramp at eye height, a view across the shaft to its tiers, and a cutaway showing the complete route.
3. **Density pass:** add branches and additional levels only after both slices pass; repeat interval, determinism, route, and whole-view timing checks at the denser preset. Frame captures to show route support as well as scale.
**Question for the owner:** should the first playable slice be the maze or the shaft descent?
@@ -1205,6 +1205,12 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const int32 SampleX=OriginVoxels.X+gx*Step;
const int32 SampleY=OriginVoxels.Y+gy*Step;
const int32 SampleZ=OriginVoxels.Z+gz*Step;
const bool bBoundarySample=gx<0||gx>GridDim||gy<0||gy>GridDim
||gz<0||gz>GridDim;
VoxelForgeCore::floating_island_detail::FScopedIslandFieldCaller islandCaller(
bBoundarySample
?VoxelForgeCore::floating_island_detail::EIslandFieldCaller::Boundary
:VoxelForgeCore::floating_island_detail::EIslandFieldCaller::GridFill);
DensityGrid[LocalIndex] = ShapeWorldContext
?ShapeWorldContext->DensityAtLattice(SampleX,SampleY,SampleZ)
:Generator->GetDensityAtLattice(SampleX,SampleY,SampleZ,
@@ -1219,12 +1225,16 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
}
};
// Very coarse tiles revisit the same XY cache window across a tall Z run. Keep that
// vertical run contiguous; SampleGridPoint writes by lattice index, so output bits do
// not depend on this traversal. Finer tiles retain plane-first traversal, which has
// lower overhead when a tile spans only one room-graph region.
// Floating-island LOD0 points reuse the same island/XY column keys across vertical
// samples; large coarse tiles also revisit the same XY window across tall Z runs.
// SampleGridPoint writes by lattice index, so output bits do not depend on traversal order.
const int64 TileExtentVoxels = static_cast<int64>(Step) * CellsPerAxis;
const bool bUseVerticalCacheTraversal = TileExtentVoxels > CHUNK_SIZE * 16;
const float TileMiddleZ=static_cast<float>(OriginVoxels.Z)
+static_cast<float>(TileExtentVoxels)*0.5f;
const bool bFloatingIslandLod0=Step==1&&ShapeWorldContext
&&ShapeWorldContext->IsFloatingIslandFieldAtZ(TileMiddleZ);
const bool bUseVerticalCacheTraversal=bFloatingIslandLod0
||TileExtentVoxels>CHUNK_SIZE*16;
const FStandaloneShapeWorld* ActiveShapeWorld=ShapeWorldContext;
const bool bUseShapeWorldZBatch=ActiveShapeWorld!=nullptr
&&ActiveShapeWorld->IsAnalyticOnly()
@@ -1235,6 +1245,12 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const auto SampleShapeWorldXBatch=[&](int32 GX0,int32 BatchCount,int32 gy,int32 gz)
{
float Densities[8]{};
const bool bBoundarySample=GX0<0||GX0+BatchCount-1>GridDim
||gy<0||gy>GridDim||gz<0||gz>GridDim;
VoxelForgeCore::floating_island_detail::FScopedIslandFieldCaller islandCaller(
bBoundarySample
?VoxelForgeCore::floating_island_detail::EIslandFieldCaller::Boundary
:VoxelForgeCore::floating_island_detail::EIslandFieldCaller::GridFill);
ActiveShapeWorld->DensityAtLatticeX8(OriginVoxels.X+GX0*Step,Step,
OriginVoxels.Y+gy*Step,OriginVoxels.Z+gz*Step,BatchCount,Densities);
if(OutStageTimings)
@@ -1275,6 +1291,12 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const int32 SampleX=OriginVoxels.X+gx*Step;
const int32 SampleY=OriginVoxels.Y+gy*Step;
float Densities[CHUNK_SIZE+3]{};
const bool bBoundarySample=gx<0||gx>GridDim||gy<0||gy>GridDim
||GzLo<0||GzHi>GridDim;
VoxelForgeCore::floating_island_detail::FScopedIslandFieldCaller islandCaller(
bBoundarySample
?VoxelForgeCore::floating_island_detail::EIslandFieldCaller::Boundary
:VoxelForgeCore::floating_island_detail::EIslandFieldCaller::GridFill);
ActiveShapeWorld->DensityAtLatticeZRun(SampleX,SampleY,
OriginVoxels.Z+GzLo*Step,Step,BatchCount,Densities);
for(int32 Lane=0;Lane<BatchCount;++Lane)
@@ -1425,6 +1447,11 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const int32 SampleX=OriginVoxels.X+gx*Step;
const int32 SampleY=OriginVoxels.Y+gy*Step;
const int32 SampleZ=OriginVoxels.Z+gz*Step;
const bool bBoundarySample=gx<0||gx>GridDim||gy<0||gy>GridDim;
VoxelForgeCore::floating_island_detail::FScopedIslandFieldCaller islandCaller(
bBoundarySample
?VoxelForgeCore::floating_island_detail::EIslandFieldCaller::Boundary
:VoxelForgeCore::floating_island_detail::EIslandFieldCaller::GridFill);
DensityGrid[LocalIndex]=ShapeWorldContext
?ShapeWorldContext->DensityAtLattice(SampleX,SampleY,SampleZ)
:Generator->GetDensityAtLattice(SampleX,SampleY,SampleZ);
@@ -2035,6 +2062,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const int32 CapSurfaceTriangleCount=CapTris.Num()/3;
TArray<uint8> GroundSkirtFaceMasks,CapSkirtFaceMasks;
const uint64 SkirtStageStartCycles=OutStageTimings?FPlatformTime::Cycles64():0;
VoxelForgeCore::floating_island_detail::FScopedIslandFieldCaller skirtFieldCaller(
VoxelForgeCore::floating_island_detail::EIslandFieldCaller::Skirt);
if (bGenerateSkirts && (GroundTris.Num() + CapTris.Num()) > 0)
{
const float ExtentCm = (float)(CellsPerAxis * Step) * GeometryVoxelSize;
+73 -27
View File
@@ -1542,7 +1542,7 @@ def run_motif_captures_and_surface_audit(runner: VerificationRunner) -> None:
auditor = LINUX56 / "AuditMotifSurfaceR24.py"
_, output = runner.run_stage("capture-and-audit-motifs-slice1-r24", script,
["--out", str(OUT), "--fixture-dir", str(OUT / "fixtures"),
"--artifact-dir", str(LINUX56 / "captures"), "--headless", str(CLANG),
"--artifact-dir", str(OUT / "captures"), "--headless", str(CLANG),
"--renderer", str(RENDERER), "--auditor", str(auditor)],
binary=CLANG, data=OWNER, recipe="surface-world", style=None,
env=env_for(capture=True),
@@ -1803,41 +1803,87 @@ def run_cost_pairs(runner: VerificationRunner) -> None:
orders = (("baseline", "candidate"), ("candidate", "baseline"),
("baseline", "candidate"), ("candidate", "baseline"),
("baseline", "candidate"))
by_recipe: dict[str, dict[str, list[float]]] = {
"floating-islands": {"baseline": [], "candidate": []},
"surface-world": {"baseline": [], "candidate": []}}
by_pair: dict[tuple[str, int], dict[str, float]] = {}
for recipe, style in (("floating-islands", 2), ("surface-world", 1)):
caves_layout = OUT / "layouts" / "native-caves-field-clang.json"
caves_camera = cave_camera_positions(caves_layout, count=1)[0]
caves_camera_flag = "--camera=" + ",".join(f"{value:.6f}" for value in caves_camera)
motif_layout = OUT / "layouts" / "motif-slice1-capsule-reachability-clang.json"
motif_camera = motif_camera_rows(motif_layout)[0][1]
motif_camera_flag = "--camera=" + ",".join(f"{value:.6f}" for value in motif_camera)
owner_styles = {"0": 2, "1": 1}
contexts = (
("floating-islands", OWNER, "floating-islands", [], 2, owner_styles, -1),
# The resolved passage uses the TunnelNetwork-side style (strate 0 = 2);
# the separate owner-style check below still verifies SurfaceWorld strate 1 = 1.
("surface-world", OWNER, "surface-world", [], 2, owner_styles, -1),
("caves", OUT / "fixtures" / "caves.json", "caves",
[caves_camera_flag, "--clip-radius=4", "--max-clip-level=0",
"--max-level=0", "--render-distance-chunks=0"],
2, owner_styles, 0),
("motifs", OUT / "fixtures" / "style-override-motifs-slice1.json", "surface-world",
[motif_camera_flag, "--clip-radius=3", "--max-clip-level=0",
"--max-level=0", "--render-distance-chunks=0"],
2, owner_styles, 0),
)
by_recipe: dict[str, dict[str, dict[str, list[float]]]] = {
name: {build: {metric: [] for metric in
("whole_view_seconds", "first_tile_seconds", "near_ring_seconds",
"moving_p50_ms", "moving_p95_ms")}
for build in ("baseline", "candidate")}
for name, *_ in contexts}
by_pair: dict[tuple[str, int], dict[str, dict[str, float]]] = {}
for name, data, recipe, base_flags, style, expected_styles, max_level in contexts:
flags = [*base_flags, "--camera-step=24,0,0", "--region-crossing"]
for pair, order in enumerate(orders, 1):
for build in order:
binary = baseline if build == "baseline" else candidate
name = f"cost-{recipe}-pair{pair}-{build}"
run_name = f"cost-{name}-pair{pair}-{build}"
expected_stamp = baseline_stamp if build == "baseline" else None
row, output = runner.run_cpp(name, binary, OWNER, recipe, [],
expected_style=2 if build == "candidate" else None,
expected_strate_styles={"0": 2, "1": 1} if build == "candidate" else None,
layout_path=OUT / "layouts" / f"{name}.json",
row, output = runner.run_cpp(run_name, binary, data, recipe, flags,
expected_style=style if build == "candidate" else None,
expected_strate_styles=expected_styles if build == "candidate" else None,
max_level=max_level,
layout_path=OUT / "layouts" / f"{run_name}.json",
expected_stamp=expected_stamp)
row["requested_style"] = style
row["expected_passage_style"] = 2 if build == "candidate" else None
ready = re.findall(r"\bwhole_view_ready=([0-9.]+)s", output)
ok = (len(ready) == 1 and "hash=off" in output
row["expected_passage_style"] = style if build == "candidate" else None
stream = re.search(r"^\[StreamPipeline\].*?first_tile_ready=([0-9.]+)s "
r".*?neighborhood_ready=([0-9.]+)s .*?whole_view_ready=([0-9.]+)s",
output, re.M)
moving = re.search(r"^\[MovingTileLatency\] entering_tiles=(\d+) "
r"p50_ms=([0-9.]+) p95_ms=([0-9.]+) "
r"metric=submit_to_completion_observed$", output, re.M)
metrics = ({"first_tile_seconds": float(stream.group(1)),
"near_ring_seconds": float(stream.group(2)),
"whole_view_seconds": float(stream.group(3)),
"moving_p50_ms": float(moving.group(2)),
"moving_p95_ms": float(moving.group(3))}
if stream and moving and int(moving.group(1)) > 0 else {})
row["cost_metrics"] = metrics
ok = (len(metrics) == 5 and "hash=off" in output
and "cache_hits=0" in output
and RECIPE_RE.findall(output) == [(recipe, recipe, "PASS")])
runner.require(f"{name}:cost-record", ok,
f"whole_view_ready={ready[0] if ready else 'MISSING'}s "
runner.require(f"{run_name}:cost-record", ok,
f"metrics={metrics if metrics else 'MISSING'} "
f"source_stamp={row['source_stamp']}")
by_recipe[recipe][build].append(float(ready[0]))
by_pair.setdefault((recipe, pair), {})[build] = float(ready[0])
for recipe, values in by_recipe.items():
old = statistics.median(values["baseline"])
new = statistics.median(values["candidate"])
paired = [((by_pair[(recipe, pair)]["candidate"] - by_pair[(recipe, pair)]["baseline"])
/ by_pair[(recipe, pair)]["baseline"] * 100.0)
for pair in range(1, 6)]
runner.require(f"cost-{recipe}-five-pairs",
len(values["baseline"]) == len(values["candidate"]) == 5,
f"median_baseline_s={old:.3f} median_candidate_s={new:.3f} "
for metric, value in metrics.items():
by_recipe[name][build][metric].append(value)
by_pair.setdefault((name, pair), {})[build] = metrics
for name, values in by_recipe.items():
for metric in values["baseline"]:
old_values = values["baseline"][metric]
new_values = values["candidate"][metric]
old = statistics.median(old_values) if old_values else float("inf")
new = statistics.median(new_values) if new_values else float("inf")
paired = [((by_pair[(name, pair)]["candidate"][metric]
- by_pair[(name, pair)]["baseline"][metric])
/ by_pair[(name, pair)]["baseline"][metric] * 100.0)
for pair in range(1, 6)
if (name, pair) in by_pair
and len(by_pair[(name, pair)].get("baseline", {})) == 5
and len(by_pair[(name, pair)].get("candidate", {})) == 5]
runner.require(f"cost-{name}-{metric}-five-pairs",
len(old_values) == len(new_values) == len(paired) == 5,
f"median_baseline={old:.3f} median_candidate={new:.3f} "
f"median_change_pct={(new / old - 1.0) * 100.0:+.2f} "
f"paired_change_pct={','.join(f'{value:+.2f}' for value in paired)}")