Commit Graph
1097 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 1553f23c0d perf(B04): 등고선 피처 풀기를 한 번만 (격자와 무관)
PLAN 0-10. 「등고선 굽기」가 확장 8회 합 19s 였는데, 실측해 보니 굽기 자체는 0.8~2.0s
이고 나머지는 **피처 4,200개를 회차마다 다시 `shape()` 로 푸는 값**이었음. 푸는 결과는
격자와 무관하므로 같은 목록·같은 하한이면 그대로 쓴다(목록 객체를 함께 들고 있어 id 가
다른 목록에 재사용되지 않음, 최근 2벌만 보관).

실측 — 같은 격자 연속 4회: 2.66 · 1.90 · 1.99 · 2.03s (2회차부터 파싱 재사용), 결과
배열은 4회 모두 동일. `build_contour_descent` 전체는 옛 코드 12.8s → 7.2s 이며
band_elevation·valid·receiver·step_length·azimuth·levels 전부 `np.array_equal` 동일.

안 한 것 — 격자가 커질 때 옛 굽기를 옮겨 붙이고 **테두리만** 굽는 안은 만들어 재 봤으나
`rasterize` 호출당 고정 비용 때문에 오히려 3.2s → 10.6s 로 느렸고, 창에 걸치는 선만
넘기도록 고쳐도 3.8s 로 손해였음(창 4개 × 166단). 그래서 걷어내고 파싱 캐시만 남김.
`levels` 는 피처 전체에서 나오므로 격자와 무관하다는 것도 확인함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 05:48:38 +09:00
eomsangdonandClaude Opus 5 f1834465c8 perf(B04): 창이 모자라면 그 타일만 넓혀 다시 재도록
PLAN 0-10 이어짐. 첫 판에서는 창이 모자란 단계를 **격자 전체**로 되돌렸는데, 격자가
커질수록 그 폴백이 25/91 까지 늘어 이득이 대부분 사라졌음(실측 확장 97.7s).

- 모자란 타일만 창을 4배로 넓혀 다시 잼. 단계 전체를 되돌리지 않음.
- 타일 256 → 128 (실측: 128/여유32 2.1s vs 256/여유32 2.7s).
- 넓힘 횟수를 계측 줄에 남김(폴백 대신).

자체검증 — 전체격자 5.2s → 2.1s(넓힘 15/91), 거리·목표행·목표열 전부 동일.
`build_contour_descent` 결과도 옛 코드와 완전 동일(8.0s → 5.1s). 시험 500 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 05:29:18 +09:00
eomsangdon c90425db72 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 05:21:01 +09:00
eomsangdonandClaude Opus 5 56d5fb26b8 perf(B04): 밴드별 하강거리 EDT 를 타일 창으로 좁힘 (값 보존)
PLAN 0-10. 확장 95.8s 중 밴드별 EDT 가 50.4s 였음 — 단계마다 격자 전체를 훑는데
정작 쓰는 값은 그 단계 밴드 셀뿐임.

- 격자를 256칸 타일로 나눠 **셀이 있는 타일만** 둘레 32칸까지 잘라 EDT 실행.
  `analyze_domain` 이 domain 을 안 넘겨 밴드가 전역에 흩어지므로 바운딩박스 하나로는
  안 좁아짐 — 타일이라야 좁아짐.
- 창 안 최대 거리가 여유에 닿거나 창에 낮은 라인이 없으면 **그 단계를 전체 격자로 다시**
  — 근사가 아니라 같은 값을 싸게 구하는 것. 폴백 횟수는 계측 줄에 찍음.
- `return_indices` 가 주는 창 좌표에 창 원점을 더해 전체 격자 좌표로 되돌림.

