September 9, 2026 Governed Agents Regulated Industry Self-Correcting Systems

🏦 The agent that graded itself, failed, and filed a pull request

I put an AI agent inside commercial loan underwriting, one of the most regulated product lines in banking, and watched it approve a request it should have denied. This is the story of the system I built around it: an exam it cannot see, a repair loop it cannot own, and the day it shipped a sandbox-verified code fix that I merged like any other engineer's PR.

8eval scenarios, live model
75→100%pass rate, three corrections
2bad fixes auto-rejected
1human merge, always
<$0.50total correction spend
Chapter One

The quiet wrong approval

A borrower asked for a forty-day extension on their revolving credit facility, ten days before it expired. The bank's credit policy is unambiguous: extension requests must arrive at least thirty days before expiry. My agent had that exact policy section in its retrieved context. It cited it. And it approved the request anyway.

No exception was thrown. No hallucinated policy section, the citation was real and verified. The reasoning read fluently. And because a forty-day extension fell under the sixty-day threshold my rules call routine, the approval sailed past the human gate without a single person seeing it. A clean, confident, quietly wrong credit decision in a product line where every decision must survive a regulatory examination.

The failures that end careers in regulated industries are not the crashes. They are the fluent approvals nobody reviewed, discovered eighteen months later by an auditor with a highlighter.

Here is the confession: I only know this happened because I had built the machinery to catch it before I ever trusted the agent with anything. And the more interesting story is what happened after the catch, because I never fixed the bug myself. The system diagnosed it, wrote the fix, proved the fix against an exam it cannot touch, and handed me a pull request. I reviewed the diff and merged it, the same way I would for any engineer.

WARDEN is the system that made that sentence possible without it being terrifying.

· · ·
Chapter Two

What today's product agents get wrong

Commercial loan underwriting is a deliberately hostile place to put an agent, and that is exactly why I chose it. Every facility action is governed by written directives. Human authority over credit decisions is not a UX preference, it is codified: no AI-assisted recommendation may execute without a recorded human authorisation. Evidence must be retained for years and reconstruct the decision under examination. Even the AI's own operating cost is a policy object with a mandated ceiling.

Against those requirements, the standard product-agent pattern collapses on contact:

Failure modeWhat we see todayWhat a regulated pipeline owes you
Chat as productNatural language in, fluent answer out, applause. The demo is the deliverable.A governed path: typed state, deterministic routing, evidence at every transition.
Vibes as QA"It seems to work" after five manual prompts. No one can say how good the agent is.A scored evaluation suite run against the live pipeline, with numbers on a dashboard.
Prompt as policyBusiness rules buried in a system prompt, enforced by hope.Deterministic rules in code that override the model. The LLM proposes; arithmetic disposes.
Approval as decorationA confirm button the happy path never hits.A structural gate: consequential actions are unreachable in code without a recorded human decision.
Self-improvement as marketing"The agent learns!" with no control experiment and write access to everything.Bounded correction tiers, measured acceptance, and an exam the agent can never edit.

The last row is where this project earns its name. Plenty of systems now claim self-improvement. Almost none can answer the auditor's follow-up: improved according to whom, measured how, and who approved the change?

· · ·
Chapter Three

The governed path

The pipeline itself is a LangGraph state graph with eight nodes and one non-negotiable fork. Intent is parsed from the analyst's natural-language request into a typed object. A retrieval step grounds the run in the credit policy corpus, section-aware chunks so that a citation like CRD-4.2 maps one-to-one to a retrievable unit. The reasoner must answer strictly from retrieved context and cite sections, and then a grounding guard verifies every citation against what was actually retrieved. Citing policy you never fetched is hallucination with a paper trail, so it is checked, not requested.

graph TD S([analyst request]) --> IP[intent_parser] IP --> CG[context_grounder
RAG + relevance threshold] CG -->|grounded| PR[policy_reasoner
structured output + citation guard] CG -->|no relevant context| RH[rejection_handler] PR --> RC[risk_classifier
deterministic rule table] RC -->|ROUTINE| AE[action_executor] RC -->|CONSEQUENTIAL| HG{{human_gate}} HG -->|APPROVED| AE HG -->|REJECTED| RH AE --> EW[evidence_writer] RH --> EW EW --> E([audit-ready JSON]) style HG fill:#2a2114,stroke:#e8b44a,stroke-width:2px

Then the fork. A deterministic rule table, not a prompt, decides what is consequential: any denial, any escalation, any error, any extension beyond sixty days. Consequential runs stop cold and render an approval card to a human: the borrower, the ask, the agent's recommendation and rationale, the exact policy sections cited, and the model spend so far. In the CLI that is a blocking prompt; in the web UI the graph literally suspends via LangGraph's interrupt mechanism and resumes only when an officer clicks a decision, which is recorded with their notes in the trail.

