refactor(B05): 구조물 설치측·이격 입력 폐지 — 데이터 필드까지 제거

사용자 지시로 두 값을 걷어낸다. 구조물별 옵션·정의는 앞으로 타입마다
따로 정한다. 어차피 소비처가 없어(B06~B08은 structures를 읽지 않는다)
화면에만 남아 있던 값이었다.

- 폼: 설치측 select·이격 칸 행 삭제, 목록 부제·종단 벌룬에서 측 표기 제거
- 계약: StructureSide 타입, StructureInstance.side/offset_m 삭제(프론트·스키마)
- 설계지문에서 두 값 제외 — 후속 단계 무효화 판정에서 빠진다
- 구 저장분은 읽을 때 두 키만 떨어낸다. extra="forbid"라 그냥 두면 정본이
  통째로 버려진다. 다른 낯선 키는 계속 거절한다
This commit is contained in:
2026-08-17 20:04:32 +09:00
parent 6c6a0c2773
commit b92ba4592e
8 changed files with 23 additions and 56 deletions
@@ -10,7 +10,7 @@
import json
import os
import uuid
from typing import Iterable
from typing import Any, Iterable
from B05_Profile.B05_Profile_Structures_Schema import StructureInstance, structure_type_map
from common_util.common_util_json import atomic_write_json
@@ -31,6 +31,12 @@ class StructureRevisionConflict(RuntimeError):
self.actual = actual
# 2026-08-17 사용자 지시로 걷어낸 필드 — 설치측·이격은 받지 않는다. 스키마가
# extra="forbid"라 남아 있는 저장분을 그대로 넘기면 정본 전체가 통째로 버려지므로,
# 읽을 때 이 두 키만 떨어낸다. 다른 낯선 키는 계속 거절해 정본이 조용히 썩는 것을 막는다.
_DROPPED_KEYS = ("side", "offset_m")
def structures_file_path(project_root: str) -> str:
"""프로젝트 저장소 안의 구조물 정본 경로."""
return os.path.join(project_root, _STAGE_DIR, STRUCTURES_FILE_NAME)
@@ -50,13 +56,23 @@ def load_structures(project_root: str) -> tuple[int, list[StructureInstance]]:
payload = json.load(handle)
revision = int(payload.get("revision", 0))
structures = [
StructureInstance.model_validate(item) for item in payload.get("structures", [])
StructureInstance.model_validate(_without_dropped_keys(item))
for item in payload.get("structures", [])
]
except (OSError, ValueError, TypeError):
return 0, []
return revision, structures
def _without_dropped_keys(item: Any) -> Any:
"""폐지된 필드가 남아 있는 저장분을 지금 스키마로 읽을 수 있게 손질한다."""
if not isinstance(item, dict):
return item
if not any(key in item for key in _DROPPED_KEYS):
return item
return {key: value for key, value in item.items() if key not in _DROPPED_KEYS}
def save_structures(
project_root: str,
structures: Iterable[StructureInstance],
@@ -97,7 +113,7 @@ def requires_downstream_invalidation(
메모나 표시용 값만 바뀐 경우까지 후속 단계를 깨면, 사용자가 메모 한 줄 고칠 때마다
횡단·수량을 다시 돌려야 한다. 그래서 설계에 실제로 영향을 주는 값
(타입·위치·범위·측·오프셋·제원)만 비교한다. 목록 순서는 설계와 무관하므로 무시한다.
(타입·위치·범위·제원)만 비교한다. 목록 순서는 설계와 무관하므로 무시한다.
"""
return _design_fingerprint(previous) != _design_fingerprint(current)
@@ -112,8 +128,6 @@ def _design_fingerprint(items: Iterable[StructureInstance]) -> set[str]:
item.chainage_m,
item.start_m,
item.end_m,
item.side,
item.offset_m,
item.options,
item.geometry,
],