WTWilly Tai
Case studyAI Governance & Assurance

The model-risk gate that never stops watching.

Most model governance is a one-time checklist at deployment. The two things that actually fail an SR 11-7 exam happen before that gate (models nobody inventoried) and long after it (models that silently degrade in production). Custodian is a deterministic control plane for both, and a language model never decides whether a model ships.

7
blocked · of 200
Failed the SR 11-7 / MAS gate.
96.2%
inventory completeness
8 telemetry-only models surfaced.
10
forced re-validation
Live models the drift monitor flagged.
100%
decisions cited & replayed
Every verdict tied to a control/metric.

Synthetic suite · 208 models · published inputs + deterministic engine → identical verdicts & hashes on every run.

01 / The pain

The findings live where the checklist never looks.

Examiners describe two recurring weak spots in model risk management, and AI/ML makes both worse because it's now roughly half of a large bank's model inventory. The first is the inventory itself. A model that turns up during an exam, running in production, never recorded, never validated, is one of the most common MRAs (Matters Requiring Attention). The second is ongoing outcomes monitoring: SR 11-7's guidance on watching a live model for degradation is among the least-implemented sections, so models drift quietly until a bad quarter exposes them. MAS's December 2024 AI Model Risk paper names the same two gaps for AI specifically.

A static deployment checklist, even a perfect one, addresses neither. It can't catch a model that was never entered to be checked, and it goes silent the moment the model passes. DBS, under MAS's Project MindForge, runs 430+ AI use cases across 2,000+ models; at that scale, "we reviewed it at launch" is not a control.

02 / Why naive AI fails here

Asking an LLM "is this model OK to deploy?" is the one thing you must not do.

The tempting shortcut is to hand the model's documentation to an LLM and let it judge readiness. That fails for structural reasons, and no better prompt can fix them:

So the real system is a deterministic rules engine over a published control set, plus a deterministic drift monitor over each model's live performance series. The model is allowed exactly one job. It phrases the gap memo and board note, and it does so only by citing a control the engine already failed, or by abstaining where there's no evidence.

03 / The trust boundary, applied

The decision is made in code. The model only writes it up, and only with a citation.

This is the load-bearing line of the system. Every verdict and every drift trigger is computed in code from the model's inventory record and its performance series. Each one is reproducible, re-runnable, and tied to a named control. The language layer is strictly downstream and read-only: it drafts the gap memo and the board paragraph about decisions the engine already made, and each clause must cite a failing control or it isn't written. A human, the MRM Head, is required for the one consequential action, which is waiving a CONDITIONAL.

DETERMINISTIC · computed, cited, reproducible MODEL + HUMAN · language & sign-off only Inventory200 models Telemetrylive perf series Gate engine6 controls → verdict Drift monitorPSI/AUC → re-validate PASS / CONDITIONAL/ BLOCKED · cited Gap memoLLM · cite-or-abstain MRM Headwaives conditional Append-only, hash-chained ledgerevery gate + drift + sign-off decision · tamper-evident · replayable
fig.1 · the trust boundary: two deterministic engines decide, and the model and the human sit downstream
04 / The decision function

Six controls resolve to one verdict, with no model in the loop.

Here is the actual gate. It joins a model's inventory fields against the published control set, scores six controls, and resolves PASS / CONDITIONAL / BLOCKED by an explicit policy: a Tier-1 model failing a hard control (inventory, validation, monitoring) is blocked; any model failing two or more is blocked; a single soft gap is conditional and waivable. The parameters are published in thresholds.json, not buried in prose.

function evaluateGate(m) {
  const checks = [];
  checks.push({id:"C1", met: m.in_inventory === true});                    // inventoried
  checks.push({id:"C2", met: m.tier != null});                            // risk-tiered
  let c3 = m.validated === true && m.validation_date &&                    // validated, in date
           monthsSince(m.validation_date) <= T.validation_validity_months[m.tier];
  checks.push({id:"C3", met: c3});
  checks.push({id:"C4", met: m.monitoring_configured === true});           // monitoring on
  checks.push({id:"C5", met: !!m.owner && !!m.approver});                  // owner + approver
  let c6 = m.last_review_date &&                                          // review in date
           monthsSince(m.last_review_date) <= T.review_cadence_months[m.tier];
  checks.push({id:"C6", met: c6});

  const fails = checks.filter(c => !c.met).map(c => c.id);
  if (fails.length === 0) return {verdict:"PASS", fails, checks};
  const hardFailed = fails.some(id => T.hard_controls.includes(id));       // C1, C3, C4
  if ((m.tier === 1 && hardFailed) || fails.length >= 2)
    return {verdict:"BLOCKED", fails, checks};
  return {verdict:"CONDITIONAL", fails, checks};                           // 1 soft gap → waivable
}
The model is nowhere in this function. It runs only afterwards, to phrase the memo, citing exactly the control IDs in fails.
05 / Worked example

