17 changed files with 1084 additions and 89 deletions

No files matched your search

+25 -21
View File
@@ -2265,32 +2265,36 @@ mouth and off the walk route. It stays disabled by default. Active records carry
L43's report records the off/on hashes, walk and interface audits, outside-stamp timing, tier
results, captures and any failed runs.
### 8.54 Opt-in native lattice field — World Assembler M3 R26 slice 1 (Linux L58)
### 8.54 Opt-in native lattice field — World Assembler M3 R26 slices 1–2 (Linux L58–L59)
`Core.Lattice.PrimitiveField` is a version-1 recipe selected only for one Maze or VerticalShafts
`Core.Lattice.PrimitiveField` is an opt-in recipe selected only for one Maze or VerticalShafts
strate by `--recipe=lattice --lattice-strate=N`. The legacy generator assets and their default
dispatch stay unchanged. Planning first binds the actual incoming lower mouth and outgoing upper
mouth from the resolved passage records, then creates arrival/exit overlap corridors, a mandatory
four-turn helix and the maze spine; two deterministic dead ends are added after that route. The
resolved room and edge seeds use `(world seed, strate, recipe version, stable ID)`. An audit control
translates the helix 20 m away from both route junctions to make the shaft network orphaned.
dispatch stay unchanged. Version 2 binds the actual incoming lower mouth and outgoing upper mouth,
then creates arrival/exit overlap corridors, an open vertical shaft and the maze spine; two
deterministic dead ends are added after that route. Resolved room and edge seeds use
`(world seed, strate, recipe version, stable ID)`. The orphan control translates the shaft 20 m
away from both route junctions and must fail reachability.
The prototype helix uses a 6 m centreline radius, 3 m clear width, 5 m pitch, four turns and 2.6 m
finished floor-to-soffit height. Its centreline descends 20 m over roughly 151 m; the inner-edge
grade is about 10.0 degrees. The 2.4 m floor-wall smooth-max gives an isolated ideal fillet radius
of 0.8485 m. A separate 0.4 m feature-union blend prevents adjoining ramps from erasing the tread.
The swept-clear diameter is 15 m; the conservative padded feature envelope is about 20.6 m (the
approved approximately 21 m site envelope).
The version-2 shaft core is a vertical cylinder of 4.5 m radius. Its air continues 8 m above the
top tread and 2 m below the bottom tread. The ramp winds around the core at a 6 m centreline radius,
with 3 m clear width, 5 m pitch and four turns. The open annular shaft air joins the core air, while
one-metre support slabs follow the helix under each tread. This leaves a 4 m vertical gap between
one tread and the underside of the next. The ledge's inner edge is open to the well; the route
centreline stays 1.5 m from the drop and leaves 1.16 m beyond the 0.34 m capsule radius. Its inner
edge grade is about 10.0 degrees. The maze retains 2.6 m room headroom. The shaft's padded outer
design envelope is 21 m. The 1.9 m floor-wall smooth-max gives an isolated ideal fillet radius of
0.6718 m; the separate 0.05 m feature-union blend keeps route junctions connected.
The layout reuses the resolved cavern graph vocabulary. A per-strate opt-in selects the native
negative-solid/positive-air field; canonical feature order is stable-ID order. Room/corridor bounds
are indexed by the graph BVH and polyline segments have a nested deterministic BVH for density and
interval queries. Box classification stays conservative, and `isTileShapeFree` refuses any tile
that intersects the graph. The L58 pipeline audits the composed field from actual mouth to mouth
with a 0.34 m by 1.76 m capsule, per-station support, 2.2 m clearance and a 15 degree grade limit;
it also checks the orphan control, brute-force interval samples and the composed wall-foot fillet.
The Linux58 report contains the measured reachability, surface, peer-determinism, timing and capture
results; the code path is not promoted to legacy Maze/VerticalShafts generation.
negative-solid/positive-air field; canonical feature order is stable-ID order. The ring-shaped shaft
air and its support layers use an analytic helix lookup instead of testing every polyline segment
per density sample. The core cylinder and annular wall have conservative interval bounds; false
all-air and all-solid controls remain rejected, and `isTileShapeFree` refuses occupied tiles. The
L59 pipeline checks the composed field from actual mouth to mouth with a 0.34 m by 1.76 m capsule,
support at every station, 2.2 m clearance and a 15 degree grade limit. It also checks the orphan
control, whole-surface ramp lip/wall-foot/underside, brute-force interval samples and the composed
wall-foot fillet. See the Linux58 and Linux59 reports for evidence. This code path is not promoted
to legacy Maze/VerticalShafts generation.
## 9. Multiplayer model (listen-server first, dedicated-friendly)
+11 -10
View File
@@ -170,8 +170,8 @@ remains `0`, and lateral regions remain gated off.
| `../../VoxelForgeCore/Private/ModuleEntry/` | Unreal module entry and an isolated `CoreMinimal.h` shim for the actual engine header. |
| `../../Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` | Standard-library-only public Core API. `VOXELFORGECORE_API` exports the API from the Unreal module and is empty for standalone builds. |
| `../../Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` / `../../Standalone/Core/src/ResolvedLayoutInternal.h` | `ResolvedLayoutSnapshotV3`: physical layout-chunk width, versioned micrometre intervals, owned ceiling/content/bedrock bands, honored transition settings, deterministic per-column transition bands, recipe anchors, director-planned passages, canonical JSON/FNV identity, compatibility/strict validators, and negative-control audit. Built once from the director-resolved plan and consumed by bounds planning, Core dispatch, composition, and validation. §8.40–8.42, §8.46. |
| `ResolvedLayoutStratePassageCapabilitiesV1::{hasNativeCaveField,hasNativeLatticeField}`, `IsNativeLatticeFieldStratum`, `HasNativeGraphField` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` / `Standalone/Core/src/ResolvedLayoutInternal.h` | Explicit per-strate native graph capability; `Core.Lattice.PrimitiveField` is restricted to Maze/VerticalShafts recipe version 1. Lattice seeds include world seed, strate, recipe version and stable feature ID; explicit polyline records keep their endpoints and receive conservative bounds. §8.54. |
| `FCavernRuntimeFeature::FSegmentNode`, `ApplyResolvedNativeCavesField`, `ClassifyNativeCaveFieldBox` | `Standalone/Core/src/ShapeWorldInternal.h` | A deterministic nested segment BVH accelerates native graph distance and conservative interval evaluation; the outer graph BVH still supplies tile candidates and protects `isTileShapeFree`. The 0.4 m feature-union width is separate from the floor fillet width. §8.54. |
| `NativeLatticeFieldRecipeVersion`, `IsNativeLatticeFieldStratum`, `LayoutLatticeFeatureSeed` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` / `Standalone/Core/src/ResolvedLayoutInternal.h` | Explicit Maze/VerticalShafts opt-in at lattice recipe version 2; stable feature seeds include world seed, strate, recipe version and feature ID. §8.54. |
| `FCavernRuntimeFeature::openShaftRamp`, `ApplyResolvedNativeCavesField`, `ClassifyNativeCaveFieldBox` | `Standalone/Core/src/ShapeWorldInternal.h` | Analytic open shaft ring, helical support lookup, exact cylinder core bounds and conservative interval proofs; the outer graph BVH supplies tile candidates and protects `isTileShapeFree`. §8.54. |
| `../../Standalone/Core/src/FloatingIslandsInternal.h` | Canonical standalone/Core floating-island planner, geometry-versioned field, manifest serializer, influence bounds, capsule-route checks, and thickness audit. |
| `Tools/VoxelForgeTest.ps1` | The single guarded test entry point. `-Scenario canonical|owner|probe|perf|tests|surface-fall|crossing|gate-stress|visual-edit|visual-lod|visual-gap-walk|visual-gap-inject|dig-motion|parity|horizon|horizon-render|determinism|region-eval|step2d|step2e|step2f|step2f-capture|step3-scale|step3-game`, optional `-Build`, `-Assets owner|default`, `-Cvars`, absolute `-Out`, `-Label`, `-HorizonLevel`, `-HorizonRenderDistanceChunks`, `-Step2fProfile=0..7`, `-Step2fCaptureView=inside|wall-closeup`, `-ParityExportSize=32|64|128`, `-ParityExportTile=x,y,z`, `-SharedDDC`, `-SampleDensityStacks`, `-StackSampleIntervalUs`, and `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH`; stages the host/assets, isolates user/DDC/config state, serializes one Unreal launch at a time, enforces the 8 GiB/30-minute guards, waits for 6 GiB free RAM before launches, and emits compact `result.json`/`summary.txt` plus full logs. Parity can render its game leg with `-EnableRender` and compares the selected export region against the exact streamed tile hashes. `visual-gap-walk` records camera-frustum surface-point coverage at 6000 cm/s; `visual-gap-inject` proves an early component hide is detected; `dig-motion` logs per-frame vertical velocity, gate, support readiness, and movement mode. `-Cvars @{ 'voxel.TestGapAuditLegacyHandoff'=1 }` replays the old visibility handoff for A/B audit baselines. Horizon traces report desired/loaded tiles, resident stream geometry, worker seconds, steady wall time, and peak private memory; `horizon-render` captures the owner view; `step2f-capture` selects one of eight parameter sets, finds a positive-density camera point and aims at a sampled rock wall for an inside or wall-closeup view, then saves it under `Saved/Research/step2f/captures` (pass the persistent render DDC with `-SharedDDC`); `determinism` compares per-tile hashes across the default CRT path and `-voxel.CrtFma3=0`; `region-eval` compares the live path with the default-off editor chunk program on the 259³ lattice and five-seed probe set; `step2d` retains the earlier independent field; `step2e` retains its earlier benchmark; `step2f` compares frozen step 2e and the coherent field for all eight profiles on the same 259³ ring, applies geometry gates, and checks sound bounds, seams, and 1-vs-6-worker hashes. `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH` checks a full-ring hash at another partition count. `-SampleDensityStacks` captures profiles, and `-StackSampleIntervalUs` sets the sampling interval.
| Step-3 scale and game validation | `step3-scale` measures the same 519³ and 259³ six-worker lattices at 12.5 cm. The cached medians are 7.347496 s and 1.169567 s respectively; determinism and brick sound-proof audits pass. `step3-game` routes in-game generation through the brick evaluator and records tile timings, spawn fill, moving frames, and profile-switch rebuilds. The visible D3D12 run measured tile generation p50/p95/max 3.326/31.045/169.867 ms, full-detail L0 fill 12.369 s for 2,765 tiles, and moving-frame p50/p95/p99/max 4.856/8.922/13.090/80.575 ms. Switching profiles rebuilt 5,815 loaded tiles. Both high-resolution screenshot requests were logged, but the harness found only one fresh PNG and it is a blank pale viewport; no lit comparison capture is accepted. Raw output: `Saved/TestHarness/step3_game_visible_final`; scale output: `Saved/Research/step3/scale/step3_scale_cacheperf_v1`. |
@@ -1310,18 +1310,19 @@ See ARCHITECTURE §8.53 and
[`Standalone/Research/WorldAssemblerM3/Linux43/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux43/REPORT.md)
for layout identities, owner hashes, outside-box timing, audits and captures.
### 3.36 Native lattice field — World Assembler M3 R26 slice 1 (Linux L58)
### 3.36 Native lattice field — World Assembler M3 R26 slices 1–2 (Linux L58–L59)
| Symbol | Canonical file | Role |
|---|---|---|
| `IsNativeLatticeFieldStratum`, `LayoutLatticeFeatureSeed`, `ResolvedCavernRoomV1::unionWidthMicrometres`, `ResolvedCavernEdgeV1::unionWidthMicrometres` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, `Standalone/Core/src/ResolvedLayoutInternal.h` | Versioned Maze/VerticalShafts opt-in and deterministic seed from `(seed, strate, recipe version, stable ID)`; optional union width preserves prior cave JSON when unset. |
| `MakeNativeLatticeSpine`, `--recipe=lattice`, `--lattice-strate=N` | `Standalone/Source/StreamBenchmarkHeadless.cpp` | Resolves actual adjacent mouths, builds a mandatory four-turn helix and maze spine, then adds two seeded dead ends; `--lattice-orphan-control` moves the helix away from both junctions. |
| `AuditNativeLatticeField` | `Standalone/Source/StreamBenchmarkPipeline.h` | Samples the final field along the mouth-to-mouth capsule route, checking support, headroom, grade, orphan rejection, composed fillet, interval signs and feature-tile exclusion. |
| `BuildLatticeFixtureL58.py`, `CaptureNativeLatticeL58.py`, `AuditLatticeSurfaceL58.py` | `Standalone/Research/WorldAssemblerM3/Linux58/` | Isolated Maze strate fixture, four reviewed captures and the L54 whole-surface triangle audit adapted to explicit native polylines. |
| `NativeLatticeFieldRecipeVersion`, `IsNativeLatticeFieldStratum`, `LayoutLatticeFeatureSeed` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, `Standalone/Core/src/ResolvedLayoutInternal.h` | Version-2 Maze/VerticalShafts opt-in and deterministic seed from `(seed, strate, recipe version, stable ID)`. |
| `MakeNativeLatticeSpine`, `--recipe=lattice`, `--lattice-strate=N` | `Standalone/Source/StreamBenchmarkHeadless.cpp` | Resolves actual adjacent mouths, builds the radius-4.5 m open shaft core, supported four-turn wall ledge and maze spine, then adds two seeded dead ends; the orphan control translates the shaft away from both junctions. |
| `AuditNativeLatticeField` | `Standalone/Source/StreamBenchmarkPipeline.h` | Samples the final field along the mouth-to-mouth capsule route, checking every-station support, headroom, grade, orphan rejection, composed fillet, shaft air/wall intervals and tile exclusion. |
| `BuildLatticeFixtureL59.py`, `CaptureNativeLatticeL59.py`, `AuditLatticeSurfaceL59.py` | `Standalone/Research/WorldAssemblerM3/Linux59/` | Isolated Maze fixture, four JPEG views of the open shaft and maze, and L54 whole-surface audit extended to include the ramp underside. |
See ARCHITECTURE §8.54 and
[`Standalone/Research/WorldAssemblerM3/Linux58/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux58/REPORT.md)
for resolved records, final-field reachability, controls, timing, hashes and captures.
See ARCHITECTURE §8.54 and the
[`Linux59 report`](Standalone/Research/WorldAssemblerM3/Linux59/REPORT.md) for the open shaft's
measured geometry, final-field reachability, controls, timing, hashes and captures. The L58 report
retains the first-slice evidence.
## 4. The density pipeline (most-edited hot path)
@@ -1004,11 +1004,13 @@ namespace VoxelForgeCore
&&stratum.recipeVersion==1;
}
inline constexpr std::uint32_t NativeLatticeFieldRecipeVersion=2;
inline bool IsNativeLatticeFieldStratum(const ResolvedLayoutStratumV2& stratum) noexcept
{
return (stratum.generatorKind=="Maze"||stratum.generatorKind=="VerticalShafts")
&&stratum.recipeId=="Core.Lattice.PrimitiveField"
&&stratum.recipeVersion==1;
&&stratum.recipeVersion==NativeLatticeFieldRecipeVersion;
}
inline bool HasNativeGraphField(const ResolvedLayoutStratumV2& stratum) noexcept
+4 -2
View File
@@ -1901,7 +1901,8 @@ bool ResolveResolvedCavernGraphV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
// The shared JSON value type stores numbers as IEEE-754 doubles. Keep the
// serialized seed in the exact integer range, as the stamp vocabulary does.
room.irregularitySeed=(isNativeLatticeStrate(room.strateIndex)
?LayoutLatticeFeatureSeed(seed,room.strateIndex,1,room.stableId)
?LayoutLatticeFeatureSeed(seed,room.strateIndex,
NativeLatticeFieldRecipeVersion,room.stableId)
:LayoutStampSeed(seed,room.strateIndex,room.stableId))
&0x001fffffffffffffull;
const std::int64_t pad=room.smoothWidthMicrometres
@@ -1918,7 +1919,8 @@ bool ResolveResolvedCavernGraphV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
{
const bool nativeLattice=isNativeLatticeStrate(edge.strateIndex);
edge.irregularitySeed=(nativeLattice
?LayoutLatticeFeatureSeed(seed,edge.strateIndex,1,edge.stableId)
?LayoutLatticeFeatureSeed(seed,edge.strateIndex,
NativeLatticeFieldRecipeVersion,edge.stableId)
:LayoutStampSeed(seed,edge.strateIndex,edge.stableId))
&0x001fffffffffffffull;
using FCurvePoint=std::array<double,3>;
+329 -7
View File
@@ -3332,6 +3332,14 @@ private:
const VoxelForgeCore::ResolvedCavernRoomV1* room=nullptr;
const VoxelForgeCore::ResolvedCavernEdgeV1* edge=nullptr;
bool nativeGraph=false;
bool openShaftRamp=false;
std::array<double,2> openShaftCenterMetres{};
std::array<double,2> openShaftStartDirection{1.0,0.0};
double openShaftCenterlineRadiusMetres=0.0;
double openShaftStartFloorMetres=0.0;
double openShaftPitchPerTurnMetres=0.0;
double openShaftTurnCount=0.0;
double openShaftRotationSign=1.0;
std::array<std::int64_t,3> boundsMinimumMicrometres{},boundsMaximumMicrometres{};
std::array<double,3> centerMetres{},halfExtentsMetres{};
struct FSegment
@@ -3792,6 +3800,15 @@ private:
:found->passageCapabilities.hasNativeLatticeField);
};
const float micronsPerVoxel=static_cast<float>(Owner->CoreVoxelSizeMicrons);
const auto shaftCoreRoom=std::find_if(ResolvedLayout->cavernRooms.begin(),
ResolvedLayout->cavernRooms.end(),[](const auto& room)
{return room.stableId=="lattice/spine/shaft-core-v2";});
std::array<double,2> shaftCoreCenter{};
if(shaftCoreRoom!=ResolvedLayout->cavernRooms.end())
{
shaftCoreCenter={shaftCoreRoom->centerMicrometres[0]/1.0e6,
shaftCoreRoom->centerMicrometres[1]/1.0e6};
}
for(const auto& room:ResolvedLayout->cavernRooms)
{
FCavernRuntimeFeature runtime;runtime.room=&room;
@@ -3822,6 +3839,11 @@ private:
{
FCavernRuntimeFeature runtime;runtime.edge=&edge;
runtime.nativeGraph=isNativeGraphStrate(edge.strateIndex);
runtime.openShaftRamp=runtime.nativeGraph
&&edge.stableId=="lattice/spine/01-helix-ramp-v1"
&&shaftCoreRoom!=ResolvedLayout->cavernRooms.end();
if(runtime.openShaftRamp)
runtime.openShaftCenterMetres=shaftCoreCenter;
runtime.boundsMinimumMicrometres=edge.boundsMinimumMicrometres;
runtime.boundsMaximumMicrometres=edge.boundsMaximumMicrometres;
for(std::size_t point=0;point<4;++point)
@@ -3865,6 +3887,37 @@ private:
std::abs((segment.end[2]-segment.start[2])/horizontal));
runtime.segments.push_back(segment);
}
if(runtime.openShaftRamp&&!runtime.segments.empty())
{
const auto& first=runtime.segments.front().start;
const auto& last=runtime.segments.back().end;
const double startX=first[0]-shaftCoreCenter[0];
const double startY=first[1]-shaftCoreCenter[1];
runtime.openShaftCenterlineRadiusMetres=std::hypot(startX,startY);
if(runtime.openShaftCenterlineRadiusMetres>1.0e-9)
runtime.openShaftStartDirection={
startX/runtime.openShaftCenterlineRadiusMetres,
startY/runtime.openShaftCenterlineRadiusMetres};
runtime.openShaftStartFloorMetres=first[2];
double totalAngle=0.0;
for(std::size_t segment=0;segment<runtime.segments.size();++segment)
{
const auto& previous=runtime.segments[segment].start;
const auto& current=runtime.segments[segment].end;
const double previousX=previous[0]-shaftCoreCenter[0];
const double previousY=previous[1]-shaftCoreCenter[1];
const double currentX=current[0]-shaftCoreCenter[0];
const double currentY=current[1]-shaftCoreCenter[1];
totalAngle+=std::atan2(previousX*currentY-previousY*currentX,
previousX*currentX+previousY*currentY);
}
constexpr double TwoPi=6.283185307179586476925286766559;
runtime.openShaftTurnCount=std::max(1.0,
std::round(std::abs(totalAngle)/TwoPi));
runtime.openShaftRotationSign=totalAngle<0.0?-1.0:1.0;
runtime.openShaftPitchPerTurnMetres=(first[2]-last[2])
/runtime.openShaftTurnCount;
}
runtime.segmentOrder.resize(runtime.segments.size());
for(std::size_t index=0;index<runtime.segmentOrder.size();++index)
runtime.segmentOrder[index]=static_cast<std::uint32_t>(index);
@@ -5245,8 +5298,49 @@ public:
const std::int32_t featureStrate=feature.room?feature.room->strateIndex
:feature.edge?feature.edge->strateIndex:-1;
if(featureStrate!=strateIndex)continue;
bool featureOverlapsBox=true,boxWithinFeatureBounds=true;
for(std::size_t axis=0;axis<3;++axis)
{
const double featureMinimum=feature.boundsMinimumMicrometres[axis]/1.0e6;
const double featureMaximum=feature.boundsMaximumMicrometres[axis]/1.0e6;
if(hi[axis]<featureMinimum||lo[axis]>featureMaximum)
{featureOverlapsBox=false;break;}
boxWithinFeatureBounds=boxWithinFeatureBounds
&&lo[axis]>=featureMinimum&&hi[axis]<=featureMaximum;
}
if(!featureOverlapsBox)continue;
// The point field omits a record outside its resolved bounds. A partial
// overlap cannot reuse the record's unbounded SDF for an all-air proof.
if(!boxWithinFeatureBounds)return {0.0,0.0,false};
FMetricInterval featureVoid;
bool openHelixSupportCouldApply=true;
double openHelixSupportLowerBound=std::numeric_limits<double>::infinity();
if(feature.room)
{
if(nativeLattice
&&feature.room->stableId=="lattice/spine/shaft-core-v2")
{
const double radius=feature.halfExtentsMetres[0];
if(!(radius>0.0))return {0.0,0.0,false};
double radialMinimumSquared=0.0,radialMaximumSquared=0.0;
for(std::size_t axis=0;axis<2;++axis)
{
const double center=feature.centerMetres[axis];
const double deltaMinimum=center<lo[axis]?lo[axis]-center
:center>hi[axis]?center-hi[axis]:0.0;
const double deltaMaximum=std::max(std::abs(lo[axis]-center),
std::abs(hi[axis]-center));
radialMinimumSquared+=deltaMinimum*deltaMinimum;
radialMaximumSquared+=deltaMaximum*deltaMaximum;
}
const double radialMinimum=std::sqrt(radialMinimumSquared)-radius;
const double radialMaximum=std::sqrt(radialMaximumSquared)-radius;
const double floorZ=feature.room->floorMicrometres/1000000.0;
const FMetricInterval bottom={floorZ-hi[2],floorZ-lo[2],true};
featureVoid={std::max(radialMinimum,bottom.minimum),
std::max(radialMaximum,bottom.maximum),true};
}
else
{
double normalizedMinimumSquared=0.0,normalizedMaximumSquared=0.0;
double meanRadius=0.0;
@@ -5272,13 +5366,134 @@ public:
featureVoid={SmoothMaxMetres(ellipsoid.minimum,floor.minimum,width),
SmoothMaxMetres(ellipsoid.maximum,floor.maximum,width),true};
}
}
else if(feature.edge&&!feature.segments.empty())
{
const bool openHelixRamp=nativeLattice&&feature.openShaftRamp;
const double radius=feature.edge->boreRadiusMicrometres/1000000.0;
const double height=feature.edge->boreHeightMicrometres/1000000.0;
if(!(radius>0.0&&height>0.0))return {0.0,0.0,false};
double tubeMinimum=std::numeric_limits<double>::infinity();
double tubeMaximum=std::numeric_limits<double>::infinity();
if(openHelixRamp)
{
double radialMinimumSquared=0.0,radialMaximumSquared=0.0;
for(std::size_t axis=0;axis<2;++axis)
{
const double center=feature.openShaftCenterMetres[axis];
const double deltaMinimum=center<lo[axis]?lo[axis]-center
:center>hi[axis]?center-hi[axis]:0.0;
const double deltaMaximum=std::max(std::abs(lo[axis]-center),
std::abs(hi[axis]-center));
radialMinimumSquared+=deltaMinimum*deltaMinimum;
radialMaximumSquared+=deltaMaximum*deltaMaximum;
}
const double radialMinimum=std::sqrt(radialMinimumSquared);
const double radialMaximum=std::sqrt(radialMaximumSquared);
const double centerline=feature.openShaftCenterlineRadiusMetres;
const double nearestRingDistance=centerline<radialMinimum
?radialMinimum-centerline:centerline>radialMaximum
?centerline-radialMaximum:0.0;
tubeMinimum=nearestRingDistance-radius;
tubeMaximum=std::max(std::abs(radialMinimum-centerline),
std::abs(radialMaximum-centerline))-radius;
openHelixSupportCouldApply=tubeMinimum<0.0;
const double startFloor=feature.openShaftStartFloorMetres;
const double pitch=feature.openShaftPitchPerTurnMetres;
const double turnCount=feature.openShaftTurnCount;
if(!std::isfinite(tubeMinimum)||!std::isfinite(tubeMaximum)
||!std::isfinite(startFloor)||!(pitch>0.0)
||!(turnCount>=1.0))return {0.0,0.0,false};
const FMetricInterval tube={tubeMinimum,tubeMaximum,true};
const double grade=pitch/(6.283185307179586476925286766559
*feature.openShaftCenterlineRadiusMetres);
const double verticalScale=1.0/std::sqrt(1.0+grade*grade);
double phaseMinimum=0.0,phaseMaximum=1.0;
const double boxCenterX=(lo[0]+hi[0])*0.5;
const double boxCenterY=(lo[1]+hi[1])*0.5;
const double centerDx=boxCenterX-feature.openShaftCenterMetres[0];
const double centerDy=boxCenterY-feature.openShaftCenterMetres[1];
const double centerDistance=std::hypot(centerDx,centerDy);
const double halfDiagonal=0.5*std::hypot(hi[0]-lo[0],hi[1]-lo[1]);
if(centerDistance>halfDiagonal)
{
const double angle=std::atan2(feature.openShaftRotationSign
*(feature.openShaftStartDirection[0]*centerDy
-feature.openShaftStartDirection[1]*centerDx),
feature.openShaftStartDirection[0]*centerDx
+feature.openShaftStartDirection[1]*centerDy);
constexpr double TwoPi=6.283185307179586476925286766559;
double centerPhase=angle/TwoPi;
const double angleRadius=std::asin(std::clamp(
halfDiagonal/centerDistance,0.0,1.0));
const double phaseRadius=angleRadius/TwoPi;
// Point evaluation normalizes phase into [0,1). If this box
// crosses the start ray, retain the full phase range; otherwise
// unwrap its center into the same range as the point field.
if(std::abs(angle)>angleRadius)
{
if(centerPhase<0.0)centerPhase+=1.0;
phaseMinimum=centerPhase-phaseRadius;
phaseMaximum=centerPhase+phaseRadius;
}
}
double verticalMinimum=std::numeric_limits<double>::infinity();
double verticalMaximum=-std::numeric_limits<double>::infinity();
const double coordinateMinimum=(startFloor-hi[2])/pitch-phaseMaximum;
const double coordinateMaximum=(startFloor-lo[2])/pitch-phaseMinimum;
if(!std::isfinite(coordinateMinimum)||!std::isfinite(coordinateMaximum))
return {0.0,0.0,false};
const int lastTurn=std::max(0,static_cast<int>(turnCount)-1);
const int firstPossibleTurn=std::clamp(
static_cast<int>(std::floor(coordinateMinimum)),-1,lastTurn+1);
const int lastPossibleTurn=std::clamp(
static_cast<int>(std::floor(coordinateMaximum)),-1,lastTurn+1);
const auto corridorInterval=[&](int turn)
{
const double floorMinimum=startFloor-pitch*(turn+phaseMaximum);
const double floorMaximum=startFloor-pitch*(turn+phaseMinimum);
const double floorToQueryMinimum=(floorMinimum-hi[2])*verticalScale;
const double floorToQueryMaximum=(floorMaximum-lo[2])*verticalScale;
const double queryToCeilingMinimum=(lo[2]-floorMaximum-height)
*verticalScale;
const double queryToCeilingMaximum=(hi[2]-floorMinimum-height)
*verticalScale;
const double turnMinimum=std::max(floorToQueryMinimum,
queryToCeilingMinimum);
const double turnMaximum=std::max(floorToQueryMaximum,
queryToCeilingMaximum);
return FMetricInterval{turnMinimum,turnMaximum,true};
};
for(int turn=firstPossibleTurn;turn<=lastPossibleTurn;++turn)
{
const int turnA=std::clamp(turn,0,lastTurn);
const int turnB=std::clamp(turn+1,0,lastTurn);
const FMetricInterval corridorA=corridorInterval(turnA);
const FMetricInterval corridorB=corridorInterval(turnB);
verticalMinimum=std::min(verticalMinimum,
std::min(corridorA.minimum,corridorB.minimum));
verticalMaximum=std::max(verticalMaximum,
std::min(corridorA.maximum,corridorB.maximum));
const double supportDepth=feature.edge->floorSupportDepthMicrometres
/1000000.0;
const double progressMinimum=turn+phaseMinimum;
const double progressMaximum=turn+phaseMaximum;
const double floorMinimum=startFloor-pitch*progressMaximum;
const double floorMaximum=startFloor-pitch*progressMinimum;
const double supportFloorMinimum=(floorMinimum-hi[2])*verticalScale;
const double supportUndersideMinimum=(lo[2]-floorMaximum+supportDepth)
*verticalScale;
openHelixSupportLowerBound=std::min(openHelixSupportLowerBound,
std::max({tubeMinimum,supportFloorMinimum,
supportUndersideMinimum}));
}
const FMetricInterval vertical={verticalMinimum,verticalMaximum,true};
const double width=feature.edge->smoothWidthMicrometres/1000000.0;
featureVoid={SmoothMaxMetres(tube.minimum,vertical.minimum,width),
SmoothMaxMetres(tube.maximum,vertical.maximum,width),true};
}
else
{
const std::array<double,3> inverseScale={1.0/radius,1.0/radius,
1.0/height};
const std::array<double,3> boxMinimum={lo[0]*inverseScale[0],
@@ -5388,6 +5603,7 @@ public:
featureVoid={SmoothMaxMetres(tube.minimum,floor.minimum,width),
SmoothMaxMetres(tube.maximum,floor.maximum,width),true};
}
}
else return {0.0,0.0,false};
if(nativeLattice)
{
@@ -5401,10 +5617,17 @@ public:
&&lo[0]<=feature.boundsMaximumMicrometres[0]/1.0e6
&&hi[1]>=feature.boundsMinimumMicrometres[1]/1.0e6
&&lo[1]<=feature.boundsMaximumMicrometres[1]/1.0e6;
if(supportDepth>0.0&&overlapsXY
const bool supportCouldApply=overlapsXY
&&(!feature.openShaftRamp||openHelixSupportCouldApply);
if(supportDepth>0.0&&supportCouldApply
&&hi[2]>=floorMinimum-supportDepth&&lo[2]<=floorMaximum)
{
double supportLower=std::max(-supportDepth,lo[2]-floorMaximum);
if(feature.openShaftRamp)
supportLower=openHelixSupportLowerBound;
latticeFloorSupportLowerBound=std::min(latticeFloorSupportLowerBound,
std::max(-supportDepth,lo[2]-floorMaximum));
supportLower);
}
}
if(!std::isfinite(featureVoid.minimum)||!std::isfinite(featureVoid.maximum))
return {0.0,0.0,false};
@@ -6962,6 +7185,10 @@ private:
return;
}
if(!feature.edge)return;
// The open helix is already carved with its exact cylindrical/turn
// field above. Its four serialized control points are a compact record
// envelope, not a walkable Bezier centerline for this legacy cap.
if(feature.openShaftRamp)return;
const auto bezier=[&](float t,std::size_t axis)
{
const float one=1.0f-t;
@@ -7098,14 +7325,34 @@ private:
const std::int32_t strateIndex=feature.room?feature.room->strateIndex
:feature.edge?feature.edge->strateIndex:-1;
if(strateIndex!=bound.StrateIndex)continue;
bool insideFeatureBounds=true;
for(std::size_t axis=0;axis<3;++axis)
insideFeatureBounds=insideFeatureBounds
&&point[axis]*1000000.0>=feature.boundsMinimumMicrometres[axis]
&&point[axis]*1000000.0<=feature.boundsMaximumMicrometres[axis];
if(!insideFeatureBounds)continue;
double featureVoid=std::numeric_limits<double>::infinity();
if(feature.room)
{
if(nativeLattice
&&feature.room->stableId=="lattice/spine/shaft-core-v2")
{
const double radius=feature.halfExtentsMetres[0];
if(!(radius>0.0))continue;
const double radial=std::hypot(
point[0]-feature.centerMetres[0],
point[1]-feature.centerMetres[1])-radius;
const double bottom=feature.room->floorMicrometres/1000000.0-point[2];
featureVoid=std::max(radial,bottom);
}
else
{
double normalizedSquared=0.0,meanRadius=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double radius=feature.halfExtentsMetres[axis];
if(!(radius>0.0)){normalizedSquared=std::numeric_limits<double>::infinity();break;}
if(!(radius>0.0))
{normalizedSquared=std::numeric_limits<double>::infinity();break;}
const double delta=(point[axis]-feature.centerMetres[axis])/radius;
normalizedSquared+=delta*delta;meanRadius+=radius/3.0;
}
@@ -7114,14 +7361,63 @@ private:
const double width=feature.room->smoothWidthMicrometres/1000000.0;
featureVoid=SmoothMaxMetres(ellipsoid,floor,width);
}
}
else if(feature.edge&&!feature.segments.empty())
{
const bool openHelixRamp=nativeLattice&&feature.openShaftRamp;
double tube=std::numeric_limits<double>::infinity();
double nearestFloor=0.0,nearestGrade=0.0,nearestRadial=0.0;
double openHelixVerticalSdf=std::numeric_limits<double>::infinity();
double openHelixPhase=0.0;
int openHelixTurnA=0,openHelixTurnB=0;
double openHelixVerticalScale=1.0;
const double radius=feature.edge->boreRadiusMicrometres/1000000.0;
const double height=feature.edge->boreHeightMicrometres/1000000.0;
if(!(radius>0.0&&height>0.0))continue;
const double minScale=std::min(radius,height);
if(openHelixRamp)
{
const double dx=point[0]-feature.openShaftCenterMetres[0];
const double dy=point[1]-feature.openShaftCenterMetres[1];
const double shaftRadial=std::hypot(dx,dy);
nearestRadial=std::abs(shaftRadial
-feature.openShaftCenterlineRadiusMetres);
tube=nearestRadial-radius;
const double phase=std::atan2(feature.openShaftRotationSign
*(feature.openShaftStartDirection[0]*dy
-feature.openShaftStartDirection[1]*dx),
feature.openShaftStartDirection[0]*dx
+feature.openShaftStartDirection[1]*dy);
constexpr double TwoPi=6.283185307179586476925286766559;
openHelixPhase=(phase<0.0?phase+TwoPi:phase)/TwoPi;
const double pitch=feature.openShaftPitchPerTurnMetres;
if(!(pitch>0.0)||!(feature.openShaftTurnCount>=1.0))continue;
const double grade=pitch/(TwoPi
*feature.openShaftCenterlineRadiusMetres);
openHelixVerticalScale=1.0/std::sqrt(1.0+grade*grade);
const double turnCoordinate=(feature.openShaftStartFloorMetres-point[2])
/pitch-openHelixPhase;
const int turnFloor=static_cast<int>(std::floor(turnCoordinate));
const int lastTurn=std::max(0,
static_cast<int>(feature.openShaftTurnCount)-1);
openHelixTurnA=std::clamp(turnFloor,0,lastTurn);
openHelixTurnB=std::clamp(turnFloor+1,0,lastTurn);
const auto floorForTurn=[&](int turn)
{
return feature.openShaftStartFloorMetres
-pitch*(turn+openHelixPhase);
};
const auto corridorSdf=[&](int turn)
{
const double floorZ=floorForTurn(turn);
return std::max((floorZ-point[2])*openHelixVerticalScale,
(point[2]-(floorZ+height))*openHelixVerticalScale);
};
openHelixVerticalSdf=std::min(corridorSdf(openHelixTurnA),
corridorSdf(openHelixTurnB));
}
else
{
std::uint32_t nearestSegment=std::numeric_limits<std::uint32_t>::max();
const auto evaluateSegment=[&](std::uint32_t segmentIndex)
{
@@ -7146,7 +7442,7 @@ private:
}
const double normalized=std::sqrt(radialSquared/(radius*radius)
+vertical*vertical/(height*height));
const double distance=(normalized-1.0)*std::min(radius,height);
const double distance=(normalized-1.0)*minScale;
if(distance<tube||(distance==tube&&segmentIndex<nearestSegment))
{
tube=distance;nearestSegment=segmentIndex;
@@ -7197,16 +7493,42 @@ private:
}
else for(std::uint32_t segment=0;segment<feature.segments.size();++segment)
evaluateSegment(segment);
}
const double supportDepth=feature.edge->floorSupportDepthMicrometres/1000000.0;
if(nativeLattice&&supportDepth>0.0&&nearestRadial<radius-0.12
&&point[2]<nearestFloor&&nearestFloor-point[2]<=supportDepth)
if(nativeLattice&&supportDepth>0.0)
{
if(openHelixRamp)
{
const auto supportSdf=[&](int turn)
{
const double floorZ=feature.openShaftStartFloorMetres
-feature.openShaftPitchPerTurnMetres
*(turn+openHelixPhase);
const double vertical=std::max(
(floorZ-point[2])*openHelixVerticalScale,
(point[2]-(floorZ-supportDepth))
*openHelixVerticalScale);
return std::max(nearestRadial-radius,vertical);
};
latticeFloorSupportMinimum=std::min(latticeFloorSupportMinimum,
std::min(supportSdf(openHelixTurnA),
supportSdf(openHelixTurnB)));
}
else if(nearestRadial<radius-0.12&&point[2]<nearestFloor
&&nearestFloor-point[2]<=supportDepth)
latticeFloorSupportMinimum=std::min(latticeFloorSupportMinimum,
(point[2]-nearestFloor)/std::sqrt(1.0+nearestGrade*nearestGrade));
}
const double width=feature.edge->smoothWidthMicrometres/1000000.0;
if(openHelixRamp)
featureVoid=SmoothMaxMetres(tube,openHelixVerticalSdf,width);
else
{
const double floor=(nearestFloor-point[2])
/std::sqrt(1.0+nearestGrade*nearestGrade);
const double width=feature.edge->smoothWidthMicrometres/1000000.0;
featureVoid=SmoothMaxMetres(tube,floor,width);
}
}
if(!std::isfinite(featureVoid))continue;
if(!std::isfinite(caveVoid))caveVoid=featureVoid;
else caveVoid=SmoothMinMetres(caveVoid,featureVoid,
@@ -0,0 +1,259 @@
#!/usr/bin/env python3
"""Run L54's triangle audit over L59's open-shaft lattice and controls."""
from __future__ import annotations
import argparse
import importlib.util
import json
import math
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
AUDIT54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54/AuditWholeSurfaceL54.py"
spec = importlib.util.spec_from_file_location("whole_surface_l54", AUDIT54)
audit54 = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(audit54)
original_make_route = audit54.make_route
def build_segment_bvh(segments: list[tuple]) -> dict:
def build(indices: list[int]) -> dict:
minimum = tuple(min(min(segments[index][0][axis], segments[index][1][axis])
for index in indices) for axis in range(3))
maximum = tuple(max(max(segments[index][0][axis], segments[index][1][axis])
for index in indices) for axis in range(3))
if len(indices) <= 8:
return {"minimum": minimum, "maximum": maximum,
"segments": tuple(sorted(indices)), "left": None, "right": None}
axis = max(range(3), key=lambda value: maximum[value] - minimum[value])
indices.sort(key=lambda index: (segments[index][0][axis]
+ segments[index][1][axis]) * 0.5)
middle = len(indices) // 2
return {"minimum": minimum, "maximum": maximum, "segments": None,
"left": build(indices[:middle]), "right": build(indices[middle:])}
if not segments:
raise ValueError("lattice audit route has no measurable segments")
return build(list(range(len(segments))))
def make_lattice_route(layout: dict, phase_m: float = 0.0) -> dict:
edges = sorted((edge for edge in layout.get("cavern_edges", [])
if edge["stable_id"] in ("lattice/spine/00-arrival-portal-v1",
"lattice/spine/01-helix-ramp-v1", "lattice/spine/99-departure-portal-v1")
or edge["stable_id"].startswith("lattice/spine/maze-edge-")),
key=lambda edge: (0 if edge["stable_id"].startswith("lattice/spine/00-") else
1 if edge["stable_id"].startswith("lattice/spine/01-") else
2 if edge["stable_id"].startswith("lattice/spine/maze-edge-") else 3,
edge["stable_id"]))
if not edges:
raise ValueError("lattice audit needs its resolved mandatory spine edges")
segments = []
routes = []
for edge_index, edge in enumerate(edges):
points = [[value / 1_000_000.0 for value in row]
for row in edge.get("polyline_um", [])]
if len(points) < 2:
raise ValueError(f"{edge['stable_id']}: explicit path is missing")
radius = edge["bore_radius_um"] / 1_000_000.0
height = edge["bore_height_um"] / 1_000_000.0
support_depth = edge.get("floor_support_depth_um", 0) / 1_000_000.0
horizontal_s = [0.0]
for a, b in zip(points, points[1:]):
horizontal_s.append(horizontal_s[-1] + ((b[0] - a[0]) ** 2
+ (b[1] - a[1]) ** 2) ** 0.5)
first = points[1]
first_dx, first_dy = first[0] - points[0][0], first[1] - points[0][1]
first_length = max(1.0e-9, (first_dx * first_dx + first_dy * first_dy) ** 0.5)
extension = (points[0][0] - first_dx / first_length * audit54.OPEN_GROUND_EXTENSION_M,
points[0][1] - first_dy / first_length * audit54.OPEN_GROUND_EXTENSION_M,
points[0][2] - (first[2] - points[0][2]) / first_length
* audit54.OPEN_GROUND_EXTENSION_M)
route_points = [extension, *points]
route_s = [-audit54.OPEN_GROUND_EXTENSION_M, *horizontal_s]
for index, (a, b) in enumerate(zip(route_points, route_points[1:])):
segments.append((a, b, route_s[index], route_s[index + 1],
radius, height, edge_index))
routes.append({"edge": edge, "points": points, "radius": radius,
"height": height, "support_depth": support_depth,
"length": horizontal_s[-1], "index": edge_index})
# The shaft core is an open cylindrical volume, not a walkable room. Its
# axis-aligned bounds include unrelated rock outside the cylinder and
# above the ramp headroom; the helix corridor already includes the inner
# wall, lip, foot, and underside where those surfaces meet the route.
rooms = [{"room": room,
"center": tuple(value / 1_000_000.0 for value in room["center_um"]),
"half": tuple(value / 1_000_000.0 for value in room["half_extents_um"]),
"floor": room["floor_um"] / 1_000_000.0}
for room in sorted(layout.get("cavern_rooms", []), key=lambda row: row["stable_id"])
if room.get("stable_id") != "lattice/spine/shaft-core-v2"]
return {"segments": segments, "edges": routes, "rooms": rooms, "phase_m": phase_m,
"segment_bvh": build_segment_bvh(segments)}
def make_route(layout: dict, phase_m: float = 0.0) -> dict:
if any(edge.get("stable_id", "").startswith("lattice/")
for edge in layout.get("cavern_edges", [])):
return make_lattice_route(layout, phase_m)
return original_make_route(layout, phase_m)
def lattice_route_nearest(point: tuple[float, float, float], route: dict):
"""Resolve stacked helix turns in 3D, then measure corridor radius in XY."""
best = None
def consider(segment_index: int) -> None:
nonlocal best
a, b, s0, s1, radius, height, edge_index = route["segments"][segment_index]
dx, dy, dz = (b[axis] - a[axis] for axis in range(3))
length_squared = dx * dx + dy * dy + dz * dz
t = 0.0 if length_squared <= 1.0e-12 else max(0.0, min(1.0,
((point[0] - a[0]) * dx + (point[1] - a[1]) * dy
+ (point[2] - a[2]) * dz) / length_squared))
x, y, z = (a[axis] + (b[axis] - a[axis]) * t for axis in range(3))
distance3d_squared = ((point[0] - x) ** 2 + (point[1] - y) ** 2
+ (point[2] - z) ** 2)
if (best is None or distance3d_squared < best[0]
or (distance3d_squared == best[0] and segment_index < best[1])):
horizontal_length = math.hypot(dx, dy)
lateral = ((dx * (point[1] - y) - dy * (point[0] - x))
/ horizontal_length if horizontal_length > 1.0e-9 else 0.0)
best = (distance3d_squared, segment_index,
math.hypot(point[0] - x, point[1] - y),
s0 + (s1 - s0) * t, z, lateral, radius, height, edge_index,
route["edges"][edge_index]["length"])
def lower_bound_squared(node: dict) -> float:
distance_squared = 0.0
for axis in range(3):
gap = (node["minimum"][axis] - point[axis]
if point[axis] < node["minimum"][axis]
else point[axis] - node["maximum"][axis]
if point[axis] > node["maximum"][axis] else 0.0)
distance_squared += gap * gap
return distance_squared
def visit(node: dict) -> None:
if best is not None and lower_bound_squared(node) > best[0]:
return
if node["segments"] is not None:
for segment_index in node["segments"]:
consider(segment_index)
return
left, right = node["left"], node["right"]
left_bound, right_bound = lower_bound_squared(left), lower_bound_squared(right)
if left_bound <= right_bound:
visit(left)
visit(right)
else:
visit(right)
visit(left)
visit(route["segment_bvh"])
if best is None:
raise ValueError("lattice audit route has no measurable segments")
return best[2:]
def mark_lattice_region(triangles: list, route: dict) -> None:
margin = audit54.CORRIDOR_MARGIN_M
extension = audit54.OPEN_GROUND_EXTENSION_M
bounds = []
for edge in route["edges"]:
points = edge["points"]
radius, height = edge["radius"], edge["height"]
support_depth = edge["support_depth"]
bounds.append((
min(point[0] for point in points) - radius - margin,
max(point[0] for point in points) + radius + margin,
min(point[1] for point in points) - radius - margin,
max(point[1] for point in points) + radius + margin,
min(point[2] for point in points) - support_depth - margin,
max(point[2] for point in points) + height + margin))
for room in route["rooms"]:
center, half, floor = room["center"], room["half"], room["floor"]
bounds.append((center[0] - half[0] - margin, center[0] + half[0] + margin,
center[1] - half[1] - margin, center[1] + half[1] + margin,
floor - margin, floor + 2.0 * half[2] + margin))
for triangle in triangles:
x, y, z = triangle.center
if not any(low_x <= x <= high_x and low_y <= y <= high_y
and low_z <= z <= high_z
for low_x, high_x, low_y, high_y, low_z, high_z in bounds):
triangle.in_region = False
triangle.reference = False
continue
nearest = lattice_route_nearest(triangle.center, route)
distance, distance_s, floor_z, lateral, radius, height, edge_index, edge_length = nearest
support_depth = route["edges"][edge_index]["support_depth"]
corridor = (-extension <= distance_s <= edge_length
and distance <= radius + margin
and floor_z - support_depth - margin <= z <= floor_z + height + margin)
room_box = any(abs(x - room["center"][0]) <= room["half"][0] + margin
and abs(y - room["center"][1]) <= room["half"][1] + margin
and room["floor"] - margin <= z
<= room["floor"] + 2.0 * room["half"][2] + margin
for room in route["rooms"])
triangle.in_region = corridor or room_box
inside_room = any(abs(x - room["center"][0]) <= room["half"][0] + 0.45
and abs(y - room["center"][1]) <= room["half"][1] + 0.45
for room in route["rooms"])
outside_bore = distance > radius + 0.45 and not inside_room
triangle.reference = (triangle.in_region and outside_bore
and triangle.smooth[2] >= 0.45)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--case", nargs=5, action="append", required=True,
metavar=("LABEL", "MESH", "LAYOUT_OR_DASH", "EXPECT", "FOCUS"))
parser.add_argument("--json", type=Path, required=True)
parser.add_argument("--svg-dir", type=Path)
parser.add_argument("--phase", type=float, choices=(-0.5, 0.0, 0.5), default=0.0)
args = parser.parse_args()
audit54.make_route = make_route
results = []
for label, mesh, layout, expect, focus in args.case:
if expect not in ("pass", "fail", "measure") or focus not in ("whole", "floor"):
parser.error("EXPECT must be pass/fail/measure and FOCUS must be whole/floor")
native_lattice = layout != "-" and any(
edge.get("stable_id", "").startswith("lattice/")
for edge in json.loads(Path(layout).read_text(encoding="utf-8")).get(
"cavern_edges", []))
original_margin = audit54.CORRIDOR_MARGIN_M
original_extension = audit54.OPEN_GROUND_EXTENSION_M
original_nearest = audit54.route_nearest
original_mark_region = audit54.mark_region
if native_lattice:
# Keep the whole-surface test on native records: one core voxel of
# tolerance captures their meshed walls while excluding the separate
# legacy transition above the resolved mouth.
audit54.CORRIDOR_MARGIN_M = 0.25
audit54.OPEN_GROUND_EXTENSION_M = 0.0
audit54.route_nearest = lattice_route_nearest
audit54.mark_region = mark_lattice_region
try:
results.append(audit54.audit_case(label, Path(mesh), Path(layout), expect,
focus, args.svg_dir, args.phase))
finally:
audit54.CORRIDOR_MARGIN_M = original_margin
audit54.OPEN_GROUND_EXTENSION_M = original_extension
audit54.route_nearest = original_nearest
audit54.mark_region = original_mark_region
if native_lattice:
print("[L59LatticeAuditScope] margin_m=0.250 ramp_underside_depth_m=1.000 "
"outside_mouth_extension_m=0.000 nearest_centerline=3D "
"radius_measure=horizontal status=PASS")
args.json.parent.mkdir(parents=True, exist_ok=True)
args.json.write_text(json.dumps({"audit": "whole-surface-open-shaft-l59-v1",
"cases": results}, indent=2) + "\n", encoding="utf-8")
failures = [result for result in results if result["status"] != "PASS"]
print(f"[L59WholeSurfaceAuditSummary] cases={len(results)} failed={len(failures)} "
f"json={args.json} status={'FAIL' if failures else 'PASS'}")
return 1 if failures else 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""Split the owner surface strate around the L59 native lattice fixture."""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--owner", type=Path, required=True)
parser.add_argument("--out", type=Path, required=True)
args = parser.parse_args()
root = json.loads(args.owner.read_text(encoding="utf-8"))
strates = root.get("strates")
if not isinstance(strates, list):
raise ValueError("owner input has no strates array")
by_index = {int(row.get("index", -1)): row for row in strates if isinstance(row, dict)}
if set(by_index) != {0, 1} or len(strates) != 2:
raise ValueError("fixture requires the reviewed two-strate owner input")
upper, surface = by_index[0], by_index[1]
if (int(upper.get("asset", {}).get("GeneratorType", -1)) != 0
or int(surface.get("asset", {}).get("GeneratorType", -1)) != 4):
raise ValueError("fixture requires TunnelNetwork over SurfaceWorld")
if int(upper.get("passage_config", {}).get("Connections", -1)) != 1:
raise ValueError("owner arrival passage count differs from the reviewed input")
# Keep both resolved mouths in the small synthetic Maze layer. The authored
# owner reach ranges are intentionally broad and can place a synthetic mouth
# hundreds of metres beyond a four-chunk prototype layer.
upper["passage_config"].update({"ReachMin": 32, "ReachMax": 32})
upper["asset"]["PassageConfig"].update({"ReachMin": 32, "ReachMax": 32})
maze = json.loads(json.dumps(surface))
maze.update({"index": 1, "top_chunk_z": -16, "bottom_chunk_z": -19,
"height_chunks": 4})
maze["asset"].update({"StrateName": "L59 Native Lattice Maze",
"GeneratorType": 3, "StrateHeightInChunks": 4})
maze["asset"].setdefault("MazeParams", {})["BoundarySealThickness"] = 8
maze["passage_config"]["Connections"] = 1
maze["passage_config"].update({"ReachMin": 32, "ReachMax": 32})
maze["asset"]["PassageConfig"].update({"Connections": 1, "ReachMin": 32, "ReachMax": 32})
lower = json.loads(json.dumps(surface))
lower.update({"index": 2, "top_chunk_z": -20, "bottom_chunk_z": -23,
"height_chunks": 4})
lower["asset"].update({"StrateName": "L59 Lower Surface", "GeneratorType": 4,
"StrateHeightInChunks": 4})
lower["passage_config"]["Connections"] = 1
lower["asset"]["PassageConfig"]["Connections"] = 1
root["total_strates"] = 3
root["strates"] = [upper, maze, lower]
# Keep the legacy passage portals proportional to this compact native
# prototype; the owner world remains at its authored scale.
root.update({"owner_voxel_size_cm": 6.25,
"owner_voxel_size_microns": 62500,
"core_voxel_size_cm": 25,
"core_voxel_size_microns": 250000,
"owner_to_core_length_scale": 0.25})
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(json.dumps(root, indent=2, sort_keys=True) + "\n",
encoding="utf-8")
print(f"[LatticeFixtureBuild] source={args.owner} source_sha256={sha256(args.owner)} "
f"fixture={args.out} fixture_sha256={sha256(args.out)} "
"strates=0:TunnelNetwork,1:Maze[4 chunks],2:SurfaceWorld[60 chunks] "
"owner_input_untouched=true status=PASS")
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,179 @@
#!/usr/bin/env python3
"""Export the L59 open-shaft lattice and render four reviewed viewpoints."""
from __future__ import annotations
import argparse
import hashlib
import importlib.util
import json
import math
import os
from pathlib import Path
import subprocess
import sys
ROOT = Path(__file__).resolve().parents[4]
CAPTURE54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54/CaptureNativeCavesL54.py"
spec = importlib.util.spec_from_file_location("capture_native_caves_l54", CAPTURE54)
capture54 = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(capture54)
run_step = capture54.run_step
camera_angles = capture54.camera_angles
filter_mesh_y_leq = capture54.filter_mesh_y_leq
fmt = capture54.fmt
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def midpoint(points: list[list[float]]) -> tuple[float, float, float]:
return tuple(sum(point[axis] for point in points) / len(points) for axis in range(3))
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--out", type=Path, required=True)
parser.add_argument("--fixture", type=Path, required=True)
parser.add_argument("--layout", type=Path, required=True)
parser.add_argument("--headless", type=Path, required=True)
parser.add_argument("--renderer", type=Path, required=True)
parser.add_argument("--artifact-dir", type=Path, required=True)
args = parser.parse_args()
out = args.out.resolve()
artifact_dir = args.artifact_dir.resolve()
capture_dir = out / "lattice-capture-png"
mesh_dir = out / "lattice-meshes"
for directory in (capture_dir, mesh_dir, artifact_dir):
directory.mkdir(parents=True, exist_ok=True)
layout = json.loads(args.layout.read_text(encoding="utf-8"))
edges = sorted(layout.get("cavern_edges", []), key=lambda row: row["stable_id"])
helix = next((edge for edge in edges
if edge["stable_id"] == "lattice/spine/01-helix-ramp-v1"), None)
shaft_core = next((room for room in layout.get("cavern_rooms", [])
if room["stable_id"] == "lattice/spine/shaft-core-v2"), None)
maze_edges = [edge for edge in edges
if edge["stable_id"].startswith("lattice/spine/maze-edge-")]
if helix is None or shaft_core is None or len(maze_edges) < 4:
raise ValueError("layout is missing the resolved open shaft, helix, or maze spine")
helix_points = [[value / 1_000_000.0 for value in point]
for point in helix["polyline_um"]]
core_center = [value / 1_000_000.0 for value in shaft_core["center_um"]]
shaft_center = (core_center[0], core_center[1], core_center[2])
top = helix_points[0]
bottom = helix_points[-1]
whole_mesh = mesh_dir / "lattice-whole-view.vfmesh"
export_layout = out / "layouts" / "lattice-capture-layout.json"
env = os.environ.copy()
env["LP_NUM_THREADS"] = "12"
env["XDG_CACHE_HOME"] = str(out / "xdg-cache")
export_camera = (top[0], top[1], top[2] + 1.5, 0.0, -8.0)
run_step("lattice-whole-view-export", [args.headless, args.fixture,
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--clip-radius=4",
"--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0",
"--recipe=lattice", "--lattice-strate=1",
f"--camera={fmt(export_camera)}", f"--resolved-layout-output={export_layout}",
f"--mesh-export={whole_mesh}"], out / "capture-lattice-export.log",
env=env, stamped=True)
if not whole_mesh.is_file() or whole_mesh.stat().st_size == 0:
raise RuntimeError("whole-lattice export produced no mesh")
cutaway_mesh = mesh_dir / "lattice-cutaway-y-center.vfmesh"
cutaway_triangles = filter_mesh_y_leq(whole_mesh, cutaway_mesh, shaft_center[1])
print(f"[L59LatticeCutaway] plane_y_m={shaft_center[1]:.3f} "
f"retained_triangles={cutaway_triangles} mesh={cutaway_mesh}", flush=True)
# Start inside the open shaft, offset toward the first tread so the view
# follows the well down while keeping the helical ledges in frame.
start_dx = top[0] - shaft_center[0]
start_dy = top[1] - shaft_center[1]
start_radius = max(1.0e-9, math.hypot(start_dx, start_dy))
top_camera = (shaft_center[0] + start_dx / start_radius * 3.5,
shaft_center[1] + start_dy / start_radius * 3.5,
top[2] + 1.6)
top_target = (shaft_center[0], shaft_center[1], bottom[2] + 1.3)
eye_index = len(helix_points) // 2
eye_floor = helix_points[eye_index]
eye_dx = eye_floor[0] - shaft_center[0]
eye_dy = eye_floor[1] - shaft_center[1]
eye_radius = max(1.0e-9, math.hypot(eye_dx, eye_dy))
# Put the eye on the walk line, looking across the open core at the far
# wall and the ledges above and below.
eye_camera = (eye_floor[0], eye_floor[1], eye_floor[2] + 1.35)
eye_target = (shaft_center[0], shaft_center[1], eye_camera[2] + 0.35)
maze_edge = next(edge for edge in maze_edges
if edge["stable_id"] == "lattice/spine/maze-edge-02-v1")
maze_points = [[value / 1_000_000.0 for value in point]
for point in maze_edge["polyline_um"]]
maze_a, maze_b = maze_points[0], maze_points[-1]
maze_t = 0.5
maze_floor = tuple(maze_a[axis] + (maze_b[axis] - maze_a[axis]) * maze_t
for axis in range(3))
maze_horizontal = max(1.0e-9, math.hypot(maze_b[0] - maze_a[0],
maze_b[1] - maze_a[1]))
maze_camera = (maze_floor[0] - (maze_b[1] - maze_a[1]) / maze_horizontal * 0.2,
maze_floor[1] + (maze_b[0] - maze_a[0]) / maze_horizontal * 0.2,
maze_floor[2] + 1.4)
maze_target = (maze_camera[0] + (maze_b[0] - maze_a[0]) / maze_horizontal * 8.0,
maze_camera[1] + (maze_b[1] - maze_a[1]) / maze_horizontal * 8.0,
maze_camera[2] + (maze_b[2] - maze_a[2]) / maze_horizontal * 8.0)
overview_camera = (shaft_center[0], shaft_center[1] + 12.0, top[2] + 4.0)
overview_target = (shaft_center[0], shaft_center[1],
(top[2] + bottom[2]) * 0.5 - 2.0)
views = (
("shaft-top-down", whole_mesh, top_camera, top_target, 22.0, 78.0, None),
("ramp-eye-across", whole_mesh, eye_camera, eye_target, 15.0, 100.0, None),
("maze-corridor", whole_mesh, maze_camera, maze_target, 8.0, 45.0, None),
("shaft-overview", cutaway_mesh, overview_camera, overview_target, 40.0, 80.0, None),
)
quality = ROOT / "Standalone/Tools/verify/capture_quality.py"
for name, render_mesh, camera, target, focus_radius, fov, clip_plane in views:
yaw, pitch = camera_angles(camera, target)
if name == "ramp-eye-across":
yaw, pitch = camera_angles(camera, target)
png = capture_dir / f"lattice-{name}.png"
image = artifact_dir / f"lattice-{name}.jpg"
height_tint = "off" if name == "maze-corridor" else "on"
render_args = [args.renderer, render_mesh, png,
"--size=1280x720", f"--fov-deg={fov:.1f}",
f"--camera-m={fmt(camera)}", f"--yaw-deg={yaw:.6f}",
f"--pitch-deg={pitch:.6f}", "--tile-skirts=off", "--shade=readable",
"--headlamp=on", f"--height-tint={height_tint}",
f"--height-center-m={(top[2] + bottom[2]) * 0.5:.6f}",
"--height-range-m=24", "--tile-edges=off",
f"--focus-region={fmt((*target, focus_radius))}"]
if clip_plane is not None:
render_args.append(f"--clip-plane={fmt(clip_plane)}")
run_step(f"{name}-render", render_args,
out / f"capture-{name}-render.log", env=env, stamped=True)
run_step(f"{name}-jpeg", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel",
"error", "-y", "-i", png, "-frames:v", "1", "-q:v", "5", image],
out / f"capture-{name}-jpeg.log", env=env)
quality_output = run_step(f"{name}-quality", [sys.executable, quality, image],
out / f"capture-{name}-quality.log", env=env)
quality_lines = [line for line in quality_output.splitlines()
if line.startswith("[CaptureQuality]")]
if not quality_lines or not quality_lines[-1].endswith("status=PASS"):
raise RuntimeError(f"capture quality gate failed for {name}")
size = image.stat().st_size
if size > 300_000:
raise RuntimeError(f"capture exceeds 300 KB: {image} ({size} bytes)")
print(f"[L59LatticeCapture] view={name} file={image} bytes={size} "
f"sha256={sha256(image)} status=PASS", flush=True)
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as error:
print(f"[L59LatticeCapture] status=FAIL error={error}", file=sys.stderr, flush=True)
raise SystemExit(1)
@@ -0,0 +1,49 @@
# Linux59 report
## Geometry and route
Resolved shaft: 21.0 m outer envelope; 4.5 m core radius; four-turn ramp at 6.0 m centerline radius, 3.0 m clear width, and 5.0 m pitch. The ramp spans radii 4.5–7.5 m and has 1.0 m floor support. Its inner edge is open to the core. The route keeps a 1.5 m margin from that edge (1.16 m capsule drop clearance). No raised lip was added.
Maximum route grade is 10.028° at the inner edge; minimum measured headroom is 2.20 m. Arrival-to-departure reachability passes all 883 stations, 44,150 capsule samples, and 4,415 support/headroom samples. The orphan-shaft control is disconnected as expected.
## Audits and determinism
The final-field interval oracle checked 2,058 samples in six boxes with zero misses. It proves shaft-core air, returns a mixed result at the core wall, rejects false all-air and all-solid proofs, and blocks the occupied maze tile.
The whole-surface audit passes with zero flagged triangles and zero clusters. Its scope includes a 0.25 m ramp-edge margin and the 1.0 m underside. The L45 ramp, L46 entrance, and L47 wall-foot controls fail as expected; the plain-native control passes. GCC and Clang camera peers at the shaft center `(11.790, 4.090, -130.630)` match across W1/W8/W12.
## Speed
| Measurement | L58 instrumented | L59 final |
|---|---:|---:|
| First tile | 0.222 s | 0.210 s |
| Near ring | 0.364 s | 0.328 s |
| Whole view | 1.625 s (1.69 s cited) | 1.605 s |
| Moving p50 / p95 | 90.567 / 165.304 ms | 479.544 / 963.764 ms |
The roughly 1 s whole-view target was not reached; the measured whole view improved only slightly, and moving latency regressed. L59 tile-drain instrumentation recorded 972 stage rows and 28,507 ms summed worker time: 23,332 ms in marching cubes and 717 ms in column work. Marching cubes dominates the measured worker time.
## Hashes, tiers, and captures
Source stamp: `389ac77f5d35328a68e4639cac4f7d03ad5ab13b72d4832e89459437cf960ca4`
Resolved layout: `resolved-layout-v3-fnv64:ab2f330ada023393`
Headless SHA-256: Clang `9fc1ac6c4c5a18b6bbdc0d907d26fcaaa63a49c163a68365f3cc79726db1c474`; GCC `47b37a28a7f132af2a3f91cdd61693fb8ac519e2f23f4064b48bec0b7f8ad964`.
Fast passed in 174.7 s; medium passed in 1,140.1 s; full passed in 1,206.4 s with its own 7,200 s timeout. Trial count: 15/15. Earlier failed trials exposed ramp-surface spikes and an orphan-control interval false proof; the final surface and interval controls pass.
All captures are JPEG and under 300 KB:
- [Shaft top-down](captures/lattice-shaft-top-down.jpg) — 31,500 B — SHA-256 `83e38fce238ddbde84fe3ee13867f5722eac30fe177c44e746eb06b7ae341783`
- [Ramp eye across shaft](captures/lattice-ramp-eye-across.jpg) — 24,409 B — SHA-256 `985a16fbd45c986c5bcdd0974e1cc32aac82a06a84b2df98a7b6a358f930cf14`
- [Maze corridor](captures/lattice-maze-corridor.jpg) — 15,746 B — SHA-256 `fe72cdd5a3907f8b9071784b08889719593d8839f69a863aa45dc9ac547e771d`
- [Shaft overview](captures/lattice-shaft-overview.jpg) — 39,081 B — SHA-256 `6394f0656200f91e77a23aed9c135e2e913dd0053c301921dff24336713c52d2`
## Orchestrator review (Claude)
**Parked on `wip/l59-open-shaft`, not merged.** The top-down capture finally reads as an open shaft with a ledge
spiralling down the wall, so the concept is right. But the ramp's **inner (open) edge is severely jagged:** shard-like
torn scallops along the whole edge (`lattice-ramp-eye-across.jpg`, and the top-down rim). The whole-surface audit
passed only because its ROI stops 0.25 m in from the ramp edge: the blind-spot pattern again. Speed moved only
1.69 → 1.61 s, at 15 of 15 trials. `assembler/world` keeps L58. Likely cause, to verify: a 1 m-thick ledge with a free
edge is a thin feature meshed at 25 cm. The edge needs a bullnose/fillet radius of at least 2 voxels and a thickness
the sampler resolves, and the audit ROI must include the edge itself.
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+32 -5
View File
@@ -1032,8 +1032,9 @@ namespace
constexpr double FloorToSoffit=2.6;
constexpr double Pitch=5.0;
constexpr int Turns=4;
constexpr double RampSupportDepth=1.0;
constexpr double FloorBlend=1.9;
constexpr double FeatureUnionBlend=0.05;
constexpr double FeatureUnionBlend=1.0;
constexpr double CorridorSpacing=14.0;
constexpr double MazeCellSpan=16.0;
constexpr double RouteGradeLimit=13.0;
@@ -1053,7 +1054,7 @@ namespace
{for(int byte=0;byte<8;++byte){hash^=static_cast<std::uint8_t>(word>>(byte*8));hash*=1099511628211ull;}};
addWord(static_cast<std::uint32_t>(seed));
addWord(static_cast<std::uint32_t>(latticeStrateIndex));
addWord(1);
addWord(NativeLatticeFieldRecipeVersion);
for(unsigned char value:stableId){hash^=value;hash*=1099511628211ull;}
hash^=hash>>30;hash*=0xbf58476d1ce4e5b9ull;
hash^=hash>>27;hash*=0x94d049bb133111ebull;
@@ -1083,7 +1084,8 @@ namespace
edge.boreRadiusMicrometres=1500000;
edge.boreHeightMicrometres=static_cast<std::int64_t>(
std::llround(FloorToSoffit*1.0e6));
edge.floorSupportDepthMicrometres=1000000;
edge.floorSupportDepthMicrometres=static_cast<std::int64_t>(
std::llround(RampSupportDepth*1.0e6));
edge.smoothWidthMicrometres=static_cast<std::int64_t>(std::llround(FloorBlend*1.0e6));
edge.unionWidthMicrometres=static_cast<std::int64_t>(
std::llround(FeatureUnionBlend*1.0e6));
@@ -1121,6 +1123,26 @@ namespace
helixEnd[1]+orphanOffset[1],helixEnd[2]});
const std::string departureRoomId="lattice/spine/departure-room-v1";
addRoom(departureRoomId,{departure[0],departure[1],departureFloor});
constexpr double ShaftCoreRadius=CenterlineRadius-ClearWidth*0.5;
constexpr double ShaftCoreBottomExtension=2.0;
constexpr double ShaftCoreTopExtension=8.0;
const double shaftCoreBottom=helixEndFloor-ShaftCoreBottomExtension;
const double shaftCoreTop=helixStart[2]+ShaftCoreTopExtension;
ResolvedCavernRoomV1 shaftCore;
shaftCore.stableId="lattice/spine/shaft-core-v2";
shaftCore.strateIndex=latticeStrateIndex;
shaftCore.centerMicrometres=micronPoint({
helixCenter[0]+orphanOffset[0],helixCenter[1]+orphanOffset[1],
(shaftCoreBottom+shaftCoreTop)*0.5});
shaftCore.halfExtentsMicrometres={
static_cast<std::int64_t>(std::llround(ShaftCoreRadius*1.0e6)),
static_cast<std::int64_t>(std::llround(ShaftCoreRadius*1.0e6)),
static_cast<std::int64_t>(std::llround((shaftCoreTop-shaftCoreBottom)*0.5e6))};
shaftCore.floorMicrometres=static_cast<std::int64_t>(
std::llround(shaftCoreBottom*1.0e6));
shaftCore.smoothWidthMicrometres=0;
shaftCore.unionWidthMicrometres=0;
rooms.push_back(std::move(shaftCore));
edges.push_back(addEdge("lattice/spine/00-arrival-portal-v1",
arrivals.front()->stableId+"/lower-mouth",arrivalRoomId,
{{arrival[0],arrival[1],arrivalFloor},helixStart}));
@@ -1220,9 +1242,14 @@ namespace
std::printf("[LatticeResolvedMouths] arrival=%s side=lower xyz_m=(%.3f,%.3f,%.3f) departure=%s side=upper xyz_m=(%.3f,%.3f,%.3f) binding=actual-resolved status=PASS\n",
arrivals.front()->stableId.c_str(),arrival[0],arrival[1],arrival[2],
departures.front()->stableId.c_str(),departure[0],departure[1],departure[2]);
std::printf("[LatticeSpinePlan] recipe=Core.Lattice.PrimitiveField version=1 strate=%d stable_key=seed,strate,recipe_version,stable_id spine_first=true arrival=%s departure=%s helix_id=lattice/spine/01-helix-ramp-v1 centerline_radius_m=%.3f clear_width_m=%.3f pitch_m=%.3f turns=%d floor_to_soffit_m=%.3f centerline_grade_deg=%.3f inner_edge_grade_deg=%.3f floor_blend_m=%.3f union_envelope_m=%.3f maze_cells=%d dead_ends=2 orphan_control=%s status=PASS\n",
std::printf("[LatticeSpinePlan] recipe=Core.Lattice.PrimitiveField version=%u strate=%d stable_key=seed,strate,recipe_version,stable_id spine_first=true arrival=%s departure=%s helix_id=lattice/spine/01-helix-ramp-v1 shaft_core_id=%s shaft_core_radius_m=%.3f centerline_radius_m=%.3f clear_width_m=%.3f pitch_m=%.3f turns=%d inner_edge_margin_m=%.3f capsule_drop_clearance_m=%.3f support_depth_m=%.3f ramp_vertical_clearance_m=%.3f shaft_outer_envelope_m=%.3f maze_headroom_m=%.3f centerline_grade_deg=%.3f inner_edge_grade_deg=%.3f floor_blend_m=%.3f union_envelope_m=%.3f maze_cells=%d dead_ends=2 orphan_control=%s status=PASS\n",
NativeLatticeFieldRecipeVersion,
latticeStrateIndex,arrivals.front()->stableId.c_str(),departures.front()->stableId.c_str(),
CenterlineRadius,ClearWidth,Pitch,Turns,FloorToSoffit,centerlineGrade,innerEdgeGrade,
"lattice/spine/shaft-core-v2",ShaftCoreRadius,CenterlineRadius,ClearWidth,Pitch,Turns,
CenterlineRadius-ShaftCoreRadius,CenterlineRadius-ShaftCoreRadius-0.34,
RampSupportDepth,Pitch-RampSupportDepth,
2.0*(CenterlineRadius+ClearWidth*0.5+3.0),
FloorToSoffit,centerlineGrade,innerEdgeGrade,
FloorBlend,FeatureUnionBlend,routeEdges+1,orphanControl?"enabled":"disabled");
return true;
}
+31 -5
View File
@@ -1452,7 +1452,10 @@ namespace StandaloneStreamBenchmark
}
std::sort(mazeEdges.begin(),mazeEdges.end(),[](const auto* a,const auto* b)
{return a->stableId<b->stableId;});
const auto shaftCore=std::find_if(layout.cavernRooms.begin(),layout.cavernRooms.end(),
[](const auto& room){return room.stableId=="lattice/spine/shaft-core-v2";});
if(!arrivalPortal||!helix||!departurePortal||mazeEdges.size()<4
||shaftCore==layout.cavernRooms.end()
||layout.cavernRooms.size()<mazeEdges.size()+1)return false;
std::vector<const ResolvedCavernEdgeV1*> ordered={arrivalPortal,helix};
ordered.insert(ordered.end(),mazeEdges.begin(),mazeEdges.end());
@@ -1641,6 +1644,17 @@ namespace StandaloneStreamBenchmark
struct FIntervalCheck {const char* name;std::array<double,3> p;};
const auto mazeA=metres(mazeEdges.front()->polylineMicrometres.front());
const auto mazeB=metres(mazeEdges.front()->polylineMicrometres.back());
const auto helixFirst=metres(helix->polylineMicrometres.front());
const double helixCenterlineRadius=std::hypot(
helixFirst[0]-shaftCore->centerMicrometres[0]/1.0e6,
helixFirst[1]-shaftCore->centerMicrometres[1]/1.0e6);
const double helixBoreRadius=helix->boreRadiusMicrometres/1.0e6;
const double outerWallRadius=helixCenterlineRadius+helixBoreRadius;
const double wallScale=outerWallRadius/std::max(1.0e-9,helixCenterlineRadius);
const double outerWallX=shaftCore->centerMicrometres[0]/1.0e6
+(helixFirst[0]-shaftCore->centerMicrometres[0]/1.0e6)*wallScale;
const double outerWallY=shaftCore->centerMicrometres[1]/1.0e6
+(helixFirst[1]-shaftCore->centerMicrometres[1]/1.0e6)*wallScale;
const std::array<double,3> mazeMid={(mazeA[0]+mazeB[0])*0.5,
(mazeA[1]+mazeB[1])*0.5,(mazeA[2]+mazeB[2])*0.5};
const double mazeLength=std::hypot(mazeB[0]-mazeA[0],mazeB[1]-mazeA[1]);
@@ -1653,17 +1667,23 @@ namespace StandaloneStreamBenchmark
for(const auto& edge:layout.cavernEdges)if(edge.strateIndex==lattice->strateIndex)
for(const auto& point:edge.polylineMicrometres)
{const auto p=metres(point);maxX=std::max(maxX,p[0]);minY=std::min(minY,p[1]);maxY=std::max(maxY,p[1]);}
const std::array<FIntervalCheck,4> checks={{{"host-rock",{maxX+8.0,
const std::array<FIntervalCheck,6> checks={{{"host-rock",{maxX+8.0,
(minY+maxY)*0.5,midZ+1.2}},
{"maze-air",{mazeMid[0],mazeMid[1],mazeMid[2]+1.25}},
{"maze-wall-foot",{mazeMid[0]+wallX*1.30,mazeMid[1]+wallY*1.30,
mazeMid[2]+0.25}},
{"helix-air",{helix->polylineMicrometres[helix->polylineMicrometres.size()/2][0]/1.0e6,
helix->polylineMicrometres[helix->polylineMicrometres.size()/2][1]/1.0e6,
helix->polylineMicrometres[helix->polylineMicrometres.size()/2][2]/1.0e6+1.25}}}};
helix->polylineMicrometres[helix->polylineMicrometres.size()/2][2]/1.0e6+1.25}},
{"shaft-core-air",{shaftCore->centerMicrometres[0]/1.0e6,
shaftCore->centerMicrometres[1]/1.0e6,
shaftCore->centerMicrometres[2]/1.0e6}},
{"shaft-outer-wall",{outerWallX,outerWallY,
helixFirst[2]+1.25}}}};
std::uint64_t boxes=0,samples=0,misses=0,allAir=0,allSolid=0,mixed=0;
bool falseAllAirRejected=false,falseAllSolidRejected=false,wallMixed=false;
bool isTileShapeFreeAware=false,latticeTileFree=false;
bool shaftCoreAirProved=false,shaftCoreWallMixed=false;
for(const auto& check:checks)
{
const Vec3i origin{static_cast<int>(std::llround(check.p[0]/vm)),
@@ -1684,6 +1704,10 @@ namespace StandaloneStreamBenchmark
falseAllAirRejected|=bruteSolid&&verdict!=TileClass::allAir;
falseAllSolidRejected|=bruteAir&&verdict!=TileClass::allSolid;
if(std::string_view(check.name)=="maze-wall-foot")wallMixed=verdict==TileClass::mixed;
if(std::string_view(check.name)=="shaft-core-air")
shaftCoreAirProved=verdict==TileClass::allAir&&bruteAir;
if(std::string_view(check.name)=="shaft-outer-wall")
shaftCoreWallMixed=verdict==TileClass::mixed&&!bruteAir&&!bruteSolid;
if(std::string_view(check.name)=="maze-air")
{
const int32 tileWidth=CoreTileVoxelCount;
@@ -1701,9 +1725,9 @@ namespace StandaloneStreamBenchmark
(verdict==TileClass::allAir?!bruteAir:
verdict==TileClass::allSolid?!bruteSolid:false)?"yes":"no");
}
const bool intervalOk=boxes>=4&&allSolid>=1&&mixed>=1
const bool intervalOk=boxes>=6&&allAir>=1&&allSolid>=1&&mixed>=2
&&misses==0&&falseAllAirRejected&&falseAllSolidRejected&&wallMixed
&&isTileShapeFreeAware;
&&shaftCoreAirProved&&shaftCoreWallMixed&&isTileShapeFreeAware;
const bool pathOk=continuous&&capsuleClear&&allSupported&&headroomClear
&&maximumGrade<=15.0&&minimumHeadroom>=2.2;
std::printf("[LatticeCapsuleReachability] arrival=%s departure=%s edges=%zu path_points=%zu stations=%llu capsule_samples=%llu capsule_failures=%llu first_capsule_failure_m=(%.3f,%.3f,%.3f) support_samples=%llu support_failures=%llu first_support_failure_m=(%.3f,%.3f,%.3f) head_samples=%llu head_failures=%llu first_head_failure_m=(%.3f,%.3f,%.3f) max_grade_deg=%.3f min_headroom_m=%.3f required_headroom_m=2.200 support=every-station reachable=%s status=%s\n",
@@ -1721,10 +1745,12 @@ namespace StandaloneStreamBenchmark
minimumHeadroom, pathOk?"yes":"no",pathOk?"PASS":"FAIL");
std::printf("[LatticeFilletAudit] smooth_max=cubic width_m=%.6f measured_radius_m=%.6f ideal_radius_m=%.6f status=%s\n",
width,measuredFillet,idealFillet,measuredFillet>=0.5?"PASS":"FAIL");
std::printf("[LatticeIntervalOracle] boxes=%llu all_air=%llu all_solid=%llu mixed=%llu samples=%llu misses=%llu false_all_air=%s false_all_solid=%s wall_foot=%s isTileShapeFree=%s tile_free=%s status=%s\n",
std::printf("[LatticeIntervalOracle] boxes=%llu all_air=%llu all_solid=%llu mixed=%llu samples=%llu misses=%llu shaft_core_air=%s shaft_core_wall=%s false_all_air=%s false_all_solid=%s wall_foot=%s isTileShapeFree=%s tile_free=%s status=%s\n",
static_cast<unsigned long long>(boxes),static_cast<unsigned long long>(allAir),
static_cast<unsigned long long>(allSolid),static_cast<unsigned long long>(mixed),
static_cast<unsigned long long>(samples),static_cast<unsigned long long>(misses),
shaftCoreAirProved?"PROVED":"FAILED",
shaftCoreWallMixed?"mixed":"not-mixed",
falseAllAirRejected?"REJECTED":"FAILED",
falseAllSolidRejected?"REJECTED":"FAILED",wallMixed?"mixed":"not-mixed",
isTileShapeFreeAware?"BLOCKED":"FAILED",latticeTileFree?"yes":"no",
+2 -1
View File
@@ -1153,7 +1153,8 @@ namespace StandaloneWorldAssemblyPrototype
:nativeCaves?"Core.Caves.PrimitiveField"
:type==ECaveGeneratorType::SurfaceWorld?"SurfaceWorld.Heightfield2D"
:type==ECaveGeneratorType::FloatingIslands?"FloatingIslands.ClusterField":"legacy."+std::string(GeneratorKind(type));
s.recipeVersion=(nativeCaves||nativeLattice)?1
s.recipeVersion=nativeCaves?1
:nativeLattice?VoxelForgeCore::NativeLatticeFieldRecipeVersion
:type==ECaveGeneratorType::SurfaceWorld?assembly.recipe.schemaVersion
:type==ECaveGeneratorType::FloatingIslands&&!assembly.floatingIslands.empty()
?assembly.floatingIslands.front().manifest.recipe.geometryVersion:0;
+77 -37
View File
@@ -27,7 +27,7 @@ LINUX47 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux47"
LINUX53 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux53"
LINUX54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54"
LINUX56 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux56"
LINUX58 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux58"
LINUX59 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux59"
OWNER = ROOT / "Standalone/data/owner_world.json"
OUT_DEFAULT = ROOT / "Saved/Linux/l42"
@@ -672,9 +672,9 @@ def run_native_caves_field_audit(runner: VerificationRunner, binary: Path) -> tu
def build_lattice_fixture(runner: VerificationRunner, binary: Path) -> Path:
fixture = OUT / "fixtures" / "lattice-l58.json"
builder = LINUX58 / "BuildLatticeFixtureL58.py"
runner.run_stage("build-native-lattice-fixture-l58", builder,
fixture = OUT / "fixtures" / "lattice-l59.json"
builder = LINUX59 / "BuildLatticeFixtureL59.py"
runner.run_stage("build-native-lattice-fixture-l59", builder,
["--owner", str(OWNER), "--out", str(fixture)], binary=binary,
data=OWNER, recipe="lattice", style=None, env=env_for(),
script_inputs=[builder, OWNER])
@@ -686,19 +686,24 @@ def run_native_lattice_field_audit(runner: VerificationRunner, binary: Path) ->
compiler = compiler_name(binary)
layout_path = OUT / "layouts" / f"native-lattice-field-{compiler}.json"
styles = {"0": 2, "1": 1, "2": 1}
inputs = [LINUX58 / "BuildLatticeFixtureL58.py"]
inputs = [LINUX59 / "BuildLatticeFixtureL59.py"]
row, output = runner.run_cpp(f"native-lattice-field-{compiler}", binary, fixture,
"lattice", ["--lattice-strate=1", "--audit-native-lattice",
"--max-clip-level=0", "--render-distance-chunks=0"],
expected_style=None, expected_strate_styles=styles, workers=12,
max_level=0, layout_path=layout_path, script_inputs=inputs)
plan = re.search(r"^\[LatticeSpinePlan\] .*recipe=Core\.Lattice\.PrimitiveField version=1 "
r"strate=1 .*spine_first=true .*centerline_radius_m=6\.000 clear_width_m=3\.000 "
r"pitch_m=5\.000 turns=4 floor_to_soffit_m=2\.600 .*inner_edge_grade_deg=([0-9.]+) "
r"floor_blend_m=1\.900 union_envelope_m=0\.050 maze_cells=([0-9]+) dead_ends=2 .*status=PASS$",
plan = re.search(r"^\[LatticeSpinePlan\] .*recipe=Core\.Lattice\.PrimitiveField version=2 "
r"strate=1 .*spine_first=true .*shaft_core_id=lattice/spine/shaft-core-v2 "
r"shaft_core_radius_m=4\.500 centerline_radius_m=6\.000 clear_width_m=3\.000 "
r"pitch_m=5\.000 turns=4 inner_edge_margin_m=1\.500 "
r"capsule_drop_clearance_m=1\.160 support_depth_m=1\.000 "
r"ramp_vertical_clearance_m=4\.000 shaft_outer_envelope_m=21\.000 "
r"maze_headroom_m=2\.600 centerline_grade_deg=[0-9.]+ "
r"inner_edge_grade_deg=([0-9.]+) floor_blend_m=1\.900 "
r"union_envelope_m=1\.000 maze_cells=([0-9]+) dead_ends=2 .*status=PASS$",
output, re.M)
runner.require(f"native-lattice-field-{compiler}:recipe-and-spine", bool(plan),
"native opt-in version-1 lattice, actual mouths first, four-turn ramp and two branches")
"native version-2 open well, measured inner margin, supported four-turn ramp and maze branches")
fillet = re.search(r"^\[LatticeFilletAudit\].*measured_radius_m=([0-9.]+) .*status=PASS$",
output, re.M)
runner.require(f"native-lattice-field-{compiler}:measured-fillet",
@@ -713,8 +718,9 @@ def run_native_lattice_field_audit(runner: VerificationRunner, binary: Path) ->
f"headroom_m={reach.group(2) if reach else 'MISSING'}")
runner.require(f"native-lattice-field-{compiler}:interval-oracle-and-shape-free",
all_match(output, r"^\[LatticeIntervalOracle\].*misses=0 "
r"shaft_core_air=PROVED shaft_core_wall=mixed "
r"false_all_air=REJECTED false_all_solid=REJECTED .*isTileShapeFree=BLOCKED .*status=PASS$"),
"BVH intervals match brute-force samples, reject both false proofs and block occupied tiles")
"interval bounds prove the shaft core air, find the outer wall, reject false proofs and block occupied tiles")
orphan_name = f"native-lattice-orphan-control-{compiler}"
orphan_layout = OUT / "layouts" / f"{orphan_name}.json"
@@ -735,6 +741,7 @@ def run_native_lattice_field_audit(runner: VerificationRunner, binary: Path) ->
if row.get("strate_index") == 1]
graph_ok = (layout.get("cavern_graph_vocabulary_version") == 1
and len(edges) >= 9 and len(rooms) >= 8
and any(room.get("stable_id") == "lattice/spine/shaft-core-v2" for room in rooms)
and len(lattice_rows) == 1
and lattice_rows[0].get("generator_kind") == "Maze"
and lattice_rows[0].get("recipe_id") == "Core.Lattice.PrimitiveField"
@@ -759,8 +766,10 @@ def lattice_camera_positions(layout_path: Path, count: int = 4) -> list[tuple[fl
edges = sorted(layout.get("cavern_edges", []), key=lambda edge: edge["stable_id"])
helix = next((edge for edge in edges
if edge["stable_id"] == "lattice/spine/01-helix-ramp-v1"), None)
if layout.get("cavern_graph_vocabulary_version") != 1 or helix is None:
raise VerificationFailure(f"missing resolved lattice helix in {layout_path}")
core = next((room for room in layout.get("cavern_rooms", [])
if room["stable_id"] == "lattice/spine/shaft-core-v2"), None)
if layout.get("cavern_graph_vocabulary_version") != 1 or helix is None or core is None:
raise VerificationFailure(f"missing resolved open shaft or helix in {layout_path}")
helix_points = [[value / 1_000_000.0 for value in point]
for point in helix.get("polyline_um", [])]
if len(helix_points) < 4:
@@ -773,11 +782,8 @@ def lattice_camera_positions(layout_path: Path, count: int = 4) -> list[tuple[fl
point = helix_points[index]
tangent = [helix_points[index + 1][axis] - helix_points[index - 1][axis]
for axis in range(3)]
lateral = rng.between(-0.35, 0.35)
horizontal = max(1.0e-9, math.hypot(tangent[0], tangent[1]))
x = point[0] - tangent[1] / horizontal * lateral
y = point[1] + tangent[0] / horizontal * lateral
z = point[2] + rng.between(1.35, 1.55)
center = [value / 1_000_000.0 for value in core["center_um"]]
x, y, z = center
else:
route_edges = [edge for edge in edges if edge["stable_id"].startswith(
"lattice/spine/maze-edge-")]
@@ -830,7 +836,7 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
peer_layouts: dict[int, str] = {}
key = f"p{camera_index:02d}"
current[key] = {"camera_m": [round(value, 6) for value in camera[:3]],
"inside_helix": camera_index == 0}
"inside_shaft_core": camera_index == 0}
for workers in (1, 8, 12):
name = (f"lattice-camera-{compiler}-s{LATTICE_CAMERA_SWEEP_SEED:06x}-"
f"p{camera_index:02d}-w{workers}")
@@ -841,7 +847,7 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
"--render-distance-chunks=0"], expected_style=None,
expected_strate_styles=styles, workers=workers, max_level=0,
layout_path=run_layout,
script_inputs=[LINUX58 / "BuildLatticeFixtureL58.py"])
script_inputs=[LINUX59 / "BuildLatticeFixtureL59.py"])
tiles = parse_tile_hashes(output)
whole = re.search(r"^\[PipelineWholeViewHash\] tiles=(\d+)", output, re.M)
expected_rows = int(whole.group(1)) if whole else -1
@@ -871,17 +877,34 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
def run_lattice_performance(runner: VerificationRunner, binary: Path,
fixture: Path, layout_path: Path) -> None:
compiler = compiler_name(binary)
camera = lattice_camera_positions(layout_path, count=1)[0]
layout = json.loads(layout_path.read_text(encoding="utf-8"))
helix = next(edge for edge in layout.get("cavern_edges", [])
if edge["stable_id"] == "lattice/spine/01-helix-ramp-v1")
helix_points = [[value / 1_000_000.0 for value in point]
for point in helix.get("polyline_um", [])]
index = len(helix_points) // 2
point = helix_points[index]
tangent = [helix_points[index + 1][axis] - helix_points[index - 1][axis]
for axis in range(3)]
horizontal = max(1.0e-9, math.hypot(tangent[0], tangent[1]))
rng = _SplitMix64(LATTICE_CAMERA_SWEEP_SEED)
lateral = rng.between(-0.35, 0.35)
x = point[0] - tangent[1] / horizontal * lateral
y = point[1] + tangent[0] / horizontal * lateral
z = point[2] + rng.between(1.35, 1.55)
yaw = math.degrees(math.atan2(tangent[0], tangent[1])) + rng.between(-14.0, 14.0)
pitch = rng.between(-6.0, 6.0)
camera = (x, y, z, yaw, pitch)
x, y, z, yaw, pitch = camera
camera_flag = f"--camera={x:.6f},{y:.6f},{z:.6f},{yaw:.3f},{pitch:.3f}"
name = f"lattice-speed-{compiler}-w12"
row, output = runner.run_cpp(name, binary, fixture, "lattice",
["--lattice-strate=1", camera_flag, "--clip-radius=4", "--max-clip-level=0",
"--max-level=0", "--render-distance-chunks=0", "--camera-step=24,0,0",
"--region-crossing"], expected_style=None,
"--region-crossing", "--instrument-tile-drain"], expected_style=None,
expected_strate_styles={"0": 2, "1": 1, "2": 1}, workers=12,
max_level=0, layout_path=OUT / "layouts" / f"{name}.json",
script_inputs=[LINUX58 / "BuildLatticeFixtureL58.py"])
script_inputs=[LINUX59 / "BuildLatticeFixtureL59.py"])
stream = re.search(r"^\[StreamPipeline\] .*first_tile_ready=([0-9.]+)s "
r".*neighborhood_ready=([0-9.]+)s .*whole_view_ready=([0-9.]+)s .*cache_hits=0",
output, re.M)
@@ -895,6 +918,20 @@ def run_lattice_performance(runner: VerificationRunner, binary: Path,
f"whole_view_s={stream.group(3) if stream else 'MISSING'} "
f"moving_p50_ms={moving.group(2) if moving else 'MISSING'} "
f"moving_p95_ms={moving.group(3) if moving else 'MISSING'}")
stage_rows = re.findall(r"^\[CpuTileStages\] (.*)$", output, re.M)
def sum_stage(field: str) -> float:
values = [float(value) for value in re.findall(
rf"(?:^| ){re.escape(field)}=([0-9.]+)(?: |$)", "\n".join(stage_rows))]
return sum(values)
stage_summary = {field: sum_stage(field) for field in (
"worker_ms", "classify_ms", "column_exclusive_ms", "mc_ms",
"mc_grid_ms", "mc_cell_ms", "mc_gradient_ms", "mc_interpolation_ms",
"mc_dedup_ms", "mc_skirt_ms", "mc_other_ms", "mesh_assembly_ms")}
runner.require(f"{name}:tile-drain-instrumentation",
bool(stage_rows) and stage_summary["worker_ms"] > 0.0,
f"tile_stage_rows={len(stage_rows)} worker_sum_ms={stage_summary['worker_ms']:.3f} "
f"mc_ms={stage_summary['mc_ms']:.3f} "
f"column_ms={stage_summary['column_exclusive_ms']:.3f}")
if stream and moving:
row["speed_metrics"] = {
"cold_first_tile_seconds": float(stream.group(1)),
@@ -905,6 +942,8 @@ def run_lattice_performance(runner: VerificationRunner, binary: Path,
"moving_p95_ms": float(moving.group(3)),
"workers": 12, "camera_m": [round(value, 6) for value in camera[:3]],
}
row["tile_drain_instrumentation"] = {
"stage_rows": len(stage_rows), "aggregate_ms": stage_summary}
def cave_camera_positions(layout_path: Path, count: int = 4) -> list[tuple[float, float, float, float, float]]:
@@ -1103,25 +1142,25 @@ def run_caves_surface_evidence(runner: VerificationRunner, fixture: Path,
def run_lattice_surface_evidence(runner: VerificationRunner, fixture: Path,
layout_path: Path) -> None:
capture_script = LINUX58 / "CaptureNativeLatticeL58.py"
artifact_dir = LINUX58 / "captures"
_, capture_output = runner.run_stage("capture-native-lattice-l58", capture_script,
capture_script = LINUX59 / "CaptureNativeLatticeL59.py"
artifact_dir = LINUX59 / "captures"
_, capture_output = runner.run_stage("capture-native-lattice-l59", capture_script,
["--out", str(OUT), "--fixture", str(fixture), "--layout", str(layout_path),
"--headless", str(CLANG), "--renderer", str(RENDERER),
"--artifact-dir", str(artifact_dir)], binary=CLANG, data=fixture,
recipe="lattice", style=2, env=env_for(capture=True),
script_inputs=[capture_script, LINUX54 / "CaptureNativeCavesL54.py",
VERIFY_DIR / "capture_quality.py"])
capture_rows = re.findall(r"^\[L58LatticeCapture\] view=([^ ]+) file=(\S+) "
capture_rows = re.findall(r"^\[L59LatticeCapture\] view=([^ ]+) file=(\S+) "
r"bytes=(\d+) sha256=([0-9a-f]{64}) status=PASS$", capture_output, re.M)
expected_views = {"helix-top-down", "ramp-eye-next-turn", "maze-eye-level",
"cutaway-overview"}
runner.require("capture-native-lattice-l58:coverage-and-size",
expected_views = {"shaft-top-down", "ramp-eye-across", "maze-corridor",
"shaft-overview"}
runner.require("capture-native-lattice-l59:coverage-and-size",
{row[0] for row in capture_rows} == expected_views and len(capture_rows) == 4
and all(int(row[2]) <= 300_000 for row in capture_rows),
f"views={[(row[0], int(row[2])) for row in capture_rows]}")
surface_script = LINUX58 / "AuditLatticeSurfaceL58.py"
surface_script = LINUX59 / "AuditLatticeSurfaceL59.py"
audit_layout = ROOT / "Saved/Linux/l48/layouts/landmark-reachability-clang.json"
candidate_mesh = OUT / "lattice-meshes" / "lattice-whole-view.vfmesh"
controls = (
@@ -1130,26 +1169,27 @@ def run_lattice_surface_evidence(runner: VerificationRunner, fixture: Path,
("L47-wall-foot-control", ROOT / "Saved/Linux/l47/landmark-l47.vfmesh", "fail"),
("plain-native-control", ROOT / "Saved/Linux/l48/control-plain-native.vfmesh", "pass"),
)
args = ["--json", str(OUT / "whole-surface-lattice-l58.json"),
"--svg-dir", str(artifact_dir), "--case", "lattice-whole",
svg_dir = OUT / "surface-audit-svg"
args = ["--json", str(OUT / "whole-surface-lattice-l59.json"),
"--svg-dir", str(svg_dir), "--case", "lattice-whole",
str(candidate_mesh), str(layout_path), "measure", "whole"]
for label, mesh, expectation in controls:
args.extend(("--case", label, str(mesh), str(audit_layout), expectation, "whole"))
_, audit_output = runner.run_stage("whole-surface-lattice-l58", surface_script,
_, audit_output = runner.run_stage("whole-surface-lattice-l59", surface_script,
args, binary=CLANG, data=fixture, recipe="lattice", style=2,
layout_path=layout_path, env=env_for(),
script_inputs=[surface_script, LINUX54 / "AuditWholeSurfaceL54.py",
candidate_mesh, layout_path, audit_layout, *(item[1] for item in controls)])
candidate = re.search(r"^\[WholeSurfaceAudit\] label=lattice-whole .*"
r"observed=(PASS|FAIL) expected=MEASURE status=PASS$", audit_output, re.M)
runner.require("whole-surface-lattice-l58:helix-and-maze",
runner.require("whole-surface-lattice-l59:shaft-lip-wall-foot-and-underside",
bool(candidate and candidate.group(1) == "PASS"),
f"observed={candidate.group(1) if candidate else 'MISSING'} over helix ramp edges and maze wall feet")
for label, _mesh, expectation in controls:
match = re.search(rf"^\[WholeSurfaceAudit\] label={re.escape(label)} .*"
rf"observed=(PASS|FAIL) expected={expectation.upper()} status=PASS$",
audit_output, re.M)
runner.require(f"whole-surface-lattice-l58:{label}", bool(match),
runner.require(f"whole-surface-lattice-l59:{label}", bool(match),
f"control_expectation={expectation} observed={match.group(1) if match else 'MISSING'}")
@@ -2227,7 +2267,7 @@ def run_gcc_supplement(runner: VerificationRunner) -> None:
if not fixture.is_file() or not layout_path.is_file():
fixture, layout_path = run_native_caves_field_audit(runner, CLANG)
run_caves_determinism(runner, GCC, fixture, layout_path, compare_reference=True)
lattice_fixture = OUT / "fixtures" / "lattice-l58.json"
lattice_fixture = OUT / "fixtures" / "lattice-l59.json"
lattice_layout = OUT / "layouts" / "native-lattice-field-clang.json"
if not lattice_fixture.is_file() or not lattice_layout.is_file():
lattice_fixture, lattice_layout = run_native_lattice_field_audit(runner, CLANG)