AI governance

What happens when the model is wrong

Every high-risk system needs a clear decision: approve, revise, or stop. I build the evidence, the review gates, and the human sign-off that make that decision defensible.

I have shipped 38 AI systems since July 2023 and 25 are in production. What follows is the machinery that decides whether one of them goes out, the artifacts it leaves behind, and the case where that machinery passed something it should not have. Every claim here points at a file in this repository, because governance you cannot inspect is just a paragraph.

The release gates

Five checks that can stop a release — and the paper trail each one leaves

These are the gates my demo factory runs on every build. Each one is a written contract a separate agent executes, and each one writes an artifact I can go back and read. A gate whose output nobody can audit is a vibe.

  1. Secret and PII scan CLEAN / LEAKS

    Runs on every build before anything else. Fails on API keys or tokens, on any real person's name, email, address or personal data, on confidential client data, and on hardcoded author filesystem paths. Fictional sample data is expected and passes. The cheapest model on the roster runs it, so it runs on everything, every time.

    Artifact: portfolio/_logs/<slug>.sanitize.log

  2. User simulation PASS / FAIL

    A real browser drives the actual primary action, with selectors derived from reading the file rather than guessed. Zero console errors and zero uncaught page errors, on load and during interaction. Warnings are allowed; errors are not.

    Artifact: portfolio/_test/<slug>.spec.mjs

  3. Offline resilience PASS / FAIL

    The same flow is run again with the network cut. It must still produce output and still throw nothing. Anything model-backed has to degrade to a deterministic bundled result rather than break in someone's hands. This is the gate that decides whether a failure is graceful or a blank screen.

    Artifact: portfolio/_logs/<slug>.qa.log

  4. Determinism PASS / FAIL

    The deterministic path runs twice with a reload in between, and the key output must be byte-identical. If I cannot reproduce an output I cannot debug it, and if I cannot debug it I should not have shipped it.

    Artifact: portfolio/_test/<slug>.spec.mjs

  5. Design fidelity MATCH / NO-MATCH

    A screenshot is compared against the real product's own design tokens, read from that product's source rather than from memory. It exists to stop a demo drifting into a prettier thing than the product it claims to represent.

    Artifact: portfolio/_shots/<slug>.png

The part that matters

The gates passed. A second audit overturned them.

The first run of the factory came back 18 of 18 green, in a single cycle. Clean on secrets, clean on the user simulation, design matching the real product tokens. I wrote that number down and it was, in the narrow sense, true.

Then I ran a deeper audit that did not trust the gates: drive each demo with a real browser and diff what it displays against what it actually did. Two demos were labelling their output groq · livewhile making no model call at all. The output was pre-baked. Every gate had passed it, because no gate was asking “is this label telling the truth?” — they were asking whether output appeared, whether it was deterministic offline, whether any secret leaked. All fine. All beside the point.

That is the failure mode I care most about, and it is not a model failure. It is a measurement failure: the system was reporting a state it was not in, and my checks were shaped so they could not notice. A demo that lies about being live is a small version of a production system that lies about being confident.

The fixes were specific. One demo got rewired to make a real call and score it against ground truth. Others: a clipboard crash, a CTA blocked by an overlay, simulated output that now says (sim) on its face, honest labels replacing aspirational ones. External web fonts stripped so the pages are genuinely self-contained rather than nearly. Four demos were left explicitly pending with a written report each, rather than being quietly marked done.

What I changed afterwards was not the demos. It was the question the gate asks. A gate that only checks whether output exists will pass a convincing lie every time.

The review desk

Run the whole review function, not just one control

Four synthetic health-system cases, worked end to end: intake, risk tier with every rule that fired, required evidence that fails closed, six reviewers whose clinical or security block cannot be outvoted, an atomic go-live decision, and a single auditable package out the other side. All in your browser, all on fictional data.

Open the Review Desk

Governance in action

Four controls you can run right now

Describing a control and demonstrating one are different claims. These four run the real logic in your own browser: a consent gate that refuses, a deterministic validator that contains no model, a release gate that blocks a committed secret, and a retention toggle that shows what is kept when a session ends.

