Commit Graph
50 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 dc52d55988 feat(B06): 구조물이 만든 폐회로로 절·성토 면적 산출
2026-09-06 사용자 확정 — 구조물 **자체 면적을 빼는 것이 아니라**, 지반선과 실제로
그려지는 설계선이 이루는 폐회로의 넓이다. 기존 계산은 표준 설계선만 보아 구조물이
있는지조차 몰랐다.

- 그리는 쪽이 이미 만든 트림(`designTrim`)을 그대로 받아 「실제로 그려지는 설계선」을
  세운다 — 트림 안쪽은 설계선, 바깥은 구조물 성토부선, 그것도 없으면 원지반(면적 0).
  그림과 면적이 같은 입력을 쓰므로 둘이 갈리지 않는다.
- 벽면은 **수직**이라 트림 경계 바로 바깥에 점을 하나 더 찍는다. 안 넣으면 사다리꼴이
  단차를 비스듬히 이어 붙여 없는 면적이 생겼다(실측 6.25㎡ → 7.5㎡).
- 절토는 암 경계선이 있으면 기존 규칙대로 토사/암으로 나눈다.
- 확인(node) — 전구간 100㎡ · 벽에서 끊음 6.25㎡ · 구조물선 포함 20㎡.

한계: 서버는 아직 구조물 기하를 몰라 이 보정이 **브라우저 계산에만** 실린다. 저장·확정
뒤 서버 재계산에서는 표준 값으로 돌아간다 — 서버 반영은 남은 작업(계획서 3-2).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 12:35:16 +09:00
eomsangdonandClaude Opus 5 2b18c1b535 feat(B06): 기슭막이 연동 해제 시 높이도 분리 — 푸는 순간 값을 굳힘
2026-09-06 사용자 지시. 연동 해제는 위치(4축)만 갈랐고 높이는 소유 측점 값을 계속
따라가, 소유 측점 높이를 바꾸면 푼 측점까지 같이 움직였다.

연동을 푸는 그 순간 화면에 그려진 벽 높이를 이 측점 조정값으로 굳힌다 — 값이 튀지
않으면서 이후에는 따로 논다. 이미 손댄 벽은 그대로 둔다. 단 수·형태는 소유 측점을
따르는 2026-08-30 확정을 그대로 지킨다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 12:09:21 +09:00
eomsangdonandClaude Opus 5 15c2d81b49 refactor(B06): 횡단 카드 껍데기·반폭 계산 분리 (700줄 제한)
`_UI_Cross_View` 784줄 → 698줄. 도면과 무관한 제목행·하단 정보행을 `_UI_Cross_Card_Chrome`
으로 옮기고, 실효 표시 반폭 계산은 순수 계산이라 `_UI_Cross_View_Metrics` 로, 측점별 줌·팬
상태 맵은 임자인 `_UI_Cross_View_Zoom` 으로 옮겼다. 계산·판정 규칙은 그대로다.

검증 — 공용 브라우저 B06 실측: 카드 65·제목행 65·하단행 65·단면유형 pill 65·사면 미교차
경고 13, 첫 카드 제목행 `0+0.0 / 0.0m / 토사·리핑암·발파암 / 편측 성토 / BP` 로 종전과 동일.
pytest 383 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:56:01 +09:00
eomsangdonandClaude Opus 5 23b1e7e5b0 feat(B05/B06): 옛 계획고 유토곡선 노출 차단 + 사면 미교차 측점 경고
① 저장된 횡단이 지금 계획선과 어긋나면(재계산 예약 상태) 유토곡선을 그리지 않고
「횡단을 지금 계획선에 맞춰 다시 계산하는 중입니다」만 띄움. 옛 계획고로 만든 면적이
2초간 보였다가 정본으로 갈아 끼워지던 것을 없앰(2026-09-03 사용자 확정 「새 값만
보여주기」). 용화 실측 — 65측점 중 56개가 낡음, 계획고 차 −9.36~+5.83m,
저장분 성토 42,050㎥ ↔ 정본 14,881㎥.

② 사면이 계산 반폭 끝까지 원지반과 만나지 않아 면적이 잘린 측점에 카드 경고 표기.
판정은 면적을 내는 엔진 한 곳(B06_Section_Engine_Design)에서 `slope_unclosed` 로
내려 화면·수량·도면이 같은 기준을 봄. 계산은 손대지 않음(2026-09-03 사용자 확정
「영원히 못 만나는 지형이 있을 수 있으니 경고로 대체」).

검증 — 공용 브라우저 B06 실측: 2.6초 재계산 안내만 표시(옛 값 미노출), 4.4초 정본
표시, 사면 미교차 경고 13/65측점. pytest 366 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 09:10:46 +09:00
eomsangdonandClaude Opus 5 8fa1652e62 feat(B06): 세월교 월류 전 노면 점선을 날개벽 상단까지 대각으로 잇는다
점선(월류가 없었을 때의 계획고)이 노견에서 뚝 끊겨, 구체 밖에서 노면이 어디로
떨어지는지 읽히지 않았다. 양 끝을 그 측 **날개벽 상단**까지 대각으로 내려 잇는다
(2026-08-30 사용자).

- `FordSideLayout.wingTop` — 바닥판 바깥 끝(계류측 극점) × 바닥판 상면 + 날개벽
  짧은쪽 높이. 날개벽 설치가 없으면 null이고, 그 측은 노견에서 끊는다.
- `appendFordSurfaceDropPlan`이 세월교 기하를 받아 한 폴리라인으로 그린다:
  좌 날개벽 상단 → 좌 노견 → 우 노견 → 우 날개벽 상단.

자체검증(공용 브라우저 5174 + 워크트리 백엔드 8001, 측점 7+9.7):
- tsc --noEmit 통과.
- 점선 폴리라인 4점 확인(수정 전 2점). 양 끝이 바닥판 바깥 상단 자리로 나간다.
- 날개벽 상단이 원래 계획고보다 21.70px 아래 = 0.890m (y축 1m = 24.375px).
  바닥판 상면~원래 계획고 1.89m − 날개 짧은쪽 높이 1.0m = 0.89m와 일치.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 13:12:23 +09:00
eomsangdonandClaude Opus 5 933f513da0 feat(B06): 세월교 노면을 월류 높이만큼 내려 앉힌다
횡단도에 그려지던 노면은 사실 월류부 가장 아래를 자른 자리다 — 구체 위 노면은
월류 높이만큼 낮게 앉아야 한다(2026-08-30 사용자 확정). 계획고를 통째로 내려
잡아 측벽·바닥판·십자선·절성토 면적이 한 번에 따라오게 했다. 전폭 평행 하강이라
횡단경사·측구·사면 규칙은 그대로다.

백엔드
- `_ford_set`이 `ford_height_m`을 `overflow_depth_m`으로 스펙에 싣는다.
- `compute_cross_design(surface_drop_m=)` — 계획고를 그만큼 내려 계산하고, 내린
  양을 `surface_drop_m`으로 echo한다(프론트가 점선을 되그리는 데 쓴다).
- `ford_surface_drops()`·`ford_drop_at()` — 관 지점 정본에서 측점별 하강량을 읽는다
  (포장 구간과 같은 방식). 설계 계산 경로 전부(기본값·재계산·프리뷰·종횡단 확정)에
  물렸다.
- `enforce_ford_surface_drops()` — 저장분이 옛 계획고면 상세 조회에서 다시 계산한다.
  월류 높이를 지우면 같은 경로로 원래 계획고로 되돌아온다.

프론트
- 십자선을 하강량만큼 내려 찍는다(`cardDesignElevation`). 종단 계획고를 그대로
  쓰던 자리다.
- `appendFordSurfaceDropPlan()` — "월류가 없었다면" 노면을 점선으로 남긴다.
  물넘이포장의 「기존 계획고 점선」과 같은 표기라 한 규칙으로 읽힌다.
- 측벽·바닥판은 내려간 설계선(`design_line`)에 그대로 붙으므로 따로 손대지 않았다.

자체검증(공용 브라우저 5174 + 워크트리 백엔드 8001, 측점 7+9.7, 월류 높이 0.39m):
- `tmp/tests/test_ford_surface_drop.py` 2건 통과 — 계획고·좌우 노견이 정확히
  0.39m 내려가고, 절토는 늘고 성토는 줄며, 하강이 없으면 `surface_drop_m` 키 자체가
  없다.
- 화면 실측: y축 눈금 1m = 24.375px에서 십자선이 점선보다 9.50px 아래
  (= 0.390m, 오차 0.001m). 수정 전에는 두 선이 같은 자리였다.
- 세월교 측벽 자동 높이 1.70m → 1.50m. 이론값 1.31m이나 하한(관경 1.0 + 최소 토피
  0.5 = 1.5m)에 걸린 값이다 — 기존 규칙 그대로다.
