wip(assembler): round L22 -- one 8 m layout chunk for every strate; real ceiling -> content -> bedrock

StrateLayoutChunkSizeMeters (world setting, default 8 m; owner decision) is resolved once in
the director/adapter and standalone loader; every generator reads the resolved width (no
CHUNK_SIZE / Core-tile inference). Every strate gets solid ceiling and bedrock bands from its
BoundarySealThickness in the shared composition path (diggable by default); faces come from the
shared boundary path. Owner world: FloatingIslands +8..-120 m (128 m, now with a bedrock floor),
SurfaceWorld -120..-632 m (unchanged; full-detail and exact-query hashes equal L21); the 60 m gap is
gone. The strict layout validator passes on the real world, with 0 endpoint dispatch
disagreements. Spawn/benchmark camera derived from route.front. Ledges under the islands gone
(reviewer capture). Evaluator 7, recipe schema 2, layout snapshot 2, FI geometry 4.
Open: SW cap profiles exceed the ceiling band (owner call); transitions still Hard; Unreal
setting/manager/adapter edits uncompiled here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-20 12:03:14 +02:00
1 parent 8753f6dbe4
commit 55c26a05a7
28 files changed
+1432 -579

No files matched your search

+50 -35
View File
@@ -39,37 +39,42 @@ namespace
}
std::string LayoutHex(std::uint64_t value)
{std::ostringstream out;out<<std::hex<<std::setfill('0')<<std::setw(16)<<value;return out.str();}
std::int64_t LayoutTransitionLimit(const ResolvedLayoutStratumV1& stratum)
std::int64_t LayoutTransitionLimit(const ResolvedLayoutStratumV2& stratum)
{
if(stratum.transitionMode=="Hard")return 0;
if(stratum.transitionMode=="Hard"||stratum.transitionFallsBackToHard)return 0;
return stratum.transitionWidthMicrometres
+(stratum.transitionMode=="Interleaved"?stratum.transitionWarpAmplitudeMicrometres:0);
}
std::string LayoutBandJson(const ResolvedLayoutBandV1& band)
std::string LayoutBandJson(const ResolvedLayoutBandV2& band)
{
std::ostringstream out;out<<"{\"kind\":"<<LayoutEscape(band.kind)
<<",\"bottom_um\":"<<band.bottomMicrometres<<",\"top_um\":"<<band.topMicrometres
<<",\"present\":"<<(band.presentInCurrentField?"true":"false")
<<",\"diggable\":"<<(band.diggable?"true":"false")
<<",\"protected\":"<<(band.protectedBand?"true":"false")
<<",\"solid_density_q16\":"<<band.solidDensityQ16
<<",\"behaviour\":"<<LayoutEscape(band.behaviour)
<<",\"density_side\":"<<LayoutEscape(band.densitySide)
<<",\"cap_path\":"<<LayoutEscape(band.capPath)<<'}';return out.str();
}
ResolvedLayoutBandV1 ParseLayoutBand(const VFJson::Value& value)
ResolvedLayoutBandV2 ParseLayoutBand(const VFJson::Value& value)
{
ResolvedLayoutBandV1 b;b.kind=value.Get("kind").String();
ResolvedLayoutBandV2 b;b.kind=value.Get("kind").String();
b.bottomMicrometres=value.Get("bottom_um").Integer();b.topMicrometres=value.Get("top_um").Integer();
b.presentInCurrentField=value.Get("present").Boolean();b.diggable=value.Get("diggable").Boolean(true);
b.protectedBand=value.Get("protected").Boolean();b.behaviour=value.Get("behaviour").String();
b.protectedBand=value.Get("protected").Boolean();b.solidDensityQ16=value.Get("solid_density_q16").Integer(65536);
b.behaviour=value.Get("behaviour").String();
b.densitySide=value.Get("density_side").String();b.capPath=value.Get("cap_path").String();return b;
}
std::string LayoutBodyJson(const ResolvedLayoutSnapshotV1& s)
std::string LayoutBodyJson(const ResolvedLayoutSnapshotV2& s)
{
std::ostringstream out;out<<"{\"schema_version\":"<<s.schemaVersion
<<",\"world_identity\":"<<LayoutEscape(s.worldIdentity)
<<",\"owner_voxel_size_um\":"<<s.ownerVoxelSizeMicrometres
<<",\"core_voxel_size_um\":"<<s.coreVoxelSizeMicrometres<<",\"strates\":[";
<<",\"core_voxel_size_um\":"<<s.coreVoxelSizeMicrometres
<<",\"strate_layout_chunk_size_um\":"<<s.strateLayoutChunkSizeMicrometres
<<",\"strate_layout_chunk_width_subvoxels\":"<<s.strateLayoutChunkWidthSubvoxels
<<",\"strates\":[";
for(std::size_t i=0;i<s.strates.size();++i)
{
if(i)out<<',';const auto& x=s.strates[i];
@@ -90,6 +95,7 @@ namespace
<<",\"transition_warp_amplitude_um\":"<<x.transitionWarpAmplitudeMicrometres
<<",\"transition_interpenetration_um\":"<<x.transitionInterpenetrationMicrometres
<<",\"transition_honoured_in_core\":"<<(x.transitionHonouredInCore?"true":"false")
<<",\"transition_falls_back_to_hard\":"<<(x.transitionFallsBackToHard?"true":"false")
<<",\"transition_dispatch_path\":"<<LayoutEscape(x.transitionDispatchPath)
<<",\"bound_dispatch_path\":"<<LayoutEscape(x.boundDispatchPath)
<<",\"query_dispatch_path\":"<<LayoutEscape(x.queryDispatchPath)
@@ -117,17 +123,18 @@ namespace
{return obj.Get(key).Boolean(fallback);}
}
std::string ResolvedLayoutSnapshotV1::ToJson() const
std::string ResolvedLayoutSnapshotV2::ToJson() const
{
const std::string body=LayoutBodyJson(*this);
return body.substr(0,body.size()-1)+",\"stable_identity\":"
+LayoutEscape(stableIdentity.empty()?"resolved-layout-v1-fnv64:"+LayoutHex(LayoutHash(body)):stableIdentity)+"}";
+LayoutEscape(stableIdentity.empty()?"resolved-layout-v2-fnv64:"+LayoutHex(LayoutHash(body)):stableIdentity)+"}";
}
bool ResolvedLayoutSnapshotV1::finalize(std::string& error)
bool ResolvedLayoutSnapshotV2::finalize(std::string& error)
{
error.clear();
if(schemaVersion!=ResolvedLayoutSchemaVersionV1||worldIdentity.empty()||strates.empty())
if(schemaVersion!=ResolvedLayoutSchemaVersionV2||worldIdentity.empty()||strates.empty()
||strateLayoutChunkSizeMicrometres==0||strateLayoutChunkWidthSubvoxels<=0)
{error="resolved layout has an unsupported version, empty world identity, or no strates";return false;}
std::stable_sort(strates.begin(),strates.end(),[](const auto& a,const auto& b)
{return a.interiorTopMicrometres!=b.interiorTopMicrometres
@@ -143,20 +150,21 @@ bool ResolvedLayoutSnapshotV1::finalize(std::string& error)
{error="resolved layout contains an invalid interior interval or voxel size";return false;}
}
stableIdentity.clear();const std::string body=LayoutBodyJson(*this);
stableIdentity="resolved-layout-v1-fnv64:"+LayoutHex(LayoutHash(body));
std::vector<ResolvedLayoutIssueV1> issues;
return validate(ResolvedLayoutValidationModeV1::compatibility,issues,error);
stableIdentity="resolved-layout-v2-fnv64:"+LayoutHex(LayoutHash(body));
std::vector<ResolvedLayoutIssueV2> issues;
return validate(ResolvedLayoutValidationModeV2::compatibility,issues,error);
}
bool ResolvedLayoutSnapshotV1::validate(ResolvedLayoutValidationModeV1 mode,
std::vector<ResolvedLayoutIssueV1>& issues,std::string& error) const
bool ResolvedLayoutSnapshotV2::validate(ResolvedLayoutValidationModeV2 mode,
std::vector<ResolvedLayoutIssueV2>& issues,std::string& error) const
{
issues.clear();error.clear();
if(schemaVersion!=ResolvedLayoutSchemaVersionV1||worldIdentity.empty()||strates.empty())
if(schemaVersion!=ResolvedLayoutSchemaVersionV2||worldIdentity.empty()||strates.empty()
||strateLayoutChunkSizeMicrometres==0||strateLayoutChunkWidthSubvoxels<=0)
{error="resolved layout schema/world/strata header is invalid";return false;}
const auto add=[&](std::string code,std::string detail)
{issues.push_back({std::move(code),std::move(detail)});};
const bool strict=mode==ResolvedLayoutValidationModeV1::strict;
const bool strict=mode==ResolvedLayoutValidationModeV2::strict;
for(std::size_t i=0;i<strates.size();++i)
{
const auto& s=strates[i];
@@ -169,7 +177,8 @@ bool ResolvedLayoutSnapshotV1::validate(ResolvedLayoutValidationModeV1 mode,
if(s.managerChunkWidthMicrometres>0&&s.dispatchChunkWidthMicrometres>0
&&s.managerChunkWidthMicrometres!=s.dispatchChunkWidthMicrometres)
add("ambiguous_dispatch_units",s.stableId+" manager chunk width differs from Core dispatch chunk width");
if(i+1<strates.size()&&s.transitionMode!="Hard"&&!s.transitionHonouredInCore)
if(i+1<strates.size()&&s.transitionMode!="Hard"&&!s.transitionHonouredInCore
&&!s.transitionFallsBackToHard)
add("transition_not_honoured",s.stableId+" declares a blend/interleave that Core does not apply on this interface");
if(!s.ceiling.presentInCurrentField)add("missing_ceiling",s.stableId+" has no explicit ceiling band in today's field");
if(!s.bedrock.presentInCurrentField)add("missing_bedrock",s.stableId+" has no explicit bedrock floor in today's field");
@@ -180,12 +189,14 @@ bool ResolvedLayoutSnapshotV1::validate(ResolvedLayoutValidationModeV1 mode,
add(!s.ceiling.presentInCurrentField?"missing_ceiling":"missing_bedrock",s.stableId+" lacks a required boundary band");
if(!s.content.presentInCurrentField)
add("missing_content",s.stableId+" has no content generator band");
const auto bandShape=[&](const ResolvedLayoutBandV1& b,std::string_view expected)
const auto bandShape=[&](const ResolvedLayoutBandV2& b,std::string_view expected)
{
if(b.kind!=expected||b.topMicrometres<=b.bottomMicrometres)
add("wrong_order",s.stableId+" has an invalid "+std::string(expected)+" band");
if(b.protectedBand&&b.diggable)
add("invalid_protection",s.stableId+" band is both protected and diggable");
if(b.solidDensityQ16<=0)
add("invalid_solid_density",s.stableId+" has a non-positive solid band strength");
};
bandShape(s.ceiling,"ceiling");bandShape(s.content,"content");bandShape(s.bedrock,"bedrock");
if(s.ceiling.bottomMicrometres!=s.content.topMicrometres
@@ -255,18 +266,20 @@ bool ResolvedLayoutSnapshotV1::validate(ResolvedLayoutValidationModeV1 mode,
return true;
}
std::optional<ResolvedLayoutSnapshotV1> ResolvedLayoutSnapshotV1::FromJson(
std::optional<ResolvedLayoutSnapshotV2> ResolvedLayoutSnapshotV2::FromJson(
std::string_view json,std::string& error)
{
VFJson::Value root;if(!VFJson::Parser(std::string(json)).Parse(root,error))return std::nullopt;
if(!root.IsObject()){error="resolved layout JSON root must be an object";return std::nullopt;}
ResolvedLayoutSnapshotV1 s;s.schemaVersion=static_cast<std::uint32_t>(LayoutInt(root,"schema_version"));
ResolvedLayoutSnapshotV2 s;s.schemaVersion=static_cast<std::uint32_t>(LayoutInt(root,"schema_version"));
s.worldIdentity=LayoutString(root,"world_identity");
s.ownerVoxelSizeMicrometres=static_cast<std::uint32_t>(LayoutInt(root,"owner_voxel_size_um"));
s.coreVoxelSizeMicrometres=static_cast<std::uint32_t>(LayoutInt(root,"core_voxel_size_um"));
s.strateLayoutChunkSizeMicrometres=static_cast<std::uint32_t>(LayoutInt(root,"strate_layout_chunk_size_um"));
s.strateLayoutChunkWidthSubvoxels=LayoutInt(root,"strate_layout_chunk_width_subvoxels");
for(const auto& v:root.Get("strates").AsArray())
{
ResolvedLayoutStratumV1 x;x.stableId=LayoutString(v,"stable_id");
ResolvedLayoutStratumV2 x;x.stableId=LayoutString(v,"stable_id");
x.order=static_cast<std::int32_t>(LayoutInt(v,"order"));x.strateIndex=static_cast<std::int32_t>(LayoutInt(v,"strate_index"));
x.generatorKind=LayoutString(v,"generator_kind");x.recipeId=LayoutString(v,"recipe_id");
x.recipeVersion=static_cast<std::uint32_t>(LayoutInt(v,"recipe_version"));
@@ -278,12 +291,14 @@ std::optional<ResolvedLayoutSnapshotV1> ResolvedLayoutSnapshotV1::FromJson(
x.transitionWidthMicrometres=LayoutInt(v,"transition_width_um");
x.transitionWarpAmplitudeMicrometres=LayoutInt(v,"transition_warp_amplitude_um");
x.transitionInterpenetrationMicrometres=LayoutInt(v,"transition_interpenetration_um");
x.transitionHonouredInCore=LayoutBool(v,"transition_honoured_in_core");x.transitionDispatchPath=LayoutString(v,"transition_dispatch_path");
x.transitionHonouredInCore=LayoutBool(v,"transition_honoured_in_core");
x.transitionFallsBackToHard=LayoutBool(v,"transition_falls_back_to_hard");
x.transitionDispatchPath=LayoutString(v,"transition_dispatch_path");
x.boundDispatchPath=LayoutString(v,"bound_dispatch_path");x.queryDispatchPath=LayoutString(v,"query_dispatch_path");
x.managerLookup=LayoutString(v,"manager_lookup");x.managerChunkWidthMicrometres=LayoutInt(v,"manager_chunk_width_um");
x.dispatchChunkWidthMicrometres=LayoutInt(v,"dispatch_chunk_width_um");
for(const auto& a:v.Get("anchors").AsArray())
{ResolvedLayoutAnchorV1 p;p.kind=LayoutString(a,"kind");p.stableId=LayoutString(a,"stable_id");p.units=LayoutString(a,"units");
{ResolvedLayoutAnchorV2 p;p.kind=LayoutString(a,"kind");p.stableId=LayoutString(a,"stable_id");p.units=LayoutString(a,"units");
for(const auto& value:a.Get("values").AsArray())p.values.push_back(value.Integer());x.anchors.push_back(std::move(p));}
s.strates.push_back(std::move(x));
}
@@ -293,12 +308,12 @@ std::optional<ResolvedLayoutSnapshotV1> ResolvedLayoutSnapshotV1::FromJson(
return s;
}
ResolvedLayoutValidatorAuditV1 AuditResolvedLayoutValidatorV1()
ResolvedLayoutValidatorAuditV2 AuditResolvedLayoutValidatorV2()
{
ResolvedLayoutValidatorAuditV1 result;
ResolvedLayoutValidatorAuditV2 result;
auto make=[](std::string id,std::int32_t order,std::int64_t top,std::int64_t bottom)
{
ResolvedLayoutStratumV1 s;s.stableId=std::move(id);s.order=order;s.strateIndex=order;s.generatorKind="synthetic";
ResolvedLayoutStratumV2 s;s.stableId=std::move(id);s.order=order;s.strateIndex=order;s.generatorKind="synthetic";
s.interiorTopMicrometres=top;s.interiorBottomMicrometres=bottom;s.voxelSizeMicrometres=250000;
s.transitionMode="Gradient";s.transitionWidthMicrometres=4000000;
s.transitionHonouredInCore=true;
@@ -307,15 +322,15 @@ ResolvedLayoutValidatorAuditV1 AuditResolvedLayoutValidatorV1()
s.bedrock={"bedrock",bottom-1000000,bottom,true,true,false,"breakable bedrock","lower face","none"};
return s;
};
const auto expectReject=[&](std::string name,ResolvedLayoutSnapshotV1 candidate)
const auto expectReject=[&](std::string name,ResolvedLayoutSnapshotV2 candidate)
{
++result.controlsRun;std::vector<ResolvedLayoutIssueV1> issues;std::string error;
if(!candidate.validate(ResolvedLayoutValidationModeV1::strict,issues,error))++result.controlsRejectedAsExpected;
++result.controlsRun;std::vector<ResolvedLayoutIssueV2> issues;std::string error;
if(!candidate.validate(ResolvedLayoutValidationModeV2::strict,issues,error))++result.controlsRejectedAsExpected;
else result.failures.push_back({"negative_control_accepted",std::move(name)+" was accepted by strict validator"});
};
auto base=ResolvedLayoutSnapshotV1{};base.worldIdentity="synthetic";base.strates={make("a",0,10000000,0),make("b",1,-2000000,-12000000)};
{std::vector<ResolvedLayoutIssueV1> issues;std::string error;
if(!base.validate(ResolvedLayoutValidationModeV1::strict,issues,error))
auto base=ResolvedLayoutSnapshotV2{};base.worldIdentity="synthetic";base.strates={make("a",0,10000000,0),make("b",1,-2000000,-12000000)};
{std::vector<ResolvedLayoutIssueV2> issues;std::string error;
if(!base.validate(ResolvedLayoutValidationModeV2::strict,issues,error))
result.failures.push_back({"positive_control_rejected","valid ceiling/content/bedrock layout was rejected"});}
auto boundaryGap=base;boundaryGap.strates[1].ceiling.topMicrometres-=1;
expectReject("bedrock/next-ceiling gap",boundaryGap);