I build software in the single worst domain for LLM truthfulness: fortune-telling. A BaZi (Chinese Four-Pillars astrology) reading app, where the model's job is to sound like a wise master — and where user reviews of competing AI products converge on one complaint: "pure nonsense." An LLM asked to "read a birth chart" will hallucinate chart elements that aren't there, invent rules that don't exist in the tradition, and deliver it all in a voice of total confidence. In a domain with zero external ground truth to check against, users can't tell — until two readings of the same chart contradict each other.

Whatever you think of the domain (I wrote about its genuinely hard timezone math earlier), the engineering answer is portable to any LLM product that must not make things up. It's one rule:

The deterministic engine decides what is said. The LLM decides only how to say it.

The chart, the element strengths, the favorable-element analysis, every derived fact — computed by a rules engine in TypeScript, unit-tested, published constants and all. The model receives those facts as a compact block and a directive: cite only what's given. It's a translator with a persona, not an oracle.

That's the easy 80%. The interesting engineering is in three places where the rule almost broke.