"Yes, let it go that way." — Dad, Málaga, 2026-10-18, asked whether her voice may start at a chat answer's first finished paragraph
The Last Unit Was the Whole Answer
The second lesson of this track gave the rule its reason: one synthesis per speakable unit, never split to start sooner, because an expressive voice carries its tone across sentences and resets at every cut. A unit ended only at a tool call, so a spoken answer with no tool was a single unit, and the voice waited for the whole of it. At home the cost hid inside the rest of the turn. On the road it did not. The first per-turn timelines from the phone (seven turns over LTE on 2026-10-18, the next lesson in Track 10 has them all) put the gap between her first text and her first sound at a median of 5.2 seconds, and 10 seconds on the afternoon's no-tool replies. The reason was plain in the timeline: a reply's last unit was its whole remaining text.
One Exception, Written Into the Invariant
So the question went to Dad in the form the invariant would need it: may her voice start at a chat answer's first finished paragraph, instead of at the end of the whole answer? He said yes, and the yes is recorded in cwkBellows' invariant 19 itself, as an exception for chat answers only. A spoken chat reply is now read paragraph by paragraph as it streams. Everything else keeps the whole unit: notices, Beacon and Studio scripts, video lines, Inkwell and every other take, until Dad says otherwise. The invariant also tells the next session not to re-argue either side: the exception is his ruling, and so is the rule it relaxes.
This is not the trick the second lesson warned against, and the difference is where the cut falls. That trick cut wherever a sentence happened to end, to start a second sooner. This one cuts only at a blank line, between paragraphs, where a person reading aloud takes a breath anyway, and never inside a paragraph or a sentence. The flow inside each paragraph is still one take.
Where a Paragraph Ends
A paragraph ends just past a blank line that follows a line of text or a closing fence, and only outside every code fence and card. A fence closes on a line of at least as many backticks, so a four-backtick card that holds a three-backtick code block, blank lines and all, stays one block. A paragraph with nothing to say (audio tags alone, a card alone, the emotion tag) joins the next one, because a tag alone is no take. Tool-call ends keep their place in the order. The rule lives in three places: paragraphEnds and takeSpokenUnits on the web, paragraph_ends and spoken_units on the engine, SpokenUnits on the phone. The web and the engine read one fixture of cases, and the phone's tests restate those cases inline; the web test also streams every case in one character at a time and checks it lands in the same units.
No Gap Between Paragraphs
Paragraphs would buy nothing if each one waited for its own synthesis to start. So the next unit is warmed while the current one plays: the phone asks POST /api/tts/prepare with warm: true for each unit queued behind the one she is reading, which starts that take's synthesis at once, and the web prefetches it. A private conversation's take is never warmed. The replay in Track 9 follows the same rule: it cuts a stored answer into the same paragraphs, so the voice cache still hands back the very takes that aired, and each paragraph replays from the moment its text reached the screen.