From c5fcedeb5bc9f0c784cc404fe71113282347314f Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Mon, 2 Nov 2026 08:02:15 +0100 Subject: [PATCH] research: flat pad stamp only (L159, one attempt; kept as patch) Clamp-between-cones pad at each tunnel end, last composition step, chamber cases removed, bounds extended (proof and feature samplers 16/16 clean). Open-ground result looks as intended; but pads pass 8/96 (flatness up to 0.75 m, blend up to 81 deg), interior air fails 16/16 (839-1,588 solid capsule samples), route audits fail, FI band check fails at seed 0. Owner asked for one attempt, no tuning. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1 --- .../Linux159/PassageEnvelopeAudit.py | 367 ++++++ .../WorldAssemblerM3/Linux159/REPORT.md | 82 ++ .../Linux159/RunL159Captures.py | 187 +++ .../Linux159/RunL159SeedSweep.py | 210 ++++ .../Linux159/captures/INDEX.md | 41 + .../after-l159-0-1-0-lower-landing.jpg | Bin 0 -> 21491 bytes .../captures/after-l159-0-1-0-lower-wide.jpg | Bin 0 -> 17201 bytes .../after-l159-0-1-0-upper-landing.jpg | Bin 0 -> 26501 bytes .../captures/after-l159-0-1-0-upper-wide.jpg | Bin 0 -> 32566 bytes .../after-l159-1-2-0-lower-landing.jpg | Bin 0 -> 16243 bytes .../captures/after-l159-1-2-0-lower-wide.jpg | Bin 0 -> 15370 bytes .../after-l159-1-2-0-upper-landing.jpg | Bin 0 -> 22314 bytes .../captures/after-l159-1-2-0-upper-wide.jpg | Bin 0 -> 17543 bytes .../after-l159-2-3-0-lower-landing.jpg | Bin 0 -> 16611 bytes .../captures/after-l159-2-3-0-lower-wide.jpg | Bin 0 -> 14120 bytes .../after-l159-2-3-0-upper-landing.jpg | Bin 0 -> 19257 bytes .../captures/after-l159-2-3-0-upper-wide.jpg | Bin 0 -> 14474 bytes .../Linux159/captures/manifest.json | 290 +++++ .../Linux159/l159-pad-stamp.patch | 1068 +++++++++++++++++ 19 files changed, 2245 insertions(+) create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/PassageEnvelopeAudit.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/REPORT.md create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/RunL159Captures.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/RunL159SeedSweep.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/INDEX.md create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-landing.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-wide.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-upper-landing.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-upper-wide.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-landing.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-wide.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-landing.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-wide.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-landing.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-wide.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-landing.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-wide.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/captures/manifest.json create mode 100644 Standalone/Research/WorldAssemblerM3/Linux159/l159-pad-stamp.patch diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/PassageEnvelopeAudit.py b/Standalone/Research/WorldAssemblerM3/Linux159/PassageEnvelopeAudit.py new file mode 100644 index 0000000..90712da --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux159/PassageEnvelopeAudit.py @@ -0,0 +1,367 @@ +#!/usr/bin/env python3 +"""Audit cave primitive bounds against passage envelopes, allowing chamber joints only.""" +from __future__ import annotations + +import math +from typing import Any + + +INFLUENCE_REACH_M = 1.053334 +SHELL_THICKNESS_M = 0.75 + + +def _point(control: dict[str, Any], scale: float) -> tuple[float, float, float, float]: + x, y, z = control["position_q"] + return (x * scale, y * scale, z * scale, control["radius_q"] * scale) + + +def _knot_span(a, b) -> float: + return max(1.0e-6, math.sqrt(math.sqrt((b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2))) + + +def _evaluate(controls, span: int, t: float): + p1, p2 = controls[span], controls[span + 1] + p0 = controls[span - 1] if span else controls[0] + p3 = controls[min(span + 2, len(controls) - 1)] + dt0, dt1, dt2 = _knot_span(p0, p1), _knot_span(p1, p2), _knot_span(p2, p3) + t2, t3 = t * t, t * t * t + result = [] + for axis in (0, 1, 3): + m1 = dt1 * ((p1[axis] - p0[axis]) / dt0 + - (p2[axis] - p0[axis]) / (dt0 + dt1) + + (p2[axis] - p1[axis]) / dt1) + m2 = dt1 * ((p2[axis] - p1[axis]) / dt1 + - (p3[axis] - p1[axis]) / (dt1 + dt2) + + (p3[axis] - p2[axis]) / dt2) + value = ((2 * t3 - 3 * t2 + 1) * p1[axis] + + (-2 * t3 + 3 * t2) * p2[axis] + + (t3 - 2 * t2 + t) * m1 + (t3 - t2) * m2) + result.append(value) + radius = min(max(result[2], min(p1[3], p2[3])), max(p1[3], p2[3])) + return result[0], result[1], p1[2] + (p2[2] - p1[2]) * t, radius + + +def _segments(passage: dict[str, Any], scale: float): + controls = [_point(row, scale) for row in passage["control_points"]] + route_end = min(max(1, int(passage.get("lower_mouth_control_index", len(controls) - 1))), + len(controls) - 1) + along = 0.0 + for span in range(route_end): + a, b = controls[span], controls[span + 1] + chord = math.hypot(b[0] - a[0], b[1] - a[1]) + steps = max(1, math.ceil(chord / 2.0)) + prior = _evaluate(controls, span, 0.0) + for step in range(1, steps + 1): + current = _evaluate(controls, span, step / steps) + length = math.dist(prior[:3], current[:3]) + yield prior, current, along, max(prior[3], current[3]) + INFLUENCE_REACH_M + along += length + prior = current + + +def _distance_squared(a, b, bounds, t: float) -> float: + total = 0.0 + for axis in range(3): + pos = a[axis] + (b[axis] - a[axis]) * t + lo, hi = bounds[axis] + gap = lo - pos if pos < lo else pos - hi if pos > hi else 0.0 + total += gap * gap + return total + + +def _overlap_interval(a, b, bounds, radius: float): + cuts = {0.0, 1.0} + for axis in range(3): + delta = b[axis] - a[axis] + if abs(delta) < 1.0e-15: + continue + for edge in bounds[axis]: + t = (edge - a[axis]) / delta + if 0.0 < t < 1.0: + cuts.add(t) + cuts = sorted(cuts) + best_t, best_d2 = 0.0, math.inf + for lo, hi in zip(cuts, cuts[1:]): + mid = (lo + hi) * 0.5 + quadratic = linear = 0.0 + for axis in range(3): + delta = b[axis] - a[axis] + pos = a[axis] + delta * mid + low, high = bounds[axis] + edge = low if pos < low else high if pos > high else None + if edge is not None: + quadratic += delta * delta + linear += delta * (a[axis] - edge) + candidate = min(hi, max(lo, -linear / quadratic)) if quadratic else lo + d2 = _distance_squared(a, b, bounds, candidate) + if d2 < best_d2: + best_t, best_d2 = candidate, d2 + for t in (0.0, 1.0): + d2 = _distance_squared(a, b, bounds, t) + if d2 < best_d2: + best_t, best_d2 = t, d2 + if best_d2 > radius * radius: + return None + + radius2 = radius * radius + if _distance_squared(a, b, bounds, 0.0) <= radius2: + left = 0.0 + else: + low, high = 0.0, best_t + for _ in range(42): + mid = (low + high) * 0.5 + if _distance_squared(a, b, bounds, mid) <= radius2: + high = mid + else: + low = mid + left = high + if _distance_squared(a, b, bounds, 1.0) <= radius2: + right = 1.0 + else: + low, high = best_t, 1.0 + for _ in range(42): + mid = (low + high) * 0.5 + if _distance_squared(a, b, bounds, mid) <= radius2: + low = mid + else: + high = mid + right = low + return left, right, best_t + + +def _inside_chamber(point, chamber: dict[str, Any], scale: float) -> bool: + cx, cy, cz = (value * scale for value in chamber["floor_center_q"]) + radius = chamber["radius_q"] * scale + clear = chamber["clear_height_q"] * scale + gx, gy = (value / 65536.0 for value in chamber["floor_gradient_q16"]) + floor = cz + gx * (point[0] - cx) + gy * (point[1] - cy) + chamber_distance = max(math.hypot(point[0] - cx, point[1] - cy) - radius, + floor - point[2], point[2] - (floor + clear)) + return chamber_distance <= SHELL_THICKNESS_M + + +def _primitive_bounds(row: dict[str, Any]): + return tuple((row["bounds_min_um"][i] / 1.0e6, + row["bounds_max_um"][i] / 1.0e6) for i in range(3)) + + +def _landing_content_band_audit(layout: dict[str, Any]) -> list[dict[str, Any]]: + """Recheck the validator's complete graded floor, headroom and shell envelope.""" + voxel_um = int(layout["core_voxel_size_um"]) + q_per_metre = 256 * 1_000_000 / voxel_um + strata = {int(row["strate_index"]): row for row in layout.get("strates", [])} + + def q_to_um(q: int) -> int: + numerator = q * voxel_um + return numerator // 256 if numerator >= 0 else -((-numerator) // 256) + + result = [] + shell_q = math.floor(0.75 * q_per_metre + 0.5) + for passage in layout.get("passages", []): + for side, key, strate_key in ( + ("upper", "upper_landing_chamber", "upper_strate_index"), + ("lower", "lower_landing_chamber", "lower_strate_index")): + chamber = passage[key] + host = strata.get(int(passage[strate_key])) + content = host.get("content", {}) if host else {} + gradient = chamber["floor_gradient_q16"] + gradient_magnitude = math.isqrt(gradient[0] ** 2 + gradient[1] ** 2) + plane_reach_q = (int(chamber["radius_q"]) * gradient_magnitude + 65535) // 65536 + floor_q = int(chamber["floor_center_q"][2]) + minimum_um = q_to_um(floor_q - plane_reach_q - shell_q) + maximum_um = q_to_um(floor_q + plane_reach_q + + int(chamber["clear_height_q"]) + shell_q) + band_bottom_um, band_top_um = int(content.get("bottom_um", 0)), int( + content.get("top_um", 0)) + passed = bool(content.get("present", False) + and minimum_um >= band_bottom_um + and maximum_um <= band_top_um) + result.append({ + "passage": passage["stable_id"], "side": side, + "host_strate": int(passage[strate_key]), + "minimum_um": minimum_um, "maximum_um": maximum_um, + "content_bottom_um": band_bottom_um, "content_top_um": band_top_um, + "bottom_margin_m": (minimum_um - band_bottom_um) / 1_000_000.0, + "top_margin_m": (band_top_um - maximum_um) / 1_000_000.0, + "passed": passed, + }) + return result + + +def _bezier(points, t: float): + u = 1.0 - t + return tuple(u**3 * points[0][axis] + 3*u*u*t * points[1][axis] + + 3*u*t*t * points[2][axis] + t**3 * points[3][axis] + for axis in range(3)) + + +def _distance_to_ellipse(radial: float, vertical: float, + radius: float, height: float) -> float: + """Euclidean distance to the edge bore's horizontal/vertical ellipse.""" + radial = abs(radial) + vertical = abs(vertical) + if (radial / radius) ** 2 + (vertical / height) ** 2 <= 1.0: + return 0.0 + + lo, hi = 0.0, math.pi / 2.0 + ratio = (math.sqrt(5.0) - 1.0) / 2.0 + + def squared_distance(angle: float) -> float: + return ((radial - radius * math.cos(angle)) ** 2 + + (vertical - height * math.sin(angle)) ** 2) + + left = hi - ratio * (hi - lo) + right = lo + ratio * (hi - lo) + left_value, right_value = squared_distance(left), squared_distance(right) + for _ in range(48): + if left_value < right_value: + hi, right, right_value = right, left, left_value + left = hi - ratio * (hi - lo) + left_value = squared_distance(left) + else: + lo, left, left_value = left, right, right_value + right = lo + ratio * (hi - lo) + right_value = squared_distance(right) + return math.sqrt(min(left_value, right_value)) + + +def _actual_edge_clearance(passage, edge, scale: float, + chamber: dict[str, Any]) -> float: + """Return minimum true tube clearance outside the landing chamber. + + The route edge is a swept ellipse, with its recorded polyline as the axis. + Comparing the tunnel tube to that ellipse avoids the false clashes caused by + intersecting two enclosing boxes. + """ + controls = [tuple(value / 1.0e6 for value in point) + for point in edge["control_points_um"]] + axis = [tuple(value / 1.0e6 for value in point) + for point in edge.get("polyline_um", [])] + if len(axis) < 2: + axis = [_bezier(controls, index / 64.0) for index in range(65)] + edge_radius = (edge["bore_radius_um"] + + edge["irregularity_amplitude_um"]) / 1.0e6 + edge_height = (edge["bore_height_um"] + + edge["irregularity_amplitude_um"]) / 1.0e6 + passage_segments = passage.get("_audit_segments") or tuple(_segments(passage, scale)) + minimum_clearance = math.inf + for a, b, _, passage_radius in passage_segments: + length = math.dist(a[:3], b[:3]) + steps = max(1, math.ceil(length / 0.05)) + for step in range(steps + 1): + t = step / steps + point = tuple(a[i] + (b[i] - a[i]) * t for i in range(3)) + if _inside_chamber(point, chamber, scale): + continue + tunnel_radius = (a[3] + (b[3] - a[3]) * t + + INFLUENCE_REACH_M) + for start, end in zip(axis, axis[1:]): + delta = tuple(end[i] - start[i] for i in range(3)) + length_squared = sum(value * value for value in delta) + projection = (sum((point[i] - start[i]) * delta[i] + for i in range(3)) / length_squared + if length_squared else 0.0) + projection = min(1.0, max(0.0, projection)) + center = tuple(start[i] + projection * delta[i] for i in range(3)) + radial = math.hypot(point[0] - center[0], point[1] - center[1]) + vertical = abs(point[2] - center[2]) + clearance = (_distance_to_ellipse(radial, vertical, + edge_radius, edge_height) + - tunnel_radius) + minimum_clearance = min(minimum_clearance, clearance) + return minimum_clearance + + +def _test_bounds(bounds, strate_index: int, passages, scale: float, + *, allow_chamber: bool = True): + for passage in passages: + if strate_index not in (passage["upper_strate_index"], passage["lower_strate_index"]): + continue + chamber_key = ("upper_landing_chamber" if strate_index == passage["upper_strate_index"] + else "lower_landing_chamber") + chamber = passage[chamber_key] + segments = passage.get("_audit_segments") + if segments is None: + segments = tuple(_segments(passage, scale)) + for a, b, along, radius in segments: + expanded = [(a[i] - radius, b[i] + radius) if a[i] <= b[i] + else (b[i] - radius, a[i] + radius) for i in range(3)] + if any(expanded[i][1] < bounds[i][0] or expanded[i][0] > bounds[i][1] + for i in range(3)): + continue + overlap = _overlap_interval(a, b, bounds, radius) + if overlap is None: + continue + first, last, closest = overlap + if allow_chamber: + points = [tuple(a[i] + (b[i] - a[i]) * t for i in range(3)) + for t in (first, closest, last)] + if all(_inside_chamber(point, chamber, scale) for point in points): + continue + point = tuple(a[i] + (b[i] - a[i]) * closest for i in range(3)) + return passage["stable_id"], along + closest * math.dist(a[:3], b[:3]), point + return None + + +def audit_layout(layout: dict[str, Any]) -> dict[str, Any]: + scale = layout["core_voxel_size_um"] / (256.0 * 1.0e6) + passages = [dict(row, _audit_segments=tuple(_segments(row, scale))) + for row in layout.get("passages", [])] + primitives = [*layout.get("cavern_rooms", []), *layout.get("cavern_edges", [])] + checked = conflicts = chamber_joints = bounds_candidates = refined_false_positives = 0 + first_conflict = None + for primitive in primitives: + bounds = _primitive_bounds(primitive) + checked += 1 + primitive_conflicted = False + for passage in passages: + found = _test_bounds(bounds, primitive["strate_index"], [passage], scale) + if not found: + continue + bounds_candidates += 1 + passage_id, station, point = found + if "control_points_um" in primitive: + side = ("upper_landing_chamber" + if primitive["strate_index"] == passage["upper_strate_index"] + else "lower_landing_chamber") + clearance = _actual_edge_clearance(passage, primitive, scale, + passage[side]) + if clearance >= 0.0: + refined_false_positives += 1 + continue + primitive_conflicted = True + conflicts += 1 + if first_conflict is None: + first_conflict = {"primitive": primitive["stable_id"], + "passage": passage_id, "station_m": round(station, 3), + "center_m": [round(value, 3) for value in point]} + break + if not primitive_conflicted: + # Count the edge's named landing association as a confirmed joint. + anchor = primitive.get("start_anchor_stable_id", "") + if anchor.endswith(("/upper-landing-chamber", "/lower-landing-chamber")): + chamber_joints += 1 + + negative_controls = 0 + long_passage = max(passages, key=lambda row: len(row["control_points"]), default=None) + if long_passage: + controls = [_point(row, scale) for row in long_passage["control_points"]] + index = min(max(1, len(controls) // 2), len(controls) - 2) + center = controls[index] + bounds = tuple((center[axis] - 0.25, center[axis] + 0.25) for axis in range(3)) + # Select the side whose chamber is farther from this forced tunnel overlap. + strate = long_passage["lower_strate_index"] + if _test_bounds(bounds, strate, [long_passage], scale, allow_chamber=False): + negative_controls = 1 + landing_content_band = _landing_content_band_audit(layout) + landing_content_band_passed = bool(landing_content_band) and all( + row["passed"] for row in landing_content_band) + return {"primitives_checked": checked, "bounds_candidates": bounds_candidates, + "refined_edge_false_positives": refined_false_positives, + "outside_chamber_conflicts": conflicts, + "chamber_joints": chamber_joints, "negative_controls": negative_controls, + "negative_controls_expected": 1, "first_conflict": first_conflict, + "landing_content_band": landing_content_band, + "landing_content_band_passed": landing_content_band_passed, + "passed": conflicts == 0 and negative_controls == 1 + and landing_content_band_passed} diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/REPORT.md b/Standalone/Research/WorldAssemblerM3/Linux159/REPORT.md new file mode 100644 index 0000000..e98e6ea --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux159/REPORT.md @@ -0,0 +1,82 @@ +# L159 — pad stamp only + +The stamp is implemented and built as evaluator v240, with no planner edits. All 12 captures passed image quality, but the seed-0 fast tier and both 16-seed composed sweeps failed; no baselines were added. + +## Seed-0 tunnel-end captures + +Each row matches the L151 eye-height pose and adds a pulled-back L159 wide view. + +| Tunnel end | Before (L151) | After, eye height (L159) | After, wide (L159) | +|---|---|---|---| +| `passage/0-1/0` upper | ![L151 upper](../Linux151/captures/after-l151-0-1-0-upper-landing.jpg) | ![L159 upper eye](captures/after-l159-0-1-0-upper-landing.jpg) | ![L159 upper wide](captures/after-l159-0-1-0-upper-wide.jpg) | +| `passage/0-1/0` lower | ![L151 lower](../Linux151/captures/after-l151-0-1-0-lower-landing.jpg) | ![L159 lower eye](captures/after-l159-0-1-0-lower-landing.jpg) | ![L159 lower wide](captures/after-l159-0-1-0-lower-wide.jpg) | +| `passage/1-2/0` upper | ![L151 upper](../Linux151/captures/after-l151-1-2-0-upper-landing.jpg) | ![L159 upper eye](captures/after-l159-1-2-0-upper-landing.jpg) | ![L159 upper wide](captures/after-l159-1-2-0-upper-wide.jpg) | +| `passage/1-2/0` lower | ![L151 lower](../Linux151/captures/after-l151-1-2-0-lower-landing.jpg) | ![L159 lower eye](captures/after-l159-1-2-0-lower-landing.jpg) | ![L159 lower wide](captures/after-l159-1-2-0-lower-wide.jpg) | +| `passage/2-3/0` upper | ![L151 upper](../Linux151/captures/after-l151-2-3-0-upper-landing.jpg) | ![L159 upper eye](captures/after-l159-2-3-0-upper-landing.jpg) | ![L159 upper wide](captures/after-l159-2-3-0-upper-wide.jpg) | +| `passage/2-3/0` lower | ![L151 lower](../Linux151/captures/after-l151-2-3-0-lower-landing.jpg) | ![L159 lower eye](captures/after-l159-2-3-0-lower-landing.jpg) | ![L159 lower wide](captures/after-l159-2-3-0-lower-wide.jpg) | + +Capture quality: **12/12 PASS**. Poses use the seed-0 layout resolved for L151; the six after-eye views reuse those camera poses. The image manifest and capture commands are in [captures/INDEX.md](captures/INDEX.md) and [RunL159Captures.py](RunL159Captures.py). + +## Change + +- Added a last-step stamp to both `ApplyResolvedStrateComposition` branches. It uses the existing landing-chamber floor center as P, radius `max(3 m, mouth radius + 1 m)`, fill depth 1.25 m, headroom 3 m, 12° cones, and an 8 m blend reach. The tube-only distance mask leaves the bore open; the smooth-min width rises to 0.5 m over the first metre beyond the flat radius. +- Removed the landing chamber box/shell composition cases. Tunnel endpoints and planner output were left unchanged. +- Extended tile feature bounds, proof bounds, fallback overlap bounds, and the proof-miss sampler for the pad influence. +- Added `LandingPadAudit` for floor flatness, support, headroom, blend grade, and four negative controls. +- Bumped `WorldAssemblyEvaluatorVersion` from 239 to 240. + +No Unreal `Source/` files changed. Changed Standalone files: [ShapeWorldInternal.h](../../../Core/src/ShapeWorldInternal.h), [VoxelForgeCore.h](../../../Core/include/VoxelForgeCore/VoxelForgeCore.h), and [StreamBenchmarkPipeline.h](../../../Source/StreamBenchmarkPipeline.h). Planner files are unchanged. + +## Gates + +| Gate | Tunnel Network | Vertical Shafts | Result detail | +|---|---:|---:|---| +| Seed-0 fast tier | FAIL | — | Stopped before composition: `owner-floating-islands-style2-clang` rejected because `passage/0-1/0 lower landing chamber does not fit inside its host content band` (exit 2, 0.465 s). | +| Combined composed run | 0/16 PASS | 0/16 PASS | Each seed returned failure from the resolved passage audit. | +| Pad audit | 0/16 seeds PASS | 0/16 seeds PASS | 8/96 endpoints passed per mode. Across the 96 pads: 49 had flatness misses (369 samples total; worst reported variation 0.74946 m), 75 had blend-grade misses (2,072 samples; max 80.754°), support was 9,384/10,368 probes, and headroom passed on 93/96 pads. There were 1,682 missing blend crossings. All four negative controls were detected on every pad: 384/384 per mode. | +| Route plan grade | 16/16 PASS | 16/16 PASS | Planned grades stayed within the 15° limit. | +| Selected-stratum route audit | 0/16 PASS | 1/16 PASS | Vertical Shafts passed only seed 2; its selected route had 0 blocked or unsupported samples. Tunnel Network failed all 16: blocked samples were present on 15 seeds and unsupported samples on 13. The full composed passage walkability summary still failed 16/16 in each mode; `route_walkable` was 0 on 15 seeds and 2 on seed 2. | +| Interior air | 0/16 PASS | 0/16 PASS | Every seed had solid capsule samples (839–1,588 per seed). | +| Shell | 11/16 PASS | 11/16 PASS | Failed seeds 2, 3, 4, 5, and 14: 2,571 floor violations and 570 wall violations in total. Other shell samples passed. | +| Ripple | 5/16 PASS | 5/16 PASS | Passing seeds: 3, 7, 11, 12, and 14. | +| Layout envelope | 8/16 PASS | 8/16 PASS | Conflicts on seeds 1, 4, 6, 7, 8, 10, 13, and 15, on existing route-edge, room, or shaft primitives near passage endpoints. | +| Tile seams | NOT REACHED, 0/16 rows | NOT REACHED, 0/16 rows | The command included `--audit-passage-tile-seams`, but every run returned from the failed passage summary before reaching the seam-audit block. Seam behavior is therefore unverified. | +| Pad proof/feature bounds (L130 sampler) | 16/16 PASS | 16/16 PASS | Per mode: 413,952 sampled points, 305,571 sign-relevant; zero proof misses and zero tile-feature misses. | +| Mode blocked-route control | 16/16 PASS | 16/16 PASS | Deliberately blocked controls were detected as expected. | + +Per-seed detail: pad `F/G` is the number of endpoints with any flatness/blend-grade failure; route `B/U` is the selected-stratum blocked/unsupported sample count. Shell `F (x/y)` gives floor/wall violations. + +| Seed | Pads passed | Pad F/G | Tunnel Network B/U | Vertical Shafts B/U | Interior solids | Shell | Ripple | Envelope | +|---:|---:|---:|---:|---:|---:|---:|:---:|:---:| +| 0 | 1/6 | 3/5 | 324/12 | 507/0 | 1,233 | PASS | FAIL | PASS | +| 1 | 1/6 | 3/4 | 190/0 | 157/0 | 839 | PASS | FAIL | FAIL | +| 2 | 1/6 | 3/4 | 159/2 | 0/0 | 915 | FAIL (513/110) | FAIL | PASS | +| 3 | 1/6 | 3/4 | 0/14 | 521/0 | 1,588 | FAIL (522/117) | PASS | PASS | +| 4 | 0/6 | 3/5 | 140/0 | 222/0 | 855 | FAIL (512/114) | FAIL | FAIL | +| 5 | 0/6 | 3/4 | 152/15 | 379/0 | 892 | FAIL (516/116) | FAIL | PASS | +| 6 | 0/6 | 3/6 | 436/24 | 495/0 | 1,350 | PASS | FAIL | FAIL | +| 7 | 1/6 | 3/5 | 299/5 | 374/0 | 1,011 | PASS | PASS | FAIL | +| 8 | 1/6 | 3/4 | 177/15 | 541/0 | 1,079 | PASS | FAIL | FAIL | +| 9 | 0/6 | 3/4 | 325/16 | 540/0 | 1,205 | PASS | FAIL | PASS | +| 10 | 1/6 | 3/5 | 171/16 | 385/0 | 921 | PASS | FAIL | FAIL | +| 11 | 0/6 | 3/5 | 150/30 | 537/0 | 1,025 | PASS | PASS | PASS | +| 12 | 1/6 | 3/4 | 266/4 | 353/0 | 1,161 | PASS | PASS | PASS | +| 13 | 0/6 | 4/6 | 153/15 | 376/0 | 1,146 | PASS | FAIL | FAIL | +| 14 | 0/6 | 3/4 | 277/18 | 386/0 | 1,075 | FAIL (508/113) | PASS | PASS | +| 15 | 0/6 | 3/6 | 173/0 | 265/0 | 970 | PASS | FAIL | FAIL | + +Full per-seed records: [Tunnel Network summary](../../../../Saved/Linux/l159/seeds/tunnel-network/summary.json) and [Vertical Shafts summary](../../../../Saved/Linux/l159/seeds/vertical-shafts/summary.json). + +The pad, route, shell, interior-air, ripple, and envelope results are composition audits, one run per seed 0–15 with `--workers=8 --clip-radius=3 --max-clip-level=8 --max-level=0 --force-generate --recipe=surface-world --audit-resolved-layout-passages --audit-passage-tile-seams` and the same source stamp (`5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640`). Both modes produced the same shared-field results. The selected-stratum route row and blocked-route control are mode-specific. + +The seed runner recorded 6,711.2 s summed child wall time for Tunnel Network and 6,762.5 s for Vertical Shafts (monotonic windows from each seed process launch to exit). These are sweep execution windows, not performance benchmark results; no L80 timing was taken. + +## Checks and remaining risks + +- Build: `bash Standalone/BuildLinux.sh --compiler=clang++-19 --variant=l159-clang --fp-contract=off --jobs=4` — passed. +- Captures: `RunL159Captures.py` — 12 views, 0 quality failures. +- Fast tier: `VOXELFORGE_L130_PASSAGE_REACH_PROOF_AUDIT=1 python3 Standalone/Tools/verify/verify.py fast --out Saved/Linux/l159 --overall-timeout 1740` — failed at the owner floating-islands fixture before composition. +- Composed sweeps: `RunL159SeedSweep.py --kind tunnel-network` and `--kind vertical-shafts`, seeds 0–15, with `VOXELFORGE_L130_PASSAGE_REACH_PROOF_AUDIT=1` — completed, all aggregate gates failed. +- `git diff --check` passed before the final report was written. No Unreal build or timing benchmark was run. + +The pad flatness, support, headroom, and blend gates remain open, and all composed passage summaries fail. Shell failures are seed-dependent. The proof-tree and tile-feature bound sampler passed; fallback overlap bounds were extended but have no separate standalone audit. Seam behavior remains unverified because the process exits before that gate. No baselines were added because the requested gates did not all pass. diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/RunL159Captures.py b/Standalone/Research/WorldAssemblerM3/Linux159/RunL159Captures.py new file mode 100644 index 0000000..51a699d --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux159/RunL159Captures.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +"""Capture matched L151 eye views and L159 wide views of all six owner pads.""" +from __future__ import annotations + +import json +import math +import os +from pathlib import Path +import re +import subprocess +import sys + + +ROOT = Path(__file__).resolve().parents[4] +DATA = ROOT / "Standalone/data/owner_world.json" +OUT = ROOT / "Saved/Linux/l159/captures" +LAYOUT = ROOT / "Saved/Linux/l151/captures/after-resolved-layout.json" +ARTIFACTS = ROOT / "Standalone/Research/WorldAssemblerM3/Linux159/captures" +HEADLESS = ROOT / "Saved/Linux/l159/bin/VoxelForgeCoreHeadless-l159-clang" +RENDERER = ROOT / "Saved/Linux/l159/bin/VoxelForgeOffscreenCapture-l159-clang" +STAMP = "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640" +LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"] +STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]{64})$", re.M) + + +def fmt(values) -> str: + return ",".join(f"{value:.6f}" for value in values) + + +def angles(camera, target) -> tuple[float, float]: + dx, dy, dz = (target[index] - camera[index] for index in range(3)) + return math.degrees(math.atan2(dx, dy)), math.degrees( + math.atan2(dz, math.hypot(dx, dy))) + + +def point_q(layout: dict, values) -> tuple[float, float, float]: + scale = layout["core_voxel_size_um"] / (256.0 * 1_000_000.0) + return tuple(value * scale for value in values) + + +def chamber_views(layout: dict) -> list[dict]: + result = [] + for passage in layout["passages"]: + controls = passage["control_points"] + for side, endpoint, neighbor in ( + ("upper", controls[0], controls[1]), + ("lower", controls[-1], controls[-2])): + chamber = passage[f"{side}_landing_chamber"] + center = point_q(layout, chamber["floor_center_q"]) + a = point_q(layout, neighbor["position_q"]) + b = point_q(layout, endpoint["position_q"]) + dx, dy = a[0] - b[0], a[1] - b[1] + length = math.hypot(dx, dy) + if length <= 1.0e-9: + raise ValueError(f"degenerate {side} tunnel tangent: {passage['stable_id']}") + dx, dy = dx / length, dy / length + eye_z = center[2] + 1.45 + distance = 9.0 + target = (center[0] + dx * distance, center[1] + dy * distance, + eye_z + (chamber["floor_gradient_q16"][0] / 65536.0 * dx + + chamber["floor_gradient_q16"][1] / 65536.0 * dy) + * distance) + camera = (center[0], center[1], eye_z) + slug = passage["stable_id"].replace("passage/", "").replace("/", "-") + result.append({"name": f"{slug}-{side}-landing", "passage": passage["stable_id"], + "side": side, "view_kind": "eye", "camera": camera, + "target": target, "focus": (center[0], center[1], eye_z, 18.0)}) + wide_camera = (center[0] - dx * 14.0, center[1] - dy * 14.0, + center[2] + 5.5) + wide_target = (center[0] + dx * 2.0, center[1] + dy * 2.0, + center[2] + 1.25) + result.append({"name": f"{slug}-{side}-wide", "passage": passage["stable_id"], + "side": side, "view_kind": "wide", "camera": wide_camera, + "target": wide_target, + "focus": (center[0], center[1], eye_z, 42.0)}) + return result + + +def stamped_run(name: str, command: list[object], log: Path, env: dict[str, str]) -> str: + probe = subprocess.run([*LIMIT, "timeout", "15s", str(command[0]), "--print-source-stamp"], + cwd=ROOT, env=env, text=True, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, check=False, timeout=20) + match = STAMP_RE.search(probe.stdout or "") + if probe.returncode or not match or match.group(1) != STAMP: + raise RuntimeError(f"{name}: source stamp mismatch for {command[0]}") + log.parent.mkdir(parents=True, exist_ok=True) + with log.open("w", encoding="utf-8") as stream: + result = subprocess.run([*LIMIT, "timeout", "1740s", *map(str, command)], + cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT, + timeout=1745, check=False) + output = log.read_text(encoding="utf-8", errors="replace") + emitted = STAMP_RE.search(output) + if result.returncode or not emitted or emitted.group(1) != STAMP: + raise RuntimeError(f"{name}: export or render failed; see {log}") + return output + + +def main() -> int: + if not DATA.is_file() or not HEADLESS.is_file() or not RENDERER.is_file(): + raise SystemExit("missing owner fixture or L159 Clang capture binaries") + OUT.mkdir(parents=True, exist_ok=True) + ARTIFACTS.mkdir(parents=True, exist_ok=True) + env = os.environ.copy() + env["LP_NUM_THREADS"] = "12" + env["XDG_CACHE_HOME"] = str(OUT / "xdg-cache") + layout = json.loads(LAYOUT.read_text(encoding="utf-8")) + if len(layout.get("passages", [])) != 3: + raise RuntimeError("owner layout did not resolve the expected three tunnels") + + quality_tool = ROOT / "Standalone/Tools/verify/capture_quality.py" + manifest = [] + failures = [] + for view in chamber_views(layout): + camera, target = view["camera"], view["target"] + yaw, pitch = angles(camera, target) + mesh_dir = OUT / "meshes" + mesh_dir.mkdir(parents=True, exist_ok=True) + mesh = mesh_dir / f"{view['name']}.vfmesh" + capture_layout = mesh_dir / f"{view['name']}-layout.json" + export = [HEADLESS, DATA, "--world-assembler-prototype", "--stream-benchmark", + "--stream-pipeline", "--workers=12", "--clip-radius=6", "--max-clip-level=0", + "--max-level=0", "--force-generate", "--seed=0", "--recipe=surface-world", + "--render-distance-chunks=0", f"--camera={fmt((*camera, yaw, pitch))}", + f"--resolved-layout-output={capture_layout}", f"--mesh-export={mesh}"] + stamped_run(f"l159-{view['name']}-export", export, + OUT / f"{view['name']}-export.log", env) + if not mesh.is_file() or mesh.stat().st_size == 0: + raise RuntimeError(f"{view['name']}: empty mesh export") + png = OUT / f"{view['name']}.png" + jpg = ARTIFACTS / f"after-l159-{view['name']}.jpg" + render = [RENDERER, mesh, png, "--size=1280x720", "--fov-deg=78.0", + 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", "--height-center-m=-950", + "--height-range-m=60", "--tile-edges=off", + f"--focus-region={fmt(view['focus'])}"] + stamped_run(f"l159-{view['name']}-render", render, + OUT / f"{view['name']}-render.log", env) + subprocess.run([*LIMIT, "timeout", "120s", "ffmpeg", "-nostdin", + "-hide_banner", "-loglevel", "error", "-y", "-i", png, + "-frames:v", "1", "-q:v", "4", jpg], cwd=ROOT, env=env, + check=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, timeout=125) + check = subprocess.run([*LIMIT, "timeout", "120s", sys.executable, + quality_tool, jpg], cwd=ROOT, env=env, text=True, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, check=False, timeout=125) + quality_ok = check.returncode == 0 and "status=PASS" in check.stdout + if not quality_ok: + failures.append(view["name"]) + quality_line = (check.stdout.strip().splitlines()[-1] + if check.stdout.strip() else f"quality exit={check.returncode}") + manifest.append({"version": "after-l159", "view": view["name"], + "passage": view["passage"], "side": view["side"], + "view_kind": view["view_kind"], + "file": str(jpg.relative_to(ROOT)), "camera_m": camera, + "target_m": target, "yaw_deg": yaw, "pitch_deg": pitch, + "source_stamp": STAMP, "pose_layout_identity": layout.get("stable_identity"), + "quality_status": "PASS" if quality_ok else "FAIL", "quality": quality_line}) + print(f"[L159Capture] view={view['name']} quality={'PASS' if quality_ok else 'FAIL'} " + f"file={jpg.relative_to(ROOT)}", flush=True) + + (ARTIFACTS / "manifest.json").write_text( + json.dumps(manifest, indent=2) + "\n", encoding="utf-8") + with (ARTIFACTS / "INDEX.md").open("w", encoding="utf-8") as index: + index.write("# L159 owner landing pad captures\n\n" + "All poses use the seed 0 layout resolved for L151. Eye-height after views " + "reuse the six L151 cameras; each pad also has one pulled-back wide view.\n\n") + for view in chamber_views(layout): + image = f"after-l159-{view['name']}.jpg" + if view["view_kind"] == "eye": + before = f"after-l151-{view['name']}.jpg" + index.write(f"## {view['passage']} / {view['side']} landing\n\n" + f"- Before: [{before}](../../Linux151/captures/{before})\n" + f"- After: [eye view]({image})\n") + else: + index.write(f"- After: [wide view]({image})\n\n") + index.write(f"Capture quality failures: {len(failures)}/{len(manifest)}.\n") + print(f"[L159CaptureSummary] views={len(manifest)} " + f"quality_failures={len(failures)}", flush=True) + return 0 if not failures else 1 + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except Exception as error: + print(f"[L159CaptureFailure] {error}", file=sys.stderr, flush=True) + raise SystemExit(1) diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/RunL159SeedSweep.py b/Standalone/Research/WorldAssemblerM3/Linux159/RunL159SeedSweep.py new file mode 100644 index 0000000..3b7ebf2 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux159/RunL159SeedSweep.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +"""Run the L159 landing-pad, passage, and seam gates across 16 owner seeds.""" +from __future__ import annotations + +import argparse +import json +import re +import subprocess +import time +from pathlib import Path + +from PassageEnvelopeAudit import audit_layout + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l159/seeds" +BIN = ROOT / "Saved/Linux/l159/bin/VoxelForgeCoreHeadless-l159-clang" +DATA = ROOT / "Standalone/data/owner_world.json" +STAMP = "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640" +STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M) +DISPATCH = { + "tunnel-network": re.compile( + r"^\[DensityDispatch\] strate=2 generator=TunnelNetwork " + r"recipe=Core\.Caves\.PrimitiveField version=1 " + r"bound_path=Caves-native adapter=FCavesFieldAdapter$", re.M), + "vertical-shafts": re.compile( + r"^\[DensityDispatch\] strate=3 generator=VerticalShafts " + r"recipe=Core\.Caves\.PrimitiveField version=1 " + r"bound_path=Caves-native adapter=FCavesFieldAdapter$", re.M), +} +ROUTES = { + "tunnel-network": re.compile( + r"^\[ResolvedStrateRouteAudit\] strate=2 .*unsupported=0 " + r"grade_failures=0 .*status=PASS$", re.M), + "vertical-shafts": re.compile( + r"^\[ResolvedStrateRouteAudit\] strate=3 .*unsupported=0 " + r"grade_failures=0 .*status=PASS$", re.M), +} +CONTROLS = { + "tunnel-network": re.compile( + r"^\[TunnelNetworkBlockedRouteControl\].*expected=FAIL status=PASS$", re.M), + "vertical-shafts": re.compile( + r"^\[VerticalShaftsBlockedRouteControl\].*expected=FAIL status=PASS$", re.M), +} +REQUIRED = { + "passage_summary": re.compile(r"^\[ResolvedPassageAuditSummary\].*status=PASS$", re.M), + "seams": re.compile(r"^\[PassageTileSeamAudit\].*status=PASS$", re.M), + "shell": re.compile(r"^\[PassageShellAuditSummary\].*status=PASS$", re.M), + "naturalness": re.compile(r"^\[PassageNaturalnessSummary\].*status=PASS$", re.M), + "mouth_profile": re.compile(r"^\[PassageMouthProfileSummary\].*status=PASS$", re.M), + "ripple": re.compile(r"^\[PassageRippleAuditSummary\].*status=PASS$", re.M), + "interior_capsules": re.compile( + r"^\[PassageInteriorCapsuleAuditSummary\].*status=PASS$", re.M), + "landing_pads": re.compile( + r"^\[LandingPadAuditSummary\] pads=6 passed=6 negative_controls=24/24 status=PASS$", re.M), + "layout_controls": re.compile( + r"^\[ResolvedLayoutValidatorControls\] rejected=10/10 status=PASS$", re.M), + "floor_profile_controls": re.compile( + r"^\[FloorProfileBlendNegativeControls\].*detected=true/true status=PASS$", re.M), + "naturalness_control": re.compile( + r"^\[PassageNaturalnessNegativeControl\].*detected=true$", re.M), + "mouth_control": re.compile( + r"^\[PassageMouthProfileNegativeControl\].*detected=true$", re.M), +} + + +def passage_rows(content: str) -> list[str]: + return re.findall(r"^\[ResolvedPassageAudit\].*$", content, re.M) + + +def grade_audit(content: str) -> tuple[bool, list[str]]: + rows = re.findall(r"^\[PassagePlanGradeAudit\].*$", content, re.M) + ids = set() + passed = bool(rows) + for row in rows: + identifier = re.search(r"\bid=([^ ]+)", row) + maximum = re.search(r"\bmax_grade_deg=([0-9.]+)", row) + limit = re.search(r"\blimit_deg=([0-9.]+)", row) + violations = re.search(r"\bviolations=(\d+)", row) + status = "status=PASS" in row + if identifier: + ids.add(identifier.group(1)) + passed &= bool(identifier and maximum and limit and violations and status + and float(maximum.group(1)) <= float(limit.group(1)) + and float(limit.group(1)) == 15.0 + and int(violations.group(1)) == 0) + return passed and len(ids) >= 3, rows + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--kind", choices=tuple(DISPATCH), required=True) + parser.add_argument("--start-seed", type=int, default=0) + parser.add_argument("--end-seed", type=int, default=15) + args = parser.parse_args() + if not 0 <= args.start_seed <= args.end_seed <= 15: + raise SystemExit("seed range must be within 0..15 and start <= end") + if not BIN.is_file() or not DATA.is_file(): + raise SystemExit("missing L159 Clang binary or composed owner fixture") + mode_out = OUT / args.kind + mode_out.mkdir(parents=True, exist_ok=True) + partial = mode_out / "runs-partial.json" + results = (json.loads(partial.read_text(encoding="utf-8")) + if partial.is_file() and args.start_seed > 0 else []) + completed = {row["seed"] for row in results} + for seed in range(args.start_seed, args.end_seed + 1): + if seed in completed: + continue + log = mode_out / f"seed{seed}.log" + layout = mode_out / f"seed{seed}.json" + command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(BIN), str(DATA), "--world-assembler-prototype", + "--stream-benchmark", "--stream-pipeline", "--workers=8", "--clip-radius=3", + "--max-clip-level=8", "--max-level=0", "--force-generate", f"--seed={seed}", + "--recipe=surface-world", "--density-dispatch-report", + "--audit-resolved-layout-passages", "--audit-passage-tile-seams", + f"--resolved-layout-output={layout}"] + started = time.monotonic() + with log.open("w", encoding="utf-8") as output: + proc = subprocess.run(command, cwd=ROOT, stdout=output, + stderr=subprocess.STDOUT, check=False, timeout=1740) + content = log.read_text(encoding="utf-8", errors="replace") + stamp = STAMP_RE.search(content) + checks = {name: bool(pattern.search(content)) for name, pattern in REQUIRED.items()} + checks["process_exit_zero"] = proc.returncode == 0 + checks["source_stamp"] = stamp is not None and stamp.group(1) == STAMP + checks["dispatch"] = bool(DISPATCH[args.kind].search(content)) + checks["route"] = bool(ROUTES[args.kind].search(content)) + checks["blocked_route_control"] = bool(CONTROLS[args.kind].search(content)) + + passages = passage_rows(content) + checks["three_passages_walkable_and_open"] = ( + len(passages) == 3 and all("walkability=PASS" in row + and "interior_air=PASS" in row + and re.search(r"\bblocked=0\b", row) + and re.search(r"\bunsupported=0\b", row) + and re.search(r"\bgrade_failures=0\b", row) + for row in passages)) + checks["three_interior_negative_controls"] = len(re.findall( + r"^\[ResolvedPassageInteriorNegativeControl\].*detected=true status=PASS$", + content, re.M)) == 3 + checks["three_ripple_gap_controls"] = len(re.findall( + r"^\[PassageRippleSamplingControl\].*status=PASS$", content, re.M)) == 3 + checks["three_blocked_passage_controls"] = len(re.findall( + r"^\[ResolvedPassageBlockedControl\].*detected=true$", content, re.M)) == 3 + chamber_rows = re.findall(r"^\[PassageLandingChamberAudit\].*$", content, re.M) + checks["six_chamber_floors"] = (len(chamber_rows) == 6 and all( + "status=PASS" in row and re.search(r"\bsolid_samples=0\b", row) + and re.search(r"\bgrade_failures=0\b", row) for row in chamber_rows)) + pad_rows = re.findall(r"^\[LandingPadAudit\].*$", content, re.M) + checks["six_landing_pad_audits"] = len(pad_rows) == 6 and all( + "status=PASS" in row and "negative_controls=4/4" in row + and all(f"{control}=detected" in row for control in ( + "pad_off", "tilt_2pct", "blend_B_half", "bore_mask_removed")) + for row in pad_rows) + checks["plan_grade"] = grade_audit(content)[0] + chamber_controls = re.search( + r"^\[PassageLandingChamberNegativeControlSummary\] " + r"detected=(\d+)/6 .*status=OBSERVED$", content, re.M) + checks["chamber_negative_control"] = bool( + chamber_controls and int(chamber_controls.group(1)) > 0) + + checks["three_ripple_profiles"] = len(re.findall( + r"^\[PassageRippleAudit\].*status=PASS$", content, re.M)) >= 3 + checks["passage_count"] = len(re.findall( + r"^\[ResolvedPassageAudit\].*walkability=PASS", content, re.M)) == 3 + checks["layout_output"] = layout.is_file() + envelope = audit_layout(json.loads(layout.read_text(encoding="utf-8"))) \ + if layout.is_file() else None + checks["envelope"] = bool(envelope and envelope["passed"] + and envelope["outside_chamber_conflicts"] == 0) + checks["envelope_negative_control"] = bool(envelope + and envelope["negative_controls"] == envelope["negative_controls_expected"] == 1) + checks["landing_content_band"] = bool(envelope + and envelope["landing_content_band_passed"] + and len(envelope["landing_content_band"]) == 6) + passed = all(checks.values()) + failed = [name for name, ok in checks.items() if not ok] + row = {"kind": args.kind, "seed": seed, + "verdict": "PASS" if passed else "FAIL", + "reason": ", ".join(failed) if failed else "all requested gates pass", + "exit": proc.returncode, "checks": checks, + "plan_grade_rows": grade_audit(content)[1], + "envelope_audit": envelope, + "elapsed_s": round(time.monotonic() - started, 3), + "log": str(log.relative_to(ROOT)), "layout": str(layout.relative_to(ROOT))} + results.append(row) + print("[L159SeedSweep] " + json.dumps(row, sort_keys=True), flush=True) + partial.write_text(json.dumps(results, indent=2) + "\n", encoding="utf-8") + + results.sort(key=lambda row: row["seed"]) + passed_count = sum(row["verdict"] == "PASS" for row in results) + completed_count = len(results) + missing_seeds = sorted(set(range(16)) - {row["seed"] for row in results}) + summary = {"kind": args.kind, "source_stamp": STAMP, + "seeds": [row["seed"] for row in results], + "completed": completed_count, "passed": passed_count, + "failed": completed_count - passed_count, "missing_seeds": missing_seeds, + "results": results} + (mode_out / "summary.json").write_text(json.dumps(summary, indent=2) + "\n", + encoding="utf-8") + status = "PASS" if completed_count == 16 and passed_count == 16 else "FAIL" + print(f"[L159SeedSweepSummary] kind={args.kind} passed={passed_count}/{completed_count} " + f"failed={completed_count-passed_count} missing={len(missing_seeds)} status={status}", + flush=True) + return 0 if status == "PASS" else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/captures/INDEX.md b/Standalone/Research/WorldAssemblerM3/Linux159/captures/INDEX.md new file mode 100644 index 0000000..934f9d6 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux159/captures/INDEX.md @@ -0,0 +1,41 @@ +# L159 owner landing pad captures + +All poses use the seed 0 layout resolved for L151. Eye-height after views reuse the six L151 cameras; each pad also has one pulled-back wide view. + +## passage/0-1/0 / upper landing + +- Before: [after-l151-0-1-0-upper-landing.jpg](../../Linux151/captures/after-l151-0-1-0-upper-landing.jpg) +- After: [eye view](after-l159-0-1-0-upper-landing.jpg) +- After: [wide view](after-l159-0-1-0-upper-wide.jpg) + +## passage/0-1/0 / lower landing + +- Before: [after-l151-0-1-0-lower-landing.jpg](../../Linux151/captures/after-l151-0-1-0-lower-landing.jpg) +- After: [eye view](after-l159-0-1-0-lower-landing.jpg) +- After: [wide view](after-l159-0-1-0-lower-wide.jpg) + +## passage/1-2/0 / upper landing + +- Before: [after-l151-1-2-0-upper-landing.jpg](../../Linux151/captures/after-l151-1-2-0-upper-landing.jpg) +- After: [eye view](after-l159-1-2-0-upper-landing.jpg) +- After: [wide view](after-l159-1-2-0-upper-wide.jpg) + +## passage/1-2/0 / lower landing + +- Before: [after-l151-1-2-0-lower-landing.jpg](../../Linux151/captures/after-l151-1-2-0-lower-landing.jpg) +- After: [eye view](after-l159-1-2-0-lower-landing.jpg) +- After: [wide view](after-l159-1-2-0-lower-wide.jpg) + +## passage/2-3/0 / upper landing + +- Before: [after-l151-2-3-0-upper-landing.jpg](../../Linux151/captures/after-l151-2-3-0-upper-landing.jpg) +- After: [eye view](after-l159-2-3-0-upper-landing.jpg) +- After: [wide view](after-l159-2-3-0-upper-wide.jpg) + +## passage/2-3/0 / lower landing + +- Before: [after-l151-2-3-0-lower-landing.jpg](../../Linux151/captures/after-l151-2-3-0-lower-landing.jpg) +- After: [eye view](after-l159-2-3-0-lower-landing.jpg) +- After: [wide view](after-l159-2-3-0-lower-wide.jpg) + +Capture quality failures: 0/12. diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-landing.jpg b/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-landing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e19b728afac6f3c9fcd5b93667b2d179bdb1f18 GIT binary patch literal 21491 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%0Af~^?UVi>% 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 X#J~kQ7>Z~;qY6hu02Bi9|8D{Sg+i7s literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-upper-wide.jpg b/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-upper-wide.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eba55a8b812c2face2ca0bf40d278052952acfa4 GIT binary patch literal 32566 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 STM6bue+l;-P-nnAEBPO@E)wGa literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-wide.jpg b/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-wide.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bc3e24f160c1eb979923354efca5cc851ea79b15 GIT binary patch literal 15370 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 H9~=J<46GF% literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-wide.jpg b/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-wide.jpg new file mode 100644 index 0000000000000000000000000000000000000000..129ca172a0fbc95edb7a1736b27419ba37b0b90b GIT binary patch literal 17543 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

