fix(532-1): E01 복사본 읽기 — 횡단 경로 null · 파일 없음 · 옛 꼴도 B06 이름 규칙으로 찾음 · 없으면 그 측점만 건너뜀 · 생성 복사 경고(요구 351)

- Source.stations · cross_section: 경로 칸 null · 파일 없음 · 절대 경로 · 옛 정수 m 이름이면 find_cross_file 로 찾음 · 그래도 없으면 「횡단 없음」(stations 에서 빠짐 · cross_section KeyError) · missing_stations 추가
- copy_stability: 같은 검사 → manifest missing_cross_chainages · warnings · E01 생성 응답 warnings
- 실측: 검증 프로젝트 14 복사 모두 stations 성공 · 검증_브레인232 null 1 행(359 m) 살림

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 21:05:14 +09:00
co-authored by Claude Opus 5.5
parent 6029108bdb
commit f2c3aefae2
4 changed files with 182 additions and 13 deletions
+22
View File
@@ -27,6 +27,7 @@ from uuid import uuid4
import aiomysql
from B05_Profile.B05_Profile_Engine_Sections_Names import find_cross_file
from common_util.common_util_storage import resolve_stored_project_path
from common_util.common_util_surface_confirmation import get_surface_confirmation_params
@@ -42,6 +43,19 @@ _STABILITY_TREES = (
"B06_Section/cross_sections",
"B04_PreProcess/drainage/edits",
)
_CROSS_DIR = "B06_Section/cross_sections"
def resolve_cross_file(root: Path, row: dict[str, Any]) -> Path | None:
"""횡단 행 → root 아래 횡단 파일 — 경로 칸이 없거나(null) · 파일이 없거나 · 절대 경로(옛 꼴)면
B06 이름 규칙(`find_cross_file` · 옛 정수 m 이름 포함)으로 찾음 · 그래도 없으면 None."""
relative = row.get("cross_section_file_path")
if relative and not Path(relative).is_absolute() and (root / relative).is_file():
return root / relative
if row.get("chainage_m") is None:
return None
found = find_cross_file(root / _CROSS_DIR, float(row["chainage_m"]))
return found if found.is_file() else None
async def _rows(cursor, sql, args):
@@ -424,6 +438,11 @@ async def copy_stability(connection, source_id: str, new_id: str, project_root:
digest.update(STABILITY_DB_NAME.encode("utf-8") + b"\0" + db_text.encode("utf-8"))
(target / STABILITY_DB_NAME).write_text(db_text, encoding="utf-8")
sizes[STABILITY_DB_NAME] = len(db_text.encode("utf-8"))
missing = sorted(
float(row["chainage_m"] or 0.0)
for row in dump["cross_sections"]
if resolve_cross_file(target, row) is None
)
manifest = {
"scope": "stability",
"source_project_id": source_id,
@@ -437,6 +456,9 @@ async def copy_stability(connection, source_id: str, new_id: str, project_root:
"longitudinal_sections": len(dump["longitudinal_sections"]),
},
"uuid_replaced": replaced,
#: 횡단 파일을 못 찾은 측점(누가거리) — E 는 그 측점을 「횡단 없음」으로 건너뜀
"missing_cross_chainages": missing,
"warnings": [f"횡단 없는 측점 {len(missing)} 개 — 해석에서 빠짐"] if missing else [],
"total_bytes": sum(sizes.values()),
"elapsed_s": round(time.perf_counter() - started, 2),
"files": sizes,