Commit Graph
279 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 2eb2c97293 fix(B06): 저장이 옛 면적을 싣던 자리 — 저장 직전 전 측점 재계산 + 「안 실림」 알림
⚠ 잡은 자리(2026-09-09 실측) — 표준단면 「측구 상폭」을 0.69 → 0.9 로 고쳐 저장했더니
정본 한 줄에 **새 측구 기하(상폭 0.9 · 측구 0.18㎡)** 와 **옛 절토 면적(3.33㎡)** 이 섞여
남았음. 브라우저는 만진 측점만 다시 계산하는데 저장은 전 측점 면적을 실어 보내므로,
안 만진 측점이 옛 값 그대로 정본이 됨. 수량이 갈리는 자리임.

- [저장]·[확정]이 면적을 모으기 **전에** 전 측점을 다시 계산함(`reconcileDesigns`).
- 표준단면 패널에 「고친 값이 측점에 아직 안 실렸음」 알림 — 언제 따라오는지 함께 적음.

 거울(파이썬·TS) 문제가 아님을 먼저 가름 — 같은 입력을 주면 두 쪽이 같은 값을 냄
(측점 20.0m: 0.69 기준 절토 3.328 · 0.9 기준 3.899, 저장분은 3.328 + 측구 0.180 으로 섞여 있었음).

시험 둘 추가(저장·확정이 재계산을 먼저 부르는지), 전체 1205 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 21:58:07 +09:00
eomsangdonandClaude Opus 5 5907de85c6 feat(B06): 측구 선택과 결과를 가른 칸 ditch_choice 추가
- 사용자가 누른 선택(`ditch_choice`)과 자동 판정 결과(`ditch_enabled`)를 다른 칸으로 나눔.
- 캐시(`CrossDesignChoice`)에 칸이 없어 토글이 화면에서 안 돌던 자리 이음 —
  선택이 있으면 그것을 따르고, 없으면 저장분 결과를 자동값과 다를 때만 선택으로 살림.
- 서버 patch 스키마에도 같은 칸을 둠. 최상위 `None` 은 병합에서 걷히므로
  「자동」으로 되돌리는 길은 아직 없음(카드 토글은 켬/끔 둘뿐이라 지금은 손해 없음).

화면 실측(카드에서 껐다 켜기)은 PLAN.md 3-16 에 미체크로 남아 있음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 20:32:50 +09:00
eomsangdonandClaude Opus 5 5cc5329cac fix(B06): 자동과 같은 측구 선택은 「자동」으로 풀림 — 다시 굳지 않게
화면 토글이 **2단**이라 「자동으로 되돌리기」 단추가 없음. 되돌리려면 원래 값으로 다시
누르는 수밖에 없는데, 그것을 선택으로 굳히면 **방금 고친 병이 그대로 되돌아옴**
(지형이 바뀌어도 안 따라감).

⇒ 선택이 자동값과 같으면 **선택 없음(자동)** 으로 본다. 파이썬·TS 짝 양쪽.
시험 하나 추가 — 「자동과 같은 선택은 자동으로 푼다」. 전체 617 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 13:18:21 +09:00
eomsangdonandClaude Opus 5 01c96e9a11 fix(B06): 측구 「선택」과 「결과」를 가름 — 한 번 저장되면 자동이 안 돌던 자리
⚠⚠ 한 칸(`ditch_enabled`)에 **두 뜻**이 담겨 있었음.
결과(실제 섰나)를 그대로 다시 입력으로 넣어 읽었으므로 **한 번 저장되면 자동 판정이
영영 다시 안 돌았음.** 계획고를 내려 절토가 생겨도 측구가 안 서고 **아무 말도 안 나왔음.**

- **선택** `ditch_choice` (없음 = 자동) · **결과** `ditch_enabled` (실제 섰나)로 가름
- 자동 판정을 **먼저** 하고 선택을 그 위에 얹음. 양성 단면은 선택보다 기하가 먼저
- ⚠ **옛 저장분은 자동값과 다를 때만 선택으로 살림** — 같으면 자동이 그렇게 냈던 것이고
  다르면 사용자가 일부러 바꾼 것임. 설계 의도를 잃지 않으면서 굳은 값을 푼 것
  (오늘 `length_m` 에서 겪은 「저장분이 걸린 자리」를 같은 방식으로 처리)
- 화면 카드는 이제 **선택**을 읽어 상태를 세우고, 표시는 **결과**를 보임
- 파이썬·TS 짝 양쪽 + 호출부 여섯 곳(재계산·저장·확정·사토장·요청 스키마)

시험 다섯 추가 — 「결과를 다시 넣어도 자동이 계속 돎」이 그 잠금. 전체 616 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 13:10:47 +09:00
eomsangdonandClaude Opus 5 f569cb8498 fix(B06): 화면 실측으로 잡은 사토장 흠 둘 — 지운 뒤 남던 값 · 가짜 경고
⚠ **시험만으로는 안 잡히던 자리임.** 실제 프로젝트에 사토장을 놓고 눈으로 본 뒤 잡음.

① **사토장을 지워도 값이 남음** — `enforce_spoil_fills` 가 **얹기만** 해서, 구조물을
   지운 뒤에도 저장분의 `spoil_fill_*` 가 그대로 남아 횡단도에 계속 그려지고 면적표에도
   섰음. ⇒ 사토장이 덮지 않는 측점에 **값이 남아 있으면** 사토장 없이 다시 계산해 지움.
   노선 성토도 그때 원래 값으로 돌아옴(사토장 몫을 빼 두었던 것이 복구됨).
   ⚠ **칸이 있는 것과 값이 있는 것은 다름** — 설계 결과는 사토장이 없어도 `0.0` 을 늘
     실으므로 「값이 남은」 측점만 되돌림(`_has_spoil_value`)
② **말풍선에 늘 뜨던 가짜 경고** — 「⚠ 0.0㎥ 는 못 담음」. 폭을 이분법으로 찾아
   400 − 399.9937 = 0.0063 이 남는 것이라, 표시 자릿수에서 안 보이는 몫은 경고 안 함

실측(프로젝트 fa76c162) — 지운 뒤 사토장 0 · 용량 null · 노선 성토가 정확히
「지우기 전 + 옮겨 갔던 몫」으로 복구됨(100m 1.7563+4.9217=6.678 …).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 12:57:34 +09:00
eomsangdonandClaude Opus 5 2972e4ccce refactor(B06): 횡단 설계 기하를 떼어 냄 — 924 → 522줄 (①/② 중 첫 조각)
TS 짝이 2026-09-04 에 이미 이 선으로 갈라 두었음(`common_util_cross_design_geometry.ts`).
**새로 긋는 선이 아니라 TS 에 있던 선을 파이썬에도 그은 것**이라 거울이 안 깨짐.

- `_SectionGeometry` + `_side_role`(TS `sideRole`) → `…_Engine_Design_Geometry.py`
- 안 옮긴 것 — 측구 방향 해석 · 지반 보간 · 사면 폐합 허용오차. **TS 도 본체에 둔 것들**
- 계산은 **한 줄도 안 바꿈**. 옮기기만 함

