passages: smoothed open-air shell joins (L110, v257) - partial, not merged
Bands = end profiles of per-control-span shell capsules (~9.35 m pitch = span spacing). Shell now smooth-unions adjacent spans over 6 m and reuses the interior chord distance; a 0.60 m clearance fades in 5-20 m from each mouth. Close-ups: bands reduced but still visible on part of the exposed shell. Cost vs L109: near-ready +8..+12% (FI 0.88 -> 1.00, TN 0.92 -> 1.01 s @W12). Audits, Clang/GCC determinism, fast tier and Linux UE build pass. Kept on its own branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
5ea01988c4
commit
bf39712792
397 files changed
+7754
-128
No files matched your search
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Check the paired L109/L110 capture set and 4 m shell close-ups."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
import struct
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
CAPTURE_ROOT = Path(__file__).resolve().parent / "captures"
|
||||
RESEARCH_ROOT = CAPTURE_ROOT.parent
|
||||
INDEX = CAPTURE_ROOT / "capture-index.json"
|
||||
OUTPUT = CAPTURE_ROOT / "capture-verification.json"
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def png_size(path: Path) -> tuple[int, int]:
|
||||
with path.open("rb") as stream:
|
||||
header = stream.read(24)
|
||||
if len(header) != 24 or header[:8] != b"\x89PNG\r\n\x1a\n" or header[12:16] != b"IHDR":
|
||||
raise RuntimeError(f"invalid PNG: {path}")
|
||||
return struct.unpack(">II", header[16:24])
|
||||
|
||||
|
||||
def main() -> int:
|
||||
captures = json.loads(INDEX.read_text(encoding="utf-8"))["captures"]
|
||||
counts = {variant: Counter(row["kind"] for row in captures
|
||||
if row["variant"] == variant)
|
||||
for variant in ("before", "after")}
|
||||
by_variant = {variant: {row["name"]: row for row in captures
|
||||
if row["variant"] == variant}
|
||||
for variant in ("before", "after")}
|
||||
errors: list[str] = []
|
||||
for variant in ("before", "after"):
|
||||
rows = [row for row in captures if row["variant"] == variant]
|
||||
if len(rows) != 53:
|
||||
errors.append(f"{variant}: expected 53 captures, got {len(rows)}")
|
||||
for row in rows:
|
||||
image = RESEARCH_ROOT / row["capture"]
|
||||
if not row.get("verified") or row.get("render_tile_skirts") != "off":
|
||||
errors.append(f"{variant}/{row['name']}: render verification flags failed")
|
||||
if row.get("drawn_triangles", 0) <= 0 or not image.is_file():
|
||||
errors.append(f"{variant}/{row['name']}: missing geometry or image")
|
||||
elif png_size(image) != (1920, 1080):
|
||||
errors.append(f"{variant}/{row['name']}: unexpected image size {png_size(image)}")
|
||||
closeups = [row for row in rows if row["kind"] == "open-air-closeup"]
|
||||
if len(closeups) != 11:
|
||||
errors.append(f"{variant}: expected 11 close-ups, got {len(closeups)}")
|
||||
for row in closeups:
|
||||
distance = row.get("shell_standoff_actual_m")
|
||||
if distance is None or not 3.0 <= distance <= 5.0:
|
||||
errors.append(f"{variant}/{row['name']}: close-up standoff {distance}")
|
||||
names_before, names_after = set(by_variant["before"]), set(by_variant["after"])
|
||||
if names_before != names_after:
|
||||
errors.append("before/after capture names do not match")
|
||||
pair_counts = Counter()
|
||||
for name in sorted(names_before & names_after):
|
||||
left, right = by_variant["before"][name], by_variant["after"][name]
|
||||
same = sha256(RESEARCH_ROOT / left["capture"]) == sha256(
|
||||
RESEARCH_ROOT / right["capture"])
|
||||
pair_counts[f"{left['kind']}_{'identical' if same else 'changed'}"] += 1
|
||||
summary = {
|
||||
"status": "PASS" if not errors else "FAIL",
|
||||
"capture_count": len(captures),
|
||||
"open_air_sections": len(json.loads(INDEX.read_text(encoding="utf-8"))[
|
||||
"open_air_sections"]),
|
||||
"per_variant_kind_counts": {variant: dict(sorted(counts[variant].items()))
|
||||
for variant in counts},
|
||||
"paired_image_bytes": dict(sorted(pair_counts.items())),
|
||||
"errors": errors,
|
||||
}
|
||||
OUTPUT.write_text(json.dumps(summary, indent=2) + "\n", encoding="utf-8")
|
||||
print(json.dumps(summary, sort_keys=True))
|
||||
return 0 if not errors else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user