Every node appends to an append-only evidence log. Every model call is metered per token and per dollar against a policy ceiling. Every run, including the failures, ends as a self-contained JSON: what happened, in what order, on what evidence, at what cost, and who authorised it. The design position underneath all of it: ERROR is not REJECTED. When retrieval finds nothing relevant, the system refuses to adjudicate at all and says so, because an audit trail must distinguish "we could not decide" from "we decided no."

· · ·
Chapter Four

Eval-first, or it's just another LLM-calling webpage

Here is the fork in the road where most agent products quietly stay demos. The pipeline worked. The canonical scenario flowed through beautifully: right citations, right routing, six tenths of a cent per decision. Traditional next step: ship it, collect anecdotes, fix what users scream about.

I wrote the exam instead, because without one, everything above is a webpage that calls an LLM. Eight scenarios with expected behavior, executed through the real graph with live model calls, scored by deterministic checks only. No LLM judging LLM output; that is circularity wearing a lab coat.

CheckQuestion it answers
RoutingDid the risk table classify correctly, and did the run reach (or correctly skip) the human gate?
RecommendationIs the decision in the acceptable set for this scenario? Some cases legitimately admit deny-or-escalate.
RetrievalDid the sections this scenario turns on actually appear in the retrieved top-k?
GroundingDoes every cited section exist in the retrieved context? The no-hallucination metric.
Cost + latencyWhat does a decision cost, and is the spend visible per node, not just per run?

The scenarios were built to hurt: a request sitting exactly on the sixty-day routine boundary, a borrower explicitly in covenant breach, a request about credit card fees that the policy corpus says nothing about (the only correct answer is to escalate rather than improvise), and the ten-days-before-expiry request from chapter one. Results land on a Streamlit dashboard as metric cards, a pass/fail matrix per check, failure drill-downs in plain English, and trend lines across eval runs. Not one raw JSON in sight.

75%first evaluation · 6 of 8
100%grounding rate
87.5%retrieval hit rate
$0.006mean cost per decision

Two failures, and both were the expensive kind. The covenant-breach case got the right answer on the wrong evidence: the agent denied, but the covenant policy section never appeared in retrieval, so the denial rested on general eligibility language. And the late submission was the nightmare from chapter one: correct context, failed date arithmetic, and an approval that skipped the gate.

· · ·
Chapter Five

The system writes the ticket

Pause on what a traditional organization does at this exact moment. The eval report becomes a screenshot in a slide. Someone files a ticket. The ticket gets groomed, sprint-planned, assigned, fixed, code-reviewed, redeployed, and re-tested. Two weeks, five humans, and every step of that loop is human glue between machines that already speak the same language.

The failure report was machine-readable. The codebase was machine-readable. The verification was machine-executable. The only irreplaceable human in the loop was the one with merge authority, so I automated everything except that person.

That is the design bet of WARDEN's correction ladder: let the system write its own ticket and work it, across both kinds of fix, the non-deterministic kind (tuning how the agent retrieves and prompts) and the deterministic kind (changing actual pipeline code), with guardrails that get stricter as the power grows.

Tier 1 · Parameter tuning

Bounded settings, measured acceptance

The model proposes exactly one change from three declared settings: retrieval depth, a retrieval query suffix, one appended reasoner rule. Hard bounds in code. The full evaluation suite re-runs; keep only if strictly better with zero regressions, else auto-revert.

Tier 2 · Code patches

Sandboxed ops agent, human-gated merge

An ops agent writes real code against a write whitelist, applies it in a disposable git worktree, and must pass the unit suite plus the full live evaluation suite there. Success produces a branch and a diff. A human merges. Always.

And one rule above both tiers, the rule the whole design hinges on: the agent may fix the system, never the exam. The eval scenarios, the scorer, the harness, and the ops agent itself sit outside every writable surface. An agent that can edit its own exam will eventually pass by editing the exam. This is not cynicism about models; it is Goodhart's law applied to things with gradient-free optimization pressure and a deadline.

· · ·
Chapter Six

Tier 1 · The loop adjusts its own settings

Iteration one. The loop read the failure report and diagnosed the covenant miss precisely: the expected section was absent from the retrieved top-four. Proposal: retrieve five chunks instead of four. The evaluation suite re-ran. Covenant-breach passed, retrieval hit rate went to 100%, nothing regressed. Accepted, and the tuning file now carries k=5 for every future run, CLI and UI alike. Pass rate: 75% → 88%.

Iteration two. The loop then correctly diagnosed the late-submission failure, the reasoner had the thirty-day rule and fumbled the arithmetic, and proposed a stern extra prompt rule about submission deadlines. The evaluation suite re-ran. The model approved the late request anyway. No improvement, automatic revert, reason logged.

