Designing an AI that never states a fact — a deterministic engine, with the LLM only writing prose
Palm features extracted by a VLM, the chart computed deterministically, and the LLM allowed to do one thing: turn those facts into sentences — whose citations are then machine-checked. How Palmia is built.
The browser version is live; the iOS app is coming. Japanese-language product.
Why this is in a consulting portfolio
"The AI might lie" is a valid reason to halt a generative-AI rollout. The way past it is to not trust the model. Palmia moves fact computation outside the AI, lets the AI only turn facts into prose, and has a machine verify the evidence that prose cites.
Why I built it
Fortune telling is the sloppiest possible use of generative AI. Write something plausible and it reads as accurate, so when the model invents a fact, nobody notices.
That makes it an ideal place to try the opposite. Whether a reading is true is unfalsifiable — but whether the evidence the app cited actually exists in that user's data is decidable by machine. If you can refuse to publish prose that fails that check, the same structure moves to contract summaries, insurance and medical explanations, and internal-policy Q&A.
The hard part
You cannot prompt your way out of hallucination. Tell a model to "answer only from the facts" and it will believe it is doing exactly that while describing a feature that isn't there.
Two genuine difficulties:
- Deciding how much to move outside the model. Computing a Four Pillars chart is a pile of calendar-conversion rules. Hand it to an LLM and it fails quietly at the boundaries between solar terms.
- Verifying the prose after you've let the model write it. Once you accept free-form natural language, correctness is normally no longer traceable.
The call I made (and what I gave up)
I split it into three layers. The VLM only extracts structured palm features. A deterministic engine computes the chart. The LLM is permitted only to turn those into Japanese prose.
The calculator produces the answer; the AI only reads it aloud. The AI never does the math — so numbers that don't exist can't appear.
For verification, every generated section must supply evidence_refs. Those references are restricted to a canonical vocabulary such as lines.heart.tip, and prose citing a reference that does not resolve fails validation and is regenerated.
What I gave up was expressive freedom. Removing the model's room to "say something nice" leaves prose that is visibly constrained by structure. I chose verifiability over being a more entertaining fortune teller.
What actually ships
Solar-term data covers 97 years (1940–2036) to the minute, and the year and month pillars switch on the exact time of the term — on the day of 立春 itself, anything before that instant still belongs to the previous year.
Models are assigned by role: Gemini 3.5 Flash for palm-feature extraction, Flash-Lite for daily readings, Claude Opus 5 for paid deep reports. Every call — success or failure — writes one row to a cost ledger with the unit price snapshotted at that moment, so a later price change cannot rewrite historical COGS.
The spend guard has three layers: per IP, per verified user, and an account-wide ceiling — on the assumption that an IP can be spoofed or tunnelled.
Palm images exist only for the duration of the request and are never persisted, on device or server.
Numbers counted from the code
86 commits between 2026-07-21 and 07-29; 114,822 lines of ts/tsx/sql/mjs. 369 test files, with 100% coverage enforced as a threshold on every workspace. The database has 22 tables and 36 RLS policies, plus 3 tables that deliberately carry no policy at all — meaning anon and authenticated can read zero rows — and are reachable only by service_role. RLS itself is verified by 13 pgTAP suites.
CI is 7 workflows. One is security-only, bundling CodeQL, Gitleaks, Secretlint, a dependency audit, a license allow-list, SBOM generation, Trivy and OSV-Scanner.
What this proves for your project
If you want generative AI in production somewhere a single wrong sentence becomes an incident, it has to look like this: fact computation outside the model, the model writing prose only, and a machine checking the evidence that prose cites. Contract summaries, insurance and medical explanations, internal-policy Q&A — they all fit the same shape.
The CI checks for regulated Japanese advertising and pharmaceutical-claim wording are implemented too, and portable as-is. The interesting part is that they are denial-aware: an article is allowed to quote a superstition in order to refute it.
I take on this kind of generative-AI work as modern / AI development. See also the client engagement running a production voice AI.
Numbers counted from the code
- Tests
- 369files100% coverage enforced as a threshold on every workspace — one untested line fails CI
- RLS policies
- 36policiesEnabled on all 22 tables; a further 3 carry no policy at all and are service_role-only
- Security CI
- 7workflowsIncluding CodeQL, Trivy, OSV, SBOM and a license allow-list
- Solar-term data
- 97years1940–2036, to the minute, verified against the National Astronomical Observatory of Japan
FAQ
- Can I use Palmia right now?
- The browser version is available. The iOS app is coming. The product interface is Japanese.
- Can the AI make up the content of a reading?
- Not structurally. A deterministic engine computes the Four Pillars facts and the LLM is permitted only to write prose. Every generated section must supply evidence references, and prose citing evidence that cannot be resolved against the canonical vocabulary fails validation and is regenerated.
- Are palm images stored?
- No. Palm images are never persisted — they exist only while the request is being processed.
- How accurate is the Four Pillars calculation?
- It uses a deterministic engine holding 97 years of solar-term times (1940–2036) to the minute, verified against the National Astronomical Observatory of Japan. Even on the day of a term boundary, a time before that instant is treated as the previous year.
- Which AI models does it use?
- Gemini 3.5 Flash for palm-feature extraction, Flash-Lite for daily readings, and Claude Opus 5 for paid deep reports. Cost is ledgered per call with the unit price snapshotted at the time of the call.
- What is the testing standard?
- 369 test files, with 100% coverage enforced as a threshold on every workspace — a single untested line fails CI. Security CI is 7 workflows including CodeQL, Trivy, OSV, SBOM and a license allow-list.
同様の課題、抱えていませんか?
あなたのビジネス課題も、最新の技術で解決できます。 まずは30分の無料技術相談から、状況をお聞かせください。
自社の課題もSaaS化できるか相談するプロジェクト単位(請負)・技術顧問、どちらにも対応可能です