"같은 입력이 항상 같은 출력을 내야 하는 일이면 Rust 몫이야. 빠르고, 테스트가 되고, 절대 추측하지 않으니까."
Rust 코어에 사는 것
봉합선에서 결정론 쪽에 있는 건 전부 Rust 코어에 살아. 부활한 WordPress-tag 레이어인 export ruleset 적용, frontmatter 와 태그를 읽고 쓰기, 파일 읽고 쓰기. 변환들은 순수해. 문서에 ruleset 을 더하면 출력이 정확히 하나 나오고, 언제 돌려도 똑같아. 파일 IO 는 순수하진 않아. 읽기는 디스크에 뭐가 있느냐에 달렸고 쓰기는 디스크를 바꾸니까. 그래도 똑같이 결정론적이고 모델이 안 껴. 같은 디스크 상태에서 같은 호출이면 같은 일을 하거든. 모델도 없고 무작위성도 없고 '경우에 따라' 도 없지. 그 성질 덕분에 이쪽은 아무한테도 안 물어보고 돌려도 안전한 거고.
왜 결정론에 Rust 인가
Rust 가 결정론 레이어에 맞는 이유가 셋이야. 우선 빨라. 다만 빠르다고 UI 가 저절로 안 막히는 건 아냐. Tauri 에서 평범한 동기 커맨드는 메인 스레드에서 돌거든. 그래서 파일 작업은 async 로 선언한 커맨드에 둬야 Tauri 가 메인 스레드 밖에서 돌려줘. 그리고 안전하니까 네 파일을 건드리는 레이어가 메모리 버그로 파일을 망가뜨릴 일이 없어. 마지막으로 재현이 되고 테스트가 돼. 타입이 잡힌 입출력을 가진 순수 함수야말로, 절대 놀랄 일이 없어야 하는 앱 밑바닥에 딱 필요한 물건이거든. 판단 레이어는 확률적이어도 되지만 네 파일에 쓰는 레이어는 그러면 안 되고, Rust 가 그 규율을 강제해줘.
#[tauri::command]
fn apply_ruleset(doc: String, ruleset: Ruleset) -> Result<String, String> {
// 순수 변환: 같은 doc 에 같은 ruleset 이면 항상 같은 출력.
// 모델 호출도 무작위도 없어서 재현 가능하고 unit 테스트도 돼.
Ok(ruleset.apply(&doc))
}
파일 IO 는 Rust 커맨드
.md 파일을 읽고 쓰는 일 자체가 결정론적 작업이라서, 프론트엔드가 직접 하지 않고 Tauri IPC 로 부르는 Rust 커맨드가 맡아. '결정론은 Rust' 라는 봉합선을 그대로 지키는 셈이고, webview 파일 API 를 쓸 때 딸려 오는 fs-scope 배관도 피할 수 있어. 프론트엔드는 Rust 코어한테 불러달라거나 저장해달라고 요청하고, 디스크를 실제로 건드리는 건 Rust 코어뿐이야. 파일 입출력의 주인이 하나뿐이라는 게 트랙 7 에서 다시 중요해져. 거기서 파일시스템을 진실의 원천으로 못 박거든.