feat(M02): 50-3 ①②⑤ 일위대가 조합 서고 서버 — 단가승격 SP · 사전조합 SC · 참조 펼침 · 굳힘

- 층 양식 길 새 종류 promote · precombo(키 = 파일 이름 · 층마다 다음 번호) · 새로 · 복사 길 POST /layers/{층}/library/{종류}
- 참조 {층 · 주인 · 키} — 위 층만 · 같은 참조 두 번 400 · 순환 422 · 쓰는 곳 있으면 지우기 409(모든 층 일위대가 · 사전조합 훑음)
- calc 가 참조 줄 펼침(재귀 · 캐시 · 깊이 상한 8 · 까닭) · 알약 키 「참조|층|주인|키」 · 분모 = 가리킨 문서 단위 · 배 1 · settle TS 짝 lineId
- 층 사이 복사 = 못 읽는 참조 같이 복사(본뜬) · 프로젝트 가져오기 = 참조사본으로 굳힘 · 로직 지우기 검사에 단가승격 더함 · 새 프로젝트 씨앗은 서고 뺌
- 시험 test_m02_labor_ref.py(펼침 · 순환 · 층 규칙 · 409 · 복사 · 굳힘 · 거울)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
This commit is contained in:
2026-10-05 18:47:02 +09:00
co-authored by Claude Opus 5.5
parent 3e572ef210
commit 9ee6c9f3fd
12 changed files with 966 additions and 53 deletions
+13 -9
View File
@@ -221,19 +221,21 @@ def check_saved(files: dict, changed: list[str], book: dict, narrowed=None) -> l
def _labor_files() -> list[tuple[str, Path]]:
"""모든 층(마스터 · 회사 · 개인)의 일위대가 문서 `labor/<열>.json` — (어디, 파일)."""
"""모든 층(마스터 · 회사 · 개인)의 일위대가 `labor/<열>.json` · 단가승격 `promote/<키>.json`
— (어디, 파일)."""
from M02_MasterTemplete import M02_Template_Layers as layers # M02 가 M01 을 부름 — 늦게
root = layers.storage_root()
found = [("마스터", p) for p in sorted((layers.system_dir() / "labor").glob("*.json"))]
found += [(f"회사 {p.parts[-4]}", p) for p in sorted(root.glob("*/templates/labor/*.json"))]
personal = sorted(root.glob("*/*/templates/labor/*.json"))
return found + [(f"개인 {p.parts[-5]}/{p.parts[-4]}", p) for p in personal]
return [
(f"{what} {where}", path)
for kind, what in (("labor", "일위대가"), ("promote", "단가승격"))
for where, path in layers.layer_files(kind)
]
def labor_errors(whole) -> list[str]:
"""일위대가 문서가 담은 로직이 마스터에 없음(39-1d) — 로직 지우기를 막음 · 어디서 쓰는지 알림.
전부터 깨진 것은 `save` 가 고치기 전 검사와 견주어 뺌."""
"""일위대가 · 단가승격 문서가 담은 로직이 마스터에 없음(39-1d · 50-3) — 로직 지우기를 막음 ·
어디서 쓰는지 알림 · 참조 줄(로직 없음)은 건너뜀. 전부터 깨진 것은 `save` 가 고치기 전 검사와
견주어 뺌."""
out = []
for where, path in _labor_files():
try:
@@ -243,10 +245,12 @@ def labor_errors(whole) -> list[str]:
name = (doc.get("일위대가번") if isinstance(doc, dict) else None) or path.stem
for one in (doc.get("담은로직") if isinstance(doc, dict) else None) or []:
key = str(one.get("로직") or "") if isinstance(one, dict) else ""
if not key:
continue
try:
whole.logic(key)
except cm.mf.FormulaError:
out.append(f"일위대가 {where} 「{name}」 이 로직 「{key}」 을 씀 — 거기서 먼저 뺌")
out.append(f"{where} 「{name}」 이 로직 「{key}」 을 씀 — 거기서 먼저 뺌")
return out