Stage 5 of enterprise AI adoption: governance hardening
This is part 5 of a series that started with the full reference diagram in part 0, covered identity and the gateway in part 1, data and retrieval in part 2, sandboxed agents with read-only connectors in part 3, and write and send behind approval in part 4.
Stage 5 is the whole bottom row marked 5, GOVERNANCE & OBSERVABILITY, with four boxes: Policy & gates, labeled "versioned as code, declared vs actual"; Audit ledger, labeled "who / what / when / which policy"; Halt & budget caps, labeled "run-level stop"; and Cost & quality metrics, labeled "p95, not averages".
It is easy to read this as governance starting here. Logging and Rate limit & budget have been running inside the gateway since stage 1, and every call has been recorded and charged against a budget from the first day. What this stage adds is comparison, attribution to a version of a rule, and the ability to stop something that is already running.
The company is the same one as in parts 1 through 4, Qingchuan, about 40 people, 8 engineers and 2 in marketing. Qingchuan is made up and only serves to walk the stage.
Coming out of stage 4, everyone logs in through the identity provider, every call carries a role through the gateway, retrieval is scoped to the asker, agents run inside a sandbox, and the writes and sends that leave the company carry an approval record the system wrote rather than one the agent reported.
By this stage Qingchuan usually has several agents or pipelines running at once. Two things are now missing rather than one. Nothing compares the rules Qingchuan wrote down against what those records actually show, and nothing can stop a run that is already out of bounds.
Policy & gates: declared against actual
The first box holds the rules, versioned as code, and the gates that evaluate them. Its label pairs declared and actual because those are two different things, and this box is where they get compared.
The failure this catches is drift, and drift is invisible from inside the rule. One from my own week. The repository that runs my site carries written rules for anyone adding an article, and one of them said articles were English only and told you not to add a Chinese variant of the file. The code had supported an optional Chinese version since September 1, and by the time I corrected the rule on September 21 all fifteen articles on the site had one, every one of them added under a rule that forbade it. Nobody was ignoring the rule. It described a system that no longer existed, and reading it could never have shown that, because drift is only visible against the record.
The comparison itself is not exempt. A status checker of mine built the address of each Chinese article by joining a prefix to the slug, while the real path had a different shape, and it reported ten live articles as dead. A gate that is wrong reports with exactly the same confidence as one that is right, so the output of a gate is evidence about the gate as much as about the system.
One property worth asking for when you pick or build the gate. The policy engine I keep evaluates with explicit unknown and conflict states rather than folding them into allow or deny. "No rule covers this" and "two rules disagree" are different facts from "denied", and an engine that cannot say them will pick one for you, in a direction you did not choose and cannot see afterwards.
Done looks like this:
- the policy is a file under version control
- changing it goes through the same review as code
- every decision a gate makes names the policy version it was made under
- the comparison between declared and recorded runs on a schedule rather than when somebody suspects something
Audit ledger: which policy allowed it
Stage 4 left four fields behind:
- which agent or person acted
- on what
- when
- who approved it
This box adds the fifth, which rule allowed it and at which version.
Without the version you can establish that an action was approved and not under which rule. If the rules changed last month, a record that complied at the time and a record that violates the current rule look the same, and the row cannot tell you which question you just answered.
The ledger has to be append-only, written by the system that performed the action, and outside the agent's reach, which is the same requirement stage 3 put on the read log and stage 4 put on the approval record.
Mine is short of it in a specific way. My publishing log records:
- time
- brand
- article
- language
- title
- platform
- status
- note
- address
There is no policy column at all, and the approver still sits inside the free text. I can answer whether something was published. Answering which rule allowed it means reading sentences and remembering what the rule was that week.
There is a second way to fall short that looks like the opposite. A field can be declared and read by nothing. The syndication block in my own article files records where each piece was republished, and no code reads it. As bookkeeping that is fine. The problem is that a recorded field and an enforced field look identical from the outside, both being structured data in a file, so a review that counts fields scores them the same. A field nobody reads is a note, not a control.
Done looks like this:
- append-only
- written by the acting system
- one row per action carrying the policy version in force at that moment
- answering which rule allowed a given action is a query rather than a reconstruction
Halt & budget caps: stopping a run, not refusing the next call
The third box is the one people assume they already have because they have a rate limit. A rate limit refuses the next call. This box stops the run that is already going.
The difference shows up once a run does many things. By the time call 41 is refused, calls 1 through 40 have happened, and after stage 4 some of them wrote to an internal system or sent something outside. The rate limit was working correctly the whole time.
In my own runtime the stop is at the level of the run:
- scope violations
- LLM call count
- tool execution count
- total tokens
Each has a cap, any one of them being reached stops the entire run, sub-agents it dispatched stop with it, and that run cannot be resumed, only started again.
The caps ship switched off, and turning one on is an explicit decision rather than a default.
The cost of that is measurable, and I measured it. In an ablation on a small
Comments
No comments yet. Start the discussion.