That revert is my favorite artifact in the repository. A plausible fix, the kind a tired engineer merges on a Friday, was discarded by measurement rather than judgment. And its verdict was blunt: this failure does not live in the prompt.

Which is itself a finding. Date arithmetic under a policy deadline is exactly the kind of check that should never have been the LLM's job. The honest fix was code. And I had just built a system that knew the root cause, held an LLM connection, and could read its own source.

· · ·
Chapter Seven

Tier 2 · The ops agent files its PR

The ops agent gets developer powers under three structural constraints. A write whitelist: pipeline source and tests only; the exam, the scorer, the tuning file, and its own code are unreachable. A sandbox: every patch applies in a disposable git worktree on an ops/ branch, where the full unit suite and the entire live-model evaluation run must pass; the working tree and master are never touched. And no merge authority: success ends with a committed branch and a diff awaiting human review, the same gate the loan decisions face, applied to the system itself, because changing the decision system is the most consequential action there is.

I pointed it at the late-submission failure. Three attempts, and the rails earned their keep twice:

AttemptWhat it proposedVerdict
1A deadline check whose date parser guessed too eagerly when no dates were presentRejected by the sandbox evaluation run: it broke the sixty-day boundary scenario. Regression fed back into the next prompt.
2A refined patch whose anchor text matched twice in the fileRefused at apply time: edits must be unique exact-match replacements. Error fed back.
3A request_date field on the parsed intent, a pure date-arithmetic function that returns None safely when dates are absent, a deterministic override forcing denial when the thirty-day window is violated regardless of what the LLM concluded, consequential routing so a human always reviews it, and a regression test for the entire path14 unit tests green, evaluation suite 8 of 8 in the sandbox, zero regressions. Committed to ops/20260909_035611. Stopped.

I read the diff. It was, line for line, the fix I would have written, plus a test I might have been too lazy to write, and one wart, a brittle regex fallback for dates in raw text, that fails safe (no match, no override) and got flagged in review notes. I merged it. A verification run on master confirmed: eight of eight.

Worth saying plainly: the fix the system shipped is deterministic code that overrides its own model. WARDEN's self-correction made the system less dependent on the LLM, not more. That is what maturation should look like in a regulated pipeline.

· · ·
Chapter Eight

Under the hood

One graph, injected world

The pipeline is a single LangGraph StateGraph over a typed state object; evidence and token usage are append-only reducers. Every external effect, the LLM, the retriever, human input, the clock, the evidence sink, enters through one injected dependency object. No globals anywhere. That one decision pays for itself three times: the entire test suite runs offline against fakes; the CLI gate (blocking stdin) and the web gate (LangGraph interrupt() plus a checkpointer) are the same node with a flag; and the eval harness drives the identical production graph rather than a test double.

Retrieval that supports citations

Policy documents are chunked on their numbered section headers, so each chunk is one citable unit with its section ID in metadata. FAISS in-memory, scores thresholded, and the reasoner's citations verified against the retrieved set after the fact. Structured output everywhere via Pydantic schemas, no free-text JSON parsing, with a malformed response routing to rejection rather than a retry-until-plausible loop.

The correction ladder as code

graph LR EV[evaluation suite
8 scenarios · live model] -->|failure report| T1[Tier 1
tuning loop] T1 -->|1 setting · re-run| ACC{better AND
zero regressions?} ACC -->|yes| KEEP[tuning.json updated] ACC -->|no| REV[auto-revert · logged] EV -->|resists tuning| T2[Tier 2
ops agent] T2 -->|whitelisted edits| SBX[git worktree sandbox
unit suite + full evaluation run] SBX -->|verified| PR[ops/ branch + diff] PR --> HUM{{human merge}} SBX -->|failed| RETRY[error fed back
bounded retries] style HUM fill:#2a2114,stroke:#e8b44a,stroke-width:2px

Failure modes the rails caught in this very story: a candidate patch regressing a passing scenario (sandbox evaluation run rejected it), a patch that could not apply uniquely (apply step refused it), and a prompt-level fix that measured as no improvement (auto-reverted). Each rejection fed its reason back into the next proposal. The loop is allowed to be wrong cheaply, which is precisely what makes it safe to run.

Evidence, end to end

A pipeline run writes an audit JSON: outcome, human involvement, per-step inputs/outputs/tokens/cost. An eval run writes a scored report. A correction run writes what was diagnosed, proposed, measured, and decided. The repo's own history is the meta trail: the ops agent's commit sits on master with its sandbox evidence, merged by a human. The unedited eval reports from every stage of this story ship in the repository, because an evidence system that curates its own evidence would be a punchline.