Nothing leaves this page. No network request, no storage, no analytics — every rule below is plain JavaScript evaluated in your tab, on synthetic data. The build fails if a request fires while these are driven, because a promise like that is worth what the test behind it is worth.

Most demos show the happy path. This one defaults to the refusal, because what a system does when it is not allowed to proceed is the only part worth trusting.

Demo — sample data only. No client or customer data. Runs entirely in your browser; nothing you interact with is sent anywhere.

Refused — the session does not run

  1. Consent record present and current — blocked

    No record found for this participant. The gate stops here — it does not fall through to a default.

  2. Teach-back completed — not evaluated

    Not evaluated. Once a gate blocks, later checks do not run and cannot overturn it.

  3. Scope matches the requested action — not evaluated

    Not evaluated.

  4. Refuse — blocked

    Session refused and the refusal is logged with the rule that caused it. A human is notified; the system does not retry.

The obvious failures get caught before any model is even asked

A missing disclosure, a promised outcome, numbers that disagree — no AI is needed to catch these, and none is used. Three plain rules run in this tab; edit the text and watch them fire.

Demo — sample data only. No client or customer data. Runs entirely in your browser; nothing you interact with is sent anywhere.

Blocked by 1 deterministic rule — no model was consulted

  • Required disclosure present — passed

    Care-sector output must carry its disclosure. A missing one is a compliance defect, not a style note.

  • No absolute-outcome language — failed

    A model will happily promise an outcome. A regex will not let it.

  • Numeric claim is internally consistent — passed

    "Five of the four" is the kind of thing fluent text hides and arithmetic catches instantly.

An LLM judge can run after this, and it is useful for the things rules cannot see. It runs second, and it cannot overturn a deterministic failure.

A dangerous change is stopped before it ships — and the gate names why

A simplified version of the fence that runs on every change. Pick a diff — three of the four are meant to be stopped, and the gate names which check stopped them.

Demo — sample data only. No client or customer data. Runs entirely in your browser; nothing you interact with is sent anywhere.

+ const client = new Client({
+   apiKey: 'sk-live-9f2c4a7e11b8', // committed by mistake
+ });

Release blocked by: Secret scan

  • Secret scan — blocked

    A live-format API key appears in the diff. Blocked before it can reach a remote.

  • Destructive-action classifier — passed

    No irreversible operations.

  • Claim-of-done requires evidence — passed

    Change is covered by the existing suite.

What is kept when the session ends

Retention off is the production default. Toggle it and watch the record change shape — with retention off the verbatim fields are absent from the page, not merely hidden.

Demo — sample data only. No client or customer data. Runs entirely in your browser; nothing you interact with is sent anywhere.

Structured summary only — there is no transcript to leak

Session id
ssn_8f21c4 (synthetic)
Duration
14 min
Topics covered
scheduling · medication reminders · follow-up
Action items
3 created, 1 assigned to a human reviewer
Sentiment band
neutral-positive

The three fields that appear when you toggle retention on are not on this page right now. That is the difference between minimisation and redaction.

Hard lines

Lines I do not cross, and what enforces them

A rule with no enforcement is a preference. Each of these is checked by something that runs, not by me remembering.

No real personal data, anywhere demonstrable

Every demo runs on fictional sample data. Real products operate on separate, isolated data paths that the demos cannot reach. During one build the scanner caught a placeholder that read like a real person's name and blocked it until it was replaced.

Enforced by: the secret and PII gate, on every build

No credential ever reaches a committed file

The model API key lives only in a gitignored environment file and in the host's environment. It is in no demo, no registry entry, and no committed file. Model calls from the browser go through a same-origin proxy so the key never travels to a client.

Enforced by: a same-origin proxy route plus the secret scan

No external network request from a demo

One same-origin call to my own proxy, and nothing else. No CDNs, no remote web fonts, no analytics, no remote images. One build wanted a real mapping library; real map tiles need external requests and real geography, so it became a self-contained abstract tracker instead.

Enforced by: the secret and PII gate flags any external URL

Simulated output is labelled as simulated