자체검증 — 실제 자료(745×1035·166단, EDT 도는 91단)에서 전체격자 10.8s → **2.9s**,
폴백 9/91, 거리·목표행·목표열 **전부 `np.array_equal` 동일**. `build_contour_descent`
결과(band_elevation·valid·receiver·step_length·azimuth·levels)도 옛 코드와 완전 동일.
여유·타일 선택 근거는 파일 주석의 실측표 참조. 시험 500 통과·18 건너뜀
(기존 실패 8건은 다른 환경의 JS 도우미 문제로 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 05:18:35 +09:00
eomsangdonandClaude Opus 5 1944414940 fix(B05): [확인]을 누를 때마다 계획노선이 깎이던 것
같은 노선으로 [확인]을 되풀이하면 계획노선 정점이 136 → 134 → 119, 노드가
22 → 21 로 계속 줄었음(보조 창 실측). 사용자가 아무것도 안 옮겨도 누를
때마다 자기 노선이 뭉개졌음.

원인은 **이미 폴리라인인 것을 다시 단순화**한 것. 두 자리 모두 그랬음 —
  - read_route_plan 이 노드를 계획노선(원호 점이 섞인 폴리라인)에서 되뽑음
  - replan_route 가 화면이 보낸 노드를 또 한 번 단순화해서 씀
단순화(Douglas-Peucker)는 원본 점군에서 한 번만 돌아야 함.

고친 것:
  - build_planned_polyline 에 simplify 갈래 신설. False 면 받은 점을
    꺾임점으로 그대로 씀(중복 제거만).
  - 폴리라인을 쓸 때 그것을 낳은 **노드도 함께 저장**
    (planned_route_nodes.csv · planned_route_initial_nodes.csv).
    노드는 폴리라인에서 되뽑을 수 없으므로 낳은 값을 보관함.
  - read_route_plan 은 저장된 노드를 그대로 씀(없는 옛 프로젝트만 뽑음).
  - replan_route 는 simplify=False 로 씀.

실측(용화 b269ea34 실제 노선 파일, 4회 왕복)
  옛 방식  노드21/정점115 → 20/115 → 20/113 → 20/115  (깎이고 흔들림)
  고친 방식 노드21/정점115 → 이후 매 회차 **완전히 동일**

시험 tmp/tests/test_route_polyline_idempotent.py 2건 신설 — 노드 왕복이
제자리인지, 그리고 옛 방식이 실제로 깎이는지(갈래가 필요한 이유) 못박음.
pytest 414 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 05:08:07 +09:00
eomsangdonandClaude Opus 5 5c22c367a9 perf(계측): 격자 확장·하강 방향장 단계 마크 추가
PLAN 0-10. 1차 영역이 2.6초로 떨어진 뒤 남은 병목이 `expand_by_red_boundary` 102초라
그 안을 가르기 위한 계측. 로직 불변.

- 확장 회차별 시간·격자·셀 수·방향장 재사용 여부를 한 줄씩
- 격자 해석 1회: 하강 방향장(재사용/새로) / 지형 조립 / 도로 굽기 / 세류 새김 / 도달 판정
- 하강 방향장: 등고선 굽기 / 밴드 표고(EDT 1회) / 밴드별 하강거리(EDT N회) /
  위치에너지 조립 / 흐름 경로

실측 로그상 방향장이 회차마다 새로 만들어지고 밴드가 100단이라, 격자 전체 EDT 가
회차당 100회씩 도는 구조로 보임 — 그 가설을 수치로 가르려는 것.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 04:58:45 +09:00
eomsangdonandClaude Opus 5 58bfe72ab5 chore(B04): 표고를 TIN 밖에서 읽은 점 수를 로그로 남김
보간 구름을 물어볼 자리 둘레 100m 로 좁힌 뒤(9317ad31), 그 둘레에
등고선이 없는 자리는 볼록껍질 밖이라 최근접 정점 값으로 빠짐. 그 값은
등고선 간격(5m)만큼 틀릴 수 있고 그러면 그 조각의 상·하류 판정이 갈림.

용화 자료에서는 안 일어났으나(판정값 일치) 다른 현장에서 조용히 갈릴 수
있어 몇 점이 빠졌는지 한 줄로 남김. 계산은 안 바뀜.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 04:58:08 +09:00
eomsangdon 9ded6fe6c6 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 04:57:03 +09:00
eomsangdon c9cd670315 Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-07 04:56:24 +09:00
eomsangdonandClaude Opus 5 b6941bd28d fix(B06): 재계산이 다단 구간값을 지우던 것 — 사용자 조작값 목록을 한 벌로
같은 「사용자 조작값」 목록이 세 곳에 흩어져 있었고 서로 달랐음.
브라우저(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>
2026-09-07 04:50:43 +09:00
eomsangdonandClaude Opus 5 48c856ea8d fix(계측): B06 확정 마크가 다른 함수에 정의되던 것 바로잡음
`marks` 정의가 `save_sections` 에 들어가고 사용은 `confirm_sections` 에 남아
`NameError: name 'marks' is not defined` 로 [확인] 재계산이 500 으로 끝났음
(노선은 자동 롤백돼 자료 손상 없음). 정의를 쓰는 함수 안으로 옮기고
`save_sections` 의 잘못 들어간 두 줄 제거. 계측 항목은 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 04:50:08 +09:00
eomsangdonandClaude Opus 5 9317ad3175 perf(B04): 표고 보간 삼각망을 물어볼 자리 둘레로 좁힘
노선 [확인] 이 293초였고 그중 285초가 배수유역 분석, 다시 그중 256초가
1차 영역 만들기였음. 범인은 ElevationSampler 하나임 —
LinearNDInterpolator 가 들로네 삼각망을 첫 호출 때 만드는데 등고선 구름을
통째로(용화 317,348점) 넘겨 그 한 번이 256~1,481초로 뛰었음(편차 큼).

표고를 묻는 자리는 도로 교차 노드에 닿은 세류 조각 몇 개뿐임. 그 조각들만
먼저 골라 그 둘레 100m 안 등고선만 남기고 삼각망을 만듦. 여유 100m 는
등고선 재샘플 간격(5m)의 스무 배라 물어볼 점은 언제나 볼록껍질 안쪽이고
보간값이 그대로임.

실측(용화 5601e828) — 보간 구름 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 / 미연결 1153.

pytest 409 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 04:37:00 +09:00
eomsangdonandClaude Opus 5 4da04929c4 perf(계측): 재확정 체인 병목 추적용 단계 마크 추가
PLAN 0-10. 8000 에서 1회 실측 결과 재확정 체인 292.9s 중 배수유역 분석이 285.0s(97%)로
나와, 그 안쪽을 가르기 위한 마크만 추가. 로직 불변.

- B06 확정: 조회 / 기본설계 계산 / 확정 저장 / 서버 재계산 / 측구 역반영
- 서버 재계산 내부: 상세+DB 병렬 조회 / 포장·세월교 보정 / Node 번들 / 정본 저장
- 배수유역 분석 내부: _prepare(도엽 읽기·좌표변환) / preview_stages / 응답 만들기·저장
- preview_stages: 1차 영역 / 격자 확장·흐름 판정 / 흐름 강도 / 외곽선·기본 관·화살표

`_log_steps` 는 체인 모듈 것을 그대로 씀(지연 임포트로 순환 회피).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 03:20:39 +09:00
eomsangdonandClaude Opus 5 41852da3b3 feat(B03): 초기 업로드부터 계획노선 폴리라인을 노선 정본으로 사용
자동 체인 2.7 단계 추가 — 초기 폴리라인을 세운 뒤 노선을 다시 읽어
그것을 BP·경유점·EP 로 세우고 algorithm=as_planned 로 넘김.

전에는 폴리라인 파일만 만들고 노선은 원본 점군으로 풀었음. 그래서
종횡단 측점·유토곡선·3D 코리도가 곡선 없는 점군 위에 섰음.
실측(용화 3건): DB 노선 정점 331·323 vs 초기 폴리라인 145.
노선을 한 번이라도 편집한 프로젝트만 145 로 맞아 있었음.

자체검증 — 2.7 재판독이 145 정점을 돌려주고 BP·EP 좌표가
expected_route.csv 첫·끝 줄과 같음. pytest 409 passed.

계측 로그(_log_steps) 동봉 — 재확정 체인 단계별 경과시간용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 02:56:45 +09:00
eomsangdon c52609417b Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 02:06:54 +09:00
eomsangdonandClaude Opus 5 71694163de fix(B06): 벽을 안 그리는 카드에 [연동] 버튼이 뜨던 것
링크 카드는 소유 측점의 벽을 빌려 그리는데, 빌릴 벽이 없는 카드에도 버튼이 떠 눌러도
아무 일이 없었음 — revetlink 에 detached 만 쌓였음(보조 창 실측: 0·20·40·60·80m 카드).
linkState 가 drawnWallKeys().length 도 함께 보게 함.

계획서 3-4 실화면 확인도 함께 마침(공용 브라우저, 용화):
- 벽이 있고 연동이 켜진 카드 820.00m 에서 [연동]을 끄자 revetx 에 820.00:outlet h=1.8 이
  적힘 — 푸는 순간의 높이가 그 측점 값으로 굳음.
- 그 뒤 소유 측점 821.62m 높이를 4.2m 로 올려도 820.00m 은 1.8m 그대로 — 따로 놂.
※ 앞서 안 굳는 것으로 본 것은 측정 오류였음. 패널이 카드마다 하나씩 67개인데 첫 번째
   패널만 봤고, 벽이 없는 카드를 골랐음(보조 창이 가려냄).

시험 409 통과·17 건너뜀, typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 01:37:59 +09:00
eomsangdonandClaude Opus 5 fe14ad02ee feat(B05): 계획노선 초기 폴리라인을 자동설계 체인에서 세움
PLAN 0-10. 그동안은 화면이 route/plan 을 처음 부를 때 만들어져, 화면을 안 열면 값이
없었음 — 초기값은 서버가 낸다는 0-4 원칙과 어긋났음.

- 파일입력 자동설계 체인이 예상노선 정본을 남긴 직후(2.6단계) 초기 폴리라인도 세움.
  실패는 비치명적 — 없으면 화면이 처음 열릴 때 만들어짐.
- _ensure_planned_initial 이 **낡음도 본다** — 예상노선 파일이 더 나중에 쓰였으면 다시
  만듦. 파일을 다시 올리면 예상노선이 새로 깔리는데 초기본이 옛 노선인 채로 남으면
  노선 초기화가 옛 자리로 돌아갔음.

자체검증 — 예상노선 파일 시각을 최신으로 만든 뒤 route/plan 을 부르니 초기 폴리라인이
다시 만들어짐(노드 28 · 곡선 13 그대로). 시험 409 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 01:19:28 +09:00
eomsangdonandClaude Opus 5 710169fd00 fix(B05): [3D 업데이트]가 만든 코리도를 바로 올리고 보관함에도 담음
보조 창 지적 — [3D 업데이트]를 눌러도 브라우저가 만들기만 하고 PUT 이 없었음.
저장 시점이 B05->B06 이동뿐이라(2026-08-23 확정), 누른 뒤 새로고침하면 저장본이 낡은
채라 다음 사람이 또 만들어야 했음.

- 버튼 경로 끝에서 saveCorridorIfDirty 를 부름.
- saveCorridorIfDirty 가 PUT 성공 뒤 그 봉투를 브라우저 보관함에도 담음(옛 열쇠 자리는
  치움). 그러지 않으면 다음 진입이 새 열쇠 주소로 16.9MB 를 한 번 더 받았음.

typecheck 통과. 실측 확인은 보조 창이 자기 프로젝트에서(저장본이 최신인 자리) 진행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 01:09:58 +09:00
eomsangdon 74a631182d Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 01:05:30 +09:00
eomsangdonandClaude Opus 5 908c75d535 fix(B05): 노선 변경 때 옛 사용자 설계가 덮여 사라지던 것 — 이월 순서
보조 창 실측 — 노드를 옮겨 재계산하면 다단 구간값(extra_spans)이 0건이 됐음.
심어 둔 표식(85.18m 의 14/6/8)이 통째로 사라짐.

원인은 순서였음. 이월이 _prepare_drainage_pipes_and_reprofile(refresh=True) **앞**에서
돌았는데, 그 단계가 측점을 새 노선 기준으로 다시 만들며 방금 얹은 설계를 덮었음.

- 이월을 측점 재생성 **뒤**로 옮김. 옛 설계는 이미 old_designs 로 손에 있음.
- 행마다 쓰던 것을 merge_cross_section_designs 로 묶음 — 행 수와 무관하게 왕복 두 번
  (원격 DB 왕복 약 12ms/질의).

같은 요청에서 확인된 통과분(보조 창) — 측점 수·끝 누가거리가 새 노선과 일치(67·1,097.4m
고정 -> 64·1,079.4m), 배수관 측점 0 -> 7~9, 「세그먼트 경로 탐색 실패」 로그 사라짐.

시험 409 통과·17 건너뜀, main import 스모크 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 01:04:49 +09:00
eomsangdon 735d34b743 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 00:49:44 +09:00
eomsangdonandClaude Opus 5 674ca82726 feat(B05): 고친 계획노선을 그대로 쓰는 입구 — 재확정 체인이 다시 풀지 않음
PLAN 0-2 항목 9 / 0-3. 노선 편집 [확인]이 재확정 체인을 타는데 그 체인이 solve_route 로
BP·CP·EP 사이를 격자에서 다시 풀었음. 사용자가 노드를 조금만 비틀어도 탐색 제약에 걸려
체인이 통째로 멈췄음(보조 창 로그: 세그먼트 1 (BP -> CP1) 경로 탐색 실패 — 종단경사
한계 26% · 최소곡선반지름 12m · 회피지역 제약).

- B05_Profile_Engine_AsPlanned.solve_as_planned 신설 — 제어점 목록이 곧 노선이고 표고만
  지표면 격자에서 뜸. 반환 꼴은 솔버와 같아 아래 단계가 그대로 이어짐.
  종단기울기·곡선반지름 위반은 **세되 막지 않음**(사용자 확정: 자동 보정·차단 없이 경고만).
- run_route_design 에 algorithm=as_planned 갈래 추가. 스키마 검증에도 허용.
- 재확정 체인이 그 갈래를 씀 — 자동탐색은 이제 초기 업로드에서만 돎.

솔버와 지표 계산이 겹치지만 합치지 않음 — 솔버는 0-3 으로 접히는 코드라 리팩터링해
두 곳을 얽을 값어치가 없음.

시험 409 통과·17 건너뜀, main import 스모크 통과.
실화면 [확인] 재검증은 보조 창이 자기 프로젝트에서 진행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 00:49:07 +09:00
eomsangdon b1be5ade7c Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 00:45:09 +09:00
eomsangdonandClaude Opus 5 53525a1d91 fix(B05): 노선 재계산이 끊겼을 때 노선만 갈아 끼워진 채 굳던 것
보조 창 실측 — [확인] 이 체인 중간에 400 으로 끊겨도 route/replan 은 success 를 돌려주고
계획노선 CSV 는 이미 새 노선으로 바뀐 뒤였음. 그 결과 배수유역·관은 새 노선, 종횡단은
옛 노선으로 어긋난 채 굳고(배수관 측점 9 -> 0), 다시 누를수록 어긋남이 쌓였음
(1,097.4 -> 1,079.4 -> 1,064.7m).

- run_redesign_chain 이 중단 사유를 문자열로 돌려줌(성공은 None). 중단 지점 넷 모두.
- replan 이 쓰기 전에 이전 수정본을 쥐고 있다가 실패하면 되돌림. 처음 고치는 경우였으면
  파일을 지워 초기 폴리라인으로 돌아감.
- 실패는 409 + 사유로 응답 — 화면이 성공으로 보이던 것을 막음.

원인 자체(자동탐색이 사용자 노선을 다시 풀다 실패)는 별건으로 남음 — 로그 사유
「세그먼트 1 (BP -> CP1) 경로 탐색 실패: 종단경사 한계(26%)·최소곡선반지름(12m)·회피지역
제약으로 통과 경로가 없습니다」. 고친 노선을 그대로 받아 쓰는 입구가 필요함(PLAN 0-2 항목 9).

시험 409 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 00:44:29 +09:00
eomsangdon e875cdb2df Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 00:38:36 +09:00
eomsangdonandClaude Opus 5 eec29a90df fix(B05,B06): 최소곡선반지름 조회가 없는 컬럼을 읽던 것 · 재계산 중단 사유 로그
보조 창이 노선 편집 [확인] 실측에서 둘을 잡음.

1. projects 에 design_speed_kph / terrain_type 컬럼이 없음(있는 것은 road_type 뿐).
   매 요청마다 OperationalError(1054) 가 ERROR 로그로 남고 기본값 폴백으로 넘어갔음.
   - 임도 종류는 projects.road_type, 설계속도·지형은 워크플로 stage 2 params 에서 읽음.
   - 산식은 이미 있던 B05_Profile_Engine_Grade.legal_plan_radius_min_m 를 씀 —
     내가 같은 표를 다시 짜 두었던 것을 지움(중복 제거).
2. 재확정 체인이 solve_route 400 으로 끊길 때 상태 코드만 남겨 원인을 못 짚었음.
   본문(사유)까지 로그에 남김. 노선 편집 [확인]이 조용히 끊겨 배수유역·관은 새 노선으로
   가고 종횡단만 옛 노선에 남는 어긋남이 굳었던 자리임.

recompute 의 상세 조회와 DB 두 건도 asyncio.gather 로 묶음(원격 DB 왕복 약 12ms/질의).

시험 409 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 00:37:53 +09:00
eomsangdon f24d8a34cf Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 00:19:20 +09:00
eomsangdonandClaude Opus 5 e2cc5e759b perf(B05): 3D 코리도를 브라우저 보관함(IndexedDB)에 담아 재수신 없앰
손 안 댄 프로젝트를 열면 저장본 열쇠가 맞아 매번 16.9MB 를 받았고, 브라우저 보관이
모듈 Map 이라 새로고침 한 번에 날아가 또 받았음(보조 창 실측: 첫 로그인~B05 도달 29MB
중 16.9MB 가 이것). 해시 질의(0b30f5b0)는 낡았을 때만 막았지 맞을 때는 그대로였음.

- b_asset_cache 에 readCachedBytes / writeCachedBytes / purgeAssetsWithPrefix 추가.
  앞 둘은 네트워크를 안 타는 순수 보관함 접근이고, 마지막은 주소 앞머리가 같은 옛
  보관본을 지움 — 코리도는 주소에 열쇠가 박혀 정본이 바뀌면 새 주소가 되므로 17MB 짜리가
  쌓이지 않게 담기 전에 치움.
- 코리도 조회가 보관함을 먼저 봄. 주소에 열쇠가 있어 정본이 바뀌면 저절로 다른 주소가
  되므로 옛 보관본을 잘못 쓸 일이 없음.

자체검증(공용 브라우저) — 담기·읽기 왕복 정상(44바이트 왕복, 해시 보존), 열쇠만 다른 두 벌을
담은 뒤 앞머리 지우기로 둘 다 제거 확인. typecheck 통과.
※ 실제 16.9MB 절감은 저장본이 최신인 프로젝트에서 확인해야 함 — 이 프로젝트는 검증 중
계획고를 만져 저장본이 낡은 상태라 코리도 자체가 안 실림(__corridorSource null).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 00:18:37 +09:00
eomsangdon b566c67c52 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 00:10:33 +09:00
eomsangdonandClaude Opus 5 9b93d3055b feat(B05): 노선 편집 모달이 정점 대신 노드를 잡게 함
사용자 지시(2026-09-06) — 노드를 제어해 계획노선을 고친다. 그동안 모달은 서버가 준
폴리라인 정점을 그대로 잡았는데, 거기에는 원호 위 점이 섞여 있어 편집 대상이 아님.

- 그려 보이는 선(폴리라인, 원호 포함)과 잡는 점(노드)을 나눔. 선은 plannedLine,
  노드는 서버가 내려 준 nodes.
- 노드에 붙은 반지름·내각·법정 위반을 화면에 실음 — 위반 노드는 붉게, 상태줄에
  곡선 수와 기준 R, 미달 개수.
- 노드를 옮기면 폴리라인은 낡은 값이므로 지우고 직선으로 미리 보임. 곡선은 [확인] 때
  서버가 같은 R 규칙으로 다시 끼움(계산을 두 벌로 짜지 않음).
- API 타입에 nodes·min_radius_m·curve_count·violation_count 추가.

자체검증(공용 브라우저, 용화) — 모달이 노드 28개로 열리고 상태줄에
「노드 28개 · 초기 폴리라인 · 곡선 13곳(R 12m)」. 전에는 폴리라인 정점 142개를 잡았음.
typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 00:09:49 +09:00
eomsangdonandClaude Opus 5 00decc812d perf(B05): 계획노선 노드 뽑기 — 완만한 긴 굴곡이 삼켜지던 것 보완
Douglas-Peucker 허용오차는 절대 거리라 굴곡이 완만하고 길수록 통째로 삼켜짐.
4.5km 노선에서 노드 20개(간격 238m)만 남았음(보조 창 실측 5개 표본).

- 남은 노드 사이가 100m 를 넘으면 그 구간만 허용오차를 절반으로 낮춰 다시 뽑음
  (최대 3겹: 4 -> 2 -> 1 -> 0.5m). 노선 길이로 허용오차를 바꾸면 짧고 급한 굴곡이 다시
  뭉개지므로 벌어진 구간만 고름.
- shapely 대신 색인을 돌려주는 Douglas-Peucker 를 직접 둠 — 되뽑기가 원본 구간을 다시
  꺼내야 해서 색인이 필요함. 새 점은 만들지 않음(노드는 언제나 원본 자리).

반지름을 원본 굴곡에서 재어 키우는 방법도 시험했으나 되돌림 — 직각 꺾임에서 R 70m ·
중앙종거 20m 가 나와 원본과 크게 어긋났음. 중앙종거 M = R(1/cos(delta/2) - 1) 이라
R 이 클수록 원호가 꺾임점에서 멀어짐. 법정 하한이 사용자가 지시한 기준값이자 원본에
가장 가까운 값이므로 그대로 둠. 곡선별 R 조정은 노드 편집 기능으로 분리(PLAN 0-10).

자체검증 — 1.1km 노선 3개: 노드 25 -> 28, 곡선 13, 위반 0, 최대 간격 82m.
4.5km 노선: 노드 20 -> 24. 그 노선의 최대 간격 1,300m 는 알고리즘 문제가 아니라 실제
직선 구간임을 확인(원본 점 간격 중앙 3.3m · 최대 3m 로 고르고, 내각 최소가 158°).
시험 2건 추가(완만한 굴곡이 살아나는지 · 되뽑기가 원본 점만 남기는지). 전체 409 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 00:05:48 +09:00
eomsangdonandClaude Opus 5 318507c88d fix(B05,B06): 종단 알약으로 고른 구조물이 B06 횡단도에 안 잡히던 것
계획서 2-2. 3D 픽·사이드 목록에는 structure-pick 기록이 있는데 종단 그래프 알약 경로에만
빠져 있었음 — 세션 키가 아예 안 써져 B06 이 잡을 값이 없었음(보조 창 추적).

- 구조물 브리지에 markChainage 추가 — 알약 id 의 누가거리를 구조물 정본·관 정본 양쪽에서
  되읽음.
- Page 의 onStructureSelect 가 writeStructurePick 으로 그 자리를 남김(사이드 목록 경로와
  같은 창구).

자체검증(공용 브라우저, 용화) — 알약 18개 중 셋을 눌러 세션 키가
찰쌓기 1 -> {at:40} · 찰쌓기 3 -> {at:80} · 옹벽 -> {at:120} 으로 써짐(전에는 null).
그 상태로 B06 진입 시 측점 6+0.0(120m) 카드가 선택된 채로 뜸. typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 23:58:53 +09:00
eomsangdon 8584a53967 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 23:55:12 +09:00
eomsangdonandClaude Opus 5 356b32163a feat(B05): 계획노선을 폴리라인으로 만드는 초기본 신설
사용자 확인(2026-09-06) — 예상노선은 폴리라인이 아니라 점 묶음이고 규칙 없는
폴리라인과도 맞지 않음. 그래서 계획노선은 원데이터를 복사해 폴리라인으로 바꾼 것이어야
하고 그것이 불변의 초기 데이터가 됨. 곡선 기준은 지식DB(별표2 I.2.다) 값을 씀.

- common_util_route_polyline.py 신설 — 점 묶음을 폴리라인으로.
  ① Douglas-Peucker 로 꺾임점(IP)만 남김. 예상노선은 격자 탐색이 낸 조밀한 점군이라
     (용화: 1,097m 에 331점) 점마다 곡선을 끼우면 접선 자리가 1.5m 뿐이라 R 이 2~6m 로
     뭉개짐. 허용오차는 격자 해상도(2m)의 두 배.
  ② 내각 155도 이상은 곡선 생략(별표2), 그 아래는 최소곡선반지름으로 원호를 끼움.
     자리가 모자라면 반지름을 줄이되 막지 않고 위반으로 표시(사용자 확정: 경고만).
  ③ 점은 옮기지 않음 — 노드는 원본 자리에 그대로 두고 그 사이에 원호를 넣음.
- planned_route_initial_path 신설 — 세 벌 구조(예상노선 점 묶음 / 초기 폴리라인 /
  수정본). load_design_route 읽는 순서에 초기 폴리라인을 예상노선보다 앞에 끼움.
- 최소곡선반지름은 임도 종류·설계속도·지형으로 고름
  (FOREST_ROAD_PROFILE_CRITERIA[min_plan_radius_m], 못 읽으면 가장 완화된 조건).
- GET /route/plan 이 노드(반지름·내각·위반)까지 함께 돌려줌 — 노드만 옮기면 선이
  저절로 규칙을 지키게 하는 것이 목적. POST /route/replan 도 받은 노드로 다시 폴리라인화.

자체검증(용화, 실화면 API) — 예상노선 331점 -> 편집 노드 25개 + 곡선 13곳
(전부 R 12m = 설계속도 20·특수지형 법정 하한, 위반 0) -> 계획노선 정점 142개. 응답 180ms.
단순화 전에는 곡선 15곳이 R 2.75~6.51m 로 전부 위반이었음.
시험 tmp/tests/test_route_polyline.py 7건(원호가 접선과 맞물리는지 좌표로 대조).
전체 407 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 23:53:25 +09:00
eomsangdonandClaude Opus 5 e5b896283f fix(B05): 배분 선반입 되먹임을 응답 반영 구간에서 끊음
표식(측점 수 + 누계)만으로는 부족했음 — 응답을 반영해 다시 그린 뒤 누계가 아주 조금
달라지는 경로가 있어 편집이 멈춘 뒤에도 2~3바퀴가 더 돌았음(보조 창 10초 관찰:
2.8~6.3초에 걸쳐 3건).

onReady 로 다시 그리는 동안 applying 을 세워 그 그리기가 거는 schedule 을 무시함.

자체검증(공용 브라우저, 접은 채 계획고 6회 편집 후 10초 관찰 3회) — 3/3/1건 -> 2/1/1건.
편집하는 동안은 종전대로 0건(400ms 안정화 유지). typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 23:27:37 +09:00
eomsangdon f7e12dddf1 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 23:13:56 +09:00
eomsangdonandClaude Opus 5 c8468e789d fix(B05): 유토 배분 선반입이 접힌 상태에서 안 돌던 것 · 응답이 요청을 다시 부르던 되먹임
- schedule 호출이 draw 의 접힘 가드 뒤에 있어 패널을 접어 두면 한 번도 안 불렸음.
  그래서 「편집이 멈추면 조용히 받아 둔다」가 성립하지 않고 펼친 뒤에야 첫 요청이 나갔음
  (보조 창 실측: 편집 6회에 요청 0건). 접힘 여부와 무관하게 지나는 emitSummary 로 옮김 —
  거기서 이미 고른 결과를 쓰므로 계산 비용 0.
- 응답이 오면 곡선을 다시 그리고, 그리기가 다시 schedule 을 불러 요청이 끝없이
  되돌아왔음. 입력 표식(측점 수 + 마지막·중간 누계)을 두어 같은 값이면 안 보냄.

자체검증(공용 브라우저, 패널 접은 채 계획고 6회 편집) — 요청 1건, 그 뒤 4초 동안
추가 0건. 고치기 전에는 편집 중 0건 + 펼친 뒤 1건 + 되먹임 1건이었음.
시험 400 통과·17 건너뜀, typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 23:13:05 +09:00
eomsangdon c25fc26f33 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 22:54:54 +09:00
eomsangdonandClaude Opus 5 4df5d0a7ea perf(B06): 카드 기하를 두 번 계산하던 것을 한 번으로
행 높이를 재는 1차와 실제 그리는 2차가 같은 측점의 crossPlotMetrics 를 각각 계산했음.
측점 67곳 기준 3.2ms/장이라 진입에서 draw 자기 시간 213ms 의 대부분이었음
(보조 창 CPU 프로파일).

- crossPlotMetrics 를 crossPlotBase(강제 높이 전) + crossPlotFromBase(높이만 얹기)로
  가름. 기존 시그니처는 둘을 잇는 감싸개로 유지.
- Section_View 1차에서 base 를 만들어 2차 카드에 그대로 넘김.
- 1차 반폭도 카드가 실제로 쓰는 값(effectiveCardHalfWidth, 자동 줌아웃 포함)으로 맞춤 —
  전에는 1차가 원래 반폭으로 재 카드·행 높이 기준이 어긋났음.
- 쓰이지 않게 된 crossCardNaturalHeight 와 그 재수출 삭제.

자체검증(공용 브라우저) — 카드 67장·SVG 67개 그대로, 같은 행 카드 높이 통일 유지
(rowsUniform true), 높이 범위 292~1,119px. 시험 400 통과·17 건너뜀, typecheck 통과.
효과 수치는 보조 창의 격리된 프로젝트에서 3회 중앙값으로 재기로 함(내 창은 편차가 큼).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 22:54:12 +09:00
eomsangdon 7060630f15 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 22:48:14 +09:00
eomsangdonandClaude Opus 5 c0bfcba34b feat(B05,B06): 유토 배분을 서버로 옮기고 브라우저는 미리 받아 쓰게 함
배분·운반거리 산식(_balance 523 + _settle 235 = 758줄)을 브라우저 번들에서 빼기 위한
배선. 계산은 여전히 한 벌 — 서버가 같은 TS 를 Node 로 돈다(CLAUDE.md 5장).

- POST /projects/{id}/sections/{route_id}/haul-plan 신설
  (B06_Section_Router_HaulPlan.py). 브라우저가 낸 누가토량 결과를 받아 배분만 돌려줌.
  화면이 쓰는 꼴 그대로 내보내 그리기 코드를 안 건드림. 표시 전용 — 정본은 저장 때 따로.
- B05_Profile_Api_HaulPlan.ts 신설 — 편집이 멈추면(400ms) 조용히 받아 두는 선반입기.
  늦게 온 응답은 버림(최신 요청만 채택). 못 받아도 곡선 자체는 그대로 보임.
- common_util_mass_haul.massHaulPayload 가 배분을 값으로 물던 것을 끊음(extra 인자).
  이 커플링 때문에 화면에서 안 불러도 번들에 남았음.
- 저장 경로는 곡선도 배분도 안 만듦 — 서버가 정본을 내므로 balloon 위치만 보냄.
- 죽은 파일 B06_Section_UI_Section_View_MassHaul.ts(236줄) 삭제.

자체검증(공용 브라우저, 용화 route 149) — 엔드포인트 200 · 196ms.
서버 배분과 브라우저 computeHaulPlan 결과가 JSON 문자열까지 동일(blocks 1 · steps 2 ·
spoil/borrow/hauled/transferred/fill_total 전부 일치). 시험 400 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 22:47:22 +09:00
eomsangdon f02eac5837 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 22:33:02 +09:00
eomsangdonandClaude Opus 5 1abb456ef9 perf(B06): 카드 넘침 정리를 한 프레임에 몰아 강제 레이아웃 67회를 1회로
카드마다 requestAnimationFrame(reflow) 을 걸어 한 프레임에 67번 돌았고, 매번
쓰기 뒤 읽기라 강제 레이아웃이 67회 났음. 한 번의 강제 레이아웃이 그때까지 들어간
카드 전부를 다시 재므로 뒤로 갈수록 비쌌음(보조 창 CPU 프로파일: 자기 시간 1위).

- reflow 를 reset(쓰기) / measure(읽기) / apply(쓰기) 세 토막으로 가름.
- 모듈 단위 scheduleReflow 가 카드를 모아 한 프레임에서 전부 reset -> 전부 measure ->
  전부 apply 순으로 돌림. 강제 레이아웃 프레임당 1회.
- ResizeObserver 는 창 크기 변경 때 그 카드만 큐에 다시 넣음(첫 호출 건너뛰기 유지).

자체검증(공용 브라우저) — B06 진입 2,330~2,864ms -> 1,994/2,088ms,
긴 작업 합 1,853 -> 1,604/1,728ms. 동작 확인: 카드를 200px 로 좁히면 버튼 3개가
... 패널로 옮겨지고 되돌리면 복귀(정상 폭에서는 scrollWidth = clientWidth = 937 로
넘침 없음). typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 22:32:17 +09:00
eomsangdon 81eb82a710 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 22:28:36 +09:00
eomsangdonandClaude Opus 5 5967d64b63 perf(B05): 측구 방향 역반영을 스레드 한 번 + 쓰기 한 문장으로 묶음
route/confirm 이 측점마다 종단 정본을 다시 열고(13.8ms) 행마다 DB 에 썼음(24.5ms).
건당 38.3ms 라 30건이면 1.15초, 67건이면 2.57초로 측점 수에 선형으로 늘었음
(보조 창 서버 내부 측정).

- 다시 계산할 측점을 먼저 고른 뒤 asyncio.to_thread 를 **한 번만** 돌림. 그 안에서
  종단 정본과 포장 제안표·세월교 하강표를 한 번 읽어 측점마다 돌려 씀.
- read_cross_design_inputs 에 preloaded 인자 추가(종단 경로·내용·포장 제안표).
  경로 검증은 resolve_longitudinal_path 로 떼어 재사용.
- 쓰기는 merge_cross_section_designs 한 문장.

자체검증(공용 브라우저 [저장] 3회) — route/confirm 470~834ms -> 324/351/356ms.
버튼 전체 대기 2,624~3,415ms -> 1,826/2,766/2,979ms.
(오늘 누적: 4,137ms -> 1,826~2,979ms) 시험 400 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 22:27:41 +09:00
eomsangdon 36a135f436 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 22:22:44 +09:00
eomsangdonandClaude Opus 5 0b30f5b035 perf(B05,B06): 지형 표고를 레이캐스팅 대신 격자 색인으로 · 카드 버튼줄 레이아웃 스래싱 제거
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 22:22:08 +09:00
eomsangdon 2476af0f4a Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-06 22:01:12 +09:00
eomsangdon 17ac08933f Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-06 22:01:09 +09:00
eomsangdonandClaude Opus 5 d650d705d1 perf(B06): 측점 설계 저장을 한 문장으로 묶어 원격 DB 왕복 제거
측점마다 SELECT+UPDATE 두 왕복을 냈고 DB 가 원격이라 왕복 하나가 약 12ms.
22행이면 670ms 이고 측점 수에 선형으로 늘었음(보조 창 서버 내부 측정).

- B06_Section_Repository_Bulk.merge_cross_section_designs 신설 — 노선 측점을 한 번에
  읽고, 파이썬에서 chainage 를 맞춰 JSON 을 합친 뒤
  `UPDATE ... SET data = CASE id ...` 한 문장으로 되돌려 씀(없는 행은 다중 INSERT).
  행 수와 무관하게 왕복 두 번. Repository 가 685줄이라 파일을 나눔(700줄 한계).
- 부르는 자리 셋을 묶음으로 바꿈 — _apply_section_edits 의 기본설계·측점 patch 두 루프,
  _recompute 의 보정·면적 두 루프.

자체검증(공용 브라우저 [저장] 3회) — sections/save 3,593ms -> 2,205 / 1,870 / 2,547ms.
버튼 전체 대기 4,137ms -> 2,624~3,415ms. 진행 표시는 2~3ms 만에 뜸.
시험 tmp/tests/test_b06_bulk_designs.py 5건(같은 JSON 결과·왕복 두 번·1cm 허용오차·
행 없을 때 INSERT·빈 목록은 왕복 0). 전체 400 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 22:00:28 +09:00