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>
This commit is contained in:
ahnyongjooandClaude Sonnet 5.5 committed 2026-10-28 11:20:18 +09:00
commit 964a841de1
3978 files changed
+58013356

No files matched your search

@@ -0,0 +1,124 @@
"""Test of improvements #34-2 (params <-> expected consistency, C9), #34-3 (field-level 'still the creation value', C3b) and #34-6 (point-list rule),
2026-10-20. No Rhino, no writes under data/ (reads only). Real piers: the finished 운곡교 P1 / P3 / P4 must show no mismatch; the backups of P3 / P4 taken
during the first real-use runs (data/<pier>/backup/before_*) hold the exact stale states that cost two gate runs each -- they must be caught.
Skipped parts (data missing) are reported, not failed."""
import copy
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"))
from testlib import verified_pier # noqa: E402
from engine import consistency, verify # noqa: E402
D = APP / "data"
ok = True
def check(name, cond, detail=""):
global ok
ok &= bool(cond)
print("PASS" if cond else "FAIL", name, str(detail)[:300], flush=True)
def load(d):
return json.loads((d / "params.json").read_text(encoding="utf-8")), json.loads((d / "expected.json").read_text(encoding="utf-8"))
def origin(d):
f = d / "origin_values.json"
return json.loads(f.read_text(encoding="utf-8")) if f.exists() else None
def run(P, E, org=None):
return verify.verify(P, E, [], {}, origin_values=org)
def c_of(res, b, cid):
return next(c for c in res[b]["checks"] if c["id"] == cid)
def bad_c9(res):
return sorted(b for b, r in res.items() if any(c["id"] == "C9" and c["st"] == "b" for c in r["checks"]))
# ---- 1. finished piers: no false mismatch
for n in ("운곡교P1", "운곡교P3", "운곡교P4"):
d = D / n if n == "운곡교P1" else verified_pier(n) # P3 / P4: the gate-verified copy (a live pier may be half-updated while it is being made again)
if d is None or not d.exists():
print("SKIP", n)
continue
P, E = load(d)
r = consistency.check(P, E)
check(f"{n}: {len(r)} linked values, none differ", r and all(x["ok"] for x in r), [x["id"] for x in r if not x["ok"]][:5])
res = run(P, E, origin(d))
check(f"{n}: C9 never b / C3b never w on the finished state", not bad_c9(res) and not any(c["id"] == "C3b" and c["st"] == "w" for r_ in res.values() for c in r_["checks"]),
bad_c9(res))
# ---- 2. the stale states of the first real-use runs are caught
p3 = D / "운곡교P3"
if p3.exists() and list((p3 / "backup").glob("before_hooks_up_*")):
bk = sorted((p3 / "backup").glob("before_hooks_up_*"))[0]
P, E = load(bk)
r = [x for x in consistency.check(P, E) if not x["ok"]]
check("P3 before_hooks_up: the 4 hooks_up points that no longer exist in c14.points are found (#34-6)",
sorted(x["id"] for x in r) == [f"coping_rebar.c14.hooks_up.{i}" for i in range(4)], [x["id"] for x in r])
res = run(P, E, origin(p3))
check("P3 before_hooks_up: params:coping_rebar becomes 불일치 (C9)", c_of(res, "params:coping_rebar", "C9")["st"] == "b" and res["params:coping_rebar"]["st"] == "b")
c3b = c_of(res, "params:coping_rebar", "C3b")
check("P3 before_hooks_up: C3b names the hooks_up coordinates that were never changed (#34-3)", c3b["st"] == "w" and "hooks_up" in c3b["text"], c3b["text"])
else:
print("SKIP P3 before_hooks_up")
if p3.exists() and list((p3 / "backup").glob("before_stage2_*")):
bk = sorted((p3 / "backup").glob("before_stage2_*"))[0]
P, E = load(bk)
r = [x for x in consistency.check(P, E) if not x["ok"]]
ids = {x["id"] for x in r}
check("P3 before_stage2: >= 40 mismatches", len(r) >= 40, len(r))
for must in ("piles.pitch_y", "coping.step2.z", "coping.step2.x0", "bearing.pitch", "column_rebar.hoop.count", "footing_rebar.bottom_X2.count", "footing_rebar.b9.y"):
check(f"P3 before_stage2: rule {must} caught", must in ids)
res = run(P, E, origin(p3))
check("P3 before_stage2: every gate bundle of expected is 불일치 before any gate runs", all(res[f"expected:G{i}"]["st"] == "b" for i in (1, 2, 3, 4)), bad_c9(res))
else:
print("SKIP P3 before_stage2")
p4 = verified_pier("운곡교P4") or D / "운곡교P4"
if p4.exists() and list((p4 / "backup").glob("before_table_apply_*")):
bk = sorted((p4 / "backup").glob("before_table_apply_*"))[0]
P, E = load(bk)
r = [x for x in consistency.check(P, E) if not x["ok"]]
check("P4 before_table_apply: the schedule copies that differ between the files are caught", any(x["id"].startswith("schedule.") for x in r), len(r))
else:
print("SKIP P4 before_table_apply")
# ---- 3. synthetic edits on a finished pier
if p3.exists():
P, E = load(p3)
E2 = copy.deepcopy(E)
E2["G1"]["piles"]["pitch_y"] = 1550
res = run(P, E2, origin(p3))
check("pile pitch changed in expected only -> expected:G1 and params:piles 불일치", res["expected:G1"]["st"] == "b" and res["params:piles"]["st"] == "b", bad_c9(res))
P2 = copy.deepcopy(P)
h = P2["coping_rebar"]["c14"]["hooks_up"][0]
P2["coping_rebar"]["c14"]["points"] = [[x, z + 5 if [x, z] == h or (x, z) == tuple(h) else z] for x, z in P2["coping_rebar"]["c14"]["points"]]
r = [x for x in consistency.check(P2, E) if not x["ok"]]
check("moving the point a hooks_up entry names breaks that entry (#34-6)", [x["id"] for x in r] == ["coping_rebar.c14.hooks_up.0"], [x["id"] for x in r])
P3_ = copy.deepcopy(P)
del P3_["coping_rebar"]["c14"]["hooks_up"]
check("no hooks_up -> no point-list rule, nothing else breaks", not [x for x in consistency.check(P3_, E) if not x["ok"]])
res = run(P, E, None)
check("without origin_values.json C3b is 해당 없음 (older piers)", c_of(res, "params:coping_rebar", "C3b")["st"] == "x")
# ---- 4. other pier types are not touched
for n in ("새재1교P1", "옥성교P1", "산외교울산P2", "Ramp-A교P1"):
d = D / n
if not d.exists():
print("SKIP", n)
continue
P, E = load(d)
r = consistency.check(P, E)
check(f"{n}: no false C9 mismatch ({len(r)} linked values)", all(x["ok"] for x in r), [x["id"] for x in r if not x["ok"]][:5])
print("RESULT", "PASS" if ok else "FAIL")
sys.exit(0 if ok else 1)