planner: four-strate owner plan spawns (L66); pinned 2-strate regression fixture

- Core caps each passage mouth reach to its own strate's usable content band (owner
  DA_Strate1 exports ReachMax=5000 owner voxels, which put the SW->FI lower mouth 79.5 m
  below FI, inside TN).
- Unreal adapter: SW route search keeps the old 64 m candidates first, then a bounded
  single-mouth search with shorter lengths; logs candidate/rejection counts.
- Internal-chain passage floor/support tweaks (only with >2 strates): ripple 1-2 4.78->2.90 cm,
  2-3 3.57->0.10 cm. Interfaces still 0/3 walkable (59/3/2 unsupported).
- verify.py: legacy tiers use Standalone/data/regression/owner_world_2strate_l61.json; new
  four-strate stage reads its expectations from owner_world.json (currently red on interfaces).
- Unreal trace L14 vs HEAD, same assets (16-chunk FlatPlain): 12.20 vs 12.56 worker-s; no x2.

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-26 22:13:22 +01:00
1 parent 47148e0a0d
commit 5e2fc53d39
17 files changed
+745 -73

No files matched your search

+34 -6
View File
@@ -2325,8 +2325,22 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
const std::int64_t midRadius=std::max<std::int64_t>(
static_cast<std::int64_t>(std::llround((upperIsSurfaceWorld?3.5:1.5)*qPerMetre)),
cfg?cfg->midRadiusSubvoxels:mouthRadius);
const std::int64_t reachMinimum=cfg?std::max<std::int64_t>(0,cfg->reachMinimumSubvoxels):8*qPerMetre;
const std::int64_t reachMaximum=cfg?std::max<std::int64_t>(reachMinimum,cfg->reachMaximumSubvoxels):24*qPerMetre;
const std::int64_t requestedReachMinimum=cfg
?std::max<std::int64_t>(0,cfg->reachMinimumSubvoxels):8*qPerMetre;
const std::int64_t requestedReachMaximum=cfg
?std::max<std::int64_t>(requestedReachMinimum,cfg->reachMaximumSubvoxels):24*qPerMetre;
// Keep the landing several metres inside the stratum's authored content.
// Near a band edge, the sampled native terrain can exist at the centerline
// while the full capsule footprint has no supporting ground.
const std::int64_t mouthClearance=std::max(mouthRadius,midRadius)+2*qPerMetre;
const auto usableReach=[&](const ResolvedLayoutStratumV2& stratum)
{
const std::int64_t depth=contentZQ(stratum.content.topMicrometres)
-contentZQ(stratum.content.bottomMicrometres);
return std::max<std::int64_t>(0,depth-mouthClearance);
};
const std::int64_t upperReachLimit=usableReach(upper);
const std::int64_t lowerReachLimit=usableReach(lower);
const std::uint32_t style=cfg?std::min<std::uint32_t>(cfg->style,3u):1u;
const std::uint32_t segments=cfg?std::clamp<std::uint32_t>(cfg->segments,16u,48u):20u;
const std::int64_t wander=cfg?std::max<std::int64_t>(0,cfg->wanderSubvoxels):3*qPerMetre;
@@ -2362,16 +2376,30 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
if(!hasUpperRoute)
{
upperMouth[0]=xy[0];upperMouth[1]=xy[1];
const auto reach=reachValue(PassageSeed(seed,upper.strateIndex,lower.strateIndex,
connection,0x55505248u),reachMinimum,reachMaximum);
const auto requestedReach=reachValue(PassageSeed(seed,upper.strateIndex,
lower.strateIndex,connection,0x55505248u),
requestedReachMinimum,requestedReachMaximum);
const auto reach=std::min(requestedReach,upperReachLimit);
upperMouth[2]=contentZQ(upper.content.bottomMicrometres)+reach;
if(requestedReach>upperReachLimit)
std::printf("[ResolvedPassageReachClamp] id=%s side=upper sampled_m=%.3f usable_max_m=%.3f selected_m=%.3f status=CLAMPED\n",
passage.stableId.c_str(),requestedReach/static_cast<double>(qPerMetre),
upperReachLimit/static_cast<double>(qPerMetre),
reach/static_cast<double>(qPerMetre));
}
if(!hasLowerRoute)
{
lowerMouth[0]=xy[0];lowerMouth[1]=xy[1];
const auto reach=reachValue(PassageSeed(seed,upper.strateIndex,lower.strateIndex,
connection,0x4c4f5752u),reachMinimum,reachMaximum);
const auto requestedReach=reachValue(PassageSeed(seed,upper.strateIndex,
lower.strateIndex,connection,0x4c4f5752u),
requestedReachMinimum,requestedReachMaximum);
const auto reach=std::min(requestedReach,lowerReachLimit);
lowerMouth[2]=contentZQ(lower.content.topMicrometres)-reach;
if(requestedReach>lowerReachLimit)
std::printf("[ResolvedPassageReachClamp] id=%s side=lower sampled_m=%.3f usable_max_m=%.3f selected_m=%.3f status=CLAMPED\n",
passage.stableId.c_str(),requestedReach/static_cast<double>(qPerMetre),
lowerReachLimit/static_cast<double>(qPerMetre),
reach/static_cast<double>(qPerMetre));
}
}
if(!radialWithin(upperMouth,placementRadius)||!radialWithin(lowerMouth,placementRadius))
+14 -9
View File
@@ -1045,6 +1045,7 @@ public:
{
const auto& passage=ResolvedLayout->passages[passageIndex];
if(passage.controlPoints.size()<2)continue;
const bool internalChainPassage=passageIndex>0;
const auto supportStratum=[&](std::int32_t strateIndex)
->const VoxelForgeCore::ResolvedLayoutStratumV2*
{
@@ -1490,7 +1491,7 @@ public:
// the nominal height smoothly as a tread approaches its landing.
double floorOffset=bridgeDeck
?PassageBridgeDeckOffsetMetres(passageIndex,static_cast<std::size_t>(index))
:std::lerp(0.15,0.20,lowerMouthBlend);
:std::lerp(internalChainPassage?0.20:0.15,0.20,lowerMouthBlend);
const double horizontalLengthSq=dx*dx+dy*dy;
const bool overlapSupportJoin=index+12<lastIndex
&&!IsPassageShortSpanSegment(passageIndex,static_cast<std::size_t>(index))
@@ -1524,7 +1525,7 @@ public:
+(2.0*v0-5.0*v1+4.0*v2-v3)*t2
+(-v0+3.0*v1-3.0*v2+v3)*t3);
};
constexpr double SmoothSupportHeightWeight=0.25;
const double SmoothSupportHeightWeight=internalChainPassage?0.0:0.25;
centerZ+=(interpolate(p0.positionSubvoxels[2],segmentA.positionSubvoxels[2],
segmentB.positionSubvoxels[2],p3.positionSubvoxels[2])-centerZ)
*SmoothSupportHeightWeight;
@@ -1576,12 +1577,14 @@ public:
// Keep the supported ramp to a comfortable walking width. Extending a
// full bore-radius shelf across overlapping helix coils can block the
// capsule on the neighbouring turn.
const bool lowerMouthBodyOverlap=index>=lowerMouthIndex-2
const bool lowerMouthBodyOverlap=ResolvedLayout->strates.size()>2
&&index>=lowerMouthIndex-2
&&supportQueryDepth<0.98*qPerMetre;
// Keep a narrow walk core, but place its top on the native surface
// so the support remains a worn ramp instead of a route-height slab.
const bool mouthTread=entryMouthShoulder
&&(!floatingIslandPassage||passage.style==0);
const bool mouthTread=lowerMouthBodyOverlap
||(entryMouthShoulder
&&(!floatingIslandPassage||passage.style==0||internalChainPassage));
double distanceFromMouthMetres=std::numeric_limits<double>::infinity();
if(entryMouthShoulder)
{
@@ -1656,7 +1659,8 @@ public:
*(3.0-2.0*supportEdgeT);
const double mouthSupportThicknessVoxels=std::lerp(
0.35*supportThicknessVoxels,supportThicknessVoxels,mouthSupportT);
const double localSupportThicknessVoxels=entryMouthShoulder
const double localSupportThicknessVoxels=(entryMouthShoulder
||lowerMouthBodyOverlap)
?mouthSupportThicknessVoxels*(1.0-0.72*supportEdgeSmooth)
:supportThicknessVoxels;
double mouthSupportBlend=1.0;
@@ -1668,8 +1672,8 @@ public:
*(3.0-2.0*mouthBlendT);
}
const double supportEdgeDepth=mouthTread?0.25:0.35;
const double mouthFloorOffset=mouthTread
?std::lerp(0.15,0.19,lowerMouthBlend):floorOffset;
const double mouthFloorOffset=internalChainPassage?0.20
:mouthTread?std::lerp(0.15,0.19,lowerMouthBlend):floorOffset;
const double baseFloorQ=centerZ-radius+mouthFloorOffset*qPerMetre
-supportEdgeSmooth*supportEdgeDepth*qPerMetre;
const double nativeSurfaceQ=static_cast<double>(qz)
@@ -1678,7 +1682,8 @@ public:
// blends the source field directly instead of extending this SDF top.
const double nativeFieldOffset=std::clamp(nativeSurfaceQ-baseFloorQ,
-0.80*qPerMetre,0.80*qPerMetre);
const double nativeSurfaceBlend=mouthTread?1.0:1.0-mouthReliefT;
const double nativeSurfaceBlend=mouthTread
?internalChainPassage?0.0:1.0:1.0-mouthReliefT;
const double nativeTreadOffset=std::clamp(
nativeFieldOffset*nativeSurfaceBlend+floorReliefOffset
-std::abs(treadRelief)*0.08*qPerMetre