- 성토 면적 18.46 → 13.85 ㎡. 이웃 일반 측점에는 점선이 그려지지 않는다.
- 검증에 쓴 `pipe_points.json` 임시 옵션은 백업본으로 되돌렸다(정본 무변경).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 12:54:29 +09:00
eomsangdon 2e28af6e86 feat(B05,B06): 구조물 배치 컨테이너를 B06에 장착하고 [횡단 조정] 사본을 세운다
B05/B06 인터페이스 일원화 1차 (2026-08-29 사용자 확정 계획):
- A00_Common/b_structures_section.ts: B05 구조물 배치 폼·목록 공용 진입점
  (재수출 + 스타일 동봉)
- B06 좌측 패널에 [구조물 배치] 섹션 + 하단 dock [목록][구분선][저장버튼]
  (B05 동일 템플릿). 구조물 조작은 세션 pending으로 쌓여 기존
  flushPendingStructures([임시저장]·[확정])로 정본 반영
- 선택 연동: 목록·폼 → 최근접 카드 focusStation, 횡단도 벽·세월교·BOX →
  좌측 폼에 소유 측점 시설 로드(wireStructureSelection)
- [횡단 조정] 하위 컨테이너(Adjust_Dock): 오버레이 조정창을 같은 deps로
  사본 인스턴스 생성해 세움 — 로직 이동 0, 카드 재렌더로 자동 동기.
  9키·십자 행은 사본에서 숨김(사용자 지시 7), 방향키 이중 입력 방지
- A군 시설 추가·이동·삭제는 B06에서 안내 토스트(배수유역 체인은 B05 몫)

검증: 공용 브라우저 — 구간값 길이 사본 + 10.0→11.0m 양측 동기,
오버레이 - 원복, ✕ 닫기 시 사본 해제. B05 회귀 없음. typecheck 통과.
2026-08-29 14:20:49 +09:00
eomsangdonandClaude Opus 5 0d4e4c758d feat(B06,B05): 기슭막이 연동·경사를 재정의하고 링크 카드까지 강조한다
사용자 확정(2026-08-30) 세 가지를 반영한다.

① 링크 강조 — 한 기슭막이는 그 연장 안 모든 횡단도에서 같이 강조된다. 선택
(조정창)과 강조를 분리해 `highlightFor`/`applyRevetHighlight`로 카드 재생성 없이
클래스만 갈아 끼운다(줌·팬 보존). 다단은 단 번호까지 같은 키로 짝짓는다.

② 연동 = 분리가 아니다 — 길이·전/후로 이미 하나의 기슭막이다. 연동을 푼 측점은
그 자리에 서므로 3D에서 벽이 노선과 평행이 아니라 자기 경로선을 따라간다. 링마다
폴리곤을 갈아 끼워(`polygons`) 측점 사이를 Catmull-Rom으로 잇는다. 해제 시 단 수가
0이 되던 것(벽 4→2)도 고쳤다 — 소유 측점 4축에서 출발해 손댄 벽만 갈아 끼운다.

③ 경사 = 수평(Z 일원화) — 3D 링만 눕히던 것을 횡단도까지 넓혔다. 링크 카드 벽
상단 표고를 소유 측점과 맞추고(d = 소유 d + 1.2×dz) 차이는 노견 확장이 흡수한다.
그래서 수평 중에는 연동 해제 불가 — 버튼을 잠그고, 해제해 둔 값은 지운다.

곁다리: 3D 재빌드 해시에 extra_spans·revet_link_detached 추가(안 넣으면 저장
코리도가 안 만료된다), 캐시 저장 payload에 extra_spans 누락 보완, 3D 머리 주석을
"정본만 읽는다" → "캐시를 읽는다"로 정정.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 12:01:22 +09:00
eomsangdonandClaude Opus 5 35547e551d fix(B06): 유입측 다단의 좌우 조작 부호를 바로잡고 통나무·목재틀·바자 한계를 2m로 둔다
- outwardOf가 role === "inlet"만 유입측으로 봐서 유입측 다단(bextra)이 반대쪽
  부호로 움직였다. inletSideRole()로 bextra를 유입측에 포함한다
- revetHeightLimit: 통나무·목재틀·바자를 2.0m로 명시한다(종전에는 함수 기본값
  3.0으로 떨어졌다 — 2026-08-29 사용자 확정)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 10:27:32 +09:00
eomsangdonandClaude Opus 5 13dda88058 feat(B06): 기슭막이 조정창을 공용화하고 형태 선택지를 B05 폼과 맞춘다
조정창은 한 컴포넌트였지만 행 표시가 역할 키에 묶여 있어, 같은 성토 벽이라도
유입/유출에 따라 창 구성이 갈렸다. 재질 선택지도 3종뿐이라 B05 폼 형태 6종을
조정창에서 고를 수 없었다.

- 단 수 행을 하나로 합치고 자리를 높이 행 아래로 고정한다. 저장 채널(extra /
  bextra)은 선택된 벽이 정하고, 등간격(≡)은 유출 채널 전용으로 제한한다
- 형태 선택지를 B05 폼과 같은 6종(REVET_FORMS)으로 바꾼다. 조작값 m의 의미를
  재질 코드에서 형태 문자열로 바꾸고, 옛 저장분은 revetFormOf가 옮겨 읽는다
- 높이 한계는 revetHeightLimit(form), 돌 표현은 materialFromForm(form)으로
  형태에서 파생한다. 벽 제원 계산은 revetWallSpec()으로 모아 배관·독립·추가가
  같은 함수를 쓴다
- 조정창 행 라벨 "재질" → "형태"

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 09:54:17 +09:00
eomsangdon 5142bdde9b auto: 2026-08-29 09:04 (EOMSANGDON-HOME) 2026-08-29 09:04:58 +09:00
eomsangdonandClaude Opus 5 f916aa52a1 feat(B05,B06): 독립 기슭막이를 배수관 시설 종류로 이관
독립 기슭막이(구조물 정본 D군 구간형)를 배수관 측점(pipe_points)의 시설 종류
"revetment"로 옮긴다. 관을 숨긴(hidden_pipe) 배관 세트로 얹혀 컴퓨트·렌더·패널·
연동·경사·3D·수량이 배관 경로를 그대로 탄다.

- common_util_drainage_pipes: PIPE_FACILITY_REVET 추가, 여유고 0
- B06_Section_Engine_Culvert: _revet_set/_revet_side — 관 숨김 세트 생성
- B06_Section_Router: attach_revetments 제거(관 세트에 통합)
- B05_Profile_Engine_Sections: 기슭막이는 시작·기준·종료 세 측점 심기
- B05_Profile_Structure_Types.json: revetment placement=point, managed_by=pipe_points,
  설치 측에 "양쪽" 추가
- B05_Profile_UI_Drainage_Facility: 기슭막이 옵션 폼(설치 측·형태·높이·길이·전후·단 수)
- B06_Section_UI_Cross_Culvert_Geom: 관 숨김 시 관경 하한·역경사 클램프·유출 가드 해제
- B06_Section_UI_Cross_Culvert_Wire: restrictToSide — 설치 측(좌/우)만 남기기
- B06_Section_UI_Cross_View: 옛 D군 경로 이중그리기 가드, appliedAdjust 되받기
- B06_Section_UI_Cross_Wall: 기슭막이 벽 공용 기하·그리기 층 신설
- B05_Profile_UI_Corridor_Structures: 3D도 같은 규칙(관 실린더 숨김, 관통 컷 없음)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 19:09:28 +09:00
eomsangdonandClaude Opus 5 0050adf7d2 feat(B06): 독립 기슭막이 조정창 연결 + 초기화 세션·코리도 정리
백로그 3건(2026-08-28).

① 기슭막이 조정창 — 배관 세트와 같은 4축
   - RevetKey 에 "own" 추가. 조작값은 배관 벽과 같은 저장소를 쓴다
     (design.revet_adjust["own"] + 세션 b06:revetx:{project}:{route}).
   - 벽을 누르면 조정창이 열린다(활성 표시 포함). 좌우 ◀▶ · 사면 ▲▼ · 높이 ± ·
     자동 자리 초기화만 보이고 집수정·단 수·구간·연동·재질·등간격 행은 숨는다
     (재질은 구조물 옵션 형태가, 단 수는 단 수(다단)가 정본).
   - computeRevetmentLayout 이 x(좌우)·d(사면, +는 아래)·h(높이)를 반영하고
     3D도 같은 값을 읽는다(코리도 해시에 조작값 포함).

② 초기화가 프로젝트 단위 세션 값도 비운다 — b05:uphill / b06:std-cross.
   키에 route_id 가 없어 새 노선에 그대로 되붙던 값이다. 표준횡단 세션 정리는
   clearStandardCrossSession() 한 곳에서 한다.

③ 초기화가 주인 없는 코리도 파일을 지운다 — prune_corridor_files(비치명,
   삭제 개수 로그). 실측 배경: 유효 route 1개인데 19개(약 85MB)가 남아 있었다.

