Files
ParaWiki/Output/reports/ADR-002-feature-dsl.md
minsung 20761ca795
All checks were successful
Publish ParaWiki / build-and-deploy (push) Successful in 31s
Feature DSL 아키텍처 ADR-002 추가
cimery Feature DSL의 20개 기본 결정 정리.
Rust 내장 DSL + IR + salsa 증분 + 별도 evaluator,
CSV 라운드트립 UX, AI·diff 친화 저장 구조.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:15:34 +09:00

199 lines
11 KiB
Markdown

---
id: ADR-002
title: cimery Feature DSL — 아키텍처 기본 결정
status: accepted
date: 2026-04-14
related-wiki:
- "[[특징 형상 기반 모델링 FBM]]"
- "[[증분형 갱신 알고리즘 LPG]]"
- "[[PCE 파라메트릭 변경 엔진]]"
- "[[Revit 조립 단위 분류]]"
- "[[선형 GIS 기반 좌표계]]"
related-adr:
- "[[ADR-001-tech-stack]]"
principles: [비패밀리, 증분, 선형-GIS]
---
# ADR-002 — cimery Feature DSL 아키텍처
## 결정
cimery는 Feature(특징 형상) 생성 규칙을 **Rust 내장(Internal) DSL**로 기술한다. DSL → IR → Evaluator → `GeomKernel`의 4계층 파이프라인, 증분·리액티브 재계산, 타입 수준 단위 강제, Excel 라운드트립 기반의 엔지니어 UX를 기본으로 한다.
## 배경
[[특징 형상 기반 모델링 FBM|FBM]]은 "생성 규칙의 자산화"를 요구한다. 이 규칙을 **어떤 언어**로 기술하고, 어떻게 저장·공유·검증·증분 갱신할지가 cimery 아키텍처의 근간이다.
거더교 MVP의 성격 (이 결정의 전제):
- **내부 파라미터 복잡도**가 본질. 선형·스테이션은 기본 입력일 뿐.
- 계산 비싸고 종속 복잡.
- 재사용 빈도는 **중간** (프리캐스트 거더 ~수십 인스턴스). Revit 패밀리(수천)도, 1회성도 아님.
## 결정 요약 표
| # | 주제 | 결정 |
|---|---|---|
| A | IR(중간표현) | **도입** |
| B | 평가 모델 | **Lazy / Reactive** |
| C | 단위(UoM) | 타입 수준 강제. **구조물 mm, 선형 m** |
| D | 의존성 추적 | **salsa crate** |
| E | IR 직렬화 | **JSON 선행 → MessagePack 승격** |
| F | 단위 구현 | **자체 newtype** (`Mm(f64)`, `M(f64)`) |
| G | Feature 조직 | 초기 **Rust 모듈** → 성숙 후 **WASM plugin** |
| H | salsa 입자도 | **Feature 단위 기본**, 비싼 sub-step만 개별 query |
| I | 기하 커널 호출 | **별도 evaluator 레이어** |
| J | DSL 문법 | **순수 builder** + 얇은 `macro_rules!` 설탕 |
| K | Feature 조합 | **2단 계층** (composite 허용, 공유 그래프 금지) |
| L | 파라미터 검증 | 타입 + `Result<_, FeatureError>` **하이브리드** |
| M | 프로젝트 파일 | 폴더 기반, 플레인 텍스트. **AI·diff 친화 최우선** |
| N | UI 모델 | **템플릿 Export → Excel 편집 → Import → DSL 생성** |
| O | USD 익스포트 | **증분 익스포트 지향** (초기엔 명시 Export) |
| P | 파라미터 선언 | **Rust attribute 매크로** (`#[param(...)]`) |
| Q | Excel 양식 | **CSV만, 단순 Replace** |
| R | 선형 입력 | **자체 포맷 (스테이션 + 점 배열 + 제원)** |
| S | 동시 편집 | **단일 사용자 + Git** |
| T | 테스트 | IR 스냅샷 + 기하 불변량 + 두 커널 cross-check + proptest |
## 파이프라인
```
[Rust 소스 — Feature DSL (builder + macro_rules!)]
│ #[param(...)] 메타 → CSV 양식 export
│ ← CSV import → DSL 소스 재생성
[IR] ─── JSON/MessagePack 직렬화 · salsa 질의 단위
[Evaluator]
[GeomKernel trait] ──► OpenCascade.js (웹) / opencascade-rs (데스크톱)
├──► 자체 wgpu 뷰어 (주 사용)
└──► USD 씬 익스포트 (Omniverse·IFC 5 파이프라인)
```
## 상세 결정
### A. IR(중간표현) 도입
DSL 실행 결과는 기하 호출 이전에 **IR**이라는 데이터 구조로 귀결된다. IR이 있어 직렬화·캐싱·증분·USD 익스포트·스냅샷 리플레이가 전부 깔끔하다. 기하 호출은 IR 이후.
### B. 평가 모델 — Lazy / Reactive
파라미터 변경 시 **전체 재계산 금지**. 영향권(cone of influence)만 무효화·재계산. [[PCE 파라메트릭 변경 엔진|PCE]]의 직렬 병목을 정면 돌파하는 경로이며 [[증분형 갱신 알고리즘 LPG|LPG 증분]]과 결합한다.
### C·F. 단위 — 타입 수준 강제, 자체 newtype
- 구조물: `Mm(f64)`. 선형·도로: `M(f64)`.
- 두 도메인 경계에서 **명시적 변환 필수**. 암묵 변환 금지.
- `uom` crate는 토목 도메인엔 과함 — 단위가 한정적이라 자체 newtype으로 명확·가볍게.
### D. 의존성 추적 — salsa
rust-analyzer가 실사용하는 증분 계산 프레임워크. 질의(query) 기반 자동 메모이제이션·무효화. 바퀴 재발명 회피. 한계 체감 시 자체 DAG 전환 고려.
### E. IR 직렬화 — JSON → MessagePack
- 초기: JSON — diff·리뷰·AI 가독성 우선.
- 규모 커지면: MessagePack — 이진·컴팩트. bincode는 Rust 종속이라 배제.
### G. Feature 조직 — 모듈 → WASM plugin
초기엔 `features::girder`, `features::bearing` 같은 Rust 모듈. 라이브러리가 커지고 써드파티 배포가 필요해지면 **WASM plugin**으로 승격. [[ADR-001-tech-stack|Tauri·PWA 듀얼 타깃]]이므로 WASM이 자연스러움.
### H. salsa query 입자도
기본은 **Feature 단위 query**. 단, 계산이 비싼 sub-step(단면 생성·스위프 등)은 개별 query로 분해. LPG의 ΔG 노드 = Feature 단위로 매핑 시작.
### I. 기하 커널 호출 — 별도 evaluator
`GeomKernel` trait 호출은 salsa query 안에서 직접 하지 않고, **evaluator 레이어**에서. IR과 기하 분리로 JSON 직렬화·USD 익스포트·스냅샷 리플레이가 깨끗해진다.
### J. DSL 문법 — 순수 builder 우선
```rust
let girder = Girder::builder()
.span(40.m())
.section(IBeam::new(...))
.build()?;
```
proc-macro는 DSL 핵심 문법에는 유보. 반복 패턴이 명확해지면 `macro_rules!`로 얇은 설탕. **단 파라미터 메타데이터 선언(P)에는 proc-macro 허용.**
### K. Feature 조합 — 2단 계층
`Bridge``Girder·Bearing·Pier` 등을 포함할 수 있는 composite 허용. 단 **순환·공유 참조 금지** (그래프가 아닌 트리). 초기 복잡도 억제 + 실무 서브 어셈블리 요구 커버.
### L. 파라미터 검증 — 하이브리드
- 타입: 음수·단위 불일치 같은 **물리적으로 말 안 되는 것**.
- 런타임 `Result<Feature, FeatureError>`: 범위·상호제약.
- 에러 메시지에 **경로 포함**`girder_3.flange_thickness < web_thickness`.
### M. 프로젝트 파일 구조 — AI·diff 친화 최우선
**인간 편의는 뒷전.** 폴더 기반, 플레인 텍스트(JSON/TOML), 결정론적 직렬화, 바이너리·zip 배제. IR 캐시는 gitignore. 구성:
```
project/
├── project.toml # 메타
├── features/ # Rust 소스 (Feature 정의·인스턴스)
├── alignment.json # 선형 (자체 포맷)
├── data/*.csv # 엔지니어 입력
└── .ir-cache/ # gitignore
```
### N. 사용자 인터페이스 — Excel 라운드트립
개발자가 Feature 템플릿(`#[param(...)]` 메타 포함)을 저작.
- 툴 → **CSV 양식 export** (엔지니어에게 친숙한 표).
- 엔지니어 → Excel에서 **값만 입력**.
- 툴 → **CSV import 시 DSL 소스 생성.**
- GUI는 뷰·파라미터 조정만. 주 입력 경로는 CSV 라운드트립.
### O. USD 익스포트 — 증분 지향
기본 뷰어는 자체 wgpu. USD는 **Omniverse·IFC 5 파이프라인 연계용**. 초기엔 명시 Export 버튼, 점진적으로 salsa/LPG 무효화 기반 **Prim 단위 증분 익스포트**로 이행.
### P. 파라미터 선언 — attribute 매크로
```rust
struct Girder {
#[param(unit = "mm", range = 10..=200, default = 150)]
flange_thickness: Mm,
#[param(unit = "mm", range = 8..=50, default = 12)]
web_thickness: Mm,
// ...
}
```
AI 친화 — Feature 정의와 메타가 한 파일. Excel export·import 툴이 이 메타를 읽어 양식 생성·검증.
### Q. Excel 양식 — CSV만, Replace
xlsx·Row ID·보호 영역 **일체 없음**. 재 import 시 기존 인스턴스 전체 교체. 중요 영역이 아니므로 단순화 우선.
### R. 선형 입력 — 자체 포맷
```json
{
"name": "main_alignment",
"stations": [{"station": 0.0, "x": ..., "y": ..., "z": ...}, ...],
"specs": { "type": "highway", "design_speed": 80, ... }
}
```
LandXML·IFC 4.3 Alignment 변환은 **프로그램 내부 import 루틴**이 담당. MVP 공식 입력은 자체 포맷만.
### S. 동시 편집 — 단일 사용자 + Git
툴 자체는 파일 락·트랜잭션 없음. 팀 작업은 브랜치·PR·병합 업계 표준 흐름. 실시간 협업(CRDT)은 오버스펙, 장기 비전 유보.
### T. 테스트·스냅샷 — 견고성 최우선
네 층 모두 **MVP부터 기본 탑재**:
1. **IR 스냅샷**`insta` crate, DSL→IR golden 비교.
2. **기하 스냅샷** — 불변량(부피·무게중심·바운딩박스·체크섬) 허용 오차 비교 + 중요 케이스는 STEP diff.
3. **두 커널 cross-check** — 같은 IR이 OpenCascade.js(웹)·opencascade-rs(데스크톱)에서 불변량 일치.
4. **proptest** — 핵심 Feature 2~3개 대상 속성 기반 테스트 (self-intersection 없음·부피 양수 등).
## USD의 위치 재확인
USD는 **Feature DSL이 아니다.** USD는 씬 기술 언어이지 규칙 언어가 아니며, 복잡한 파라미터 종속·계산을 표현할 수 없다. Feature DSL이 생성한 결과를 **Omniverse·시뮬레이션·IFC 5 파이프라인에 태우는 출력 포맷**으로 둔다.
## 기각된 대안
- **외부 DSL 선행** (OpenSCAD류 전용 문법): 파서·툴체인 자체 구축 비용. Rust 타입 안전성 포기. 필요 시 승격 가능하므로 지금은 아님.
- **비주얼 DSL 선행** (Grasshopper·Dynamo 스타일): diff·AI 가독성 낮음. 뷰어·에디터 구현 부담. 장기 보조 도구로만.
- **Eager 평가**: 거더교 파라미터 수·계산 비용을 감당 못함. PCE의 직렬 병목을 그대로 재현.
- **USD를 DSL 자리에**: 씬 기술 언어로 규칙을 기술하는 것은 구조적 오용. variants·references는 열거형 스위치 수준.
- **Revit Assembly식 바이너리 패밀리 축적**: [[특징 형상 기반 모델링 FBM|FBM]] 원칙에 반함. "규칙의 자산화"가 아닌 "인스턴스의 파일화".
## 후속 결정 필요
- [ ] UI 프레임워크 확정 (ADR-001에서 미정 항목 — egui / Yew / Leptos).
- [ ] salsa + GeomKernel 프로토타입으로 증분 성능 측정.
- [ ] 첫 Feature 세트 정의 (거더·받침·신축이음·교각 등 우선순위).
- [ ] WASM plugin 승격 시점·인터페이스 스펙.
- [ ] USD 스키마 매핑 (IfcBridge·IfcAlignment ↔ UsdGeom·UsdPhysics).
- [ ] LandXML/IFC Alignment import 루틴 구현 시점.
## 검토 시점
- 첫 거더 Feature 엔드-투-엔드(DSL → IR → 기하 → USD)가 동작할 때 ADR 재검토.
- salsa 증분 성능이 기대 이하면 재검토 — 자체 DAG·Adapton 등.
- IFC 5 + USD 표준화 진전이 있으면 O·R 항목 재검토.