- `docs/` 를 .gitignore 에서 빼 git 추적 대상으로 전환 (위키·완료 이력·검증 기록) - `docs/raw/PLAN.md` · `docs/raw/OWNERS.md` 를 저장소 최상위로 이동 후 .gitignore 에 등록 — 창끼리 공유하되 저장소에는 안 올리는 장부 - 살아 있는 경로 참조 7개 파일 정정 (아카이브 107건은 그때 사실이라 그대로 둠) - graphify 날짜별 산출물(`docs/wiki/graphify-out/20*/`) 제외 — `graphify update` 가 다시 만듦 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
98 KiB
완료 항목 이관 (2) — 2026-09-07 저녁
무엇 — 상시계획서
docs/raw/PLAN.md에서 끝난 것을 옮긴 두 번째 묶음. 같은 날 낮에 한 번 옮겼고(2026-09-07_plan_completed_items.md), 그 뒤 하루 작업이 다시 쌓여 2,059줄이 되어 한 번 더 갈랐음.원문 그대로 — 본문은 한 글자도 고치지 않았음. 바꾼 것은 어디에 두느냐뿐임.
두 종류가 섞여 있음
- 1부 — 절째 옮긴 것: 그 절에 남은 일이 하나도 없어 통째로 옮김.
- 2부 — 절 안에서 완료분만 옮긴 것: 절은 계획서에 그대로 있고(남은 일이 있어서) 끝난 덩어리만 이쪽으로 왔음. 계획서의 그 절에는 이 파일을 가리키는 줄이 붙어 있음.
절 번호는 계획서 것 그대로. 남은 절들이 이 번호로 서로를 가리킴.
1부 — 절째 옮긴 것 (남은 일 없음)
0-1. B05·B06 캐시·세션 일원화 (2026-09-06 사용자 지시)
대전제 — B05와 B06은 한 페이지임. 두 화면은 같은 키를 읽고 쓰며, 페이지를 오갈 때는 캐시를 그대로 들고 이동해 다시 부르지 않음. 이 전제를 지키려면 어떤 값이 캐시로 움직이고 어떤 값이 즉시 서버로 가는지가 먼저 정의돼 있어야 함 — 그래서 이 작업이 필요함(2026-09-06 사용자). 「B05↔B06 이동 지연」(옛 1순위)은 원인이 한 페이지처럼 쓸 캐시가 없어서이므로 이 항목에 흡수함 — 속도 목표만 자체검증에 남김.
같은 일을 여러 번 고쳤는데도 매번 판단이 갈림 — 규칙이 문서에 없고 읽고 쓰는 코드가 파일마다 흩어져 있기 때문임.
현황 조사 (2026-09-06)
- 세션 접근이 19개 파일 64곳, 키 이름이 네 갈래(
b05:,b06:,b05-route-,aislo:)로 제각각임. - 키가 페이지 이름으로 갈려 있음 — 같은 설계값인데
b05:…/b06:…로 나뉘어 두 화면이 서로의 값을 못 봄. (구조물 미저장분·유토곡선 범례처럼 이미 공유하는 키도 있어 규칙이 뒤섞임) - 계산 결과 보관이 거의 없음 — 횡단 상세는 메모리 캐시라 페이지를 떠나면 사라지고, B05 진입은 세션 캐시를 일부러 무시하고 DB를 다시 읽음(옛 노선번호 방지용 안전장치). 오갈 때마다 처음부터 다시 부르는 직접 원인임.
- 초안 범위가 제각각 — 프로젝트 단위와 프로젝트+노선 단위가 섞임.
- 초안 비우기가 파일마다 따로 있음.
- 통에 없는 성격이 하나 더 있음 — 페이지 간 넘김값(B05에서 고른 구조물을 B06으로 넘김). 세션에 임시로 얹혀 있음.
데이터를 네 통으로 나눔 (2026-09-06 사용자 확정)
| 통 | 무엇 | 어디에 | 언제 서버로 | 대상 |
|---|---|---|---|---|
| ① 화면 취향 | 패널 열림·높이, 보기 토글, 선택 상태 | 사용자 계정(+세션) | 바뀔 때 조용히 | 패널 접힘·높이, 유토곡선 범례, 테이블 열림 |
| ② 설계 초안 | 사용자가 만진 설계값 | 세션(초안) | [저장]·[확정] 때만 | 종단 계획선 · 횡단 · 구조물 · 배수유역 조작분 |
| ③ 즉시 반영 | 누르는 순간 다시 계산을 부르는 명령 | 안 쌓음 | 즉시 | 등고선 간격, 횡단 반폭 재생성, 노선 확정, 코리도 프리빌드 |
| ④ 계산 결과 | 서버·브라우저가 만들어 낸 값 | 세션·IndexedDB | 안 감(다시 계산) | 3D 코리도 · 유토곡선 · 배수유역 해석 결과 |
- ①은 계정에 붙임(2026-09-06 사용자 동의) — 다른 PC로 옮겨도 같은 배치로 열림.
- ②는 되돌릴 수 있어야 하고 [저장] 전에는 서버에 닿지 않음.
- ③은 되돌릴 조작이 아니라 「다시 계산해라」는 지시라 초안에 쌓을 값이 아님.
- ④는 저장 대상이 아님 — 입력(②·③)이 바뀌면 버리고 다시 만듦. 유토곡선·3D·배수유역 그림은 여기 속함. 사용자가 그 위에서 만진 값(관 위치·유역 나누기)은 ②로 감.
- 통이 정해지면 처리 방법이 따라옴. 새 기능은 이 표에 줄부터 넣고 코드를 씀.
- 실제 배분은 계획 반영 뒤 제어·리소스 현황을 보고 조정(사용자 지시) — 무거운 항목이 세션을 넘치면 ④를 IndexedDB로 내림.
기능마다 캐시냐 즉시냐 고를 수 있는가 — 됨 (조건 3개)
값마다 등록표에 통을 적어 두고 그 표만 보고 움직이게 만들면, 나중에 표 한 줄만 고쳐 캐시↔즉시를 바꿀 수 있음. 다만 아래 셋은 선택이 아니라 정해짐.
- 서버가 다시 계산해야 나오는 값(반폭 재생성·노선 확정 등)은 즉시밖에 안 됨 — 캐시에 담아 둘 값 자체가 없음.
- 식별자·판번호가 생기는 조작(구조물 새로 만들기 등)은 임시 식별자를 먼저 붙여야 캐시로 다룰 수 있음 — 지금 그렇게 돼 있음.
- 되돌리기·[초기화]가 걸리는 값은 캐시여야 함. 즉시로 두면 되돌릴 자리가 없음.
방법 (일원화 절차)
- 키 대장 만듦 — 지금 쓰는 세션 키 전부를 훑어 「키 · 통 · 소유 페이지 · 정본 위치」 표로 정리하고 이 계획서 참고 절에 둠. 분류가 애매한 키는 사용자에게 물어 확정.
- 그 대장을 코드에도 등록표로 둠 — 값마다 통을 한 줄로 적고, 저장·복원·비우기가 전부 그 표만 보고 움직이게 함(나중에 한 줄 고쳐 캐시↔즉시 전환).
- 화면 취향(①)을 계정에 저장하는 길을 냄 — 사용자별 화면 설정 저장·조회. 세션은 그 값의 사본으로 두고, 서버가 없으면 세션 값으로 동작.
- 세션 접근을 공용 파일 한 곳으로 모음 —
취향 읽기/쓰기,초안 읽기/쓰기, 키 만들기(프로젝트·노선 붙이기) 세 가지만 밖으로 냄. 다른 파일에서sessionStorage직접 호출 금지. - 키 이름 규칙 하나로 — 페이지 이름을 키에 넣지 않음.
aislo:{통}:{이름}:{프로젝트}[:{노선}]. ②·④는 두 페이지가 같은 키를 씀. 형식이 바뀌면 뒤에 판번호, 옛 키는 한 번 읽어 옮기고 지움. - 화면 취향(①)만 페이지별로 갈릴 수 있음 — 그 경우에도 키가 아니라 값 안에서 화면을 나눔.
- 이동할 때 다시 부르지 않음 — B05↔B06 이동은 캐시(②·④)를 그대로 들고 감. 진입은 캐시로 먼저 그리고 신선도 확인은 뒤에서. B05의 강제 새로읽기(
loadLatest(true))를 걷어내고 옛 노선번호는 지표면 서명으로 판정. - 페이지 간 넘김값(구조물 선택 등)은 ②의 한 자리로 흡수 — 별도 임시 키를 두지 않음. (→ 2-2 가 이 위에서 풀림)
초안은 한 덩어리— 하지 않기로 함(2026-09-07). 근거는 0-6 에 적었음 — 관리는 이미 한 벌이고, 키가 여럿인 것은 범위가 달라서이며, 합치면 실패 격리가 사라짐.- ③ 즉시 반영은 목록에 적힌 것만 허용 — 코드 훑기로 확정(2026-09-06). 허용 목록: 최적 경로 계산 · 초기화 · 등고선 간격 재적용(
route/contour-interval) · 횡단 반폭 변경(sections/{route}/regenerate) · 옛 데이터 폴백 프리뷰(cross-design/preview). 그 밖의 즉시 저장은 없음.- 규칙에 어긋나던 자리 하나 제거 — 횡단 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈)이 누를 때마다
POST cross-design으로 서버가 계산하고 바로 저장했음. 이제 선택은 세션 초안(crossdesign)에 쌓이고 계산은 브라우저가 하며 [저장]·[확정]에서만 나감. - 면적은 전 측점을 patch 에 실음 — 카드 버튼을 바꾸면 구조물이 없는 측점 면적도 달라져 구조물 측점만 보내면 수량이 어긋남.
- 규칙에 어긋나던 자리 하나 제거 — 횡단 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈)이 누를 때마다
- 초안을 비우는 자리도 한 곳으로 — [저장]·[확정]·[초기화]·노선 변경 뒤.
- 페이지 이동·새로고침 복원 경로를 그 한 곳으로 통일.
자체검증 (2026-09-06 화면 실측)
결과 — 캐시 우선 그리기는 섬: 새로고침 뒤에도 횡단 상세를 서버에 다시 묻지 않고 (
sections/detail호출 없음) 세션 사본으로 화면이 서며, 노선 최신값은 배경 확인 한 번으로 바뀜. 다만 요청 수 목표는 미달 — SPA 이동에서 B05→B06 12건, B06→B05 20건이 남음(로그인 확인·워크플로우 상태·지표면 목록·배수유역·구조물· 코리도 등 진입 호출). 옛 1순위의 「중복 호출 제거·진입 병렬화」가 아직 안 된 몫이다. 이 항목은 아래 남은 체크로 계속 잡을 것.
- 중복·순차 호출 정리 — 로그인 확인 1회로, 워크플로우 상태·지표면·구조물 중복 제거, 진입 호출 병렬화. 목표 = 이동 한 번에 10건 이하.
- 조작 후 새로고침 — 조작값은 남고 서버 정본은 그대로(2026-09-06 실측: 새로고침 뒤에도 초안 9개·구조물 초안 5건 그대로, 서버 구조물 2건 그대로).
- [저장] 후 — 현재 노선의 초안은 비고 서버 값과 일치(2026-09-06 실측: 구조물 초안
3건이 정본으로 나가 5건·판번호 6, 초안 키 사라짐). 남아 있던 초안은 옛 노선(145)
과 다른 프로젝트 것 — 노선이 바뀌면 노선 범위 키가 갈려 남는다(0-7 규칙대로
모달이 지우지만, 그 기능 이전에 생긴 것은 남아 있음).
- 남은 것 하나 —
std-cross(프로젝트 범위)는 저장 뒤에도 남음. 서버 값과 같은 내용이라 해는 없으나 규칙대로면 비워야 함.
- 남은 것 하나 —
- B05에서 만진 값이 B06에서 그대로 보이고 [저장] 한 번에 함께 나감(2026-09-06 실측: B05 에서 넣은 구조물 3건이 B06 화면에 그대로 서고, B05 [저장] 한 번에 정본 5건이 됨).
- 즉시 반영 목록 밖 호출이 없는지 코드 훑기로 확인 (2026-09-07) — 자동저장 없음.
B05·B06 의 쓰기 호출(PUT·POST) 전부를 눌러 본 결과, 설계값을 서버에 쓰는 길은
saveProfileAlignment(=[확정] 직전) ·saveStructuresIfDirty(=[저장]·[확정]) ·sections/save·confirm넷뿐이고 디바운스 후 즉시 PUT 은 한 곳도 없음. 목록 밖 쓰기는 둘인데 설계값이 아니고 둘 다 명시적 버튼임: ① 코리도 캐시PUT /corridor— [3D 업데이트] 버튼 · [임시저장] · B06 이동 세 자리 (B05_Profile_UI_Page.ts:328·:290,_Page_Actions.ts:188). 그림 재료라 설계값 아님. ②PUT /route/contour-interval— [재적용] 버튼(_Page.ts:613). 등고선 간격은 화면 취향이라 나중에 계정 저장으로 옮길 것(같은 절의 「화면 취향(①)」 항목).cross-design/preview는 이름대로 계산만 하는 폴백 경로임(B06_Section_Cross_Refresh.ts:230). - 속도 — B06→B05 이동 7건(목표 충족), B05 첫 진입 18건(그중 지형·지도 자료 8건, 핵심 API 10건). 중복 호출 제거: 로그인 확인 4→1, 워크플로 상태 2→1, 구조물 이관 POST 매 진입 → 1회만.
뒤로 미룬 판단
- ②·④ 실제 배분은 구현 뒤 제어·리소스 현황을 보고 확정(2026-09-06 사용자).
- ③ 즉시 반영 목록에 더 넣을 것이 있는지도 그때 함께 봄.
0-6. 남은 구조 개편 두 건 (2026-09-06 — 검증 뒤로 미룬 것)
둘 다 잘 도는 저장 경로를 통째로 건드리는 일이라, 검증을 먼저 끝내려고 미뤘음.
-
화면 취향(①)을 계정에 저장 — 1단계(브라우저 기억) 완료 · 2단계(계정 저장) 코드 완료, DB 적용 대기 (2026-09-07 커밋
9db84d9d·8a0a8f18)- 1단계 — 로컬 사본을
localStorage로(9db84d9d). 원래 계획서는 「PC 를 바꾸면 초기화」로 적혀 있었으나 실제로는 sessionStorage 라 탭을 새로 열 때마다 초기화됐음 — 불편이 훨씬 잦았음. · 절반만 옮겨지는 함정 — 공용 부품 셋(ui_template_resizer·_overlay·_overlay_drag)이 키만 들고 저장소를 직접 만져 접힘 4개는 옮겨지고 높이 3개는 세션에 남았음(실측). · 실측 — 옮기기 전 local 0·session 8 → 옮긴 뒤 local 8·session 0(종단 438px·표 204px 보존) → 새 탭에서 같은 값. 옛 취향은 첫 로드에 한 번 쓸어 옮겨 초기화되지 않게 함. - 2단계 —
018_user_ui_prefs(8a0a8f18). 사용자당 한 줄 ·prefsJSON 한 칸 ·users외래키.CREATE TABLE IF NOT EXISTS라 기존 표는 안 건드림.GET/PUT /api/dashboard/me/ui-prefs는 배치 값만(스키마가 문자열만 받아 설계값이 섞일 수 없음). 로그인 확인 첫 순간 한 번 받아 로컬 위에 얹고, 바뀌면 1.5초 모아 한 번 올림. 서버가 없거나 못 읽으면 로컬로 그대로 돎 — 그래서 표가 없는 지금도 화면 정상이고 다른 창이 sync 로 받아도 변화 없음. - 같은 함정 세 번째 — 창구를 하나로 모았음.
storageOf로 저장소만 골라 주니 키만 아는 자리가 직접 쓰면 서버 올려보내기도 안 걸렸음(키 → 저장소 → 올려보내기, 셋이 같은 모양). ⇒storageOf를 없애고readByKey/writeByKey한 창구로 모음 — 저장소 선택과 서버 올려보내기가 그 한 곳에만 있음. 코드에storageOf참조 0개, 그물 위반 0. - DB 적용 완료 — 이 건 완결 (2026-09-07). 25 와 시점을 맞춰 적용.
· 표 —
user_ui_prefs(user_id int·prefs longtext JSON·updated_at). 기존 표 안 건드림. · API —PUT/GET /api/dashboard/me/ui-prefs둘 다 200. 보낸 키 8개 → 되받은 키 8개 (profile-height = 438). DB 한 줄 확인(user_id=3 · prefs 309자). · 완결 지점 — 로컬을 비운 뒤 서버에서 돌아옴: localStorage 취향 8개 삭제 → 새로고침 → 8개 그대로 복원(profile-height 438·table-height 204). 로컬이 빈 상태에서 값이 섰으므로 「처음 여는 다른 PC」와 같은 조건임 — PC 두 대 필요 없었음. · 폴백도 실제로 겪어 확인됨 — 표를 만들기 전 API 가 404 를 냈는데(백엔드가 옛 코드) 그동안 화면은 로컬 취향 8개로 정상 동작했음. 일부러 만든 상황이 아니라 실제로 그렇게 돈 것임. · 되돌리려면DROP TABLE user_ui_prefs하나. — 패널 높이·열림 같은 값이 지금은 브라우저 세션에만 있어 PC 를 바꾸면 초기화됨. DB 표(016_*.sql) 추가가 필요함. - 사용자 승인 (2026-09-07): 진행 — DB 표 추가 승인.
- ⚠ DB 는 4환경 공용 — 스키마 변경·마이그레이션 적용 전에
ListAgents→SendMessage로 다른 창에 알릴 것(OWNERS 자원 점유). 적용 순간 다른 창의 로그인 세션이 끊길 수 있음.
- 1단계 — 로컬 사본을
-
초안을 한 덩어리로— 하지 않기로 함 (2026-09-07 조사 뒤 확정).- 문제 진술이 틀렸음 — 「키 16개로 흩어져 관리가 여럿」이 아니라 관리는 이미 한 벌임.
등록표
STATE_REGISTRY(A00_Common/b_page_state.ts:90~155) 하나가 이름·통·범위를 다 정하고stateKey·clearDrafts·hasDrafts가 그 표를 돎. 세션을 직접 만지는 모듈 여섯도 키는stateKey로 받아 씀. 실제 초안 이름은 19개(옛 수 16 은 낡음) — 프로젝트 범위 5 · 노선 범위 15. 키가 여럿인 것은 범위가 달라서이고, 합치면 그 구분이 사라짐. - [저장] 창구는 5개이나 비면 안 나감 —
B05_Profile_UI_Page_Persist.ts:228~250의 ①관 옵션 ②상단측 ③관 목록 ④구조물 ⑤sections/save. 앞 넷은 초안이 비면 즉시 return 이라 보통 1~2건만 나감. 노선 범위 초안 15개는 이미 한 요청(sections/save의crossPatches)으로 모여 있음. - 지금 구조가 일부러 그런 것임 — 넷은 각각 다른 정본(관 옵션·종단·
pipe_points.json·structures.json)을 쓰고, 하나가 실패해도 나머지가 나감. 2026-08-29 사고(타입이 거절되자sections/save가 아예 안 나감) 뒤 실패 격리를 위해 만든 구조임(코드 주석에 명시). - 3-2 사고를 막았겠는가 — 아니오. 그 원인은 판번호를 진입 때 받아 쓴 것 + 409 실패 처리가 초안까지 지운 것이었음. 한 덩어리·한 판번호였으면 409 한 번에 전부 날아가 더 나빴을 것.
- 얻는 것 — 저장 요청 최대 5 → 1(실제로는 1~2 → 1), 시간 이득 ≈ 0 (저장 802ms 중 서버 재계산이 0.6s 로 지배적, 요청 수는 병목이 아님).
- 다시 꺼낼 조건 — 저장 창구가 늘어 실제로 빠뜨림이 관찰되거나, 요청 수가 병목이 될 때.
- 문제 진술이 틀렸음 — 「키 16개로 흩어져 관리가 여럿」이 아니라 관리는 이미 한 벌임.
등록표
-
작은 그물 셋으로 대신함 (2026-09-07 결정)
- ⓐ 등록표 밖 세션 키 금지 시험 —
tmp/tests/test_session_keys_registered.py3건 (2026-09-07f8fafd23). 화면 폴더 여섯(A00_Common·B05·B06·B07·common_util·ui_template)의.ts를 훑어sessionStorage.getItem/setItem/removeItem(뒤에 따옴표·백틱이 바로 오면 실패. 지금 코드에서 걸리는 자리 0개 —rockb가 유일한 구멍이었고 그것도 막았음. 읽는 쪽이 등록표를 거치는지 · 옛 키가 코드에 안 남았는지도 못박음(주석은 예외).- ⚠ 함정 — 훑을 때
node_modules를 들어가기 전에 가지쳐야 함. 걸러내기만 하면 B07 CAD 의존성 트리를 통째로 걸어 몇 분씩 멈춤(실제로 걸렸음). - 그물을 한 번 넓혔음 (2026-09-07 커밋
159e2a52) — ⓐ 는 날문자열 키만 막았는데, 화면 설정 작업에서 「키는 등록표에서 받으면서 저장소는 이름으로 직접 고르는」 자리가 또 나왔음(공용 부품 셋이 그래서 접힘 4개만 옮겨지고 높이 3개는 세션에 남았음). 같은 계통인데 그물이 한쪽만 막고 있었음 ⇒ **「저장소 선택은storageOf한 곳만」**으로 넓힘. · 걸린 자리 2곳, 둘 다 고침 —B06_Section_UI_Page_Persist.ts:95·108(암 경계선 오프셋) ·B06_Section_UI_Page.ts:536·715(표시 반폭). 둘 다 지금은 초안이라 세션이 맞았음 (잘못 돌고 있던 것은 아니고, 통이 바뀌면 조용히 갈릴 자리였음). 남은 위반 0. · 제외 하나 —CURRENT_PROJECT_ID_KEY(frd_current_project_id). 「지금 보는 프로젝트」 가리개라 등록표가 관리하는 화면 상태가 아니고 워크플로우 전체가 그 한 값을 봄. 시험에 이유를 적어 제외했음. · ⚠ 그물 범위를 「등록표 키를 쓰는 파일」로 좁힌 이유 — 저장소를 직접 만지는 파일은 전체로 보면 30개인데 대부분 등록표와 무관한 제 값임(로그인 OTP·자산 캐시· B07 CAD 앱·업로드 흐름). 전부 금지로 넓히면 정당한 자리까지 걸림.
- ⚠ 함정 — 훑을 때
- ⓑ
std-cross가 저장 뒤에도 안 비는 것 — 의도임. 지우면 안 됨(2026-09-07 확정).sections/context가 주는standard_cross_section은 저장분이 아니라 config 기본값임 (B06_Section_Router.py:132이STANDARD_CROSS_SECTION상수를 그대로 내보냄). 프로젝트 저장분(longitudinal.options.standard_cross_section)은 서버 안에서만 쓰임. 패널은sessionValue ?? cloneDefaults(defaults)로 서고(_UI_Standard_Panel.ts:271~273), 브라우저 횡단 계산은effectiveStandardCross= 세션 ?? config 기본값. ⇒std-cross는 브라우저가 가진 유일한 사용자 표준단면이라 [저장] 뒤 비우면 그 순간 계산이 config 기본값으로 되돌아감 — 비우는 것이 오히려 결함. 등록표(b_page_state.ts)에 「저장 뒤에도 유지 · [초기화]에서만 버림」을 이유와 함께 적어 둠. - ⓒ 저장 창구 넷이 「비었으면 안 나간다」를 지키는지 — 시험 2건
tmp/tests/test_b06_save_channels.py(커밋647ec367). 넷 다 빈 초안에서 이른 반환을 가짐. 저장 앞단이 넷을 다 거치는지와 실패 격리(catch)가 셋 이상 남아 있는지도 봄 — 0-6 을 「안 함」으로 정한 근거가 그 성질에 기대므로 그물을 남긴 것임.pytest451 통과.
- ⓐ 등록표 밖 세션 키 금지 시험 —
-
🔴 암 경계선 오프셋을 읽는 쪽이 옛 키를 봄 — 늘 빈 값 (2026-09-07 조사에서 드러남)
- 쓰는 쪽
B05_Profile_UI_Page.ts:414→stateKey("rockb", …)=aislo:draft:rockb:{p}:{r}. 읽는 쪽B05_Profile_UI_Page_Persist.ts:39·49readRockBoundarySession은b06:rockb:{p}:{r}(옛 키)를 날것으로 읽음.writeStateRaw는 옛 키를 안 쓰므로 늘 빈 값을 받음. - 영향 —
B06_Section_Cross_Refresh.ts:124·245가 계획선을 고친 뒤 횡단을 다시 계산할 때 암 경계선 오프셋을 못 실어 보냄 → 그 재계산에서 토사/암 나눔이 기본값으로 돌아감. 수량이 갈리는 자리임. [저장] payload 는 메모리 Map 을 써서 저장 자체는 무사함. - 오늘 고친 셋과 같은 계통(조용히 값이 무시됨).
- 진짜 결함이었음 — 화면 전후 실측으로 확정(2026-09-07 커밋
f8fafd23, 용화 5601e828 · route 169). 고치기 전: 카드에서 암 경계선을 ▼ 세 번 눌러 -0.5 → -0.8m, 저장된 자리는aislo:draft:rockb:…:169={"0.00":-0.8}인데 읽는 쪽이 보던 옛 키b06:rockb:…:169는 세션 열쇠 목록에 아예 없었음.readRockBoundarySession이 늘{}를 돌려주던 것이 실측으로 확인됨 — 죽은 코드가 아니라 살아 있는 결함. - 읽는 쪽을 등록표(
readState("rockb", …))로 바꾸고 옛 키 만드는 함수는 지움. 새로고침 뒤에도 세션{"0.00":-0.8}· 화면 표기-0.8m그대로.pytest449 통과. - ✅ 재계산 전 구간 왕복 확인 끝냄 — 암 나눔이 살아남음 (2026-09-07 보조 창, 8879c53b).
-
준비 — 서버 재기동 뒤
/api/health의stale: false확인하고 시작(7-2 표시). -
세운 조건 — 측점 180.0m(A)의 암 경계를 ▼ 네 번, -0.5 → -0.9m. 화면 절토가 토사 1.83 → 3.22 · 리핑암 1.78 → 0.89 로 갈림. 세션에
aislo:draft:rockb:8879c53b…:128={"180.00":-0.9}(새 키에 쌓임). 대조용으로 196.1m(B)는 손대지 않음(-0.5m 유지). -
태운 경로 — 종단설계로 가서 1000.0m 측점을 골라 계획고 ▲ 한 칸(+0.1m). 편집이 실제로 걸림(
b05-profile-alignment-draft:128={"1000.000":0.1}, 누가토량 −5,339.4 → −5,665.6㎥) → 전 측점 재계산이 돎(refreshCrossDesigns). -
결과 — 횡단으로 돌아오니 A 는 암 경계 -0.9m · 토사 3.22 · 리핑암 0.89 그대로, B 도 그대로. 기본값으로 안 돌아감.
-
음성 대조(고치기 전이면 어떻게 되나) — 같은 서버 창구를 오프셋 빼고 한 번 더 불러 비교.
요청 A(180m) 암 경계 A 절토 토사 B(196.1m) 오프셋 보냄(고친 코드) -0.9m 3.5178㎡ -0.5m · 1.9535㎡ 오프셋 뺌(옛 결함) -0.5m 1.9989㎡ -0.5m · 1.9535㎡ → 읽는 쪽이 빈 값을 주면 정확히 기본값으로 되돌아감이 수치로 확인됨. 고침이 그 자리를 막음.
-
뒷정리 — A 는 ↺ 로 -0.5m·토사 1.83·리핑암 1.78(원래 값)로 되돌리고, 계획고도 ▼ 한 칸으로 0 으로 되돌림. 누가토량은 −5,081.3 → −5,085.4㎥(0.08%) 로 아주 조금 다른데, 세션 캐시가 서버 저장분 대신 방금 다시 계산한 설계를 들고 있어서임 — [저장]·[확정]은 누르지 않았으므로 정본은 안 바뀜.
-
- 쓰는 쪽
2-1. 3D 탑뷰에서 노선 선이 끊겨 보임 — 원인 확정 (2026-09-06 실측)
원인은 노선 선의 해상도임(사용자 추정과 일치). 3D 노선 선은 노선 폴리라인 정점을 그대로 이어 그리고 지형 위로 0.35m만 띄움(B05_Profile_UI_Markers.ts). 실측 — 정점 간격 중앙값 10.0m(점 500개, S자유역검증). 10m 현이 볼록한 능선을 가로지르면 0.35m 띄움으로는 모자라 선이 지면 아래로 잠기고, 그 구간만 안 보여 폴리라인이 끊긴 것처럼 보임. 화면에서 161+0.0~163+0.0 구간이 통째로 사라지는 것을 확인함.
- 고침 방향 셋 중 택일 — ① 선을 1~2m 간격으로 다시 뽑아 각 점의 지형고를 찍음(형상도 매끄러워짐) ② 띄움 높이를 키움(임시방편, 비스듬한 시점에서 뜬 선이 보임) ③ 깊이검사를 꺼 항상 위에 그림(지형에 가려지지 않으나 뒤쪽 선도 비침).
- ①번(선을 2m 간격으로 다시 뽑아 각 점의 지형고를 찍음)이 이미 들어가 있음
(
B05_Profile_UI_Markers.ts—DRAPE_STEP_M = 2, 점마다 지형고 샘플). 용화 프로젝트 TOP 뷰에서 노선 선이 끊김 없이 이어지는 것을 화면으로 확인(2026-09-06). - 코리도 투영 커브(0.02m)는 같은 문제가 아님 — 그 선은 코리도 서피스 위에 얹히고 리본 정점을 그대로 따라가므로 긴 현이 생기지 않음. 0.02m 는 z-fighting 방지용.
- S자유역검증 프로젝트에서도 이어짐 — 확인 끝(2026-09-07 보조 창, 8879c53b 3D 씬
실측). 노선 선 객체를 직접 재니 점 2,359개 · 점 사이 간격 최대 2.00m · 평균 1.92m ·
선 길이 4,521m.
DRAPE_STEP_M = 2조밀화가 이 프로젝트에도 걸려 있고, 최대 간격이 2m 라 문제였던 「10m 현이 능선을 뚫는」 상황이 어느 구간에서도 성립하지 않음. 161+0.0163+0.0(3,2203,260m)은 4,521m 안이라 당연히 포함됨. 띄움은 상수ROUTE_LINE_LIFT_M = 0.35m이고 점마다 지형고를 다시 찍은 뒤 올림 (B05_Profile_UI_Markers.ts:265~300) — 2m 안에서 지형이 0.35m 넘게 볼록해야 잠기는데 임도 종단에 그런 곡률은 안 나옴.
2-5b. 구조물 알약 크기 축소 (2026-09-06 사용자 지시)
「구조물 카드가 너무 커서 높이를 많이 차지함」 — 종단 그래프 아래 구조물 알약 레인을 낮춤.
- 알약 높이 24 → 18px, 혼자 있을 때 31 → 22px, 글자 11 → 10px.
레인 전체 54 → 42px(그만큼 그래프가 세로를 더 씀).
- 자체검증 — 실화면 레인 42px, 알약 22px, 「찰쌓기 1·2·3·4」·「배수관 1·2」·「옹벽」· 「세월교 1」 모두 읽힘.
- 확인 끝 — 사용자가 말한 것은 「종단도 하단 알약의 높이」였음(2026-09-07 사용자 답).
횡단 카드가 아님. 그 알약은 이미 줄였고(레인 54 → 42px · 알약 24 → 18px, 혼자 22px),
B06 도 2-6 에서 같은 부품(
buildStructureLane)을 쓰게 되어 양쪽이 같은 크기임. ⇒ 이 절 닫음. 더 줄일 일이 생기면 새로 꺼낼 것.
3-7. 횡단·수량 후속
- 3D 코리도 스윕과 저장·확정·새로고침에서
extra_spans단별 구간값을 확인한다. 끝남(2026-09-07 보조 창 실화면, b269ea34 · route 165 · 81.77m 유출측).- 단 수 0 → 1 → 그 단에 길이 15 · 전 8 · 후 7 입력 → 초안
extraspan에 남음 → [저장] 뒤 정본extra_spans={"extra0":{15.0,8.0,7.0}}·extra_wall_counts={"outlet":1}→ 새로고침 유지(재로그인 뒤에도) → [확정](184.6초 전체 재계산) 유지. →b6941bd2(서버 재계산이 값을 지우던 것) 가 실화면에서 서는 것 확인됨. - 물량까지 흐름 — 그 측점 성토가 10.9027 → 10.6743㎡ 로 달라짐(단이 자리를 먹음).
- 3D 도 섬 — 메쉬
outlet11.28m ·extra013.10m,__corridorBuild.structures에{kind:"revet", key:"extra0", at:81.773106, rings:16}. 넣은 구간값만큼 기준벽보다 길게 뻗음. - 곁가지 — 「3D 코리도가 아예 안 만들어진다」는 앞 보고는 오진이었음. 화면이 통째로
비어 있었을 뿐이고(옛 vite 모듈 그래프를 문 탭), 캐시를 비우고 새로고침하니 1.18초에
새로 만들어짐(
source:"built"· 구조물 메쉬 55개). - 환경 규칙 하나 얻음 — 백엔드를 재시작하면 vite 도 같이 새로 뜨는데, 열려 있던 탭이
옛 모듈을 물어 백지가 되고 콘솔 오류도 안 남. 화면 조작 전에 ① 8000·5173 둘 다 200
확인 ②
Network.clearBrowserCache+ reload ③ 그 다음 조작. - 지금 상태(2026-09-07 확인, 용화 5601e828) — 측점 67곳 어디에도
extra_spans·extra_wall_counts가 없음. 즉 값을 만드는 것부터 해야 함(카드 조정창에서 단 추가 → 구간값 입력). - 조정창 단추는 정상임을 실화면에서 확인(2026-09-07, 용화 5601e828 · 8000/5173) —
보조 창이 「눌러도 아무 일 없음」으로 막혔던 건은 결함이 아니었음.
- 기준벽(유출 기슭막이) 구간값 — 길이 + 한 번에 10.0 → 11.0m, 전·후 5.0 → 5.5m,
예약이
aislo:draft:culvertopt:…에{"85.05":{"outlet_revet_length_m":11,…}}로 남음. 되돌리기 -로 10.0/5.0/5.0 복구까지 확인. - 보조가 본 열쇠가 다른 자리였음 —
revetx는 다단 이동량(x·d·h·폼) 자리라 구간값이 거기 없는 게 정상. 기준벽은culvertopt, 다단 구간값은extraspan. - 단 수 + 도 대부분 측점에서 정상(유출 벽 6곳 중 4곳 0단 → 1단, 되돌림도 확인).
- 기준벽(유출 기슭막이) 구간값 — 길이 + 한 번에 10.0 → 11.0m, 전·후 5.0 → 5.5m,
예약이
- ⚠ 단 수 + 가 조용히 되잘리는 측점 — 성토부가 없어 벽을 못 세우면
syncCount(B06_Section_UI_Page_Station_Controls.ts:370)가 개수를 0으로 자름. 고침(2026-09-07 보조 창09442ae1) — 안내 자체는 이미 있었고 (B06_Section_UI_Cross_Culvert_Wire.ts의B06_Cross_Extra_Limit), 조정창에서 그 벽을 고른 상태에서만 떴던 것이 문제였음. 조건을 없애고 자리(측점·측·세워진 단 수) 마다 한 번만 내게 함. 문구는 기존 것 그대로(새 문구 안 만듦). 유입측도 같은 규칙. - 특히 볼 것 — 포장 구간이나 세월교가 앉은 측점에 단을 넣을 것. 고친 자리가 바로 그 두 재계산 경로라, 그 측점이라야 수정 전이면 값이 사라졌을 자리임.
- 순서: 단 추가·구간값 입력 → [저장] → 새로고침 → 값 유지 확인 → 3D 코리도 스윕 반영 확인 → [확정] → 다시 확인.
- 단 수 0 → 1 → 그 단에 길이 15 · 전 8 · 후 7 입력 → 초안
- [~] 좌우 이동이 안 먹는 측점 — 수치로 재고 절반만 가름(2026-09-06).
추가 기슭막이에 좌우 1.0m 를 요청해 재니 264.06 · 731.31 · 821.62 · 914.93 은 0.00m,
1002.24 만 0.18m 움직임. 코드상 막는 자리는 「원지반 매몰 금지」(
placeable)이고, 막히면 요청을 자동 자리 쪽으로 0.05m 씩 되돌린다.- 원인 확정 + 고침(2026-09-07,
ec153bc2) — 지형이 아니라 선반 하한이었음. 좌우 이동은 선반 길이가 음수가 되지 않게1.2 × 상하 내림까지 따라 나감 (shelfFloor,B06_Section_UI_Cross_Culvert_Extra.ts). 저장값이 d 2.6m 이면 하한이 3.12m 라 1.0m 요청은 애초에 아무 변화도 못 냄. 그래서 「지형에 막힌 양」 (shiftBlockedM)이 0 으로 나온 것이 맞았음 — 다른 까닭이었을 뿐. 1002.24 만 0.18m 움직인 것도 그 자리 하한이 0.82m 였다는 뜻으로 앞뒤가 맞음.- 고침 —
shiftFloorM을 남기고 벽 툴팁에 하한을 적음(지형 탓과 자리를 나눠 둠). - 시험 —
tmp/tests/test_b06_extra_shift_floor.py3건. 화면 코드를 그대로 컴파일해 Node 로 돌림. d 2.0m 아래에서 좌우 0.5m 요청 → 실제 2.4m, 그 값이 알려지는 것, 그리고 요청이 없으면 안 뜨는 것까지. - 덤으로 찾은 것(
023c0d54) — 독립 기슭막이(D군) 툴팁은 따로 만들어져 있어 「지형에 막힘」 안내조차 여태 안 떴음. 두 줄을 같은 문구로 붙였고 기준벽 경로에도 하한을 남기게 함.
- 고침 —
- ✅ 실화면 확인 끝냄(2026-09-07 보조 창) — 두 경로 모두 툴팁이 실제로 뜸.
아래 「확인 남음」 기록은 그때까지의 경위이므로 남겨 둠.
- 방법 — 공용 브라우저에서 사용자처럼 조작. 먼저 성토사면이 가장 긴 측점을 카드
머리의 「성토사면」 표기로 골랐음(273장 중
≥23.43m가 11곳). - ① 배관 다단 벽(
ec153bc2) — STA 188+6.2(카드 227, 성토사면≥23.43m)의 유출 기슭막이. 좌측 목록의 유출구 칸에서 단 1 추가 → 생긴 「추가(성토부) 기슭막이」를 도면에서 고르고 카드 위 조정창 ▼ 2회. 결과 — 상하(사면) 아래 0.9m, 툴팁에 「⚠ 좌우 이동 하한 1.08m」. 셈 대조: 1.2 × 0.9 = 1.08 ✅ (다단은shelfFloor = 1.2·d). 이어 ▶ 를 눌러도 「좌우 바깥」이 1.1m 그대로 — 알림이 말하는 「눌러도 안 움직임」이 실제로 재현됨. - ② 독립 벽(C군 구간형)(
023c0d54) — 성토사면≥23.43m인 STA 141+0.0(카드 169)에 돌쌓기(찰) 을 새로 넣고(군 C → 종류 → 기준측점 141+0.0 → [추가]), 그 벽을 골라 조정창 ▼ 3회. 결과 — 상하(사면) 아래 2.9m, 툴팁에 「⚠ 좌우 이동 하한 0.41m」. 셈 대조: 1.2 × 2.9 − 3.073 = 0.407 → 0.41 ✅ (1단은xFloor = 1.2·d − PIPE_WALL_DEFAULT_RUN_M, 그 상수 = 4.0×1.2/√2.44 = 3.073). ▶ 로는 0.4m 에서 안 움직이다가 ◀(이쪽이 바깥) 로 0.5m 가 되자 알림이 사라짐 — 요청이 하한을 넘으면 안 뜨는 것도 맞음. - 계획 대비 — 「▼ 2~3회 → ◀ 1회」 순서 그대로 재현됨. 다만 1단과 다단의 하한 식이
다름을 확인: 다단은
1.2·d, 1단은 거기서 자동 자리 3.07m 를 뺌. 그래서 같은 내림이라도 1단 쪽 하한이 훨씬 작음. - 뒷정리 — 넣었던 돌쌓기(찰)은 지웠고(목록·도면 모두 0), 카드 227 은 단 0 · 자동 자리 · 이격 0.32m 로 원래대로 되돌림. 사용자 화면은 만지기 전과 같음.
- 방법 — 공용 브라우저에서 사용자처럼 조작. 먼저 성토사면이 가장 긴 측점을 카드
머리의 「성토사면」 표기로 골랐음(273장 중
- ⚠ (경위) 실화면 확인 남음 — 알림이 실제로 뜨는 것까지는 못 봄. 용화(5601e828)에서는
고른 벽마다 「이동」 행이
is-hidden이고offsetParent도 null 이라 사용자에게 보이지도, 눌러도 아무것도 안 쌓임(revetx비어 있음). 캐시를 비우고 새로고침한 뒤에도 같음 — 옛 화면 탓이 아니라 그 벽들이 이동 대상이 아님(canNudgefalse). → 조건을 세우려면 C군 구간형 벽(돌쌓기 등)을 새로 넣어야 함 —own벽을 만드는 것은 D군(점형)이 아니라 C군 구간형임(withDraftWalls).- ⚠ 함정 — 이동 십자는 dock 에 없음. 두 창이 헛짚었음. 십자(▲▼◀▶)·집수정 9키는
횡단도 위 조정창 전용이고 좌측 [횡단 조정] dock 에서는 CSS 로 숨김
(
B06_Section_UI_Style_Cross_Controls.css:244~253, 그 반대 규칙이:281~). 2026-08-29 사용자 지시로 「값·형식은 좌측, 위치제어는 도면 위」로 나눈 것 — 정상임. - 순서: C군 구간형 추가 → 카드 위 조정창에서 ▼ 2~3회(내림 2m 이상) → ◀ 1회 → 툴팁에 「좌우 이동 하한」 확인.
- ⚠ 정정(2026-09-07) — 십자는 정상임. 한때 두 창이 「십자가 크기 0 이라 안 그려진다」로
결론냈으나 틀렸음. 고른 벽의 카드에서 재면 조정창 124×185, 이동 행 107×86 ·
display:flex로 멀쩡히 섬. 0 이 나온 것은 스크립트가 화면에 열린 아무 패널이나 집어 잰 탓임(카드가 66장이라 다른 카드의 빈 패널이 먼저 잡힘). → 검증 스크립트는 버튼 크기가 0 이 아닌 패널만 골라 눌러야 함. - 그래도 툴팁 확인은 아직 못 함 — 조건을 세우려면 상하 내림이 큰 벽이 필요한데,
단을 세우려 한 측점들이 성토부가 없어 단이 안 서고(
syncCount되잘림) 그 조합을 못 만들었음. 다음에는 성토부가 넉넉한 측점을 먼저 고를 것. - 그동안 확인된 것 — 셈과 알림 자체는 시험으로 섬(
test_b06_extra_shift_floor.py3건). 화면 조작으로 조건을 세우는 길만 못 찾음.
- ⚠ 함정 — 이동 십자는 dock 에 없음. 두 창이 헛짚었음. 십자(▲▼◀▶)·집수정 9키는
횡단도 위 조정창 전용이고 좌측 [횡단 조정] dock 에서는 CSS 로 숨김
(
- 「지형에 막힌 이동량」을 벽 툴팁에 알리는 배선은 넣어 둠(
shiftBlockedM) — 되돌림이 실제로 일어나는 경우에 뜬다.
- 원인 확정 + 고침(2026-09-07,
- 불규칙 측점 생성 시점 — 이미 규칙대로임을 확인(2026-09-06). 자동분(관 지점)은 체인이 정본에 저장하고(용화 신규 프로젝트에서 구조물 측점 11곳 저장 확인), 사용자 추가분은 캐시에 있다가 [저장]·[확정]에서
irregular_stations로 나감.
7-1. ✅ 개발 화면이 API 를 못 부름 — vite 프록시가 IPv6 를 먼저 물음 (2026-09-07 보조 창 발견)
증상 — 브라우저의 모든 /api 요청이 「Failed to fetch」. 백엔드는 127.0.0.1:8001 로
정상 200, vite 도 200, 새 탭을 열어도 같음. 화면 검증이 통째로 막힘.
찾은 것 — 백엔드는 0.0.0.0(IPv4 전용)로 뜨는데 vite.config.ts:5 의 프록시 대상이
http://localhost:${AISLO_API_PORT} 임. Node 18+ 는 localhost 를 IPv6(::1) 먼저
물어서 프록시가 [::1]:8001 로 붙으려다 실패함. 실측 — 127.0.0.1:8001 200 ·
[::1]:8001 연결 실패.
「절반」은 틀렸고 원인은 전부 이것임 (2026-09-07 재판정, 배분 창 지적으로 다시 봄).
SERVER_HOST=:: 시험은 반증이 아니라 같은 결함의 동전이 반대로 떨어진 것임 — 그때 화면이
안 된 까닭은 둘 중 하나인데 어느 쪽이든 결론이 같음. ① vite 를 안 다시 띄웠으면 프록시는 옛
설정 그대로라 시험 자체가 성립 안 함 ② 다시 띄웠다면 그 vite 가 localhost 를 IPv4 로
풀었고 백엔드는 v6 전용이었으니 또 엇갈림. 양쪽 다 localhost 가 뽑기라서 생긴 일이고,
숫자로 박으니 한 번에 끝났음. SERVER_HOST 는 0.0.0.0 그대로 두면 됨.
다른 창(laptop-main 8000·5173) 실측 — 같은 조건인데 증상은 안 겪었음 (2026-09-07)
| 잰 것 | 값 |
|---|---|
127.0.0.1:8000/api/health |
200 |
[::1]:8000/api/health |
연결 실패 |
node -v |
v22.17.0 |
hosts 의 ::1 localhost |
주석 아닌 줄 없음 |
그 창의 vite.config.ts |
아직 localhost (25 수정분 미병합) |
그런데 그 창은 하루 종일 5173 프록시로 /api 를 수십 번 성공했음(조정창 열기·저장·초안 조회).
즉 그 프로세스에서는 localhost 가 IPv4 로 풀렸음.
→ 판단: 백엔드 바인딩(IPv4 전용)은 4환경 공통이고, 갈리는 것은 localhost 를 무엇으로
푸느냐뿐임. Node 18+ 의 verbatim DNS 는 해석기가 주는 순서를 그대로 쓰므로 같은 PC에서도
프로세스·시점에 따라 ::1 이 먼저 올 수 있음. 즉 지금 잘 도는 창도 잠재 결함이고 운이
좋았을 뿐임. 127.0.0.1 로 박아 순서 의존을 없애는 것이 맞음(두 창 합의).
오늘 겪은 것들이 이것으로 설명될 수 있음 — 「저장 Failed to fetch」 · 「화면 백지」. 부팅 때 API 가 죽으면 화면이 아무것도 안 그림.
vite.config.ts의apiTarget을127.0.0.1로 박음(한 줄, 왜 그런지 주석 붙임). 커밋8f4c486a. 배분 창 승인받고 고쳤고 두 창에 알림.- 자체검증 (2026-09-07, 공용 브라우저 새 탭 — 사용자 탭은 안 건드림)
- 방법 — 고친 뒤 vite 를 다시 띄우고(
AISLO_API_PORT=8001) 화면에서 직접 부름. - 결과 — 화면 그려짐 ·
/api/health200 · 로그인 POST 200. 이어서 사용자 탭도 캐시 비우고 되살림: 화면 200 · 횡단 카드 273장. - 계획 대비 — 「셋을 따로 재기」는 불필요해짐. 한 줄로 증상이 사라져 원인이 하나로 확정됨.
- 방법 — 고친 뒤 vite 를 다시 띄우고(
- 다른 창(laptop-main 8000·5173)은 같은 증상을 안 겪었음 — 위 표대로 조건은 똑같은데
그 프로세스가
localhost를 IPv4 로 풀었을 뿐임. 환경 차이가 아니라 뽑기 차이이므로 4환경 공통 잠재 결함이 맞고, 공용 파일 한 줄로 네 창이 같이 나음.
7-3. 회귀 묶음 — 「사용자 값이 조용히 사라지거나 갈리는 것」 (2026-09-07 신설)
오늘 나온 결함이 전부 한 계통이었음 — 사용자가 넣은 값이 재계산·재진입·다른 경유에서 조용히 사라지거나 갈림. 시험이 여섯 파일에 흩어져 있어 한 번에 도는 묶음을 따로 뒀음 (기존 시험은 그 자리에 그대로 — 옮기면 각 결함의 사연이 시험 머리에서 떨어져 나감).
tmp/tests/test_user_values_survive.py — 9 통과 · 1 건너뜀(⑧ 자리 비움). 전체 463 통과.
줄마다 커밋 해시 + 한 줄 사연을 머리에 달아, 깨졌을 때 무엇을 되밟는지 바로 알게 함.
대상 일곱 — 19444149 노선 깎임 · a0bd9c87 반지름 눌림 · b6941bd2 다단 구간값 지워짐 ·
908c75d5 이월 덮임 · b8f0f7ad 2단 절토 켬 소멸 · f8fafd23 암 경계선 옛 키 ·
72e50b3e 표준단면 탭 밖 갈림.
구성
- 실제 계산을 태우는 것 4 — ① 노선을 다시 넣어도 꺾임점이 안 줄어듦 ② 편집을 거쳐도 맞춰 둔 R 이 남음(30m 초과) ③ 포장 재계산 뒤에도 구조물 조작값 4종이 그대로 ④ 토사에서 켠 2단 절토가 왕복해도 True.
- 구조를 지키는 것 3 — ⑤ 이월이 측점 재생성 뒤에 오는지(순서가 곧 고침) ⑥ 암 경계선이 등록표 키로 읽히는지 ⑦ 저장 표준단면 칸이 있고 브라우저가 두 갈래 모두에서 세우는지.
- 화면이 필요한 것은 안 넣음 —
pytest로만 돎.
음성 대조 2건(그물이 헛돌지 않음의 증명) — ② 갈아 끼우기를 빼면 R 이 하한 12m 로 눌림 ·
③ 보존 목록에서 extra_spans 를 빼면 그 값이 즉시 사라짐.
안 붙인 이유 — ①④ 는 옛 동작 재현에 고치기 전 코드가 필요함(코드를 되돌리지 않고는 못 세움).
⑤⑥⑦ 은 소스를 지키는 시험이라 단정문 자체가 대조임.
- ⑧ 암 경계선이 나눔에 실제로 닿는다 — 채움(2026-09-07). 보조 창 화면 수치를 시험 머리에
사연으로 적고, 같은 성질을 엔진에서 수치로 봄:
ripping_rock측점에서 암 경계선을 -0.5 → -0.9m 로 내리면 토사가 늘고 암이 줌(토사 0.7443 → 1.0512 · 암 0.171 → 0.0).- ⚠ 바로잡은 것 — 「절토 합계는 그대로」가 틀렸음. 처음에 그 단정을 함께 넣었다가 뺐음. 2단 절토의 무릎이 경계와 함께 움직여 총 절토도 달라짐(0.9153 → 1.0512㎡). ⇒ 암 경계선을 옮기면 나눔뿐 아니라 총 절토량도 바뀜. 이 시험이 지키는 것은 「경계가 나눔에 실제로 닿는다」임.
- ⑨ 다단이 물량에 닿는지(
e9ad8cdf) — 채움 — 단이 서면 그 측점 성토가 줄어드는 것 —computeCulvertLayout이 다단 성토부선을 면적 트림에 넣는지, 유출측·집수정 계류측 둘 다 넣는지, 묻힌 구간(cut)은 빼는지를 구조로 봄. 값이 아니라 구조로 본 이유(면적 경로가 DOM 까지 끌고 와pytest로 못 돎)와 화면 실측 수치(10.9027 → 10.6743㎡)를 시험 머리에 적었음. ⇒ 묶음 11 통과 · 자리 비움 없음.
2부 — 절 안에서 완료분만 옮긴 것
아래 절들은 계획서에 그대로 있음(남은 일이 있어서). 끝난 덩어리만 여기 모았음.
0-5. B05·B06 계산을 양쪽에서 다 돌 수 있게 (2026-09-06 사용자 지시)
-
배수관 세트 부착 TS 짝 신설 —
common_util/common_util_culvert_sets.ts. 다섯 시설(배관·세월교·BOX·물넘이포장·독립 기슭막이)을 모두 태워 거울 테스트로 딕셔너리째 대조(tmp/tests/test_b06_culvert_sets_mirror.py). 흩어져 있던 임시 산식(관경÷1000 · BOX 구체 길이 · 날개벽 바닥판 연장) 세 곳을 이 한 벌로 바꿈. -
종단 계획선 초기 산출을 TS 로— 하지 않기로 함 (2026-09-07 조사 뒤 확정).- 자리 —
B05_Profile_Engine_Sections.py:236~258이 자동설계 체인에서 세 갈래로 시도함: ①design_pipe_anchored_profile(배관 정착) → ②design_alignment_profile(선형, 주 경로) → ③design_grade_line(균형 최적화, 폴백). 입력은 지반고 종단 배열 + 등급 옵션뿐이라 파일·DB·래스터를 안 만짐 — 입력 쪽에는 「서버여야만 하는 이유」가 없음. - 그런데 셋 다
scipy제약 최적화에 묶여 있음 —solve_alignment_elevations가scipy.optimize.minimize+LinearConstraint(B05_Profile_Engine_Grade_Solver.py:359~, SLSQP/trust-constr 갈아탐), 폴백optimize_pvi_elevations도 같음. ⇒ TS 로 옮기려면 제약 최적화기를 직접 짜야 함. 가장 예민한 수치 코드를 새로 만드는 일임. 기존 짝(_Grade_Alignment.py↔_UI_Profile_Alignment.ts)은 PVI 구조·종단곡선 기하(순수 기하)만 다루므로 이 범위 밖임. Node 실행도 답이 아님 — TS 쪽에 solver 가 없어 결국 같은 최적화기를 새로 짜게 됨(= 세 벌째). - 얻는 시간은 거의 0 (같은 크기 합성 종단 실측) — 1,340m·측점 68: 선형 0.01초 · 배관정착 0.00초 · 폴백 0.06초 / 4,520m·측점 227: 선형 0.06초 · 배관정착 0.00초 · 폴백 2.26초. [확인] 90초 중 종단 몫은 0.1초 미만. 90초는 배수유역 몫이지 종단 몫이 아님(0-11).
- 사용자 지시(「B05·B06 을 양쪽에서 다 돌 수 있게」)는 이미 충족됨 — 조작 중 계산은
브라우저에 있음(
buildAlignment·adjustStation·shiftSegment·setCurveRadius). 없는 것은 초기 산출뿐이고 그건 5장이 「초기값은 서버가 한 번」이라고 못박은 자리임. 옮기면 오히려 「브라우저를 안 열면 값이 없다」(0-4 가 막은 것)로 되돌아감. - 다시 꺼낼 조건 — 종단 초기 산출이 사용자 대기의 눈에 띄는 몫이 될 때. ⚠ 이 결정은 사용자 지시를 일부 접는 것이므로, 사용자가 「그래도 옮기라」 하면 그때 다시 봄.
- 자리 —
-
배수관 쪽 계산 두 개를 TS 짝으로— 폐기(2026-09-06 두 창 합의). 서버 낭비를 걷어내니 왕복이 907 → 187ms 라 「관을 놓고 나서 보는 값」 기준 합격이고, 격자 npz 3.1MB 를 브라우저로 보낼 값이 그만큼 크지 않음. 서버 전용으로 확정. 상세는 0-8. -
원지반을 다시 뜨는 자리 확인 — 노선 재탐색과 횡단 반폭 변경 둘뿐(
sections/{route_id}/generate). 둘 다 자리가 바뀌는 경우라 맞음. 상세 조회는 파일을 읽기만 함. -
읽을 때마다 서버가 계획을 다시 계산하는 자리 세 곳 정리 (2026-09-06 마무리) —
get_section_detail이 조회할 때마다 ① 포장 구간 맞추기(_enforce_pavement_ranges) ② 세월교 노면 하강(_enforce_ford_surface_drops) ③ 설계 미지정 측점 기본 설계 프리뷰(_attach_default_designs) 를 돌림. 셋 다 「저장분이 낡을 수 있다」는 이유로 붙은 읽기 시점 보정임. 0-4 에서 [저장]·[확정] 때 서버가 정본을 다시 만들게 했으므로, 저장 쪽을 믿을 수 있으면 읽기는 읽기만 하면 됨. 옛 프로젝트 저장분이 걸리므로 화면 검증과 함께 걷어낼 것.- 마무리(2026-09-06) — ①·②는 저장 시점으로 옮겼고, ③ 은 저장분이 있으면 아무 일도 안 하는 폴백임을 수치로 확인: 용화 프로젝트 조회에서 측점 67곳 전부 저장된 설계가 실려 폴백이 한 번도 돌지 않음(0곳). 저장된 적 없는 비정규 측점만 이 길을 탄다.
-
B05 배수관 편집이 세션에 안 쌓이던 것 고침(2026-09-06) — 등록표에
pipes초안(프로젝트 범위)을 되살리고, 배치가 바뀌는 순간(추가·이동·삭제) 목록을 초안에 담게 함. 내보내기는flushPendingPipes한 창구로 모아 B05 [임시저장]·B06 [저장]·[확정] 모두에서 부름(자동저장 없음). 자체검증 — 초안으로 정본 11 → 10개 저장·초안 비움, 되돌려 11개 복구. -
서버가 계산해 저장하는 값과 프론트가 보내 저장하는 값이 같은
design딕셔너리에 섞여 있음 — 재계산이 사용자 값을 덮지 않게 지키는 것이preserveUserFields하나뿐. 0-4 에서 「사용자 값」과 「계산 값」을 키 이름으로 갈라 둘 것.- 그 위험이 실제 결함이었음 — 고침(커밋
b6941bd2, 2026-09-07). 같은 목록이 세 곳에 흩어져 있었고 서로 달랐음. 브라우저(PRESERVED_KEYS)는extra_spans(다단 구간값)를 살렸는데 서버 둘은 안 살렸음 — ①B06_Section_Router_Design._USER_TOUCHED_KEYS(포장 강제·세월교 노면 하강 재계산) ②B06_Section_Router안의 인라인 사본(단측점 설계 갱신). 그래서 포장 구간이나 세월교가 앉은 측점이 다시 계산되면 사용자가 넣은 다단 구간값이 조용히 사라졌음. 서버 목록을 공개 이름USER_TOUCHED_KEYS한 벌로 모으고extra_spans를 넣음. 라우터 사본은 지움. 시험tmp/tests/test_b06_user_touched_keys.py3건 — 목록이 다시 갈라지면 깨짐.pytest412 passed. - 본안 재설계 (2026-09-07 전수 조사 뒤 확정 — 개명은 하지 않음)
조사해 보니
design키는 두 갈래가 아니라 세 갈래였고, 위험한 칸은 하나뿐이었음.- ① 사용자 값인데 재계산 입력으로 되먹여 저절로 살아남는 것 8개 —
ground_type·section_mode·ditch_side·ditch_type·paved·two_stage_slope·ditch_enabled·rock_boundary_offset_m.enforce_pavement_ranges가 이 값들을compute_cross_design인자로 다시 넣음 (B06_Section_Router_Design.py:176~190). 보존 목록에 없어도 안 사라짐. - ② 베껴 넣어야만 살아남는 것 12개 —
USER_TOUCHED_KEYS10개 +status·pavement_suggested. 계산이 만들지 않는 값이라 목록에서 빠지면 그 자리에서 사라짐.b6941bd2가 바로 이 칸에extra_spans가 빠져 있던 것. - ③ 계산 값 24개 — 면적·설계선·계획고·경사·폭·확폭 등. 면적은 브라우저도 보내나 [저장]에서 서버가 다시 내므로 정본은 서버.
- 진짜 취약점은 「목록이 네 벌」인 것 — 같은 키 집합을 손으로 나열한 자리가 넷임:
ⓐ
B06_Section_Router_Design.pyUSER_TOUCHED_KEYSⓑB06_Section_Cross_Refresh.tsPRESERVED_KEYSⓒB06_Section_Router_Confirm.py:120~160의if patch_item.X is not None:한 줄씩 ⓓB06_Section_Section_Store.ts:176부근의put("X", design.X)한 줄씩. 새 사용자 값을 넣으려면 넷을 다 고쳐야 하고 하나만 빠지면 조용히 사라짐 — 오늘 결함 둘이 정확히 이 모양이었음. - 결론: 접두어 개명·딕셔너리 분할은 하지 않음. 저장된 모든 프로젝트 JSON 을 옮겨야 하고 읽는 쪽이 파이썬·TS·3D·도면·수량까지 넓은데, 얻는 것(「목록을 안 잊는 것」)은 아래로도 얻어짐. 마이그레이션 없이 같은 효과.
- ① 사용자 값인데 재계산 입력으로 되먹여 저절로 살아남는 것 8개 —
- 그 위험이 실제 결함이었음 — 고침(커밋
-
본안 — 목록 일원화 + 불변식 시험 (2026-09-07, 커밋
744059ae. A안 채택)- 불변식 시험 — 통과. 「
CrossSectionPatch의 사용자 필드는 반드시 ①(재계산 인자) 이거나 ②(보존 목록) 이어야 한다」. 몰랐던 구멍 없음 — 지금 코드가 전부 걸림.b6941bd2를 사전에 잡았을 시험임. - 손나열 두 곳 제거 — 확정·저장 payload 조립(
B06_Section_Router_Confirm.py)의if patch_item.X is not None:11개를 스키마 통째 덤프 + 최상위 None 걷기로, 브라우저 payload(B06_Section_Section_Store.ts)의put(...)10줄을 목록 순회로 바꿈.B06_Section_Cross_Refresh.ts가USER_TOUCHED_KEYS를 내보내고PRESERVED_KEYS는 거기에 상태 둘을 더해 만듦 — 목록이 갈릴 자리가 없어짐.- 중첩 None 은 남겼음 — 기슭막이 4축의
d: null은 「자동」이라는 뜻이 있는 값임. - 다섯 번째 자리는 없었음. 넷이 전부고 그중 둘은 타입 선언이라 정당함.
- 중첩 None 은 남겼음 — 기슭막이 4축의
- 보존 시험 — 포장 재계산 뒤 ② 12개가 남는 것 + ① 8개가 인자로 실제 전달되는 것.
pytest442 통과 · 실패 0. 저장 형식 안 바뀜.
- 불변식 시험 — 통과. 「
-
🔴
two_stage_slope— 사용자의 「켬」이 영구히 사라지는 결함 (2026-09-07)- 한 키가 요청과 결과를 겸함. 엔진이 적용 결과를 내보냄
(
B06_Section_Engine_Design.py:667"two_stage_slope": bool(geometry.two_stage), TS 짝common_util_cross_design.ts:387). 그래서 사용자가 켜도 엔진이 못 쓰면false가 저장되고, 그false가 다음 재계산 인자로 되먹여져 「켬」이 영구히 사라짐. - 읽는 쪽 전수 조사 — 「실제로 적용됐나」로 읽는 곳이 하나도 없음 (2026-09-07).
전부 「사용자 설정」으로 씀: 재계산 인자(
B06_Section_Router_Design.py3곳 ·B05_Profile_Router_Confirm.py:155) · 화면 상태(B06_Section_UI_Cross_Design.ts:330?? true) · 세션 우선(B06_Section_Cross_Refresh.ts:209).B06_Section_Common.ts:124는undefined인 옛 저장분 판별이지 결과 판정이 아님. - ⇒ 결과 키를 새로 뺄 필요 없음. 엔진 둘이
geometry.two_stage(결과) 대신 받은 요청값을 내보내게 하면 됨 — 2줄. 저장 형식 안 바뀌고 옛 저장분도 그대로 읽힘. - 엔진 둘(
B06_Section_Engine_Design.py·common_util_cross_design.ts)이geometry.two_stage(결과) 대신 받은 요청값을 내보냄 — 두 줄 (2026-09-07 커밋b8f0f7ad). - 거울 시험은 새로 안 만듦 — 기존
test_b06_cross_design_mirror.py가 결과 딕셔너리를 키 단위로 통째 대조하고two_stage_slope가 그 안에 있음. 한쪽만 고치면 그 시험이 깨지므로 그물이 이미 있음. - 새 시험
tmp/tests/test_b06_two_stage_slope_kept.py4건 — 토사에서 켬 유지 · 되먹임 왕복(저장값을 인자로 다시 넣어도 안 눌림) · 끔도 유지 · 「2단은 설계선이 그린다」. 토사 측점으로 세움 — 손실이 실제로 나던 조건 그대로.pytest446 통과 · 실패 0. - 잃는 것이 없음을 확인 — 「2단 사면을 실제로 그리는 판정」은 이 키가 아니라
설계선 기하(
design_line) 임. 암 지반은 켬·끔에 따라design_line이 달라지고, 토사 지반은 켜든 끄든 같음(엔진이 애초에 안 쓰는 자리). 그래서 「켰는데 안 쓴 측점」 구분이 저장분에서 사라져도 그림은 그대로임. 저장 형식 안 바뀌고 옛 저장분도 그대로 읽힘.
- 한 키가 요청과 결과를 겸함. 엔진이 적용 결과를 내보냄
(
-
위 표의 시간 두 열을 같은 회차로 다시 잼— 불필요해짐. 0-8 이 전후를 같은 창·같은 프로젝트에서 다시 쟀고, 그 표가 지금 기준임. 이 표는 계산 자리 지도로만 씀. -
uphill(3D 램프로 바꾼 측구 방향)이 B05 [임시저장]에만 실리고 B06 [저장]·[확정]에는 안 실리던 것 —flushUphillOverrides를 만들어 B06 저장 앞단(flushPendingEdits)에서 호출(횡단 patch 보다 먼저 나가 사용자 수정이 위에 얹힘). -
pipes등록 항목은 읽는 곳도 쓰는 곳도 없는 죽은 자리였음 — 삭제. 관 위치 정본은pipe_points.json이고 화면이 [저장] 때savePipes()로 바로 내보냄. (2026-09-06 같은 날 오후에 되살림 — 위 줄 참조.) -
자체검증 — 짝마다 거울 테스트로 같은 입력에 같은 값이 나오는지 수치 대조 (2026-09-07) — 가장 중요한 짝에 거울 테스트가 없었음. 배수관 세트·구조물 벽에는 있었는데, 수량에 바로 닿는 횡단 설계선·단면적 짝 (
B06_Section_Engine_Design.compute_cross_design↔common_util_cross_design.ts)에는 없었음.tmp/tests/test_b06_cross_design_mirror.py신설.- 태운 갈래 8가지 — 지반유형 셋(토사·리핑암·발파암) · 좌/우 절토 · 일반/L형 측구 · 포장+측구없음 · 2단 경사 켬/끔 · 세월교 노면 하강 · 곡선부 확폭(반경표·저장값, 좌/우) · 지반선 결측 구간. 표준단면 수치는 파이썬 config 를 그대로 TS 에 넘겨 산식 차이만 잡음.
- 결과 — 지금은 두 쪽이 완전히 일치함(갈린 항목 0). 딕셔너리를 재귀로 훑어 어느 항목이 갈렸는지 경로까지 찍음.
- 시험이 헛돌지 않는지도 확인 — 값 1mm·설계선 좌표 2mm 어긋남과 키 사라짐을 전부 잡음, 같은 것끼리는 통과. 절토·성토 면적이 실제로 나오는 경우가 섞여 있는지도 따로 검사.
- ⚠ 함정 —
tsc가 낸 상대 import 에 확장자가 없어 Node ESM 이 못 읽음(번들러가 붙여 주던 몫). 짝 파일이 서로를 부르므로 시험이.js를 채워 넣음. - ⚠
tmp/tests는 git 밖이라 이 시험은 내 폴더에만 있음 — 다른 창은 못 받음. 저장소 규칙(CLAUDE.md 4장)이 그래서인데, 거울 테스트처럼 짝이 갈리는 것을 막는 그물은 창마다 따로 있어야 뜻이 있음. 사용자 판단이 필요한 지점으로 남김.
-
🔴 표준단면이 「그 탭 안에서만」 살아 서버와 갈림 (2026-09-07 ⓑ 조사에서 드러남)
std-cross는 sessionStorage 라 탭을 새로 열면 사라짐. 그때 서버는 저장분(사용자가 고친 표준단면)으로 계산하고 브라우저는 config 기본값으로 계산함 ⇒ 같은 측점이 두 곳에서 다르게 나옴.- 드러나는 조건 — 표준단면을 한 번이라도 고친 프로젝트를 새 탭에서 열 때. 안 고친 프로젝트는 둘이 같아 티가 안 남. 오늘 계통(조용히 값이 갈림)과 같음.
- 고치는 방향 —
sections/context(또는 상세)가 저장분을 함께 주고, 세션이 비면 그것으로 세움. 「context 는 config 기본값」이라는 지금 계약이 바뀌므로 응답에 필드 하나가 늘어남 (기존 필드는 그대로 — 옛 화면도 깨지지 않음). - 고치기 전 — 진짜 갈렸음(2026-09-07, 용화 5601e828 · route 169). DB 저장분과 config
기본값을 값으로 대조(표기 차이는 걸러냄):
rock.cross_slope_pct.max저장 5 vs 기본 3.0 ·rock.ditch.top_width_m저장 0.9 vs 기본 0.69, 그 밖은 일치. 화면이 받던 응답에는 저장분 칸 자체가 없었음 — 브라우저는 3%·0.69m 로, 서버는 5%·0.9m 로 계산했음. 암반 측점의 횡단 모양이 두 곳에서 달랐던 것. - 응답에
stored_standard_cross_section을 더함(기존 칸은 그대로 — 옛 화면 안 깨짐). 세우는 자리는 두 화면이 함께 지나는fetchSectionContext한 곳이고 세션이 비었을 때만 세움 — 그 탭에서 고친 값은 안 건드림. 커밋72e50b3e·pytest454 통과. - 빈 새 탭 실측 — 새 탭에는
std-cross가 없고([]), B06 진입 후 세션이rock.ditch.top_width_m=0.9·rock.cross_slope_pct.max=5로 저장분으로 섬. 검증 탭은 닫았고 사용자 탭은 안 건드렸음.
0-11. 노선 [확인] 한 번이 3분 반 (2026-09-06 실측, 0-10 에서 갈라 나옴)
-
계측 자리 만듦 (커밋
41852da3) —B03_FileInput_Service_Chain._log_steps가[계측] {이름} 총 {초} = 단계 초(비중)한 줄로 남김. 지금 걸린 곳 셋: 「배수·관·측점」 · 「재확정 체인」 · 「노선 [확인] 재계산」. -
단계별 실측 1회 (2026-09-07, 용화 b269ea34) — 범인은 하나임.
-
181초가 어디로 가는지 가름 (2026-09-07) — 엔진 자체 로그가 범인을 안 재고 있었음.
preview_stages의started = time.perf_counter()가resolve_primary_region뒤에 있어서(..._Analyze.py) 「단계 분석 104.3s」 는 그 앞을 뺀 값이었음.get_primary_region전체를 재니(용화 5601e828, 1회): -
진범을 잡아 고침 (커밋
9317ad31) —ElevationSampler하나였음.- 가는 길:
resolve_primary_region을 둘로 가르니build_contour_cloud0.8s(무죄) ·build_primary_region256.6s. cProfile 로 그 안을 보니ElevationSampler.at이 호출 4번에 301초,__init__은 2.1초. 따로 재니at()첫 호출 한 번이 1,481초(2점을 물었을 뿐), 그 뒤 호출은 0.0초. - 원인:
LinearNDInterpolator가 들로네 삼각망을 첫 호출 때 만드는데 등고선 구름을 통째로(317,348점) 넘기고 있었음. Qhull 이 등고선처럼 촘촘히 늘어선 점에 약해 같은 입력에도 256~1,481초로 편차가 큼. - 고친 법: 표고를 묻는 자리는 도로 교차 노드에 닿은 세류 조각 몇 개뿐(나머지 1,153개는 확산으로만 정해짐). 그 조각들만 먼저 골라 그 둘레 100m 안 등고선만 남겨 삼각망을 만듦. 여유 100m = 등고선 재샘플 간격(5m)의 스무 배라 물어볼 점은 언제나 볼록껍질 안쪽이고 보간값이 그대로임.
- 실측 — 보간 구름 317,348 → 4,367점, 1차 영역 256.6s → 43.8s
(⚠ 뒤 측정은 기기 부하가 9배였음: 「준비」가 5.1s → 45.7s. 깨끗한 값은 재측정 대기).
결과 완전 동일 — 1차 영역 266,697㎡ · 격자 545×835 · 268,456셀 ·
노선 이탈 0m/1079m · 상류망 1 / 하류망 109 / 미연결 1,153.
pytest409 passed. - ❌ 빗나간 추정 둘(기록으로 남김) — ① 「페이로드·파일 쓰기가 181초」 → 실제 1초
② 「
build_contour_cloud가 먼 등고선까지 shapely 로 만들어 느리다」 → 실제 0.8초. 엔진 자체 로그(단계 분석 104.3s)가 범인을 아예 안 재고 있어서 두 번 헛짚었음.
- 가는 길:
-
깨끗한 기기에서 끝까지 1회 재측정 (2026-09-07, 보조 창 8001) — [확인] 292.9s → 119.5s(브라우저 체감 124.3s). 1차 영역 285초대 → 2.6초.
-
폴백 그물 하나 놓음(커밋
58bfe72a) — 구름을 좁힌 뒤 「둘레 100m 안에 등고선이 없는 자리」는 볼록껍질 밖이라 최근접 정점 값으로 빠지고, 그러면 상·하류 판정이 갈릴 수 있음. 용화에서는 안 일어났으나 다른 현장에서 조용히 갈리지 않게 빠진 점 수를 로그로 남김. 계산은 안 바뀜. -
깨끗한 기기에서 [확인] 재측정 (2026-09-07, 보조 창 2회) — [확인] 98.9s / 114.9s, 확장 95.8 → 77.9s / 88.5s. 「보간 구름을 좁힘」 로그가 실제로 찍히는 것도 확인함(옛 코드 함정 회피).
- ⚠ 회차 편차가 큼 — 같은 코드·같은 입력인데 98.9 vs 114.9(16%), 1차 영역만도
2.3 vs 6.8s(3배). 그래서 「몇 초가 됐다」를 한 숫자로 말하면 안 됨.
믿을 값은 한 프로세스 안에서 옛/새를 번갈아 잰 것 — 밴드 EDT 91단
5.2s → 2.1s(2.5배),
build_contour_descent전체 8.0s → 5.1s. - 결과 동일성 통과 — 드리프트 수정 덕에 [확인] 두 번을 그냥 비교할 수 있었음. 관 10개(기본 1 + 보충 9) · 측점 60 · 배수관 측점 6개의 누가거리 (81.77 · 244.14 · 423.55 · 523.77 · 621.98 · 722.20)가 두 회차 소수 둘째 자리까지 일치, 노드 21 · 정점 115 로 깎임 없음.
- 중간에 한 번 헛돎 — 첫 판이 「창이 모자라면 단계 전체를 격자 전체로 되돌리는」 꼴이라
격자가 커질수록 폴백이 25/91 까지 늘어 이득이 사라졌음(확장 97.7s). 모자란 타일만
창을 4배로 넓혀 다시 재도록 고쳐 폴백 개념을 없앰(커밋
f1834465).
- ⚠ 회차 편차가 큼 — 같은 코드·같은 입력인데 98.9 vs 114.9(16%), 1차 영역만도
2.3 vs 6.8s(3배). 그래서 「몇 초가 됐다」를 한 숫자로 말하면 안 됨.
믿을 값은 한 프로세스 안에서 옛/새를 번갈아 잰 것 — 밴드 EDT 91단
5.2s → 2.1s(2.5배),
-
① 등고선 굽기 — 진짜 원인은 다른 데 있었음 (보조 창 커밋
1553f23c)- 「옛 격자 옮겨 붙이고 테두리만 굽기」를 실제로 만들어 재니 오히려 느렸음(3.2s →
10.6s).
rasterize호출당 고정 비용 때문 — 창을 넷으로 나누면 166단 × 4 = 664회 호출이 되고 창마다 선 목록을 다시 훑음. 걸치는 선만 넘겨도 3.8s 로 여전히 손해. - 그 실험에서 진짜 원인이 드러남 — 굽기 자체는 0.8~2.0초뿐이고, 나머지는 등고선 피처
4,200개를 회차마다 다시
shape()로 푸는 값이었음. 격자와 무관함. - 푼 결과를 한 번만 만들어 쓰게 함(같은 목록·같은 하한일 때만, 최근 2벌 보관).
같은 격자 연속 4회 2.66 · 1.90 · 1.99 · 2.03s(2회차부터 재사용), 결과 배열 4회 동일.
build_contour_descent전체 12.8s → 7.2s, 값은np.array_equal로 전부 동일. - 창·테두리 기계장치는 전부 걷어냄 — 남은 것은 캐시 한 벌뿐.
- 부수 확인 —
levels는 피처 전체에서 나오므로 격자와 무관. 걱정하던 「테두리에 새 표고가 들어와 단계가 늘어난다」는 안 일어남.
- 「옛 격자 옮겨 붙이고 테두리만 굽기」를 실제로 만들어 재니 오히려 느렸음(3.2s →
10.6s).
-
🔴 요청이 하나도 없는 서버가 CPU 70%를 먹던 것 — 원인 확정·차단 (2026-09-07)
- 범인은 저장소를 되가리키는 정션이었음 — `B07_DesignDetail\openwebcad
0-7. 노선이 바뀌면 세 벌은 어떻게 되나 — 규칙 확정 (2026-09-06 사용자 확정)
-
위 5개가 전부 실제로 서 있음 — 대조 완료(2026-09-07). 0-2·0-10·0-12 구현에 이미 들어갔고, 새로 만들 것은 없었음. 자리는 아래.
- ① 계획노선을 고칠 길 —
B05_Profile_UI_RouteEdit.ts모달. 노드 끌기·두 번 클릭 삽입· 오른쪽 클릭 삭제·곡선 지우기/넣기·R 입력·손잡이 끌기. - ② 배수유역부터 다시 도는 경로 —
B05_Profile_Router_Replan.py:371run_redesign_chain. 모달 [확인]이 부름(_UI_RouteEdit.ts:595), 안내도 「배수유역부터 다시 계산 중」(:573). - ③ 구조물·배수관 — 규칙 6 대로 갈려 있음. 관 지점은
_Router_Replan.py:303·310이 체인 전에clear_pipe_points로 지우고 새 노선에서 새로 계산(투영 이월 안 씀). 그 밖 구조물은structures.json을 안 건드려 누가거리를 그대로 이어받음. - ④ 두 노선을 함께 그림 —
_UI_RouteEdit.ts:197예상노선 점선(회색) ·:205계획노선 실선(주황). 규칙 8 그대로. - ⑤ 프로젝트 범위 초안 비우기 —
_UI_RouteEdit.ts:578clearDrafts+clearResults. 등록표(A00_Common/b_page_state.ts:92·94·99·102)에서structures·uphill·pipes·std-cross가scope:"project"라 한 줄에 지워짐. - 수치 확인 둘 —
· 노선 범위 초안은 이 호출로 안 지워짐(
stateKey가 routeId 없으면null을 냄). 그래도 규칙은 지켜짐 — [확인]마다 새 노선 행이 생겨 키가 저절로 갈림 (_Router_Replan.py:382get_latest_route). 근거: 용화 5601e828 세션에…:145·…:161·…:169세 노선의 초안 키가 남아 있음 = 재계산마다 노선 id 가 바뀐 증거. · [초기화] = 복사가 맞음 —reset_route_plan(:520~536)이 수정본 파일만 지워 (working_path.unlink()) 설계 계통이 원본을 읽게 하고 재계산함. 노선 행을 지우거나 첫 스냅샷을 되돌리지 않음 — 옛 동작과 다름.
- ① 계획노선을 고칠 길 —
-
옛 노선 초안이 세션에 쌓임 (같은 대조, 위생 문제) — 145·161 잔재가 실제로 남아 있음. 기능 문제는 아니고 용량·혼동 문제. 「노선 변경 때 그 프로젝트의 route 범위 초안도 싹 비우기」 한 줄이면 됨.
- 고침(2026-09-07 보조 창) — 원인은 「안 지웠다」가 아니라 못 지웠다임.
노선 변경 자리는 새 번호를 아직 모르니
clearDrafts(projectId)로 부르는데,stateKey가 노선 번호 없이는null을 내어 route 범위 키가 한 개도 안 나갔음.clearState한 곳에서 노선 번호가 없으면aislo:<통>:<이름>:<프로젝트>:로 시작하는 키를 모두 쓸어 내게 고침 —clearDrafts·clearResults가 같이 나음. - 안전 확인 — 옛 노선치를 읽는 자리 없음(
readState호출 8곳 전부 전역·프로젝트 범위), 노선 복원도 새 route id 를 발급하므로 옛 키는 다시 안 불림. - 자체검증 —
tmp/tests/test_page_state_route_sweep.py3건. 옛 코드로 같은 시험을 돌리면proj-1의 145·161·169 세 벌이 그대로 남아 깨짐을 확인(헛도는 시험 아님). 노선 번호를 주면 그 한 벌만 나가는 것도 봄. 전체pytest tmp/tests/ -q511 passed · 18 skipped. - 값싼 실화면 확인 — 통과, 닫음(2026-09-07). 전체 재계산 없이 화면이 쓰는 모듈을 그대로
불러(
import('/b_page_state.ts')) 용화에 노선 145·161·169 초안을 세운 뒤clearDrafts·clearResults를 노선 번호 없이 부름. 용화 키 8개 → 0개(세운 초안 셋 + 노선범위 결과…:149+ 프로젝트범위 넷), 활성 프로젝트(8879c53b) 키 10개 → 10개 한 글자도 안 변함 (쓰던 값 안 날아감), 세션 전체 56 → 48. 화면 그대로(횡단 카드 273장). - 실화면 확인(2026-09-07, 전체 재계산 없이) — 공용 브라우저에서 화면이 쓰는 그 모듈을 그대로
불러(
import('/b_page_state.ts')) 용화(5601e828)에 노선 145·161·169 초안을 세운 뒤clearDrafts(용화)·clearResults(용화)를 노선 번호 없이 부름. · 용화 키 8개 → 0개(세운 초안 셋 + 노선범위 결과…:149+ 프로젝트범위 넷 전부). · 활성 프로젝트(8879c53b) 키는 10개 → 10개, 한 글자도 안 변함 — 쓰던 값이 안 날아감. · 세션 전체 56 → 48(딱 용화 8개). 화면도 그대로 섬(횡단 카드 273장).
- 고침(2026-09-07 보조 창) — 원인은 「안 지웠다」가 아니라 못 지웠다임.
노선 변경 자리는 새 번호를 아직 모르니
0-8. 속도 개선 — 한 묶음 기록 (2026-09-06 완료, 두 창 공동)
-
유토 배분 선반입 실사용 확인 ⓒ (2026-09-07, 공용 브라우저 5173 · 용화 5601e828) — 예전 모양 그대로 그려짐. 범례 「토량 분배」를 실제로 눌러 확인:
- 켜짐 반영 —
masshaul-visible-v5가["cross"]→["cross","balance"] - 운반 블록(장비 띠) polygon 0 → 9개(면 다각형 점 9
73개 + balloon 도형 36점) - balloon 글자 45개 — 「종무대 1 · Q=33㎥ · L=10.0m · EA=12㎥ · RR=21㎥ · BR=0㎥」, 「도쟈 2 · Q=167㎥ · L=47.5m …」 · 「EP -7,250.6㎥」
- 평형선·경계현·평균운반거리 — 파선 노드 12개, 패턴 셋(
3px,2px·6px,4px·2px,3px) - 전체 맞춤도 살아 있음 — viewBox 가 4,711 → 907 로 줄어 곡선 전체가 한 화면에 듦
- 선반입 칩(「다시 계산 중…」)은 요소만 있고 화면에는 안 보임(
display:none) — 정상 - 만진 것(범례·창 둘) 전부 원래대로 되돌려 놓음.
- ⚠ 함정 하나 더 — 유토곡선 손잡이는 종단 창 안에 있음. 종단이 접혀 있으면
display:none이라 클릭이 15초 타임아웃으로 실패함. 종단을 먼저 펼 것.
- 켜짐 반영 —
-
저장 왕복을 1초 아래로 — 이미 달성(2026-09-07 보조 창 실측, b269ea34 · 측점 60 · route 165). 저장 왕복 802ms, 상세 조회 207·196ms.
- 내부 쪼갬(서버 재계산 0.6s) — 상세+DB 조회(병렬) 0.1s 19% · 포장·세월교 보정 0.0s 3% · Node 번들 0.1s 22% · 정본 저장 0.4s 57%. 계획에 적혔던 셋(242·241·251ms)은 지금 100·100·— 수준이고, 가장 큰 조각이 「정본 저장」으로 바뀌었음.
- 단서 — 이번 측정은 빈 patch(편집 없음)라 「편집 반영」 몫은 안 잡혔음.
- 「방금 커밋한 값을 다시 읽지 않기」는 하지 않기로 함(2026-09-07 판단).
get_section_detail은 단순 재조회가 아니라 DB 설계 + 파일 기반 지반·설계선 + 읽기 시점 보정 + 행 없는 측점을 합친 한 벌을 만듦. 부르는 쪽은 patch 만 들고 있어 「그대로 쓸」 재료가 없고, 브라우저 상세를 받아 쓰는 길은 5장 금지임. 이득도 0.1s(19%)뿐. 더 줄일 일이 생기면 정본 저장 0.4s(merge 쓰기) 부터 볼 것.
-
3D 코리도를 브라우저 보관함에 담음 (2026-09-06, 커밋
e2cc5e75) — 저장본 열쇠가 맞을 때는 매번 16.9MB 를 받았고, 브라우저 보관이 모듈Map이라 새로고침 한 번에 날아가 또 받았음(보조 창 실측: 첫 로그인~B05 도달 29MB 중 16.9MB). 해시 질의는 「낡았을 때」만 막았지 맞을 때는 그대로였음.b_asset_cache에readCachedBytes·writeCachedBytes·purgeAssetsWithPrefix를 더해 코리도 조회가 보관함을 먼저 보게 함. 주소에 열쇠가 박혀 정본이 바뀌면 저절로 다른 주소가 되고, 담기 전에 앞머리가 같은 옛 보관본을 치워 17MB 짜리가 쌓이지 않음. 자체검증(보조 창, 저장본이 최신인 프로젝트에서 보관함을 비우고 시작) — ① 첫 진입 코리도 1건 16.89MB ·source:"stored"② 새로고침 1회 → 0건 · 0.00MB ③ 새로고침 2회 → 0건. 해시 동일(97fb20a9)로 3D 도 실제로 섰음. 첫 진입 16.9MB 는 그대로 — 보관함은 「다시 열 때」를 없애는 것이지 첫 수신을 줄이는 것이 아님. 첫 수신을 더 줄이는 것은 하지 않기로 함(부동소수 배열이라 압축 절반· 자릿수 87% 잔존을 이미 쟀음). -
[3D 업데이트] 가 저장본을 안 올리던 것 (커밋
710169fd) — 눌러도 브라우저가 만들기만 하고 PUT 이 없었음(저장 시점이 B05→B06 이동뿐, 2026-08-23 확정). 누른 뒤 새로고침하면 저장본이 낡은 채라 다음 사람이 또 만들었음. 버튼 경로 끝에서saveCorridorIfDirty를 부르고, 그 함수가 PUT 성공 뒤 봉투를 보관함에도 담게 함 (옛 열쇠 자리는 치움) — 그러지 않으면 다음 진입이 새 열쇠 주소로 16.9MB 를 또 받음. 실측 확인은 보조 창(저장본이 최신인 프로젝트)이 진행.
0-2. 계획노선 편집 — 예상노선을 바꿔 쓰는 길 (2026-09-06 사용자 지시)
-
모달 안에 수치지형 등고선 + 예상노선을 그림 — 배수유역도와 같은 지도 도구를 씀.
-
예상노선은 폴리라인이므로 선 성분 교차점마다 노드를 놓음(정점 323개에 노드).
-
노드 옮기기·끼우기(선 두 번 클릭)·지우기(오른쪽 클릭) — 곡선(R) 성분은 남음(아래).
-
고치는 동안 예상노선(점선)·계획노선(실선)이 함께 보임.
-
[확인]을 누르면 배수유역부터 다시 계산 — 재확정 체인 재사용(용화 실측 203초).
-
계산 도중 화면을 덮는 안내(오래 걸리는 조작이라 오버레이) — 중간 취소는 남음(아래).
-
업로드 원본(예상노선)
expected_route.csv신설, 계획노선planned_route.csv를 따로 둠. -
설계 계통(
load_design_route)이 계획노선 → 예상노선 순으로 읽어 계획노선 기준으로 돎. -
노선이 바뀌면 무엇이 다시 서는지 규칙 확정 — 0-7 로 옮겨 적음(2026-09-06 사용자 확정). 요지: 예상노선(원본)·계획노선(수정본) 두 벌, 편집은 계획노선만, [초기화]는 원본 복사, 노선이 바뀌면 배수유역부터 다시, 구조물·배수관은 새 노선으로 이동만, 계산은 모달 [확인] 에서만 시작.
-
자동 체인이 노선을 세우는 자리에서 예상노선 정본을 함께 씀(전처리 전에 두 벌).
-
모달에 예상노선(점선)·계획노선(실선)을 함께 그림.
-
[확인] 뒤 재확정 체인 재사용 —
POST /route/replan이 고친 노선을 수정본에 쓰고 (조밀화) stage 2 제어점을 갈아 끼운 뒤 기존 체인을 그대로 태움. 편집 중에는 계산 없음. -
구조물(
structures.json)은 손대지 않아 옛 측점값 그대로 남음. -
횡단배수 지점은 새로 계산한 값을 씀 — 재계산 앞단에서 저장분을 지움 (용화 실측: 새 노선에서 기본 1 + 보충 10 = 11개로 새로 배치).
-
재계산이 끝나면 모달이 세션 초안·조회 캐시를 비움(
clearDrafts·clearResults). -
곡선(R) 성분 편집 — 0-12 에서 완료(2026-09-07). R 칸·곡선 지우고 넣기·곡선 시작·끝점 끌기까지 붙었음. 이 줄은 그쪽을 가리키기만 함.
-
실화면에서 [확인]까지 눌러 노선이 바뀐 뒤 B05·B06 화면이 새 노선으로 서는지 확인 (2026-09-07, 보조 창 8001 · 공용 브라우저) — 모달이 「노드 28개 · 곡선 13곳(R 12m)」로 열리고, [확인] 뒤 관 10개 · 측점 60 · 배수관 측점 6곳이 새 노선 기준으로 다시 섬. 두 회차를 이어 눌러도 값이 완전히 같음(노드 21 · 정점 115 · 배수관 누가거리 소수 둘째 자리까지) — 0-10 의 「깎임」 수정이 실화면에서 서는 것까지 함께 확인됨.
3-6. B06 구조물 추가 — 남은 확인 (2026-09-05 조사)
- 실화면 왕복 확인(2026-09-06) — B06 좌측 「구조물 배치」로 흙막이(8+0.0)를 넣고
[저장] → 정본 5 → 6건(판번호 6 → 7), 새로고침 뒤 목록에 「7+15.0~8+5.0 흙막이」
그대로. 서버 상세에도 160m 측점에 벽 제원이 붙음.
- 곁가지 하나 — 저장 직후에는 화면이 들고 있던 상세 사본에 새 벽이 아직 안 붙음 (다음 조회부터 붙음). 저장 뒤 상세 캐시를 버리게 고쳤고, 그 자리에서 캐시를 비우면 벽이 5 → 7개로 붙는 것을 확인함. 다만 저장 직후 한 번은 여전히 옛 사본이 잡혀 한 겹 더 볼 것(재현: 저장 직후 같은 화면에서 조회).
3-9. 소단(berm) 신설 — 절토 비탈면에 평평한 턱 넣기 (2026-09-07 사용자 지시)
-
①② 계단이 값에는 이미 실림 (2026-09-07) — 파이썬·TS 짝 완성, 거울 시험 10건 통과. 절토 면적 55.1 → 78.8㎡(기본 0.5m·3m).
- 기존 설계는 안 바뀜 — 소단을 안 주면 종전과 완전히 같은 값(설계선까지 동일). 무릎 방식을 「한 번만 꺾음」으로 그대로 지켰기 때문임.
- 시험이 어림을 두 번 잡아냄(기록용) — ⓐ 「늘어난 면적 = 폭 × 그 위 높이」로 잡았더니 11.797 vs 7.770㎡ 로 틀림. 설계선이 밖으로 밀리면 지반과 만나는 점도 함께 밀려 절토가 더 길어지기 때문. ⇒ 면적 대신 밀린 거리를 재는 것으로 바꿈. ⓑ 그 다음엔 「폭만큼 밀린다」로 잡았는데 그 표고 아래 소단이 둘이라 2배였음. 참값은 「그 아래 소단 개수 × 폭」. 둘 다 코드가 아니라 기대값이 틀렸던 것임.
-
③ 화면에 계단이 섰음 (2026-09-07 커밋
061d550e). 사진·수치 https://claude.ai/code/artifact/4200377e-498d-42c8-a99b-b5f113474229-
배선 — 세션 열쇠
berm(측점키 → 폭·간격·기울기)을 등록표에 두고 ① 브라우저 재계산과 ② 서버 미리보기 양쪽에 실었음. 암 경계선과 같은 길이라 「계획선을 고치면 계단이 사라지는」 일이 없음. -
절토량 전후 (실화면 8001·5174,
stale:false확인 후. 측점 4120.0m 에 소단을 놓고 계획고를 한 칸 올렸다 내려 전 구간 재계산) —4120.0m 토사 리핑암 절토 계 소단 없음 2.42 4.42 6.84㎡ 폭 0.5 · 3m (기본값) 3.24 4.86 8.10㎡ (+1.26) 폭 1.0 · 2m 5.03 7.93 12.96㎡ (+6.12) 옆 측점 4100.0m (안 놓음) 1.79 1.97 3.77㎡ 변화 없음 놓은 측점만 달라지고 옆은 그대로. 되돌리니 6.84 로 정확히 복귀. 정본 안 건드림 ([저장]·[확정] 안 누름, 서버 조회로
display_half_width_mnull 확인). -
cut_slope_segments도 넣음(파이썬·TS 짝) — 소단을 놓아도 구간별 경사비가 1.0 그대로 나오는 것 확인 ⇒ 법정 검사가 실효 경사에 안 속음. 거울 시험에 구간 대조 추가.
-
-
④⑤⑥ 폼 · 회귀 등록 · 소단측구 연장까지 끝남 — 아래 각 줄 참조.
-
🔴 소단이 암 경계를 다시 만나는 경우 — 「조용히 틀림」이었음. 미루지 않고 막았음 (2026-09-07 커밋
5a6617f2).- 무슨 일이 났나 — 소단을 지나 경계 아래로 되돌아가면 종전 「무릎 한 번」 규칙이 그 구간을 암인데 토사 경사로 그림. 토사 경사가 더 완만하니 절토가 더 크게 나오고 경고도 안 뜸.
- 드문 일이 아니었음 — 소단은 평탄한데 암 경계선은 지반을 따라 올라감. 지반 1:1 이면 폭 0.5m 소단 하나를 지나는 동안 경계는 0.5m 오르고 소단은 2°(0.017m)만 오름. ⇒ 소단이 있는 암 구간에서는 되돌아 들어가는 것이 오히려 정상. 「나중에」로 둘 수 없었음.
- 고침 — 경계를 오갈 때마다 꺾게 하되 소단이 있을 때만 켬. 소단이 없을 때 켜면 지금 측점 설계가 같이 바뀌므로(실측 0.0016m) 기본값은 종전 그대로 — 소단을 안 쓰는 프로젝트는 여전히 한 글자도 안 바뀜.
- 시험 — 경계를 뚫고 올라갔다가 소단마다 뒤처져 되돌아 들어가는 지형을 만들어 ① 두 규칙의 결과가 실제로 갈리고 ② 되돌아 들어간 구간이 암 경사라 같은 거리에서 더 높이 오르는 것을 고정. 거울 시험에도 그 경우를 한 줄 더해 파이썬·TS 일치 확인(12건). 전체 539 passed · 18 skipped.
- ⇒ 「무릎 하나뿐」 전제는 소단 경로에서 완전히 풀렸음. 소단 없는 경로만 종전 규칙으로 남았고, 그쪽은 사용자가 틀린 값을 받는 상태가 아님(소단이 없으면 지금까지와 똑같은 값).
-
법정 경사 검사가 무엇을 보는지 확인 — 답: 절토엔 없고, 성토엔 있는데 소단이 그것을 깨뜨림 (2026-09-07). 「깨질 전제」가 셋이 아니라 넷임.
- 절토측 — 법정 경사 검사가 아예 없음. 절토 경사비(
cut_slope_ratio)는 표준 횡단면 설정에서 오는 입력값일 뿐이고, 별표2 범위(암 1:0.30.8 · 토사 1:0.81.5)와 대조하는 코드가 없음. ⇒ 소단이 그것을 흐릴 위험도 없음. (그 검사를 나중에 만들 때는 반드시 소단 사이 구간 경사를 볼 것 — 실효 경사를 보면 위반이 사라진 것처럼 나옴. 아래 별도 항목.) - 🔴 성토측 — 있고, 지금 방식으로는 소단이 들어가면 틀린 값이 됨.
· 검사 — 「성토사면 길이 5m 이내, 초과 시 옹벽·석축 의무」(
성토_비탈면.md§2, 상수FILL_SLOPE_MAX_LENGTH_M). 횡단 카드 머리의 「성토사면 ≥23.43m」가 그 값임. · 지금 재는 법(B06_Section_UI_Cross_Fit.tsfillSlopeLengths) — 노견에서 지반과 처음 만나는 점까지의 수평 거리 × 경사 기울기. 주석에도 「그 사이 성토선은 1:n 직선」이라는 전제가 적혀 있음. · 소단이 들어가면 성토선이 직선이 아니게 됨 → 곱셈으로 내는 길이가 틀리고, 법정 판정이 「완만해졌으니 통과」로 잘못 나옴. 옹벽 의무 판정이 조용히 틀림 — 금액에 닿는 자리. - 성토 소단 +
fillSlopeLengths수정 — 한 묶음으로 끝냈음 (2026-09-07 커밋db4f17fb·c7770b75). 옹벽 의무 판정이 소단을 제대로 봄. · 「소단 없는 측점은 값이 같다」 — 272측점 전수 대조, 달라진 곳 0. 구조로도 보장됨 (design.berm이 없으면 종전 식(수평거리 × 기울기)을 그대로 타 계산 자체가 안 바뀜). · 소단을 놓으면 판정이 바뀜 (측점 2820.0m, 성토사면이 긴 자리) — 소단 없음 ≥32.54m(옹벽·석축 의무 대상) → 폭 0.5m·3m마다 ≥3.00m(5m 이내, 의무 해소. 3.00m 은 소단 간격 그대로). 옆 측점 2840.0m(안 놓음)은 ≥32.54m 그대로. · ⚠ 실화면이 두 가지를 더 잡았음 — 시험만으로는 못 잡았을 자리 ① TS 결과에 소단을 안 실었음 — 파이썬만 되싣고 브라우저 판을 빠뜨림. 판정은 브라우저에서 도는데design.berm이 없어 종전 식으로 갔음. 짝을 빠뜨린 것. ② 소단을 「폭」으로 찾으면 못 찾음 — 설계선 꼭짓점에 지반 샘플(0.5m 격자)이 섞여 폭 0.5m 소단이 두 도막으로 쪼개짐(실측 평탄부 0개). 게다가 설계선이 오프셋 오름차순이라 우측(음수) 성토면은 같은 소단이-기울기로 나와 부호를 그대로 대면 못 찾음. ⇒ 기울기로 가르게 고침 — 소단 2°(0.035) vs 성토 1:1.22.0(0.50.83). 성토 기울기의 절반만 잡아도 갈리고, 쪼개져도 부호가 뒤집혀도 걸림. 단위 시험은 꼭짓점을 직접 만들어 쓰니 「샘플 격자에 쪼개짐」·「우측은 부호 반대」가 재현되지 않음. 화면 수치를 눈으로 본 것이 잡았음. 사연을 코드 주석에 남겼음.
- 절토측 — 법정 경사 검사가 아예 없음. 절토 경사비(
-
소단을 구조물로 옮김 — 끝(2026-09-07 커밋
7833b9e6).- 「사면안정」 군은 이미 있었음 — C군이 그것임(
C: "C 사면안정"). 군 신설 없이 C군에 「소단」 타입만 냄. 목록: 옹벽·돌쌓기(찰)·돌쌓기(메)·흙막이·큰돌쌓기·소단. - 폼은 다른 C군과 같은 꼴 — 기준 측점 2칸 + 길이 10 · 전 5 · 후 5 · 폭 0.5 · 간격 3 · 안쪽 기울기 0°(2 → 0 정정 반영, 코드 주석·시험 근거도 함께 고침).
- ⚠ 안 뺐으면 큰일 날 뻔한 자리 — 소단은 C군 구간형이라 그대로 두면 「독립 기슭막이」로
그려짐(
withDraftWalls·load_wall_structures가 C군 구간형을 전부 벽으로 봄). 파이썬·TS 양쪽 벽 필터에서 뺐고 화면에서 벽 폴리곤 0개 확인. - 실화면(측점 141+0.0 에 소단) — 목록 「140+15.0~141+5.0 소단」 · 절토 6.49 → 7.47㎡ · 성토 47.72 → 89.84㎡ · 성토사면 ≥32.54m → ≥3.00m(옹벽 의무 해소가 구조물 경로로도 작동) · 옆 측점 그대로 · [삭제] 하니 정확히 복귀.
- 기하는 한 줄도 안 건드림 — 입구만 옮겼고 계산 계통(브라우저·서버·
USER_TOUCHED_KEYS· 옹벽 판정)은 그대로. 좌측 별도 패널은 모듈째 삭제. - ⚠ 알아 둘 것 — 성토면 소단은 성토량을 크게 늘림(47.72 → 89.84㎡, 거의 두 배). 옹벽을 안 세우는 대신 흙을 더 쌓는 맞바꿈임. 금액이 어느 쪽으로 가는지는 현장마다 다름.
- 「사면안정」 군은 이미 있었음 — C군이 그것임(
-
소단측구 — B군 항목에 같은 꼴 옵션을 붙였음(폭·간격은 소단을 따르고 기울기만 사면 쪽). 소단이 서면서
PENDING_TYPE_IDS빈 칸이 풀려 연장 수량이 다른 구조물과 같은 길로 나옴 (시험을 「빈 칸」에서 「연장 100m」로 뒤집음). -
절토 비탈 법정 경사 검사— 폐기 (2026-09-07 사용자 확정). 사용자 지시 원문 — 「연암과 경암 / 발파암과 리핑암 선택은 횡단도에서 선택 안함. 사유는 향후 설계내역에서 설계자가 직접 비율로 지정하기로 함. 암반 지정과 범위 애매모호한 경우가 있어. 실무자는 그렇게 하기로 판단함. 대신 경고부분은 삭제해주고 대신 각도를 사용자가 넣을수 있게 반영. 전체 공통으로 변경하는 경우에는 기본값 지정으로 하면 되지만 횡단도 하나만 변경하는 폼은 가져야함」- 왜 폐기인가 — 암반의 지정·범위가 실무에서 애매함. 측점마다 암질을 못 박는 것이 오히려 틀림. 암질이 안 정해지니 별표2 판정 기준을 세울 수 없음. 하루 사이에 「매핑을 고르라」 → 「암질 버튼을 두라」 → **「아예 횡단도에서 안 고른다」**로 좁혀졌고, 마지막이 실무 판단임.
- 되돌린 것 — 카드 경고 배지 · 검사 모듈(
B06_Section_Cut_Slope_Check.ts) · config 별표2 범위표 · context 필드. (커밋1e596846은 로컬에만 있었고 push 안 함.) - 남는 것 —
cut_slope_segments(구간별 경사)는 그대로 둠. 소단이 끼어도 구간 경사를 아는 값이라 뒤에 쓸 자리가 있고, 25 의 소단 작업이 이미 그 위에 서 있음. - ⇒ 조사 자체는 값이 있었음 — 이 과정에서 무릎 위 구간의 암/토사 라벨이 13구간 잘못
붙어 있던 것이 드러나 고쳐졌음(25 커밋
4e7a4bf7). 그 결함은 검사와 무관하게 남음.
7-2. 백엔드 자동 반영(감시)이 조용히 죽는 것 (2026-09-07 — 오늘 세 번 속았음)
- 죽었는지 눈에 보이게 함 —
/api/health가 알림 (2026-09-07 커밋df02793c). 개발 모드에서started_at(기동 시각) ·code_mtime(기동 때 본 소스 최신 수정) ·source_mtime(지금 소스 최신 수정) ·stale을 함께 냄. 기동 로그에도 한 줄 ([reload] 감시 폴더 12개, 소스 최신 수정 …).- 장치가 실제로 도는 것 확인 — 감시 폴더의
.py를 고치니 리로드는 안 뜨고stale이 즉시true로 바뀜. - ⇒ 화면·속도를 재기 전에
/api/health한 번이면 「옛 코드로 도는가」가 1초에 가려짐. 사람이 지키는 규칙을 장치로 바꾼 것임. - 실전 두 번째 (2026-09-07) —
018적용 뒤 API 가 404 를 내길래/api/health를 보니stale: true(코드 11:52 · 소스 14:44). 재시작하니 바로 200. 원인 찾기 0분. - 실전 첫 사례 (2026-09-07, 만든 날) — 보조 창이 구조물 레지스트리 JSON 을 고쳤는데 화면에
안내가 안 떴음.
/api/health가stale: true여서 재기동하니 바로 떴음. (레지스트리는@lru_cache라 JSON 만 고쳐서는 안 바뀜 — 4장 「백엔드 엔진·템플릿은 재시작」 규칙과 같은 자리.) 원인 찾기에 쓴 시간 ≈ 0 — 이 장치가 없었으면 화면·코드부터 뒤졌을 자리임. - ⚠
main.py가 바뀌었음(공용). 받은 창은 서버를 한 번 다시 띄워야 새 항목이 보임.
- 장치가 실제로 도는 것 확인 — 감시 폴더의
3부 — 옮기기 직전의 「지금 상태」 (낮 정리 시점 기록)
지금 상태 (2026-09-07 갱신)
남은 항목 20(체크 안 된 줄 기준 — 그중 3건은 「(보류)」 표시라 실제로 손댈 것은 17건) · 끝난 항목 257. 오늘 두 창이 병렬로 돌며 사용자 지시 다섯 건을 처리했음.
계획서 정리 (2026-09-07 저녁) — 1,910줄이 되어 읽기 어려워져, 끝난 절 24개를
docs/raw/plans/2026-09-07_plan_completed_items.md 로 옮기고 1,000줄 남짓으로 줄였음.
남은 일이 없어진 B01·B02 · B07 · B03·B04 구획은 통째로 빠졌음. 다시 걸릴 만한 검증
함정만 「참고」로 건져 왔음. 위키화는 다른 AI 몫.
| 사용자 지시(2026-09-07) | 상태 |
|---|---|
| 1. 옹벽도 수량이 변경되어야 함 | 고침(e9ad8cdf) — 다만 파급 하나 판단 대기(아래) |
| 2. 계획노선을 직선>곡선>직선으로 + 편집 | 완료 — 0-12 |
| 3. 구조물 폼 선택 칸(나중에 비활성화) | 완료(6b76a3f2) |
| 4. 구조물 표시 통일 | 완료(67972612) |
| 5. 구조물 전체를 넣을 수 있게 | 완료(a811286e) — 수량까지 흐르는지는 확인 중 |
| (추가) 155° 곡선 생략 쓰지 말 것 | 완료(9626d9e8) |
| (추가) R·직선 삭제·추가 | 완료(f59932de·56a6d186·20f34390) |
사용자 결정 (2026-09-07 오후) — 셋 다 답이 나왔음.
- 옹벽 수정의 파급 = 그대로 둠(OK). 단 없는 자리의 성토 증가를 되돌리지 않음. 빠져 있던 물량을 바로잡은 것으로 확정. 되돌릴 자리 주석은 근거로만 남김. → 3-5 절
watchfiles설치 승인 — 넣었음(55895c3e). 놀 때 CPU 18% → 0%, 보조 창도 0%. 기동 로그가using WatchFiles로 바뀜. → 0-11 절- 시험 실패 9건 원인 = 파일이 아니라 확장자·환경 — 아래.
오늘 굵직하게 바뀐 것
- 노선 [확인] 293초 → 약 90초 — 범인은 표고 보간 삼각망(등고선 317,348점을 통째로) 하나였음.
- 계획노선이 「직선 > 곡선 > 직선」이 됨 — 이어진 꺾임을 한 곡선으로 묶고 예정노선에 가장 가까운 반지름을 고름. 흉내낸 곡선에서 원본 R 25/40/80m 을 25.1/39.8/78.2m 로 되찾음.
- 놀고 있는 서버가 CPU 70% 먹던 것 — 저장소를 되가리키는 정션 때문. 85% → 18%.
- 조용히 값이 사라지던 결함 셋 — [확인]마다 노선이 깎임 · 다단 구간값이 재계산에서 지워짐 · 편집 한 번에 맞춰 둔 반지름이 하한으로 눌림. 전부 고치고 시험으로 못박음.
알아 둘 것 — 오늘 두 번 속은 함정 속도·화면을 재기 전에 ① 백엔드를 확실히 재시작하고 ② 그 수정의 로그나 새 응답 항목이 실제로 있는지 먼저 볼 것. 옛 코드로 도는 서버에 두 번 속았고, 한 번은 응답에 새 항목이 아예 없는데도 화면은 정상처럼 보였음(다른 값으로 세는 폴백이 있었음).
시험 — pytest 432 통과(실패 0).
시험 실패 9건 — 원인 밝힘(2026-09-07)
- 증상 — 보조 창 폴더에서
test_b05_patch_skirt.py8건 +test_b05_cut_merged_loop.py1건이require is not defined in ES module scope로 실패. 같은 파일이 내 폴더에서는 통과. - 원인 — 루트
package.json에"type": "module"이 있어 도우미.js가 ESM 으로 읽힘. 그러면 그 안의require가 죽음. 다른 JS 시험들이 멀쩡한 이유는 전부.mjs(명시적 ESM)라서고,require를 쓰는.js는 이 둘뿐이었음. 두 폴더가 갈린 것은 Node 판·환경 차이임 — 내 Node(v22.17.0)에서는 같은 자리에서require와import.meta가 둘 다 동작해 안 깨졌음(NODE_OPTIONS없음). - 고침 — 도우미를
.cjs로 바꿈..cjs는type과 무관하게 언제나 CommonJS 라 어느 폴더·어느 Node 에서도 같게 돎. 부르는 시험의 경로 한 줄씩만 바뀜. ⚠tmp/tests는 git 밖이라 폴더마다 따로 적용해야 함(보조 창에 방법 넘김).