- 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>
106 lines
5.4 KiB
Python
106 lines
5.4 KiB
Python
"""Patch (2026-10-13, Ulsan P1): per-pier gate scope in the web app and the report.
|
|
Gates outside params["scope"] are not listed / run / required; the previous gate of a gate is the previous gate
|
|
in scope; optional sections (params.piles for a pier without piles) are not required for confirmation."""
|
|
from pathlib import Path
|
|
|
|
APP = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
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[:70])
|
|
s = s.replace(a, b)
|
|
p.write_text(s, encoding="utf-8")
|
|
|
|
|
|
patch("web/store.py", [
|
|
(""" def gate_requirements(self, gate):
|
|
need = COMMON + GATE_SECTIONS[gate]
|
|
return [dict(file=f, key=k, **self.section_state(f, k)) for f, k in need]""",
|
|
""" def gate_requirements(self, gate):
|
|
need = COMMON + GATE_SECTIONS[gate]
|
|
P = self.load("params")
|
|
need = [(f, k) for f, k in need if not ((f, k) in OPTIONAL and k not in P)]
|
|
return [dict(file=f, key=k, **self.section_state(f, k)) for f, k in need]
|
|
|
|
def scope(self):
|
|
\"\"\"Gates modelled for this pier (params["scope"], default all five).\"\"\"
|
|
sc = self.load("params").get("scope")
|
|
return [g for g in ("G1", "G2", "G3", "G4", "G5") if not sc or g in sc]"""),
|
|
("""GATE_SECTIONS = {""", """OPTIONAL = {("params", "piles")} # a pier on a spread footing has no piles (Ulsan P1)
|
|
GATE_SECTIONS = {"""),
|
|
])
|
|
|
|
patch("web/app.py", [
|
|
(""" gates = [dict(id=g, name=GATE_NAMES[g], **p.gate_status(g)) for g in gate_ids()]""",
|
|
""" gates = [dict(id=g, name=GATE_NAMES[g], **p.gate_status(g)) for g in p.scope()]"""),
|
|
(""" out = []
|
|
for g in gate_ids():
|
|
for r in p.gate_requirements(g):""",
|
|
""" out = []
|
|
for g in p.scope():
|
|
for r in p.gate_requirements(g):"""),
|
|
(""" k = gate_ids().index(gate)
|
|
if k > 0 and not p.gate_status(gate_ids()[k - 1])["approved"]:
|
|
out.append(f"{gate_ids()[k - 1]} 미승인")""",
|
|
""" ids = p.scope()
|
|
if gate not in ids:
|
|
return [f"{gate}는 이 교각의 범위 밖"]
|
|
k = ids.index(gate)
|
|
if k > 0 and not p.gate_status(ids[k - 1])["approved"]:
|
|
out.append(f"{ids[k - 1]} 미승인")"""),
|
|
(""" todo = [g for g in gate_ids() if not p.gate_status(g)["approved"]]
|
|
if not todo:""",
|
|
""" todo = [g for g in p.scope() if not p.gate_status(g)["approved"]]
|
|
if not todo:"""),
|
|
(""" for g in gate_ids()]
|
|
for r in rows:""",
|
|
""" for g in p.scope()]
|
|
for r in rows:"""),
|
|
(""" todo=[g for g in gate_ids() if not p.gate_status(g)["approved"]])""",
|
|
""" todo=[g for g in p.scope() if not p.gate_status(g)["approved"]],
|
|
out_of_scope=[g for g in gate_ids() if g not in p.scope()])"""),
|
|
(""" if not any(p.gate_status(g)["report"] for g in gate_ids()):""",
|
|
""" if not any(p.gate_status(g)["report"] for g in p.scope()):"""),
|
|
(""" stale = {g for g in gate_ids() if p.gate_status(g)["stale"]}
|
|
out = report_files.write(p.dir, p.run_dir, request.form.get("by", "").strip(), stale)""",
|
|
""" stale = {g for g in p.scope() if p.gate_status(g)["stale"]}
|
|
out = report_files.write(p.dir, p.run_dir, request.form.get("by", "").strip(), stale,
|
|
[g for g in gate_ids() if g not in p.scope()])"""),
|
|
(""" todo=[g["id"] for g in gates if not g["approved"]], running=anything_running(p),""",
|
|
""" todo=[g["id"] for g in gates if not g["approved"]], running=anything_running(p),
|
|
out_of_scope=[g for g in gate_ids() if g not in p.scope()],"""),
|
|
])
|
|
|
|
patch("web/templates/gates.html", [
|
|
("""<h2>일괄 승인 (필요하면 실행)</h2>""",
|
|
"""{% if out_of_scope %}<p class="muted">이 교각의 범위 밖 게이트: {{ out_of_scope|join(', ') }} (실행·승인 대상 아님)</p>{% endif %}
|
|
<h2>일괄 승인 (필요하면 실행)</h2>"""),
|
|
])
|
|
patch("web/templates/pier.html", [
|
|
("""<h2>3. 게이트</h2>""",
|
|
"""<h2>3. 게이트</h2>
|
|
{% if out_of_scope %}<p class="muted">범위 밖: {{ out_of_scope|join(', ') }} — 이 교각에서는 모델링하지 않습니다.</p>{% endif %}"""),
|
|
])
|
|
|
|
patch("engine/report_files.py", [
|
|
("""def write(pier_dir, run_dir, author="", stale=()):""", """def write(pier_dir, run_dir, author="", stale=(), out_of_scope=()):"""),
|
|
(""" md, d = report.build(pier_dir, run_dir, author, today, stale)""",
|
|
""" md, d = report.build(pier_dir, run_dir, author, today, stale, out_of_scope)"""),
|
|
])
|
|
|
|
patch("engine/report.py", [
|
|
("""def build(pier_dir, run_dir, author="", today=None, stale=()):""",
|
|
"""def build(pier_dir, run_dir, author="", today=None, stale=(), out_of_scope=()):"""),
|
|
(""" all_ok = all(gates[g] and gates[g]["verdict"] == "PASS" and appr.get(g, {}).get("decision") == "승인"
|
|
for g in gate_ids())""",
|
|
""" all_ok = all(gates[g] and gates[g]["verdict"] == "PASS" and appr.get(g, {}).get("decision") == "승인"
|
|
for g in gate_ids() if g not in out_of_scope)"""),
|
|
(""" rows.append([g, gname, "입력 변경 — 무효(재실행 필요)" if g in stale else "미실행", "-", "-", "-"])""",
|
|
""" rows.append([g, gname, "범위 밖" if g in out_of_scope else
|
|
("입력 변경 — 무효(재실행 필요)" if g in stale else "미실행"), "-", "-", "-"])"""),
|
|
])
|
|
print("patched")
|