Skip to content
How much to read

Knowledge base

projects / clarity / features

Deterministic narration in Clarity Insights

Clarity's Insights feature keeps a language model away from arithmetic entirely by having it narrate figures a typed engine already computed, gated by a deterministic faithfulness check.

feature · current · updated 2026-09-16 · Clarity case study

Clarity's Insights feature turns monthly financial data into plain language commentary. The hard rule: every number is produced by typed code, and the model receives computed figures and writes prose. It never queries, calculates, or invents a figure.

How it works

Transactions flow through an insights engine of nine independently testable pure functions (metric bundle, treatment mix, trend, margin erosion, payout concentration, price drift, expense coverage gaps, receivables, meaningful change), each with a colocated unit test. The resulting typed metric bundle goes to the model for narration.

Before anything reaches the screen, a faithfulness gate, itself a pure, deterministic, offline function with no model call, extracts every numeral from the narration and traces each back to a value in the bundle, canonicalising both sides so a raw integer can match a rendered currency string. Anything that fails to reconcile is thrown away, and nothing is shown rather than showing an unverified figure.

Why this design

The model never sees the clinic's records, only aggregated monthly figures already on screen, and nothing with a patient's name. That is also why every generated number can be traced to a row. The narration layer is deliberately non load bearing: if the model is unavailable, the numbers still render.

The engine is exposed as a versioned typed API, so wrapping it as a tool or a skill later is a thin adapter rather than a refactor. Narration runs on Gemini Flash, deliberately a different frontier vendor than the one authoring the code, and the faithfulness gate checks narration text against the metric bundle rather than anything vendor specific, so swapping the model changes no downstream logic.

The original whole-screen Summary narration card was later replaced by a scoped, engine-diagnosed "why" on the Insights Trend card; see the trend "why".

Rounding and sign

The bundle fed to the model rounds money and counts to whole numbers but keeps any percentage field at one decimal, since a whole-number percentage lost the distinction between a 24.6% and a 25.1% swing that an owner cares about. A later eval run caught the model restating a signed decline (a negative month-over-month change) as a bare positive magnitude; the faithfulness gate is deliberately sign-sensitive and correctly rejected it, so the fix was prompt-side: the model is now told to quote a signed field with its sign rather than drop it.

See the eval suite for how this gate is tested at scale, and overview.

This page was written by a model from my own repositories and checked by a second one against the same sources. I did not write it, and no version of it was approved by me before it went up. How that works, and where it can still be wrong.