한글 완성형·분해형, 일본어 결합 문자, ZWJ로 연결된 이모지는 같은 모양이어도 내부 표현과 code point 수가 다릅니다. String.length나 단순 일치 비교만 사용하면 정답을 오답으로 보거나 이모지 하나를 여러 글자로 셀 수 있었습니다.
엔진은 Flutter widget과 IME lifecycle에 의존하지 않고 같은 문자열·정책·시간에 같은 결과를 내야 했습니다. 짧은 학습 문장을 대상으로 하므로 편집 경로를 설명할 수 있는 구현을 우선하고, O(n×m) 시간·메모리 경계를 README에 명시했습니다.
NFC 정규화 후 extended grapheme cluster로 나누고 Levenshtein distance를 계산했습니다. 동점인 편집 경로에는 고정 우선순위를 두고, 공백과 종결부호는 버전이 붙은 정책으로 처리하며 정확도와 gross CPM은 1000배 정수로 반환합니다.
- 한글 완성형·분해형, 일본어 kana, 결합 문자, ZWJ 이모지를 테스트.
- 정책 JSON을 엄격하게 파싱하고 알 수 없는 버전·값·필드를 거절.
- 공통 입력과 기대 결과를 conformance/v1 fixture로 공개.
포맷·정적 분석·테스트 39개·배포 사전 검증을 통과했고, 공개 저장소 CI에서 Dart 3.8과 stable을 확인합니다.
Unicode 대응은 정규화 함수를 추가하는 데서 끝나지 않고, 무엇을 한 글자로 세며 동점인 오류 경로를 어떻게 설명할지까지 계약으로 고정해야 했습니다.