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.
Synthetic suite · 208 models · published inputs + deterministic engine → identical verdicts & hashes on every run.
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.
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.
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.
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
}
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.
| Model | What the engine found | Decision path | Evidence cited | Result |
|---|---|---|---|---|
| MDL-0020 | Tier-1; independent validation expired (past its 12-mo window) | hard control C3 fails on a Tier-1 model | C3:fail | blocked |
| MDL-0038 | Tier-3; validation expired AND monitoring off | 2 controls fail (C3 + C4) | C3:fail · C4:fail | blocked |
| MDL-0004 | last governance review past cadence; all else met | 1 soft gap (C6) → waivable | C6:fail | conditional |
| MDL-0113 | passed the gate, then PSI > 0.25 for 2 consecutive months in the live series | gate PASS, but drift monitor fires | 2026-03 · PSI 0.406 > 0.25 | forced re-validation |
| SHADOW-03 | active in telemetry, no inventory record | C1 fails (uninventoried) | telemetry · inventory:absent | undocumented |
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:
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.
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))
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.
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.