검증: pytest 245 passed / 7 skipped(코리도 정리 4건 신규). tsc·ruff·prettier 통과.
실측 — 315m 벽 클릭 시 조정창 제목 "기슭막이(독립)", 좌 1회·사면 아래 1회·
높이 +0.1 조작에 벽 좌표가 각각 이동하고 세션에
{"315.00:own":{"x":1,"d":1,"h":1.1}} 저장. 임시 구조물은 삭제하고 정본 복구.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 15:41:24 +09:00
eomsangdonandClaude Opus 5 e371c2754a feat(B05,B06): 물넘이 3D 파임 + 독립 기슭막이 횡단·3D + 포장 기본값·표준횡단 반영
2026-08-28 사용자 지시 4건.

① 물넘이 파임을 3D 코리도에도 반영
   classifyStation 이 노면·노견 조각 표고를 횡단도와 같은 산식(fordDeckElevationAt)
   으로 내린다. 노면 밖 비탈은 그대로라 노견 끝에 수직 단차가 선다. BUILD_VERSION 85.

② 표준횡단면 저장분을 포장 재계산에 싣는다
   확정 때 종단 정본 options 에 실린 standard_cross_section 을 읽어
   enforce_pavement_ranges / attach_default_designs 에 넘긴다. 없으면 config 기본값.

③ 포장 구간 기본값 10 / 5 / 5 (기슭막이와 같은 출발값).

④ 독립 기슭막이
   - 측점: is_station_planting_type() 규칙 신설(A군 + D군 구간형). 구간형은
     시작·기준·종료에 측점을 심는다 — 길이가 길수록 횡단도가 여러 장 나온다.
     구조물 재이관 차단도 같은 규칙을 본다(기타 고스트 방지).
   - 서버: B06_Section_Engine_Revetment 신설 — 구간 안 측점 전부에 section.revetment.
   - 횡단도: B06_Section_UI_Cross_Revetment 신설 — 벽 상단 = 성토면 끝(설계선-지반
     교차점), 아래로 높이 + 근입 0.5m, 전면 1:0.3(교본 7-3). 설치 측은 사용자가
     좌/우로 고른다(레지스트리 side 옵션 신설 — 자동 판정 없음).
   - 3D: 같은 폴리곤을 기준측점 전/후만큼 스윕. BUILD_VERSION 86 + 구조물 해시에
     물넘이·기슭막이 제원 추가.

검증: pytest 241 passed / 7 skipped(신규 4건). 공용 브라우저 실측 —
물넘이 240m 투입 시 3D 노면이 계획고보다 0.38~0.42m 아래(대조군 200m 정상),
기슭막이 225~255 투입 시 측점 23→25·횡단 카드 3장·3D revet 솔리드 3개(31링).
임시 데이터는 원래 정본으로 복구했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 12:54:45 +09:00
eomsangdonandClaude Opus 5 80c2a265f9 feat(B05,B06): 물넘이 횡단 표현 + 포장 구간 수기 지정, 경사 자동 포장 폐지
2026-08-28 사용자 확정 스펙.

물넘이포장 — 노면을 판 자리로 그린다
- 서버가 _ford_pavement_set(월류 폭·월류 높이·바닥 경사)을 만들고 물넘이만
  span 연동을 켜 **범위 안 측점 전부**에 얹는다. 깊이가 없으면 None으로 두어
  화면이 그리지 않는다(수치를 지어내지 않는다).
- 횡단도: 기존 계획고 점선 + 물넘이 바닥 실선 + 진한 회색 빗금 포장.
  깊이는 노선 중심 기준, 바닥은 유입(상단측)이 높게 기운다. 경사를 비우면
  그 측점의 노면 횡단경사를 쓴다.
- 물넘이 폼에 "바닥 경사 유입→유출(%)" 칸을 추가하고, 월류 폭 기본값
  리터럴을 config_frontend 상수로 모아 서버 값과 짝지었다.

포장 — 사용자가 구간으로 지정한다
- 구조물 레지스트리 G군 pavement_concrete 를 되살려 기준측점 + 길이 + 전/후로
  받는다(기슭막이와 같은 폼). 길이 기본값은 0 = 미지정.
- pavement_ranges/paved_at 이 구간을 판정하고, enforce_pavement_ranges 가
  저장분이 비포장이어도 구간 안이면 포장으로 다시 계산한다(사용자 조작값 승계).
- **종단경사 자동 포장 적용을 없앴다** — paved=suggested 3곳 제거. 별표1-2 상한
  초과 경고(pavement_suggested 배지·근거 문구)는 그대로 남는다.
- 포장 구간이 물넘이를 통째로 품으면 모달로 알리고 앞/뒤로 나눠 저장하고,
  끝만 걸치면 값을 고치라고 안내하고 멈춘다.

700줄 제한: _compute_default_designs 를 Router_Design 으로 옮겼다(657/306줄).

검증: pytest 238 passed / 7 skipped(신규 9건). 공용 브라우저 실측 — 물넘이 임시
투입 시 240m 카드에만 파임 3요소가 그려지고(일반 포장 박스 0), 바닥이 계획고보다
0.4m 아래·노면 전폭 4.0m에 1.5% 기울기, 220·260은 비포장 유지. 겹침 규칙은
브라우저에서 모듈을 직접 불러 3분할·안내·취소를 확인했다. 실측용 임시 관 지점은
매번 원래 정본 4건으로 복구했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 12:16:38 +09:00
eomsangdonandClaude Opus 5 a87182496e feat(B06·B05): BOX암거 조정창 · 구체 기울기 · 3D 벽 구간 정리
조정창에서 좌·우 끝을 따로 잡는다 — ◀▶는 구체 길이, ▲▼는 그 끝의 구체 표고를
0.1m씩 움직인다. 좌·우 표고가 달라지면 구체가 기울고, 날개벽 구간 바닥(에이프런)은
각 끝 표고에서 수평을 지킨다(2026-08-25 사용자).

- `computeBoxLayout`이 좌·우를 따로 푼다: 끝 표고·길이·성토선·에이프런
- 성토선은 그쪽 표고 기준으로 물매 1:1.2를 지키므로 표고를 내리면 구체가 길어진다
- 조정창 `_Cross_Box_Panel.ts` + 제어 `createBoxControls` + `design.box_adjust` 저장
  (세션 → 캐시 → 확정 payload, 세월교와 같은 체계)
- 3D: 구체 밖(날개벽 구간)에 서 있던 벽을 없앴다 — 천장 없는 통로가 생기던 자리는
  날개벽 몫이다. 이제 상판·구체 저판·측벽 2매·에이프런 2매 + 날개벽 4매로 나뉜다
- 카드 렌더러의 구체 배선(선택 토글·강조·조정창)을 `_Cross_View_Bodies.ts`로 분리,
  연동 플래그 세션은 `_Page_Link_Session.ts`로 분리(700줄 제한)

검증(10+0.9): 구체 5.34m·수평 → ◀ 1회 5.44m → ▼ 2회 표고 −0.2m·물매 1:28.4,
에이프런 두 장 모두 수평 유지, ↺ 원복. 3D 솔리드 10개(측벽 링 0.2m).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 15:03:53 +09:00
eomsangdonandClaude Opus 5 55e97b8925 fix(B06): BOX암거 성토선 추가 — 박스 최상단을 지나고 노견은 수평 연장
박스 위 성토선이 빠져 있었다. 물매 1:1.2를 고정하고 성토선이 **박스 최상단
모서리**를 지나게 하면, 박스를 길게 잡을수록 노견이 저절로 수평 연장되고 각도는
그대로다(기슭막이 "벽이 밖으로 나간 만큼 노폭 연장"과 같은 규칙, 2026-08-25 사용자).

- 구체 길이 = 노폭 + 2 × (노면 − 박스 상단) × 1.2. 노면이 크라운이라 좌·우 필요량이
  다르므로 큰 쪽에 맞춰 대칭으로 잡고, 남는 쪽은 노견을 수평 연장한다
- 성토선 = 노견 → (수평 연장) → 박스 최상단 모서리 → 1:1.2로 원지반까지
- 노견 밖 설계선은 이 성토선이 대신하므로 다시 트림한다

검증(10+0.9): 구체 ±2.744m, 저판 8.32m, 좌 성토선 물매 1.200·1.200,
우 성토선 수평 0.144m 뒤 1.200·1.200.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:52:40 +09:00
eomsangdonandClaude Opus 5 d4c8de738a feat(B05·B06): BOX암거 횡단도 · 3D 중공 셸·날개벽·관통 보어
BOX암거를 세월교와 같은 계류 방향 절단면으로 그리고, 3D는 속이 빈 서피스 셸로
만든다. 관통 컷·중공 튜브는 배수관 세트와 세월교에도 함께 적용한다.

B06 횡단도
- `_box_set()` — 내공 폭·높이(B05 옵션), 부재 두께 세월교 승계(측벽 0.2·상하판 0.3),
  복토 0.5m(별표2 교차 참조), 날개벽 투영 저판 연장
