All checks were successful
Publish ParaWiki / build-and-deploy (push) Successful in 31s
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>
199 lines
11 KiB
Markdown
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 항목 재검토.
|