WTWilly Tai
Case study · AI governance & assuranceLive demoPublic dataset

Commentary that must cite the ledger, or admit it found nothing.

Every close ends the same way: someone spends 7 to 12 hours digging through the general ledger to explain why the numbers moved, and the paragraphs they produce become the evidence for a management review control that auditors test. Handing that writing to a model creates the sharpest failure mode in finance AI, a fluent explanation with no ledger line behind it. The Governed Flux Writer inverts the risk. Code computes every variance and decides which ones matter; the model is only allowed to phrase sentences over payment lines the code assembled, with its citation coverage measured; and where the lines cannot explain the movement, it must write no explanation found in the ledger and hand the flux to a human. The data is real: two fiscal years of State of Connecticut expenditures.

68 → 21
variance cells → material fluxes
computed and flagged by code, rule visible on screen (public data)
94.9%
avg citation coverage · 20 drafts
share of each movement the cited lines account for, computed per draft
100%
sentences carrying citations
95 of 95 drafted sentences link to ledger lines or to the computed arithmetic
1
mandated abstention
$22.1M unexplained, routed to follow-up instead of a paragraph

Public dataset: State of CT Open Expenditures (Public Domain) · FY2024 vs FY2025 · one flux deliberately trimmed to force the abstain, disclosed in-app

01 · The pain

Twelve hours of GL archaeology, and the output is folklore.

