Kristopher Baker iOS · Product engineering · Systems and tooling
← Aoede

shipped · 2026.07.02 · 1 min read

Separating generated and author-provided furigana

Aoede's furigana errors came from two different sources, so I built a small harness to separate them before changing the reader. FuriganaQA runs the production pipeline over Aozora books and compares each result with the ruby supplied in the text. Each mismatch comes from something the generator should have produced or a reading it could not infer.

The first group exposed fixable problems. Aoede took phonetic forms from OpenJTalk, causing long vowels to use phonetic spellings instead of the expected spelling. It also grouped mixed kanji runs too broadly. Switching to orthographic readings and using JmdictFurigana for per-kanji placement fixed those cases, with JMdict validating the result.

The second group includes readings chosen by an author, such as 本気 read as マジ. No analyzer can recover that choice from the characters. Aoede now preserves ruby from Aozora markup and EPUB <ruby> elements, gives it priority over generated furigana, and uses it for speech as well as display.

The harness made the boundary testable: published ruby wins when it exists, dictionaries handle known readings, and OpenJTalk fills the remaining gaps.