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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
No files matched your search
@@ -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}
|
||||||
@@ -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 |  |  |  |
|
||||||
|
| `passage/0-1/0` lower |  |  |  |
|
||||||
|
| `passage/1-2/0` upper |  |  |  |
|
||||||
|
| `passage/1-2/0` lower |  |  |  |
|
||||||
|
| `passage/2-3/0` upper |  |  |  |
|
||||||
|
| `passage/2-3/0` lower |  |  |  |
|
||||||
|
|
||||||
|
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.
|
||||||
@@ -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)
|
||||||
@@ -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())
|
||||||
@@ -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.
|
||||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,290 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"version": "after-l159",
|
||||||
|
"view": "0-1-0-upper-landing",
|
||||||
|
"passage": "passage/0-1/0",
|
||||||
|
"side": "upper",
|
||||||
|
"view_kind": "eye",
|
||||||
|
"file": "Standalone/Research/WorldAssemblerM3/Linux159/captures/after-l159-0-1-0-upper-landing.jpg",
|
||||||
|
"camera_m": [
|
||||||
|
37.0,
|
||||||
|
-5.25,
|
||||||
|
-372.3810546875
|
||||||
|
],
|
||||||
|
"target_m": [
|
||||||
|
28.40474992442715,
|
||||||
|
-7.918646874047773,
|
||||||
|
-372.325197471535
|
||||||
|
],
|
||||||
|
"yaw_deg": -107.24848481126237,
|
||||||
|
"pitch_deg": 0.3555935154874107,
|
||||||
|
"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-landing.jpg pixels=921600 mean_luma=113.911 stddev_luma=9.359 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.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"
|
||||||
|
}
|
||||||
|
]
|
||||||