- 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>
82 lines
4.4 KiB
Python
82 lines
4.4 KiB
Python
"""Stage A (2026-10-16): web/app.py pier page metadata, F-field edit rule (D3) and V3 edit block; web/store.py edit log.
|
|
Backup in backup/2026-10-16_묶음개편A전/. Refuses to run twice."""
|
|
from pathlib import Path
|
|
|
|
APP = Path(__file__).resolve().parents[2]
|
|
A, S = APP / "web" / "app.py", APP / "web" / "store.py"
|
|
|
|
|
|
def patch(path, pairs):
|
|
s = path.read_text(encoding="utf-8")
|
|
assert "# stage A 2026-10-16" not in s, f"{path.name} already patched"
|
|
for a, b in pairs:
|
|
assert s.count(a) == 1, (path.name, a[:60])
|
|
s = s.replace(a, b)
|
|
path.write_text(s, encoding="utf-8")
|
|
|
|
|
|
patch(S, [(
|
|
' def set_section(self, which, key, value):',
|
|
''' def log_fixed_edit(self, which, key, paths, reason):
|
|
"""Record of an edit of fixed (F) fields with its reason (D3) # stage A 2026-10-16"""
|
|
log = rjson(self.dir / "edit_log.json", [])
|
|
log.append({"at": now(), "section": f"{which}:{key}", "fixed_fields": paths, "reason": reason})
|
|
wjson(self.dir / "edit_log.json", log)
|
|
|
|
def set_section(self, which, key, value):''')])
|
|
|
|
patch(A, [
|
|
("from engine import recommend, reader, report_files # noqa: E402", "from engine import recommend, reader, report_files, variability # noqa: E402"),
|
|
(''' secs = []
|
|
for s in p.sections():
|
|
secs.append(dict(s, **p.section_state(s["file"], s["key"])))
|
|
''', ''' secs = []
|
|
req = required(p)
|
|
for s in p.sections():
|
|
secs.append(dict(s, **p.section_state(s["file"], s["key"]), meta=p.section_meta(s["file"], s["key"]),
|
|
required=(s["file"], s["key"]) in req))
|
|
origin_same = [s for s in secs if s["required"] and s["meta"]["origin"]] # stage A 2026-10-16
|
|
'''),
|
|
(''' return render_template("pier.html", p=p, sections=secs, gates=gates, need=unconfirmed(p),''',
|
|
''' return render_template("pier.html", p=p, sections=secs, gates=gates, need=unconfirmed(p), origin_same=origin_same,
|
|
has_origin=bool(p.info.get("origin")), grades=variability.GRADES,'''),
|
|
(''' text = json.dumps(d[key], ensure_ascii=False, indent=1)
|
|
if request.method == "POST":
|
|
text = request.form["value"]
|
|
try:
|
|
p.set_section(which, key, json.loads(text))
|
|
flash("저장했습니다. 확정하려면 '확정'을 누르세요.", "ok")
|
|
return redirect(url_for("section", name=name, which=which, key=key))
|
|
except (ValueError, json.JSONDecodeError) as e:
|
|
flash(f"저장 안 됨: {e}", "fail")
|
|
return render_template("section.html", p=p, which=which, key=key, text=text, st=p.section_state(which, key))''',
|
|
''' text = json.dumps(d[key], ensure_ascii=False, indent=1)
|
|
meta = p.section_meta(which, key)
|
|
if request.method == "POST":
|
|
text = request.form["value"]
|
|
reason = request.form.get("reason", "").strip()
|
|
try:
|
|
new = store.expand_chains(json.loads(text))
|
|
if meta["grade"] == "V3":
|
|
raise ValueError("생성 변수(V3)는 화면에서 직접 고칠 수 없습니다. 판독 스크립트를 다시 실행해 목록을 만든 뒤 반영하세요")
|
|
fixed = ["(묶음 전체)"] if meta["grade"] == "F" and new != d[key] else variability.changed_fixed(d[key], new, meta["fixed_fields"])
|
|
if fixed and not reason:
|
|
raise ValueError(f"고정(F) 항목({', '.join(fixed)})을 바꾸면 같은 템플릿이 아닐 수 있습니다. 바꾸는 사유를 입력하세요")
|
|
p.set_section(which, key, new)
|
|
if fixed:
|
|
p.log_fixed_edit(which, key, fixed, reason)
|
|
flash("저장했습니다. 확정하려면 '확정'을 누르세요." + (" 고정 항목 변경 사유를 기록했습니다." if fixed else ""), "ok")
|
|
return redirect(url_for("section", name=name, which=which, key=key))
|
|
except (ValueError, json.JSONDecodeError) as e:
|
|
flash(f"저장 안 됨: {e}", "fail")
|
|
return render_template("section.html", p=p, which=which, key=key, text=text, st=p.section_state(which, key), meta=meta,
|
|
grades=variability.GRADES)'''),
|
|
('''def unconfirmed(p):''', '''def required(p):
|
|
"""Bundles any gate of the pier's scope needs (existing ones)."""
|
|
return {(r["file"], r["key"]) for g in p.scope() for r in p.gate_requirements(g) if r["exists"]}
|
|
|
|
|
|
def unconfirmed(p):'''),
|
|
])
|
|
print("patched app.py, store.py")
|