feat(design): 구조물 명세 공용 틀 + 횡단배수 배관(표 01) 컨테이너 폼

- 공용 틀(A00_Common/design/design_structure_*) — 명세(컨테이너 필수/선택 · 여러 개 · 항목 고르기/숫자/자동 · 상위 값에 따른 선택지 · 저장 키) · 그리기([추가]/[빼기]) · 길이 = 전 + 후 맞물림(마지막에 고친 둘을 지킴)
- 배관 명세 = 관 · 관 보호공(유입) · 관 보호공(유출) · 흙막이 추가 · 도수로/돌붙임 · 저장 키는 pipe_points 옛 키 그대로 · 옛 관종 · 날개벽 · 집수정 형식은 화면에서 빼고 지난 정의 값으로 남김
- 컨테이너 인스턴스마다 「구조물 조합」 잇기(group_items · 그룹 [고르기] 길 그대로) · 명세 종류는 그룹 상자 · 종류 단위 줄 가림 · 종류 단위 잇기 줄은 기준 측점 바로 아래
- 관 길이 자동 = 횡단 기하 computeStoredLayouts 값(서버 Node 와 같은 함수) · 높이 빈 칸 안내 = 관경 기준 최소 높이
- 정의 판 6 — 종류.pipe.이름 표(이름 바꿈 키) · 검사기가 이름 표 받음 · 판 5 이력 보관
- 시험 test_52_structure_spec_pipe · 병합 시험 기대값(빠진 옛 칸은 남음)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
This commit is contained in:
2026-10-05 23:13:21 +09:00
co-authored by Claude Opus 5.5
parent 4bc6ec8106
commit 0a095c14b1
19 changed files with 4439 additions and 175 deletions
@@ -87,8 +87,15 @@ def _type_errors(doc: dict[str, Any]) -> tuple[list[str], dict[str, dict[str, An
return errors, keys
def _names_ok(value: Any) -> bool:
"""구조물 명세 이름 바꿈 표 — `{컨테이너[.항목[=값]]: 빈 글 아닌 이름}`."""
return isinstance(value, dict) and all(
isinstance(k, str) and isinstance(v, str) and v.strip() for k, v in value.items()
)
def _kind_errors(doc: dict[str, Any], keys: dict[str, dict[str, Any]]) -> list[str]:
"""종류마다 덧칸 — `{기준측점: 참거짓, 동작: [동작 이름]}`."""
"""종류마다 덧칸 — `{기준측점: 참거짓, 동작: [동작 이름], 이름: {명세 이름 키: 이름}}`(이름 = PLAN 52)."""
errors: list[str] = []
acts = doc.get("동작") if isinstance(doc.get("동작"), dict) else {}
for tid, row in doc["종류"].items():
@@ -100,8 +107,10 @@ def _kind_errors(doc: dict[str, Any], keys: dict[str, dict[str, Any]]) -> list[s
continue
if name == "동작" and isinstance(value, list) and all(a in acts for a in value):
continue
if name == "이름" and _names_ok(value):
continue
errors.append(
f"종류 덧칸 「{tid}.{name}」 이 틀림(기준측점 참거짓 · 동작 = 동작 이름들)"
f"종류 덧칸 「{tid}.{name}」 이 틀림(기준측점 참거짓 · 동작 = 동작 이름들 · 이름 = 글 묶음)"
)
return errors