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,172 @@
from pathlib import Path
APP = Path(r"C:\Users\User\Desktop\바이브코딩\pier_T\Code\교각모델링앱")
def patch(rel, reps):
p = APP / rel
s = p.read_text(encoding="utf-8")
for a, b in reps:
assert s.count(a) == 1, (rel, a[:60])
s = s.replace(a, b)
p.write_text(s, encoding="utf-8")
patch("web/app.py", [
("""import json
import sys
import threading
import traceback""", """import json
import os
import sys
import threading
import traceback
import uuid"""),
("""RHINO_LOCK = threading.Lock() # one Rhino job at a time""",
"""RHINO_LOCK = threading.Lock() # one Rhino job at a time
ACTIVE = {} # job id -> thread of this server process"""),
("""def _gate_job(p, gate):
jp = p.run_dir / f"{gate}_job.json"
inputs = p.inputs_sha()
log = []
def note(m):
log.append(m)
store.wjson(jp, {"state": "실행 중", "at": store.now(), "log": log})
with RHINO_LOCK:
try:
note("Rhino 작업 시작")
rep = run_gate(gate, p.dir / "params.json", p.dir / "expected.json", p.run_dir, log=note)
rep["inputs_sha"] = inputs
store.wjson(p.run_dir / f"{gate}_gate.json", rep)
store.wjson(jp, {"state": "완료", "at": store.now(), "log": log})
except Exception:
store.wjson(jp, {"state": "오류", "at": store.now(), "log": log, "error": traceback.format_exc()})""",
"""def job_state(job):
\"\"\"A queued/running job counts only while its thread lives in this server process; a job left behind by a
stopped server (or test process) is shown as 중단됨 and may be run again.\"\"\"
if job and job["state"] in ("대기", "실행 중"):
t = ACTIVE.get(job.get("id"))
if job.get("pid") != os.getpid() or not (t and t.is_alive()):
return "중단됨"
return job and job["state"]
def _gate_job(p, gate, jid):
jp = p.run_dir / f"{gate}_job.json"
inputs = p.inputs_sha()
log = []
def put(state, **kw):
store.wjson(jp, dict({"id": jid, "pid": os.getpid(), "state": state, "at": store.now(), "log": log}, **kw))
def note(m):
log.append(m)
put("실행 중")
with RHINO_LOCK:
try:
note("Rhino 작업 시작")
rep = run_gate(gate, p.dir / "params.json", p.dir / "expected.json", p.run_dir, log=note)
rep["inputs_sha"], rep["job_id"] = inputs, jid
store.wjson(p.run_dir / f"{gate}_gate.json", rep)
put("완료")
except Exception:
put("오류", error=traceback.format_exc())"""),
(""" job = p.gate_status(gate)["job"]
if job and job["state"] in ("대기", "실행 중"):
flash(f"{gate}는 이미 실행 중입니다.", "fail")
return redirect(url_for("gates", name=name))
# Mark the job as queued before the thread starts, so no request sees the previous run's "완료" state.
store.wjson(p.run_dir / f"{gate}_job.json", {"state": "대기", "at": store.now(), "log": []})
threading.Thread(target=_gate_job, args=(p, gate), daemon=True).start()""",
""" if job_state(p.gate_status(gate)["job"]) in ("대기", "실행 중"):
flash(f"{gate}는 이미 실행 중입니다.", "fail")
return redirect(url_for("gates", name=name))
# Mark the job as queued (with its id) before the thread starts, so no request sees the previous run's state.
jid = uuid.uuid4().hex[:12]
store.wjson(p.run_dir / f"{gate}_job.json",
{"id": jid, "pid": os.getpid(), "state": "대기", "at": store.now(), "log": []})
t = threading.Thread(target=_gate_job, args=(p, gate, jid), daemon=True)
ACTIVE[jid] = t
t.start()"""),
(""" rows = [dict(id=g, name=GATE_NAMES[g], blockers=gate_blockers(p, g), req=p.gate_requirements(g), **p.gate_status(g))
for g in gate_ids()]
running = any(r["job"] and r["job"]["state"] in ("대기", "실행 중") for r in rows)""",
""" rows = [dict(id=g, name=GATE_NAMES[g], blockers=gate_blockers(p, g), req=p.gate_requirements(g), **p.gate_status(g))
for g in gate_ids()]
for r in rows:
r["state"] = job_state(r["job"])
running = any(r["state"] in ("대기", "실행 중") for r in rows)"""),
])
patch("web/templates/gates.html", [
("""{% if g.job and g.job.state in ('대기', '실행 중') %}<p class="warn">{{ g.job.state }}: {{ g.job.log[-1] if g.job.log else '' }}</p>
{% elif g.job and g.job.state == '오류' %}<p class="fail">오류</p><pre>{{ g.job.error }}</pre>{% endif %}""",
"""{% if g.state in ('대기', '실행 중') %}<p class="warn">{{ g.state }}: {{ g.job.log[-1] if g.job.log else '' }}</p>
{% elif g.state == '중단됨' %}<p class="warn">중단됨: 이전 실행이 끝나지 않은 채 서버가 멈췄습니다. 다시 실행하세요.</p>
{% elif g.state == '오류' %}<p class="fail">오류</p><pre>{{ g.job.error }}</pre>{% endif %}"""),
])
patch("tools/test_web.py", [
("""def html(r):
return r.get_data(as_text=True)""",
"""def html(r):
return r.get_data(as_text=True)
def run_and_wait(c, P, g, limit=900):
\"\"\"POST run, then wait until the job with the id written at start-up is finished; returns (job, trace).\"\"\"
c.post(f"/pier/{P}/gate/{g}/run")
jid = (store.Pier(P).gate_status(g)["job"] or {}).get("id")
t0, trace = time.time(), []
while time.time() - t0 < limit:
job = store.Pier(P).gate_status(g)["job"] or {}
trace.append((round(time.time() - t0), job.get("id") == jid, job.get("state")))
if jid and job.get("id") == jid and job.get("state") in ("완료", "오류"):
return job, trace
time.sleep(3)
return None, trace"""),
(""" r = c.post(f"/pier/{P}/gate/{g}/run", follow_redirects=True)
t0 = time.time()
while True:
job = store.Pier(P).gate_status(g)["job"]
if job and job["state"] in ("완료", "오류"):
break
if time.time() - t0 > 900:
break
time.sleep(3)
st = store.Pier(P).gate_status(g)
rep = st["report"] or {}
check(f"{g} run via app -> PASS", job and job["state"] == "완료" and rep.get("verdict") == "PASS",
f"{rep.get('summary')} {time.time() - t0:.0f}s {job.get('error', '')[-200:] if job else ''}")""",
""" job, trace = run_and_wait(c, P, g)
rep = store.Pier(P).gate_status(g)["report"] or {}
check(f"{g} run via app -> PASS", bool(job) and job["state"] == "완료" and rep.get("verdict") == "PASS"
and rep.get("job_id") == job["id"], f"{rep.get('summary')} {trace[-1][0]}s {(job or {}).get('error', '')[-200:]}")"""),
(""" c.post(f"/pier/{P}/gate/G1/run")
t0 = time.time()
while time.time() - t0 < 600:
job = store.Pier(P).gate_status("G1")["job"]
if job and job["state"] in ("완료", "오류"):
break
time.sleep(3)
rep = store.Pier(P).gate_status("G1")["report"]
check("pile length +5 mm -> G1 FAIL (pile length)", rep["verdict"] == "FAIL" and "pile length" in rep["unplanned_fails"],
rep["unplanned_fails"])""",
""" job, trace = run_and_wait(c, P, "G1")
rep = store.Pier(P).gate_status("G1")["report"]
check("pile length +5 mm -> G1 FAIL (pile length)", bool(job) and rep.get("job_id") == job["id"]
and rep["verdict"] == "FAIL" and "pile length" in rep["unplanned_fails"],
f"{rep['unplanned_fails']} trace {trace[:2]}..{trace[-2:]}")"""),
(""" check("report: other modelled marks match", md.count("| 일치 |") == 35, md.count("| 일치 |"))""",
""" sec6 = md.split("## 6.")[1].split("## 7.")[0]
check("report: other modelled marks match (35)", sec6.count("| 일치 |") == 35, sec6.count("| 일치 |"))"""),
(""" # 8 a wrong input gives a FAIL gate""",
""" # 7b a job left "실행 중" by a stopped process must not block the gate forever
jp = TD / P / "runs" / "current" / "G1_job.json"
store.wjson(jp, {"id": "orphan", "pid": -1, "state": "실행 중", "at": store.now(), "log": ["x"]})
r = c.get(f"/pier/{P}/gates")
check("orphaned running job shown as 중단됨", "중단됨: 이전 실행" in html(r))
# 8 a wrong input gives a FAIL gate"""),
])
print("patched")