AI governance

AI proposes. The engine decides whether it posts.

The most important architectural decision in this product is that agents have no write path to the general ledger. They produce a structured proposal; a deterministic engine evaluates it against rules that are code, not context; and only the engine posts. That boundary is why the rest of the automation is safe to run.

Objectivehuman intentAgentproposesPolicyvalidatesApprovalwhere requiredEngineexecutesLedgerrecordsfails policy → human exception queueAI operates heredeterministic · never AI
No agent-only write pathSix invariants at writeRejection is final

What is enforced

Six checks, every write, no exceptions.

Balance

Debits must equal credits at the transaction boundary. An unbalanced entry cannot be persisted, so there is no moment where the ledger is temporarily wrong and a later job fixes it.

Period state

Open, soft close, closed, or locked — evaluated on every write. Corrections into a closed period become reversing entries in the next open one.

Account validity

The account must exist, be active, accept postings, and be permitted for that entity. Control accounts reject direct entries entirely.

Required dimensions

Configured per account. A posting missing a required dimension is rejected rather than accepted with a blank that quietly breaks reporting later.

Actor permission

The posting actor — human or agent — must hold the permission for this action, in this entity, at this amount. Evaluated at write, not assumed from context.

Immutability

Entries are append-only. A correction is a new entry referencing the original, and the engine will not accept an edit or a delete from anything.

Why the model is not trusted with this

Not because models are unreliable — they are increasingly good at exactly the work these agents do. Because the reliability is probabilistic, and a general ledger needs a guarantee rather than a high likelihood.

A model that codes correctly 99.4% of the time is genuinely useful and genuinely unsuitable as the last line of defence. Over a hundred thousand postings, that residual is six hundred wrong entries, and the ones that matter are the confident wrong ones nobody reviews. The engine converts a probabilistic proposal into a deterministic outcome: it either satisfies the invariants or it does not post, and that judgement has no confidence interval.

A model gives you a high likelihood. A ledger needs a guarantee. The engine is where one becomes the other.

The failure this prevents

Consider an agent that concludes a bill belongs in a period that closed last week. With a write path, the plausible outcomes are that it posts and quietly reopens a signed period, or posts to the wrong period, or writes an unbalanced entry that a nightly job later corrects. All three have happened in systems that let models write directly.

With the engine in between, the proposal is rejected, the reason is recorded, and the item goes to a human queue. The agent cannot argue, cannot retry under different framing, and cannot escalate. Rejection is terminal for that proposal.

What an agent actually produces

Not a natural-language instruction. A structured object: action type, target records, amounts and lines, dimensions, the policy it believes applies, and its confidence. The engine evaluates that object against your configuration and returns permit, hold-for-approval, or reject.

This matters more than it sounds. Because the interface between the probabilistic part and the deterministic part is a typed object rather than text, the boundary can be tested, versioned, and reasoned about. There is no prompt that produces a different enforcement outcome, because the enforcement layer never reads a prompt.

What this costs

Honestly: some automation. There are cases where a model is confident and correct and the engine still refuses — an entry into a period a person closed early, a posting to an account somebody deactivated last month. Those become exceptions that a human resolves, and the exception queue is a little longer than it would otherwise be.

That is the trade, and we would make it every time. The alternative is a system where the answer to "could the AI have posted this incorrectly" is "probably not."

This is not unique to us — but it is not universal

Several serious vendors take the same approach and we are not claiming novelty. Others let models write more directly and rely on review to catch errors. It is a fair question to ask any vendor, and the useful follow-up is whether the boundary is enforced in code or described in a system prompt.

Questions

What engineers and auditors ask.

Could a bug in the agent cause a bad posting?
It could cause a bad proposal. Whether that becomes a bad posting depends on the engine and your policy, which is the point of separating them. A proposal that violates an invariant is rejected regardless of what produced it.
Could a bug in the engine cause one?
Yes, which is why the engine is the component we publish property-based tests for and have reviewed by a third-party attest firm. Concentrating the risk in a small, deterministic, heavily tested component is the design.
Does this apply to every module?
Every posting to the general ledger, from any source — agent, human, integration, or API. There is no privileged path, including for our own internal services.
What happens to a rejected proposal?
It is recorded with the rejection reason and routed to a human exception queue. It is not retried, not reformulated, and not escalated automatically.
How is this different from validation?
Validation typically runs after a write and flags problems. This runs before, and a failure means no write occurred at all. The distinction matters because there is never a window in which the ledger holds an invalid state.

Ask us to break it.

During a demo, ask us to make an agent post into a closed period. It takes two minutes and answers the question properly.