From 908c75d535da1a027e2b19aa66891af91bf0b3e0 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 7 Sep 2026 01:04:49 +0900 Subject: [PATCH] =?UTF-8?q?fix(B05):=20=EB=85=B8=EC=84=A0=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=95=8C=20=EC=98=9B=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=20=EC=84=A4=EA=B3=84=EA=B0=80=20=EB=8D=AE=EC=97=AC=20=EC=82=AC?= =?UTF-8?q?=EB=9D=BC=EC=A7=80=EB=8D=98=20=EA=B2=83=20=E2=80=94=20=EC=9D=B4?= =?UTF-8?q?=EC=9B=94=20=EC=88=9C=EC=84=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 보조 창 실측 — 노드를 옮겨 재계산하면 다단 구간값(extra_spans)이 0건이 됐음. 심어 둔 표식(85.18m 의 14/6/8)이 통째로 사라짐. 원인은 순서였음. 이월이 _prepare_drainage_pipes_and_reprofile(refresh=True) **앞**에서 돌았는데, 그 단계가 측점을 새 노선 기준으로 다시 만들며 방금 얹은 설계를 덮었음. - 이월을 측점 재생성 **뒤**로 옮김. 옛 설계는 이미 old_designs 로 손에 있음. - 행마다 쓰던 것을 merge_cross_section_designs 로 묶음 — 행 수와 무관하게 왕복 두 번 (원격 DB 왕복 약 12ms/질의). 같은 요청에서 확인된 통과분(보조 창) — 측점 수·끝 누가거리가 새 노선과 일치(67·1,097.4m 고정 -> 64·1,079.4m), 배수관 측점 0 -> 7~9, 「세그먼트 경로 탐색 실패」 로그 사라짐. 시험 409 통과·17 건너뜀, main import 스모크 통과. Co-Authored-By: Claude Opus 5 (1M context) --- B03_FileInput/B03_FileInput_Service_Chain.py | 60 +++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/B03_FileInput/B03_FileInput_Service_Chain.py b/B03_FileInput/B03_FileInput_Service_Chain.py index b180c33d..618764d9 100644 --- a/B03_FileInput/B03_FileInput_Service_Chain.py +++ b/B03_FileInput/B03_FileInput_Service_Chain.py @@ -352,8 +352,8 @@ async def run_redesign_chain( from B06_Section.B06_Section_Repository import ( get_cross_section_designs, get_longitudinal_section, - update_cross_section_design, ) + from B06_Section.B06_Section_Repository_Bulk import merge_cross_section_designs from B06_Section.B06_Section_Router_Confirm import confirm_sections from B06_Section.B06_Section_Schema import SectionConfirmRequest from common_util.common_util_initial_snapshot import ( @@ -468,33 +468,11 @@ async def run_redesign_chain( new_route_id, ) - # 3) 옛 측점별 사용자 설계를 chainage 매칭으로 새 경로에 이월(비치명적). + # 3) 옛 측점별 사용자 설계 이월은 **측점을 다시 만든 뒤**(아래 5) 한다. + # 여기서 하면 `_prepare_drainage_pipes_and_reprofile(refresh=True)` 가 측점을 + # 새로 만들며 덮어써 값이 사라진다(2026-09-06 실측: 다단 구간값 `extra_spans` 가 + # 노선 변경 뒤 0건이 됐음). 옛 설계는 `old_designs` 로 이미 손에 있다. carried = 0 - try: - async with pool.acquire() as connection: - await connection.begin() - try: - for record in old_designs: - design = record.get("design") - if not isinstance(design, dict): - continue - await update_cross_section_design( - connection, - route_id=new_route_id, - chainage_m=float(record["chainage_m"]), - design=design, - project_id=project_id, - ) - carried += 1 - await connection.commit() - except Exception: - await connection.rollback() - raise - except Exception: - logger.exception( - "재확정 체인 — 옛 설계 이월 실패(계속 진행): project_id=%s", project_id - ) - logger.info("재확정 체인 설계 이월: project_id=%s %d건", project_id, carried) # 4) B05 확정 → B06 확정(옛 표준단면 설정 이월, 미지정 측점 기본값 채움). # 재확정 후에도 stage 2·3은 IN_PROGRESS로 남겨 사용자 재검토를 받는다. @@ -510,6 +488,34 @@ async def run_redesign_chain( # 계획선을 앉히면 전부 어긋나고, 저장분은 노선 변경을 스스로 알지 못한다. await _prepare_drainage_pipes_and_reprofile(project_id, new_route_id, refresh=True) + # 5) 이제 측점이 새 노선 기준으로 다 섰다 — 옛 사용자 설계를 **누가거리로** 얹는다. + # 묶어 쓰므로 행 수와 무관하게 왕복 두 번이다(`merge_cross_section_designs`). + try: + entries = [ + (float(record["chainage_m"]), record["design"]) + for record in old_designs + if isinstance(record.get("design"), dict) + ] + async with pool.acquire() as connection: + await connection.begin() + try: + carried = await merge_cross_section_designs( + connection, + route_id=new_route_id, + entries=entries, + replace=True, + project_id=project_id, + ) + await connection.commit() + except Exception: + await connection.rollback() + raise + except Exception: + logger.exception( + "재확정 체인 — 옛 설계 이월 실패(계속 진행): project_id=%s", project_id + ) + logger.info("재확정 체인 설계 이월: project_id=%s %d건", project_id, carried) + old_options = ((old_longitudinal or {}).get("data") or {}).get("options") or {} section_request = ( SectionConfirmRequest(standard_cross_section=old_options["standard_cross_section"])