chore(계획): 요구 434 분석 — 사면안정 구조물군 길 · 소단만 사본 = 옛 흔적 · PLAN 577

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-29 09:31:25 +09:00
co-authored by Claude Opus 5.5
parent 61373d70b0
commit 22ccd1085f
@@ -0,0 +1,102 @@
# 요구 434-4 · 435 — 사면안정 구조물군 로직 조사
조사만 · 코드 · git · storage · 마스터 안 고침 · 서버 · 브라우저 안 씀.
## 0. 한 줄 결론
- 소단도 놓기 · 저장 · M02 표 제어는 다른 사면안정 구조물과 같은 길임.
- 다른 것은 「횡단 계산에 들어가는 문」 하나 — 벽(옹벽 · 흙막이 · 돌쌓기)은 **계산 뒤 덧그림 · 자름**, 소단은 **계산 앞 입력**(설계선 자체가 계단)임. 이것은 성질이라 못 합침.
- 그런데 계산 앞 입력인 다른 시설(포장 · 물넘이 기울임 · 세월교 하강 · 맹암거)은 사본 없이 구조물 목록이나 측점에 얹은 형상에서 바로 읽음. 소단만 **저장 노선 다시 셈 한 길**에서 세션 사본 `berm` 을 거침.
- 사본은 성질 탓이 아니라 이력 탓 — 2026-09-07 처음엔 B06 카드의 측점 입력(세션 `berm` = 「측점키 → 폭 · 간격 · 기울기」 · 암 경계 `rockb` 와 같은 자리)이었고, 같은 날 「구조물 배치」로 옮기며 세션 칸을 구조물에서 편 사본으로 남김(`docs/raw/plans/2026-09-07_plan_completed_items_2.md:866-884`).
## 1. 마스터에 있는 사면안정 구조물군
| 종류 | type_id | 군 | 목록 | 표 형상 | 횡단도 | 3D | 정의 · 부품 줄 |
|---|---|---|---|---|---|---|---|
| 옹벽 | retaining_wall | C | 켜짐 | wall(형태 콘크리트 · 물빼기) | span3 | wall | `resources/master_template/구조물정의.json:919` · `common_util/common_util_structure_parts.json:287` |
| 흙막이 | soil_guard | C | 켜짐 | wall(빈 형태 = 통나무 · 목재틀) | span3 | wall | `구조물정의.json:1468` · `parts.json:318` |
| 소단 | berm | C | 켜짐 | **berm** | span3 | surface(설계선만) | `구조물정의.json:1905` · `parts.json:338` |
| 돌쌓기(찰) | masonry_wet | C | 숨김 | wall | span3 | wall | `구조물정의.json:1028` · `parts.json:298` |
| 돌쌓기(메) | masonry_dry | C | 숨김 | wall | span3 | wall | `구조물정의.json:1247` · `parts.json:308` |
| 큰돌쌓기 | boulder_masonry | C | 숨김 | wall | span3 | wall | `구조물정의.json:1720` · `parts.json:328` |
| (곁) 기슭막이 | revetment | D | 숨김 · 관 지점 정본 | hidden_revet | span3 | wall | `parts.json:366` |
| (곁) 비탈면 녹화 | revegetation | F | B06 만 | none | none | none | `구조물정의.json:2898` · `parts.json:479` |
- 낙석 · 블록 독립 종류 없음 — 블록은 옹벽 「형식」 선택지 「식생옹벽블럭」(detail 단계)뿐.
- 표 09(54-26) 칸 — 흙막이 형태 · 길이 · 높이 · 전 · 후 / 옹벽 형태 · 길이 · 높이 · 전 · 후 / 소단 **폭만**(`구조물정의.json:3379` 「표시」가 깊이 · 간격 · 기울기 · 높이 · 길이 · 전 · 후 숨김 → 깊이 1.0 · 간격 3.0 · 0° 기본값으로 돎).
- 「표 형상」 칸이 길을 가름(`common_util/common_util_structure_catalog.py` `resolve_catalog` · TS 짝) — wall 이면 벽 길 · berm 이면 소단 길 · 종류 키로 안 가름. M02 제어는 이미 같은 문.
## 2. 길 표 — 벽 대 소단
| 단계 | 벽(옹벽 · 흙막이 · 돌쌓기 · 큰돌) | 소단 |
|---|---|---|
| 놓기 | B05 「구조물 배치」 같은 폼 · 옹벽 · 흙막이 「추가 단」(`A00_Common/design/logic/design_structure_slope_tier.ts:26`) | 같은 폼 · 칸은 폭만 |
| 저장(정본) | `structures.json`(`B05_Profile/B05_Profile_Structures_Repository.py:50` 읽기 · `:110` 쓰기) | 같음 |
| 측점에 얹기 | 형상 얹기 한 벌 `attachShapes`(`common_util/common_util_structure_attach.ts:130-168`) → `wallSpecsFrom` · `attachWallSpecs`(`common_util/common_util_structure_walls.ts:105-168`) → `section.revetment` · 파이썬 짝 `B06_Section/B06_Section_Engine_Structures_Wall.py:72-110 · 179-197` · 서버 GET `B06_Section/B06_Section_Engine_Attach.py:169-199` | **안 얹음** — 구조물 목록 → `bermSpansFromStructures`(`common_util/common_util_berm_spans.ts:50-90`) → 구간 → 측점마다 `bermSpecAt`(:93) · 파이썬 짝 `Engine_Structures_Wall.py:113-176` |
| 횡단 계산 | 표준 설계선은 벽을 모르고 셈 → **계산 뒤** 벽 기하(`computeRevetmentLayout`)가 성토 사면을 벽에서 자름(트림) → 폐회로 면적으로 면적 칸 덮어씀(`B06_Section/logic/B06_Section_Structure_Layouts.ts:98-145 · 287 · 379` · `common_util/common_util_cross_structure_areas.ts`) · 저장 설계선 = 표준선 그대로 | **계산 앞** 입력 `berm` → 설계선 자체가 계단(`common_util/common_util_cross_design_geometry.ts:356` · `common_util_cross_berm.ts` · 파이썬 짝 `.py`) → 지반과 만나는 점이 밀림 · 면적 = 기본 적분 · 결과 `design.berm` 저장 |
| 횡단 조절(사용자) | 카드 끌기 → `design.revet_adjust`(횡단 patch · `B06_Section/logic/B06_Section_Design_Keys.ts:18`) | 카드 ▲▼ → 세션 `bermdepth` → `design.berm_depth_left/right_m`(횡단 patch · 같은 파일 :40-41) |
| 횡단 그림 · B07 | 덧그림 `B06_Section/B06_Section_UI_Cross_Revetment.ts` · B07 `B07_DesignDetail/B07_DesignDetail_Cross_Overlay.ts:493-500`(트림 설계선) · `:513`(벽) · 전개도 `B07_DesignDetail_Engine_Cad_Development.py:150` | 설계선 그대로(같은 `:493`) · B07 사면 가름 `B07_DesignDetail_Engine_SlopeGeometry.py:178 · 240`(design.berm) |
| 3D | 벽 스윕 `B05_Profile/logic/B05_Profile_Corridor_Structures.ts:300-306`(section.revetment) | surface = 설계선만 → 계단이 면에 그대로 |
| 수량(B08) | 토공 = 트림 폐회로 면적 · 구조물 집계 줄 없음(`B08_Quantity/B08_Quantity_Router_Summary.py:79-81` 배수 종류만) | 토공 = 계단 설계선 면적 · 집계 줄 없음 |
## 3. 계산 앞 입력 — 소단 대 다른 시설
| 길 | 소단 원천 | 포장 · 물넘이 기울임 · 세월교 하강 · 맹암거 원천 |
|---|---|---|
| 노선 초안(브라우저 묶음 cross 엔진) | `ctx.inputs.structures` → `bermAt`(`A00_Common/design/design_pipeline_page.ts:348` · `design_shared.ts:258-266`) → `crossWithBerm`(`B05_Profile/logic/B05_Profile_Pipeline_Detail.ts:123-146`) | 같은 `ctx.inputs.structures` → `crossWithShapes`(같은 파일 :267-286 · 형상 얹기) |
| **저장 노선 다시 셈**(브라우저 · cross=server 면 Node `cross.refresh`) | **세션 사본 `berm`**(`B06_Section/B06_Section_Cross_Refresh.ts:231-242`) ← 시설 줄 `syncBerm` · `putBerm`(`A00_Common/design/design_facility_lane.ts:155-182`) · 사본이 바뀌면 cross 를 한 번 더 부탁(forceCross) | 다시 셈 바로 앞에 형상 다시 얹음(`Cross_Refresh.ts:138` → `withDraftShapes` → `attachShapes`) → 측점 형상 읽음(`B06_Section/logic/B06_Section_Cross_Refresh_Calc.ts:224-243`) |
| 서버 Node 묶음 cross | `ctx.inputs.structures`(`A00_Common/design/logic/design_calc_node_stages.ts:193`) | 같은 status |
| [저장] · [확정] | 구조물 정본(TS `B06_Section/logic/B06_Section_Cross_Save.ts:222-256` · 파이썬 `B06_Section_Router_Design.py:224-228` → `B06_Section_Engine_Design_Node.py:139` Node `cross.berm_spans`) | 구조물 · 관 정본(`facilityRanges` 같은 파일 :222 · 파이썬 tilt_ranges · ford drops) |
| B05 확정 · 넓힘 | 저장 결과 `design.berm`(`B05_Profile_Router_Confirm.py:184` · `Engine_SampleExtend.py:162`) | 저장 결과 `design.paved` 등 |
- 사본은 저장 노선 다시 셈 한 길에만 있음. 까닭 = 묶음이 저장 노선 길 `savedCross(detail, routeId, stations)`(`design_pipeline_page.ts:357`)에 구조물 목록을 안 넘김 — 엔진 길(:348)은 넘김.
## 4. 소단만 다른 까닭
- **비탈 모양을 계산 전에 바꿔야 함 — 맞음.** 소단은 성토 사면 노면 끝 아래 깊이에 한 단 · 계단 뒤 사면이 다시 지반까지 걸어 내려가 만나는 점이 밀림(3-9 기록 — 늘어난 면적이 「폭 × 높이」가 아니라 밀린 거리로 정해짐). 계산 뒤 자르는 벽 방식으로는 못 냄.
- **벽은 비탈 모양을 안 바꿈.** 표준 사면으로 셈한 뒤 벽 자리에서 자르고 성토부선으로 대신 그림 · 면적만 폐회로 값(2026-09-06 확정 「구조물 자체 면적을 빼는 것이 아님」).
- **같은 일을 하는데 길이 다른 것 — 사본 하나.** 같은 「계산 앞 입력」인 포장 · 물넘이 · 세월교 하강 · 맹암거는 사본 없이 감. 소단 사본은 옛 B06 측점 입력의 흔적이고, 그 뒤 465 · 467(B05 만 연 탭) · 477-4(결과 통)로 사본을 덧고쳐 옴.
- 사본 때문에 따로 있는 것 — 시설 줄 `syncBerm` · `putBerm` · 사본 비교 · forceCross 한 바퀴(`design_facility_lane.ts:175-181`) · 계산 자리 서버 갈래 `C4.copy` · 지킴 시험(`test_477_undo_now_berm` · `test_272_berm_source`).
## 5. 한 벌로 합치는 안
### 안 A — 사본 없앰 (가장 작음 · 권함)
- 저장 노선 길에도 엔진 길처럼 구조물 목록을 넘김 — `design_pipeline_page.ts:357` 에서 `ctx.inputs.structures` 를 `savedCross` 에 더 넘김 → `design_shared.ts:270` savedCross 에서 노선 초안 `bermAt`(:262)이 이미 쓰는 `calcChecked("quantity", "cross.berm_spans", bermSpansFromStructures, …)` 로 구간 셈 → `CrossRefreshInput`(`Cross_Refresh.ts:75`)에 `bermSpans` 칸 → `gatherRefresh`(:233-241)가 세션 대신 그 값.
- 지움 — 세션 칸 `berm`(`A00_Common/b_page_state.ts` 결과 통 줄) · `writeBermSpans`(`B06_Section/B06_Section_UI_Page_Persist.ts:128`) · `syncBerm` · `putBerm` · `run(syncBerm)` 두 곳(`design_facility_lane.ts:155-182 · 237 · 244`).
- 고칠 파일 — `A00_Common/design/design_pipeline_page.ts` · `design_pipeline_page_types.ts:67` · `design_shared.ts` · `B06_Section/B06_Section_Cross_Refresh.ts` · `A00_Common/design/design_facility_lane.ts` · `B06_Section/B06_Section_UI_Page_Persist.ts` · `A00_Common/b_page_state.ts`. 시험 — `test_477_undo_now_berm.py` · `test_272_berm_source.py` · `test_511_a_calc_browser.py:62`(`C4.copy` 줄) · `helper_271` · `helper_473`(빈 stub).
- 파이썬 · TS 짝 — 그대로(파이썬 안 고침). 서버 Node 묶음 — `cross.refresh` 가 받는 `bermSpans` 꼴이 같고 `Cross_Refresh_Calc.ts` 안 고침 → 다시 짓기 없음.
- 값 영향 — 없음(같은 구조물 → 같은 구간). 구조물 고친 뒤 cross 한 바퀴 줄어듦 · 옛 사본으로 한 번 셌다 다시 세는 깜빡임 없어짐(코드 읽기 · 실측 안 함).
- 위험 — 낮음. 저장분 옛 꼴 없음(structures.json · design.berm 그대로 · 탭에 남은 옛 세션 `berm` 은 안 읽힘). 정본 자리 그대로 — 소단 제원 = 구조물 배치(structures.json) · 쪽 깊이 = 횡단 patch · design.berm = 계산 결과. 구조물을 아직 모를 때는 지금처럼 저장분 design.berm 으로 물러섬 유지.
### 안 B — 소단도 측점에 얹음(형상 얹기 한 벌에 들임)
- `attachShapes`(TS) · `_attach_python`(파이썬 짝)에 소단 얹기를 더해 측점 칸(예 `berm_span`)을 세움 → 다시 셈은 포장처럼 측점 칸을 읽음(`Cross_Refresh_Calc.ts:150`) · 노선 초안 `shapeContext`(`B05_Profile_Pipeline_Detail.ts:256`)도 같은 칸 → `crossWithBerm` · `bermAt` 옵션 · `bermSpans` 입력 지움 + 안 A 의 사본 지움.
- 고칠 파일 — `common_util_structure_shape_keys.ts` · `common_util_structure_attach.ts` · `common_util_berm_spans.ts` · `B06_Section_Engine_Attach.py`(SHAPE_KEYS · `_attach_python`) · `B06_Section_Engine_Structures_Wall.py`(얹기 짝) · `Cross_Refresh_Calc.ts` · `B05_Profile_Pipeline_Detail.ts` · `design_shared.ts` · `design_pipeline_page(_types).ts` · `design_calc_node_stages.ts` + 안 A 지움.
- 짝 — TS ↔ 파이썬 얹기 거울(`test_323_4_attach_mirror`) 늘림. 서버 Node 묶음(server-calc · corridor) 다시 지어야 반영.
- 값 영향 — 설계 값 없음. `SHAPE_KEYS` 가 3D 지문(`B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Hash.ts:41`)에 들어가 소단 측점 3D 저장본이 한 번 다시 셈 · 서버 GET 상세에 새 칸.
- 위험 — 중간. 정본 못 읽을 때 물러섬 · B07 · E03 이 같은 얹기를 씀(`E03_StabSection/E03_StabSection_Walls.py:50`).
- 이득 — 사면안정 구조물(벽 · 소단) 모두 「표 형상 → 측점 얹기 → 그림 · 계산」 한 길.
### 안 C — 「계산 앞 시설 맥락」 한 함수
- 같은 판정이 셋으로 나뉨 — 노선 초안 `shapeContext`(`B05_Profile_Pipeline_Detail.ts:256-264`) · 다시 셈 안쪽(`Cross_Refresh_Calc.ts:224-243`) · [저장] `facilityAt`(`B06_Section/logic/B06_Section_Cross_Enforce.ts:71`) + 소단 `bermSpecAt`. 안 B 위에서 포장 · 기울임 · 하강 · 소단을 한 함수로 모으고 [저장] 파이썬 짝(`B06_Section_Router_Design.py` 포장 · 기울임 · 소단)도 그 꼴로.
- 범위 큼(파이썬 [저장] 길 · 거울 시험 셋) · 지금 값 어긋남 없음 → 지금은 안 권함.
### 권함
- **안 A.** 물음(「왜 소단만 사본」)의 원인을 바로 없앰 · 값 그대로 · 파이썬 · 서버 묶음 안 건드림.
- 소단이 「계산 앞 입력」인 것은 성질이라 남음 — 벽과 같은 문(계산 뒤 자름)으로 합치는 것은 기하상 불가.
- 안 B 는 측점 얹기까지 한 길로 하고 싶을 때 다음 단계.
## 6. 사용자 물음
- 안 A(사본만 없앰 · 값 같음)로 갈지 · 안 B(소단도 다른 구조물처럼 측점에 얹음 · 소단 측점 3D 한 번 다시 셈)까지 갈지.
## 7. 확인 못 함
- 화면 실측 — 서버 · 브라우저 안 씀(지시대로) · 안 A 의 「cross 한 바퀴 줄어듦」은 코드 읽기로만.
- 낙석 · 블록 — 마스터에 독립 종류 없음 · 사용자 표 09 원본 문서와 대조 안 함.
- 3D surface 가 소단 계단을 그대로 면으로 그리는지 — 부품 이름 「설계선만(몸체 없음)」 · 코리도 빌드가 design_line 을 읽는 것까지만 봄.
- B08 사면안정 구조물 집계 — 지금 집계표가 배수 종류만이라 벽 · 소단 수량 길 없음(재작업 범위 · 이 조사 밖).
- 안 A 에서 계산 자리 quantity = server 일 때 저장 노선 소단 값 — 지금 `C4.copy` 는 서버 값만 · 노선 초안 `bermAt` 은 브라우저 값 + 뒤 대조. 안 A 는 노선 초안 꼴로 맞추는 것으로 봄(코드상 둘 다 가능).