- 상판 윗면 = 노면 − 복토, 구체는 수평 설치(교본 3장). 계류 하상과의 고저차는 툴팁 표기
- 구체가 노면 아래 묻히므로 계획선은 자르지 않는다(세월교와 다른 점)

3D
- 로프트가 **링별 폴리곤**을 받는다 — 구조물을 위·아래 조각으로 갈라 링마다 틈을
  벌려 빈 공간을 만든다. 틈 0이면 속 찬 단면 그대로라 토폴로지가 유지된다
- BOX = 내공 구간만 틈을 벌려 측벽이 저절로 생기는 셸 + 날개벽 4매(날개 축 프레임)
- 관통 보어 = 링 y에서 틈 높이 2·√(r²−(y−y₀)²) → 배관 외측 기준 원형 구멍.
  기슭막이·집수정·세월교 측벽에 적용
- 배관은 중공 튜브(바깥·안쪽 원통 + 양 끝 고리)로 내부 유로를 보인다

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:45:32 +09:00
eomsangdonandClaude Opus 5 81bb505cc4 feat(B05·B06): 세월교 횡단 구체·조정창·3D 예상형상
B05 세월교 옵션에 BOX암거 날개벽 한 벌(설치·짧은쪽 높이 1m·길이 2m·각도 45°)을
그대로 붙이고, B06 횡단도에 세월교 구체를 그린다. 구체는 양측 ㄴ형 집수정 측벽 +
그 사이를 잇는 바닥판 + 바닥판 상면에 안힌 관 + 관 위 성토(노체) 채움이다.

- 바닥판 편측 연장 = 날개벽 길이 × cos(각도) — 각도는 관축 기준 벌어짐각
- 측벽은 buildBasin 재사용이라 1:0.3 기움·좌우·상하 대각 이동·계류측 성토부선이
  집수정과 같은 규칙으로 따라온다 (기슭막이 다단·재질과는 연계하지 않음)
- 구체는 월류 폭만큼 도로 방향으로 이어져 기준 측점 전후 절반까지 붙는다
- 조정창: 측벽 높이·좌우·상하, 관경·수량(정본 pipe_points 되쓰기).
  높이·좌우·상하는 세션 + design.ford_adjust에 저장
- 3D 예상형상: 구체 부재는 월류 폭 구간 스윕, 관은 련수만큼 폭 안 등간격
- 부재 두께: 바닥판 0.3m(교본 물넘이 물받이 최소 30cm), 측벽 0.2m(집수정 승계)

700줄 제한으로 카드 렌더러·측점 제어기·페이지에서 배선을 분리했다
(_Cross_View_Ford, _Page_Ford_Controls, _Page_Patches, Culvert_Const 구간값 헬퍼).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:05:42 +09:00
eomsangdonandClaude Opus 5 cd8d14f105 feat(B05·B06): 기슭막이 구간값 조정창 · 연동 기슭막이 옵션 · 가림 구간 선 정리
기슭막이 범위(길이·기준측점 전/후)를 B06 횡단도 조정창에서 지정하게 하고, 그
범위가 덮는 옆 측점의 기슭막이를 "연동" 파생물로 다루도록 체계를 세웠다.
값의 원천은 배수관 옵션(pipe_points) 하나다 — 같은 숫자를 B06 정본에 따로 담으면
B05 배수관 카드와 갈려 어느 쪽이 참인지 알 수 없다.

① 집수정 전/후 필드 신설 — inlet_basin_before_m·after_m(기본 각 1m), 길이 2m 유지.
   종방향 구간 계산을 revetSpanOfSpec·basinSpanOfSpec 한 곳으로 모아 2D 링크 판정과
   3D 스윕이 같은 값을 쓰게 했다.
② B06 조정창에 길이·전·후 행 — 기슭막이(유입·유출)·집수정 모두. 캐시를 고쳐 즉시
   보여주고 저장은 조작이 멎으면 한 번만 나간다(세부유역 재계산이 매번 돌지 않게).
   길이를 바꾸면 늘어난 몫만 지금 비율대로 나눠 담는다 — 총길이에서 비율로 다시
   계산하면 0.1m 반올림이 쌓여 5.0/5.0이 5.6/5.4로 어긋난다.
③ 링크 카드 선택 허용 — "소유 측점 통째 복사"에서 "위치 4축만 물려받고 원지반
   접합은 이 측점 지형으로 재계산"으로 바꿨다. 구조물 형식은 언제나 소유 측점 값이다.
   손대기 전에도 어긋나지 않게 소유 측점이 실제로 적용한 4축(revetShift)을 명시값으로
   물려준다.
④ 연동(측점별)·경사(전체 공통) 토글 — 연동 조작은 소유 측점 키에 실리고 그 연장이
   덮는 측점을 함께 다시 그린다. 경사는 3D 전용 스위치다(끄면 스윕 프레임 dz=0).
   횡단도까지 -dz로 밀면 노견에서 출발하는 성토선까지 내려가 노견과 벌어진다.
⑤ 가림 구간 선 정리 — 유입부 접속선과 유출부 접지 후 절토선을 2D·3D 모두에서
   빼되 기하는 남긴다. 면적·수량 계산은 건드리지 않았다(전면 개편 대상).
⑥ 집수정은 소유 측점 횡단도 하나에만 — 링크 카드에서 집수정·계류측 다단을 뺀다.
⑦ 3D 구간 겹침 정리 — 측점 간격이 구조물 연장보다 좁으면 두 구간 제어점이 번갈아
   서서 짧은 쪽(집수정 2m)이 잘려 보였다. 두 소유 측점의 중간에서 끊는다.
⑧ 조정창 정리 — 십자·9키를 맨 아래로, 창을 위쪽 기준 오버레이로(낮은 횡단도에서
   제목이 잘리던 문제), 연동·경사를 1행 토글 버튼으로, 스크롤 자리 유지.

파일 분리: B06_Section_UI_Cross_View_Structure.ts(조정창 배선),
B06_Section_Api_Culvert_Options.ts(구간값 저장) — 700줄 제한.
BUILD_VERSION 14 → 17(저장 코리도 만료).
tsc/ruff/prettier 통과, pytest 196 passed(기존 실패 1건 유지).
작업이력·자체검증 기록: docs/raw/PLAN.md §4-9.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 19:26:35 +09:00
eomsangdonandClaude Opus 5 83eb58a251 feat(B05·B06): 배수관 측점 정본화 · 코리도 단차 제거 · 인접 측점 기슭막이 링크
3D 예상형상은 종단·횡단 확정 뒤의 최종 산출물이고 3D 쪽 편집 경로는 없다
(2026-08-24 사용자 확정). 그런데 구조물(비정규) 측점은 횡단 정본 자체가 없어
조회할 때마다 프리뷰 기본값이 재계산됐고, 조정창 조작값은 세션에서 사라졌다.
정본 경로를 열고, 그 위에서 코리도 단차를 걷어냈다.

① 구조물 측점 정본화 — 확정·임시저장이 종단 정본 stations 중 DB 행이 없는
   측점을 대상에 넣어 upsert. cross_sections 19 → 23행.
② 조정창 조작값 정본화 — 기슭막이 4축(x·d·h·m)·다단 단 수를 design.revet_adjust
   / extra_wall_counts로 저장하고, 3D culvertLayoutOf가 그 값을 기하 입력으로 쓴다.
   카드 우선순위는 세션 → 정본 → 자동.
③ 노폭 연장의 노견 편입 — PIECE_COLS.shoulder 2→3으로 원 노견 끝 꺾임을 남기고,
   조기 return을 없애 확폭이 구조물 구간 내내 유지되게 했다.
④ 종단 기울기 반영 — 구조물 구간 복사 단면에 계획고 차이를 전량 얹는다.
   노견 표고 단차 0.49~0.61m 제거.
⑤ 접속 테이퍼 — 구간 경계를 제어점으로 세워 "복사 vs 보간" 두 규칙을 하나로
   통합. 노폭 3.0m·성토비탈 8.1m 단차 제거. 접속 길이 = 인접 측점까지.
   제어점 생성은 B05_Profile_UI_Corridor_Frames.ts로 분리(Build 699 → 635줄).
⑥ 인접 측점 링크 — 기슭막이 연장(기본 10m)이 덮는 옆 측점 횡단도에도 소유 측점
   단면을 계획고 차이만 얹어 그린다. 요소별 연장 판정(관·집수정 제외), 표시 전용.

