wip(assembler): round S2 (Sol) -- shared per-tile feature queries for every Core family; island placement 30x faster

Island-only worker context replaced by a shared worker-local candidate domain
(WorldAssemblyFeatureTileListV1 / ScopedWorldAssemblyFeatureQueriesV1) serving
SurfaceWorld, FloatingIslands and far-shell queries; a per-domain cost hint keeps the
full scan on small plans. Content placement prepares the same queries and skips proven
air: owner island cell p95 7.07 -> 0.24 ms; populated fixture 572 exact placements,
3.27 s -> 29 ms. Full/candidate hashes equal with dropped-feature controls on both
families; S1 default W1/W8/W16 hashes reproduced; Core-off and M2 fixtures pass.
Default contract for future families in ARCHITECTURE 8.23. Run on gpt-6.1-sol medium.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-18 19:50:45 +02:00
1 parent d6e69420e8
commit 6ddb834b1c
19 files changed
+1849 -132

No files matched your search

+125 -2
View File
@@ -15,6 +15,45 @@
namespace VoxelForgeCore
{
namespace
{
thread_local const ScopedWorldAssemblyFeatureQueriesV1* ActiveAssemblyQueries = nullptr;
}
ScopedWorldAssemblyFeatureQueriesV1::ScopedWorldAssemblyFeatureQueriesV1(
std::span<const WorldAssemblyFeatureQueryV1> queries, bool forceCandidatesForValidation) noexcept
: queries_(queries), forceCandidates_(forceCandidatesForValidation), previous_(ActiveAssemblyQueries)
{
// Resolve cost hints once per domain, never rediscover them in the sample loop.
// Resoudre les indications de cout une fois par domaine, hors de la boucle d'echantillons.
ActiveAssemblyQueries = nullptr;
for (const auto& query : queries_)
if (forceCandidates_ || query.features.candidateEvaluationUseful)
{ ActiveAssemblyQueries = this; break; }
}
ScopedWorldAssemblyFeatureQueriesV1::~ScopedWorldAssemblyFeatureQueriesV1()
{ ActiveAssemblyQueries = previous_; }
const WorldAssemblyFeatureTileListV1* ScopedWorldAssemblyFeatureQueriesV1::find(
const void* recipe, const void* plan, std::int64_t x, std::int64_t y,
std::int64_t z, bool columnOnly) noexcept
{
const std::array<std::int64_t, 3> point{x,y,z};
if (ActiveAssemblyQueries)
for (const auto& query : ActiveAssemblyQueries->queries_)
{
if (query.recipe != recipe || query.plan != plan
|| (!ActiveAssemblyQueries->forceCandidates_ && !query.features.candidateEvaluationUseful)) continue;
bool inside = true;
for (std::size_t axis=0; axis<(columnOnly ? 2u : 3u); ++axis)
inside = inside && point[axis]>=query.features.minimumSubvoxels[axis]
&& point[axis]<=query.features.maximumSubvoxels[axis];
if (inside) return &query.features;
}
return nullptr;
}
std::vector<std::uint32_t> BuildWorldAssemblyFeatureTileListV1(
std::span<const WorldAssemblyFeatureBoundsV1> features,
const std::array<std::int64_t, 3>& tileMinimumSubvoxels,
@@ -52,8 +91,54 @@ std::vector<std::uint32_t> BuildWorldAssemblyFeatureTileListV1(
return result;
}
WorldAssemblyFeatureColumnRangeV1 BuildWorldAssemblyFeatureColumnRangeV1(
std::span<const WorldAssemblyFeatureBoundsV1> bounds, std::int64_t x, std::int64_t y)
{
WorldAssemblyFeatureColumnRangeV1 result;
result.known=true;
result.empty=true;
for(const auto& bound:bounds)
{
for(std::size_t axis=0;axis<3;++axis)
if(bound.minimumSubvoxels[axis]>bound.maximumSubvoxels[axis]) return {};
if(x<bound.minimumSubvoxels[0]||x>bound.maximumSubvoxels[0]
||y<bound.minimumSubvoxels[1]||y>bound.maximumSubvoxels[1])continue;
if(result.empty)
{
result.minimumZSubvoxels=bound.minimumSubvoxels[2];
result.maximumZSubvoxels=bound.maximumSubvoxels[2];
result.empty=false;
}
else
{
result.minimumZSubvoxels=std::min(result.minimumZSubvoxels,bound.minimumSubvoxels[2]);
result.maximumZSubvoxels=std::max(result.maximumZSubvoxels,bound.maximumSubvoxels[2]);
}
}
return result;
}
namespace world_assembly_detail
{
// Preserve recipe order without allocating or looking up metadata in the point loop.
// Garder l'ordre de recette sans allocation ni recherche de metadonnees par point.
struct FeatureRange
{
const std::vector<WorldAssemblyFeatureV1>& features;
const WorldAssemblyFeatureTileListV1* list;
struct Iterator
{
const FeatureRange* range;
std::size_t index;
const WorldAssemblyFeatureV1& operator*() const
{ return range->features[range->list ? range->list->featureIndices[index] : index]; }
Iterator& operator++() { ++index; return *this; }
bool operator!=(const Iterator& other) const { return index!=other.index; }
};
Iterator begin() const { return {this,0}; }
Iterator end() const { return {this,list ? list->featureIndices.size() : features.size()}; }
};
constexpr std::int64_t Q16 = 1ll << 16;
constexpr std::int64_t MinimumCliffShelfThicknessSubvoxels = 2 * WorldAssemblySubvoxelsPerVoxel;
constexpr std::int64_t MaxSerializedMagnitude = 1000000000000ll;
@@ -1294,7 +1379,8 @@ namespace world_assembly_detail
:CapHeightV2(recipe,plan,neighbor,x,y);
std::int64_t cap=primaryCap+((neighborCap-primaryCap)
*(static_cast<std::int64_t>(Q16)-selection.primaryWeightQ16))/Q16;
for(const auto& feature:plan.features)
const auto* list=ScopedWorldAssemblyFeatureQueriesV1::find(&recipe,&plan,x,y,0,true);
for(const auto& feature:FeatureRange{plan.features,list})
{
if(feature.type==1)
{
@@ -1730,6 +1816,42 @@ bool Heightfield2D::isValid() const noexcept
});
}
WorldAssemblyFeatureTileListV1 Heightfield2D::buildFeatureTileList(
const std::array<std::int64_t,3>& minimum,
const std::array<std::int64_t,3>& maximum) const
{
WorldAssemblyFeatureTileListV1 result;
// One shelf in the staged owner plan has no useful scan to shorten. Keep its full evaluator.
// Une seule corniche dans le plan auteur ne justifie pas la selection par echantillon.
result.candidateEvaluationUseful=plan_->features.size()>1;
result.minimumSubvoxels=minimum;
result.maximumSubvoxels=maximum;
std::vector<WorldAssemblyFeatureBoundsV1> bounds;
bounds.reserve(plan_->features.size());
for(const auto& feature:plan_->features)
{
WorldAssemblyFeatureBoundsV1 bound{feature.stableId,
feature.minimumSubvoxels,feature.maximumSubvoxels};
// Column writers affect every Z; finite volumes have an exact no-op outside their box.
// Les modificateurs de colonne agissent sur tout Z; les volumes sont neutres hors boite.
if(feature.type==1||feature.type==3)
{
bound.minimumSubvoxels[2]=std::numeric_limits<std::int64_t>::min();
bound.maximumSubvoxels[2]=std::numeric_limits<std::int64_t>::max();
}
else if(feature.type!=2&&feature.type!=4)
{
// Unknown future operations must opt into a proof before they can be culled.
// Une operation inconnue reste active tant que sa preuve manque.
bound.minimumSubvoxels.fill(std::numeric_limits<std::int64_t>::min());
bound.maximumSubvoxels.fill(std::numeric_limits<std::int64_t>::max());
}
bounds.push_back(bound);
}
result.featureIndices=BuildWorldAssemblyFeatureTileListV1(bounds,minimum,maximum);
return result;
}
HeightfieldPointSample Heightfield2D::point(std::int64_t x, std::int64_t y,
std::int64_t z) const noexcept
{
@@ -1744,7 +1866,8 @@ HeightfieldPointSample Heightfield2D::point(std::int64_t x, std::int64_t y,
out.capHeightSubvoxels-z);
if(recipe_->evaluatorVersion>=2)
{
for(const auto& feature:plan_->features)
const auto* list=ScopedWorldAssemblyFeatureQueriesV1::find(recipe_,plan_,x,y,z);
for(const auto& feature:FeatureRange{plan_->features,list})
{
if(feature.type==2)
{