검증 — 거울 시험(횡단 설계선·단면적 두 쪽 대조) 통과. 전체 610 통과 / 22 건너뜀.
남은 것 — ② 표준값 해석·저장분 읽기 도우미 분리(522줄이라 급하진 않음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 12:42:20 +09:00
eomsangdonandClaude Opus 5 e1fed5f68b fix(B06/B08): 스냅된 관이 측점에 안 붙어 금액에서 빠지던 것 — 배수관 넷 복구
⚠⚠ **진단이 뒤집힌 자리임.** 계획서 3-14 는 「관을 나중에 놓으면 측점이 안 생긴다」로
적혀 있었으나 실측하니 **측점은 이미 있었음** — 구조물 이름표까지 달고.

진짜 원인 — **관 자리와 측점 자리는 최대 0.5m 어긋나고 그것이 설계임.**
측점을 만들 때 정수 미터가 같은 격자 측점이 있으면 그리로 스냅함
(`B05_Profile_Engine_Sections_Core` — 횡단 파일명이 정수 미터라 두 측점이 한 파일을
덮어쓰는 것을 막는 가드). 관 440.241 은 **측점 440.0** 위에 섬.
그런데 붙이는 쪽이 **0.02m** 로만 봐서 그런 관은 어느 측점에도 안 붙었음
⇒ 횡단도에 안 서고 길이도 안 실려 B08 이 「연장 없음」으로 막음.

- `attach_culvert_sets` / `attachCulvertSets`(짝) — **가장 가까운 측점 하나**를 그 관의
  자리로 봄. 거리로 자르지 않아 스냅 폭이 바뀌어도 따라가고, 하나만 고르므로 두 번 안 셈
- `pipeOwnerChainage` 신설 — 길이를 싣는 주인도 같은 규칙
- `SECTION_MATCH_TOLERANCE_M` 0.05 → 0.5 — 좁게 보면 「횡단 자체가 없습니다」라는
  **거짓 사유**가 뜸(반대 방향의 거짓). 옛 판단 근거를 주석에 남기고 뒤집은 까닭도 적음

실측 — 관 9개 중 **5개만** 길이가 있던 것이 **9개 전부**로 (440·620·720·900 복구).

곁들여
- 「측점 없는 구조물 N개」 알림 + [측점 만들기] 단추(3-14 ㉯) — **진짜로 측점이 없는**
  경우를 위해 남김. 판정은 스냅을 셈에 넣어 0.5m.
  샘플링 조건은 확정 때 남긴 `sampling.json` → 없으면 1단계 저장값. 둘 다 없으면 막고 사유
- 등록부 `retaining_wall.form` 에 「식생옹벽블럭」 추가(다른 창 요청)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 12:02:27 +09:00
eomsangdonandClaude Opus 5 513aff3ec0 feat(B06/B05): 사토장을 면적표에 갈라 보임 + 등록부 칸 셋
사토장
- 카드 면적표에 「사토장」 줄을 따로 세움 — 성토와 **합치지 않음**(확정 ㉠).
  사토장이 없는 측점에는 줄을 세우지 않음(어느 측점에 있는지 표에서 보이게)
- 성토와 다른 색으로 둠 — 같은 색이면 한 덩어리로 읽힘

등록부(다른 창 요청, 기본값 없음 — 현장 치수라 지어내지 않음)
- `erosion_check.top_length_m`·`bottom_length_m` — 골막이 정면적이 사다리꼴이라
  두 변이 있어야 셈. 실무 정본 산출식이 상장ⓐ·하장ⓑ를 씀
- `soil_guard.form` 에 「떼」 추가 — 실무 정본에 떼흙막이 산출식이 있는데 붙일 칸이 없었음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 11:36:54 +09:00
eomsangdonandClaude Opus 5 490566eb4d feat(B06): 횡단도에 사토장 성토선·말풍선 표시
교본 6장 3절이 운반처리 위치를 평면도·횡단도에 표시하도록 요구함.

- 긴 파선+점(9 3 2 3) · 사토장 색 — **터파기 짧은 점선과 선 종류를 가름**
- 이름표 「유용토운반작업장 ○㎡」 를 평상 위에 얹음
- 말풍선에 단면·폭·구간 용량·못 담은 몫·잘림 경고와 **근거 두 줄**
  (「폭은 노면 끝에서 잼」·「교본 6장 3절이 표시를 요구함」)
- 지반을 못 만나 잘린 사토장은 붉게 — 사면 미폐합 경고와 같은 결
- 계획선을 만져도 사토장이 안 사라지게 저장분 폭·구간값을 이어 붙임
  (폭은 구간 용량에서 서버가 정한 값이라 브라우저가 다시 풀지 않음)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 11:29:57 +09:00
eomsangdonandClaude Opus 5 3a5a13b488 feat(B06): 사토장 용량에서 폭을 정해 측점마다 세움
사용자는 「이 구간에 ○㎥」를 정하는데 단면은 폭을 알아야 그려짐.
그 구간 측점을 한꺼번에 보고 **폭 하나**를 이분법으로 찾음(작업장은 폭이 일정함).

- `enforce_spoil_fills` 신설 — `enforce_ford_surface_drops` 와 같은 자리·같은 방식.
  자동설계 체인·[저장] 뒤 **맨 마지막**에 돎(앞 보정이 다시 계산하면 사토장 칸이 지워짐)
- 「자동」이면 그 측점의 **성토 쪽**에 섬 (`structure_face_role` 재사용)
- 상한(지반 샘플이 있는 데까지)에서 멈추고 못 담은 몫은 `spoil_fill_unplaced_m3` 로 냄
- 구간 안 측점만 씀 — **새 측점을 만들지 않음**(사용자 확정 ③)
- 용량이 없으면 아무것도 안 세움(폭을 정할 근거가 없음)

실측 — 용량 200㎥·800㎥ 를 넣으면 각각 그만큼 담기고(오차 2% 안), 100만㎥ 를 넣으면
상한 폭에서 멈추고 남은 몫이 값으로 남음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 08:31:23 +09:00
eomsangdonandClaude Opus 5 d9b801aeaa feat(B06): 횡단 설계가 사토장 단면을 냄 — 노선 성토와 갈라서
사토장이 선 측점은 **노면 끝 바깥이 사토장 몫**이라 노선 성토에서 빼야 함.
안 빼면 같은 흙을 두 번 셈(2026-09-09 확정 ㉠).

- `compute_cross_design(spoil_fill=…)` / `computeCrossDesign({spoilFill})` 신설(짝)
- 새 칸: `spoil_fill_area_m2` · `spoil_fill_side` · `spoil_fill_width_m` ·
  `spoil_fill_max_width_m` · `spoil_fill_line` · `spoil_fill_unclosed` ·
  `spoil_fill_replaced_fill_m2`(노선 성토에서 뺀 몫 — 되짚기용)
- **합쳐서 하나로 내지 않음** — 받는 쪽이 갈라 볼 수 있어야 함
- 기울기가 비면 그 측점의 노선 성토 기울기를 그대로 씀(새 값 안 만듦)
- `fillAreaBeyond`/`_fill_area_beyond` — 경계 종거를 보간해 자름(한 칸도 안 흘림)
- 거울 시험에 사토장 사례 둘 추가 + 값이 0 이면 잡히는 가드

⚠ `B06_Section_Engine_Design.py` 가 924줄 — 700줄 제한 초과 상태임(이번 전에도 881줄).
  기능이 다 선 뒤 분리할 자리.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 07:51:41 +09:00
eomsangdonandClaude Opus 5 1379b7fd69 fix(B06): 채집석 공제도 축을 맞춰 뺌 — 갈래마다 ×C
채집석은 **벽 입적(제자리 부피)**이라 자연 축이고 유토곡선은 다짐 축임.
축이 다른 값을 그냥 빼고 있었음(리핑암이면 13% 어긋남).

- 갈래별 값(`collected_stone_by_ground_m3`)이 오면 갈래마다 ×C 해서 뺌
- 갈래를 못 가른 몫은 계수가 없어 **환산하지 않고** 그대로 뺌
- 갈래가 아예 안 오면 종전처럼 총량을 그대로 뺌 (안 온 것과 0 은 다름)
- 통로 정리 — `_mass_haul_context` 가 B08 입력 dict 를 통째로 받게 함
  (칸이 늘 때마다 인자를 늘리다 빠뜨리던 자리)

⚠ 벽 입적과 원바닥 암 부피의 관계를 정한 원문이 없음 — 그 가정은 그대로 두고
**축만** 맞춘 것임(세 창 합의, 근거 문구는 B08 이 값과 함께 보냄).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 07:27:02 +09:00
eomsangdonandClaude Opus 5 e5f540658d fix(B08): 운반 물량 상태 되돌림 — 거리는 다짐, 내역 수량은 자연상태
「운반거리의 산정 시에 모든 수량은 다짐상태로 환산하여 계산하고, 내역서에
적용하는 수량은 자연상태로 한다」(설계실무 요령, config 5-4-3 인용문) 인데
유토곡선이 쌓은 다짐 물량이 그대로 내역 줄로 서 있었음.

- HaulSummary: 줄마다 `natural_m3`(÷C)·`volume_basis`·`conversion_c` 를 함께 냄.
  환산은 이 파일 한 곳에서 한 번만. 거리·검산은 다짐 기준 그대로.
  `L`(1.3·1.35·1.625) 은 안 씀 — 품셈 10-11·10-12 가 `f = 1/L` 을 스스로 곱함.
- 토공집계표: 운반 줄을 자연상태로 실음. 갈래를 모르면 다짐 그대로 두고 사유 표기.
- 사토 줄: `natural_m3_by_ground`·`volume_basis` 신설. 갈래 없는 몫은 환산 안 함.
- 구조물 잔토(자연상태)를 곡선에 담기 전 ×C — 왕복이 맞게 됨. 갈래 모르면 그대로.

실측 변화(내역 4줄): 도자 토사 15.65→17.39 · 리핑암 70.30→61.13 ·
덤프 토사 33.76→37.51 · 리핑암 140.78→122.42 (합 260.49→238.45, −8.5%).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 07:03:48 +09:00
eomsangdonandClaude Opus 5 df6d33c462 feat(B06): 구조물 잔토에 터파기 토질을 이어받아 사토 갈래(ea/rr/br)를 채움
B08 이 구조물터파기에서 이미 판정한 토질(`design.ground_type`, 품셈 9-13 3구분)을
잔토 측점값에 함께 실어 준다. **새 근거를 만드는 것이 아니라 이어받는 것**이라
두 자리가 같은 판정을 쓴다(두 벌로 짜면 갈린다).

- `structure_spoil_points[].ground_type` (soil→ea · ripping_rock→rr · blasting_rock→br).
  옛 이름(`ground`)·라벨(`ground_label`)도 함께 받는다.
- ⚠ **섞여서 못 고른 구조물은 `null`** 로 오고 그 몫은 갈래 없이 담겨
  `ground_unknown_m3` 로 드러난다 — 임의로 토사로 몰지 않는다.
- ⚠ 한계는 그대로 넘어온다: 「터파기 깊이가 암반 경계선보다 깊은지」는 안 본다
  (터파기 토질에 이미 있던 한계이고 새로 생기는 것이 아니다).

시험 8건(갈래별로 담김·못 고른 몫은 「모름」으로 남음 포함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 23:15:08 +09:00
eomsangdonandClaude Opus 5 7e41c94be7 feat(B06): 담을 사토가 없으면 사토를 새로 세워 구조물 잔토를 담음 (확정 ㉰)
사토가 0 인 노선(전 구간 토취)에서는 잔토를 더할 자리가 없어 **물량이 그냥 사라졌다**.
파낸 흙은 어디로든 가므로 그것이 가장 나쁘다.

- 담을 사토 잔량이 없으면 **그 측점에 사토를 새로 세워** 담는다. 물량이 보존되고
  운반비가 붙는다(금액이 느는 방향 — 안전측).
- ⚠ 토취를 줄이는 길(㉯)은 「그 잔토를 성토재로 쓸 수 있다」는 근거가 있어야 한다.
  구조물 터파기 흙은 암이 섞일 수 있고 우리가 그 판정을 안 하므로, **근거 없이 금액을
  내리지 않는다.** 확정되면 이 함수 한 곳만 바꾸면 된다 — 그 문장을 주석에 남겼다.
- 새로 세운 사토는 자연방토 0 · 지반유형 안분 0 — 실어 내는 흙이고 지반을 모른다.
- 측점별 잔토를 Node 진입점까지 이어 붙임(빠져 있어 총량 갈래로 떨어지고 있었다).

실측(route 184): 사토 0 → **12.88㎥**, 잔량이 **측점 5m 자리에 섬**(전에는 노선 전체 구간).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 22:50:43 +09:00
eomsangdonandClaude Opus 5 abf586108c fix(B06): 구조물 몫(공제·잔토)이 실제로 흐르게 — 부르는 자리 둘이 인자를 안 넘기고 있었음
통로는 났는데 `_mass_haul_context()` 를 **인자 없이** 불러 값이 늘 `None` 이었다
(`Router_HaulPlan.py:64` · `Server_Calc_Prebuild.py:170`). 오늘 세 번째로 나온
「받는 곳은 있는데 넣는 곳이 없던」 자리다.

- `haul_inputs_for()` 로 B08 의 `project_haul_inputs` 를 받아 두 자리 모두에 넘긴다.
  ⚠ 여기서 다시 세지 않는다 — 두 값 다 B08 전개에서 나온다(CLAUDE.md 5장).
- 측점별 잔토(`structure_spoil_points`)를 받으면 **그 자리 잔량에 얹는다** —
  총량 비례로 흩으면 운반거리가 틀린다. 총량만 오면 종전대로 비례 분배(차선).
- 저장 payload 에 받은 값·실제로 먹은 값 넷을 남긴다 — 「값이 흐르는지」를 저장분에서
  바로 가릴 수 있어야 한다.

실측(route 184): 공제 0(구입이라 채집 없음) · 구조물 잔토 12.875㎥ 가 **실제로 전달됨**.
⚠ 그 노선은 사토가 0(전 구간 토취)이라 더할 잔량이 없어 `added=0` — 아래 물음 참조.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 22:44:50 +09:00
eomsangdonandClaude Opus 5 3ac616fb5b feat(B06): 구조물 잔토를 사토에 더하는 통로 신설 — 공제와 짝이 되는 자리
데스크탑 메인이 구조물 터파기·되메우기·잔토를 인계에 실었는데, **잔토 126.625㎥ 가
어디에도 안 실렸다**. 사토로 실어 내는 몫이라 유토곡선이 세야 겹치지 않는다.

    구조물 잔토는 사토에 한 번만 더한다.
    B08 은 소요량(structure_spoil_m3, ㎥ 양수)을 내기만 하고,
    더하는 자리는 유토곡선의 사토뿐이다.

- ⚠ **잔량 하나하나를 늘린다** — 총량만 늘리면 사토는 늘고 운반이 안 는다(공제 때와 같은 자리).
- ⚠ 나누는 법: 지금은 총량 하나만 오므로 **남은 사토 잔량 크기에 비례**해 나눈다.
  한 곳에 몰면 운반거리가 틀린다. 측점별 값이 오면 이 함수만 고치면 된다.
- ⚠ 자연방토·지반유형 안분은 안 건드린다 — 실어 내는 흙이고, 어느 지반에서 나온지 모른다.
- `null`(아직 안 옴) ≠ `0`(없음), 받은 값과 **실제로 더한 값**을 따로 싣는다.

시험 5건(더해짐·잔량 동반 증가·자연방토 불변·토취 불변·공제와 함께 와도 한 번씩).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 22:33:21 +09:00
eomsangdonandClaude Opus 5 9c811c4d20 fix(B06): 구조물을 놓아도 횡단도에 안 보이던 것 — 빈 초안이 저장분을 지우고 있었음
「구조물을 놓아도 횡단도에 아무것도 안 보인다」가 창 둘에서 같은 증상이었다.
화면에 표식을 심어 재 보니 **브라우저 쪽 단면에 `revetment` 자체가 없었다**.

- 원인: `withDraftWalls` 가 미저장 초안 목록이 **빈 배열**일 때도 「초안 있음」으로 읽고
  **서버 저장분(`revetment`)을 통째로 지운 뒤** 아무것도 안 얹었다.
  ⇒ `!drafts || !drafts.length` 로 고쳤다 — 빈 목록도 「초안 없음」이다.
- 초안 경로가 `foundation` 을 안 실어 터파기가 안 그려지던 것도 함께 고침
  (`WallSpec.foundation` 추가, 거울 시험도 같이 갱신).
- 겹침 방지 가드를 **좁혔다** — 링크가 있기만 하면 막던 것을, 그 링크의 벽이
  **이 카드에 실제로 설 때만** 막게 했다(`culvertWallsStandAt`). 관이 아홉·열하나인
  노선에서는 링크가 거의 모든 측점을 덮어 독립 벽 경로가 통째로 죽어 있었다.

화면 확인: 벽 터파기 「기초유 · 폭 1.62m · 깊이 0.50m (수직)」, 관 터파기 Φ1000 1.80m ·
Φ800 1.60m, 그려진 선 전부 좌우 변이 수직.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 22:16:24 +09:00
eomsangdonandClaude Opus 5 ae52ba7699 feat(B05·B06): 터파기 축을 관에도 · 독립 벽까지 잇고, 계수·강도 칸 신설
- `pipe.revet_foundation`(기슭막이 기초) 신설 — **유입·유출 한 칸**. 한 공사에서 한쪽만
  기초유로 하는 일이 드물어 폼을 둘로 안 늘렸다. 실무가 갈라 쓰면 그때 나눌 것.
- 독립 기슭막이·돌쌓기 갈래도 이음: 구조물 정본 `foundation` → `RevetmentSpec` →
  `RevetmentLayout.foundation` → 터파기 그림. ⚠ 이름을 저장 칸과 **같은 글자**로 뒀다.
- ⑨ `stone_coeff_basis`(품셈/실무 관행) · ⑩ `fill_concrete_mpa`(180/210) 칸 신설.
  ⚠ **기본값 없음** — 「비어 있음 = 아직 안 정함」이고 기본값(⑨ 품셈 · ⑩ 210)은 계산 쪽이 갖는다.
- 저장 왕복 확인: PUT 200 → 되읽기에서 "실무 관행"·"180"·"기초유" 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 21:48:54 +09:00
eomsangdonandClaude Opus 5 bec7e841e0 feat(B06): 횡단도에 터파기 선 — 관은 법정 표값 폭, 벽은 실무 정본 수직
사용자 확정 ④ 「터파기가 횡단도에서 표현이 안 된다 → 교본·실무문서로 구현 →
노티스 → 사용자가 선택」.

- 관: 관 위에서 관 바닥까지 **표값 폭**으로 수직(KCS 44 40 10 그림 3.2-1).
  표에 없는 관경이면 **안 그린다** — 폭을 지어내지 않는다.
- 벽: 벽 바닥선 아래로 **수직**(정본 식에 기울기 항 없음). 폭 = 바닥폭 + 여유 0.2,
  깊이 = 기초유 0.5 / 기초버림 0.1.
- ⚠ `foundation` 이 비어 있으면 **안 그린다** — 고르기 전에는 근거가 없다.
- 말풍선에 **근거의 급을 갈라** 적는다: 관은 「법정 표」, 벽은 「품셈에 규정이 없어
  실무 관행으로 정한 값」.
- 파선(`.b06-chart__excavation`)으로 구조물보다 먼저 그려 벽 밑에 깔린다.

화면 확인: 관 터파기 5개소, Φ1000 → 1.80m · Φ800 → 1.60m (표값 그대로).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 21:35:24 +09:00
eomsangdonandClaude Opus 5 f3f37494f2 fix(B06): [저장]이 「행은 있는데 설계가 빈 측점」도 채우게 함
재생성이 `cross_sections` 행을 지우고 다시 쓰면 `data.design` 에 면적 4키만 남는다.
`get_cross_section_designs` 는 `ground_type` 있는 줄만 담으므로 그 상태는 「설계 없음」이고,
B08 토적표가 통째로 0 이 됐다(창 셋에서 같은 증상).

원인은 결함이 아니라 분담이었다 — 체인은 재생성 뒤 [확정]을 불러 그 자리를 채웠고,
재생성만 따로 도는 길에는 그 단계가 없었다. 그래서 [확정] 없이도 정본이 서게 한다.

- [저장]이 확정과 **같은 조회**(`get_cross_sections_missing_design_chainages`)로
  빈 측점을 골라 기본 설계로 채운다.
- ⚠ **값이 있는 행은 안 건드린다** — 사용자 조작값·이월분이 거기 있다. 시험으로 잠금.
- 실측(route 184): 저장 뒤 DB 설계 62행·38키 복구, 층따기 13,696.8 ㎡,
  측구 토사 0.173 / 암 8.886 ㎡ — 파일 기반 값과 일치.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 20:12:22 +09:00
eomsangdonandClaude Opus 5 6a7c339f8a feat(B06): 측구터파기 단면적을 토사/암으로 가름 — 새 입력 없이 암반 경계선으로
별표2 Ⅰ.1.나.(5) 「측구터파기 단면적」이 횡단도 표의 법정 칸인데 한 값뿐이라
「측구 토사 / 측구 암석」 두 칸이 반만 채워졌다.

- 가르는 근거는 **절토 분리와 같은 것**(지반 유형 + 암반 경계선). 새 입력을 만들지 않았다.
- 측구 상단에서 암반 경계선까지의 깊이로 공칭 도형(사다리꼴·L형)을 가로로 가른다.
- ⚠ 근거가 없으면 **나누지 않는다.** 사유를 `ditch_split_basis` 로 함께 냄:
  rock_boundary / soil_ground / rock_ground_no_boundary / no_ditch.
- 기존 `ditch_area_m2` 는 **합계로 그대로** 두고 갈래를 덧붙였다 — B08 이 순서대로 옮겨 갈 수 있게.
- 파이썬·TS 짝을 함께 고침. 거울 테스트 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 19:22:58 +09:00
eomsangdonandClaude Opus 5 f60fb9c355 feat(B06): 채집석 공제를 사토에서 빼는 통로 신설
네 창 합의 문구 그대로 못 박음:

    채집석 공제는 사토에서 한 번만 뺀다.
    B08 은 소요량(collected_stone_deduction_m3, ㎥ 양수)을 내기만 하고 공제하지 않으며,
    빼는 자리는 유토곡선의 사토뿐이다 —
    실어 내는 몫(spoil_m3 − natural_spoil_m3)에서 먼저 빼고 모자라면 자연방토에서 뺀다.

- `computeHaulPlan` 이 공제를 받아 **잔량 하나하나**를 줄인다 — 총량만 줄이면 사토
  balloon·운반거리가 안 따라간다. 지반유형 안분도 같은 비율로 줄인다.
- ⚠ `null`(아직 안 옴)과 `0`(공제 없음)을 가른다. 결과에 받은 값과 실제로 뺀 값을 함께 싣는다.
- 서버 진입점·파이썬 context 를 통로로 이어 둠. B08 이 값을 내면 실어 주기만 하면 됨.

시험 3건(공제 반영·잔량 동반 감소·사토 초과 시 사토까지만·자연방토는 나중) 을
TS 를 실제로 돌려 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 19:15:27 +09:00
eomsangdonandClaude Opus 5 86437ce753 feat(B06): 층따기 밑수를 횡단 설계에서 냄 — 성토부 아래 원지반 지표면 길이
사용자 확정(2026-09-09): 층따기 단위는 ㎡. 대신 그 면적이 B06 설계에서 나와야 한다.

- `_bench_cut_length`: 성토(diff<0) 구간에서 원지반 횡단기울기가 **1:4 보다 급한**
  조각만 골라 지표면을 따라간 길이(빗변)를 더한다. 절·성토 경계는 영교점까지만 센다.
  근거는 별표2·교본 6장 4절, 지식DB 성토_비탈면 §4 [구현].
- 결과에 `bench_cut_length_m` 을 실어 B08 이 측점 사이를 평균단면적법으로 이어 ㎡ 를 낸다.
  ⚠ 여기서 ㎥ 로 바꾸지 않는다 — 단의 높이·폭은 설계도서 값이라 지어낼 수 없다.
- 파이썬·TS 짝을 함께 고침(`common_util_cross_design_areas.ts`). 거울 테스트 통과.
- ⚠ 성토 비탈면 길이가 아니라 **원지반 표면**을 센다 — 층따기 대상 면이 그쪽이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 19:06:53 +09:00
eomsangdonandClaude Opus 5 a1741be43f fix(B06): 좁은 폭에서 좌측 패널 항목이 2px 새던 것 — 그 폭에서만 라벨을 접음
창폭 480 에서 좌측 패널이 237 까지 물러나면 「횡단 반폭(m)」 라벨이 안 줄어
`.ui-field` 가 2px 넘쳤다(공용 `.ui-field` 는 안 건드리고 내 행에서 처리).

- `@media (max-width: 560px)` 에서만 라벨을 윗줄로 접는다.
- ⚠ 폭 제한 없이 `flex-wrap` 을 주면 넓은 폭에서도 라벨이 윗줄로 올라간다 —
  실제로 재 보고 되돌린 뒤 폭 조건을 붙였다.

확인(1400·760·620·480): 넘침 0 · 잘린 라벨 0 · 가로 스크롤 0,
넓은 폭 높이 42(한 줄) 유지, 480 에서만 68(두 줄).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 18:42:15 +09:00
eomsangdonandClaude Opus 5 8555e693ac fix(B06): 관 길이를 **소유 측점에만** 싣게 — 같은 관을 두 번 셀 뻔한 자리
`pipe_length_m` 을 넣고 실화면 [저장]으로 확인하다 드러남 — **관 9개인데 값이 10곳**에 실렸음.
까닭은 `attach_culvert_sets` 가 세트를 **폭의 절반까지 옆 측점에도** 붙이기 때문임(3D·카드가
이어 그리려고). 그 자리에 길이를 실으면 수량이 **같은 관을 두 번** 셈.

- 스펙에 **놓인 누가거리(`chainage_m`)** 를 함께 얹음 — 파이썬 `attach_culvert_sets` ·
  TS `attachCulvertSets` **둘 다**(한쪽만 얹으면 세트 거울 시험이 깨짐. 실제로 깨져서 알았음).
- 길이는 그 값과 측점이 같을 때만 실음.
- 옛 값 정리 — 이미 실려 있던 이웃 측점 4곳(260.0·800.0·900.0·980.0)에서 지웠음.
  **파생값이라 병합만으로는 안 지워짐**(merge 는 키를 얹기만 함).

⚠ **따로 드러난 것 — 관 3개(439.55·620.43·720.37)는 측점 행 자체가 없음.** 그 관들은 횡단
설계도 수량도 통째로 빠져 있음. 별건으로 조사할 것(계획서에 적음).

실측 결과 — 관 길이가 실린 측점 **6곳**(85.05→10.0 · 258.12→11.0 · 534.49→9.0 · 804.30→9.0 ·
901.24→10.0 · 984.18→10.0m). 나머지 셋이 위 별건임.

시험 7건(소유 측점 판정 한 건 추가) · 전체 507 passed · 17 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 09:36:23 +09:00
eomsangdonandClaude Opus 5 5f5e91d655 feat(B06): 배수관 연장(m)을 정본에 실음 — 수량이 관 공종을 셀 수 있게
B08 창 보고(2026-09-08): 관 11개가 `pipe_points.json` 에 있고 품셈 공종도 있는데 **연장(m)이
없어** 배수관 물량이 막혀 있었음. 관 길이는 횡단 기하가 **m 단위 올림까지** 끝낸 값
(`CulvertLayout.pipe.lengthM`)인데 **정본(`design`)에 안 실렸음**.

**옮기거나 새로 짜지 않았음** — 그 계산은 **이미 서버가 Node 로 그대로 실행**하고 있었음
(`B06_Section_Server_Calc_Node` ← `Server_Calc_Prebuild.recompute_server_side`, [저장]·[확정]).
구조물 폐회로 면적이 실리는 **그 다리에 값 한 줄만** 더 실었음 — 계산을 두 벌로 짜지 않음
(CLAUDE.md 5장). B08 창이 낸 갈래 둘(서버로 이관 / 저장 때 남기기)은 둘 다 불필요했음.

- `STRUCTURE_AREA_KEYS` → **`STRUCTURE_ROW_KEYS`** 로 이름을 고치고 `pipe_length_m` 추가.
  이름이 「면적」이라 길이를 담으면 거짓말이 됨.
- **면적을 못 내는 측점에서도 길이는 냄** — 설계선이 모자라 폐회로가 안 닫히는 자리에도
  관은 서 있고 수량은 그 길이가 필요함(`return pipeRow`).
- ⚠ **서버에 화이트리스트가 하나 더 있었음** — `_AREA_KEYS`(「Node 가 다른 키를 내도 안 흘림」).
  거기 안 넣으면 Node 가 값을 내도 **조용히 버려짐**. 넣고, **두 목록을 대조하는 시험**을 둠.
- 키 이름은 `pipe_length_m` 으로 **B08 창과 미리 못 박음** — 오늘 `back_len_cm` 이 엔진에서
  `stone_back_length_cm` 로 읽혀 저장값이 영영 안 닿던 사고가 있었음.

⚠ 값이 정본에 실리려면 그 프로젝트에서 **[저장] 한 번**이 필요하고, **번들 재빌드**
(`npm run build:server-calc`)도 필요함 — 번들은 git 밖이라 창마다 각자 돌려야 함.

시험 6건 — 패치로 받는지 · 음수 거부 · 면적과 **같은 목록**으로 실리는지 · 면적 실패 시에도
길이는 나오는지 · 이름을 두 번 적지 않는지 · **서버 화이트리스트와 TS 목록이 짝인지**.
전체 507 passed · 17 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 09:25:55 +09:00
eomsangdonandClaude Opus 5 032ea53ede feat(B06): 구조물 상세 제원을 B06 폼에서 받게 — 수량이 품셈 갈래를 고를 수 있게 됨
데스크탑 창 보고(2026-09-08): 실무 프로젝트 구조물의 **상세 옵션이 통째로 비어 있음** —
`back_len_cm`(뒷길이) · `stone_cm`(돌규격) · `form`(옹벽 형식). 그래서 B08 수량이 품셈 갈래를
못 골라 **금액이 0 으로 남음**(13-4 돌쌓기 뒷길이 · 13-6 큰돌쌓기 직경 · 12-3 옹벽 형식).

**까닭 — 아무도 안 받고 있었음.** 레지스트리가 그 칸들을 `phase: "detail"` 로 두고
「B05 는 유무·종류·위치만, **상세 치수는 B06/B07 에서**」(2026-08-17 사용자 확정)로 갈라 놨는데,
**그 화면이 아직 안 그리고 있었음**. 폼은 한 벌인데 필터(`isB05Option`)가 늘 상세를 숨겼음.

고침 — 폼이 `includeDetail` 을 받아 **B06 에서만** 상세 칸까지 그림(B05 는 종전 그대로).
새 결정이 아니라 **2026-08-17 확정을 이제 구현한 것**임.

⚠ **기본값 없는 필수 항목은 빈 칸(「— 선택 —」)으로 연다** — 첫 항목을 슬쩍 고르면 근거 없는
값(뒷길이 25㎝ 같은)이 수량·단가로 흘러감. 설계자가 고르게 둠.

**큰돌쌓기에 「쌓기 방식」(메쌓기·찰쌓기) 옵션 신설** — 품셈이 13-6-1 메 / 13-6-2 찰로 갈라
두는데 구분 칸이 없었음(돌쌓기는 이미 타입이 갈려 있음). 기본값 없음·필수·상세.

실화면 확인(용화 5601e828 · B06) — C군 → 큰돌쌓기 고르면 **돌규격·쌓기 방식** 칸이 빈 채로 뜸.
돌규격 `60~80` · 쌓기 방식 `찰쌓기` 로 한 건 넣고 [저장] → 정본 `structures.json` 에
`{"stone_cm": "60~80", "bond": "찰쌓기", …}` 로 남는 것 확인. 시험분은 지우고 저장해
**원래 7건**으로 되돌림.

시험 5건 — B06 만 상세를 받는지 · B05 는 종전대로인지 · 기본값 없는 필수는 빈 칸인지 ·
큰돌쌓기 메/찰 구분 · **규격 축이 타입마다 다른지**(큰돌쌓기=직경, 돌쌓기=뒷길이 — 데스크탑이
섞여 있던 결함을 잡은 자리). 전체 501 passed · 17 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 04:39:39 +09:00
eomsangdonandClaude Opus 5 33aa07f782 docs(B06): cut_slope_segments 는 지금 읽는 곳이 없음을 코드에 명시
데스크탑 창이 「법정 경사 검사가 빈 값을 볼 수 있다」고 알려 와 확인함. **검사 자체가 없어
문제 없음** — 별표2 검사는 오늘 폐기됐고(`cc428d7e`, 암질을 횡단도에서 안 고르기로 사용자
확정), 지금 이 값을 읽는 코드는 **한 곳도 없음**(계산해 내보내기만 함).

같이 확인한 사실 — 저장분에도 안 들어감. 실측(공용 DB) `cross_sections.data.design` **33키**에
`cut_slope_segments` 없음(같은 자리에 `cut_area_m2` 는 있음). 저장되는 것은 화면이 보낸
**설계 지정값**이라 엔진 출력 전체가 아님.

그런데 주석 셋이 아직 「법정 경사 검사가 읽는다」로 남아 있어 **다음 사람이 저장분에서 읽으면
된다고 오해**할 자리였음. 그 셋을 고쳐 ① 지금 읽는 곳 없음 ② 저장분에도 없음 ③ 남겨 두는
까닭은 소단 기하가 이 셈 위에 서 있어서 ④ **되살릴 때는 저장분에서 읽지 말고 계산해서 쓸 것**
을 적음. 코드는 한 줄도 안 바뀜(주석만).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:29:25 +09:00
eomsangdon 29559b2b5e Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1
# Conflicts:
#	B06_Section/B06_Section_Api_Types.ts
2026-09-07 18:09:36 +09:00
eomsangdon 77a614ecf9 Merge remote-tracking branch 'origin/main_desktop_1' into sub_laptop_1 2026-09-07 18:08:34 +09:00
eomsangdonandClaude Opus 5 e7695c678f feat(B06): 지반유형을 「토사」 토글 하나로 — 끄면 암(기본), 표준 패널에 각도 병기
사용자 확정(2026-09-07): 「리핑암과 발파암 버튼을 삭제하면서 구분의 의미가 없어졌어. …
토사버튼만 존재하고 이값은 활성화/비활성화로 반영(기본값은 비활성화) / 비활성화 상태에서는
암경계선이 나오고 암경계선 아래는 사용자가 지정한 암 절토각 반영. 이후는 토사 절토 각도를
반영 / 활성화 상태에서는 암반이 없으니 절토는 토사 절토 각도로만 구현」

**화면** — 카드 제목줄의 지반유형 버튼 셋(토사·리핑암·발파암)이 **「토사」 단추 하나**가 됨.
색으로 켜짐/꺼짐을 보이고 **기본은 꺼짐(암)**. 측구 토글과 같은 꼴임.

실화면 확인(용화 5601e828 · route 169 · 측점 1+0.0):
· **암**(꺼짐) — 암 경계선·암 절토각 칸 보임, 절토 토사 1.99 + 암 1.91 = **3.90㎡**
· **토사**(켜짐) — 두 칸 사라짐, 절토 **전량 토사 7.20㎡**(토사 경사가 더 완만해 더 팜)
· 다시 끄면 3.90㎡ 로 정확히 원복

**저장값은 종전 그대로** — 꺼짐 = `ripping_rock`, 켜짐 = `soil`. 옛 자료의 `blasting_rock`
도 「암」으로 읽힘. ⚠ 유토곡선·수량은 이제 암을 **한 종류(리핑암)**로 잡음 — 연암:경암 ·
발파암:리핑암을 가르는 것은 **설계내역에서 설계자가 비율로**(계획서 8-1).

표준 횡단면 설정의 절토·성토 경사 칸에 **각도를 함께 보임**(툴팁) — 카드가 도(°)로 받으므로
두 자리의 말이 갈리지 않게 함. 1:0.4 = 68.2° · 1:1.0 = 45° · 1:1.5 = 33.7°.

⑤ **표준을 바꿔도 개별로 고친 측점은 그대로**를 실화면에서 확인 —
1번 카드에 40° 를 넣고 표준 암 절토경사를 0.4 → 0.8 로 바꿔 [전체 측점 반영]:
· 1번(사용자 값) **40.0° 유지 · 암 절토 5.66㎡ 그대로**
· 2번(값 없음) 68.2° → **51.3°**(=1:0.8) · 암 절토 2.61 → 4.01㎡
· 표준을 되돌리자 둘 다 원상 복귀

시험 3건 더 — 토글 하나인지 · 기본이 암인지 · 옛 발파암 자료도 암 기하로 읽히는지.
전체 **486 passed · 17 skipped**.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 18:05:46 +09:00
eomsangdonandClaude Opus 5 6b9c115baa feat(B06): 절토 경사를 사용자가 넣게 — 카드에 암 절토각(°), 전체는 표준 설정
사용자 지시(2026-09-07): 「대신 경고부분은 삭제해주고 대신 각도를 사용자가 넣을수 있게 반영.
전체 공통으로 변경하는 경우에는 기본값 지정으로 하면 되지만 횡단도 하나만 변경하는 폼은
가져야함 / 개별 횡단도에는 암 절토 각도의 개별 수정 가능해야함」

**화면** — 암 측점 카드 아래에 「암 절토 68.2° ↺」 칸이 섬. 값을 넣으면 그 측점만 사면이
새 경사로 다시 그려지고 절토량도 따라 바뀜. ↺ 는 표준값으로 되돌림. 전체를 바꾸는 자리는
종전대로 좌측 [표준 횡단면 설정]임.

**계산에 넣는 자리는 한 곳씩** — 파이썬 `compute_cross_design(cut_slope_ratio=…)` ·
TS `computeCrossDesign({cutSlopeRatio})` 의 **그룹을 만든 바로 뒤**에서 경사비만 갈아 끼움.
부르는 쪽 9곳에서 표준값을 측점마다 복제하는 방식은 안 씀(한 곳만 빠져도 값이 조용히
사라지는 실패군). 기하·소단 코드는 한 줄도 안 건드림 — 25 확인대로 소단이 그 값을 읽어
서므로 **위치·개수가 새 경사를 저절로 따라옴**.

⚠ **경사는 나르는 값이 아니라 기하 입력임** — 계산 뒤에 키만 베껴 붙이면 설계선은 옛 경사로
그려지고 숫자만 새것이 됨(소단에서 겪은 자리). 그래서 재계산 세 경로(포장 강제·세월교 하강·
선형 재계산)와 브라우저 재계산·서버 프리뷰 **모두 계산 인자로** 넘김.

**되돌리기는 0 을 남김** — 세션에서 지우기만 하면 정본에 남은 옛 사용자 값이 되살아나
표준으로 못 돌아감. 0 = 「표준값을 씀」.

값의 길 — 세션 `cutslope`(등록표 한 줄) → 카드 입력 → [저장]·[확정]에서 `cross_patches`
(`design.cut_slope_ratio_user`) → 정본. `USER_TOUCHED_KEYS` 양쪽에 넣어 **표준을 바꿔도
개별로 고친 측점은 그대로** 둠(사용자 원문 끝줄).

시험 — 새 7건(넣은 경사가 실제로 그려짐 · 무릎 위 토사 경사는 그대로 · 0 은 되돌림 ·
재계산에도 남음 · **계산 전에 넘어감** · 각도↔경사비 · 칸은 암 측점에만),
거울 시험에 「암 절토 경사를 측점에서 바꿈」 한 갈래 추가, 7-3 회귀 한 줄 추가.
전체 **483 passed · 17 skipped**.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 17:52:06 +09:00
eomsangdonandClaude Opus 5 7833b9e677 feat(구조물): 소단을 「구조물 배치」로 옮김 — C군 사면안정 신설 (계획서 3-9, 사용자 재확정)
사용자 확정(2026-09-07) — 소단은 좌측 별도 폼이 아니라 **다른 옹벽·기슭막이와 같은 자리**
(구조물 배치)에서 놓는 것으로 바뀜. 기하는 그대로 두고 **입구만 옮겼음.**

· 레지스트리에 **C군(사면안정) 「소단」** 신설. 옵션은 다른 C군 구간형과 같은 꼴 —
  길이·기준측점 전·후 + 폭·간격(사면길이)·안쪽 기울기.
· ⚠ **소단은 C군 구간형이지만 벽이 아님** — 기슭막이 제원 자리에 얹히지 않게 파이썬·TS
  양쪽 벽 필터에서 뺐음. 안 뺐으면 소단을 놓는 순간 「독립 기슭막이」로 그려졌을 것임.
· 구조물 목록이 바뀌면 소단 구간을 세션 사본(`berm`)으로 펴고, 달라졌을 때만 재계산함.
  계산 계통(브라우저·서버·`USER_TOUCHED_KEYS`·옹벽 의무 판정)은 **한 줄도 안 바꿨음**.
· ④에서 만든 좌측 별도 「소단」 패널은 걷어냈음(모듈 삭제).

**안쪽 기울기 기본값 2° → 0°** (사용자 재확정). 기울이는 것은 실무이나 법령·교본 근거가
없어 기본으로 넣지 않고 폼에서 받음. 주석·지식DB 방침도 그에 맞춰 고침.

**소단측구**(B군 종단배수)도 같은 꼴로 옵션을 붙였음 — 소단 위에 놓이는 시설이라 폭·간격이
소단을 따르고, 기울기만 **사면 쪽**(소단과 반대). 소단이 실제로 서면서
`PENDING_TYPE_IDS` 빈 칸이 풀려 연장 수량이 다른 구조물과 같은 길로 나옴.

자체검증 — 「근거 없는 기본값 금지」 시험에 두 타입 12개 기본값을 근거와 함께 등재.
소단측구 연장 시험을 「빈 칸」에서 「연장 100m」로 뒤집음. 전체 544 passed · 18 skipped.
TS 타입 검사·ruff 통과. 화면 확인은 다음 단계.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 17:29:50 +09:00
eomsangdonandClaude Opus 5 c7770b7529 fix(횡단): 옹벽 의무 판정이 소단을 실제로 보게 함 — 부호·쪼개짐 두 곳 (계획서 3-9 ⑥)
앞 커밋으로는 화면 값이 안 바뀌어 실화면에서 두 가지를 더 찾았음.

① **TS 결과에 소단을 안 실었음** — 파이썬만 되싣고 브라우저 판을 빠뜨렸음.
   판정(`fillSlopeLengths`)은 브라우저에서 도는데 `design.berm` 이 없어 종전 식으로 갔음.

② **소단을 폭으로 찾으면 못 찾음** — 설계선 꼭짓점에는 지반 샘플(0.5m 격자)이 섞여 있어
   폭 0.5m 짜리 소단이 **두 도막으로 쪼개짐**(실측: 평탄부 0개). 게다가 설계선은 오프셋
   오름차순이라 **우측(음수) 성토면은 같은 소단이 `-기울기`로 나와** 부호를 그대로 대면
   역시 못 찾음.
   ⇒ **기울기로 가름.** 소단은 2°(0.035), 성토는 1:1.2~2.0(0.5~0.83)이라 성토 기울기의
   절반만 잡아도 확실히 갈림. 쪼개져도 부호가 뒤집혀도 걸림.

실화면 확인(8001·5174, `stale:false`) — 측점 2820.0m, 성토사면이 긴 자리:
· 소단 없음 → **≥32.54m** (옹벽·석축 의무 대상)
· 폭 0.5m·3m마다 놓음 → **≥3.00m** (5m 이내 — 의무 해소). 3.00m 은 소단 간격 그대로임
· 옆 측점(2840.0m, 안 놓음) → **≥32.54m 그대로**

**소단 없는 측점은 값이 안 바뀜 — 272측점 전수 대조, 달라진 곳 0.**
구조로도 보장됨(`design.berm` 이 없으면 종전 식을 그대로 탐).

전체 542 passed · 18 skipped. TS 타입 검사 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 16:59:48 +09:00
eomsangdon f6a0eff9b9 Merge remote-tracking branch 'origin/main_laptop_1' into main_desktop_1 2026-09-07 16:57:30 +09:00
eomsangdonandClaude Opus 5 cc428d7e12 revert(B06): 절토 경사 법정 검사 폐기 — 암질을 횡단도에서 고르지 않음
사용자 확정(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 16:56:26 +09:00
eomsangdonandClaude Opus 5 1e596846cd feat(B06): 절토 경사 판정 암질을 설계자가 고르게 — 기본 경암
사용자 확정(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>
2026-09-07 16:42:32 +09:00
eomsangdonandClaude Opus 5 db4f17fb1c feat(횡단): 성토면 소단 + 옹벽 의무 판정을 「소단 사이 구간별 최대」로 (계획서 3-9 ⑥)
한 묶음으로 처리했음 — 화면에 5m 판정이 틀린 채 서 있는 시간이 없게.

성토 사면 꼭짓점 짝 신설(`fill_profile_points` · `fillProfilePoints`). 절토와 달리
경사가 하나뿐이라 무릎이 없고, 소단 규칙은 같음. 설계선·지반 교차·꼭짓점 목록이 모두
그 선을 봄.

⚠ **옹벽 의무 판정을 함께 고쳤음** — 「성토사면 길이 5m 이내, 넘으면 옹벽·석축 의무」
(`성토_비탈면.md` §2)를 재는 `fillSlopeLengths` 가 **「성토선은 1:n 직선」을 전제로
수평거리 × 기울기**로 재고 있었음(주석에도 그 전제가 적혀 있었음). 소단이 들어가면 그
전제가 깨져 값이 틀림.

고침 — 소단이 있으면 설계선을 걸어가며 **소단으로 끊긴 한 도막**의 최대 길이를 잼.
· 전체를 한 줄로 재면 소단을 넣어도 5m 를 넘어 **의무가 사라지지 않음**
· 실효 경사로 재면 완만해져 **의무가 사라진 것처럼** 보임
둘 다 틀리므로 「끊긴 한 도막」이 맞는 기준임.

**소단이 없는 측점은 종전 식을 그대로 탐** — `design.berm` 이 없으면 예전 계산 그대로라
값이 한 톨도 안 바뀜(구조로 보장). 화면 전후 대조는 다음 단계에서 냄.

자체검증 — 새 시험 2건(성토면에 계단이 서고 같은 거리에서 덜 내려감 · 소단이 없으면
성토선이 곧은 한 줄). 전체 542 passed · 18 skipped. TS 타입 검사·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 16:38:33 +09:00
eomsangdonandClaude Opus 5 a066023da9 merge: sub_laptop_1 되받기 — 저장 흐름 import 충돌 해소
`B06_Section_UI_Page_Persist.ts` 의 import 한 줄만 갈렸음. 양쪽 다 쓰는 이름이라 합침 —
`readByKey`/`writeByKey`(저장소 선택을 한 창구로 모은 것)와 `writeState`(소단 배선)가
같은 파일에서 각각 한 번씩 쓰임. 다른 충돌 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 16:26:57 +09:00
eomsangdonandClaude Opus 5 4e7a4bf787 fix(횡단): 사면 구간 재료를 **그린 경사비**로 가름 — 「토사 경사인데 암」 라벨 없앰
다른 창이 전 측점을 돌려 찾은 것(용화 5601e828 · route 169, 63측점 124구간).
`material: "rock"` 인데 경사비가 1.0(토사)인 구간이 **13개** 나왔음.

까닭 — 재료를 **암반 경계선을 다시 재서** 붙였음. 그런데 무릎을 지난 뒤에도 경계선은
지반을 따라 계속 오르므로, 토사 경사로 그린 구간이 경계 아래로 **되돌아가 있는** 일이
흔함. 그것을 경계로 재면 그린 것과 라벨이 어긋남.

고침 — 재료는 **그 구간을 실제로 그린 경사비**를 따라 붙임(암 경사비에 가까우면 암,
토사 경사비에 가까우면 토사). 두 경사비가 같으면(2단 절토 아님) None.

영향 — 별표2 경사 판정이 갈리던 자리임. 13개가 「암인데 너무 완만」 위반으로 잘못 뜰 수
있었음. 토사 구간 50개는 종전대로 위반 0.

자체검증 — 새 시험 1건: 지반이 가파른 암 지반에서 모든 구간의 재료가 그 경사비와 맞는지
확인(어긋나면 실패). 거울 시험도 통과. 전체 542 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 16:25:46 +09:00
eomsangdonandClaude Opus 5 973128f798 feat(B06): 절토 비탈 법정 기울기 검사 — 별표2 범위 밖이면 카드에 경고
법정 위반 표시가 없던 유일한 자리였음(평면 곡선반경·성토사면 길이는 이미 있음).
절토 경사비는 표준 횡단면 설정에서 오는 입력값일 뿐이라 범위를 벗어나도 아무 표시가 없었음.

- 기준 — 별표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 16:20:42 +09:00
eomsangdonandClaude Opus 5 819aa643dc feat(횡단): 좌측 [소단] 패널 — 구간에 놓고 빼기 + 확정 뒤에도 남게 함 (계획서 3-9)
사용자가 소단을 **직접 놓는** 화면을 만들었음. 프로그램이 「붕괴 우려 지역」을 판정하지
않고, 법정 기준 셋 중 무엇도 자동 적용하지 않음(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>
2026-09-07 16:19:32 +09:00
eomsangdon d48302898f Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-07 16:09:54 +09:00
eomsangdonandClaude Opus 5 061d550e55 feat(횡단): 소단을 미리보기·재계산에 실어 화면에 계단이 서게 함 (계획서 3-9)
계단이 값에만 있던 것을 화면까지 연결함.

배선 — 세션 열쇠 `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>
2026-09-07 15:28:16 +09:00
eomsangdonandClaude Opus 5 5a6617f278 fix(횡단): 소단이 암 경계 아래로 되돌아가면 다시 암 경사로 그림 (계획서 3-9)
배분 창 지적으로 확인한 자리 — 미룰 수 없는 쪽이었음.

무엇이 문제였나 — 소단은 평탄한데 암 경계선은 지반을 따라 올라감. 지반이 1:1 이면
폭 0.5m 소단 하나를 지나는 동안 경계는 0.5m 오르고 소단은 2°(0.017m)만 오름. 그래서
설계선이 경계 아래로 **되돌아 들어가는 일이 흔함**. 무릎을 한 번만 꺾는 종전 규칙으로는
그 구간을 **암인데 토사 경사로** 그려 절토가 조용히 커짐 — 경고도 안 뜸.

고침 — `multi_knee` 를 둬서 경계를 오갈 때마다 꺾게 함. **소단이 있을 때만** 켬.
소단이 없을 때 켜면 지금 측점들의 설계가 같이 바뀌기 때문임(실측: 물결 경계 0.0016m).
기본값은 거짓이라 소단을 안 쓰는 프로젝트는 그대로임.

자체검증
- 새 시험 1건 — 경계를 뚫고 올라갔다가 소단마다 뒤처져 되돌아 들어가는 지형에서
  한 번만 꺾는 결과와 갈리고, 되돌아 들어간 구간이 암 경사(가파름)라 같은 거리에서
  더 높이 올라가는 것을 확인.
- 거울 시험에 되돌아 들어가는 경우를 한 줄 더해 파이썬·TS 일치 확인(12건).
- 전체 539 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 14:58:18 +09:00
eomsangdonandClaude Opus 5 e43ad18f97 feat(횡단): 절토 사면에 소단(계단) 기하를 넣음 — 파이썬·TS 짝 (계획서 3-9)
사용자 확정(2026-09-07)에 따라 소단을 **자동 적용하지 않고 사용자가 놓는 것**으로 만듦.
이 커밋은 그 기하 한 벌이고, 화면 폼은 다음 단계임.

새 짝 모듈 `common_util_cross_berm.py` · `.ts` — 절토 사면 꼭짓점을 만듦.
암 경계 무릎과 소단이 한 목록에 함께 들어가고, `breakpoints` 가 그 꼭짓점을 설계선에
실어 도면·면적·유토곡선·3D 가 계단을 그대로 봄.

기본값 폭 0.5m · 간격(사면길이) 3.0m · 안쪽 기울기 2°.
· 폭·간격은 별표2 범위(사면길이 2~3m마다 · 폭 50~100㎝) 안에서 가장 적게 파는 조합임.
  기본값은 되돌리기 쉬운 쪽이어야 함 — 더 넣는 것은 폼에서 한 번이지만 이미 판 것을
  되돌리면 전 측점을 다시 계산해야 함. 실효 경사로도 그러함(경사 1:1 기준)
  폭 0.5·간격 3 → 1:1.24 / 폭 1.0·간격 3 → 1:1.47 / 폭 1.0·간격 2 → 1:1.71.
· 기울기 2°는 사용자 확정값이고 법령·교본 근거가 없어 지식DB 에 적지 않음(사용자 지시).

무릎은 종전대로 **한 번만** 꺾음. 여러 번 꺾게 풀면 소단이 없는 지금 측점 설계도 같이
바뀌므로 별건으로 미룸(실측: 물결 경계에서 0.0016m 차이, 경계를 다시 만나면 구조가 달라짐).

자체검증
- 거울 시험 10건 `tmp/tests/test_cross_berm_mirror.py` — 소단 켠 5경우 포함해 파이썬·TS
  꼭짓점이 1e-9 안에서 일치. 간격이 수평이 아니라 사면길이 기준인 것, 평탄부가 2° 기운 것,
  소단이 없으면 옛 무릎 방식과 완전히 같은 것까지 확인.
- 면적 시험 6건 `tmp/tests/test_cross_berm_area.py` — 절토 55.115 → 78.785㎡(기본값),
  폭·간격이 물량에 단조로 반영, 소단 모서리가 설계선에 실림, 소단을 안 주면 설계선까지 동일.
- ⚠ 어림식 두 번을 시험이 잡아냄. 「늘어난 면적 = 폭 × 그 위 높이」는 틀림(11.797 vs
  7.770㎡) — 설계선이 밀리면 지반과 만나는 점도 함께 밀려 절토가 더 길어짐. 「폭만큼 밀림」도
  틀림 — 참값은 「그 아래 소단 개수 × 폭」임. 시험은 그 참값으로 잼.
- 기존 거울 시험(`test_b06_cross_design_mirror.py`) 10건 그대로 통과 — 리팩터가 값을
  안 바꿨다는 증거임. 전체 537 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 14:54:18 +09:00
eomsangdonandClaude Opus 5 8a0a8f18e3 feat(화면): 화면 배치를 계정에 저장 — PC 를 바꿔도 따라오게
사용자 승인(2026-09-07). 앞서 취향을 localStorage 로 옮겨 **탭·재시작** 문제는 풀었고,
이 변경은 그 위에 **다른 PC 에서도 같은 배치**를 얹음. 사용자가 노트북·데스크톱 두 대를 오감.

- `db_management/018_user_ui_prefs.sql` — 사용자당 한 줄, `prefs` JSON 한 칸.
  칸을 나누면 취향이 늘 때마다 마이그레이션이 또 필요해 한 칸에 담음.
- `GET/PUT /api/dashboard/me/ui-prefs` — 배치 값만. **설계값은 안 담음**(문자열만 받음).
- 로그인이 확인된 첫 순간에 한 번 받아 로컬 위에 얹고, 취향이 바뀌면 1.5초 모아 올림.
  서버가 없거나 못 읽으면 **로컬 값으로 그대로 돔**(계획서 원문).

⚠ 같은 함정을 또 밟을 뻔했음 — 키만 아는 자리가 저장소를 직접 고르면 **올려보내기도 안 걸림**.
그래서 `storageOf` 를 없애고 **읽기·쓰기 창구 하나**(`readByKey`/`writeByKey`)로 모음.
저장소 선택과 서버 올려보내기가 그 한 곳에만 있음. 그물도 그 이름으로 갱신.

**DB 는 아직 적용하지 않았음** — 표가 없으면 API 가 실패하고 화면은 로컬 값으로 도는 것이
정상 동작임. 적용 시점은 다른 창들과 맞춘 뒤.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 14:50:31 +09:00
eomsangdonandClaude Opus 5 159e2a5226 refactor(B06): 등록표 키를 쓰는 자리가 저장소를 직접 고르지 않게
오늘 같은 계통이 두 번 났음 — 키는 등록표에서 받는데 **저장소는 제 맘대로** 고르는 자리.
· `rockb` — 키를 날문자열로 만들어 읽는 쪽이 늘 빈 값(`f8fafd23`)
· 화면 취향 — 키는 맞았는데 저장소를 직접 골라 **절반만** 옮겨짐(`9db84d9d`)

남은 두 자리(암 경계선 저장·표시 반폭)도 `storageOf` 를 거치게 함. 지금은 둘 다 초안이라
세션이 맞지만, 통이 바뀌면 조용히 갈릴 자리였음.

그물도 넓힘(`test_session_keys_registered.py`) — 등록표 키를 쓰는 파일이 저장소를 이름으로
직접 고르면 깨짐. 고르는 곳은 `b_page_state` 하나. 앱 전역 값(`CURRENT_PROJECT_ID_KEY`)은
등록표 밖이라 제외하고 이유를 적어 둠. **훑어 보니 남은 위반 0곳.**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 14:41:38 +09:00
eomsangdonandClaude Opus 5 72e50b3edd fix(B06): 저장된 표준 횡단면이 새 탭에서 화면에 안 서던 것
표준단면 편집값은 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>
2026-09-07 11:47:27 +09:00