사용자 확정(2026-09-07): 「연암과 경암 / 발파암과 리핑암 선택은 횡단도에서 선택 안함.
사유는 향후 설계내역에서 설계자가 직접 비율로 지정하기로 함. 암반 지정과 범위 애매모호한
경우가 있어. 실무자는 그렇게 하기로 판단함. 대신 경고부분은 삭제해주고 대신 각도를
사용자가 넣을수 있게 반영.」
**왜 폐기인가** — 판정이 서려면 측점마다 암질(연암·경암)을 못 박아야 하는데, 실무에서
암반 지정·범위가 애매해 그 못 박음 자체가 틀린 전제였음. 암 비율은 **설계내역 단계에서
설계자가 비율로** 넣음. 기준이 없으니 경고도 없음.
되돌린 것 — 1e596846(암질 선택) + 973128f7(별표2 경고). 카드 경고 배지 · 판정 모듈 ·
config 범위표 · context 필드 · 표준 패널 암질 칸 전부 사라짐.
⚠ **남긴 것** — `cut_slope_segments`(구간별 경사)는 지우지 않음. 소단 기하가 그 위에
서 있고 구간 경사를 아는 값이라 뒤에 쓸 자리가 있음. 4e7a4bf7(사면 구간 재료를 그린
경사비로 가름 — 무릎 위 라벨 13구간 오류 수정)도 남김. 검사와 무관하게 옳은 고침임.
시험 4건 — 되살아나지 않게 막는 쪽으로 다시 씀(판정 모듈 없음 · 카드 경고 없음 ·
암질 고르는 자리 없음 · **구간별 경사값은 남아 있음**).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07): 「연암과 경암도 별도의 버튼으로 선택하게 하고 경암을 기본값으로
선택. 리핑을 할지 발파를 할지는 설계자가 선택 필요함.」
**축이 둘이었음 — 섞지 말 것.**
· **암질**(연암·경암) = 별표2 경사 판정의 기준. 설계자가 고름. 기본 **경암**.
· **굴착 공법**(리핑암·발파암, `cut_rock_kind`) = 어떻게 파는가. 수량·단가 몫.
처음에는 공법에서 암질을 유추하려 했는데 **그것이 잘못 세운 문제**였음. 매핑을 걷어내고
암질 선택 하나로 바꿈 — 표준 횡단면 설정 안, 자리는 그대로.
- config 매핑 상수 → `FOREST_ROAD_CUT_SLOPE_ROCK_QUALITY_DEFAULT = "hard_rock"`.
- 판정에서 `cut_rock_kind` 를 뗌. 수량 쪽 쓰임은 그대로 둠.
- 실측(용화 63측점·구간 124개) — 기본값 경암에서 **위반 0건**. config 기본 절토비 1:0.4 가
경암 범위(0.3~0.8) 안임. 토사 63구간도 0건. **기존 설계·수량 안 바뀜.**
(연암으로 고르면 61건 — 1:0.4 가 연암 하한 0.5 밖이라 그때는 설계 검토가 필요함.)
시험 8건 — 별표2 값 · 작업임도 제외 · **암질은 설계자가 고르고 기본은 경암** ·
**공법으로 암질을 추론하지 않음** · 구간별 판정 · 소단이 있어도 위반이 안 사라짐 ·
경계값 통과 · 카드에 같은 방식으로 붙는지.
7-3 회귀에 소단 한 줄 더함 — 「소단은 값이 아니라 **기하 입력**이라 계산 뒤에 베껴 붙이면
`berm` 값만 남고 계단이 안 그려진다」. 저장분 소단을 **계산 전에** 읽어 넣는 순서를 지킴.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`B06_Section_UI_Page_Persist.ts` 의 import 한 줄만 갈렸음. 양쪽 다 쓰는 이름이라 합침 —
`readByKey`/`writeByKey`(저장소 선택을 한 창구로 모은 것)와 `writeState`(소단 배선)가
같은 파일에서 각각 한 번씩 쓰임. 다른 충돌 없음.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
법정 위반 표시가 없던 유일한 자리였음(평면 곡선반경·성토사면 길이는 이미 있음).
절토 경사비는 표준 횡단면 설정에서 오는 입력값일 뿐이라 범위를 벗어나도 아무 표시가 없었음.
- 기준 — 별표2(지식DB `01_임도/02_상세설계/절토_비탈면.md` §1): 경암 1:0.3~0.8 ·
연암 1:0.5~1.2 · 토사 1:0.8~1.5. **작업임도는 규정 없음 → 검사 제외.**
- 판정은 **구간별 경사**(`cut_slope_segments`)로 함. 소단이 서면 실효 경사가 완만해져
**위반이 사라진 것처럼** 보임(폭 1.0·간격 2 이면 1:1 이 1:1.71). 그 함정을 시험으로 못박음.
- 표시는 **기존 방식 그대로** — 성토사면·미폐합 경고와 같은 자리·같은 클래스. 새 방식 안 만듦.
- 지반유형(리핑암·발파암) → 별표2 줄 매핑은 법령 근거가 아니라 **프로그램 설정**이라
표준 횡단면 설정에서 **사용자가 고르게** 함(2026-09-07 사용자 확정). 기본값 리핑암 → 연암 ·
발파암 → 경암. 표준단면과 함께 저장돼 이미 사용자 값 계통임.
- 기준값은 서버가 컨텍스트로 내려보냄 — 화면에 상수를 복제하지 않음.
시험 7건 — 별표2 값 · 작업임도 제외 · 매핑이 기본값일 뿐 · 구간별 판정 ·
**소단이 있어도 위반이 안 사라짐** · 경계값 통과 · 카드에 같은 방식으로 붙는지.
⚠ 실화면 — 사용자 선택 칸은 섰음(리핑암 연암 · 발파암 경암). 다만 이 프로젝트 저장분
63측점에 `cut_slope_segments` 가 아직 없어(오늘 새로 생긴 키) 경고가 뜨는 것은 못 봄.
재계산이 한 번 돌면 채워짐 — 지금 경고 0건은 맞는 동작임.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자가 소단을 **직접 놓는** 화면을 만들었음. 프로그램이 「붕괴 우려 지역」을 판정하지
않고, 법정 기준 셋 중 무엇도 자동 적용하지 않음(2026-09-07 사용자 확정).
폼은 C군 구간형 구조물과 **같은 꼴** — 기준 측점 + 전·후 거리로 종단 범위를 잡고
폭·간격·기울기를 함께 받음. 기본값 폭 0.5m · 간격(사면길이) 3.0m · 안쪽 2°.
새 모듈 `B06_Section_UI_Berm_Panel.ts` 로 뺐음 — 좌측 페이지가 이미 700줄을 넘어 있어
거기 더 넣지 않고 두 줄만 꽂음(그 파일 분리는 별건).
세션에는 **구간 목록**으로 둠. 측점별로 펴서 저장하면 「어디부터 어디까지 놓았나」를
되짚을 수 없음. 읽는 자리에서 펴고, 서버에는 측점키 dict 로 실어 보냄.
**확정 뒤에도 계단이 남게** — 소단 제원을 설계 결과에 되싣고(`berm`),
`USER_TOUCHED_KEYS` 에 넣어 재계산이 지우지 않게 함. 서버 재계산은 세션값이 없으면
저장분을 씀(`stored_berm`).
⚠ 소단은 사용자 조작값이면서 **기하 입력**이라 다른 사용자 키와 다름 — 계산 뒤에 키만
베껴 붙이면 설계선·면적은 계단 없이 나오고 `berm` 값만 남아 서로 어긋남. 그래서 단측점
설계 경로는 저장분을 **계산 전에** 읽도록 순서를 바꿨고, 포장 강제·세월교 노면 하강
재계산 경로에도 저장분 소단을 실었음. `extra_spans` 가 그렇게 빠져 있던 자리와 같음.
자체검증 — 새 시험 2건(저장분만으로 같은 설계가 나오는지 · 값이 없거나 손상되면 None).
전체 541 passed · 18 skipped. TS 타입 검사·ruff 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계단이 값에만 있던 것을 화면까지 연결함.
배선 — 세션 열쇠 `berm`(측점키 → 폭·간격·기울기)을 등록표에 두고,
`readBermSession` 으로 읽어 ① 브라우저 재계산(`refreshCrossDesigns`)과
② 서버 미리보기(`cross-design/preview` 의 `berms`) 양쪽에 실음.
암 경계선 오프셋과 같은 길이라 「계획선을 고치면 계단이 사라지는」 일이 없음.
실화면 확인(8001·5174, `/api/health` `stale:false`) — 측점 4120.0m 에 소단을 놓고
계획고를 한 칸 올렸다 내려 전 구간 재계산을 태움.
· 폭 0.5m · 간격 3.0m → 절토 6.84 → 8.10㎡ (토사 2.42→3.24 · 암 4.42→4.86)
· 폭 1.0m · 간격 2.0m → 절토 6.84 → 12.96㎡, 횡단도에 **계단이 눈으로 보임**
· 소단을 안 놓은 옆 측점(4100.0m)은 3.77㎡ 그대로 — 놓은 곳만 달라짐
· 되돌린 뒤 6.84㎡ 로 복귀. [저장]·[확정] 안 눌렀으므로 정본은 그대로.
`cut_slope_segments` 신설 — 절토 사면을 경사 구간별로 쪼갠 목록(파이썬·TS 짝).
법정 경사 검사가 읽을 값임(다른 창 요청). 소단이 서면 사면 전체를 하나로 재는
「실효 경사」가 완만해져 **위반이 사라진 것처럼** 보이므로(폭 1.0·간격 2 이면 설계 1:1 이
실효 1:1.71), 검사는 소단을 뺀 구간 자체를 봐야 함. 실측 — 소단을 놓아도 구간별 경사비는
1.0 그대로 나옴. 평탄부(소단)와 지반 만난 뒤 구간은 싣지 않음.
자체검증 — 거울 시험에 사면 구간 대조를 더해 파이썬·TS 일치 확인.
전체 539 passed · 18 skipped. TS 타입 검사 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표준단면 편집값은 sessionStorage 에만 살아 **탭을 새로 열면** 사라졌음. 그때 브라우저는
config 기본값으로, 서버는 저장분으로 계산해 **같은 측점이 갈렸음**. 표준단면은 모든 측점의
횡단 모양을 정하므로 면적·유토곡선·수량까지 그대로 흐름.
- `sections/context` 가 저장분을 **한 칸 더** 실어 보냄(`stored_standard_cross_section`).
기존 `standard_cross_section`(config 기본값)은 그대로 둠 — 옛 화면 안 깨짐, 마이그레이션 없음.
- 브라우저는 두 화면이 함께 지나는 한 자리(`fetchSectionContext`)에서 **세션이 비었을 때만**
그 값으로 세움. 그 탭에서 고친 값이 있으면 안 건드림(초안 우선).
실측(용화 5601e828 · route 169):
- 고치기 전 — 저장분 암반 횡단경사 **5%** · 측구 상단폭 **0.9m** 인데
화면이 받는 값은 **3%** · **0.69m**(config 기본값)였음. 응답에 저장분 칸 자체가 없었음.
- 고친 뒤 — 응답에 0.9·5 가 실리고, **빈 새 탭**에서 B06 을 열면 세션이
`rock.ditch.top_width_m=0.9` · `rock.cross_slope_pct.max=5` 로 섬(검증 탭은 닫음).
시험 `test_b06_stored_standard_reaches_browser.py` 3건 — 칸이 따로 있고 기본은 None ·
라우터가 저장분을 실음 · 브라우저가 세션이 빈 경우에만 세움(두 갈래 모두).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 「사용자 조작값」 목록이 세 곳에 흩어져 있었고 서로 달랐음.
브라우저(B06_Section_Cross_Refresh.ts PRESERVED_KEYS)는 extra_spans 를
살렸는데 서버 두 곳은 안 살렸음 —
- B06_Section_Router_Design._USER_TOUCHED_KEYS (포장 강제 재계산 ·
세월교 노면 하강 재계산이 씀)
- B06_Section_Router 안의 인라인 사본 (단측점 설계 갱신)
그래서 포장 구간이나 세월교가 앉은 측점이 다시 계산되면 사용자가 넣은
다단 구간값이 조용히 사라졌음.
_USER_TOUCHED_KEYS 를 공개 이름 USER_TOUCHED_KEYS 로 바꾸고 extra_spans 를
넣음. 라우터의 인라인 사본을 지우고 그 한 벌을 씀.
시험 tmp/tests/test_b06_user_touched_keys.py 3건 신설 — 서버 목록에
extra_spans 가 있는지, 서버와 브라우저 목록이 같은지(status ·
pavement_suggested 는 부르는 쪽이 붙이므로 제외), 라우터에 사본이
남지 않았는지. 목록이 다시 갈라지면 시험이 깨짐.
pytest 412 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05 진입이 간헐적으로 13~14초 멎던 원인을 CDP 프로파일로 잡음. 13,537ms 중
getVertexPosition 3,267 + intersectTriangle 3,178 + checkGeometryIntersection 3,012
+ _computeIntersections 2,198 = 11.6초가 three.js 레이캐스팅이었음.
- terrainElevation 이 점마다 Raycaster 로 지형 높이를 찾고 있었음(한 번 쏠 때마다
삼각형 전수 훑기). 마커·측점선이 점마다 부르는 자리라 곱해짐. 이미 있던
TerrainHeightIndex(격자 색인)로 돌리고, 색인도 지형과 한 벌로 보관(빌드 O(삼각형)).
같은 교훈을 2026-08-23 비탈 투영에서 겪어 색인을 만들어 뒀는데 이 함수만 옛 길이었음.
- B06 카드 버튼줄 reflow 의 레이아웃 스래싱 제거 — 한 칸 옮길 때마다 scrollWidth 를
다시 읽어 매번 강제 레이아웃을 냈음(카드 67장마다). 읽기/쓰기를 갈라 폭을 한 번만
재고 옮길 개수를 계산. ResizeObserver 첫 호출도 건너뜀(rAF 와 겹쳐 두 번 돌았음).
- get_section_context·get_section_detail 의 순차 읽기를 asyncio.gather 로 묶음
(원격 DB 왕복 약 12ms/질의).
자체검증(공용 브라우저 4왕복) — B05 진입 14,708/1,060/14,841 -> 1,269/806/726/746ms.
급등 사라짐. B06 진입 2,884 -> 2,330~2,864ms(긴 작업 합 2,313 -> 1,853).
시험 400 통과·17 건너뜀, typecheck 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
좌측 「구조물 배치」로 넣은 옹벽·돌쌓기 같은 벽이 지금까지 측점만 심고 기하가 없어
절·성토 면적이 그대로였음(2026-09-06 사용자 확정: 반영해야 함).
- 독립 기슭막이가 쓰던 `section.revetment` 제원 자리에 그대로 얹음 — 기하·설계선
트림·폐회로 면적·3D 가 손대지 않고 따라옴.
- 서버 `B06_Section_Engine_Structures_Wall.py`(저장분) ↔ 브라우저
`common_util_structure_walls.ts`(미저장 초안) 짝 + 거울 테스트.
- 설치 측 칸이 없는 C군은 성토가 나는 쪽으로 자동 배치, 양측 절토면 세우지 않음.
- 구조물 목록이 바뀌면 B06 이 초안을 얹어 다시 그림.
검증: 40m 돌쌓기(찰) 추가 시 그 측점 성토 5.81 → 5.02㎡. 테스트 390 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-06): 읽을 때는 영구저장소에서 가져오기만 하고, 계산은
화면(캐시)에서 하며, 저장·확정에서만 영구저장소에 쓴다.
- get_section_detail 이 조회할 때마다 돌리던 포장 구간 보정·세월교 노면 하강
보정을 제거. 조회는 저장분을 그대로 싣는다.
- 두 보정을 recompute_server_side 로 옮겨 [저장]·[확정]·자동설계 체인에서
정본에 남긴다. 보정된 설계 위에서 구조물 면적·유토곡선이 나오도록 순서를
잡았다.
- 설계 미지정 측점 폴백(attach_default_designs)만 조회에 남긴다 — 저장분이
있으면 아무 일도 하지 않는다.
검증: pytest 387 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 확정. 별표2 Ⅰ.2.나.(4) 확폭표(R 10~45m → 2.25~0.25m)를 측점별
평면 곡선반경에 물려 차도 폭을 넓힌다.
- 확폭 방향은 **곡선 바깥쪽 편측** — 노선 폴리라인의 외적 부호로 회전 방향을 보고
바깥쪽을 정한다(좌회전이면 우측). 측점 기록에 `curve_outer_side` 로 실린다.
- 차도 반폭을 좌·우로 나눠 들어 한쪽만 넓어지게 함. 확폭이 0이면 예전과 같은 대칭
단면이다. 노견·측구·사면은 그 바깥으로 그대로 밀린다.
- 확폭을 더한 유효너비는 법정 상한 5m 에서 자른다(규격 3.0m 면 최대 2.0m 까지).
- 계산 짝을 함께 고침 — 파이썬 `compute_cross_design` 과 브라우저 `computeCrossDesign`,
표는 양쪽에 두되 짝임을 주석으로 못 박음. 확폭 입력은 측점 기록에서 뽑는 헬퍼
하나로 9개 호출부(횡단·확정·B07 도면)에 같은 값이 가게 함.
- 횡단도에 노폭 라벨 — 확폭이 걸리면 「노폭 4.5m (규격 3.0 + 확폭 1.5)」로 적는다.
- 확인: 표 경계·편측 적용·5m 상한·회전 방향 판정 5건(pytest) + 브라우저 표 15건 일치.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 조작 중의 계산은 브라우저 안에서 끝나야 함(2026-09-03 사용자 확정). 계획고가
바뀔 때마다 전 측점 횡단 계산이 `POST …/cross-design/preview` 로 나가 왕복이 조작
속도를 지배했음.
- `refreshCrossDesigns` 를 로컬 계산으로 교체. 계획고는 저장 선형(`base_pvi`)에 편집
델타를 얹어 TS `buildAlignment` 로 여기서 풂 — 호출부(B05·B06) 시그니처는 그대로라
단일 창구가 유지됨. 서버 프리뷰는 선형 저장분이 없는 옛 데이터 폴백으로만 남음.
- 표준단면 config 기본값·암 경계 기본 오프셋을 `sections/context` 응답에서 세션에 기억
(`rememberStandardDefaults`·`rememberRockBoundaryDefault`). 프론트에 config 수치를
복제하지 않으면서 패널 없는 B05 도 같은 값으로 계산함.
- 디바운스 250 → 60ms — 왕복이 사라져 손을 떼는 즉시 유토곡선이 따라옴.
- 낡음 판정을 `hasStaleDesigns` 로 바꿔 첫 건에서 중단하고, 계획선 유효 샘플을
샘플 배열당 한 번만 걸러 이진탐색(그리기 프레임당 2.33ms → 0.07ms 실측).
- 파이썬 엔진 2파일·프리뷰 라우터에 「TS 짝 파일과 한 벌」 경고 블록 추가.
검증: `tmp/tests/test_b06_cross_design_mirror.py` 10건 — 토사/암 2단계/L형 측구/포장/
세월교 하강/사면 미닫힘 등에서 파이썬과 TS 결과가 면적·설계선까지 일치. 전체 183건 통과.
`tsc --noEmit` 통과. 실측: route 127(측점 128) 전 측점 로컬 재계산 7.5ms.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 데이터를 두 화면에 보여 주는 기능인데 세 곳이 갈려 값이 달랐다(실측: 절토(자연)
B06 3,704.6㎥ ↔ B05 4,526.8㎥).
① 보는 노선 — B05는 최신 경로, B06은 최신 **확정** 경로를 열어 노선을 다시 탐색한
프로젝트에서 서로 다른 노선을 봤다(route 126 DRAFT ↔ 125 CONFIRMED, 같은 20m
측점 성토 4.82㎡ ↔ 85.9㎡). `get_workflow_route_context()`(최신 경로) 신설해 B06
화면 context가 그것을 쓴다. 납품 도면(B07)이 쓰는 확정 전용 창구는 그대로 둔다.
② 횡단 재계산 — 호출이 두 벌이라 인자가 갈렸다(B06만 표준 단면값·암 경계 오프셋 전달,
보존하는 사용자 부속값도 2개 ↔ 7개). `B06_Section_Cross_Refresh.refreshCrossDesigns()`
한 창구로 모으고 세션 편집값은 저장소에서 직접 읽어 패널 없는 B05도 같은 값을 보낸다.
③ 낡음 판정 — 「옛 암 2단계 필드 누락」 조건이 B06 페이지에만 있어 B05는 재계산을
건너뛰었다. 공용 `staleDesignChainages()` 안으로 옮겨 두 화면이 같은 시점에 같은
조치를 한다.
검증 — 공용 브라우저 실측: 두 화면 모두 route 126, 요약줄 문자열 완전 일치
(`절토(자연) 4,526.8㎥ · 성토 14,881.8㎥ · 토취 10,213.3㎥ · 최종 누가토량 −10,213.3㎥`).
pytest 370 passed·17 skipped(일원화 검사 4건 신설), typecheck·prettier·ruff 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
횡단배수 최소 계획고가 두 곳에서 강제됐다. 자동설계는 배관 자리 계획고를 시설
여유만큼 들어 올렸고(B05_Profile_Engine_Sections), 화면은 그 아래로 내리는 편집을
차단했다(blocksMinCover). 배수 자리마다 계획고가 끌려 올라가 제어가 어려웠다.
산식(common_util_drainage_pipes.facility_clearance_m)은 그대로 두고 적용 여부만
enforce_pipe_clearance 스위치 하나로 뺐다. 기본은 해제라 자동 전처리가 계획고를
들어 올리지 않고, 편집도 막히지 않는다. 부족분 경고(minCoverWarningText)는 켜고
끔과 무관하게 계속 뜬다. 스위치는 요청 → DB 저장값 → 해제 순으로 정해지며,
계획선 criteria와 B06 재생성 경로도 확정 당시 값을 따라간다.
3D 예상형상은 계획선 편집마다 500ms 디바운스로 따라오던 것을 없앴다. 편집이
쌓이면 상단 [3D 업데이트] 버튼에 대기 점이 붙고, 누를 때 코리도와 측점선을 한 번에
갱신한다. 최초 진입의 자동 그림은 그대로다.
횡단도에 그려지던 노면은 사실 월류부 가장 아래를 자른 자리다 — 구체 위 노면은
월류 높이만큼 낮게 앉아야 한다(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-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>
[초기화] 후 관 지점 횡단(비정규 측점)이 통째로 사라지던 문제. 측점 정본은
longitudinal.json stations + cross_*.json 파일인데, 그 파일을 쓰는
run_section_generation 에는 공급자가 없었다. 유일한 공급자가 프론트
[임시저장]이라 초기화·반폭 재생성이 파일을 다시 쓸 때마다 측점이 날아갔다
(실측: 초기화 직후 cross 23 -> 19, irregular 4 -> 0).
- resolve_extra_stations 신설 — 관 정본(pipe_points.json) + 구조물 정본 A군에서
매번 파생한다. 라벨 형식은 프론트 structureLabel()과 같다. 물넘이포장은
비정규 측점으로 올리지 않는다(2026-08-28 사용자 확정).
- run_section_generation 이 generate_sections 앞에서 이 목록을 심는다. 호출자가
넘긴 extra_stations 는 무시한다 — DB 스냅샷으로 되쓰이는 값이라 되먹이면
B04에서 지운 관이 파일 정본을 이기고 부활한다.
- _load_pipe_anchors -> _load_pipe_points. 계획선 정착과 측점 생성이 같은 한 번의
읽기를 쓴다. 지문 불일치 경고에 버린 건수를 남겨 침묵 실패를 없앤다.
- B06_Section_Router._extra_stations 삭제(자기참조라 늘 빈 값이었다).
706 -> 689줄로 700줄 규칙 위반도 함께 해소.
- 격자와 같은 정수 미터인 비정규 측점은 격자로 스냅한다 — cross_*.json 파일명이
정수 미터라 측점 수와 파일 수가 어긋났다.
- 구조물 이관 필터를 A군 6종 라벨로 넓힌다 — 서버가 심은 세월교·BOX암거 라벨을
"기타"로 재이관하던 고스트를 막는다.
검증: pytest 229 passed / 7 skipped(신규 14건). 공용 브라우저 실측 — 초기화 직후
임시저장 없이 cross 23 / irregular 4(라벨 일치), B06 카드 23장, 반폭 재생성
20->25->20 에도 23 유지, DB cross_sections 23행.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
기슭막이 범위(길이·기준측점 전/후)를 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>
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>
_regeneration_options가 extra_stations를 넘기지 않아, 반폭 재생성 한 번에
구조물 측점 횡단도가 통째로 사라졌다(2026-08-23 사용자 보고). 옵션 스냅샷
(data.options.extra_stations)에서 목록을 읽어 재생성 옵션에 실어 준다.
자체검증: ./venv/Scripts/python.exe -m pytest tmp/tests/test_regeneration_extra_stations.py -q (2 passed)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 종단 상단 표시줄을 법정 판정 3항목으로 축소: 최대 기울기/상한(별표2 Ⅰ.2.라),
절·성토 불균형(Ⅰ.1.나.(4)(다)), 종단곡선 필요 n곳(Ⅰ.2.마 — 대수차 5% 초과인데
곡선이 빠진 변화점). 변화점·종단곡선 개수·기본 곡선길이 L·중복 경고칩은 제거.
- [초기선 복원] → [편집 되돌리기] — 실제 동작은 화면 편집 델타 삭제이지 저장 지점
복귀가 아니다. 툴팁에 동작과 [초기화]와의 차이를 적었다.
- 3D 뷰포트 안내 라벨 삭제(로딩 완료 후 남던 조작법 문구).
- 배수유역 버튼 정비: 유역 다시 나누기 / 선택한 관 삭제 / 배관 배치 초기화 +
각 툴팁에 실제 동작 명시(선택 삭제는 툴팁 자체가 없었다).
- 유토곡선 요약 12칩 → 5칩(절토·성토·잉여|부족·운반·검산). 토질 3종 내역·다짐
환산·블록 수·장거리 운반·사토는 해당 칩 툴팁으로. B05·B06 공용 함수라 동시 반영.
- 설계속도 축 도입(임도는 속도를 낼 수 없는 노선 — 기본 20km/h):
· 임도 종류는 프로젝트 등록값(projects.road_type)을 읽어 B05가 읽기 전용 표시
(main→간선임도, fire→산불진화임도, 그 외→작업임도). 화면에서 고치지 않는다.
· 설계속도 선택(간선·산불진화 20/30/40, 작업 20 고정) 신설 — 종단기울기 상한과
종단곡선 반경이 등급이 아니라 이 값으로 정해진다(지식DB 설계제원_총괄 §6·§7).
· B02 임도 종류 선택지를 현행 3종으로 정리(지선 폐지·계류보전은 사방 구분).
· 백엔드: ROUTE_GRADE_CLASSES 3종+branch 호환, selectable_design_speeds 신설,
resolve_design_speed 신설, legal_grade_limit_pct·resolve_grade_options에
설계속도 인자, sections/context가 road_type 제공(B06도 저장값 승계).
· 계획선 정책은 그릴 때마다 현재 기준으로 동기화 — 저장분의 옛 상한이 남지 않는다.
- 검증: pytest 125 통과(설계속도 12건 신규), tsc, 헤드 브라우저 — 진입 시 상한 9%,
40km/h 전환 시 7% 즉시 반영, 원복 9%, 안내문 '간선임도 · 설계속도 20km/h ·
일반지형', 유토곡선 5칩, 유역 버튼 새 이름·툴팁, 3D 라벨 빈 문자열 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>