One blocked model and one drifting model, each traced to its evidence.

Two cases show the two halves of the system. The first is a static gate verdict. The second is a model that passed the gate and was forced back into validation months later by the drift monitor, which is the failure mode a launch checklist can never see.

ModelWhat the engine foundDecision pathEvidence citedResult
MDL-0020Tier-1; independent validation expired (past its 12-mo window)hard control C3 fails on a Tier-1 modelC3:failblocked
MDL-0038Tier-3; validation expired AND monitoring off2 controls fail (C3 + C4)C3:fail · C4:failblocked
MDL-0004last governance review past cadence; all else met1 soft gap (C6) → waivableC6:failconditional
MDL-0113passed the gate, then PSI > 0.25 for 2 consecutive months in the live seriesgate PASS, but drift monitor fires2026-03 · PSI 0.406 > 0.25forced re-validation
SHADOW-03active in telemetry, no inventory recordC1 fails (uninventoried)telemetry · inventory:absentundocumented
The drift row is the whole argument. That model satisfied all six controls at deployment and would sit green on any static dashboard. The deterministic monitor caught its population-stability index crossing 0.25 for two straight months and flagged it back into the queue, cited to the exact month and metric. That is the SR 11-7 weakness (outcomes monitoring) turned into a control that fires on its own.
06 / Numbers & honest trade-offs

What the suite produced, and exactly what it does not prove.

Run over the synthetic suite of 200 inventoried models plus 8 telemetry-only ones, the engine produces: 7 blocked for SR 11-7 / MAS gaps, 23 conditional, 170 passed; inventory completeness 96.2% once the 8 undocumented models are surfaced; 10 live models auto-flagged for forced re-validation on drift; and 100% of gate and drift decisions cited to a control or metric and reproduced on replay. The 30 seeded-deficient models resolve cleanly to 7 blocked plus 23 conditional, which is the policy working, not a fudge.

Where these come from, flatly. This is a synthetic suite, a seeded inventory whose deficiencies and degradations are deliberately injected, so these figures show what a governed control plane looks like rather than a real-world outcome on a real model book. The inputs (models.json, thresholds.json) are published and inspectable, and the gate and drift engine is fully deterministic, so a third party gets the same verdicts and the same hashes on every run. That reproducibility is the point, but it is reproducibility of a constructed world.

The honest limits, stated plainly:

07 / Governance, shown

A row of the ledger, and what breaks it.

Every gate verdict, drift trigger and MRM sign-off is appended to a hash-chained ledger. Each entry's hash covers its own fields and the previous hash, so rewriting any decision after the fact breaks the chain at exactly that row, which the live Tamper button demonstrates. Replay recomputes every hash from the recorded fields and confirms they reproduce, which is the same guarantee the seeded generator gives upstream.

AI Control Ledger · entryintegrity verified · replay reproduces
seq        : 2
action     : drift_revalidation
subject    : MDL-0113        decision : FORCED RE-VALIDATION
evidence   : [month:2026-03, "PSI 0.406 > 0.25; AUC 0.685 < 0.7"]
prev_hash  : 7a1c4e09
hash       : b1b3f3d5   ← = fnv1a(prev_hash + canonical(entry))
Threat model: append-only; a flipped decision or evidence changes the canonical string → the recomputed hash no longer matches the stored one → chain breaks at that seq. Tamper + Verify run live in the demo.

See it run.

The numbers above are live output from the engine over the synthetic suite. The working application gives you the 200-row inventory, the animated control checklist with its cited gap memo, the 24-month PSI/AUC lifecycle timeline with the breach marked, the MRM-Head waiver, and the tamper-evident ledger, all client-side with no network.

Open the live demo →Click a model row → watch the gate decide → open its lifecycle. Then tamper with the ledger.

Why I built the watching half, not just the gate.

It would have been easier to ship the deployment checklist alone. It demos well and it's the part everyone builds. But the checklist is the part examiners already know how to pass. The findings that actually hurt sit in the two places a checklist is blind: the model nobody entered, and the model that quietly went bad after it shipped. So I made both of those into deterministic controls that fire on their own, a telemetry-vs-inventory reconciliation and a thresholded drift monitor, and I kept the language model strictly downstream, citing the control or saying nothing. The discipline I'm showing here is more than "I can build a gate." It is knowing which control is load-bearing, being honest that a synthetic validated? flag can't stand in for real validation judgement, and refusing to let a model decide anything an examiner would later have to defend.