Files
ParaWiki/Output/reports/ADR-004-sprint-25-39-decisions.md
minsung e32c09df2d 품질 강화 — ADR-004 + IFC snapshot 테스트 + helper 유닛 + clippy 경고 정리
## ADR-004 (Output/reports/ADR-004-sprint-25-39-decisions.md)
Sprint 25~39 기간의 **15개 아키텍처 결정** 정리:
- D1~D9: 거더교 MVP 확장 (단면 분기·다경간·Skew 관례·방호벽·격벽·Camber·헌치·UI)
- D10~D13: IFC4X3 Add2 익스포터 4 결정 (크레이트 분리·형상 전략 3단계·GUID·Camber 근사)
- D14: proc-macro 스캐폴딩 (전면 #[param] 는 Feature 10+ 안정 후)
- D15: 변단면 거더 알고리즘 (소핏 lift + Y 선형보간)
- 미결 6항목 (Pset 확장·LinearPlacement·ElementAssembly·IfcPile·#[param] 전면·변단면 IFC)
- 테스트 커버리지 101개 현황표

## IFC 스냅샷 테스트 (crates/ifc/tests/snapshot_tests.rs)
insta 기반 회귀 방지, 8개 baseline:
- mask_guids(): 22자 IFC GUID 를 'GUID' 로 정규화 (결정적 비교 가능)
- 시나리오: 기본 단경간 PSC-I / 2경간 π형 / skew 15° / camber 50mm /
  Rectangle 단면 / parapets off
- mask_guids 자체 유닛 테스트 2개

## Mesh helper 유닛 테스트 (crates/viewer/src/bridge_scene.rs helper_tests)
순수 함수 9개 검증:
- apply_camber_mesh: zero 항등·midspan 도달값·경간 밖 미영향
- rotate_y_around_z: 0 회전 항등·90° 피봇 회전·정점 개수 보존
- apply_variable_depth: zero 항등·소핏 lift · 지점 0 lift

## clippy lib 경고 15+ → 0
- map_identity (kernel/expansion_joint.rs)
- unnecessary_lazy_evaluations ×4 (dsl/abutment·pier·csv_template — auto-fix)
- too_many_arguments (usd save_scene — allow with justification)
- clamp-like 패턴 ×7 (viewer bridge_scene/incremental_scene 의 .max(1).min(N) → .clamp(1, N))
- redundant_closure ×2 (project_file 의 `|e| Error::other(e)` → `Error::other`)
- redundant_guard ×1 (viewer KeyboardInput match guard → 패턴 내 직접 매치)

cargo clippy --workspace --lib: 0 경고.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 08:37:11 +09:00

11 KiB
Raw Blame History

id, title, status, date, related-wiki, related-adr, principles
id title status date related-wiki related-adr principles
ADR-004 cimery Sprint 25~39 아키텍처 결정 — 거더교 MVP 확장·IFC4X3 Add2·proc-macro 스캐폴딩 accepted 2026-04-15
교각 형식 분류
교각 파라미터 카탈로그
선형 GIS 기반 좌표계
특징 형상 기반 모델링 FBM
ADR-001-tech-stack
ADR-002-feature-dsl
ADR-003-architecture-followups
비패밀리
증분
선형-GIS

ADR-004 — Sprint 25~39 아키텍처 결정

Sprint 124 기반 위에서 거더교 MVP 확장과 IFC4X3 Add2 익스포터 Phase 13b 구축 중 내린 15개 결정을 정리. 이후 세대 에이전트가 설계 의도를 빠르게 소환하도록 한다.

결정 요약표

# 주제 결정 Sprint
D1 단면 타입 분기 SceneParams section_type 로 런타임 분기. build_selectable_scene 하드코딩 금지 25
D2 span_m 의미 경간 당 길이(총 길이 아님). 다경간 총 길이 = span_m × span_count 26
D3 피어 MVP 스펙 wiki 112개 변수 중 Phase 1 = 30% 입력만. 기본 사각기둥·CSB 2m 26
D4 거더·데크 Skew 미적용 (precast 거더 관례). 교대·교각·받침·신축이음만 회전 27
D5 방호벽 표현 뷰어: 독립 RC 박스 / IFC: IfcRailing .GUARDRAIL. 28
D6 격벽 표현 뷰어 전용 (IFC 미구현, Phase 4 ElementAssembly 로드맵) 29
D7 Camber 알고리즘 포물선 4·mid·u·(span-u)/span², 경간별 독립 적용 30
D8 헌치 Y 기준 데크 soffit Y = bearing_h + girder_h + haunch_depth 31
D9 UI 카테고리 6 섹션 CollapsingHeader 분리 (상부/바닥판/기하/하부/추가/표시) 32
D10 IFC 크레이트 분리 cimery-ifc 독립 크레이트. viewer/app 에서 선택적 의존 33
D11 IFC 형상 전략 Phase 1 Rectangle → Phase 2 PSC-I Arbitrary → Phase 3 Alignment 33-36
D12 IFC GUID UUIDv4 → base64-22 (buildingSMART charset 0-9A-Za-z_$) 33
D13 IFC Camber 근사 camber > 0 시 거더를 N=10 세그먼트 IfcExtrudedAreaSolid 로 분할 37
D14 proc-macro 스캐폴딩 cimery-macros 최소 선행 — #[derive(ParamSummary)] 만, 전면 #[param] 은 Phase 2 38
D15 변단면 거더 알고리즘 포물선 soffit lift + Y 선형보간 y_new = y + lift·(1 - y/h) 39

D1. 단면 타입 런타임 분기

맥락: build_selectable_sceneSectionType::PscI 를 하드코딩. 사용자가 SteelBox 를 선택해도 PscI 로 렌더되는 버그.

결정: SceneParams.section_type 로 런타임 분기. build_bridge_scene 과 동일한 match 패턴 적용.

근거:

  • 하드코딩은 FBM(비패밀리 원칙) 위반.
  • build_bridge_scene 에 이미 올바른 패턴 존재 → 한 쪽만 틀린 비대칭 버그.

영향: SteelBox·PscU·SteelPlateI 추가 시 match p.section_type 에 한 줄만 추가. 카탈로그 확장 비용 최소화.


D2. span_m 의미 재정의

맥락: 단경간 가정 하에 span_m = 전체 교량 길이 로 사용. 다경간 추가 시 의미 충돌.

결정: span_m = 경간 당 길이. span_count 신규 도입. total_mm = span_m × span_count × 1000.

근거:

  • 실무 교량 설계는 "경간 × N" 으로 사고 (예: "40m × 3 연속교").
  • ProjectFile 호환성: v1 저장 파일(span_count 없음)은 default = 1 로 기존 단경간 동작 유지.

대안 기각:

  • total_length_m + span_count (계산 필요, 사고 무겁)
  • span_lengths: Vec<f64> (MVP 과도, Phase 2+)

D3. 피어 MVP 스펙 — wiki Phase 1

맥락: ParaWiki [[교각 파라미터 카탈로그]]112개 변수 vs 현재 PierIR ~8개 변수 격차.

결정: Phase 1 MVP = 사용자 입력 30% ≈ 30개 변수 중 핵심 5개만:

  • pier_type (T/π), column_count (1/2), column_diameter/depth (CSB 매트릭스 기본값 2000mm), column_height, cap_beam 치수.

나머지 82개 자동계산·상세 변수는 Phase 2~4 로드맵 (wiki 안내 순서).

근거:

  • MVP 원칙: 기능 축소 OK, 아키텍처 타협 금지.
  • 112개 전면 구현은 IR·DSL·UI·IFC 4 레이어 동시 확장 필요 → Sprint 1개에 불가.
  • wiki 의 "Phase 1" 권장 순서가 엔지니어링 검증된 우선순위.

D4. 거더·데크 Skew 미적용

맥락: 경사교(skew bridge) 표현 방식 선택.

결정: skew_deg 파라미터는 교대·교각·받침·신축이음에만 Y축 회전 적용. 거더·데크는 직선 유지.

근거:

  • Precast 거더 스큐 교량의 일반 관례 — 거더는 직교 제작, 교대 seat 만 사각으로 절단.
  • 사각 데크 슬래브는 현장 타설 평행사변형으로 맞춤 (본 MVP 스코프 밖).
  • 거더 회전 시 mesh 경계 교대와 맞물리는 정합성 문제 발생.

영향: rotate_y_around_z() 헬퍼로 지점부 요소만 후처리 회전. 기하 복잡도 최소화.


D5~D6. 방호벽·격벽 표현 경로

D5 방호벽 (Parapet):

  • 뷰어: 독립 RC 박스(500mm × 1200mm × 전체 길이) 양쪽 엣지
  • IFC: IfcRailing .GUARDRAIL.

D6 격벽 (Diaphragm):

  • 뷰어 전용. IFC 미구현.
  • 향후 IfcElementAssembly 로 Pier 그룹 + Diaphragm 포함 예정 (Phase 4).

근거:

  • IFC 표준에서 방호벽 → IfcRailing 이 가장 근접.
  • 격벽은 IFC4X3 에 전용 엔티티 없음 — IfcBeam 또는 IfcElementAssembly 내부 원소로 표현.
  • MVP 에선 격벽을 IFC 스킵하고 뷰어만 지원 → 범위 축소.

D7. Camber 알고리즘

결정: 포물선 수식 y_off(u) = 4 · mid · u · (span - u) / span², 경간별 독립 적용.

근거:

  • 실무 거더 precamber 근사식과 정합 (중앙에서 최대, 양단 0).
  • 경간별 독립 → 다경간 연속교에서도 각 경간이 올바른 솟음.
  • 정점 단위 Y 오프셋만 추가 → mesh 생성 파이프라인 변경 최소.

구현 위치: apply_camber_mesh(mesh, z0, z1, mid_mm) — 순수 함수, 단위 테스트 가능.


D8. 헌치 Y 기준

결정: 데크 soffit Y = bearing_h + girder_h + haunch_depth (헌치 0 이면 거더 상면 = 데크 소핏).

근거:

  • 현실 bridge 단면: 거더 top flange → 헌치 블록 → 데크 soffit 순서.
  • 단일 변수 haunch_depth 로 데크 높이·신축이음·방호벽 기준선 전부 이동 (6군데 일괄 수식 변경).

D9. UI 카테고리 6 섹션

맥락: Sprint 14 ~ 31 누적 슬라이더·체크박스 11개가 한 덩어리 섹션에 쌓임.

결정: 6개 CollapsingHeader 로 분리:

  1. 상부구조 (경간·거더 5개)
  2. 바닥판 (슬래브 두께·헌치)
  3. 선형·기하 (경사각·솟음·변단면)
  4. 하부구조 (교각 형식)
  5. 추가 부재 (가로보·신축이음·격벽)
  6. 표시 (선형·투영)

근거: Revit UX 패턴과 정합 (카테고리별 속성 분류). 슬라이더 10+ 개 평면 배치는 스캐닝 비용 높음.

매크로 hygiene 부산물: ps! 매크로가 외부 ui 를 캡처하는 문제를 ps!($ui, ...) 명시 매개변수화로 해결.


D10~D13. IFC 익스포터 4 결정

D10 크레이트 분리: cimery-ifc 독립. viewer/app 에서 선택적 의존 (deps: cimery-ifc = { workspace = true }). 크로스 컴파일·WASM 호환성 격리.

D11 형상 전략 3단계:

  • Phase 1 (Sprint 33): IfcRectangleProfileDef 일률 — 엔티티 계층·워크플로 검증용
  • Phase 2 (Sprint 34): IfcArbitraryClosedProfileDef + IfcPolyline 로 PSC-I 14점 실제 단면
  • Phase 3b (Sprint 36): IfcAlignment 독립 엔티티 — LinearPlacement 는 Phase 3c+

D12 GUID: UUIDv4 → buildingSMART base64-22 (0-9A-Za-z_$ charset).

  • 대안 기각: IFC1 규격 Base85 — 길이 20자지만 charset 가독성 낮음.

D13 Camber 근사: camber > 0 시 거더를 CAMBER_SEGMENTS = 10IfcExtrudedAreaSolid 로 분할.

  • 대안 기각 1: IfcSurfaceCurveSweptAreaSolid — directrix curve 정의 복잡, 뷰어 지원도 낮음.
  • 대안 기각 2: 단일 extrude + 속성에 camber 값만 기록 — 기하가 평평함, 시각 검증 불가.
  • 선택: 다중 세그먼트 포물선 근사. 10 세그먼트 해상도면 ~1mm 오차, BIM 뷰어에서 곡선처럼 보임.

D14. proc-macro 스캐폴딩

맥락: ADR-002 D #[param(unit, range, default)] 전면 구현 제안 대비 현재 Feature 카탈로그 규모.

결정: Sprint 38 에서 cimery-macros 크레이트와 #[derive(ParamSummary)] 최소 선행만. 전면 #[param] attribute 는 카탈로그 10+ feature 안정 후.

근거:

  • 현재 Feature = 거더·데크·받침·피어·교대·가로보·신축이음 7종. 수동 builder 로 관리 가능.
  • Proc-macro 전면 구현은 큰 투자 — 실제 사용처(중복 보일러플레이트)가 누적돼야 ROI.
  • 크레이트 인프라(syn/quote) 만 먼저 세팅 → 향후 #[param] 추가 시 진입 비용 최소.

D15. 변단면 거더 알고리즘

결정: 포물선 soffit lift + Y 선형보간.

  • lift(u) = 4 · max · u · (span - u) / span²
  • y_new = y + lift(u) · (1 - y/h)

근거:

  • 연속교 중앙부 단면 축소의 물리적 모델: 상면 유지(도로면 평탄) + 소핏 상승 = web 축소.
  • 선형 보간 계수 (1 - y/h) 로 정점 클래스 구분 없이(top/web/bottom 구분 불필요) 균일 처리.
  • 단일 함수 apply_variable_depth(mesh, z0, z1, max, girder_h) — camber 와 독립 조합 가능.

영향: 상수 단면 mesh 생성 후 post-process 만 추가. 커널(psc_i.rs·steel_box.rs) 수정 불필요.


미결·재검토 항목

  • C1 Pset_BearingCommon / Pset_SlabCommon: Sprint 35 에서 Pset_BeamCommon 만 구현. 후속 스프린트에서 확장.
  • C2 IfcLinearPlacement: Sprint 36 에서 IfcAlignment 만 추가, 요소 배치는 아직 IfcLocalPlacement. Phase 3c.
  • C3 IfcElementAssembly: Pier 의 column + cap beam + footing 을 그룹화. Phase 4.
  • C4 IfcPile: IFC4X3 신규 엔티티. 현재 피어 기초는 IfcFooting 으로 통합 표현. Phase 4.
  • C5 #[param] 전면 구현: D14 언급, 카탈로그 확장 시점에 재검토.
  • C6 변단면 거더 IFC 반영: Sprint 37 Camber 와 동일하게 세그먼트 분할 기법 적용 가능.

테스트 커버리지

Sprint 25~39 기간 추가된 테스트:

  • cimery-ifc: 20 lib + 8 snapshot = 28
  • cimery-viewer mesh helpers: 9 (camber/rotate/variable_depth)
  • cimery-macros derive: 3
  • 기존 kernel 4층 테스트: 61 유지

61 + 40 = 101 테스트 통과 현황.


관련