feat(구조물표): 322-2 M02 표 화면 — 탭 셋(한눈 표 · 종류별 · 부품) · 반영 · 부품 · 알약 색 저장 · 목록 + enabled 함께 · 검사 짝(화면 = 서버 · 1-3 규칙 · 만든 뒤 고정) · 명세 폼 보임 따름 · 판 알림

- 한눈 표(M02_SO_Def_Table): 군 · 종류 ▲▼ · 이름 · 목록 · 자리꼴 · 정본(고정) · 횡단도 · 카드 이름 · 형상(+ 벽 기본 형태 · 물빼기) · 알약 색 · 3D · 검사 · 처음 값 = 흐림 「기본」 · 바꿈 = 진함 · [처음 값으로]
- 종류별: 반영 칸 + 명세 이름 나무 줄마다 보임(컨테이너 = 그 안 칸) · 못 숨김 · 미리보기 숨김 따름 · 「안 씀」 = 목록 B06 만
- 부품 탭(M02_SO_Def_Parts): 부품 · 읽는 칸 · 자리꼴 · 정본 · 쓰는 종류 · 켬/끔(정의 부품 = 끈 것만)
- 편집 손질(M02_SO_Def_Reflect): 처음 값이면 반영에서 지움 · [저장] 때 enabled = 목록 both 일 때만 참
- 검사 짝 M02_SO_Def_Check.ts ↔ M02_SO_Check.py(글까지 같음): 반영 · 부품 꼴 · 형상 none → 횡단도 none · 부품 자리꼴 · 정본 · 기본값 없는 읽는 칸 새로 숨김 금지(앞 판 숨김 그대로) · 종류 지우기 · 자리꼴 · 정본 · 군 글자 · 선택지 값 고정 · 서버 check(doc, 지금 판) · 앞 판 없으면 꼴만
- 명세 폼: 쓰는 옵션 키가 모두 숨긴 칸 · 상자는 안 그림(값 그대로) · B05 · B06 시설 · 구조물 명세 폼이 정의 「표시」를 따름
- 판 알림: GET 구조물 목록에 definition_version · structures.json 판 ≠ 지금 판이면 「구조물 정의가 판 N 으로 바뀜 — 저장하면 반영」 한 번
- 시험: test_322_2_check_mirror(거울 · 규칙 · 반영 손질 · 서버 저장 · 422) · 판 알림 · 옛 정의 화면 시험 = 선택지 값 대신 이름 표 · 못 숨김 아닌 칸

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
2026-10-14 15:40:38 +09:00
co-authored by Claude Opus 5.5
parent bbd6254892
commit 3abd2bdfd4
26 changed files with 1635 additions and 34 deletions
@@ -18,10 +18,12 @@ from pydantic import ValidationError
from B05_Profile import B05_Profile_Structures_Schema as schema
from common_util.common_util_json import atomic_write_json
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete.StructOptions.M02_SO_Check import catalog_errors
FILE = "구조물정의.json"
HISTORY = "구조물정의_이력"
TOP = {"판", "schema_version", "comment", "구조물군", "동작", "types"}
# 반영 · 부품 = 구조물 표 칸(322-2 · 없으면 처음값 · 검사 = `M02_SO_Check`)
TOP = {"판", "schema_version", "comment", "구조물군", "동작", "types", "반영", "부품"}
SECTIONS = {"종류": dict, "표시": dict, "그룹": dict, "배치": dict, "규칙": list}
SPOT = ("줄", "칸", "너비")
@@ -171,8 +173,8 @@ def _rule_errors(doc: dict[str, Any], keys: dict[str, dict[str, Any]]) -> list[s
return errors
def check(doc: Any) -> list[str]:
"""정의 한 벌 검사 — 틀린 것 목록(빈 목록 = 통과)."""
def check(doc: Any, before: dict[str, Any] | None = None) -> list[str]:
"""정의 한 벌 검사 — 틀린 것 목록(빈 목록 = 통과). `before` = 지금 판(만든 뒤 고정 · 322-2)."""
from M02_MasterTemplete.StructOptions import M02_SO_Groups as groups
from M02_MasterTemplete.StructOptions import M02_SO_Options as options
@@ -194,7 +196,8 @@ def check(doc: Any) -> list[str]:
fn(doc[section], plain)
except store.StoreError as e:
errors += e.detail["errors"] if isinstance(e.detail, dict) else [str(e.detail)]
return errors + _kind_errors(doc, keys) + _spot_errors(doc, keys) + _rule_errors(doc, keys)
errors += _kind_errors(doc, keys) + _spot_errors(doc, keys) + _rule_errors(doc, keys)
return errors + ([] if errors else catalog_errors(doc, before))
def _commit(change: Callable[[dict[str, Any]], dict[str, Any]], version: Any) -> dict[str, Any]:
@@ -206,7 +209,7 @@ def _commit(change: Callable[[dict[str, Any]], dict[str, Any]], version: Any) ->
if str(version) != str(have):
raise store.StoreError(409, {"stale": [FILE], "판": have})
doc = {**change(current), "판": have}
errors = check(doc)
errors = check(doc, current)
if errors:
raise store.StoreError(422, {"errors": errors})
atomic_write_json(history_path(have), current)