BUILD_VERSION 11 → 14 (저장 코리도 만료).
tsc/ruff/prettier 통과, pytest 192 passed (기존 실패 1건 유지).
작업이력·자체검증 기록: docs/raw/PLAN.md §4-8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 17:11:21 +09:00
eomsangdonandClaude Fable 5 5371534fc3 feat(B06): 기슭막이 높이·자리 체계 개편 + 조정창 방향키 조작
- 조정창 십자 키패드 키보드 방향키 조작(집수정 9키는 십자 축만)
- 배관 기슭막이 높이 = 순수 높이(바닥~상단), 하한·기본 = 관경+1.0m (고정 2.0m 폐기)
- 매몰 시 전면 발끝 지반 추적 바닥 심화 삭제 — 바닥 = invert-0.5 고정
- 상하(d) 0점 = 성토선 0 지점(벽 상단=노견), 기본 자리 = 성토사면 경사길이 4m 지점
  (d=null 자동, 저장·표시·정수맞춤 pinned 판정 연동, 구세션 d=0 호환)
- 유입 접속 절토선: 지반 교차 없으면 1m 공간 확보에서 끝
- 자동 집수정 기본 형상 L형 -> I형 (선택지 밖 구조물 그려지던 불일치)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 20:34:30 +09:00
eomsangdonandClaude Opus 5 eb41202bf4 fix(B06): 교차점 자동 줌아웃이 5m 사면 규칙에 잘리던 문제
자동 줌아웃 판정이 배수관용 slopeToeOffset(성토사면 5m에서 컷오프)을 써서, 사면이
5m를 넘는 측점은 필요 폭을 과소 산정했고 교차점이 화면 밖에 남았다(2026-08-23
사용자 보고).

- _UI_Cross_Fit 재작성: 설계선(design_line)과 지반선의 **실제 교차점**을 0.1m
  간격으로 훑어 찾는다(노면·노견·측구 구간은 건너뜀). 설계선이 만나기 전에 끝나면
  끝단 기울기 차로 외삽하고 1m 올림.
- 카드 자동 줌아웃(effectiveHalfWidth)이 이 값을 쓴다. 보유 샘플 밖으로는 넓히지
  않는다(지반이 없어 빈 화면이 될 뿐).
- [적용]은 전 측점 중 필요한 최대 폭까지 함께 넓힌다 — 20m를 넘으면 그 값으로
  재생성해 각 카드가 자동 줌아웃할 지반을 확보한다.

자체검증: node tmp/tests/test_toe_extrapolate.mjs (사면 18m 교차점을 5m 컷오프
없이 탐색, 설계선이 15m에서 끊겨도 외삽으로 같은 자리), tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:54:38 +09:00
eomsangdonandClaude Opus 5 5ac61cb4cc fix(B06): ⤢(오토핏) 기본값을 전역 횡단 반폭 보기값으로
⤢가 항상 교차점 맞춤 폭으로 가서 전역 보기값보다 좁아지기도 했다. 이제 초기화는
전역 보기값이 기본이고, 그 폭에서 절·성토선과 원지반 교차점이 안 보이는 측점만
교차점이 보이는 폭(그 측점의 기본값)으로 되돌린다(2026-08-23 사용자 지시).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:34:50 +09:00
eomsangdonandClaude Opus 5 ea29cc2e59 feat(B06): 확대 상태 팬으로 캐시 보유 범위까지 열람
- 도형(지반선·면적 밴드·설계선·암 경계선)을 표시 반폭으로 자르지 않고 **캐시 보유
  전 구간**으로 그린다. 표시 반폭 밖은 기존 clip이 가리므로 원배율 화면은 그대로다.
- 팬 한계(clampPan)를 그려진 범위까지 확장 — 배율 1에서는 종전대로 이동 0으로 묶고,
  확대 상태에서만 캐시 끝까지 가운데 버튼 드래그로 끌어다 볼 수 있다.
- 축 눈금은 팬 상태를 역산해 다시 그리므로(_UI_Cross_Axes) X·Y 값이 따라 움직인다.

자체검증: node tmp/tests/test_cross_pan_bounds.mjs (배율 1 고정, 2배에서 좌우 한계가
캐시 끝과 일치, 범위 밖 이탈 없음, content 없을 때 옛 규칙 유지),
test_cross_axes_zoom.mjs 재실행, tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:24:23 +09:00
eomsangdonandClaude Opus 5 0d80d03b96 fix(B06): 횡단 줌·팬에 X·Y 축 눈금 동기화
도형만 transform으로 확대되고 축은 고정이라 확대·이동 후 눈금값이 실제 위치와
어긋났다(2026-08-23 사용자 보고). 축·격자를 별도 레이어(_UI_Cross_Axes)로 옮기고
줌·팬 상태가 바뀔 때마다 보이는 범위를 역산해 다시 그린다.

- 눈금 개수·간격도 그때 보이는 범위로 다시 고른다(1·2·5 계열, X 목표 7·Y 목표 10,
  라벨 겹침 하한 X 48px·Y 14px). 확대할수록 촘촘·소수 단위로 자동 전환.
- X 눈금이 7등분 고정(비정수 간격)이던 것도 같은 규칙으로 정리.
- Cross_View는 축 코드가 빠져 622줄.

자체검증: node tmp/tests/test_cross_axes_zoom.mjs (원배율·4배 확대에서 눈금이
플롯 안에 있고, 같은 offset의 도형 자리와 눈금 자리가 일치), tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:20:22 +09:00
eomsangdonandClaude Opus 5 f2ad5508f5 feat(B06): 횡단 줌 조작 일원화 + 교차점 맞춤 자동 확대
- 카드 하단 ◀/▶/↺(개별 표시 반폭) 삭제. 조작구는 우측 상단 줌 버튼 하나로.
- 줌 버튼 역할 확장(원배율에서만 반폭 조작):
  − 배율>1이면 축소, 원배율이면 표시 반폭 +1m
  + 배율>1이면 확대, 원배율이면 표시 반폭 −1m(하한 2m)
  ⤢ 배율 원복 + 절·성토 교차점이 다 보이는 폭으로 맞춤
- 교차점 맞춤(_UI_Cross_Fit): 보유 샘플(계산 반폭 20m) 안에서 교차점을 찾고,
  샘플 끝까지 안 만나면 끝단 사면·지반 기울기 차로 만나는 자리를 추세 외삽해
  올림 +1m을 요청 반폭으로 쓴다(상한 60m).
- 요청 반폭 > 보유 샘플이면 그 폭으로 재생성(regenerate) 후 해당 측점만 세션
  반폭으로 넓게 표시. 계산 기본 20m·캐시는 그대로, 확정 시 기존 경로대로
  display_half_width_m에 영구 저장.
- 재생성 로직을 _UI_Page_Common.createSampleWidener로 분리(700줄 제한),
  [전체 측점 반영]도 같은 경로 사용. 연타 중복 요청 차단.

자체검증: node tmp/tests/test_toe_extrapolate.mjs (외삽 좌/우·발산 지형·+1m 올림),
tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 18:16:31 +09:00
eomsangdonandClaude Opus 5 ec514a4560 fix(B06): 횡단 Y축 눈금이 X축 아래로 삐져나오던 문제
눈금 범위를 elevationMid 중심(±displaySpan/2)으로 잡아, displayMax에 들어간
면적표 여유(AREA_OVERLAY_HEADROOM_PX/2)만큼 아래로 밀려 최하단 격자선·라벨이
X축 라벨 줄 아래에 그려졌다. 범위를 실제 표시 상·하단(displayMax 기준)에서
역산해 플롯 안에만 눈금이 오게 한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 17:53:52 +09:00
eomsangdonandClaude Opus 5 c10fb3400e fix(B06): 횡단면도 Y축 눈금도 정수·1·2·5 계열로 정의
- 5등분 고정(소수 표기) → 종단면도와 같은 niceTickStep 규칙 적용.
- niceTickStep을 _UI_Section_Common으로 옮겨 종·횡단이 공유(정의 한 곳).
- 횡단은 카드 높이가 낮아 라벨 간격 하한 14px(종단 16px)로 개수 상한 산정.
- 횡단 표고 여유는 기존 crossPlotMetrics의 8% 패딩 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 17:51:38 +09:00
eomsangdonandClaude Opus 5 917cdce5df feat(B06): 집수정 9키 조작 · 좌우 화면 기준 통일 · 계류측 성토부 체계 도입
① 집수정 조작을 9키(3×3)로 — 십자 축은 이동(◀▶ 좌우 / ▲▼ 사면 대각),
   네 모서리는 크기(⇕ 내부 높이 · ⇔ 내부 폭), 가운데는 초기화. 기슭막이
   십자와 같은 축 규칙·버튼 크기라 행열이 맞는다. I형은 내공 개념이 없어
   네 모서리만 숨긴다.
② 좌우 반전 해소 — 집수정 lateralM이 계류측(outward) 기준값에 그대로 묶여
   유입이 우측인 측점에서 ◀가 화면 오른쪽으로 갔다. 버튼을 **화면 기준**으로
   받아 카드가 부호를 환산한다. 노견 안쪽(음수)은 0에서 멈추고 토스트로 알린다.