If output did not come from a model call, it does not get to look like it did. This is now a hard line specifically because a previous version of the factory broke it and the gates did not notice.

Enforced by: the second-pass runtime audit, which is why it exists

Cost is a governance decision

Keeping the checks cheap enough that they still get run in month nine

Spending a frontier model on a regex scan is not rigour, it is waste, and waste is what makes teams quietly stop running the checks. I route by what the job actually needs.

Model routing by agent role, with the reason for each choice
RoleTierWhy
OrchestratorFrontierPlanning, dependency and loop control, resolving conflicting reviews, final audit synthesis. Highest reasoning, fewest calls.
BuilderMidThe coding workhorse. Reads real product source and reproduces design and flow. Many run in parallel, so cost per call matters.
VerifierMidWrites and runs the browser simulation and interprets what a failure actually means. Needs real reasoning about errors, not pattern matching.
Design reviewerMidCompares a screenshot against real tokens, and escalates genuinely ambiguous calls upward rather than guessing.
ScannerCheapestRegex, secret and PII scanning, registry validity. Rote work with a clear right answer. Cheap enough that it runs on everything.

The principle: reserve the expensive reasoning for judgment, parallelise the mid-tier for building and verifying, push rote checks down to the cheapest thing that succeeds. A deterministic script beats any model at the jobs a script can do, and it never has an off day.

Restraint

Two places I stopped short on purpose

The eval numbers stay internal

I run accuracy evals against labelled ground truth on the systems that need them. Those numbers are a quality instrument, and the moment they become a marketing surface I will start optimising the number instead of the system. They are also easy to quote out of the context that makes them meaningful. So they inform what I ship and they do not go on a page. If you are evaluating me and you want to see them, ask and I will walk you through them properly.

HIPAA, stated precisely

Two of the production systems sit in the care sector, so PHI handling under HIPAA is a design constraint from the first commit rather than a retrofit: separate isolated data paths, access control and audit logging on the paths that touch it, and no real personal data in anything demonstrable. What you will not find on this site is a “HIPAA certified” badge, because no authority issues one. There is no certifying body. A vendor claiming that badge is telling you they have not worked under the rule. When there is a signed BAA or a completed third-party assessment behind a claim, the right move is to name that artifact and who signed it, which is a stronger thing to say than a badge anyway.

The first ninety days

What a team would see me do in the first 90 days

A proposed operating approach for running an AI review function inside an existing governance program — not a claim about any organisation's internal state. Everything here is a practice I have already run owner-side, scaled to a team.

Days 0–30 — see the whole board before touching anything

Inventory the AI use cases in flight: lifecycle stage, owners, and the decision forums that already exist. Baseline the review queue — volume, age, risk mix, turnaround, blocked reasons, analyst capacity. Map current policies and artifacts against NIST AI RMF, CHAI guidance, ISO/IEC 42001, HIPAA, FDA CDS guidance and state obligations. Pick one high-risk and one high-volume workflow as the first two to improve.

Days 31–60 — agree the rules, then pilot them on real work

Agree the risk taxonomy, evidence standards, decision rights, exception rules and turnaround targets with the people who have to live with them. Pilot the review workflow with clinical, privacy, security, legal, operations and data science at the same table. Define monitoring minimums and change-control triggers by risk tier, and set an analyst calibration and coaching cadence.

Days 61–90 — make it visible, drill it, report it

Launch the prioritised queue and its dashboards. Publish decision templates, model-card requirements and escalation paths. Run one monitoring-and-incident tabletop and one vendor model-change review, end to end. Report to leadership on cycle time, backlog, evidence quality, exceptions, incidents — and the friction the process is costing delivery teams, because a control nobody can live with gets bypassed.

Honest gaps

What this page does not cover yet

Next step

I name these gaps because closing them is the work

Solo-built products earn solo-scale controls; a health system runs the enterprise versions — independent review, continuous monitoring, provenance, red-teaming — inside a program that already exists. I have built every one of these controls owner-side, and what I want next is to operate and strengthen them at that scale, with cross-functional accountability. I would rather start that conversation from an accurate picture than a badge.