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:
commit
964a841de1
3978 files changed
+58013356
No files matched your search
@@ -0,0 +1,103 @@
|
||||
"""Stage A test of the 입력 묶음 확인·확정 개편 (2026-10-16), no Rhino: variability classes, template-origin marking, F-field edit rule (D3),
|
||||
V3 edit block. Own data root 검증/variability_test_data (recreated); real piers are not touched.
|
||||
Checks: every bundle of the 6 protected templates has a class (100 %), grades follow 기획서 부록 A, a new pier from a template shows all
|
||||
required bundles as "템플릿 원본 그대로" and an edited bundle drops out, an old pier without origin record claims nothing, F edits need a
|
||||
reason and are logged, V3 edits are refused, saved templates get a variability.json."""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
APP = Path(__file__).resolve().parents[1]
|
||||
TD = APP / "검증" / "variability_test_data"
|
||||
if TD.exists():
|
||||
shutil.rmtree(TD)
|
||||
shutil.copytree(APP / "data" / "_템플릿", TD / "_템플릿", ignore=shutil.ignore_patterns("_이전"))
|
||||
shutil.copytree(APP / "data" / "옥성교P1", TD / "옥성교P1", ignore=shutil.ignore_patterns("runs", "backup", "drawings"))
|
||||
os.environ["PIERAPP_DATA"] = str(TD)
|
||||
sys.path.insert(0, str(APP / "web"))
|
||||
sys.path.insert(0, str(APP))
|
||||
import app as webapp # noqa: E402
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from testlib import confirm_required # noqa: E402
|
||||
import store # noqa: E402
|
||||
from engine import variability # 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)
|
||||
|
||||
|
||||
# ---- 1. classes of the protected templates
|
||||
for t in store.templates():
|
||||
d = TD / "_템플릿" / t["name"]
|
||||
P, E = (json.loads((d / f).read_text(encoding="utf-8")) for f in ("params.json", "expected.json"))
|
||||
v = json.loads((d / "variability.json").read_text(encoding="utf-8"))["sections"]
|
||||
want = {f"params:{k}" for k in P} | {f"expected:{k}" for k in E}
|
||||
check(f"{t['name']}: every bundle classified ({len(want)})", set(v) == want and all(s["grade"] in variability.GRADES for s in v.values()),
|
||||
sorted(want ^ set(v))[:5])
|
||||
v3 = sorted(k for k, s in v.items() if s["grade"] == "V3")
|
||||
exp_v3 = {"운곡교P1형": [], "산외교울산P1형": ["params:coping_rebar"], "산외교울산P2형": ["params:coping_rebar"], "Ramp-A교P1형": ["params:coping_rebar"],
|
||||
"옥성교P1형": ["params:coping_rebar", "params:footing_rebar"], "새재1교P1형": ["params:coping_rebar", "params:footing_rebar"]}[t["name"]]
|
||||
check(f"{t['name']}: V3 = {exp_v3} (explicit bar lists, 부록 A)", v3 == exp_v3, v3)
|
||||
check(f"{t['name']}: run settings / pier_id are F", all(v[k]["grade"] == "F" for k in ("params:pier_id", "expected:pier_id", "expected:checkers") if k in v))
|
||||
|
||||
# ---- 2. new pier from a template: all required bundles are "원본 그대로"
|
||||
c = webapp.app.test_client()
|
||||
r = c.post("/pier/new", data={"name": "원본시험", "type": "T형", "template": "tpl:새재1교P1형"})
|
||||
check("new pier created", r.status_code == 302, r.status_code)
|
||||
p = store.Pier("원본시험")
|
||||
req = webapp.required(p)
|
||||
same = {(s["file"], s["key"]) for s in p.sections() if p.section_meta(s["file"], s["key"])["origin"]}
|
||||
check(f"all {len(req)} required bundles are still the template's original", req <= same and len(req) > 20, f"{len(req & same)}/{len(req)}")
|
||||
html = c.get("/pier/원본시험").get_data(as_text=True)
|
||||
check("pier page warns about original values and shows grade / source columns", f"템플릿 원본 그대로인 필수 묶음 {len(req)}개" in html
|
||||
and "변수 등급" in html and "값 출처" in html and "V1 값 변수" in html)
|
||||
check("pier folder holds its own variability.json and the origin record", (TD / "원본시험" / "variability.json").exists() and p.info.get("origin", {}).get("sha"))
|
||||
|
||||
# ---- 3. editing a V1 bundle drops it from the original list
|
||||
col = json.loads(json.dumps(p.load("params")["column"]))
|
||||
col["height"] = col["height"] + 100
|
||||
r = c.post("/pier/원본시험/section/params/column", data={"value": json.dumps(col)})
|
||||
check("V1 edit saved without reason", r.status_code == 302 and p.load("params")["column"]["height"] == col["height"])
|
||||
check("edited bundle is no longer 'original'", p.section_meta("params", "column")["origin"] is False and p.section_meta("params", "footing")["origin"] is True)
|
||||
|
||||
# ---- 4. F fields need a reason (D3), the reason is logged
|
||||
col2 = dict(col, shape="rectangular")
|
||||
r = c.post("/pier/원본시험/section/params/column", data={"value": json.dumps(col2)})
|
||||
check("F-field change without reason refused", "고정(F) 항목" in r.get_data(as_text=True) and p.load("params")["column"]["shape"] == "circular")
|
||||
r = c.post("/pier/원본시험/section/params/column", data={"value": json.dumps(col2), "reason": "사각 기둥 시험"})
|
||||
log = store.rjson(TD / "원본시험" / "edit_log.json", [])
|
||||
check("F-field change with reason saved and logged", p.load("params")["column"]["shape"] == "rectangular" and log and log[-1]["reason"] == "사각 기둥 시험"
|
||||
and log[-1]["fixed_fields"] == ["shape"], log[-1:] )
|
||||
sc = p.load("params")["scope"]
|
||||
r = c.post("/pier/원본시험/section/params/scope", data={"value": json.dumps(sc[:-1])})
|
||||
check("F bundle (scope) change without reason refused", "고정(F) 항목" in r.get_data(as_text=True) and p.load("params")["scope"] == sc)
|
||||
|
||||
# ---- 5. V3 bundles cannot be edited by hand
|
||||
before = p.load("params")["coping_rebar"]
|
||||
r = c.post("/pier/원본시험/section/params/coping_rebar", data={"value": json.dumps(before)})
|
||||
check("V3 bundle edit refused", "생성 변수(V3)" in r.get_data(as_text=True) and p.load("params")["coping_rebar"] == before)
|
||||
check("V3 section page explains", "판독 스크립트를 다시 실행" in c.get("/pier/원본시험/section/params/coping_rebar").get_data(as_text=True))
|
||||
|
||||
# ---- 6. an old pier (no origin record) claims nothing
|
||||
q = store.Pier("옥성교P1")
|
||||
check("old pier: origin unknown (None), no 'original' claim", q.info.get("origin") is None and all(q.section_meta(s["file"], s["key"])["origin"] is None for s in q.sections()))
|
||||
html = c.get("/pier/옥성교P1").get_data(as_text=True)
|
||||
check("old pier page says the origin is not recorded", "템플릿 복사 기록이 없어" in html and "▲ 템플릿 원본 그대로" not in html)
|
||||
|
||||
# ---- 7. saving a template writes variability.json
|
||||
store.save_template("원본시험", "시험형", "시험")
|
||||
check("save_template writes variability.json", (TD / "_템플릿" / "시험형" / "variability.json").exists())
|
||||
|
||||
# ---- 8. confirmation still works and the confirm records are untouched by the new metadata
|
||||
confirm_required(c, webapp, store, "원본시험", "시험자")
|
||||
check("confirming every required bundle one by one works", not webapp.unconfirmed(store.Pier("원본시험")))
|
||||
print("RESULT", "PASS" if ok else "FAIL")
|
||||
sys.exit(0 if ok else 1)
|
||||
Reference in new issue
Block a user