③ 집수정 계류측에 **유출측과 같은 성토부 체계** 적용(ㄴ·ㄷ형) — 구조물 계류측
   끝이 원지반 위로 나오면 1:1.2 성토부선을 긋고, 5m를 넘으면 다단 기슭막이를
   둘 수 있다(키 , 단 수 행 별도). 원지반 안이면 종전 절토선,
   I형은 관 하단 3도 되메움선이 맡는다. 좌우 이동 시 마감선을 억제하던 임시
   조건은 제거했다(급경사 선의 근본 원인은 이미 설계선 트림에서 해결).
- 700줄 유지: attachBasin(Basin)·buildExtrasAt(Extra) 추출 + 주석 정리

검증: 4+4.3 ㄴ형 좌우 2m — 성토부선 2.41m가 원지반에 0.001m 오차로 접함
(종전 마감선 없음) · ◀ 클릭 시 4+4.3(유입 좌)·13+15.7(유입 우) 모두 화면
왼쪽으로 이동 · 9키 3×3 좌표 정렬 확인 · tsc·ruff·prettier 통과 ·
pytest 148 passed, 7 skipped · B06_Section 700줄 초과 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 18:59:09 +09:00
eomsangdonandClaude Opus 5 2a247184fd feat(B06): 집수정 좌우·상하 이동 및 내공 조정 + 설계선 스냅 급경사 제거
- 집수정 조정값(BasinAdjust: 내공 폭·높이, 좌우 lateralM, 상하 slopeM) 신설.
  측점별 세션 보관 + 백엔드 design.basin_adjust 저장 경로(Schema·Router) 연동
- 조정창에 집수정 조정 항목 추가, I형 관 시작점을 벽 안쪽 변과 원지반의
  교차점으로 산출(이분법), 집수정 성토(되메움)선 5° → 성토 비탈 1:1.2로 통일
- 설계선 트림 수정: 배수관 레이아웃이 사면 폴리라인을 준 쪽은 그 시작점(노견)에서
  설계선을 끊는다 — 종전에는 트림 경계에서 끝점 표고를 벽 상단으로 강제 스냅해
  집수정을 좌우로 옮기면 마지막 구간이 수직으로 튀는 선이 남았다(사용자 지적)
- basinApproachPoints의 길이 0 중복 꼭짓점 제거

검증: 4+4.3(집수정 I형 좌우 2.9m 이동)·13+15.7·5+0.0·2+0.0에서 급경사
세그먼트 0건 · tsc --noEmit 통과 · ruff check 통과 · prettier 적용 ·
pytest tmp/tests/ 148 passed, 7 skipped · B06_Section 700줄 초과 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 17:50:45 +09:00
eomsangdonandClaude Opus 5 e54da341ea refactor(B06): 700줄 초과 파일 분리 — Router·Cross_View·Section_View·Style
- B06_Section_Router.py(824) → Router_Design.py(139) 분리
- Cross_View → Cross_View_Metrics.ts(75) 분리
- Cross_Design → Cross_Design_Surface.ts(54) 분리
- Section_View → Section_View_Panel.ts(53) 분리
- Page → Page_Common.ts(15) 분리
- Style_Cross.css → Style_Cross_Controls.css(174) 분리
- B06_Section/ 전체 700줄 초과 0건

검증: tsc --noEmit 통과 · ruff check 통과(import 정렬·포맷 적용) ·
prettier 적용 · pytest tmp/tests/ 148 passed, 7 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 17:04:08 +09:00
eomsangdonandClaude Opus 5 7cbfa475a6 fix(B06): 유입 하강을 유출 수용 가능 여부로 제한 + 계산은 전체 샘플 사용
- 유입이 유출보다 높아야 하므로 유입을 내리면 유출도 따라 내려간다. 유출이
  원지반에 묻히고 3도 절토선이 지반과 다시 못 만나는 높이면 **유입도 그만큼
  못 내려간다**(placeInletWall의 outletGuard, 아래 방향만 되돌림)
- 횡단 카드의 배수관 기하 계산 입력을 표시 반폭으로 자른 샘플 → **전체 샘플**로
  변경(2026-08-22 사용자 확정: 표시 반폭은 보기용, 계산은 계산용 전 구간)
- 유입 배치 로직을 placeInletWall(Solve)로 이전

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 16:00:40 +09:00
eomsangdonandClaude Opus 5 8be67485be style(B06): Cross_View 주석 정리 — 700줄 제한 준수
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 15:44:58 +09:00
eomsangdonandClaude Opus 5 cd855e32d3 feat(B06): 관 접속 절·성토선 3도 물매 + 교차점 보간 + 절성토 교차 기준 자동 줌아웃
- 관 유도 접속선을 0도 → **3도**로: 유입측은 계류 쪽 오름(물이 관으로),
  유출측 매몰 절토선은 계류 쪽 내림(물이 밖으로). 집수정 I형 되메움선도 동일
- 모든 유도선·성토부선 끝점을 격자점이 아니라 **선형 보간 교차점**에 붙여
  선이 원지반을 미세하게 벗어나던 문제 해소(2026-08-22 사용자 지적)
- 카드 자동 줌아웃: **구조물 없는 상태**의 설계 절·성토선이 원지반과 만나는
  지점(+0.5m)이 표시 반폭 밖이면 그 카드만 반폭을 넓혀 그린다. 보유 샘플
  범위를 넘는 경우는 기존 전역 반폭 재생성 경로(applyPanelToAll)가 담당

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 15:44:10 +09:00
eomsangdonandClaude Opus 5 de78feabde feat(B06): 다단 등간격 배치 버튼 + 유입 0도 접속선 + 유출 매몰 절토선·이동 금지
① 십자 우측 하단 ≡ 버튼 — 벽 사이 사면 구간을 같게 재배치(끝 성토부는 지형
   결정값이라 제외). 다단 연쇄(아랫단 바닥 하강) 때문에 1회 분할이 아니라
   구간 오차를 d로 되먹임하는 수렴 반복(≤8회, 허용 0.05m)으로 푼다.
② 유입 기슭막이 관 시작 접속선: 관 하단점이 원지반보다 위면 0도 성토선
   (지반 교차에서 정지), 아래면 0도 1m 후 표준 절토 경사(1:n)로 지반까지.
③ 유출 마지막 구조물 시작점이 원지반에 묻히면 0도 절토선을 지반 교차까지
   연장, 교차가 없는 자리는 이동 금지(배관 벽·추가 벽 공통 클램프).
- 배관 벽 4축 배치를 placePipeWall(Solve)로 추출 — Geom 700줄 유지

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 15:29:43 +09:00
eomsangdonandClaude Opus 5 97bf00a8ef fix(B06): 유출 관 끝점·전면 근입 기준 + 줌 유지·조정창 레이아웃 정리
- 유출 관 하단 끝점 = 벽 바닥 +0.5m 기준선과 전면 경사선(1:0.3)의 교차점
  (성토부선 시작점과 동일 자리) — 정수 맞춤 재배치에도 동일 적용
- 근입 0.5m는 경사선(전면) 측 깊이 기준 — 전면 발끝 지반 아래 0.5까지
  수렴 반복으로 내림(배관 벽·추가 벽 공통, 뜬 벽은 기준선 아래 0.5)
- 카드 내부 조작(조정창 등)으로 다시 그려져도 줌·팬 배율 유지
  (측점별 상태 보관, ZoomPanState)
- 조정창: 재질 행을 높이 행 위 별도 행으로(폭 축소 — 한계는 툴팁),
  추가 기슭막이(단) 행은 유출 벽에서 항상 표시(레이아웃 널뜀 방지)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 14:32:30 +09:00
eomsangdonandClaude Opus 5 ff3e3b734b feat(B06): 기슭막이 4축 조작 — 좌우(노견 연장)·상하(사면 대각)·높이·재질
- 좌우 ◀▶ = 노견(추가 벽은 윗단 0.5m 기준선) 수평 연장 평행이동 —
  성토선 물매 1:1.2·상단 표고 불변, 지반에 못 닿으면 바닥 뜸 허용
- 상하 ▲▼ = 성토선을 타는 대각 이동(수평 성분 1m), 위 한계 =
  최소 성토고·토피(역경사), 추가 벽은 윗단 하단 관통 금지
- 높이 ±0.1m: 배관 벽 2.0~재질한계(기본 2.5, 메쌓기면 2.0로 절삭),
  일반 벽 0.5~재질한계(기본 1.5). 높이 기준 = 근입 0.5 위 기준선~상단
- 재질 선택(메쌓기 2.0/찰쌓기 3.0/콘크리트 5.0m) — 한계 초과 시
  토스트로 재질 변경 안내, 자동 높이는 기본값 고정(사용자 확정)