* 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 U2pkYNAaFq7fWTiOAhpN)Z#)3xw*UYD literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-landing.jpg b/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-landing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05dc67bd5182cecbe5b10f2d1266177a2bca654d GIT binary patch literal 16611 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 Y0U-e)0U-e)0U-e)0U?3kA+XNpF literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-landing.jpg b/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-landing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a5b9e8af48be25656bfa6fbc6559aaf85d8bd46 GIT binary patch literal 19257 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.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "0-1-0-upper-wide", + "passage": "passage/0-1/0", + "side": "upper", + "view_kind": "wide", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-upper-wide.jpg", + "camera_m": [ + 50.37038900644665, + -1.0987715292590199, + -368.3310546875 + ], + "target_m": [ + 35.08994442765048, + -5.843032638677283, + -372.5810546875 + ], + "yaw_deg": -107.24848481126239, + "pitch_deg": -14.8756820016388, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-upper-wide.jpg pixels=921600 mean_luma=119.719 stddev_luma=11.104 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "0-1-0-lower-landing", + "passage": "passage/0-1/0", + "side": "lower", + "view_kind": "eye", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-landing.jpg", + "camera_m": [ + 25.8369140625, + 3.19921875, + -736.6798828125 + ], + "target_m": [ + 17.97380590951016, + -1.1793118453464206, + -734.970169262755 + ], + "yaw_deg": -119.11101808688004, + "pitch_deg": 10.756207017349817, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-landing.jpg pixels=921600 mean_luma=112.097 stddev_luma=12.698 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "0-1-0-lower-wide", + "passage": "passage/0-1/0", + "side": "lower", + "view_kind": "wide", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-wide.jpg", + "camera_m": [ + 38.06841563381753, + 10.0102663427611, + -732.6298828125 + ], + "target_m": [ + 24.089556695168923, + 2.226211951034129, + -736.8798828125 + ], + "yaw_deg": -119.11101808688004, + "pitch_deg": -14.875682001638797, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-lower-wide.jpg pixels=921600 mean_luma=105.110 stddev_luma=2.648 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "1-2-0-upper-landing", + "passage": "passage/1-2/0", + "side": "upper", + "view_kind": "eye", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-landing.jpg", + "camera_m": [ + 19.166015625, + -14.2001953125, + -731.8810546875 + ], + "target_m": [ + 10.35825176774404, + -16.050410390488395, + -733.216132282697 + ], + "yaw_deg": -101.86342177874246, + "pitch_deg": -8.437834550031965, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-landing.jpg pixels=921600 mean_luma=117.708 stddev_luma=15.445 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "1-2-0-upper-wide", + "passage": "passage/1-2/0", + "side": "upper", + "view_kind": "wide", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-wide.jpg", + "camera_m": [ + 32.86698162517594, + -11.322082968962494, + -727.8310546875 + ], + "target_m": [ + 17.20873476783201, + -14.611354218719644, + -732.0810546875 + ], + "yaw_deg": -101.86342177874248, + "pitch_deg": -14.875682001638797, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-upper-wide.jpg pixels=921600 mean_luma=105.434 stddev_luma=3.032 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "1-2-0-lower-landing", + "passage": "passage/1-2/0", + "side": "lower", + "view_kind": "eye", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-landing.jpg", + "camera_m": [ + 19.166015625, + -14.2001953125, + -753.05390625 + ], + "target_m": [ + 10.48848361510052, + -16.587754362485967, + -751.7193175939389 + ], + "yaw_deg": -105.38384894032598, + "pitch_deg": 8.434788863627224, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-landing.jpg pixels=921600 mean_luma=120.892 stddev_luma=15.997 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "1-2-0-lower-wide", + "passage": "passage/1-2/0", + "side": "lower", + "view_kind": "wide", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-wide.jpg", + "camera_m": [ + 32.664398751510305, + -10.486214568077383, + -749.00390625 + ], + "target_m": [ + 17.237675178355673, + -14.73076399027466, + -753.25390625 + ], + "yaw_deg": -105.38384894032599, + "pitch_deg": -14.875682001638793, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-1-2-0-lower-wide.jpg pixels=921600 mean_luma=104.587 stddev_luma=2.079 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "2-3-0-upper-landing", + "passage": "passage/2-3/0", + "side": "upper", + "view_kind": "eye", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-landing.jpg", + "camera_m": [ + -20.0625, + -5.068359375, + -812.075390625 + ], + "target_m": [ + -13.604954164712868, + -11.337338700629157, + -813.6662645746064 + ], + "yaw_deg": 134.15112141809087, + "pitch_deg": -10.024269857937275, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-landing.jpg pixels=921600 mean_luma=119.468 stddev_luma=15.926 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "2-3-0-upper-wide", + "passage": "passage/2-3/0", + "side": "upper", + "view_kind": "wide", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-wide.jpg", + "camera_m": [ + -30.10757129933554, + 4.683386242645357, + -808.025390625 + ], + "target_m": [ + -18.627489814380638, + -6.46146589180648, + -812.275390625 + ], + "yaw_deg": 134.15112141809087, + "pitch_deg": -14.875682001638797, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-upper-wide.jpg pixels=921600 mean_luma=108.691 stddev_luma=5.224 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "2-3-0-lower-landing", + "passage": "passage/2-3/0", + "side": "lower", + "view_kind": "eye", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-landing.jpg", + "camera_m": [ + -20.0625, + -5.068359375, + -900.0333984375 + ], + "target_m": [ + -14.865342978484083, + -12.416118141706198, + -898.4427583280197 + ], + "yaw_deg": 144.72777711381306, + "pitch_deg": 10.022826283920647, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-landing.jpg pixels=921600 mean_luma=120.115 stddev_luma=17.038 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "version": "after-l159", + "view": "2-3-0-lower-wide", + "passage": "passage/2-3/0", + "side": "lower", + "view_kind": "wide", + "file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-wide.jpg", + "camera_m": [ + -28.146966477913647, + 6.361487595431864, + -895.9833984375 + ], + "target_m": [ + -18.90757621744091, + -6.701194656490266, + -900.2333984375 + ], + "yaw_deg": 144.72777711381306, + "pitch_deg": -14.8756820016388, + "source_stamp": "5b8ab5e84364e26c1a555428fba8bedb23faed14ef0f6b7d397edf654883d640", + "pose_layout_identity": "resolved-layout-v3-fnv64:ed02312296ac2003", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-2-3-0-lower-wide.jpg pixels=921600 mean_luma=104.815 stddev_luma=2.399 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + } +] diff --git a/Standalone/Research/WorldAssemblerM3/Linux159/l159-pad-stamp.patch b/Standalone/Research/WorldAssemblerM3/Linux159/l159-pad-stamp.patch new file mode 100644 index 0000000..bff6bbf --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux159/l159-pad-stamp.patch @@ -0,0 +1,1068 @@ +diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +index 4799b9e..13440df 100644 +--- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h ++++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +@@ -512,7 +512,8 @@ namespace VoxelForgeCore + // boundary-blended host rock from widening the authored passage wall. + // v238 plans one resolved passage spline with explicit landing chambers. + // v239 plans their floor planes as the passage's continuous floor profile. +- inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 239; ++ // v240 replaces chamber boxes and shells with bounded clamp-and-cone landing pads. ++ inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 240; + + enum class FieldChannel : std::uint32_t + { +diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h +index 6b1a6af..3ce93e4 100644 +--- a/Standalone/Core/src/ShapeWorldInternal.h ++++ b/Standalone/Core/src/ShapeWorldInternal.h +@@ -56,6 +56,11 @@ static bool VF_IsL130PassageReachProofAuditEnabled() + static constexpr double VF_PassageShellThicknessMetres=0.75; + static constexpr double VF_PassageWallReliefMetres=0.21; + static constexpr double VF_PassageCornerBlendMetres=0.50; ++static constexpr double VF_LandingPadConeSlope=0.2125565616700221; // tan(12 degrees) ++static constexpr double VF_LandingPadFillDepthMetres=1.25; ++static constexpr double VF_LandingPadHeadroomMetres=3.0; ++static constexpr double VF_LandingPadBlendRadiusMetres=8.0; ++static constexpr double VF_LandingPadSmoothMinMaximumMetres=0.50; + static constexpr double VF_PassageReachMarginMetres=0.01; + // Radial support in metres: shell + maximum relief + the smooth-max support + // (corner-blend width / 6) + a 1 cm guard for float and bound rounding. +@@ -1234,8 +1239,11 @@ public: + + float ApplyResolvedStratePassageCarves(float density,float X,float Y,float Z, + float nativeTunnelFieldDensity=std::numeric_limits::lowest(), +- float nativeFloorSupport=std::numeric_limits::lowest()) const ++ float nativeFloorSupport=std::numeric_limits::lowest(), ++ float* outTubeOnlyDistance=nullptr) const + { ++ if(outTubeOnlyDistance) ++ *outTubeOnlyDistance=std::numeric_limits::infinity(); + VoxelForgeCore::Linux77Profiler::FScopedPhase l77PassagePhase( + VoxelForgeCore::Linux77Profiler::EPhase::Passage); + if(!ResolvedLayout||ResolvedLayout->passages.empty()||!std::isfinite(X) +@@ -1280,8 +1288,6 @@ public: + double unionDistance=std::numeric_limits::infinity(); + double unionShellDistance=std::numeric_limits::infinity(); + double unionFloorShellDistance=std::numeric_limits::infinity(); +- double unionLandingChamberFloorShellDistance= +- std::numeric_limits::infinity(); + double plannedTunnelPassageShellDistance=std::numeric_limits::infinity(); + const std::uint32_t reliefSeed=static_cast(Owner?Owner->Seed:0); + const auto* queryStratum=FindBoundStratumForManagerZ(Z); +@@ -1324,48 +1330,6 @@ public: + if(passageProfile)++passageProfile->passageIterations; + const auto& constants=PassageComposerConstants[passageIndex]; + +- const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1* landingChamber=nullptr; +- if(queryStratum&&queryStratum->Resolved) +- { +- if(queryStratum->StrateIndex==passage.upperStrateIndex) +- landingChamber=&passage.upperLandingChamber; +- else if(queryStratum->StrateIndex==passage.lowerStrateIndex) +- landingChamber=&passage.lowerLandingChamber; +- } +- if(landingChamber&&landingChamber->radiusSubvoxels>0 +- &&landingChamber->clearHeightSubvoxels>0) +- { +- const double centerX=static_cast( +- landingChamber->floorCenterSubvoxels[0]); +- const double centerY=static_cast( +- landingChamber->floorCenterSubvoxels[1]); +- const double floorCenterZ=static_cast( +- landingChamber->floorCenterSubvoxels[2]) +- +(landingChamber->floorGradientQ16[0]*(qx-centerX) +- +landingChamber->floorGradientQ16[1]*(qy-centerY))/65536.0; +- const double radialDistance=DeterministicSqrt( +- (qx-centerX)*(qx-centerX)+(qy-centerY)*(qy-centerY)) +- -landingChamber->radiusSubvoxels; +- const double floorDistance=floorCenterZ-qz; +- const double ceilingDistance=qz-(floorCenterZ +- +landingChamber->clearHeightSubvoxels); +- const double chamberDistance=std::max({radialDistance, +- floorDistance,ceilingDistance}); +- const double chamberShellDistance=std::max(-chamberDistance, +- chamberDistance-shellThickness); +- const double chamberFloorShellDistance=std::max( +- std::max(-floorDistance,floorDistance-shellThickness), +- radialDistance); +- unionDistance=std::min(unionDistance,chamberDistance); +- unionShellDistance=std::min(unionShellDistance,chamberShellDistance); +- unionFloorShellDistance=std::min(unionFloorShellDistance, +- chamberFloorShellDistance); +- unionLandingChamberFloorShellDistance=std::min( +- unionLandingChamberFloorShellDistance,chamberFloorShellDistance); +- if(passageTargetsPlannedTunnelNetwork) +- plannedTunnelPassageShellDistance=std::min( +- plannedTunnelPassageShellDistance,chamberShellDistance); +- } + if(passageTargetsNativeCaveField&&!passageTargetsPlannedTunnelNetwork) + continue; + +@@ -1658,12 +1622,9 @@ public: + } + + if(!std::isfinite(unionDistance))return density; ++ if(outTubeOnlyDistance) ++ *outTubeOnlyDistance=static_cast(unionDistance/Q); + const float passageAirDistance=static_cast(-unionDistance/Q); +- // Keep the landing floor shell where it is exposed to the chamber. At +- // the tunnel joint, the passage void must be able to open through that +- // floor shell so its own continuous floor and shell define the throat. +- if(unionLandingChamberFloorShellDistance<0.0&&unionDistance>0.0) +- return static_cast(unionLandingChamberFloorShellDistance/Q); + const auto plannedPortalWalkCorridorContains=[&]() + { + if(!queryStratum||!queryStratum->Resolved +@@ -1746,90 +1707,6 @@ public: + departureTailDistance) + ||nearRouteSegment(*lastTwo,*last,PortalWalkLeadMetres,true,0.0); + }; +- const auto connectedSurfaceLandingShellContains=[&]() +- { +- if(!queryStratum||!queryStratum->Resolved +- ||queryStratum->Resolved->generatorKind!="SurfaceWorld")return false; +- const double queryX=qx/qPerMetre,queryY=qy/qPerMetre,queryZ=qz/qPerMetre; +- constexpr double ChamberShellThicknessMetres=0.75; +- constexpr double RouteClearanceMetres=1.25; +- constexpr double RouteHeightClearanceMetres=1.5; +- constexpr double PortalWalkLeadMetres=9.0; +- for(const auto& passage:ResolvedLayout->passages) +- { +- if(passage.upperStrateIndex!=queryStratum->StrateIndex)continue; +- const auto& chamber=passage.upperLandingChamber; +- if(chamber.radiusSubvoxels<=0||chamber.clearHeightSubvoxels<=0)continue; +- const double cx=static_cast(chamber.floorCenterSubvoxels[0])/qPerMetre; +- const double cy=static_cast(chamber.floorCenterSubvoxels[1])/qPerMetre; +- const double floorZ=static_cast(chamber.floorCenterSubvoxels[2])/qPerMetre +- +chamber.floorGradientQ16[0]/65536.0*(queryX-cx) +- +chamber.floorGradientQ16[1]/65536.0*(queryY-cy); +- const double radialDistance=std::hypot(queryX-cx,queryY-cy) +- -static_cast(chamber.radiusSubvoxels)/qPerMetre; +- const double floorDistance=floorZ-queryZ; +- const double ceilingDistance=queryZ-(floorZ +- +static_cast(chamber.clearHeightSubvoxels)/qPerMetre); +- const double chamberDistance=std::max({radialDistance, +- floorDistance,ceilingDistance}); +- const double chamberShellDistance=std::max(-chamberDistance, +- chamberDistance-ChamberShellThicknessMetres); +- if(chamberDistance<=0.0||chamberShellDistance>=0.0)continue; +- +- std::vector route; +- for(const auto& anchor:queryStratum->Resolved->anchors) +- if(anchor.kind=="route_point"&&anchor.values.size()>=3) +- route.push_back(&anchor); +- if(route.size()<2)continue; +- const double mouthZ=static_cast(passage.upperMouthSubvoxels[2]) +- /qPerMetre; +- std::size_t endpoint=route.size(); +- double endpointDistanceSquared=1.0; +- for(std::size_t index=0;indexvalues[0]/qPerMetre; +- const double y=route[index]->values[1]/qPerMetre; +- const double z=route[index]->values[2]/qPerMetre; +- const double dx=x-cx,dy=y-cy; +- const double distanceSquared=dx*dx+dy*dy; +- if(distanceSquared routeDistance(route.size(),0.0); +- for(std::size_t index=1;indexvalues[0]-route[index-1]->values[0]) +- /qPerMetre; +- const double dy=(route[index]->values[1]-route[index-1]->values[1]) +- /qPerMetre; +- routeDistance[index]=routeDistance[index-1]+std::hypot(dx,dy); +- } +- for(std::size_t index=1;indexPortalWalkLeadMetres)continue; +- const double routeX=ax+t*dx,routeY=ay+t*dy; +- const double routeZ=az+t*(b.values[2]-a.values[2])/qPerMetre; +- if(std::hypot(queryX-routeX,queryY-routeY)<=RouteClearanceMetres +- &&std::abs(queryZ-routeZ)<=RouteHeightClearanceMetres)return true; +- } +- } +- return false; +- }; + if(plannedTunnelStratum + &&nativeTunnelFieldDensity!=std::numeric_limits::lowest() + &&nativeTunnelFieldDensity<0.0f) +@@ -1893,13 +1770,95 @@ public: + return std::max(density,passageAirDistance); + if(unionDistance>0.0&&unionShellDistance<0.0&&density>=0.0f) + { +- if(connectedSurfaceLandingShellContains()) +- return std::max(density,passageAirDistance); + return static_cast(unionShellDistance/Q); + } + return std::max(density,passageAirDistance); + } + ++ float ApplyResolvedLandingPadStamps(float density,float X,float Y,float Z, ++ float tubeOnlyDistance) const ++ { ++ if(!ResolvedLayout||ResolvedLayout->passages.empty()||!std::isfinite(X) ++ ||!std::isfinite(Y)||!std::isfinite(Z))return density; ++ const auto* bound=FindBoundStratumForManagerZ(Z); ++ if(!bound||!bound->Resolved)return density; ++ const double coreMetres=std::max(1, ++ ResolvedLayout->coreVoxelSizeMicrometres)/1000000.0; ++ constexpr double Q=static_cast( ++ VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); ++ const double qPerMetre=Q/coreMetres; ++ const double xMetres=static_cast(X)*coreMetres; ++ const double yMetres=static_cast(Y)*coreMetres; ++ const double zMetres=static_cast(Z)*coreMetres; ++ const double tubeDistanceMetres=static_cast(tubeOnlyDistance)*coreMetres; ++ const auto* tileQueries=FScopedPassageTileQueries::CurrentFor(*this); ++ const auto* candidatePassages=tileQueries ++ ?&tileQueries->routePassageIndices():nullptr; ++ const std::size_t candidateCount=candidatePassages ++ ?candidatePassages->size():ResolvedLayout->passages.size(); ++ float result=density; ++ constexpr double CosTwelveDegrees=0.9781476007338057; ++ constexpr double OuterReachMetres=VF_PassageInfluenceReachMetres; ++ for(std::size_t offset=0;offset=ResolvedLayout->passages.size())continue; ++ const auto& passage=ResolvedLayout->passages[passageIndex]; ++ const auto applyPad=[&]( ++ const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& pad) ++ { ++ if(pad.radiusSubvoxels<=0)return; ++ const double centerX=static_cast(pad.floorCenterSubvoxels[0]) ++ /qPerMetre; ++ const double centerY=static_cast(pad.floorCenterSubvoxels[1]) ++ /qPerMetre; ++ const double floorP=static_cast(pad.floorCenterSubvoxels[2]) ++ /qPerMetre; ++ const double radius=std::max(3.0, ++ static_cast(std::max(0, ++ passage.mouthRadiusSubvoxels))/qPerMetre+1.0); ++ const double dx=xMetres-centerX,dy=yMetres-centerY; ++ const double radial=DeterministicSqrt(dx*dx+dy*dy); ++ const double outerRadius=radius+VF_LandingPadBlendRadiusMetres; ++ if(radial>outerRadius+OuterReachMetres ++ ||zMetresfloorP+VF_LandingPadHeadroomMetres ++ +VF_LandingPadConeSlope*VF_LandingPadBlendRadiusMetres ++ +OuterReachMetres)return; ++ const double coneRun=std::max(0.0,radial-radius); ++ const double lower=floorP-VF_LandingPadConeSlope*coneRun; ++ const double upper=floorP+VF_LandingPadConeSlope*coneRun; ++ const double fillDistanceMetres=std::max({ ++ CosTwelveDegrees*(zMetres-lower), ++ CosTwelveDegrees*(lower-VF_LandingPadFillDepthMetres-zMetres), ++ radial-outerRadius}); ++ const double airDistanceMetres=std::min({ ++ CosTwelveDegrees*(zMetres-upper), ++ CosTwelveDegrees*(upper+VF_LandingPadHeadroomMetres-zMetres), ++ outerRadius-radial}); ++ const double fillVoxels=fillDistanceMetres/coreMetres; ++ const double airVoxels=airDistanceMetres/coreMetres; ++ const double maskedFill=std::max(fillVoxels,-tubeDistanceMetres/coreMetres); ++ const double smoothWidthMetres=VF_LandingPadSmoothMinMaximumMetres ++ *std::clamp(radial-radius,0.0,1.0); ++ const float next=static_cast(result); ++ const float fill=static_cast(maskedFill); ++ const float width=static_cast(smoothWidthMetres/coreMetres); ++ const float clamped=width>0.0f ++ ?SmoothMinDistance(next,fill,width):std::min(next,fill); ++ result=std::max(clamped,static_cast(airVoxels)); ++ }; ++ if(passage.upperStrateIndex==bound->StrateIndex) ++ applyPad(passage.upperLandingChamber); ++ if(passage.lowerStrateIndex==bound->StrateIndex) ++ applyPad(passage.lowerLandingChamber); ++ } ++ return result; ++ } ++ + float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const + { + float graphDensity=0.0f; +@@ -1930,6 +1889,7 @@ public: + } + float composed=boundary; + float stamped=composed; ++ float tubeOnlyDistance=std::numeric_limits::infinity(); + if(!StampRuntime.empty()) + { + VoxelForgeCore::Linux77Profiler::FScopedPhase l77StampPhase( +@@ -1963,12 +1923,13 @@ public: + const float nativeTunnelFieldDensity=nativeTunnelField + ?graphDensity:std::numeric_limits::lowest(); + stamped=ApplyResolvedStratePassageCarves(stamped,X,Y,Z, +- nativeTunnelFieldDensity,nativeGraphFloorSupport); ++ nativeTunnelFieldDensity,nativeGraphFloorSupport, ++ &tubeOnlyDistance); + } + if(bTraceTnComposition) + std::printf("[L75TNCompositionTrace] input=%.9g graph=%.9g boundary=%.9g passage=%.9g stamp=%.9g native=1\n", + density,graphDensity,boundary,composed,stamped); +- return stamped; ++ return ApplyResolvedLandingPadStamps(stamped,X,Y,Z,tubeOnlyDistance); + } + // The legacy landmark demo retains its compatibility floor cap. Native caves + // already combine each floor with its wall before the single void carve above. +@@ -1985,12 +1946,14 @@ public: + VoxelForgeCore::Linux77Profiler::EPhase::Passage); + FScopedLegacyFieldTermTimer TermTimer( + ELegacyFieldTerm::ComposerPassage); +- final=ApplyResolvedStratePassageCarves(final,X,Y,Z); ++ final=ApplyResolvedStratePassageCarves(final,X,Y,Z, ++ std::numeric_limits::lowest(), ++ std::numeric_limits::lowest(),&tubeOnlyDistance); + } + if(bTraceTnComposition) + std::printf("[L75TNCompositionTrace] input=%.9g graph=%.9g boundary=%.9g passage=%.9g stamp=%.9g final=%.9g native=0\n", + density,graphDensity,boundary,composed,stamped,final); +- return final; ++ return ApplyResolvedLandingPadStamps(final,X,Y,Z,tubeOnlyDistance); + } + + bool ResolvedPassageIntersectsBox(const int32 minimum[3],const int32 maximum[3]) const +@@ -2033,26 +1996,35 @@ public: + } + if(overlaps(low,high))return true; + } +- const auto chamberOverlaps=[&]( +- const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& chamber) +- { +- const double cx=static_cast(chamber.floorCenterSubvoxels[0])/Q; +- const double cy=static_cast(chamber.floorCenterSubvoxels[1])/Q; +- const double cz=static_cast(chamber.floorCenterSubvoxels[2])/Q; +- const double radius=static_cast(chamber.radiusSubvoxels)/Q; +- const double floorExtent=radius*std::hypot( +- static_cast(chamber.floorGradientQ16[0])/65536.0, +- static_cast(chamber.floorGradientQ16[1])/65536.0); ++ const auto padOverlaps=[&]( ++ const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& pad, ++ std::int64_t mouthRadiusSubvoxels) ++ { ++ if(pad.radiusSubvoxels<=0)return false; ++ const double cx=static_cast(pad.floorCenterSubvoxels[0])/Q; ++ const double cy=static_cast(pad.floorCenterSubvoxels[1])/Q; ++ const double pz=static_cast(pad.floorCenterSubvoxels[2])/Q; ++ const double qPerMetre=Q*1000000.0/ ++ std::max(1,ResolvedLayout->coreVoxelSizeMicrometres); ++ const double coreMetres=Q/qPerMetre; ++ const double radius=std::max(3.0, ++ static_cast(std::max(0,mouthRadiusSubvoxels)) ++ /qPerMetre+1.0); ++ const double outerRadius=radius+VF_LandingPadBlendRadiusMetres; + const double extent=reachCoreVoxels+0.01; +- const double low[3]={cx-radius-extent,cy-radius-extent, +- cz-floorExtent-extent}; +- const double high[3]={cx+radius+extent,cy+radius+extent, +- cz+floorExtent+static_cast( +- chamber.clearHeightSubvoxels)/Q+extent}; ++ const double coneHeight=VF_LandingPadConeSlope ++ *VF_LandingPadBlendRadiusMetres; ++ const double low[3]={cx-outerRadius/coreMetres-extent, ++ cy-outerRadius/coreMetres-extent, ++ pz-(VF_LandingPadFillDepthMetres+coneHeight)/coreMetres-extent}; ++ const double high[3]={cx+outerRadius/coreMetres+extent, ++ cy+outerRadius/coreMetres+extent, ++ pz+(VF_LandingPadHeadroomMetres+coneHeight)/coreMetres+extent}; + return overlaps(low,high); + }; +- if(chamberOverlaps(passage.upperLandingChamber) +- ||chamberOverlaps(passage.lowerLandingChamber))return true; ++ if(padOverlaps(passage.upperLandingChamber,passage.mouthRadiusSubvoxels) ++ ||padOverlaps(passage.lowerLandingChamber,passage.mouthRadiusSubvoxels)) ++ return true; + } + return false; + } +@@ -5415,6 +5387,9 @@ private: + if(!ResolvedLayout||ResolvedLayout->passages.empty())return; + constexpr double Q=static_cast(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); + constexpr std::size_t CandidateFineSamplesPerSpan=5; ++ const double coreMetres=std::max(1, ++ ResolvedLayout->coreVoxelSizeMicrometres)/1000000.0; ++ const double qPerMetre=Q/coreMetres; + const double requiredReachCoreVoxels=VF_PassageInfluenceReachCoreVoxels( + ResolvedLayout->coreVoxelSizeMicrometres); + for(std::size_t passageIndex=0;passageIndexpassages.size(); +@@ -5471,40 +5446,47 @@ private: + std::ceil((localMaximum[axis]+localExtent)*Q)); + } + } +- const auto includeLandingChamber=[&]( +- const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& chamber) +- { +- const double cx=static_cast(chamber.floorCenterSubvoxels[0])/Q; +- const double cy=static_cast(chamber.floorCenterSubvoxels[1])/Q; +- const double cz=static_cast(chamber.floorCenterSubvoxels[2])/Q; +- const double radius=static_cast(chamber.radiusSubvoxels)/Q; +- const double gx=static_cast(chamber.floorGradientQ16[0])/65536.0; +- const double gy=static_cast(chamber.floorGradientQ16[1])/65536.0; +- const double floorExtent=radius*std::hypot(gx,gy); +- const double height=static_cast( +- chamber.clearHeightSubvoxels)/Q; +- const double extent=requiredReachCoreVoxels+0.01; +- const std::array minimum{ +- cx-radius-extent,cy-radius-extent,cz-floorExtent-extent}; +- const std::array maximum{ +- cx+radius+extent,cy+radius+extent, +- cz+floorExtent+height+extent}; ++ const auto includeLandingPad=[&]( ++ const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& pad, ++ std::int64_t mouthRadiusSubvoxels) ++ { ++ if(pad.radiusSubvoxels<=0)return; ++ const double cx=static_cast(pad.floorCenterSubvoxels[0])/Q; ++ const double cy=static_cast(pad.floorCenterSubvoxels[1])/Q; ++ const double pz=static_cast(pad.floorCenterSubvoxels[2])/Q; ++ const double radius=std::max(3.0, ++ static_cast(std::max(0,mouthRadiusSubvoxels)) ++ /qPerMetre+1.0); ++ const double outerRadius=radius+VF_LandingPadBlendRadiusMetres; ++ const double coneHeight=VF_LandingPadConeSlope ++ *VF_LandingPadBlendRadiusMetres; ++ const std::array baseMinimum{ ++ cx-outerRadius/coreMetres, ++ cy-outerRadius/coreMetres, ++ pz-(VF_LandingPadFillDepthMetres+coneHeight)/coreMetres}; ++ const std::array baseMaximum{ ++ cx+outerRadius/coreMetres, ++ cy+outerRadius/coreMetres, ++ pz+(VF_LandingPadHeadroomMetres+coneHeight)/coreMetres}; + FPassageProofBound proof; ++ const double extent=requiredReachCoreVoxels+0.01; + for(std::size_t axis=0;axis<3;++axis) + { +- routeMinimum[axis]=std::min(routeMinimum[axis],minimum[axis]); +- routeMaximum[axis]=std::max(routeMaximum[axis],maximum[axis]); +- proof.minimum[axis]=minimum[axis]; +- proof.maximum[axis]=maximum[axis]; ++ routeMinimum[axis]=std::min(routeMinimum[axis],baseMinimum[axis]); ++ routeMaximum[axis]=std::max(routeMaximum[axis],baseMaximum[axis]); ++ proof.minimum[axis]=baseMinimum[axis]-extent; ++ proof.maximum[axis]=baseMaximum[axis]+extent; + } + PassageProofBounds.push_back(proof); + }; + if(segmentIndex==0) +- includeLandingChamber( +- ResolvedLayout->passages[passageIndex].upperLandingChamber); ++ includeLandingPad(ResolvedLayout->passages[passageIndex] ++ .upperLandingChamber,ResolvedLayout->passages[passageIndex] ++ .mouthRadiusSubvoxels); + if(segmentEndIndex==segmentCount) +- includeLandingChamber( +- ResolvedLayout->passages[passageIndex].lowerLandingChamber); ++ includeLandingPad(ResolvedLayout->passages[passageIndex] ++ .lowerLandingChamber,ResolvedLayout->passages[passageIndex] ++ .mouthRadiusSubvoxels); + const double routeExtent=maximumRadiusSubvoxels/Q + +requiredReachCoreVoxels+0.01; + const double tileExtent=routeExtent; +@@ -5629,6 +5611,108 @@ private: + } + } + } ++ for(std::size_t passageIndex=0; ++ passageIndexpassages.size();++passageIndex) ++ { ++ const auto& passage=ResolvedLayout->passages[passageIndex]; ++ const auto sampleLandingPad=[&]( ++ const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& pad) ++ { ++ if(pad.radiusSubvoxels<=0)return; ++ const double centerX=static_cast( ++ pad.floorCenterSubvoxels[0])/qPerMetre; ++ const double centerY=static_cast( ++ pad.floorCenterSubvoxels[1])/qPerMetre; ++ const double floorP=static_cast( ++ pad.floorCenterSubvoxels[2])/qPerMetre; ++ const double radius=std::max(3.0, ++ static_cast(std::max(0, ++ passage.mouthRadiusSubvoxels))/qPerMetre+1.0); ++ const double probeRadius=radius+VF_LandingPadBlendRadiusMetres-0.25; ++ const std::array probeHeights{ ++ floorP-0.5*VF_LandingPadFillDepthMetres, ++ floorP+0.5*VF_LandingPadHeadroomMetres}; ++ for(const double probeZ:probeHeights) ++ { ++ const double sampleQ[3]={centerX*qPerMetre, ++ centerY*qPerMetre,probeZ*qPerMetre}; ++ const double sampleVoxel[3]={sampleQ[0]/Q, ++ sampleQ[1]/Q,sampleQ[2]/Q}; ++ const float contribution=ApplyResolvedLandingPadStamps( ++ 0.0f,static_cast(sampleVoxel[0]), ++ static_cast(sampleVoxel[1]), ++ static_cast(sampleVoxel[2]), ++ std::numeric_limits::infinity()); ++ ++sampled; ++ if(std::abs(contribution)<=1.0e-6f)continue; ++ ++signRelevant; ++ if(PassageProofNodes.empty() ++ ||!PassageProofBoundsOverlapNode(0,sampleVoxel,sampleVoxel)) ++ ++proofMisses; ++ std::array sampleMinimum{},sampleMaximum{}; ++ for(std::size_t axis=0;axis<3;++axis) ++ { ++ sampleMinimum[axis]=static_cast( ++ std::floor(sampleQ[axis])); ++ sampleMaximum[axis]=static_cast( ++ std::ceil(sampleQ[axis])); ++ } ++ const auto candidates=BuildPassageFeatureTileList( ++ sampleMinimum,sampleMaximum); ++ const bool featureContainsPassage=std::any_of( ++ candidates.begin(),candidates.end(), ++ [&](std::uint32_t featureIndex) ++ { ++ return featureIndex(edgeSampleVoxel[0]), ++ static_cast(edgeSampleVoxel[1]), ++ static_cast(edgeSampleVoxel[2]), ++ std::numeric_limits::infinity()); ++ ++sampled; ++ if(std::abs(edgeContribution)<=1.0e-6f)continue; ++ ++signRelevant; ++ if(PassageProofNodes.empty() ++ ||!PassageProofBoundsOverlapNode(0,edgeSampleVoxel,edgeSampleVoxel)) ++ ++proofMisses; ++ for(std::size_t axis=0;axis<3;++axis) ++ { ++ sampleMinimum[axis]=static_cast( ++ std::floor(edgeSampleQ[axis])); ++ sampleMaximum[axis]=static_cast( ++ std::ceil(edgeSampleQ[axis])); ++ } ++ const auto edgeCandidates=BuildPassageFeatureTileList( ++ sampleMinimum,sampleMaximum); ++ const bool edgeFeatureContainsPassage=std::any_of( ++ edgeCandidates.begin(),edgeCandidates.end(), ++ [&](std::uint32_t featureIndex) ++ { ++ return featureIndex0&&signRelevant>0 + &&proofMisses==0&&featureMisses==0; + std::printf("[L130PassageReachProofAudit] reach_m=%.3f sampled=%llu sign_relevant=%llu proof_misses=%llu feature_misses=%llu status=%s\n", +diff --git a/Standalone/Source/StreamBenchmarkPipeline.h b/Standalone/Source/StreamBenchmarkPipeline.h +index 2fcf4b5..1b502ed 100644 +--- a/Standalone/Source/StreamBenchmarkPipeline.h ++++ b/Standalone/Source/StreamBenchmarkPipeline.h +@@ -4703,78 +4703,6 @@ namespace StandaloneStreamBenchmark + [index](const auto& s){return s.strateIndex==index;}); + return it==ResolvedLayout->strates.end()?nullptr:&*it; + }; +- const auto landingChamberConnectionContains=[&]( +- const VoxelForgeCore::ResolvedLayoutPassageV1& passage,bool upper, +- double xMetres,double yMetres,double zMetres) +- { +- const auto& chamber=upper?passage.upperLandingChamber +- :passage.lowerLandingChamber; +- const auto* stratum=findStratum(upper?passage.upperStrateIndex +- :passage.lowerStrateIndex); +- if(!stratum||chamber.radiusSubvoxels<=0)return false; +- std::vector route; +- for(const auto& anchor:stratum->anchors) +- if(anchor.kind=="route_point"&&anchor.values.size()>=3) +- route.push_back(&anchor); +- if(route.size()<2)return false; +- const double cx=qToMetres(chamber.floorCenterSubvoxels[0]); +- const double cy=qToMetres(chamber.floorCenterSubvoxels[1]); +- const double mouthZ=qToMetres(upper?passage.upperMouthSubvoxels[2] +- :passage.lowerMouthSubvoxels[2]); +- std::size_t endpoint=route.size(); +- double endpointDistanceSquared=1.0; +- for(std::size_t index=0;indexvalues[0])-cx; +- const double dy=qToMetres(route[index]->values[1])-cy; +- const double z=qToMetres(route[index]->values[2]); +- const double distanceSquared=dx*dx+dy*dy; +- if(distanceSquared routeDistance(route.size(),0.0); +- for(std::size_t index=1;indexvalues[0] +- -route[index-1]->values[0]); +- const double dy=qToMetres(route[index]->values[1] +- -route[index-1]->values[1]); +- routeDistance[index]=routeDistance[index-1]+std::hypot(dx,dy); +- } +- for(std::size_t index=1;index9.0)continue; +- const double routeX=ax+t*dx,routeY=ay+t*dy; +- const double routeZ=az+t*qToMetres(b.values[2]-a.values[2]); +- const double lateralDistance=std::hypot(xMetres-routeX, +- yMetres-routeY); +- if(stratum->generatorKind=="TunnelNetwork" +- ||stratum->generatorKind=="VerticalShafts") +- { +- const double routeFloor=routeZ-1.13; +- if(lateralDistance<=0.80&&zMetres>=routeFloor-0.30 +- &&zMetres<=routeFloor+2.25)return true; +- } +- else if(lateralDistance<=1.25 +- &&std::abs(zMetres-routeZ)<=1.5)return true; +- } +- return false; +- }; + const auto controlSnapshot=CoreSnapshot.withoutResolvedLayoutPassages(); + VoxelForgeCore::World blockedWorld(controlSnapshot); + std::string blockedCompileError; +@@ -5153,89 +5081,6 @@ namespace StandaloneStreamBenchmark + if(interior<=0.0f)++audit.interiorViolations; + } + } +- constexpr std::array chamberFloorRadii{{0.0,2.5,5.0}}; +- constexpr std::array chamberWallHeights{{1.13,3.20}}; +- constexpr std::size_t ChamberAngularSamples=16; +- for(const bool upper:{true,false}) +- { +- const auto& chamber=upper?passage.upperLandingChamber +- :passage.lowerLandingChamber; +- if(chamber.radiusSubvoxels<=0||chamber.clearHeightSubvoxels<=0)continue; +- const double centerX=qToMetres(chamber.floorCenterSubvoxels[0]); +- const double centerY=qToMetres(chamber.floorCenterSubvoxels[1]); +- const double baseFloorZ=qToMetres(chamber.floorCenterSubvoxels[2]); +- const double radius=qToMetres(chamber.radiusSubvoxels); +- const double gx=chamber.floorGradientQ16[0]/65536.0; +- const double gy=chamber.floorGradientQ16[1]/65536.0; +- for(const double radial:chamberFloorRadii) +- { +- if(radial>=radius-1.0)continue; +- const std::size_t angles=radial==0.0?1:ChamberAngularSamples; +- for(std::size_t angleIndex=0;angleIndex(angleIndex)/ChamberAngularSamples; +- const double sampleX=centerX+radial*std::cos(angle); +- const double sampleY=centerY+radial*std::sin(angle); +- const double floorZ=baseFloorZ+gx*(sampleX-centerX) +- +gy*(sampleY-centerY); +- for(const double depth:PassageShellAuditDepthsMetres) +- { +- const double sampleZ=floorZ-depth; +- const VoxelForgeCore::Vec3d position{sampleX/coreMetres, +- sampleY/coreMetres,sampleZ/coreMetres}; +- if(Native.densityAt(position)<0.0f)continue; +- if(landingChamberConnectionContains(passage,upper, +- sampleX,sampleY,sampleZ)) +- {++audit.chamberConnectionSkips;continue;} +- ++audit.chamberFloorSamples; +- const float density=Field.densityAt(position); +- if(density>=PassageShellDensityTolerance) +- { +- ++audit.chamberFloorViolations; +- std::printf("[PassageLandingChamberShellSample] id=%s side=%s kind=floor_missing xyz_m=(%.3f,%.3f,%.3f) native=%.6f density=%.6f\n", +- passage.stableId.c_str(),upper?"upper":"lower", +- sampleX,sampleY,sampleZ,Native.densityAt(position),density); +- } +- } +- } +- } +- for(std::size_t angleIndex=0;angleIndex(angleIndex)/ChamberAngularSamples; +- const double nx=std::cos(angle),ny=std::sin(angle); +- for(const double depth:PassageShellAuditDepthsMetres) +- for(const double height:chamberWallHeights) +- { +- const double sampleX=centerX+(radius+depth)*nx; +- const double sampleY=centerY+(radius+depth)*ny; +- const double floorZ=baseFloorZ+gx*(sampleX-centerX) +- +gy*(sampleY-centerY); +- const double sampleZ=floorZ+height; +- const VoxelForgeCore::Vec3d position{sampleX/coreMetres, +- sampleY/coreMetres,sampleZ/coreMetres}; +- if(Native.densityAt(position)<0.0f)continue; +- if(passageInteriorWinsAt(sampleX,sampleY,sampleZ, +- std::numeric_limits::max(), +- std::numeric_limits::max(),passageIndex) +- ||landingChamberConnectionContains(passage,upper, +- sampleX,sampleY,sampleZ)) +- {++audit.chamberConnectionSkips;continue;} +- ++audit.chamberWallSamples; +- const float density=Field.densityAt(position); +- if(density>=PassageShellDensityTolerance) +- { +- ++audit.chamberWallViolations; +- std::printf("[PassageLandingChamberShellSample] id=%s side=%s kind=wall_missing xyz_m=(%.3f,%.3f,%.3f) native=%.6f density=%.6f radial_m=%.3f height_m=%.3f\n", +- passage.stableId.c_str(),upper?"upper":"lower", +- sampleX,sampleY,sampleZ,Native.densityAt(position),density, +- radius+depth,height); +- } +- } +- } +- } + return audit; + }; + const auto mouthInContent=[&](std::int32_t index, +@@ -5305,10 +5150,257 @@ namespace StandaloneStreamBenchmark + } + return total; + }; ++ struct FLandingPadAudit ++ { ++ std::uint64_t flatSamples=0,flatFailures=0; ++ std::uint64_t supportSamples=0,supportFailures=0; ++ std::uint64_t headroomSamples=0,headroomFailures=0; ++ std::uint64_t blendRootSamples=0,blendMissing=0,blendGradeFailures=0; ++ std::uint64_t negativeControlsDetected=0; ++ double maximumFlatnessMetres=0.0,maximumGradeDegrees=0.0; ++ bool passed=false; ++ }; ++ const auto auditLandingPad=[&](const VoxelForgeCore::World& field, ++ const VoxelForgeCore::ResolvedLayoutPassageV1& passage,bool upper) ++ { ++ constexpr double ConeSlope=0.2125565616700221; ++ constexpr double CosTwelveDegrees=0.9781476007338057; ++ constexpr double FillDepthMetres=1.25,HeadroomMetres=3.0; ++ constexpr double BlendRadiusMetres=8.0; ++ constexpr double FlatnessLimitMetres=0.020; ++ constexpr double GradeLimitDegrees=15.0; ++ constexpr std::size_t RadialDirections=36; ++ constexpr double FloorSearchStepMetres=0.125; ++ FLandingPadAudit audit; ++ const auto& pad=upper?passage.upperLandingChamber ++ :passage.lowerLandingChamber; ++ if(pad.radiusSubvoxels<=0)return audit; ++ const double centerX=qToMetres(pad.floorCenterSubvoxels[0]); ++ const double centerY=qToMetres(pad.floorCenterSubvoxels[1]); ++ const double floorP=qToMetres(pad.floorCenterSubvoxels[2]); ++ const double radius=std::max(3.0, ++ qToMetres(std::max(0,passage.mouthRadiusSubvoxels))+1.0); ++ const auto densityMetres=[&](const VoxelForgeCore::World& source, ++ double x,double y,double z) ++ { ++ const float value=source.densityAt({x/coreMetres,y/coreMetres, ++ z/coreMetres}); ++ return std::isfinite(value)?static_cast(value)*coreMetres ++ :std::numeric_limits::quiet_NaN(); ++ }; ++ struct FFloorRoot ++ {double z=0.0;std::uint32_t crossings=0;bool found=false;}; ++ const auto findFloorRoot=[&](auto&& sampleDensity,double x,double y, ++ double low,double high) ++ { ++ FFloorRoot result; ++ double previousZ=low; ++ double previous=sampleDensity(x,y,previousZ); ++ if(!std::isfinite(previous))return result; ++ for(double z=low+FloorSearchStepMetres; ++ z=0.0) ++ { ++ const double denominator=current-previous; ++ const double t=std::abs(denominator)>1.0e-12 ++ ?std::clamp(-previous/denominator,0.0,1.0):0.0; ++ const double root=std::lerp(previousZ,currentZ,t); ++ ++result.crossings; ++ if(!result.found)result.z=root; ++ result.found=true; ++ } ++ previousZ=currentZ; ++ previous=current; ++ if(currentZ>=high)break; ++ } ++ return result; ++ }; ++ const auto fieldDensity=[&](double x,double y,double z) ++ {return densityMetres(field,x,y,z);}; ++ const auto sourceFieldDensity=[&](double x,double y,double z) ++ { ++ const float value=Shape.passageSourceDensityAt({x/coreMetres, ++ y/coreMetres,z/coreMetres}); ++ return std::isfinite(value)?static_cast(value)*coreMetres ++ :std::numeric_limits::quiet_NaN(); ++ }; ++ struct FFlatProbe {double x=0.0,y=0.0,z=0.0;}; ++ std::vector flatProbes; ++ const auto probeFlatness=[&](double radial,double angle) ++ { ++ const double x=centerX+radial*std::cos(angle); ++ const double y=centerY+radial*std::sin(angle); ++ const auto root=findFloorRoot(fieldDensity,x,y, ++ floorP-0.75,floorP+0.75); ++ ++audit.flatSamples; ++ if(!root.found||root.crossings!=1) ++ {++audit.flatFailures;return;} ++ const double error=std::abs(root.z-floorP); ++ audit.maximumFlatnessMetres=std::max( ++ audit.maximumFlatnessMetres,error); ++ if(error>FlatnessLimitMetres)++audit.flatFailures; ++ flatProbes.push_back({x,y,root.z}); ++ }; ++ probeFlatness(0.0,0.0); ++ for(std::size_t direction=0;direction(direction)/RadialDirections; ++ probeFlatness(0.90*radius,angle); ++ } ++ constexpr std::array SupportRadii{{0.0,0.5,0.9}}; ++ for(const double radialFraction:SupportRadii) ++ for(std::size_t direction=0;direction(direction)/RadialDirections; ++ const double x=centerX+radialFraction*radius*std::cos(angle); ++ const double y=centerY+radialFraction*radius*std::sin(angle); ++ ++audit.supportSamples; ++ if(!(fieldDensity(x,y,floorP-0.10)<0.0)) ++ ++audit.supportFailures; ++ ++audit.headroomSamples; ++ if(!(fieldDensity(x,y,floorP+2.0)>0.0)) ++ ++audit.headroomFailures; ++ } ++ constexpr std::size_t BlendStations=16; ++ const double blendEnd=BlendRadiusMetres-0.25; ++ for(std::size_t direction=0;direction(direction)/RadialDirections; ++ bool previousFound=false; ++ double previousRadius=0.0,previousFloor=0.0; ++ for(std::size_t station=0;station<=BlendStations;++station) ++ { ++ const double radial=radius+blendEnd ++ *static_cast(station)/BlendStations; ++ const double x=centerX+radial*std::cos(angle); ++ const double y=centerY+radial*std::sin(angle); ++ const double coneRun=std::max(0.0,radial-radius); ++ const double coneHeight=ConeSlope*coneRun; ++ const auto root=findFloorRoot(fieldDensity,x,y, ++ floorP-coneHeight-0.75,floorP+coneHeight+0.75); ++ ++audit.blendRootSamples; ++ if(!root.found||root.crossings!=1) ++ { ++ ++audit.blendMissing; ++ previousFound=false; ++ continue; ++ } ++ if(previousFound) ++ { ++ const double grade=std::atan2( ++ std::abs(root.z-previousFloor),radial-previousRadius) ++ *180.0/3.14159265358979323846; ++ audit.maximumGradeDegrees=std::max( ++ audit.maximumGradeDegrees,grade); ++ if(grade>GradeLimitDegrees)++audit.blendGradeFailures; ++ } ++ previousFound=true; ++ previousRadius=radial; ++ previousFloor=root.z; ++ } ++ } ++ const auto sourceField=[&](double x,double y,double z) ++ {return sourceFieldDensity(x,y,z);}; ++ bool padOffRejected=false; ++ for(std::size_t direction=0;direction(direction)/RadialDirections; ++ const double x=centerX+0.90*radius*std::cos(angle); ++ const double y=centerY+0.90*radius*std::sin(angle); ++ const auto root=findFloorRoot(sourceField,x,y, ++ floorP-0.75,floorP+0.75); ++ if(!root.found||root.crossings!=1 ++ ||std::abs(root.z-floorP)>FlatnessLimitMetres) ++ {padOffRejected=true;break;} ++ } ++ const bool tiltRejected=std::any_of(flatProbes.begin(),flatProbes.end(), ++ [&](const FFlatProbe& probe) ++ { ++ return std::abs((probe.z-floorP) ++ +0.02*(probe.x-centerX))>FlatnessLimitMetres; ++ }); ++ const auto controlStamp=[&](double blendRadius,double radial,double z, ++ double native,double tubeDistance) ++ { ++ const double coneRun=std::max(0.0,radial-radius); ++ const double lower=floorP-ConeSlope*coneRun; ++ const double upper=floorP+ConeSlope*coneRun; ++ const double outer=radius+blendRadius; ++ const double fill=std::max({CosTwelveDegrees*(z-lower), ++ CosTwelveDegrees*(lower-FillDepthMetres-z),radial-outer}); ++ const double air=std::min({CosTwelveDegrees*(z-upper), ++ CosTwelveDegrees*(upper+HeadroomMetres-z),outer-radial}); ++ const double masked=std::max(fill,-tubeDistance); ++ const double smoothWidth=0.5*std::clamp(radial-radius,0.0,1.0); ++ double smoothMinimum=std::min(native,masked); ++ if(smoothWidth>0.0) ++ { ++ const double h=std::max(smoothWidth ++ -std::abs(native-masked),0.0)/smoothWidth; ++ smoothMinimum-=h*h*h*(smoothWidth/6.0); ++ } ++ return std::max(smoothMinimum,air); ++ }; ++ const double outerProbe=radius+BlendRadiusMetres-0.25; ++ const double outerProbeZ=floorP-ConeSlope*(outerProbe-radius)-0.05; ++ const double fullBlendProbe=controlStamp(BlendRadiusMetres, ++ outerProbe,outerProbeZ,0.0,std::numeric_limits::infinity()); ++ const double halfBlendProbe=controlStamp(BlendRadiusMetres*0.5, ++ outerProbe,outerProbeZ,0.0,std::numeric_limits::infinity()); ++ const bool halfBlendRejected=fullBlendProbe< -0.01 ++ &&std::abs(halfBlendProbe)<1.0e-6; ++ const double boreMasked=controlStamp(BlendRadiusMetres, ++ radius*0.5,floorP-0.25,0.25,-0.50); ++ const double boreUnmasked=controlStamp(BlendRadiusMetres, ++ radius*0.5,floorP-0.25,0.25, ++ std::numeric_limits::infinity()); ++ const bool boreMaskRejected=boreMasked>0.0&&boreUnmasked<0.0; ++ audit.negativeControlsDetected=static_cast(padOffRejected) ++ +static_cast(tiltRejected) ++ +static_cast(halfBlendRejected) ++ +static_cast(boreMaskRejected); ++ audit.passed=audit.flatSamples>0&&audit.flatFailures==0 ++ &&audit.supportSamples>0&&audit.supportFailures==0 ++ &&audit.headroomSamples>0&&audit.headroomFailures==0 ++ &&audit.blendRootSamples>0&&audit.blendMissing==0 ++ &&audit.blendGradeFailures==0 ++ &&audit.negativeControlsDetected==4; ++ std::printf("[LandingPadAudit] id=%s side=%s radius_m=%.3f blend_m=%.3f flatness_samples=%llu flatness_max_m=%.5f flatness_failures=%llu support=%llu/%llu headroom=%llu/%llu blend_transects=%zu blend_roots=%llu blend_missing=%llu blend_grade_max_deg=%.3f blend_grade_failures=%llu negative_controls=%llu/4 pad_off=%s tilt_2pct=%s blend_B_half=%s bore_mask_removed=%s status=%s\n", ++ passage.stableId.c_str(),upper?"upper":"lower",radius, ++ BlendRadiusMetres,static_cast(audit.flatSamples), ++ audit.maximumFlatnessMetres, ++ static_cast(audit.flatFailures), ++ static_cast(audit.supportSamples ++ -audit.supportFailures), ++ static_cast(audit.supportSamples), ++ static_cast(audit.headroomSamples ++ -audit.headroomFailures), ++ static_cast(audit.headroomSamples), ++ RadialDirections, ++ static_cast(audit.blendRootSamples), ++ static_cast(audit.blendMissing), ++ audit.maximumGradeDegrees, ++ static_cast(audit.blendGradeFailures), ++ static_cast(audit.negativeControlsDetected), ++ padOffRejected?"detected":"MISSED",tiltRejected?"detected":"MISSED", ++ halfBlendRejected?"detected":"MISSED", ++ boreMaskRejected?"detected":"MISSED",audit.passed?"PASS":"FAIL"); ++ return audit; ++ }; + std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0; + std::uint64_t passageInteriorCapsuleSamples=0,passageInteriorSolidSamples=0; + std::uint64_t passageInteriorControls=0; + std::uint64_t landingChamberCount=0,landingChamberNegativeControls=0; ++ std::uint64_t landingPadCount=0,landingPadPasses=0,landingPadControls=0; + std::uint64_t mouthProfilePasses=0,ripplePasses=0,rippleControlsDetected=0; + std::uint64_t floorRippleControlsDetected=0,floorStepRippleControlsDetected=0; + std::uint64_t shellAudits=0,shellFloorSamples=0,shellFloorViolations=0; +@@ -5346,6 +5438,13 @@ namespace StandaloneStreamBenchmark + passage,passageIndex,true); + const FWalkAudit lowerChamberAudit=auditLandingChamber(Shape, + passage,passageIndex,false); ++ const FLandingPadAudit upperPadAudit=auditLandingPad(Shape,passage,true); ++ const FLandingPadAudit lowerPadAudit=auditLandingPad(Shape,passage,false); ++ landingPadCount+=2; ++ landingPadPasses+=static_cast(upperPadAudit.passed) ++ +static_cast(lowerPadAudit.passed); ++ landingPadControls+=upperPadAudit.negativeControlsDetected ++ +lowerPadAudit.negativeControlsDetected; + const bool landingChambersWalkable=upperChamberAudit.passed + &&lowerChamberAudit.passed; + const bool passageInteriorAirPassed= +@@ -5426,6 +5525,7 @@ namespace StandaloneStreamBenchmark + floorRippleControlsDetected+=rippleAudit.floorControlDetected; + floorStepRippleControlsDetected+=rippleAudit.floorStepControlDetected; + passagePasses+=passageAudit.passed&&landingChambersWalkable ++ &&upperPadAudit.passed&&lowerPadAudit.passed + &&passageInteriorAirPassed + &&mouthsInRadius&&mouthsInContent + &&naturalAudit.passed&&mouthProfileAudit.passed&&rippleAudit.passed; +@@ -5889,6 +5989,13 @@ namespace StandaloneStreamBenchmark + static_cast(landingChamberCount), + static_cast(landingChamberCount + -landingChamberNegativeControls)); ++ std::printf("[LandingPadAuditSummary] pads=%llu passed=%llu negative_controls=%llu/%llu status=%s\n", ++ static_cast(landingPadCount), ++ static_cast(landingPadPasses), ++ static_cast(landingPadControls), ++ static_cast(landingPadCount*4), ++ landingPadCount>0&&landingPadPasses==landingPadCount ++ &&landingPadControls==landingPadCount*4?"PASS":"FAIL"); + const bool shellAuditPassed=shellAudits==passageCount + &&shellFloorViolations==0&&shellWallViolations==0 + &&shellChamberFloorViolations==0&&shellChamberWallViolations==0 +@@ -5935,6 +6042,8 @@ namespace StandaloneStreamBenchmark + ripplePasses==passageCount?"PASS":"FAIL"); + const bool auditPassed=passageCount>0&&passagePasses==passageCount + &&passageInteriorAuditPassed ++ &&landingPadCount>0&&landingPadPasses==landingPadCount ++ &&landingPadControls==landingPadCount*4 + &&naturalPasses==passageCount&&l23SmoothWallDetected + &&mouthProfilePasses==passageCount&&l23TerraceControlDetected + &&ripplePasses==passageCount