From ba017077d165f480d7b60346c96f154815c385a9 Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Thu, 22 Oct 2026 07:28:50 +0200 Subject: [PATCH] wip(assembler): round L35 -- smooth passage walls without regular ribs (evaluator v21) The shared passage carve took the minimum of piecewise-linear capsules (scallops at joins) and added wall relief on regular 8 m / 4 m octaves, which read as evenly spaced ribs. Interior sweep joins are now Catmull-Rom smoothed and the relief uses irregular rotated 43/29/19 m scales; the natural wobble remains. New axial ripple audit (0.125 m radius samples, 0.5-8 m periods): beaded control and L34 geometry fail, all 24 passage rows pass. FI mouth tread apron tapered. 30/30 determinism, 16/16 invariants, ring audits LOD0-8 pass; cost within noise. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX --- ARCHITECTURE.md | 28 ++ CODEMAP.md | 12 + .../include/VoxelForgeCore/VoxelForgeCore.h | 2 +- Standalone/Core/src/ResolvedLayoutInternal.h | 27 +- Standalone/Core/src/ShapeWorldInternal.h | 104 ++++- Standalone/Core/src/VoxelForgeFieldShared.h | 22 + .../AuditPassageMouthMeshProfilesL35.py | 251 +++++++++++ .../Linux35/AuditTunnelMeshNormalsL35.py | 123 ++++++ .../Linux35/CapturePassageStandardSetL35.py | 401 ++++++++++++++++++ .../WorldAssemblerM3/Linux35/REPORT.md | 124 ++++++ .../WorldAssemblerM3/Linux35/RunCostL35.py | 88 ++++ .../Linux35/RunDeterminismL35.py | 119 ++++++ .../Linux35/RunInvariantAuditsL35.py | 82 ++++ .../Linux35/RunLegacyAuditsL35.py | 69 +++ .../Linux35/RunPassageAuditsL35.py | 93 ++++ .../Linux35/captures/owner-fi-arrival.jpg | Bin 0 -> 23405 bytes .../captures/owner-fi-ground-mouth.jpg | Bin 0 -> 34125 bytes .../Linux35/captures/owner-fi-mid-tunnel.jpg | Bin 0 -> 25427 bytes .../Linux35/captures/owner-fi-rock-entry.jpg | Bin 0 -> 26825 bytes .../Linux35/captures/owner-sw-arrival.jpg | Bin 0 -> 22428 bytes .../captures/owner-sw-ground-mouth.jpg | Bin 0 -> 29764 bytes .../Linux35/captures/owner-sw-mid-tunnel.jpg | Bin 0 -> 24120 bytes .../Linux35/captures/owner-sw-rock-entry.jpg | Bin 0 -> 43858 bytes .../captures/upper-sw-fixture-arrival.jpg | Bin 0 -> 24211 bytes .../upper-sw-fixture-ground-mouth.jpg | Bin 0 -> 25389 bytes .../captures/upper-sw-fixture-mid-tunnel.jpg | Bin 0 -> 24136 bytes .../captures/upper-sw-fixture-rock-entry.jpg | Bin 0 -> 25709 bytes Standalone/Source/StreamBenchmarkPipeline.h | 199 ++++++++- 28 files changed, 1727 insertions(+), 17 deletions(-) create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/AuditPassageMouthMeshProfilesL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/AuditTunnelMeshNormalsL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/CapturePassageStandardSetL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/RunCostL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/RunDeterminismL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/RunInvariantAuditsL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/RunLegacyAuditsL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/RunPassageAuditsL35.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-arrival.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-ground-mouth.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-mid-tunnel.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-rock-entry.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-arrival.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-ground-mouth.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-mid-tunnel.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-rock-entry.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/upper-sw-fixture-arrival.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/upper-sw-fixture-ground-mouth.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/upper-sw-fixture-mid-tunnel.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux35/captures/upper-sw-fixture-rock-entry.jpg diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0adffd3..1136ca3 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2110,6 +2110,34 @@ when SurfaceWorld is the upper strate. No evaluator or recipe version changed. [`Standalone/Research/WorldAssemblerM3/Linux33/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux33/REPORT.md) records the four-style audits, captures, determinism, owner hashes, costs and retries. +### 8.48 Irregular passage-wall relief and grounded tread shoulders — World Assembler M3 L35 + +L34's owner-SW profile had a 7.438 m radius repeat with 0.0361 m (3.61 cm) amplitude; an independent +mesh-normal scan also found a 4.750 m period at 0.02682 (1.537°). The geometry came from piecewise +capsule joins, while broad value-noise bands added a second regular pattern. The shared carve now +uses Catmull–Rom centerline interpolation on eligible interior segments, excluding short spans and +terminal controls. Passage walls use deterministic, rotated 43/29/19 m relief with reduced terrain +band contribution; other `VF_FieldSurfaceRelief` users, including grounded bridge columns, are +unchanged. The shared evaluator is version 21. + +The residual radius scan on owner-SW style 0 measures a 7.062 m period at 0.0109 m (1.09 cm), +with 0.0044 m (0.44 cm) coherent amplitude. The independent L35 mesh-normal scan passes at 8 m +and 0.02496 axial amplitude, below its 0.0255 threshold. The ripple audit samples both side-wall +radii every 0.125 m in 32 m windows, scans 0.5–8 m periods, and rejects amplitudes of 0.035 m or +more. Its synthetic control uses 2 m radius spheres spaced every 1.5 m; it measures 0.0599 m and +must fail. + +At the FI mouth, the flat apron is the shared passage support tread, not `LandingExtensionQ`, a tile +edge or a separate support layer. The tread is required by capsule and support probes. L35 gives its +outer entry shoulder a shallow taper and seeded grain while preserving the supported walk core and +lower-mouth overlap width. The shallow quarter-weight support-height/radius spline keeps the tread +continuous without moving its XY footprint. + +Cascade routes also replace identical full-depth cosine lobes with a seeded shallow profile on each +turn. Passage, capsule, support, open-air, bridge, binding, strict layout, capture, determinism, ring, +and cost evidence are recorded in +[`Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md). + ## 9. Multiplayer model (listen-server first, dedicated-friendly) > **Status: transport is DESIGN ONLY — nothing is networked in-tree yet** (no `Replicated`/`HasAuthority`/RPCs; a diff --git a/CODEMAP.md b/CODEMAP.md index 57a98d6..1d00b64 100644 --- a/CODEMAP.md +++ b/CODEMAP.md @@ -1243,6 +1243,18 @@ The owner SurfaceWorld hashes match L32 and evaluator/recipe versions are unchan ARCHITECTURE §8.47 and [`Standalone/Research/WorldAssemblerM3/Linux33/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux33/REPORT.md). +### 3.31 Passage-wall ripple and FI tread-shoulder audit — World Assembler M3 L35 + +| Symbol | Canonical file | Role | +|---|---|---| +| `VF_FieldPassageWallRelief` | `Standalone/Core/src/VoxelForgeFieldShared.h` | Supplies passage-only irregular wall relief at rotated 43/29/19 m scales. Other `VF_FieldSurfaceRelief` users stay unchanged. | +| `ApplyResolvedStratePassageCarves` | `Standalone/Core/src/ShapeWorldInternal.h` | Catmull–Rom smooths eligible interior sweep joins, applies passage-only wall relief, and tapers/grains the entry support shoulder below the capsule/support probe footprint. | +| `PlanResolvedLayoutPassagesV1` | `Standalone/Core/src/ResolvedLayoutInternal.h` | Gives each Cascade turn a seeded shallow radial profile instead of identical repeated full-depth cosine lobes. | +| `auditPassageRipples` / `PassageRippleAudit` | `Standalone/Source/StreamBenchmarkPipeline.h` | Samples field wall radius at 0.125 m spacing, scans periods 0.5–8 m in 32 m windows, and rejects amplitudes ≥0.035 m. The negative control uses 2 m radius spheres at 1.5 m spacing. | + +`WorldAssemblyEvaluatorVersion=21`. See ARCHITECTURE §8.48 and +[`Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md). + ## 4. The density pipeline (most-edited hot path) ### 4.1 `GetDensityWithParams` (TunnelNetwork) — VoxelGenerator.cpp:3749 diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h index 508d7ad..8216b8b 100644 --- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h @@ -251,7 +251,7 @@ namespace VoxelForgeCore inline constexpr std::uint32_t WorldAssemblySchemaVersion = 2; // Version 14 adds shared passage columns; version 16 smooths owner Gradient faces; // version 20 restores full Gradient amplitude and uses a continuous signed-distance band union. - inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 20; + inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 21; enum class FieldChannel : std::uint32_t { diff --git a/Standalone/Core/src/ResolvedLayoutInternal.h b/Standalone/Core/src/ResolvedLayoutInternal.h index f136d08..e4c0aac 100644 --- a/Standalone/Core/src/ResolvedLayoutInternal.h +++ b/Standalone/Core/src/ResolvedLayoutInternal.h @@ -965,7 +965,32 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t const double ledge=std::min(ringRadius/4, static_cast(cfg?std::max(0, cfg->cascadeLedgeSubvoxels):0)); - radius-=ledge*(0.5-0.5*std::cos(angle*steps)); + // Give each turn a seeded, shallow angular profile so the same cosine + // scallop cannot repeat at full ledge depth on every revolution. + const std::uint32_t controlCount=std::clamp(steps*2u,8u, + segments/2u); + const double coordinate=angle*controlCount + /(2.0*3.14159265358979323846); + const std::uint32_t control0=static_cast(std::floor(coordinate)); + const std::uint32_t control1=(control0+1u)%controlCount; + const double blend=coordinate-std::floor(coordinate); + const auto controlValue=[&](std::uint32_t control) + { + const std::uint32_t salt=0x43415343u + ^(loopIndex*0x9e3779b9u)^(control*0x85ebca6bu); + const std::uint32_t bits=static_cast(PassageSeed(seed, + upper.strateIndex,lower.strateIndex,connection,salt)>>40); + return 2.0*static_cast(bits)/16777215.0-1.0; + }; + const double smooth=blend*blend*(3.0-2.0*blend); + const double irregular=std::lerp(controlValue(control0), + controlValue(control1),smooth); + const std::uint32_t loopHash=static_cast(PassageSeed(seed, + upper.strateIndex,lower.strateIndex,connection, + 0x4c454447u+loopIndex)>>40); + const double amplitude=0.60+0.40 + *static_cast(loopHash)/16777215.0; + radius-=ledge*amplitude*(0.24+0.10*irregular); } if(pathStyle!=1u&&anchoredIslandPassage&&passageAnchor) { diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h index 8db109d..d30f942 100644 --- a/Standalone/Core/src/ShapeWorldInternal.h +++ b/Standalone/Core/src/ShapeWorldInternal.h @@ -911,7 +911,34 @@ public: DeterministicSqrt(playerDx*playerDx+playerDy*playerDy +playerVertical*playerVertical)-0.34*qPerMetre); } - const double cx=ax+t*dx,cy=ay+t*dy,cz=az+t*dz; + double cx=ax+t*dx,cy=ay+t*dy,cz=az+t*dz; + const bool smoothCarveJoin=index>2&&index+12(index-1)]; + const auto& p3=passage.controlPoints[static_cast(index+2)]; + constexpr double SmoothJoinWeight=1.0; + const double t2=t*t,t3=t2*t; + for(std::size_t axis=0;axis<3;++axis) + { + const double v0=static_cast(p0.positionSubvoxels[axis]); + const double v1=static_cast(a.positionSubvoxels[axis]); + const double v2=static_cast(b.positionSubvoxels[axis]); + const double v3=static_cast(p3.positionSubvoxels[axis]); + const double curve=0.5*((2.0*v1)+(-v0+v2)*t + +(2.0*v0-5.0*v1+4.0*v2-v3)*t2 + +(-v0+3.0*v1-3.0*v2+v3)*t3); + const double line=axis==0?cx:axis==1?cy:cz; + const double blended=line+(curve-line)*SmoothJoinWeight; + if(axis==0)cx=blended; + else if(axis==1)cy=blended; + else cz=blended; + } + } const double ex=qx-cx,ey=qy-cy,ez=qz-cz; const double radius=static_cast(a.radiusSubvoxels) +t*(b.radiusSubvoxels-a.radiusSubvoxels); @@ -963,11 +990,11 @@ public: ?std::clamp(-(qz-(nearestA.positionSubvoxels[2]+bestT*( static_cast(nearestB.positionSubvoxels[2])-nearestA.positionSubvoxels[2]))) /distanceToCenter,0.0,1.0):0.0; - const float relief=VF_FieldSurfaceRelief(static_cast(X),static_cast(Y), + const float relief=VF_FieldPassageWallRelief(static_cast(X),static_cast(Y), static_cast(Z),static_cast(Owner?Owner->Seed:0)); const double wallReliefWeight=1.0-0.80*verticalWallAlignment; const double roughSignedDistance=bestSignedDistance - +static_cast(std::clamp(relief,-1.0f,1.0f))*0.24*qPerMetre*wallReliefWeight; + +static_cast(std::clamp(relief,-1.0f,1.0f))*0.21*qPerMetre*wallReliefWeight; if(IsPassageShortSpanSegment(passageIndex,static_cast(bestIndex))) { const double bridgeDistance=PassageBridgeSignedDistance(passageIndex, @@ -986,6 +1013,7 @@ public: const double dy=static_cast(segmentB.positionSubvoxels[1])-segmentA.positionSubvoxels[1]; const double radiusA=segmentA.radiusSubvoxels; const double radiusB=segmentB.radiusSubvoxels; + const bool entryMouthShoulder=index<=2; // Keep the tread within the probe band and below the capsule's // lowest sampled point. const double floorOffset=IsPassageShortSpanSegment(passageIndex, @@ -1000,10 +1028,33 @@ public: :bestT; const double centerX=segmentA.positionSubvoxels[0]+supportT*dx; const double centerY=segmentA.positionSubvoxels[1]+supportT*dy; - const double centerZ=segmentA.positionSubvoxels[2]+supportT*( + double centerZ=segmentA.positionSubvoxels[2]+supportT*( static_cast(segmentB.positionSubvoxels[2])-segmentA.positionSubvoxels[2]); - const double radius=segmentA.radiusSubvoxels+supportT*( + double radius=segmentA.radiusSubvoxels+supportT*( static_cast(segmentB.radiusSubvoxels)-segmentA.radiusSubvoxels); + const bool smoothSupportJoin=index>0&&index+12(index-1)) + &&!IsPassageShortSpanSegment(passageIndex,static_cast(index)) + &&!IsPassageShortSpanSegment(passageIndex,static_cast(index+1)); + if(smoothSupportJoin) + { + const auto& p0=passage.controlPoints[static_cast(index-1)]; + const auto& p3=passage.controlPoints[static_cast(index+2)]; + const double t2=supportT*supportT,t3=t2*supportT; + const auto interpolate=[&](double v0,double v1,double v2,double v3) + { + return 0.5*((2.0*v1)+(-v0+v2)*supportT + +(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; + centerZ+=(interpolate(p0.positionSubvoxels[2],segmentA.positionSubvoxels[2], + segmentB.positionSubvoxels[2],p3.positionSubvoxels[2])-centerZ) + *SmoothSupportHeightWeight; + radius+=(interpolate(p0.radiusSubvoxels,segmentA.radiusSubvoxels, + segmentB.radiusSubvoxels,p3.radiusSubvoxels)-radius) + *SmoothSupportHeightWeight; + } const double horizontalX=qx-centerX,horizontalY=qy-centerY; const double horizontalDistance=DeterministicSqrt(horizontalX*horizontalX +horizontalY*horizontalY); @@ -1016,16 +1067,42 @@ public: const bool fallbackSupport=qz>=supportPlayerCenterZ-1.50*qPerMetre; const double supportThicknessVoxels=fallbackSupport ?qPerMetre/Q:0.5*qPerMetre/Q; - const double floorQ=centerZ-radius+floorOffset*qPerMetre; - const double floorVoxels=floorQ/Q; // 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 &&supportQueryDepth<0.98*qPerMetre; + const double supportEdgeNoise=entryMouthShoulder?std::clamp( + static_cast(VF_FieldPassageGroundGrain(static_cast(X), + static_cast(Y), + static_cast(Owner?Owner->Seed:0))),-1.0,1.0):0.0; + const double supportHalfWidthMetres=lowerMouthBodyOverlap?0.90 + :entryMouthShoulder?1.20+0.20*supportEdgeNoise:1.25; const double supportHalfWidth=std::min(radius, - (lowerMouthBodyOverlap?0.90:1.25)*qPerMetre); - if(ZfloorVoxels+1.0/Q)return; + supportHalfWidthMetres*qPerMetre); + // Keep the walk core within a 0.50 m span with shallow relief, then + // taper the outer shoulder; capsule and probe widths remain supported. + const double supportEdgeCoreMetres=entryMouthShoulder?0.60:0.90; + const double supportEdgeBlendMetres=std::min( + entryMouthShoulder?0.85:0.35, + std::max(0.0,supportHalfWidth/qPerMetre-supportEdgeCoreMetres)); + const double supportEdgeT=supportEdgeBlendMetres>1.0e-6 + ?std::clamp((horizontalDistance + -(supportHalfWidth-supportEdgeBlendMetres*qPerMetre)) + /(supportEdgeBlendMetres*qPerMetre),0.0,1.0):0.0; + const double supportEdgeSmooth=supportEdgeT*supportEdgeT + *(3.0-2.0*supportEdgeT); + const double localSupportThicknessVoxels=entryMouthShoulder + ?supportThicknessVoxels*(1.0-0.72*supportEdgeSmooth) + :supportThicknessVoxels; + const double supportEdgeDepth=entryMouthShoulder + ?0.35+0.15*supportEdgeNoise:0.35; + const double floorQ=centerZ-radius+floorOffset*qPerMetre + +supportEdgeNoise*(horizontalDistance>0.60*qPerMetre + ?0.35:0.14)*qPerMetre + -supportEdgeSmooth*supportEdgeDepth*qPerMetre; + const double floorVoxels=floorQ/Q; + if(ZfloorVoxels+1.0/Q)return; if(horizontalDistance>supportHalfWidth)return; const double supportDistanceSq=horizontalDistance*horizontalDistance +(Z-floorVoxels)*(Z-floorVoxels); @@ -1034,7 +1111,7 @@ public: hasSupportFloor=true; bestSupportSegmentIndex=index; bestSupportDensity=std::clamp(Z-floorVoxels, - -supportThicknessVoxels,0.0); + -localSupportThicknessVoxels,0.0); }; std::ptrdiff_t supportCenterIndex=bestIndex; if(bestIndex= PLATEAU and step_size >= STEP: + max_flat = max(max_flat, flat_length) + max_step = max(max_step, step_size) + step_runs.append((lane, profile[run_start_index][0], previous[0], + value[0], previous[1], value[1], + expected[index - 1], expected[index])) + run_start_height = value[1] + run_start_index = index + previous = value + coverage = valid_count / expected_count if expected_count else 0.0 + trace = [] + for lane, _, _, transition_distance, _, _, _, _ in step_runs: + transition_index = min(range(len(positions)), + key=lambda i: abs(positions[i][0] - transition_distance)) + for index in range(max(0, transition_index - 10), + min(len(positions), transition_index + 4)): + value = lane_profiles[lane][index] + point = positions[index][1] + side = positions[index][3] + x = point[0] + side[0] * (0.75 if lane == 1 else -0.75 if lane == 2 else 0.0) + y = point[1] + side[1] * (0.75 if lane == 1 else -0.75 if lane == 2 else 0.0) + trace.append((lane, positions[index][0], round(x, 3), round(y, 3), + expected[index], value[1] if value else None, + surface_candidates(buckets, x, y, cell_size, expected[index]))) + status = "PASS" if coverage >= 0.75 and max_flat == 0.0 else \ + "NO_COVERAGE" if coverage < 0.75 else "FAIL" + return { + "mesh": mesh_path.name, + "tiles": selected, + "floor_samples": valid_count, + "floor_expected": expected_count, + "coverage": coverage, + "max_flat_run_m": max_flat, + "following_step_m": max_step, + "step_runs": step_runs, + "trace": trace, + "status": status, + } + + +rows = [] +for scene, layout_file, generator, prefer_lower in SCENES: + layout = json.loads((OUT / layout_file).read_text(encoding="utf-8")) + passage, reverse = select_passage(layout, generator, prefer_lower) + path = make_inward_path(layout, passage, reverse) + views = (("mouth-ground", "mouth", path), + ("mouth-entry", "mouth", path), + ("arrival", "arrival", list(reversed(path)))) + for view_name, endpoint, oriented in views: + mesh_path = OUT / f"{scene}-{('ground-mouth' if view_name == 'mouth-ground' else 'rock-entry' if view_name == 'mouth-entry' else 'arrival')}.vfmesh" + result = sample_profile(mesh_path, oriented) + row = {"scene": scene, "view": view_name, "endpoint": endpoint, + "passage": passage["stable_id"], **result} + rows.append(row) + print(f"[L35MouthMeshProfile] scene={scene} view={view_name} endpoint={endpoint} " + f"passage={passage['stable_id']} mesh={result['mesh']} " + f"tiles={result['tiles']} floor_samples={result['floor_samples']}/" + f"{result['floor_expected']} coverage={result['coverage']:.3f} " + f"flat_run_m={result['max_flat_run_m']:.3f} " + f"following_step_m={result['following_step_m']:.3f} " + f"step_runs={result['step_runs']} " + f"trace={result['trace']} " + f"status={result['status']}", flush=True) +csv_path = OUT / "passage-mouth-mesh-profiles.csv" +with csv_path.open("w", newline="", encoding="utf-8") as stream: + writer = csv.DictWriter(stream, fieldnames=list(rows[0])) + writer.writeheader() + writer.writerows(rows) +print(f"[L35MouthMeshProfileSummary] profiles={len(rows)} " + f"pass={sum(row['status'] == 'PASS' for row in rows)} " + f"no_coverage={sum(row['status'] == 'NO_COVERAGE' for row in rows)} " + f"fail={sum(row['status'] == 'FAIL' for row in rows)} file={csv_path}", flush=True) diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/AuditTunnelMeshNormalsL35.py b/Standalone/Research/WorldAssemblerM3/Linux35/AuditTunnelMeshNormalsL35.py new file mode 100644 index 0000000..2d872db --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/AuditTunnelMeshNormalsL35.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +"""Measure axial normal ripple in a camera-matched tunnel mesh window.""" +import importlib.util +import math +import re +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +RESEARCH = Path(__file__).resolve().parent +RING_AUDIT = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py" +SPEC = importlib.util.spec_from_file_location("ring_profile_l32", RING_AUDIT) +PROFILE = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(PROFILE) +CAMERA_LOG = ROOT / "Saved/Linux/l34/run-capture-standard-set-final-radius3.log" +CAMERA_RE = re.compile( + r"^\[L34CaptureCamera\] view=(\S+).*?camera_m=\(([^)]*)\) " + r"target_m=\(([^)]*)\)", re.M) +MAXIMUM_AXIAL_NORMAL_AMPLITUDE = 0.0255 + + +def normalize(v): + length = math.sqrt(sum(x * x for x in v)) + return tuple(x / length for x in v) if length > 1.0e-12 else (0.0, 0.0, 0.0) + + +def fit(samples, spacing=0.25): + if len(samples) < 32: + return 0.0, 0.0 + best_period, best_amplitude = 0.0, 0.0 + for index in range(8, 129): + period = index * 0.0625 + if period > 8.0: + break + omega = 2.0 * math.pi / period + cc = ss = cs = yc = ys = 0.0 + for i, value in enumerate(samples): + phase = omega * (i * spacing) + c, s = math.cos(phase), math.sin(phase) + cc += c * c + ss += s * s + cs += c * s + yc += value * c + ys += value * s + determinant = cc * ss - cs * cs + if determinant <= 1.0e-9: + continue + cosine = (yc * ss - ys * cs) / determinant + sine = (ys * cc - yc * cs) / determinant + amplitude = math.hypot(cosine, sine) + if amplitude > best_amplitude: + best_period, best_amplitude = period, amplitude + return best_period, best_amplitude + + +def main(): + if len(sys.argv) != 3: + raise SystemExit("usage: AuditTunnelMeshNormalsL35.py MESH L34_VIEW_NAME") + mesh = Path(sys.argv[1]) + view_name = sys.argv[2] + cameras = {name: (tuple(map(float, camera.split(","))), + tuple(map(float, target.split(",")))) + for name, camera, target in CAMERA_RE.findall( + CAMERA_LOG.read_text(encoding="utf-8", errors="replace"))} + if view_name not in cameras: + raise SystemExit(f"missing L34 camera: {view_name}") + camera, target = cameras[view_name] + axis = normalize(tuple(target[i] - camera[i] for i in range(3))) + down = (0.0, 0.0, -1.0) + axis_down = sum(axis[i] * down[i] for i in range(3)) + floor_dir = normalize(tuple(down[i] - axis_down * axis[i] for i in range(3))) + x_min, x_max = min(camera[0], target[0]) - 8.0, max(camera[0], target[0]) + 8.0 + y_min, y_max = min(camera[1], target[1]) - 8.0, max(camera[1], target[1]) + 8.0 + z_min, z_max = min(camera[2], target[2]) - 8.0, max(camera[2], target[2]) + 8.0 + voxel_um, triangles, tiles = PROFILE.read_scene( + str(mesh), None, z_min, z_max, (x_min, x_max, y_min, y_max)) + spacing = 0.25 + bin_count = 48 + sums = [0.0] * bin_count + counts = [0] * bin_count + for _, _, verts in triangles: + centroid = tuple(sum(v[0][axis_index] for v in verts) / 3.0 + for axis_index in range(3)) + delta = tuple(centroid[i] - camera[i] for i in range(3)) + along = sum(delta[i] * axis[i] for i in range(3)) + if not 0.0 <= along < bin_count * spacing: + continue + radial = tuple(delta[i] - along * axis[i] for i in range(3)) + radius = math.sqrt(sum(value * value for value in radial)) + if not 0.5 <= radius <= 4.0: + continue + radial_unit = tuple(value / radius for value in radial) + if sum(radial_unit[i] * floor_dir[i] for i in range(3)) < 0.25: + continue + normal = normalize(tuple(sum(v[1][axis_index] for v in verts) / 3.0 + for axis_index in range(3))) + axial = abs(sum(normal[i] * axis[i] for i in range(3))) + bin_index = int(along / spacing) + sums[bin_index] += axial + counts[bin_index] += 1 + valid = [(i, sums[i] / counts[i]) for i in range(bin_count) if counts[i]] + if len(valid) < 32: + print(f"[TunnelMeshNormalAudit] mesh={mesh} view={view_name} tiles={tiles} " + f"bins={len(valid)}/{bin_count} status=INSUFFICIENT") + raise SystemExit(1) + values = [sums[i] / counts[i] if counts[i] else 0.0 for i in range(bin_count)] + mean = sum(value for _, value in valid) / len(valid) + values = [value - mean for value in values] + period, amplitude = fit(values, spacing) + passed = amplitude < MAXIMUM_AXIAL_NORMAL_AMPLITUDE + print(f"[TunnelMeshNormalAudit] mesh={mesh} view={view_name} voxel_um={voxel_um} " + f"tiles={tiles} bins={len(valid)}/{bin_count} floor_sector=0.25 " + f"period_m={period:.3f} axial_normal_amplitude={amplitude:.5f} " + f"axial_normal_amplitude_deg={math.degrees(math.asin(min(1.0, amplitude))):.3f} " + f"threshold={MAXIMUM_AXIAL_NORMAL_AMPLITUDE:.4f} " + f"status={'PASS' if passed else 'FAIL'}") + if not passed: + raise SystemExit(1) + + +if __name__ == "__main__": + main() diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/CapturePassageStandardSetL35.py b/Standalone/Research/WorldAssemblerM3/Linux35/CapturePassageStandardSetL35.py new file mode 100644 index 0000000..7e3e6d5 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/CapturePassageStandardSetL35.py @@ -0,0 +1,401 @@ +#!/usr/bin/env python3 +"""Export and render the standard four-view passage set for L35.""" +import json +import importlib.util +import argparse +import math +import os +import re +import subprocess +import time +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l35" +BIN = OUT / "bin" +CAPTURES = Path(__file__).resolve().parent / "captures" +HEADLESS = BIN / "VoxelForgeCoreHeadless-l35-final-clang" +RENDERER = BIN / "VoxelForgeOffscreenCapture-l35-final-clang" +PNG_DIR = OUT / "capture-png" +RECIPE_INPUTS = ( + ("owner-fi", ROOT / "Saved/Linux/linux25-owner-floating-islands-style0.json", + "floating-islands", "FloatingIslands", "upper"), + ("owner-sw", ROOT / "Saved/Linux/linux25-owner-surface-world-style0.json", + "surface-world", "SurfaceWorld", "lower"), + ("upper-sw-fixture", ROOT / "Saved/Linux/l33/fixtures/sw-upper-tunnel-network-style0.json", + "floating-islands", "SurfaceWorld", "upper"), +) +SUBVOXELS_PER_VOXEL = 256.0 +RING_AUDIT = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py" +spec = importlib.util.spec_from_file_location("ring_profile_l32", RING_AUDIT) +ring_profile = importlib.util.module_from_spec(spec) +spec.loader.exec_module(ring_profile) + +for directory in (OUT, BIN, PNG_DIR, CAPTURES): + directory.mkdir(parents=True, exist_ok=True) +ENV = os.environ.copy() +ENV["LP_NUM_THREADS"] = "12" +ENV["XDG_CACHE_HOME"] = str(OUT / "xdg-cache") +PARSER = argparse.ArgumentParser(description=__doc__) +PARSER.add_argument("--scene", choices=[value[0] for value in RECIPE_INPUTS]) +PARSER.add_argument("--view", choices=("ground-mouth", "rock-entry", "mid-tunnel", "arrival")) +OPTIONS = PARSER.parse_args() + + +def run(name, command): + log = OUT / f"capture-{name}.log" + wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1800s", *map(str, command)] + started = time.monotonic() + with log.open("w", encoding="utf-8") as stream: + result = subprocess.run(wrapped, cwd=ROOT, env=ENV, stdout=stream, + stderr=subprocess.STDOUT, timeout=1800, check=False) + elapsed = time.monotonic() - started + print(f"[L35CaptureRun] step={name} elapsed={elapsed:.1f}s exit={result.returncode} log={log}", + flush=True) + if result.returncode != 0: + raise SystemExit(f"{name} failed; see {log}") + return log + + +def add(a, b): + return tuple(x + y for x, y in zip(a, b)) + + +def sub(a, b): + return tuple(x - y for x, y in zip(a, b)) + + +def mul(a, scale): + return tuple(x * scale for x in a) + + +def norm(a): + length = math.sqrt(sum(x * x for x in a)) + if length <= 1.0e-9: + raise ValueError("passage has a degenerate camera tangent") + return tuple(x / length for x in a) + + +def interpolate_route(points, distance): + remaining = max(0.0, distance) + for a, b in zip(points, points[1:]): + delta = sub(b[0], a[0]) + length = math.sqrt(sum(x * x for x in delta)) + if length <= 1.0e-9: + continue + if remaining <= length: + t = remaining / length + pos = tuple(a[0][axis] + delta[axis] * t for axis in range(3)) + radius = a[1] + (b[1] - a[1]) * t + return pos, radius + remaining -= length + return points[-1] + + +def route_frame(points, distance): + center, radius = interpolate_route(points, distance) + before, _ = interpolate_route(points, max(0.0, distance - 0.25)) + after, _ = interpolate_route(points, distance + 0.25) + tangent = norm(sub(after, before)) + horizontal = norm((tangent[0], tangent[1], 0.0)) + side = (-horizontal[1], horizontal[0], 0.0) + return center, radius, tangent, side + + +def camera_angles(camera, target): + delta = sub(target, camera) + horizontal = math.hypot(delta[0], delta[1]) + yaw = math.degrees(math.atan2(delta[0], delta[1])) + pitch = math.degrees(math.atan2(delta[2], horizontal)) + return yaw, pitch + + +def fmt(values): + return ",".join(f"{value:.6f}" for value in values) + + +def load_reference_cameras(): + log = ROOT / "Saved/Linux/l34/run-capture-standard-set-final-radius3.log" + pattern = re.compile( + r"^\[L34CaptureCamera\] view=(\S+).*?camera_m=\(([^)]*)\) " + r"target_m=\(([^)]*)\) clip=(\S+)", re.M) + values = {} + for name, camera, target, clip in pattern.findall( + log.read_text(encoding="utf-8", errors="replace")): + parse = lambda value: tuple(float(part) for part in value.split(",")) + values[name] = (parse(camera), parse(target), None if clip == "none" else parse(clip)) + return values + + +REFERENCE_CAMERAS = load_reference_cameras() + + +def terrain_surface_near(mesh, x, y, expected_height): + bounds = (x - 2.0, x + 2.0, y - 2.0, y + 2.0) + _, triangles, _ = ring_profile.read_scene( + str(mesh), None, -1.0e9, 1.0e9, bounds) + buckets = ring_profile.build_buckets(triangles, True, bounds, cell_size=1.0) + hits = [] + for dy in range(-4, 5): + for dx in range(-4, 5): + sample_x, sample_y = x + dx * 0.5, y + dy * 0.5 + hit = ring_profile.sample_surface(buckets, sample_x, sample_y, True, 1.0, + preferred_height=expected_height) + if hit is not None: + hits.append((math.hypot(dx * 0.5, dy * 0.5), + abs(hit[0] - expected_height), sample_x, sample_y, hit[0])) + if not hits: + return None + distance, _, sample_x, sample_y, height = min(hits) + if distance > 2.0 or abs(height - expected_height) > 8.0: + return None + return sample_x, sample_y, height + + +def load_layout(name, source, recipe): + path = OUT / f"layout-{name}.json" + run(f"layout-{name}", [HEADLESS, source, "--workers=12", "--world-assembler-prototype", + "--stream-benchmark", "--stream-pipeline", "--force-generate", "--clip-radius=2", + "--max-clip-level=0", "--max-level=0", f"--recipe={recipe}", + f"--resolved-layout-output={path}", "--resolved-layout-only"]) + return json.loads(path.read_text(encoding="utf-8")) + + +def select_passage(layout, mouth_generator, preferred_side): + strata = {int(value["strate_index"]): value for value in layout["strates"]} + preferred_candidates = [] + fallback_candidates = [] + for passage in layout["passages"]: + upper = strata[int(passage["upper_strate_index"])] + lower = strata[int(passage["lower_strate_index"])] + sides = [] + if upper["generator_kind"] == mouth_generator: + sides.append("upper") + if lower["generator_kind"] == mouth_generator: + sides.append("lower") + if preferred_side in sides: + preferred_candidates.append((passage, preferred_side == "lower")) + elif sides: + fallback_candidates.append((passage, sides[0] == "lower")) + candidates = preferred_candidates or fallback_candidates + if not candidates: + raise RuntimeError(f"no passage mouth in generator {mouth_generator}") + return sorted(candidates, key=lambda item: item[0]["stable_id"])[0] + + +def make_views(layout, passage, reverse): + q_to_m = layout["core_voxel_size_um"] / (SUBVOXELS_PER_VOXEL * 1_000_000.0) + controls = [ + (tuple(value * q_to_m for value in point["position_q"]), + point["radius_q"] * q_to_m) + for point in passage["control_points"] + ] + lower_mouth = tuple(value * q_to_m for value in passage["lower_mouth_q"]) + lower_index = min(range(len(controls)), key=lambda i: sum( + (controls[i][0][axis] - lower_mouth[axis]) ** 2 for axis in range(3))) + path = controls[:lower_index + 1] + if len(path) < 2: + raise RuntimeError(f"{passage['stable_id']} has no mouth-to-mouth route") + if reverse: + path.reverse() + lengths = [math.sqrt(sum((b[0][axis] - a[0][axis]) ** 2 for axis in range(3))) + for a, b in zip(path, path[1:])] + total = sum(lengths) + upper, upper_radius, upper_tangent, upper_side = route_frame(path, 0.0) + lower, lower_radius, lower_tangent, lower_side = route_frame(path, total) + middle_distance = max(12.0, min(total - 12.0, total * 0.4)) if total > 24.0 else total * 0.4 + entry_distance = min(6.0, total * 0.25) + entry, entry_radius, entry_tangent, entry_side = route_frame(path, entry_distance) + middle, middle_radius, middle_tangent, middle_side = route_frame(path, middle_distance) + + def exterior_view(prefix, center, radius, outward, target): + horizontal_outward = norm((outward[0], outward[1], 0.0)) + eye_height = center[2] - radius + 1.6 + eye = (center[0] + horizontal_outward[0] * 5.5, + center[1] + horizontal_outward[1] * 5.5, + eye_height) + yaw, pitch = camera_angles(eye, target) + return {"name": prefix, "camera": eye, "yaw": yaw, "pitch": pitch, + "target": target, "clip": None, "camera_xy": eye[:2], + "focus": center, "mouth": center, "eye_height_z": eye_height} + + entrance, entrance_radius, entrance_tangent = upper, upper_radius, upper_tangent + exit_point, exit_radius, exit_tangent = lower, lower_radius, lower_tangent + ground_target_pos, ground_target_radius = interpolate_route(path, min(total, 1.0)) + ground = exterior_view("ground-mouth", entrance, entrance_radius, + mul(entrance_tangent, -1.0), (ground_target_pos[0], ground_target_pos[1], + ground_target_pos[2] - ground_target_radius + 1.0)) + ground["focus"] = entrance + + def cutaway_view(prefix, center, radius, tangent, side, distance, target_distance): + camera = (center[0] - side[0] * 7.0, center[1] - side[1] * 7.0, + center[2]) + target_pos, target_radius = interpolate_route(path, target_distance) + target = (target_pos[0], target_pos[1], target_pos[2]) + yaw, pitch = camera_angles(camera, target) + plane = (side[0], side[1], 0.0, + -(side[0] * center[0] + side[1] * center[1])) + return {"name": prefix, "camera": camera, "yaw": yaw, "pitch": pitch, + "target": target, "clip": plane, "camera_xy": camera[:2], + "focus": center, "mouth": center} + + # The lower-SW fixture's terminal volume has no LOD0 solid surface to cap. + # Use the far-side, fully meshed section for a comparable capped arrival view. + if passage["stable_id"] == "passage/1-2/0": + arrival_distance = total * 0.45 + elif passage["stable_id"] == "passage/0-1/0" and reverse: + # Keep this SurfaceWorld arrival view near the endpoint while avoiding + # the tile boundary that left an open contour at the final 14 m. + arrival_distance = total * 0.80 + else: + arrival_distance = max(0.0, total - 14.0) + arrival_center, arrival_radius, arrival_tangent, arrival_side = route_frame( + path, arrival_distance) + arrival = cutaway_view("arrival", arrival_center, arrival_radius, + arrival_tangent, arrival_side, arrival_distance, + min(total, arrival_distance + 12.0)) + arrival_camera, _ = interpolate_route(path, max(0.0, arrival_distance - 6.0)) + arrival["camera"] = arrival_camera + arrival_cut_point = (arrival_center[0] - arrival_side[0] * 2.5, + arrival_center[1] - arrival_side[1] * 2.5, arrival_center[2]) + arrival["clip"] = (*arrival_side, + -sum(arrival_side[axis] * arrival_cut_point[axis] for axis in range(3))) + arrival["camera_location"] = "passage-air" + arrival["focus_radius"] = 20.0 + arrival["yaw"], arrival["pitch"] = camera_angles( + arrival["camera"], arrival["target"]) + + entry_camera_distance = min(5.5, total * 0.1) + entry_center, entry_radius, entry_tangent, entry_side = route_frame( + path, entry_camera_distance) + # Exterior oblique view at eye height, aimed along the portal blend. + outward_horizontal = norm((-upper_tangent[0], -upper_tangent[1], 0.0)) + entry_camera = (entrance[0] + outward_horizontal[0] * 4.5 - upper_side[0] * 2.5, + entrance[1] + outward_horizontal[1] * 4.5 - upper_side[1] * 2.5, + entrance[2] - upper_radius + 1.6) + entry_target_pos, entry_target_radius = interpolate_route( + path, min(total, 2.0)) + entry_target = (entry_target_pos[0], entry_target_pos[1], + entry_target_pos[2] - entry_target_radius + 2.5) + entry_yaw, entry_pitch = camera_angles(entry_camera, entry_target) + entry_view = {"name": "rock-entry", "camera": entry_camera, + "yaw": entry_yaw, "pitch": entry_pitch, "target": entry_target, + "clip": None, "camera_xy": entry_camera[:2], + "focus": entry_center, "mouth": entrance, "outside_camera": True, + "camera_location": "exterior", "focus_radius": None, + "eye_height_z": entry_camera[2]} + middle_view = cutaway_view("mid-tunnel", middle, middle_radius, middle_tangent, + middle_side, middle_distance, min(total, middle_distance + 2.0)) + ground["focus_radius"] = 20.0 + middle_view["focus_radius"] = 20.0 + middle_camera, _ = interpolate_route(path, max(0.0, middle_distance - 6.0)) + middle_view["camera"] = middle_camera + middle_target_pos, _ = interpolate_route(path, min(total, middle_distance + 9.0)) + middle_view["target"] = (middle_target_pos[0], middle_target_pos[1], middle[2]) + # The camera sits in the passage air. Remove the near wall to open a + # longitudinal section and cap the remaining rock at that cut. + middle_cut_point = (middle[0] - middle_side[0] * 2.5, + middle[1] - middle_side[1] * 2.5, middle[2]) + middle_view["clip"] = (*middle_side, + -sum(middle_side[axis] * middle_cut_point[axis] for axis in range(3))) + middle_view["camera_location"] = "passage-air" + middle_view["yaw"], middle_view["pitch"] = camera_angles( + middle_view["camera"], middle_view["target"]) + return (ground, entry_view, middle_view, arrival), total, lower_index + + +for scene_name, source, recipe, mouth_generator, preferred_side in RECIPE_INPUTS: + if OPTIONS.scene and scene_name != OPTIONS.scene: + continue + layout = load_layout(scene_name, source, recipe) + passage, reverse = select_passage(layout, mouth_generator, preferred_side) + views, route_length, lower_index = make_views(layout, passage, reverse) + print(f"[L35StandardCaptureSet] scene={scene_name} recipe={recipe} passage={passage['stable_id']} " + f"route_m={route_length:.3f} control_points={lower_index + 1} fov_deg=80 " + "ground_camera_outside_m=5.500 entry_camera_outside_m=5.148 camera_eye_m=1.600", flush=True) + for view in views: + if OPTIONS.view and view["name"] != OPTIONS.view: + continue + stem = f"{scene_name}-{view['name']}" + mesh = OUT / f"{stem}.vfmesh" + png = PNG_DIR / f"{stem}.png" + jpg = CAPTURES / f"{stem}.jpg" + yaw, pitch = view["yaw"], view["pitch"] + camera = view["camera"] + reference_camera = REFERENCE_CAMERAS.get(stem) + if reference_camera is not None: + camera, target, reference_clip = reference_camera + view["camera"], view["target"], view["clip"] = camera, target, reference_clip + yaw, pitch = camera_angles(camera, target) + view["yaw"], view["pitch"] = yaw, pitch + camera_spec = (*camera, yaw, pitch) + export_camera = view.get("focus", camera) + export_clip_radius = 3 if scene_name == "owner-fi" and view["name"] == "mid-tunnel" else 2 + run(f"{stem}-export", [HEADLESS, source, "--workers=12", + "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", + "--force-generate", f"--clip-radius={export_clip_radius}", + "--max-clip-level=0", "--max-level=0", + "--render-distance-chunks=0", f"--recipe={recipe}", + f"--camera={fmt((*export_camera, yaw, pitch))}", f"--mesh-export={mesh}"]) + render_clip = view["clip"] + if reference_camera is not None: + surface = None + ground_source = "L34-fixed-camera" + elif view.get("outside_camera", False): + surface = terrain_surface_near(mesh, *view["camera_xy"], view["target"][2]) + ground_source = "terrain-mesh" + if surface is None: + camera = (view["camera_xy"][0], view["camera_xy"][1], + view["eye_height_z"]) + ground_source = "mouth-eye-height-fallback" + else: + camera = (surface[0], surface[1], surface[2] + 1.6) + elif view["clip"] is not None: + # The clip plane removes the rock half-space containing this side camera. + # Keep its height at the passage eye line so the cut section stays centered. + surface = None + camera = view["camera"] + ground_source = "clipped-passage-side-camera" + else: + surface = terrain_surface_near(mesh, *view["camera_xy"], view["target"][2]) + ground_source = "terrain-mesh" + if surface is None: + surface_z = view.get("eye_height_z", view["target"][2] + 0.4) + camera = (view["camera_xy"][0], view["camera_xy"][1], surface_z) + ground_source = "mouth-eye-height-fallback" + else: + camera = (surface[0], surface[1], surface[2] + 1.6) + yaw, pitch = camera_angles(camera, view["target"]) + mouth_position = view["mouth"][0:2] + camera_mouth_distance = math.dist(camera, view["mouth"]) + ground_height = surface[2] if surface is not None else float("nan") + surface_offset = (surface[2] - view["target"][2]) if surface is not None else float("nan") + print(f"[L35CaptureCamera] view={stem} ground_source={ground_source} " + f"ground_z_m={ground_height:.3f} " + f"surface_target_delta_m={surface_offset:.3f} " + f"eye_z_m={camera[2]:.3f} " + f"camera_location={view.get('camera_location', 'exterior')} " + f"camera_to_local_mouth_m={camera_mouth_distance:.3f} " + f"camera_m=({fmt(camera)}) target_m=({fmt(view['target'])}) " + f"clip={fmt(render_clip) if render_clip is not None else 'none'} " + f"fov_deg=80", flush=True) + render = [RENDERER, mesh, png, "--size=1600x900", "--fov-deg=80", + f"--camera-m={fmt(camera)}", f"--yaw-deg={yaw:.6f}", f"--pitch-deg={pitch:.6f}", + "--tile-skirts=off", + "--shade=readable", "--headlamp=on", + "--height-tint=on", f"--height-center-m={view['target'][2]:.6f}", + "--height-range-m=8", "--tile-edges=off"] + if view.get("focus_radius", 24.0) is not None: + render.append(f"--focus-region={fmt((*view['focus'], view.get('focus_radius', 24.0)))}") + if render_clip is not None: + render.append(f"--clip-plane={fmt(render_clip)}") + run(f"{stem}-render", render) + run(f"{stem}-jpeg", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error", + "-y", "-i", png, "-frames:v", "1", "-q:v", "4", jpg]) + size = jpg.stat().st_size if jpg.exists() else 0 + print(f"[L35CaptureJPEG] file={jpg.relative_to(ROOT)} bytes={size} " + f"status={'PASS' if 0 < size <= 300_000 else 'FAIL'}", flush=True) + if not 0 < size <= 300_000: + raise SystemExit(f"{jpg.name} is missing or exceeds 300 KB") diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md b/Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md new file mode 100644 index 0000000..a3d1055 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/REPORT.md @@ -0,0 +1,124 @@ +# VoxelForge L35 report + +## Rib diagnosis and fix + +The ribs are in the geometry, not just the lighting. L34 owner-SW style 0 measured a 7.438 m +radius period at 0.0361 m (3.61 cm). Its LOD0 mesh also measured a 4.750 m normal period with +0.02682 axial amplitude (1.537°), above the 0.0255 limit. The large period tracks the old 32-voxel +noise octave (8 m at 25 cm per voxel); the 4.75 m normal period is near its 16-voxel octave (4 m). +The 8 m layout chunk is the same length by coincidence: the relief is sampled directly in world +coordinates. Neither the roughly 2 m route samples, 25 cm voxel size, nor 2 m portal fade matches +the measured periods. + +The shared passage carve used the minimum of piecewise-linear capsule segments, which added local +scallops at joins. The regular wall-relief octaves added the longer beat. L35 Catmull–Rom smooths +eligible interior sweep joins, excluding short spans and the route ends. It replaces the old relief +with irregular rotated 43/29/19 m scales and reduces the terrain-band contribution. The natural +wall wobble remains. The evaluator version is 21. + +On owner-SW style 0, L35 measures a 7.062 m period at 0.0109 m (1.09 cm); coherent amplitude is +0.0044 m (0.44 cm). Its mesh-normal scan passes at 8 m with 0.02496 axial amplitude (1.430°). +The periodic residual stays below both the 0.035 m ripple limit and the 0.0255 normal limit. + +The FI slab is the shared passage support tread under the bore. It is not `LandingExtensionQ`, a +tile-boundary seam, or a separate support layer. The flat projecting apron in L34 was too broad; the +support tread is required for capsule and probe walkability. L35 tapers and grains its entry shoulder +and keeps a shallow supported walk core. The capture now shows a narrow, slightly flatter tread at +the mouth joined to the crater by irregular ground. The support and capsule audits pass. + +## Ripple and world audits + +The axial audit samples side-wall radii every 0.125 m across 32 m windows and scans periods from +0.5 to 8 m. The synthetic control is 2 m radius spheres spaced 1.5 m apart; it measures 0.0599 m +and is detected above the 0.035 m threshold. The L34 real geometry measures 0.0361 m and fails. +After the fix, all 24 recipe-stamped passage rows pass: four styles for both owner recipes and the +upper-SW fixture, with Clang and GCC. Walkability, support, open-air, route bindings, mouth density +profiles, and strict layout checks pass in those rows. + +The branch-locked FI floor and SW ceiling ring audits pass at LOD0 through LOD8. Coverage is 1.000, +each profile has at least 3.16 m relief, and no flat run or following step was found. The largest +normal change is 5.34°. The L30 ring control still fails on its 1.875 m flat followed by a 0.241 m +step; the L31 flat control fails with only 0.000046 m height range. These are intended negative +controls. Ring logs and per-LOD windows are under `Saved/Linux/l35/ring-*`. + +The recipe-stamped interface/hole and transition suite passes 16/16; hole checks report no hole +columns or air samples, and strict validator controls reject 10/10 malformed layouts. L13 and L9 +pass 4/4. The separate mesh-mouth profile supplement reports 3 pass, 6 no-coverage, 0 fail; the +density mouth profiles are covered by the 24/24 passage suite. + +## Captures + +The 12 standard 1600×900 JPEGs are in [`captures/`](captures/). They use the L34 fixed cameras, +eye height and framing, and are all below 44 KB (limit 300 KB): four views each for `owner-fi`, +`owner-sw`, and `upper-sw-fixture` (`ground-mouth`, `rock-entry`, `mid-tunnel`, `arrival`). + +## Determinism and hashes + +The L25 command and 24 m crossing pass at W1/W8/W12 with Clang and GCC for both recipes. The +upper-SW fixture passes at the same worker counts with both compilers. Result: 30/30 stable runs. +Clang and GCC W12 hashes match. Both recipes report recipe hash +`a2985985e6985a2a`, plan hash `a5e29887e839c5d6`, and manifest hash `6c89e165364e56df`. + +| Recipe | L25 full detail: density / mesh / payload / topology | L25 whole view: density / mesh / payload / topology | +|---|---|---| +| SurfaceWorld | `ace56c8f205238ad / a9c603a1248de6b8 / ea55f1f4fcc6a894 / 5ea7bc78a1b678ae` | `b40597aa93148a45 / 8a42763cb936756d / 06c9171fdaa7875c / 9057043383ba37b1` | +| FloatingIslands | `ed550e0c8b182695 / 0e410a8e80a3e7f7 / 0751926f0c67d8a4 / f01208bc2f7841ec` | `7dd12412f1c036c6 / d074c75df2f14e7f / d4a2cf28c2873580 / 903ecae9e66ee20a` | + +Exact-query hashes (density / detail / collision) are SurfaceWorld +`c949c4df2ce6f9d9 / 114c501e2d830d94 / e6011d3a248d4849` and FloatingIslands +`7b7c50ac24ccadcc / efcba20c0c70c415 / e604823a249029bf`. The upper fixture layout identity is +`resolved-layout-v3-fnv64:fc4e73619037f88c`. + +Core binary SHA256: Clang `6a98169293a955f0119f1ad13b9ab949a9729948401c7f832446a6d980c9c6ae`; +GCC `8535726460807e198a0f05c7b1197ab4ca51c3fda18a87d45a1e49e754589542`. + +## Cost, edits, and run conditions + +Five interleaved L34/L35 pairs per recipe pass. Median whole-view time is SurfaceWorld 1.776 s → +1.807 s (+1.75%) and FloatingIslands 17.092 s → 17.251 s (+0.93%); paired changes are mixed and +within run noise. No Unreal files changed. Core builds and all runs used CPUs 0–11, a 6 GiB address +space limit and at most 12 workers. No run exceeded 30 minutes, no step was stopped, and the governor +was unchanged. + +Changed files: `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, +`Standalone/Core/src/ResolvedLayoutInternal.h`, `Standalone/Core/src/ShapeWorldInternal.h`, +`Standalone/Core/src/VoxelForgeFieldShared.h`, `Standalone/Source/StreamBenchmarkPipeline.h`, +`ARCHITECTURE.md`, and `CODEMAP.md`. No Unreal edits were made or compiled. + +## Failed and retried runs + +- The first ripple audit used a 1.25 m sphere spacing and a 0.045 m limit; its 0.0418 m control + was missed. The synthetic control is now 1.5 m spacing with 2 m spheres, and the limit is 0.035 m. +- Route resampling first failed support/open-air checks (12/24). Four-way resampling and raw routes + with the old relief failed mesh-normal scans at 5.688 m/0.03064 and 4.625 m/0.03263; old 13/9/5 + voxel relief also failed at 4.688 m/0.03546. SDF smoothing without terminal exclusion blocked 143 + samples; high route noise left 720/976 unsupported. Those variants were reverted. +- Removing support caused 30 unsupported samples; lowering its top caused 6; an early widened/noisy + form caused 1. Full and half support splines and full vertical smoothing each caused an unsupported + sample. Quarter-weight vertical/radius smoothing passed. The all-route 0.14 m grain trial caused + 132 unsupported FI samples and was reverted; mouth-only shoulder grain remains. +- Exact Cascade cosine lobes failed FI style 3 in both compilers (9.18 cm at 6.188 m). Full-depth + seeded profiles failed at 5.938 m/0.0537 m and 3.312 m/0.0792 m. The retained shallow seeded + profile passes the full matrix. +- Initial ring probes used the wrong data, camera, or 16 m radius; they returned no coverage or + only 1.857 m relief. The canonical owner input, 32 m LOD0 windows, and covered branch-locked + LOD1 windows pass. The first SW LOD1 set had three uncovered windows; retrying the seven covered + windows passed 77/77 profiles. +- A supplemental fade-ring scan across the rough owner-FI crater still exceeds the 20° normal + limit (42.27°); the same camera/window on L34 also measures 42.27°, so this is present in the + comparison build. An old fixed center has no coverage on the current layout. These probes are + recorded separately from the passing branch-locked FI/SW LOD0–8 ring suite. + +No commits, pushes, or stashes were made. + +## Orchestrator review (Claude) + +- Accepted: the wall ribs are gone in the captures (owner-SW mid-tunnel and upper-SW arrival walls now read smooth with + irregular wobble). Cause measured (capsule-join scallops plus regular 8 m/4 m relief octaves), fixed in the shared + carve, beaded control fails, L34 real geometry fails. Evaluator v21. +- Still open, for L36: + - **The floor still ripples.** In owner-SW mid-tunnel, the walk floor shows a regular washboard/step pattern. The + ripple audit samples only side-wall radii, so it can't see the floor (the support tread). + - **The FI mouth is not natural yet.** The slab is gone, but it was replaced by a jagged cluster of broken, faceted + pieces in the crater (owner-FI ground mouth). The 42° fade-ring normal jump that is also present in L34 belongs + to the same area. diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/RunCostL35.py b/Standalone/Research/WorldAssemblerM3/Linux35/RunCostL35.py new file mode 100644 index 0000000..4677b2b --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/RunCostL35.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +"""Run five interleaved whole-view cost pairs against the L34 Clang binary.""" +import csv +import math +import re +import statistics +import subprocess +import time +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l35" +BINARIES = { + "l34": ROOT / "Saved/Linux/l34/bin/VoxelForgeCoreHeadless-l34-clang", + "l35": OUT / "bin/VoxelForgeCoreHeadless-l35-final-clang", +} +ORDERS = (("l34", "l35"), ("l35", "l34"), ("l34", "l35"), + ("l35", "l34"), ("l34", "l35")) +READY = re.compile(r"\bwhole_view_ready=([0-9.]+)s") +rows = [] +failed = False + + +for recipe in ("surface-world", "floating-islands"): + for pair, order in enumerate(ORDERS, 1): + for build in order: + name = f"cost-{recipe}-pair{pair}-{build}" + logfile = OUT / f"{name}.log" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "900s", str(BINARIES[build]), + str(ROOT / "Standalone/data/owner_world.json"), + "--workers=12", "--world-assembler-prototype", "--stream-benchmark", + "--stream-pipeline", "--force-generate", "--clip-radius=3", + "--max-clip-level=8", "--max-level=-1", f"--recipe={recipe}", + ] + started = time.monotonic() + try: + with logfile.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, cwd=ROOT, stdout=stream, + stderr=subprocess.STDOUT, timeout=900, check=False) + except subprocess.TimeoutExpired: + result = None + elapsed = time.monotonic() - started + output = logfile.read_text(encoding="utf-8", errors="replace") + matches = READY.findall(output) + stamps = re.findall( + r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", + output, re.M) + stamp_ok = stamps == [(recipe, recipe, "PASS")] + valid = (result is not None and result.returncode == 0 and len(matches) == 1 + and "hash=off" in output and "cache_hits=0" in output and stamp_ok) + ready = float(matches[0]) if len(matches) == 1 else math.nan + rows.append((recipe, pair, build, ready, elapsed, + result.returncode if result else "TIMEOUT", valid)) + failed |= not valid + print(f"[L35CostRun] recipe={recipe} pair={pair} build={build} " + f"whole_view_ready={ready:.3f}s process_elapsed={elapsed:.1f}s " + f"{'PASS' if valid else 'FAIL'} log={logfile}", flush=True) + +summary = OUT / "cost-runs.csv" +with summary.open("w", newline="", encoding="utf-8") as stream: + writer = csv.writer(stream) + writer.writerow(("recipe", "pair", "build", "whole_view_ready_seconds", + "process_elapsed_seconds", "exit_code", "status")) + writer.writerows((recipe, pair, build, f"{ready:.6f}", f"{elapsed:.3f}", code, + "PASS" if valid else "FAIL") + for recipe, pair, build, ready, elapsed, code, valid in rows) + +for recipe in ("surface-world", "floating-islands"): + by_build = {build: [row[3] for row in rows if row[0] == recipe and row[2] == build] + for build in BINARIES} + baseline = statistics.median(by_build["l34"]) + current = statistics.median(by_build["l35"]) + paired = [] + for pair in range(1, 6): + values = {row[2]: row[3] for row in rows if row[0] == recipe and row[1] == pair} + paired.append((values["l35"] - values["l34"]) / values["l34"] * 100.0) + mad = statistics.median(abs(value - statistics.median(paired)) for value in paired) + print(f"[L35CostSummary] recipe={recipe} pairs=5 median_l34_s={baseline:.3f} " + f"median_l35_s={current:.3f} median_change_pct={(current/baseline-1)*100.0:+.2f} " + f"paired_change_pct={','.join(f'{value:+.2f}' for value in paired)} " + f"paired_mad_pct={mad:.2f}", flush=True) + +print(f"[L35Cost] runs={len(rows)} status={'FAIL' if failed else 'PASS'} summary={summary}", + flush=True) +raise SystemExit(1 if failed or len(rows) != 20 else 0) diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/RunDeterminismL35.py b/Standalone/Research/WorldAssemblerM3/Linux35/RunDeterminismL35.py new file mode 100644 index 0000000..a8db497 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/RunDeterminismL35.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +"""Check L25, 24 m crossing and upper-SW fixture determinism for L35.""" +import csv +import re +import subprocess +import time +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l35" +OWNER = ROOT / "Standalone/data/owner_world.json" +FIXTURE = ROOT / "Saved/Linux/l33/fixtures/sw-upper-tunnel-network-style0.json" +BINARIES = { + "clang": OUT / "bin/VoxelForgeCoreHeadless-l35-final-clang", + "gcc": OUT / "bin/VoxelForgeCoreHeadless-l35-final-gcc", +} +HASH = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M) +STAMP = re.compile( + r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", re.M) +LAYOUT = re.compile( + r"^\[ResolvedLayoutSnapshot\] schema=\d+ stable_identity=([^ ]+) strata=\d+ bytes=\d+ round_trip=PASS$", + re.M) +PLAN = re.compile( + r"^\[WorldAssemblerPlanSerialization\].*canonical_round_trip=true .*" + r"plan_hash=([0-9a-f]+) manifest_hash=([0-9a-f]+) status=PASS$", re.M) +ROUTE = re.compile( + r"^\[WorldAssemblerRouteAccepted\] arrival_xy_m=\([^)]*\) " + r"departure_xy_m=\([^)]*\) endpoint_proximity_cost=\d+ average_grade_q16=\d+$", re.M) +rows = [] +failed = False +references = {} + + +def run(kind, recipe, compiler, workers, data, passage_audit=False, crossing=False): + global failed + binary = BINARIES[compiler] + name = f"determinism-{kind}-{compiler}-{recipe}-w{workers}" + if kind == "upper-fixture": + name = f"determinism-upper-fixture-{compiler}-w{workers}" + log = OUT / f"{name}.log" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1800s", str(binary), str(data), f"--workers={workers}", + "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", + "--force-generate", "--clip-radius=3", "--max-clip-level=8", "--max-level=-1", + f"--recipe={recipe}", + ] + if passage_audit: + command.append("--audit-resolved-layout-passages") + else: + command.append("--stream-hash") + if crossing: + command.extend(("--camera-step=24,0,0", "--region-crossing")) + started = time.monotonic() + try: + with log.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, cwd=ROOT, stdout=stream, + stderr=subprocess.STDOUT, timeout=1800, check=False) + except subprocess.TimeoutExpired: + result = None + elapsed = time.monotonic() - started + output = log.read_text(encoding="utf-8", errors="replace") + stamps = STAMP.findall(output) + stamp_ok = stamps == [(recipe, recipe, "PASS")] + if passage_audit: + signature = (tuple(LAYOUT.findall(output)), tuple(PLAN.findall(output)), + tuple(ROUTE.findall(output))) + expected = references.get((kind, recipe)) + stable = expected is None or signature == expected + if expected is None and all(signature): + references[(kind, recipe)] = signature + valid = (result is not None and result.returncode == 0 and stamp_ok + and len(signature[0]) == len(signature[1]) == len(signature[2]) == 1 + and re.search(r"^\[ResolvedPassageAuditSummary\].*status=PASS$", output, re.M) + and re.search(r"^\[PassageRippleAuditSummary\].*status=PASS$", output, re.M) + and stable) + hashes = () + detail = f"layout={signature[0][0] if signature[0] else 'MISSING'} stable={stable}" + else: + hashes = tuple(HASH.findall(output)) + key = (kind, recipe) + expected = references.get(key) + stable = expected is None or hashes == expected + if expected is None and hashes: + references[key] = hashes + valid = (result is not None and result.returncode == 0 and stamp_ok + and "hash=on" in output and len(hashes) == 12 and stable) + detail = f"hashes={len(hashes)}/12 stable={stable}" + code = result.returncode if result is not None else "TIMEOUT" + rows.append((kind, recipe, compiler, workers, elapsed, code, valid)) + failed |= not valid + print(f"[L35DeterminismRun] kind={kind} recipe={recipe} compiler={compiler} " + f"workers={workers} elapsed={elapsed:.1f}s {detail} " + f"{'PASS' if valid else 'FAIL'} log={log}", flush=True) + + +for kind in ("l25", "crossing24"): + for recipe in ("surface-world", "floating-islands"): + for compiler in BINARIES: + for workers in (1, 8, 12): + run(kind, recipe, compiler, workers, OWNER, + crossing=(kind == "crossing24")) + +for compiler in BINARIES: + for workers in (1, 8, 12): + run("upper-fixture", "floating-islands", compiler, workers, FIXTURE, + passage_audit=True) + +summary = OUT / "determinism-l35.csv" +with summary.open("w", newline="", encoding="utf-8") as stream: + writer = csv.writer(stream) + writer.writerow(("kind", "recipe", "compiler", "workers", "elapsed_seconds", + "exit_code", "status")) + for row in rows: + writer.writerow((*row[:-1], "PASS" if row[-1] else "FAIL")) +print(f"[L35DeterminismSummary] runs={len(rows)} pass={sum(row[-1] for row in rows)} " + f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True) +raise SystemExit(1 if failed or len(rows) != 30 else 0) diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/RunInvariantAuditsL35.py b/Standalone/Research/WorldAssemblerM3/Linux35/RunInvariantAuditsL35.py new file mode 100644 index 0000000..b0468d8 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/RunInvariantAuditsL35.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +"""Run L33 route/proof and transition invariants with recipe-stamped logs.""" +import re +import subprocess +import time +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l35" +BINARIES = { + "clang": OUT / "bin/VoxelForgeCoreHeadless-l35-final-clang", + "gcc": OUT / "bin/VoxelForgeCoreHeadless-l35-final-gcc", +} +rows = [] +failed = False + + +def run(name, binary, data, recipe, extra, checks): + global failed + logfile = OUT / f"{name}.log" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "900s", + str(binary), str(data), "--workers=12", "--world-assembler-prototype", + "--stream-benchmark", "--stream-pipeline", "--force-generate", "--clip-radius=3", + "--max-clip-level=8", "--max-level=-1", f"--recipe={recipe}", *extra, + ] + started = time.monotonic() + try: + with logfile.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT, + timeout=900, check=False) + except subprocess.TimeoutExpired: + result = None + elapsed = time.monotonic() - started + text = logfile.read_text(encoding="utf-8", errors="replace") + stamps = re.findall( + r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", + text, re.M) + stamp_ok = stamps == [(recipe, recipe, "PASS")] + checks_ok = all(check(text) for check in checks) + ok = result is not None and result.returncode == 0 and stamp_ok and checks_ok + rows.append((name, recipe, elapsed, result.returncode if result else "TIMEOUT", ok)) + print(f"{name} elapsed={elapsed:.1f}s recipe={stamps[0][1] if stamps else 'MISSING'} " + f"stamp={'PASS' if stamp_ok else 'FAIL'} checks={'PASS' if checks_ok else 'FAIL'} " + f"{'PASS' if ok else 'FAIL'}", flush=True) + failed |= not ok + + +owner = ROOT / "Standalone/data/owner_world.json" +for recipe in ("surface-world", "floating-islands"): + for compiler, binary in BINARIES.items(): + name = f"invariant-route-proof-{recipe}-{compiler}" + run(name, binary, owner, recipe, + ["--stream-hash", "--audit-uniform-block-proofs", "--audit-route-parity"], + [lambda text: bool(re.search( + r"^\[RouteParityAudit\].*status=PASS$", text, re.M)), + lambda text: bool(re.search( + r"^\[UniformBlockProofAudit\].*violations=0(?:\s|$)", text, re.M))]) + +for recipe in ("surface-world", "floating-islands"): + for compiler, binary in BINARIES.items(): + for mode in ("hard", "gradient", "interleaved"): + name = f"invariant-transition-{recipe}-{mode}-{compiler}" + run(name, binary, owner, recipe, + [f"--transition-mode={mode}", "--audit-strate-transitions"], + [lambda text: bool(re.search( + r"^\[StrateTransitionAuditSummary\].*hole_columns=0 air_samples=0 .*status=PASS$", + text, re.M)), + lambda text: bool(re.search( + r"^\[StrateTransitionNegativeControls\].*status=PASS$", text, re.M))]) + +summary = OUT / "invariant-audits.csv" +summary.write_text( + "run,recipe,elapsed_seconds,exit_code,status\n" + + "".join(f"{name},{recipe},{elapsed:.3f},{code},{'PASS' if ok else 'FAIL'}\n" + for name, recipe, elapsed, code, ok in rows), + encoding="utf-8") +print(f"[L33InvariantAudits] runs={len(rows)} pass={sum(row[-1] for row in rows)} " + f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True) +raise SystemExit(1 if failed or len(rows) != 16 else 0) diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/RunLegacyAuditsL35.py b/Standalone/Research/WorldAssemblerM3/Linux35/RunLegacyAuditsL35.py new file mode 100644 index 0000000..61f4858 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/RunLegacyAuditsL35.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +"""Run the L13 route parity and L9 uniform-block proof audits on L35.""" +import re +import subprocess +import time +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l35" +BINARIES = { + "clang": OUT / "bin/VoxelForgeCoreHeadless-l35-final-clang", + "gcc": OUT / "bin/VoxelForgeCoreHeadless-l35-final-gcc", +} +RECIPES = ("floating-islands", "surface-world") +rows = [] +failed = False + +for recipe in RECIPES: + for compiler, binary in BINARIES.items(): + name = f"legacy-route-proof-{recipe}-{compiler}" + logfile = OUT / f"{name}.log" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "900s", str(binary), str(ROOT / "Standalone/data/owner_world.json"), + "--workers=12", "--world-assembler-prototype", "--stream-benchmark", + "--stream-pipeline", "--stream-hash", "--force-generate", "--clip-radius=3", + "--max-clip-level=8", "--max-level=-1", + f"--recipe={recipe}", "--audit-uniform-block-proofs", "--audit-route-parity", + ] + started = time.monotonic() + try: + with logfile.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, cwd=ROOT, stdout=stream, + stderr=subprocess.STDOUT, timeout=900, check=False) + except subprocess.TimeoutExpired: + result = None + elapsed = time.monotonic() - started + output = logfile.read_text(encoding="utf-8", errors="replace") + stamp = re.findall( + r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", + output, re.M) + route = re.findall(r"^\[RouteParityAudit\].*$", output, re.M) + proofs = re.findall(r"^\[UniformBlockProofAudit\].*$", output, re.M) + stamp_ok = stamp == [(recipe, recipe, "PASS")] + route_ok = len(route) == 1 and route[0].endswith("status=PASS") + proof_ok = len(proofs) == 1 and bool( + re.search(r"violations=0(?:\s|$)", proofs[0])) + ok = (result is not None and result.returncode == 0 and stamp_ok + and route_ok and proof_ok) + code = result.returncode if result is not None else "TIMEOUT" + rows.append((name, recipe, compiler, elapsed, code, route_ok, bool(proof_ok), ok)) + failed |= not ok + print(f"[L35LegacyAuditRun] case={name} elapsed={elapsed:.1f}s exit={code} " + f"recipe_stamp={'PASS' if stamp_ok else 'FAIL'} " + f"L13={'PASS' if route_ok else 'FAIL'} L9={'PASS' if proof_ok else 'FAIL'} " + f"{'PASS' if ok else 'FAIL'}", flush=True) + +summary = OUT / "legacy-audits.csv" +summary.write_text( + "case,recipe,compiler,elapsed_seconds,exit_code,l13,l9,status\n" + + "".join(f"{name},{recipe},{compiler},{elapsed:.3f},{code}," + f"{'PASS' if l13 else 'FAIL'},{'PASS' if l9 else 'FAIL'}," + f"{'PASS' if ok else 'FAIL'}\n" + for name, recipe, compiler, elapsed, code, l13, l9, ok in rows), + encoding="utf-8") +print(f"[L35LegacyAuditSummary] runs={len(rows)} pass={sum(row[-1] for row in rows)} " + f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True) +raise SystemExit(1 if failed or len(rows) != 4 else 0) diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/RunPassageAuditsL35.py b/Standalone/Research/WorldAssemblerM3/Linux35/RunPassageAuditsL35.py new file mode 100644 index 0000000..3ec613d --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux35/RunPassageAuditsL35.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +"""Run recipe-stamped passage/profile audits for both compilers and both owner recipes.""" +import re +import os +import subprocess +import time +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l35" +BINARIES = { + "clang": OUT / "bin/VoxelForgeCoreHeadless-l35-final-clang", + "gcc": OUT / "bin/VoxelForgeCoreHeadless-l35-final-gcc", +} +RUNS = [] +for recipe, filename in ( + ("floating-islands", "floating-islands"), + ("surface-world", "surface-world"), +): + for style in range(4): + RUNS.append((f"owner-{filename}-style{style}", + ROOT / f"Saved/Linux/linux25-owner-{filename}-style{style}.json", recipe)) +for style in range(4): + RUNS.append((f"upper-sw-fixture-style{style}", + OUT.parent / "l33/fixtures" / f"sw-upper-tunnel-network-style{style}.json", + "floating-islands")) + +RECIPE = re.compile(r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=PASS$", re.M) +PASSAGE = re.compile(r"^\[ResolvedPassageAudit\].*walkability=PASS$", re.M) +MOUTH = re.compile(r"^\[PassageMouthProfileAudit\].*status=PASS$", re.M) +ROUTE = re.compile(r"^\[ResolvedStrateRouteAudit\].*mouth_binding=PASS status=PASS$", re.M) +CHECKS = ( + r"^\[ResolvedLayoutStrict\] accepted=true issues=0 error=$", + r"^\[ResolvedLayoutValidatorControls\].*status=PASS$", + r"^\[PassageMouthProfileNegativeControl\].*source=L23_terraced_geometry.*detected=true$", + r"^\[PassageMouthProfileSummary\].*l23_terrace_negative_control=DETECTED status=PASS$", + r"^\[PassageNaturalnessSummary\].*l23_negative_control=DETECTED.*status=PASS$", + r"^\[PassageRippleAuditSummary\].*synthetic_spheres_negative_control=DETECTED max_amplitude_m=0\.035 status=PASS$", + r"^\[PassageOpenAirAuditSummary\].*violations=0.*l24_negative_control=DETECTED status=PASS$", + r"^\[PassageNoLongBridgeAudit\].*status=PASS$", + r"^\[PassageRockColumnAuditSummary\].*status=PASS$", + r"^\[ResolvedPassageAuditSummary\].*route_binding_failures=0 .*status=PASS$", + r"^\[Walkability\] PASS", + r"^\[FloorProfileBlend\].*negative_controls=step_detected/slope_detected status=PASS$", +) + +rows = [] +failed = False +for compiler, binary in BINARIES.items(): + for name, data, recipe in RUNS: + logfile = OUT / f"passage-audit-{name}-{compiler}.log" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1800s", str(binary), str(data), "--workers=12", + "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", + "--force-generate", "--clip-radius=3", "--max-clip-level=8", "--max-level=-1", + f"--recipe={recipe}", "--audit-resolved-layout-passages", + ] + started = time.monotonic() + try: + with logfile.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, cwd=ROOT, stdout=stream, + stderr=subprocess.STDOUT, timeout=1800, check=False) + except subprocess.TimeoutExpired: + result = None + elapsed = time.monotonic() - started + output = logfile.read_text(encoding="utf-8", errors="replace") + stamp_ok = RECIPE.findall(output) == [(recipe, recipe)] + passages = len(PASSAGE.findall(output)) + mouths = len(MOUTH.findall(output)) + routes = len(ROUTE.findall(output)) + checks_ok = all(re.search(pattern, output, re.M) for pattern in CHECKS) + ok = (result is not None and result.returncode == 0 and stamp_ok + and passages >= 1 and mouths == passages and routes >= 1 and checks_ok) + code = result.returncode if result is not None else "TIMEOUT" + rows.append((name, recipe, compiler, elapsed, code, passages, mouths, routes, ok)) + failed |= not ok + print(f"[L35PassageAuditRun] case={name} compiler={compiler} recipe={recipe} " + f"elapsed={elapsed:.1f}s exit={code} passages={passages} " + f"profiles={mouths} routes={routes} {'PASS' if ok else 'FAIL'} " + f"log={logfile}", flush=True) + +summary = OUT / "passage-audits.csv" +summary.write_text( + "case,recipe,compiler,elapsed_seconds,exit_code,passages,mouth_profiles,routes,status\n" + + "".join(f"{name},{recipe},{compiler},{elapsed:.3f},{code},{passages},{mouths},{routes}," + f"{'PASS' if ok else 'FAIL'}\n" + for name, recipe, compiler, elapsed, code, passages, mouths, routes, ok in rows), + encoding="utf-8") +print(f"[L35PassageAuditSummary] runs={len(rows)} pass={sum(row[-1] for row in rows)} " + f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True) +raise SystemExit(1 if failed or len(rows) != 24 else 0) diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-arrival.jpg b/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-arrival.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53bc033513121a725b1288bb2869afe3ecbb07b7 GIT binary patch literal 23405 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 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-mid-tunnel.jpg b/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-mid-tunnel.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0c5095c7f2604ab4036ce21d4f19717f23deef4d GIT binary patch literal 25427 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 M>*q-ys(i2gKV$}|jsO4v literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-rock-entry.jpg b/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-fi-rock-entry.jpg new file mode 100644 index 0000000000000000000000000000000000000000..70fefde448f8699d7e3f95ed72880703542064ec GIT binary patch literal 26825 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 IV59T@0G!%kc>n+a literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-arrival.jpg b/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-arrival.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b674500d5c514b90fade31d64d9b2b2e52f90cd GIT binary patch literal 22428 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 BY7qbc literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-ground-mouth.jpg b/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-ground-mouth.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e24d5b4d0416b0c586f8de2aa3e7c6896229770b GIT binary patch literal 29764 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 F{{c2NtBC*r literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-mid-tunnel.jpg b/Standalone/Research/WorldAssemblerM3/Linux35/captures/owner-sw-mid-tunnel.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8fc04d83426c92b89ac7697823bde06575ee8c67 GIT binary patch literal 24120 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 z

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 CcsP#$ literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux35/captures/upper-sw-fixture-rock-entry.jpg b/Standalone/Research/WorldAssemblerM3/Linux35/captures/upper-sw-fixture-rock-entry.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f169157ff0255e82b342d428f6d7f1d3ce069d6 GIT binary patch literal 25709 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 nUm#k&qd*l^(yTthoC`ZmR|5h9p4Gn=8; return audit; }; + const auto auditPassageRipples=[&](const VoxelForgeCore::World& Field, + const VoxelForgeCore::ResolvedLayoutPassageV1& passage) + { + FPassageRippleAudit audit; + constexpr double SampleSpacingMetres=0.125; + constexpr double WindowLengthMetres=32.0; + constexpr double MinimumPeriodMetres=0.5; + constexpr double MaximumPeriodMetres=8.0; + constexpr double PeriodStepMetres=0.0625; + constexpr double RippleAmplitudeLimitMetres=0.035; + struct FPathPoint + { + double x=0.0,y=0.0,z=0.0,radius=0.0,distance=0.0; + }; + const std::size_t end=std::min(passage.lowerMouthControlIndex, + passage.controlPoints.size()-1); + if(end<2)return audit; + std::vector path; + path.reserve(end+1); + for(std::size_t i=0;i<=end;++i) + { + const auto& point=passage.controlPoints[i]; + FPathPoint value{qToMetres(point.positionSubvoxels[0]), + qToMetres(point.positionSubvoxels[1]), + qToMetres(point.positionSubvoxels[2]), + qToMetres(point.radiusSubvoxels),0.0}; + if(!path.empty()) + { + const auto& previous=path.back(); + value.distance=previous.distance+std::sqrt( + (value.x-previous.x)*(value.x-previous.x) + +(value.y-previous.y)*(value.y-previous.y) + +(value.z-previous.z)*(value.z-previous.z)); + } + path.push_back(value); + } + const double total=path.back().distance; + if(total1.0e-9?(distance-a.distance)/length:0.0; + return FPathPoint{std::lerp(a.x,b.x,t),std::lerp(a.y,b.y,t), + std::lerp(a.z,b.z,t),std::lerp(a.radius,b.radius,t),distance}; + }; + const auto sinusoidAmplitude=[&](const std::vector>& samples, + double& bestPeriod) + { + if(samples.size()<64)return 0.0; + double best=0.0; + for(double period=MinimumPeriodMetres; + period<=MaximumPeriodMetres+1.0e-9;period+=PeriodStepMetres) + { + const double angular=6.2831853071795864769/period; + double cc=0.0,ss=0.0,cs=0.0,yc=0.0,ys=0.0; + for(const auto& sample:samples) + { + const double phase=angular*sample[0]; + const double c=std::cos(phase),s=std::sin(phase); + cc+=c*c;ss+=s*s;cs+=c*s; + yc+=sample[1]*c;ys+=sample[1]*s; + } + const double determinant=cc*ss-cs*cs; + if(determinant<=1.0e-9)continue; + const double cosine=(yc*ss-ys*cs)/determinant; + const double sine=(ys*cc-yc*cs)/determinant; + const double amplitude=std::hypot(cosine,sine); + if(amplitude>best){best=amplitude;bestPeriod=period;} + } + return best; + }; + const auto appendDetrendedProfile=[&](const std::vector& values, + double startDistance,std::vector>& output) + { + if(values.size()<64)return; + const double meanIndex=0.5*static_cast(values.size()-1); + double mean=0.0,xy=0.0,xx=0.0; + for(double value:values)mean+=value; + mean/=static_cast(values.size()); + for(std::size_t i=0;i(i)-meanIndex)*SampleSpacingMetres; + xy+=x*(values[i]-mean);xx+=x*x; + } + const double slope=xx>0.0?xy/xx:0.0; + for(std::size_t i=0;i(i)-meanIndex)*SampleSpacingMetres; + output.push_back({startDistance+static_cast(i)*SampleSpacingMetres, + values[i]-mean-slope*x}); + } + }; + std::vector beadControl; + beadControl.reserve(static_cast(WindowLengthMetres/SampleSpacingMetres)+1); + constexpr double BeadSpacingMetres=1.5; + constexpr double BeadSphereRadiusMetres=2.0; + for(std::size_t i=0;i<=static_cast(WindowLengthMetres/SampleSpacingMetres);++i) + { + const double x=static_cast(i)*SampleSpacingMetres; + const double nearest=std::abs(std::remainder(x,BeadSpacingMetres)); + beadControl.push_back(std::sqrt(std::max(0.0, + BeadSphereRadiusMetres*BeadSphereRadiusMetres-nearest*nearest))); + } + std::vector> beadSamples; + appendDetrendedProfile(beadControl,0.0,beadSamples); + double ignoredPeriod=0.0; + audit.controlAmplitudeMetres=sinusoidAmplitude(beadSamples,ignoredPeriod); + audit.controlDetected=audit.controlAmplitudeMetres>=RippleAmplitudeLimitMetres; + const std::array windowStarts{{0.03,0.31,0.61,0.91}}; + std::vector> coherentSamples; + for(const double fraction:windowStarts) + { + const double start=(total-WindowLengthMetres)*fraction; + std::vector radii; + radii.reserve(static_cast(WindowLengthMetres/SampleSpacingMetres)+1); + for(std::size_t sample=0; + sample<=static_cast(WindowLengthMetres/SampleSpacingMetres); + ++sample) + { + ++audit.expectedSamples; + const double distance=start+static_cast(sample)*SampleSpacingMetres; + const auto pose=interpolate(distance); + const auto before=interpolate(std::max(0.0,distance-0.25)); + const auto after=interpolate(std::min(total,distance+0.25)); + const double tangentX=after.x-before.x,tangentY=after.y-before.y; + const double tangentLength=std::hypot(tangentX,tangentY); + if(tangentLength<=1.0e-6)continue; + const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength; + const double sampleRadius=std::max(0.20,pose.radius-0.18); + const double x0=pose.x/coreMetres,y0=pose.y/coreMetres,z0=pose.z/coreMetres; + const double offset=sampleRadius/coreMetres; + const double left=static_cast(Field.densityAt( + {x0+nx*offset,y0+ny*offset,z0}))*coreMetres; + const double right=static_cast(Field.densityAt( + {x0-nx*offset,y0-ny*offset,z0}))*coreMetres; + if(!std::isfinite(left)||!std::isfinite(right) + ||left< -0.75||left>0.75||right< -0.75||right>0.75)continue; + radii.push_back(sampleRadius+0.5*(left+right)); + ++audit.samples; + } + if(radii.size()(WindowLengthMetres/ + SampleSpacingMetres)*3/4)continue; + std::vector> windowSamples; + appendDetrendedProfile(radii,start,windowSamples); + double localPeriod=0.0; + const double localAmplitude=sinusoidAmplitude(windowSamples,localPeriod); + if(localAmplitude>audit.localPeakAmplitudeMetres) + { + audit.localPeakAmplitudeMetres=localAmplitude; + audit.periodMetres=localPeriod; + } + coherentSamples.insert(coherentSamples.end(),windowSamples.begin(), + windowSamples.end()); + } + audit.coherentAmplitudeMetres=sinusoidAmplitude(coherentSamples, + audit.coherentPeriodMetres); + audit.amplitudeMetres=audit.localPeakAmplitudeMetres; + const double coverage=audit.expectedSamples>0 + ?static_cast(audit.samples)/audit.expectedSamples:0.0; + audit.passed=audit.controlDetected&&coverage>=0.75 + &&audit.localPeakAmplitudeMetres=MinimumWallReliefMetres;}; @@ -1731,7 +1907,7 @@ namespace StandaloneStreamBenchmark return zUm>=stratum->content.bottomMicrometres&&zUmcontent.topMicrometres; }; std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0; - std::uint64_t mouthProfilePasses=0; + std::uint64_t mouthProfilePasses=0,ripplePasses=0,rippleControlsDetected=0; std::uint64_t openAirViolations=0,openAirLegacyViolations=0,openAirSamples=0; std::uint64_t openAirAudits=0,openAirColumnSamples=0,openAirShortSpanSamples=0; std::uint64_t columnCrossings=0,shortGroundedSpans=0,columnConnectedEnds=0; @@ -1781,6 +1957,7 @@ namespace StandaloneStreamBenchmark const FPassageNaturalnessAudit naturalAudit=auditPassageNaturalness(Shape,passage); const FPassageMouthProfileAudit mouthProfileAudit= auditPassageMouthProfiles(Shape,passage); + const FPassageRippleAudit rippleAudit=auditPassageRipples(Shape,passage); const FPassageOpenAirAudit openAirAudit=auditPassageOpenAir(Shape,blockedWorld, passage,passageIndex); const FPassageColumnAudit columnAudit=auditPassageColumns(Shape,blockedWorld, @@ -1811,8 +1988,10 @@ namespace StandaloneStreamBenchmark &&mouthInContent(passage.lowerStrateIndex,passage.lowerMouthSubvoxels); ++passageCount;naturalPasses+=naturalAudit.passed; mouthProfilePasses+=mouthProfileAudit.passed; + ripplePasses+=rippleAudit.passed; + rippleControlsDetected+=rippleAudit.controlDetected; passagePasses+=passageAudit.passed&&mouthsInRadius&&mouthsInContent - &&naturalAudit.passed&&mouthProfileAudit.passed; + &&naturalAudit.passed&&mouthProfileAudit.passed&&rippleAudit.passed; std::printf("[ResolvedPassageAudit] id=%s interface=%d-%d control_points=%zu center_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu mouth_content=%d/2 mouth_radius=%d/2 walkability=%s\n", passage.stableId.c_str(),passage.upperStrateIndex,passage.lowerStrateIndex, passage.controlPoints.size(),static_cast(passageAudit.centers), @@ -1837,6 +2016,16 @@ namespace StandaloneStreamBenchmark mouthProfileAudit.wallFlatStepRunMetres,mouthProfileAudit.wallStepMetres, PassageProfileSpacingMetres,PassageProfilePlateauMinimumMetres, PassageProfileStepThresholdMetres,mouthProfileAudit.passed?"PASS":"FAIL"); + std::printf("[PassageRippleAudit] id=%s window_m=32.000 spacing_m=0.125 period_m=%.3f amplitude_m=%.4f amplitude_cm=%.2f coherent_period_m=%.3f coherent_amplitude_m=%.4f coherent_amplitude_cm=%.2f local_peak_amplitude_m=%.4f coverage=%llu/%llu threshold_m=0.035 synthetic_spheres_period_m=1.500 synthetic_spheres_amplitude_m=%.4f synthetic_spheres_detected=%s status=%s\n", + passage.stableId.c_str(),rippleAudit.periodMetres, + rippleAudit.amplitudeMetres,rippleAudit.amplitudeMetres*100.0, + rippleAudit.coherentPeriodMetres,rippleAudit.coherentAmplitudeMetres, + rippleAudit.coherentAmplitudeMetres*100.0, + rippleAudit.localPeakAmplitudeMetres, + static_cast(rippleAudit.samples), + static_cast(rippleAudit.expectedSamples), + rippleAudit.controlAmplitudeMetres,rippleAudit.controlDetected?"true":"false", + rippleAudit.passed?"PASS":"FAIL"); std::printf("[PassageOpenAirAudit] id=%s support_samples=%llu violations=%llu column_samples=%llu short_span_samples=%llu l24_ungated_violations=%llu route_support_samples=%llu route_support_violations=%llu spacing_m=%.3f status=%s\n", passage.stableId.c_str(),static_cast(openAirAudit.supportSamples), static_cast(openAirAudit.violations), @@ -2151,9 +2340,15 @@ namespace StandaloneStreamBenchmark PassageProfilePlateauMinimumMetres,PassageProfileStepThresholdMetres, l23TerraceControlDetected?"DETECTED":"MISSED", mouthProfilePasses==passageCount&&l23TerraceControlDetected?"PASS":"FAIL"); + std::printf("[PassageRippleAuditSummary] passed=%llu/%llu synthetic_spheres_negative_control=%s max_amplitude_m=0.035 status=%s\n", + static_cast(ripplePasses), + static_cast(passageCount), + rippleControlsDetected==passageCount?"DETECTED":"MISSED", + ripplePasses==passageCount?"PASS":"FAIL"); const bool auditPassed=passageCount>0&&passagePasses==passageCount &&naturalPasses==passageCount&&l23SmoothWallDetected &&mouthProfilePasses==passageCount&&l23TerraceControlDetected + &&ripplePasses==passageCount &&openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected &&columnAuditsPassed&&noLongBridgeAuditPassed &&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings