passages: continuous floor h(s) along the dense route; shell-probe oracle fix (L115, v223)

Floor height from the planner profile h(s) by horizontal projection + arc-length interpolation;
adjacent fine segments share endpoint values. Floor zero-crossing offsets max 7.8 mm (L114: up
to 73 mm); rock-floor close-ups show no ribs. The 2 L114 shell misses were oracle false positives
(points inside an overlapping bore); the oracle now checks every overlapping span; no gate relaxed.
Fast tier PASS; Clang/GCC W1/W8/W12 deterministic. Speed regression grows: near-ready +17..+31% vs
L109 (fine-segment/sample pairs 49.0M vs 19.8M). Not merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-30 01:48:29 +01:00
1 parent 5e875ae504
commit f403af1fc1
37 files changed
+2741 -183

No files matched your search

@@ -0,0 +1,260 @@
#!/usr/bin/env python3
"""Capture L115 rock floors at three rock stations per passage and open-air walls."""
from __future__ import annotations
import importlib.util
import json
import math
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
RESEARCH = Path(__file__).resolve().parent
CAPTURES = RESEARCH / "captures"
SAVED = ROOT / "Saved/Linux/l115/captures"
L113_RESEARCH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux113"
L115_SAVED = ROOT / "Saved/Linux/l115"
BINARIES = {
"L115": L115_SAVED / "bin/VoxelForgeCoreHeadless-l115-clang",
}
RENDERERS = {
"L115": L115_SAVED / "bin/VoxelForgeOffscreenCapture-l115-clang",
}
SECTION = re.compile(
r"^\[PassageOpenAirSection\] id=(\S+) section=(\d+) start_m=([\d.]+) "
r"end_m=([\d.]+) samples=(\d+) midpoint_xyz_m=\(([^)]*)\) "
r"midpoint_radius_m=([\d.]+)", re.M)
sys.dont_write_bytecode = True
SPEC = importlib.util.spec_from_file_location(
"l113_capture_helpers", L113_RESEARCH / "RunL113Captures.py")
if SPEC is None or SPEC.loader is None:
raise SystemExit("cannot load the verified L113 capture helpers")
HELPERS = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(HELPERS)
HELPERS.RESEARCH = RESEARCH
HELPERS.CAPTURES = CAPTURES / "L115"
HELPERS.SAVED = SAVED / "L115"
HELPERS.BINARIES = BINARIES
HELPERS.RENDERERS = RENDERERS
def parse_sections(log: Path) -> list[dict]:
sections = []
text = log.read_text(encoding="utf-8", errors="replace")
for passage, section, start, end, samples, midpoint, radius in SECTION.findall(text):
sections.append({"passage": passage, "section": int(section),
"start_m": float(start), "end_m": float(end),
"samples": int(samples), "midpoint": HELPERS.vector(midpoint),
"radius_m": float(radius)})
return sections
def rocky_spans(total: float, sections: list[dict]) -> list[tuple[float, float]]:
spans = []
cursor = 0.0
for section in sorted(sections, key=lambda item: item["start_m"]):
start = max(0.0, min(total, section["start_m"]))
end = max(start, min(total, section["end_m"]))
if start - cursor > 2.0:
spans.append((cursor + 1.0, start - 1.0))
cursor = max(cursor, end)
if total - cursor > 2.0:
spans.append((cursor + 1.0, total - 1.0))
return [(start, end) for start, end in spans if end - start >= 1.0]
def rock_station_candidates(spans: list[tuple[float, float]]) -> list[float]:
total = sum(end - start for start, end in spans)
if total < 3.0:
raise RuntimeError("passage has less than 3 m of rock route outside open-air spans")
stations = []
for fraction in (0.25, 0.50, 0.75, 0.10, 0.90, 0.35, 0.65, 0.20, 0.80,
0.40, 0.60):
remaining = total * fraction
for start, end in spans:
span = end - start
if remaining <= span:
stations.append(start + remaining)
break
remaining -= span
return stations
def rock_floor_view(layout: dict, passage: dict, station: float, index: int) -> dict:
raw_route = HELPERS.smooth_route(layout, passage)
route, body_depth = HELPERS.derived_smooth_route(raw_route, passage, layout)
lengths, prefix = HELPERS.route_lengths(route)
center, radius = HELPERS.at_distance(route, lengths, prefix, station)
floor_depth = min(body_depth, max(0.0, radius - 0.23))
planned_floor = (center[0], center[1], center[2] - floor_depth)
tangent = HELPERS.tangent_at(route, lengths, prefix, station)
grade = math.degrees(math.atan2(abs(tangent[2]),
math.hypot(tangent[0], tangent[1])))
camera = tuple(planned_floor[axis] - 2.5 * tangent[axis]
+ (1.25 if axis == 2 else 0.0) for axis in range(3))
yaw, pitch = HELPERS.angles(camera, planned_floor)
safe_id = HELPERS.sanitize(passage["stable_id"])
return {"name": f"{safe_id}-rock-floor-station-{index}",
"passage": passage["stable_id"], "kind": "rock-floor-close",
"station": f"rock-floor/{station:.1f}m", "camera": camera,
"target": planned_floor, "yaw": yaw, "pitch": pitch,
"focus": planned_floor, "center_z": planned_floor[2],
"route_distance_m": station, "requested_route_distance_m": station,
"route_length_m": prefix[-1], "planned_floor_m": planned_floor[2],
"planned_grade_deg": grade}
def capture_rock_floor(layout: dict, passage: dict, station: float, index: int) -> dict:
view = rock_floor_view(layout, passage, station, index)
row = HELPERS.capture("L115", view, layout)
scene = ROOT / row["scene"]
anchor = HELPERS.nearest_surface_anchor(scene, view["target"], margin_m=5.0,
preferred_normal=(0.0, 0.0, 1.0), minimum_alignment=0.85)
alignment = HELPERS.dot(anchor["normal"], (0.0, 0.0, 1.0))
camera_distance = math.dist(row["camera_actual_m"], anchor["position_m"])
row.update({"variant": "L115", "kind": "rock-floor-close",
"planned_floor_m": view["planned_floor_m"],
"planned_grade_deg": view["planned_grade_deg"],
"floor_anchor_position_m": anchor["position_m"],
"floor_anchor_normal": anchor["normal"],
"closeup_camera_to_floor_distance_m": camera_distance,
"closeup_target_surface_distance_m": anchor["distance_m"],
"closeup_floor_normal_alignment": alignment,
"verified_upward_floor_normal": alignment >= 0.85})
if (not row["verified"] or not 2.0 <= camera_distance <= 3.2
or anchor["distance_m"] > 0.25 or alignment < 0.85
or view["planned_grade_deg"] < 2.0 or row["drawn_triangles"] <= 0
or row["pixel_quality_status"] not in
("pass", "low_contrast_geometry_visible")):
raise RuntimeError(f"rock-floor close-up failed at {passage['stable_id']} s={station:.2f}")
return row
def main() -> int:
layout_path = L115_SAVED / "audit-layout-candidate.json"
audit_log = L115_SAVED / "audit-owner-clang.log"
if any(not path.is_file() for path in (*BINARIES.values(), *RENDERERS.values(),
layout_path, audit_log)):
raise SystemExit("missing L115 binaries, layout, or passage audit log")
layout = json.loads(layout_path.read_text(encoding="utf-8"))
sections = parse_sections(audit_log)
if not sections:
raise SystemExit("no L115 open-air sections found")
CAPTURES.mkdir(parents=True, exist_ok=True)
HELPERS.CAPTURES = CAPTURES / "L115"
HELPERS.SAVED = SAVED / "L115"
HELPERS.CAPTURES.mkdir(parents=True, exist_ok=True)
HELPERS.SAVED.mkdir(parents=True, exist_ok=True)
rows = []
for passage in sorted(layout["passages"], key=lambda item: item["stable_id"]):
passage_sections = [item for item in sections
if item["passage"] == passage["stable_id"]]
raw_route = HELPERS.smooth_route(layout, passage)
route, _body_depth = HELPERS.derived_smooth_route(raw_route, passage, layout)
_lengths, prefix = HELPERS.route_lengths(route)
spans = rocky_spans(prefix[-1], passage_sections)
candidates = rock_station_candidates(spans)
accepted_stations = []
total_rock_length = sum(end - start for start, end in spans)
minimum_spacing = max(1.0, total_rock_length * 0.02)
for station in candidates:
if any(abs(station - prior) < minimum_spacing for prior in accepted_stations):
continue
index = len(accepted_stations) + 1
try:
row = capture_rock_floor(layout, passage, station, index)
except RuntimeError as error:
message = str(error)
if not (message.startswith("no nearby surface vertices in mesh scene:")
or message.startswith("rock-floor close-up failed at ")):
raise
print(f"[L115CaptureSkip] passage={passage['stable_id']} "
f"station_m={station:.3f} reason=surface-or-anchor-check", flush=True)
continue
accepted_stations.append(station)
rows.append(row)
if len(accepted_stations) == 3:
break
if len(accepted_stations) < 3:
for base_station in tuple(accepted_stations):
for offset in (-10.0, 10.0, -15.0, 15.0, -20.0, 20.0,
-25.0, 25.0, -30.0, 30.0):
station = base_station + offset
if not any(start < station < end for start, end in spans):
continue
if any(abs(station - prior) < minimum_spacing
for prior in accepted_stations):
continue
index = len(accepted_stations) + 1
try:
row = capture_rock_floor(layout, passage, station, index)
except RuntimeError as error:
message = str(error)
if not (message.startswith(
"no nearby surface vertices in mesh scene:")
or message.startswith("rock-floor close-up failed at ")):
raise
print(f"[L115CaptureSkip] passage={passage['stable_id']} "
f"station_m={station:.3f} reason=nearby-station-check",
flush=True)
continue
accepted_stations.append(station)
rows.append(row)
if len(accepted_stations) == 3:
break
if len(accepted_stations) == 3:
break
if len(accepted_stations) != 3:
raise RuntimeError(f"only {len(accepted_stations)} verified rock-floor views for "
f"{passage['stable_id']}: {accepted_stations}")
open_air_views = HELPERS.make_views(layout, sections, use_derived_shape=True,
use_spline=True, include_open_air=True)
open_air_views = [view for view in open_air_views
if view["kind"] == "open-air-close"]
if len(open_air_views) != 2 * len(sections):
raise RuntimeError("L115 open-air close-up count is not two per section")
for view in open_air_views:
row = HELPERS.capture("L115", view, layout)
if (not row["verified"]
or abs(row["closeup_camera_target_distance_m"] - 4.0) > 0.02
or row["closeup_target_surface_distance_m"] > 5.0
or row["closeup_wall_normal_alignment"] < 0.25
or row["drawn_triangles"] <= 0
or row["pixel_quality_status"] not in
("pass", "low_contrast_geometry_visible")):
raise RuntimeError(f"open-air close-up failed: {view['name']}")
row["variant"] = "L115"
rows.append(row)
(CAPTURES / "capture-index.json").write_text(
json.dumps({"captures": rows}, indent=2) + "\n", encoding="utf-8")
floor_rows = [row for row in rows if row["kind"] == "rock-floor-close"]
wall_rows = [row for row in rows if row["kind"] == "open-air-close"]
passage_ids = {item["stable_id"] for item in layout["passages"]}
if (len(floor_rows) != 3 * len(passage_ids)
or any(sum(row["passage"] == passage for row in floor_rows) != 3
for passage in passage_ids)
or len(wall_rows) != 2 * len(sections)):
raise RuntimeError("L115 capture count mismatch")
lines = ["# L115 captures", "",
"Each passage has three floor close-ups sampled outside the audited open-air spans. "
"Floor anchors require an upward normal alignment of at least 0.85, a target-to-floor "
"distance of at most 0.25 m, and a camera-to-floor distance between 2.0 and 3.2 m. "
"Each open-air section has verified outside and interior wall close-ups at 4 m.", ""]
for row in rows:
lines.append(f"- [{row['passage']} {row['station']}]({row['capture']}) — "
f"{row['kind']}; {row.get('drawn_triangles', 0)} triangles; "
f"{row['pixel_quality_status']}")
(CAPTURES / "INDEX.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
print(f"[L115CaptureSummary] captures={len(rows)} rock_floors={len(floor_rows)} "
f"open_air_closeups={len(wall_rows)} sections={len(sections)} status=PASS",
flush=True)
return 0
if __name__ == "__main__":
raise SystemExit(main())