The audit bot tests the whole ledger once. This runs every day, and instead of re-screaming the same 46 exceptions every morning, it diffs each run against the last and surfaces only what's new since the previous run. That delta is the part a one-shot audit can't give you. This page walks through how the diff works, why "just re-run the audit daily" fails, and where the dial sits.
An internal audit certifies the books as of a date. The morning after sign-off, a new invoice lands, an approver changes, or a duplicate slips across a period boundary, and the control that was clean yesterday is breached today, invisibly, until the next quarterly review or a loss makes it visible. Point-in-time assurance scales to a calendar, not to a business that transacts every day. What you actually need is a control that re-tests continuously and tells you the moment the picture changes, rather than a sharper version of the same photograph.
The obvious continuous version is a cron job around the audit bot: run all six checks over the whole population, every morning, and email the results. It demos beautifully and dies in week two, because re-running a stable audit over a slow-moving ledger re-surfaces the same exceptions every single day:
So the real job is not to "run the audit more often." It is to snapshot each run, diff against the previous one, and alert only on the delta, while tracking a per-control trend so drift and re-opens become visible across time, instead of lost inside a daily wall of identical rows.
This is the load-bearing decision, so it's worth drawing precisely. Counts, the set-difference against the prior snapshot, the value-at-risk delta, the per-control trend and the hash-chain are all computed in Python from the joined records, reproducible to the cent, re-runnable, and comparable run over run. The language model is downstream and read-only: it writes the daily digest paragraph about a delta the engine already computed, and it must cite the exact new record IDs or it writes nothing. The model never decides what counts as new.
Inside a run, each finding carries a stable invoice_id. The monitor keeps a seen set of every id that has ever been raised, and today's ids minus seen is the alert set. The trend is simply the exception count appended to the run history. The parameters are explicit, not a matter of judgment:
The run on 2026-06-24 is the clean case. That day's generator dropped fresh transactions, and the engine raised 52 exceptions, up from 48. The diff against the prior snapshot put 4 of them in ids[t] − seen, including INV-20260624-02 and INV-20260624-03. Those four alerted, and the 48 already in seen were correctly suppressed. Only then did the model draft the digest, quoting those exact new IDs.
| Invoice | In prior snapshot? | Observation | Value-at-risk delta | Evidence | Result |
|---|---|---|---|---|---|
| INV-20260624-02 | no · first seen 06-24 | new three-way-match breach in today's batch | +S$11,401 | INV-20260624-02 · PO · GRN | alerted · NEW |
| INV-00001 | yes · seen since 06-13 | same quantity-over-PO exception, unchanged | n/a | INV-00001 · PO-00001 · GRN-00001 | suppressed · already-seen |
| INV-20260625 | n/a · 06-25 run | 0 ids in ids[t] − seen the next morning | n/a | run 2026-06-25 | quiet · nothing new |
Where these come from, honestly. Origin Company is a synthetic enterprise whose books grow with seeded transactions every day. So these figures prove the mechanism, that the daily delta is computed correctly run over run, rather than that it survives a specific real ledger. The exceptions, value-at-risk and sigma (~3.1 to 3.2σ) are illustrative on synthetic data, and the engine is the audit bot's tools.py unchanged. What's real here is the diff: the 40→42→43→45→46→48→52 trend and the per-run new_exceptions count (5, 2, 1, 2, 1, then a 4-spike on 06-24, then 0) come straight from the run history, not a mock.
The trade-off the monitor actually buys on is what counts as "new." The dial is the dedup window: how long a cleared exception's id stays in seen before a re-appearance is treated as new again. Set it too wide and a genuine re-open (a breach that cleared, then came back) is silently suppressed as "already seen", which is a missed event. Set it too narrow and ordinary day-to-day churn re-alerts on ids you've already triaged, which is back to fatigue. There's no free setting. Tightening recall on re-opens costs you false alarms, and the right point depends on how fast the control's population actually turns over. The monitor doesn't pretend a delta equals a problem. It produces a cited, deduplicated candidate list a human triages, and the window is the knob that decides how much lands on their desk each morning.
Every run and every governed decision is written to a hash-chained ledger, so the monitor can be audited, not just the transactions. Each entry's hash covers its contents and the previous hash, so altering any record after the fact breaks the chain at exactly that row. The decision fields are the control plane's structured output, and the model never writes them.
seq : 312 agent : Continuous Controls Monitoring action : raise_rfi subject : INV-20260624-02 run_date : 2026-06-24 delta : NEW (ids[t] − seen) · run exceptions 48 → 52 · new 4 tier : low decision : escalate → control owner evidence : [INV-20260624-02, PO-…, GRN-…] prev_hash : 7b14…e3a9 hash : c5d0…91ff ← = sha256(prev_hash + canonical(entry))
The audit bot and this monitor share an engine, the same tools.py and the same population, but they are answering different questions. The distinct judgment here is temporal. A one-shot audit answers "what's wrong now," and the moment you run it on a schedule, the real problem becomes telling signal from noise over time. So I draw the trust boundary first: the diff and the trend are computed in code, reproducible run over run, and the model sits strictly downstream, narrating only the new set and citing it. Then I confront the hard part out loud. A re-run that can't say what changed trains people to stop looking, and the dedup window is a real trade between recall and fatigue with no free setting. Re-engineering a control to run continuously and stay quiet until something genuinely changes is the judgment I'd bring to leading an AI transformation.
The numbers above are real output from the engine's run history over Origin's growing ledger. The full interactive console runs as a working application: the run timeline, the drift trend, the new-since-last-run delta, and a live tamper test on the ledger.