· · ·
Chapter Nine

The numbers

StagePass rateGroundingRetrieval hitsWho acted
First evaluation run75%100%87.5%nobody yet
Tier 1 · k: 4→588%100%100%loop · auto-accepted
Tier 1 · prompt rule88%100%100%loop · auto-reverted
Tier 2 · attempts 1–2rejectedsandbox rails
Tier 2 · attempt 3 + merge100%100%100%agent proposed · human merged
Post-merge verification on master100%100%100%evaluation re-run

Total model spend for every evaluation run, every correction iteration, and every sandbox verification: under fifty cents, on a flash-class model. Mean cost per loan decision: about $0.006, metered per node against a policy ceiling of fifty cents per workflow, at which point the run is flagged, exactly as the operational risk directive demands.

· · ·
Chapter Ten

Why this matters beyond a demo repo

For regulated enterprises

Banks, insurers, and healthcare systems do not have an AI capability problem anymore; they have an AI accountability problem. The blocker in every serious conversation is the same three questions: what did it do, what did it cost, and who authorised it? WARDEN is small, but its shape is the answer those industries are converging on: the agent as a component inside a governed path, deterministic policy checks that override the model, human authority encoded structurally rather than procedurally, and evidence generated by the machinery itself rather than reconstructed after the fact. If your model-risk-management team cannot replay a decision from the artifact alone, you do not have an AI product, you have an AI liability.

For companies building agent platforms

The next differentiator in the agent tooling market is not a smarter loop; flash-class models are already capable enough to be dangerous. It is the operations story: evaluation suites as first-class citizens, correction tiers with graduated authority, sandboxed self-modification with an untouchable exam, and promotion gates that produce diffs a human can review. Every one of those is a product surface. The teams that ship them win the enterprise deals that "look how fluent it is" never will.

The transferable pattern

Nothing here is loan-specific. Swap the policy corpus for clinical protocols, procurement rules, or claims guidelines; swap the scenarios; keep the ladder. The pattern is three words at every tier: measured, bounded, gated. Improvements are kept by measurement, not persuasion. Authority is bounded by construction, not instruction. And promotion, of a loan and of a line of code alike, passes through a human, every time, with the evidence attached.

· · ·
Chapter Eleven

The fine print

🤔 Read before quoting the 100%

The evaluation suite is eight hand-authored scenarios. It found two real failures, a good hit rate for eight cases, but it is a smoke alarm, not a certification; scenario generation and coverage growth are the obvious next investment. The Tier-1 loop got lucky on its first setting, retrieval k is forgiving. The ops agent's regex fallback for dates in raw text is brittle and shipped anyway because it fails safe, which is what the human review gate is for. The sandbox is a git worktree, proportionate for whitelisted Python reviewed before merge, not for a hostile threat model. And one honest caveat about the whole arc: the same model family that failed the date arithmetic inside the pipeline diagnosed and fixed it as the ops agent. Less paradoxical than it sounds, structured diagnosis over an explicit failure report is a far easier task than catching your own slip mid-reasoning, but it deserves saying out loud.

The deeper limitation is philosophical and worth owning: WARDEN proves the loop on a miniature. Eight nodes, three policy documents, eight scenarios. The claim is not that this scales unchanged to a core banking platform. The claim is that the shape scales: every piece here, the gate, the exam, the ladder, the whitelist, the sandbox, is the small version of a thing enterprises already know how to operate at size.

· · ·
Chapter Twelve

⚡ Try WARDEN

The whole system is one clone away: the governed pipeline, the web UI with the live approval gate, the evaluation suite and dashboard, both correction tiers, and the unedited eval reports behind every number in this post.

# clone and install (Python 3.11+)
git clone https://github.com/mailtotanvir/warden.git
cd warden
python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# configure Vertex AI (any Gemini project works)
cp .env.example .env        # set GOOGLE_CLOUD_PROJECT
gcloud auth application-default login

# run the governed pipeline, hold the gate yourself
python main.py                       # 90-day request → human gate
python main.py --request routine     # 30-day request → auto-approved
streamlit run app.py                 # web UI + eval dashboard

# the exam, and the ladder
python -m evals.run                  # score the evaluation suite → dashboard
python -m evals.self_correct         # tier 1: bounded tuning loop
python -m evals.ops_agent            # tier 2: sandboxed fix → ops/ branch

pytest -v                            # 14 tests, fully offline

Run the evaluation suite, break a scenario, and watch the ladder climb. Then try to make the ops agent touch the exam. That refusal is the product.

Governed AgentsLangGraphHuman-in-the-Loop Eval-FirstSelf-Correcting SystemsSandboxed Ops Agent Commercial LendingVertex AI · Gemini FlashFAISS RAG Audit EvidencePython 3.11