"맞춤법 검사기는 사전을 알아. voice 검사기는 너를 알아. Rekindle 의 두 번째 decoration 역할이 후자야."
역할 둘 — 맞춤법 검사기가 아니라 voice 검사기
decoration 엔진의 두 번째 역할은 세상 어디에도 없는 거야. 라이브 voice 검사기. 쓰는 동안, voice 규칙을 건드리는 구절 — register 미끄러짐, token-mirror 함정, 지나치게 센 단어 선택 — 에 밑줄을 긋고, 왜인지 설명하는 작은 여백 노트를 띄워. 맞춤법 검사기는 네 텍스트를 모두가 공유하는 사전에 대고 재. voice 검사기는 네 독트린에 대고 재. 한 작가가 중요하다고 정한 특정 함정과 선호. 맞춤법 검사와 같은 제자리-밑줄 UX 인데, 사적인 무언가를 겨눈 거야.
독트린의 구체적 예: 문서화된 한국어 규칙 하나가 register 에 더 부드러운 선택이 맞는 자리의 박다 — 지나치게 센 동사 — 를 표시해. 문법 오류가 아냐. 어떤 범용 도구도 절대 못 잡아. voice 규칙이고, 한 작가의 독트린을 중심으로 지은 voice 검사기만 그걸 강제할 수 있어.
단일 탐지 경계
메커니즘적으론 mark 플러스 widget 이야. 문제 범위에 밑줄 (mark) 을 긋고 옆에 노트 (widget) 를 붙여. 모든 지능은 함수 하나 detectVoiceIssues(doc) 뒤에 숨어. 문자 범위와 노트를 반환하지. 오늘 탐지는 TypeScript 의 결정론적 규칙이고, 나중에 Rust voice-엔진 substrate 로 옮기거나 AI-판단 레이어를 키울 수 있어 — 그래도 decoration 코드는 안 바뀌어. 오직 범위만 소비하니까. 경계가 트릭 전부야. '뭐가 이슈냐' 를 함수 하나 뒤에 두면, '어떻게 그리냐' 는 탐지가 어떻게 진화하든 동일하게 남아.
type VoiceIssue = { from: number; to: number; note: string };
// 탐지는 경계 하나. 오늘 규칙; 나중에 Rust 나 AI-판단 —
// decoration 레이어는 절대 안 바뀌어, 범위만 소비하니까.
function detectVoiceIssues(doc: string): VoiceIssue[] { /* ... */ }
같은 엔진, 새 목적
물러서서 봐. 이건 Live Preview 의 정확히 그 기계장치를, 다른 질문에 겨눈 거야. Live Preview 는 '마크업이 어디?' 를 묻고 mark 를 그렸어. voice underline 은 'voice 이슈가 어디?' 를 묻고 mark 플러스 노트를 그려. 같은 원시 요소, 새 입력. 트랙의 thesis 가 두 번째로 도착한 거고 — 진짜 새로운 기능 (어디에도 없는 voice 검사기) 이 새 기계장치를 거의 안 들이고 지어진 이유야.