"The spec was written for languages that put a space after a word. Korean puts a particle there."
Asterisks That Stayed Asterisks
On 2026-09-24 Dad met it in a travel guide he was reading in Waystone, the family's travel app: a line like **공항 급행버스(€5)**는 rendered with its asterisks showing, and with two such phrases on one line the bold landed on the text between them. It was not a Rekindle bug in the usual sense. CommonMark decides whether a run of ** can open or close emphasis by looking at its neighbours (the "flanking" rules), and one of those rules says a closing run that comes right after punctuation must be followed by whitespace or punctuation. English almost always is. Korean attaches its particles directly to the word — (€5)**는 — so the closer is refused, the asterisks stay literal, and the parser goes looking for another partner. cmark-gfm, Apple's AttributedString(markdown:) and remark all behave the same way, and the frozen Tauri original had exactly the same flaw.
Decide the Pairs Before the Parse
Once a parser has paired the wrong delimiters, nothing after the parse can un-pair them. So the fix runs before it. The sibling kit's CjkStrong (a Swift twin of a TypeScript twin, the same algorithm line for line) scans the source, pairs exact ** runs inside one paragraph with the flanking rules relaxed where a neighbour is a CJK character, and swaps only the pairs that touch CJK for private-use markers (U+E000 to open, U+E001 to close). Each marker is one UTF-16 unit, exactly like each * it replaces, so every source range the editor computes stays valid. A pair that touches no CJK is left to the parser untouched; an unmatched marker reads back as the ** it was written as.
After the parse, each renderer resolves the markers into bold in its own terms. In Rekindle that is three places: the editor's presentation adds strong spans at the marker pairs, the styled-HTML renderer emits <strong>, and the chat renderer resolves them in its own node tree.
The Edges Are Where It Bites
The first version skipped fenced code and backtick spans, but not an indented code block — so a line indented four spaces after a blank line, such as x = **값**이, put private-use characters into a code sample. The same evening it was fixed in two layers: the kit's resolvers and the Rekindle consumers now pass code through untouched, and a pair that straddles code and the paragraph after it bolds nothing. A later kit change also skips link destinations, raw HTML tags and bare URLs. A pre-parse pass sees raw text, so it has to know every place where asterisks are not prose.
A Departure From the Spec, Not Just the Original
Every departure in lesson 5 bent the original app. This one bends the format: Rekindle now renders as bold something CommonMark says is not. The commit says it plainly — the change "deliberately diverges from the frozen original, which had the same flaw" — and Dad's ruling of 2026-09-24 covers every family renderer, not only this editor. Two honest consequences follow. The file stays byte-identical Markdown; only the rendering of Korean-glued bold differs, so another Markdown tool will still show those asterisks. And this ruled divergence is recorded in the app's kit-adoption notes rather than in the architecture's departures list — the very drift lesson 5's newest note points at.