Flux and variance commentary is the narrative half of the close. The trial balance says spend rose 28%; the commentary is supposed to say why. In practice a preparer exports comparatives, eyeballs the movements against an informal threshold, digs through journal detail, emails process owners, and writes paragraphs from memory and chat replies. Some of what gets written is real analysis. Some of it is folklore, the word "timing" doing unpaid overtime. When I scanned finance workflows for defensible AI use cases, this one surfaced independently from three different lenses (a business analyst's, a product manager's and a CFO's), always with the same two numbers attached: 7 to 12 preparer hours per close, and commentary quality that swings with whoever prepared it.

The governance problem is sharper than the effort problem. That commentary is the primary evidence of the management review control, and MRC precision is a recurring theme in ICFR deficiency findings: reviewers sign off on narratives nobody can trace to entries. An auditor who samples the MRC and finds commentary that does not reconcile to the ledger has not found a documentation gap. They have found a control that does not operate.

02 · Why the shortcut makes it worse

A model that writes plausible commentary is the failure, industrialised.

The obvious move is to paste the comparatives into a chat window and ask for commentary. The output will be fluent, confident and shaped exactly like good commentary, because the model has read thousands of MD&A paragraphs. What it will not be is traceable. A language model asked to explain a $30.7M drop in building spend will produce a sensible-sounding cause (deferred maintenance, a completed programme, an energy initiative) whether or not any entry supports it. The old failure mode was a tired preparer writing "timing". The new one is a machine that writes plausible fiction at scale, wearing the format of evidence.

Auditors have noticed. The moment a team says "we use AI in the close", the sampling gets less friendly, and unevidenced narrative is the first thing they probe for. So the design question is never how well the model writes. It is whether the process can prove that every written sentence traces to the ledger, and whether it behaves safely at the boundary where the ledger stops explaining. A model with no boundary answers every question. That is precisely the property you do not want in a control.

03 · The trust boundary, applied to prose

Code decides what needs explaining. The model only phrases what code assembled.

The demo runs the boundary I draw in every system on this site, this time over narrative rather than numbers. Deterministic code computes all 68 period-over-period variance cells, applies a materiality rule that sits on screen next to the board it governs ($5.0M and 10% of prior year), and, for each material flux, pre-assembles the vendor-level ledger lines that compose the movement. The model performs no arithmetic and cannot promote or suppress a flux. It gets one job: phrase sentences over the assembled lines, citing them, while code measures what share of the movement the cited lines account for. Below an 80% coverage floor, drafting is forbidden and the output is mandated: no explanation found in the ledger, flux routed to a follow-up queue for a process-owner answer.

GOVERNED FLUX WRITER · ONE FLUX, INSTRUMENTED Ledger extract CT expenditures · FY24 vs FY25 DETERMINISTIC · DECIDES variances + materiality rule assembles evidence lines computes citation coverage $5.0M and 10% · floor 80% WRITER · PHRASES ONLY every sentence cited or mandated abstention Reviewer approve · edit · reject HASH-CHAINED LEDGER · THE MRC EVIDENCE WRITES ITSELF every variance → draft + citation set + coverage → edit diff → approval → sign-off, replayable code refuses the sign-off until every material flux is approved or in follow-up
One flux, instrumented: code decides and measures, the writer phrases or abstains, a named human gates, the chain remembers.

Two deterministic functions carry the whole design. The first is the materiality decision the model never touches. The second selects citations sign-aware, always taking the largest line that shrinks the unexplained remainder, so coverage is a measurement rather than a claim. Both ship in the demo exactly as below.

// the flux is material because the rule says so, never because the model finds it interesting
function isMaterial(prior, cur) {
  var v = cur - prior;
  if (Math.abs(v) < MAT_ABS) return false;          // $5.0M
  if (prior === 0) return true;                       // new category: dollar test alone
  return Math.abs(v / prior) >= MAT_PCT;              // 10% of prior year
}

// sign-aware greedy citation: cite the largest assembled line that shrinks the
// unexplained remainder; coverage = 1 - |remainder| / |variance|, computed, not asserted
while (cites.length < MAX_CITES) {
  var pick = null;
  for (var i = 0; i < pool.length; i++)
    if (Math.abs(rem - pool[i].delta) < Math.abs(rem) &&
        (!pick || Math.abs(pool[i].delta) > Math.abs(pick.delta))) pick = pool[i];
  if (!pick) break;                                   // nothing left that helps: stop citing
  pool.splice(pool.indexOf(pick), 1);
  cites.push(pick); rem -= pick.delta;
  if (Math.abs(rem) / Math.abs(variance) <= 0.10) break;
}
// below the 80% floor the writer's mandated output is the abstention sentence
04 · Two clicks, one lesson

Watch it explain a $41.3M jump, then refuse a $30.7M one.

Open the demo and the flux board is already computed: 68 cells across four Connecticut agencies, 21 flagged material in red by the rule printed above the board. Click the Department of Energy and Environmental Protection's Other Program Expenses, up $41.3M (+95.4%). The commentary assembles in front of you, sentence by sentence, each carrying its citation: payments to Eversource rose $34.2M, from $29.0M to $63.2M [E1]; United Illuminating rose $6.3M [E2]. The coverage meter lands on 98.1%, which is not the model's opinion of its own work. It is code reporting that the cited lines arithmetically account for that share of the movement, with specimen invoice ids underneath.

Then click the flux marked ◆, Government Buildings at the Department of Administrative Services, down $30.7M. The extract for that flux has been deliberately trimmed (the app says so on screen), so the assembled lines can explain only 28.0% of the movement. The same writer that just produced footnoted paragraphs now produces one sentence: no explanation found in the ledger for $22.1M of this variance, and the flux drops into the follow-up queue for a process-owner answer. Same model, same prompt discipline, opposite behaviour, because the safeguard sits outside the model. The reviewer, named on every decision, approves, edits or rejects each draft, and code refuses the MRC signature until all 21 material fluxes carry approved commentary or an open follow-up. Try to sign early and the refusal itself lands in the hash-chained ledger, where Verify, Replay and Tamper do what they do in every demo on this site: prove the run reproduces, and locate the exact entry if anyone rewrites history.

Why the trim is honest: the full public dataset can explain that flux; the shipped extract deliberately cannot. The point being demonstrated is behavioural. Where evidence runs out, a governed writer stops writing, and the demo needed a place where evidence visibly runs out.
05 · What the numbers mean, and where they stop

Real payments, computed coverage, and limits I will state plainly.

The data is real: the State of Connecticut's Open Expenditures ledger (Public Domain, published by the State Comptroller), FY2024 against FY2025, embedded as a 55KB extract with vendor totals and specimen payment lines. The engine's numbers are computed live in your browser: 68 cells, 21 material fluxes, 20 drafts averaging 94.9% citation coverage with a worst case of 86.3%, 95 drafted sentences of which 95 carry citations, one abstention. The headline claim follows from the mechanism rather than from a benchmark: when code pre-assembles the evidence and the writer must cite it, the preparer's 7 to 12 hours of archaeology becomes a review pass over drafts that arrive pre-traced, and invented explanations are structurally excluded because the only alternative to citation is abstention.

The limits. This is cash-basis government expenditure data: no revenue, no balance sheet, no accruals, so the corporate close framing is an analogy and the app labels it as one. Commentary quality is bounded by what a ledger records; the real "why" behind a movement often lives in contracts and operating decisions, which is exactly what the follow-up queue represents rather than papers over. Materiality here is a simple two-part threshold, visible but not auditor-derived. And the writer is a deterministic stub standing in for an LLM, which is the point of the architecture: the citation floor, the coverage measure and the sign-off gate would constrain a real model in precisely the same way, because none of them run inside it.

06 · See it run

Click the red flux. Then click the one it refuses.

The board is live the moment the page loads. Draft a commentary, watch the coverage meter, force the abstention, reject a draft into follow-up, try to sign the MRC early, and tamper with the ledger to watch the chain locate the break.

▶ Open the live demo Runs entirely in your browser · real Connecticut expenditure data · seeded, reproducible run

The writing control.

Most of my portfolio governs computation: matching, reconciliation, release decisions. This piece governs prose, which is where finance AI is currently least defended, because narrative feels harmless right up until it becomes audit evidence. An accountant knows why the MRC fails inspections; an engineer can make sentence-level citation a hard constraint rather than a style guideline. The deliverable here is the part I care about most: a review control whose evidence assembles itself, replayable to the exact draft, edit and signature the reviewer saw. If your close produces paragraphs a machine helped write, this is the shape in which your auditors should be allowed to meet them.