Files
Pier_v1/Code/교각모델링앱/tools/test_rampa.py
T
ahnyongjooandClaude Sonnet 5.5 964a841de1 chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합
- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환
- Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용
- pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관)
- worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md)
- D:\Rhino-MCP 경로 참조를 새 위치로 치환

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 11:20:18 +09:00

76 lines
4.6 KiB
Python

"""Ramp-A P1 form test (2026-10-13), no Rhino: table reading fixes and the pier inputs.
- ELEVATION TABLE header below detail labels, window cut at the 솔플레이트 TABLE title, '1,000' integers
- reference piers unchanged: table records / proposals equal 검증/open19_snapshot_after.json
- Ramp-A table candidates all equal the hand-typed expected / params (independent transcription check)
- gate reports of data/Ramp-A교P1 (engine run) PASS with negatives detected
"""
import json
import sys
from pathlib import Path
APP = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(APP))
sys.path.insert(0, str(APP / "tools"))
sys.path.insert(0, str(APP / "web"))
from engine import reader # noqa: E402
import store # noqa: E402
from open19_snapshot import snapshot # noqa: E402
ok = True
def check(name, cond, detail=""):
global ok
ok &= bool(cond)
print("PASS" if cond else "FAIL", name, str(detail)[:300], flush=True)
ref = json.loads((APP / "검증" / "open19_snapshot_after.json").read_text(encoding="utf-8"))
now = snapshot()
for k in ref:
check(f"{k}: table records unchanged", ref[k]["records"] == now[k]["records"])
check(f"{k}: proposals unchanged", ref[k]["proposals"] == now[k]["proposals"])
p = store.Pier("Ramp-A교P1")
tables = reader.table_candidates(p.texts())
el = [t for t in tables if t["key"] == "elevation"]
recs = [r for _, r in reader.table_records(el[0]["rows"], lambda s: s.isdigit())] if el else []
check("ELEVATION TABLE: 2 rows NO.1 / NO.2", [r["_key"] for r in recs] == ["1", "2"], [r["_key"] for r in recs])
check("ELEVATION TABLE: all 15 columns read", recs and all(len(r) == 16 for r in recs), [len(r) for r in recs])
check("ELEVATION TABLE NO.2 EL.'X' 60.427, C3 1400", recs and recs[1].get("EL.'X'") == "60.427" and recs[1].get("C3") == "1400")
sp = [t for t in tables if t["key"] == "sole_plate"]
srec = [r for _, r in reader.table_records(sp[0]["rows"], lambda s: s.isdigit())] if sp else []
check("솔플레이트 TABLE: 2 rows, L '1,000'", [r["_key"] for r in srec] == ["1", "2"] and srec[0].get("L") == "1,000", srec)
check("thousands separator", reader._int("1,000") == 1000 and reader._int("50") == 50)
rows = reader.proposals(reader.field_candidates(tables), p.load("params"), p.load("expected"))
diff = [(r["file"], r["path"], r["current"], r["candidate"]) for r in rows if not r["same"]]
kinds = {r["file"] + "." + ".".join(str(x) for x in r["path"][:2]) for r in rows}
check(f"candidates all equal the typed inputs ({len(rows)} rows)", rows and not diff, diff)
check("candidates cover G1 seats, G5 el_x, params bearings and sole plates",
{"expected.G1.seats", "expected.G5.el_x", "params.bearing_seats.bearings", "params.sole_plates.table"} <= kinds, sorted(kinds))
for g, n in (("G1", 97), ("G2", 26), ("G3", 48), ("G4", 126), ("G5", 39)): # G2, G3 2026-10-13; G4 coping rebar 2026-10-14
r = json.loads((p.dir / "runs" / "current" / f"{g}_gate.json").read_text(encoding="utf-8"))
check(f"{g} gate PASS {n}/{n}, negatives detected, reload ok",
r["verdict"] == "PASS" and r["summary"]["passed"] == n == r["summary"]["total"]
and all(v["detected"] for v in r["negative"].values()) and (r["reload"]["ok"] or r.get("mode") == "batch"), r["summary"]) # batch mode (app 일괄 승인) skips save + reload on purpose (OPEN #25)
r2 = json.loads((p.dir / "runs" / "current" / "G2.json").read_text(encoding="utf-8"))
cov = r2["summary"]["min_cover"]
check("G2 min side cover P1 107.5 / P2 91 / P3 76 (R 1,000 - radial - bar radius)",
cov == {"P1": 107.5, "P2": 91.0, "P3": 76.0}, cov)
check("scope G1~G5", p.scope() == ["G1", "G2", "G3", "G4", "G5"], p.scope())
r4 = json.loads((p.dir / "runs" / "current" / "G4.json").read_text(encoding="utf-8"))
cov4 = r4["summary"]["cover"]
check("G4 min cover of coping bars >= 40 (corner clipping)", all(v >= 40 for k, v in cov4.items() if not k.startswith("S")), cov4)
check("G4 449 bars", sum(len([b for b in p.load("params")["coping_rebar"]["bars"] if b["mark"] == m]) for m in
{b["mark"] for b in p.load("params")["coping_rebar"]["bars"]}) == 449)
r3 = json.loads((p.dir / "runs" / "current" / "G3.json").read_text(encoding="utf-8"))
cov3 = r3["summary"]["min_cover"]
check("G3 min cover (side / bottom) as hand-computed",
cov3 == {"P1-1": 158.0, "P1-2": 164.5, "P2-1": 142.0, "P3-1": 98.5, "P3-2": 92.0}, cov3)
check("template Ramp-A교P1형 = pier inputs",
all((store.DATA / "_템플릿" / "Ramp-A교P1형" / f).read_bytes() == (p.dir / f).read_bytes()
for f in ("params.json", "expected.json")))
print("RESULT", "PASS" if ok else "FAIL")
sys.exit(0 if ok else 1)