- 다단 단 수: 숫자 입력 + +/- 버튼 병행, 입력기 스피너 제거
- 저장 스키마: revetx 값이 {x,d,h,m} 객체로 확장(구 숫자 형식 호환)
- 인터페이스 3종을 Wire로 이전(Cross_View 700줄 제한)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 14:21:30 +09:00
eomsangdonandClaude Opus 5 8167dd23c3 feat(B06): 다단 기슭막이 규칙 재정립 — 정확한 1:1.2·매몰 종단·단 수 입력
- 벽 사이 성토사면 = 정확히 1:1.2 — 벽 높이를 자리에서 역산(닫힌식),
  0.1m 눈금 올림 제거(물매 정확 유지 우선)
- 아랫단 상단은 윗단 하단(수평 기초) 관통 금지 — 안쪽 이동 한계
- 다음 단 성토선 시작 = 윗단 하단 +0.5m 수평선 × 전면 경사선(1:0.3) 교차점
  (배관 벽의 관 하단 꼭짓점과 같은 자리)
- 시작점이 원지반 아래(벽 0.5m 이상 매몰)면 성토 불필요 — 다단 종료
- 추가 방식 = 유출 벽 조정창의 단 수 숫자 입력(+/- 버튼 대체),
  지형 허용 단 수 초과 시 토스트로 가능한 단 수 안내 후 되는 만큼만 반영

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 13:39:21 +09:00
eomsangdonandClaude Opus 5 9a58e3b1bd feat(B06): 유출부 보호공 삭제·성토부선 전환 + 추가 기슭막이(계단식)
- 보호공(돌붙임) 띠 삭제, 윗면 선만 성토부선(계획선)으로 유지 — 구간별
  사면길이·5m 초과 여부 툴팁 표기
- 성토부 5m 이상이면 조정창 +로 추가 기슭막이(배관 없는 동일 형상 벽)
  계단식 추가 — 자동 자리는 배관용과 같은 규칙(1:1.2 최소 자리)
- 추가 벽도 ◀/▶/↺ 이동(안쪽 한계 = 앞 구조물), 마지막 벽 - 삭제
- 개수·이동량 세션 보관(b06:extrawall / revetx extra{n} 키)
- 700줄 제한: Extra(성토부선·추가 벽)·Wire(카드 배선) 분리 신설

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 13:24:47 +09:00
eomsangdonandClaude Opus 5 8743ccf810 feat(B06): 상황별 구조물 선택지 숨김 + 집수정 I형 원지반 근입
- 선택지 가용성(inletChoiceAvailability — Basin 분리):
  · 기슭막이+배관: 자동 자리 원지반이 토피 상한보다 높아 배관이 묻힐
    수밖에 없으면 숨김(2026-08-22 사용자 ①)
  · 집수정 ㄴ·ㄷ형: ㄴ형 가정으로 세워 봐서 원지반으로 밀고 들어가지
    않으면(절토선 없음) 숨김(사용자 ②)
  현재 선택된 값은 숨기지 않는다(빈 셀렉트 방지). 자동 자리 스캔은
  가용성 판정과 공용(중복 제거 — Geom 698줄).
- 집수정 I형 벽 하단을 원지반까지 근입(지반 아래 부재두께 0.2m) 후
  배관 배치(2026-08-22 사용자 — ㄴ·ㄷ형은 현행 유지). 벽면 기울기
  그대로 연장, 관 끝 마감면은 벽 폴리곤 실제 변 복사로 일반화.
- 검증: 13+15.7 I형 근입 0.40m·관 유입 불변(539.141), L형 회귀,
  dz 스윕(-2/-1: revet 숨김, +1: ㄴㄷ 숨김), 실화면 4+4.3 L·U 숨김
  / 13+15.7 revet 숨김(절토향 오르막 — 관 묻힘 판정) 드롭다운 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 11:45:09 +09:00
eomsangdonandClaude Opus 5 1774d61101 feat(B06): 집수정 관 끝선·두께 0.2·구조물 형식 드롭다운
2026-08-22 사용자 요청 3건:
- 관 끝선 = I형 벽의 안쪽(물받는 쪽) 변 복사(기슭막이와 동일 방식).
  관 시작점(하단): ㄴ·ㄷ형은 측벽 안쪽 변×바닥 윗면 교차점, I형은
  내공 1.0m 유지.
- 집수정 부재(벽·바닥판) 두께 0.2m(BASIN_MEMBER_THICKNESS_M).
- 유입 구조물 형식 드롭다운: 자동(규칙)/기슭막이+배관/집수정 I·ㄴ·ㄷ형.
  집수정 클릭 선택 가능, 선택 시 조정창에 드롭다운(집수정은 ◀▶ 숨김).
  세션 보관(inletstruct)·revet 선택 시 양측성토 로직 복귀·manual 사유.
- 집수정 구성을 _Cross_Culvert_Basin.ts로 분리(700줄 제한 — Geom 690줄).
  I형 바닥판 제거(벽뿐 — 정의 정합).
- 검증: 13+15.7 모듈(auto/revet/I/L/U 전부 기대 형상·관유입 자리 일치)
  + UI 실조작(집수정 클릭→드롭다운 revet/U/auto 전환, 부재 수 2→0→3→2,
  세션 왕복) + 스크린샷 대조.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 11:04:40 +09:00
eomsangdonandClaude Opus 5 a24cfe1378 feat(B06): 기슭막이 이동 한계 도달 시 토스트 안내
- 조정창 ◀/▶ 요청이 한계에 잘려 벽이 안 움직일 때 이유를 토스트로
  알린다(2026-08-22 사용자 요청, 13+15.7 참조).
  · 안쪽 한계: 성토 물매 1:1.2가 깨지는 자리(배관 최소 길이)
  · 바깥 한계: 조정 범위 초과
- 그 벽이 선택된 조작 중에만 띄운다 — 리로드로 복원된 세션 값에는 침묵.
- 검증: 공용 브라우저 실조작 — 13+15.7 안쪽 시도 토스트 표시,
  바깥 정상 이동 시 무음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 09:35:52 +09:00
eomsangdonandClaude Opus 5 564b289ee6 fix(B06): 이동량이 한계에 걸려도 숫자만 커지던 문제·안쪽 이동 최소 물매
- 조정창 숫자가 실제와 갈렸다. 안쪽으로 계속 누르니 "안쪽 10.0m"까지 올라가는데
  벽은 노견 한계에서 멈춰 있었다. 기하가 **실제 적용한 이동량**(revetShift)을 돌려
  주고, 카드가 그 값을 제어기에 되담는다 — 이제 한계에 닿으면 숫자도 멈춘다.
- 안쪽으로 당기면 사면이 짧아져 물매가 급해진다. **1:1.2(가장 급한 한계)**를 넘지
  않는 자리까지만 들어가게 막았다(2026-08-21 사용자 지시). 바깥으로 밀 때는 완만해
  지므로 막지 않고 범위 밖이면 경고로만 알린다.

검증: 4+4.3은 자동 자리가 이미 1:1.21이라 안쪽 이동 0(차단), 13+15.7은 −1m까지
허용(1:1.61)하고 그 이상 차단. 조정창 숫자도 같은 자리에서 멈춘다. 두께 16케이스
0.450 고정, 계획고 스윕 24케이스 문제 0. tsc 통과, pytest 148 pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 17:24:35 +09:00
eomsangdonandClaude Opus 5 8564e118d6 fix(B06): 조정 단위를 관 길이 1m로·벽 형상 불변·사면 역전 차단
지적 3건:
- 우측(유출) 기슭막이만 좌우로 밀 때 단면이 변했다. 0.1m씩 미니 관 길이 정수의
  끝수를 벽 폭이 흡수해 0.45→0.90까지 뚱뚱해졌다. 조정 단위를 **관 길이 1m**로
  바꾸고, 조정창으로 옮긴 벽은 폭을 절대 건드리지 않게 했다. 자리만 옮기면 정수
  길이가 성립하므로 형상이 그대로다(검증: 두께 0.450 고정, L 1m씩 증감).
- 성토 사면이 역전되는 자리가 있었다. 벽 상단이 노견보다 높아지면 사면선이 위로
  올라간다 — 최소 성토고 0.3m(FILL_MIN_RISE_M)를 두고 그 앞에서 멈춘다.
- 이동이 노견을 넘어 도로 반대편까지 갔다. 벽은 제 노견 바깥에만 서게 막았다.

조정창은 "관 길이 8m · 바깥 2.0m"처럼 관 길이를 같이 적는다.
700줄 유지를 위해 clampWallOffset·cutLength·outletSlopeFactory를 _Solve로 옮겼다.

검증: 이동 ±5m 20케이스 역전 0건·두께 고정, 275.71 유출 이동 11↔7m 정상,
계획고 스윕 24케이스 회귀 문제 0. tsc 통과, pytest 148 pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 16:50:45 +09:00
eomsangdonandClaude Opus 5 4eed191d2a feat(B06): 구조물 위치 조정을 횡단도 안 오버레이 창으로
카드 하단 버튼 그룹을 걷어내고 **해당 횡단도 안**에 뜨는 조정창으로 바꿨다
(2026-08-21 사용자 확정). 앞으로 구조물 위치 조정은 모두 이 창을 통한다.

- _UI_Cross_Structure_Panel.ts 신설. 그래프 영역 좌측 하단에 절대 위치로 얹는다
  (줌 버튼 우측 상단·면적표 중상단과 겹치지 않는 자리).
- 창 내용: 구조물 이름 · 자동 자리 대비 이동량 · ◀/▶/↺ · ✕(닫기 = 선택 해제).
- 이동량은 부호(+/−) 대신 "바깥 0.2m"처럼 적는다 — 좌·우 벽에서 부호만으로는
  어느 쪽인지 읽히지 않는다.

검증(공용 브라우저 4+4.3): 유입 벽 클릭 → 창 열림(제목·자동 자리), ◀ 2회 →
"바깥 0.2m"·도형 이동, ↺ → 자동 자리 복귀, ✕ → 창 닫힘·강조 해제.
tsc 통과, pytest 148 pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 16:34:09 +09:00
eomsangdonandClaude Opus 5 83a1309a37 feat(B06): 구조물 선택 = 카드 선택·면적 강조와 같은 레벨, 붉은 강조
- 강조 색을 --color-danger(붉은색)로 변경.
- 구조물을 고르면 그 측점 카드도 같이 선택된다. 이미 선택된 카드 안에서 다른
  구조물을 고를 때는 강조만 옮겨 가고 카드 선택은 건드리지 않는다.
- 구조물 선택과 절·성토 면적 강조는 같은 레벨 — 하나를 고르면 다른 하나가 풀린다.
  카드가 선택에서 빠져도 구조물 선택은 풀린다.
- 조정 버튼이 안 보이던 원인: .b06-cross-card__revetctl 스타일과 .is-hidden 규칙이
  아예 없었다. 스타일을 넣고 "기슭막이" 라벨을 붙여 표시 반폭 그룹과 구분했다.

미선택 카드에서 구조물이 먹히지 않던 버그도 잡았다 — 면적 비우기(onAreaSelect)가
먼저 카드를 선택해 버려, 뒤이은 onSelect가 "같은 측점 재클릭 = 해제"로 상쇄됐다.

검증(공용 브라우저 4+4.3): 미선택 카드에서 구조물 클릭 → 벽 강조 + 화살표 + 카드
선택. 같은 카드 다른 구조물 → 강조만 이동. 면적칩 → 구조물 해제. 다시 구조물 →
면적 해제. tsc 통과, pytest 148 pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 16:28:27 +09:00
eomsangdonandClaude Opus 5 6a3c991b5a feat(B06): 기슭막이 선택·X 자리 조절 화살표
- 기슭막이 폴리곤을 눌러 고르면 강조되고 카드 하단에 ◀/▶/↺가 뜬다. 0.1m씩
  화면 좌우로 민다(좌우 벽에서 뜻이 뒤집히지 않게 outward 부호는 내부 환산).
- 구조물 선택이 절·성토 면적 강조보다 우선한다. 벽 클릭은 벽에서 멈춰 밴드·카드
  선택으로 번지지 않고, 한쪽을 고르면 다른 쪽 강조는 꺼진다.
- computeCulvertLayout에 revetShift 인자 추가. 손으로 민 자리는 고정되어 관 길이
  정수 맞춤이 벽을 다시 옮기지 않고 폭으로만 흡수한다(폭 상한 0.45×2).
- 값은 세션 보관(b06:revetx), 이동 범위 ±3m.
- 700줄 정리: Page 751→690(_UI_Page_Station_Controls 분리),
  Cross_View 765→629(_UI_Cross_View_Zoom 분리).

검증: 이동 5케이스 접점 오차 0.00e+00, 계획고 스윕 24케이스 회귀 문제 0,
tsc 통과, pytest 148 pass. 화면 조작 확인은 다음 단계.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 16:14:17 +09:00
eomsangdonandClaude Fable 5 0d5fba4400 feat(B06): 배수관 횡단도 세트(배관·기슭막이/집수정·보호공) 추가
B05에서 배치한 배수관 측점의 B06 횡단도에 배관·기슭막이(또는 집수정)·보호공을
분리 도형으로 그린다. 기존 도형(지반선·면적 밴드·포장·암 경계)은 손대지 않고,
계획선 표시 규칙만 세트와 정합을 맞춰 함께 정비했다.

- 백엔드: pipe_points.json 정본(facility=="pipe")에 레지스트리 기본값을 채워
  chainage ±0.02m로 맞는 횡단에 culvert 키를 얹는다(Engine_Culvert 신규, Router의
  상세조회·재생성 두 경로에서 호출). 횡단 dict는 자유형이라 Pydantic 변경 없음.
- 배관: 유입 invert = min(노견 아래 원지반, 노면고 − 관경 − 토피 0.5), 유출 앵커는
  성토사면이 지반과 만나는 사면 끝(성토사면 길이 5m 한계 — 별표2 Ⅰ.2.차.(3)).
  역경사는 수평 클램프, 길이는 m 단위 올림. 단면은 축 법선 방향 직사각형이고
  외경선(실선)+내경선(점선) 2겹으로 관벽 두께를 보인다(파형강관 2.7T — KS D 3590).
  끝단면은 구조물의 계류측 변을 복사해 자른다.
- 기슭막이: 배면 수직 사다리꼴 + 전면 평행사변형 띠(1:0.3, t=0.45 — 실무 L3=45)의
  합성 단면. 높이는 이음선 상단점이 성토 사면선과 만나는 접점까지, 하한 관경+0.45,
  상한은 형태별 한계(찰 3.0/메 2.0 — 교본 7-3). 근입 0.5m(실무 기초콘크리트 H=0.5).
  돌 해칭은 벽 폴리곤 clipPath 안에만 그려 어떤 높이에서도 벽 밖으로 새지 않는다.
- 집수정: 절토측 유입이거나 원지반이 관 단면의 30% 이상을 막으면 자동 전환.
  I형(벽)·ㄴ형(+바닥)·ㄷ형(+반대측 막음), 기본 ㄴ형·내공 1.0m. 구조물이 원지반
  안쪽에 박히면 절토선을 공사 계획선(보라 실선)으로 긋는다. 라벨은 I형 벽 하단.
- 보호공: 시작 윗점 = 관 하단 꼭짓점, 시작 변은 기슭막이 전면과 같은 경사.
  성토경사를 따라 원지반까지 내려간 뒤, 최소 길이(낙차고×2)를 채울 때까지 원지반을
  따라 더 간다.
- 계획선 표시: 원지반과 차이 없는 구간은 그리지 않되(보라 점선 폐지), 노면·노견·
  측구부터 사면 1차 접점까지는 항상 그린다. 측구는 노견 바깥에 붙으므로 보호 범위를
  측구 폭만큼 넓히고 접점 탐색도 그 바깥에서 시작한다. 배수관 측점은 벽 접점에서 트림.
- B05: 배수관 측점 계획고를 지반고 + 관경 + 토피 0.5m 아래로 내리지 못하게 막고
  경고 토스트를 띄운다.
- 700줄 제한: 오버레이 파일이 919줄이 되어 기하(_Geom 678줄)와 그리기(247줄)로
  분리했다. import 경로는 재수출로 유지해 B05·Cross_View는 건드리지 않았다.

근거 미확정(코드 주석·툴팁에 명시): 토피 0.5m(별표2 교량·암거 복토 50㎝ 교차 참조),
기슭막이 근입 0.5m(실무값), 흄관·VR관 관벽 두께(관경÷12 — KS F 4403 미확보).

검증: tsc, ruff, pytest 148 passed(신규 test_b06_culvert_set.py 6건), 헤드 브라우저 —
4+4.3·13+15.7 세트 표시, 보호공 시작점과 관 하단 꼭짓점 간격 0.6px 이내·시작 변
기울기 실측 0.223(= 0.3·H/(H+0.5) 이론값과 일치)·최소 길이 5.0m 확보, 계획선
세그먼트 연결 틈 0개(8·9·10·12·4+4.3). ⚠ 13+15.7 성토사면 5.03m로 법정 5m를
0.03m 초과 — 툴팁에 표기하고 접점 보간 여부는 사용자 판단 대기.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:43:51 +09:00
eomsangdonandClaude Fable 5 54954a05e5 refactor(B05,B06): B05_wf2_Route -> B05_Profile, B06_wf3_ProfileCross -> B06_Section 동시 개명
- 한몸으로 동작하는 두 페이지라 한 커밋으로 처리 (상호 참조 다수)
- B05 37파일 + B06 20파일 접두사 개명 (git mv, 이력 보존)
- 참조 치환 91파일: import 경로, 라우트 슬러그(b05-profile/b06-section),
  라우트 키(B05_PROFILE/B06_SECTION), B03 자동 체인, storage 상수, pyproject 제외 경로
- 로직 변경 없음. typecheck·백엔드 import 검증 통과

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 10:03:11 +09:00