AI EngineeringZero to ProductionHome·About·What’s new·Contact
Safety & Red-teaming · Chapter RT5

Governance, compliance & bias

Defenses keep a system safe; governance makes it accountable: EU AI Act risk tiers, model cards, audit trails, bias auditing, and the incident runbook a regulated org needs.

⏱️ ~2 hours🧪 1 lab🎯 Expert

Learning objectives

  • Explain the governance an org needs around a live AI system.
  • Place a system in the EU AI Act risk tiers and know the obligations.
  • Write a model card and keep an audit trail.
  • Audit for bias and fairness, and run an AI incident.
▶ Runnable companionThe code in this lesson is also saved under code/rt5-governance/ in the course, with a README. Run the scripts or copy the configs directly.

From safe to accountable advanced

Picture the moment every AI team dreads. Your support agent has been live for six months. Then a customer forwards a screenshot: the bot approved a refund it should have escalated, quoting a policy that doesn't exist. Legal calls. Your VP asks three questions in a row — Who signed off on this going live? Can you show me exactly what the model was told and what it decided? What happens now, this hour, to stop it? — and you realize you can't answer any of them. The model was safe in the sense that it had guardrails. It was not accountable: no one owned it, nothing was written down, and there was no plan for the bad day. That gap between "we added defenses" and "we can stand behind this in front of a regulator" is exactly what this chapter closes.

Here is the distinction in one line: defenses reduce the chance of harm; governance is how the organization takes responsibility for it. Think of it like a commercial airliner. Anti-lock brakes and redundant hydraulics are the defenses — engineering that makes the plane safer to fly. But you'd never board a plane that had only those. What lets it carry passengers is the governance around it: a certified type rating, a maintenance logbook every mechanic signs, a checklist the crew runs before every takeoff, and an accident-investigation process for when something does go wrong. Governance is the paperwork, the ownership, and the process that turn "probably safe" into "answerable to someone."

Concretely, governance for a live AI system is four things, and every later section of this chapter is one of them: a risk classification (how much scrutiny does this system legally require?), documentation (what is it for, and what did we test?), an audit trail (what actually happened, provably?), and an incident process (what do we do the day it breaks?). The common mistake engineers make is treating all of this as bureaucracy that slows shipping — a tax paid to a compliance team after the real work is done. It's the opposite: governance decided early shapes the architecture. If you know on day one that a hiring tool is legally high-risk, you build in human review, logging, and fairness testing from the first commit, rather than bolting them on in a panic after launch. This is why it belongs in a red-team track and not just a legal binder: the engineer who understands governance builds systems that are defensible by design.

Defenses (RT4) keep a system safe; governance makes it accountable — the documentation, compliance, and process a regulated org (like a financial-services company) needs. It extends O4 and W14 into legal and ethical obligations.

defenses make a system SAFE; the four pillars on top make it ACCOUNTABLE Defenses (RT4) reduce harm + 1 · Risk tier how much scrutiny 2 · Docs model card 3 · Audittrail what happened 4 · Incident the bad-day plan Accountable answerable to a regulator Governance = defenses + four pillars. Defenses alone make a system safe; a risk classification, documentation, an audit trail, and an incident process are what make it accountable — each is a later section of this chapter.
🗺️ How to read this diagram

Read it left to right: start from what you already have, add the four middle boxes, and arrive at the payoff on the right.

  • The blue box on the left is the RT4 defenses — guardrails that reduce the chance of harm. That is where the previous chapter stopped.
  • The four white boxes in the middle are the four things governance adds: a risk tier (how much legal scrutiny), documentation (the model card), an audit trail (a provable record of what happened), and an incident process (the plan for the bad day). Each is a numbered section later on this page.
  • The green box on the right is the payoff: only with all four does "probably safe" become accountable — something you can stand behind in front of a regulator.

In short: safe is engineering; accountable is safe plus the four governance pillars.

EU AI Act risk tiers advanced

Two teams build a chatbot. One ships in a week; the other spends three months in review. Why? Because one bot answers product questions and the other decides who gets a mortgage. Same technology, wildly different consequences if it's wrong — and the law noticed. Regulators realized long ago that you cannot write one rule for "AI," any more than you'd write one safety rule for both a toaster and a nuclear reactor. So instead of regulating the technology, they regulate the stakes: the more a system can hurt someone, the more you have to prove before you turn it on.

That is the whole idea behind a risk-tiered framework, and the EU AI Act is the one that has become the global reference point (much as GDPR became the default for privacy — companies far outside Europe adopt it because it's the strictest bar, and clearing it clears the others). It sorts every AI system into four buckets by potential for harm. Think of it as a customs form: before your system crosses into production, you declare what it does, and that declaration determines how much inspection it gets. A spam filter waves through; a credit-scoring model gets opened and searched.

The reason this matters to you as a builder and not just a lawyer: your tier is a design constraint, not a paperwork step at the end. The single most expensive mistake here is discovering late that your "simple internal tool" is actually high-risk — because it screens job applicants, say — after you've already built it with no logging, no human-in-the-loop, and no fairness data. Now you're re-architecting under deadline pressure. Classify honestly on day one and the obligations become a checklist you build toward, not a wall you hit. And classify to the use, not the tech: the same LLM is minimal-risk writing marketing copy and high-risk ranking loan applications.

The EU AI Act classifies AI systems by risk, and the tier sets your obligations. Even outside the EU it's becoming the reference framework.

higher stakes → heavier obligations; classify to the USE, not the tech Unacceptable — banned e.g. social scoring High-risk — heavy obligations e.g. credit scoring · hiring · medical Limited — transparency (disclose AI) e.g. chatbots Minimal — few requirements e.g. spam filters · game AI stakes ↑ Four tiers, sorted by potential for harm. The law regulates the stakes, not the technology — the same LLM is minimal-risk writing marketing copy and high-risk ranking loan applications, so classify to the use.
🗺️ How to read this diagram

Read the stack from the bottom up — that's the direction of increasing stakes, marked by the arrow on the right.

  • The green bar at the bottom is Minimal risk (spam filters, game AI) — few or no requirements. The blue bar above it is Limited risk, where the only duty is transparency: tell the user it's AI.
  • The amber bar is High-risk — consequential decisions about people (credit, hiring, medical) that carry the heavy obligations: conformity assessment, documentation, human oversight, and audit. The red bar at the top is Unacceptable: not regulated but outright banned.
  • The bars narrow as they rise because fewer systems sit in each higher tier, and the color shift from green to red is the escalating consequence of being wrong.

In short: your tier is a design constraint — classify honestly on day one and the obligations become a checklist, not a wall.

TierExamplesObligation
Unacceptablesocial scoringbanned
High-riskcredit scoring, hiring, medicalconformity assessment, docs, human oversight
Limitedchatbotstransparency (disclose it's AI)
Minimalspam filtersfew requirements
Know your tier before you buildA credit or hiring model is high-risk — that's documentation, testing, human oversight, and audit obligations, not optional extras. Classifying your system early shapes the whole design. (This is directly relevant to FICO-style use cases.)

Model cards & audit trails expert

A new engineer joins your team and inherits a model that's been in production for a year. They ask the reasonable questions: What is this thing actually supposed to do? What data was it trained on? What does it explicitly not handle? How good is it, and for whom? If the only answers live in the head of someone who left the company, you don't have a model — you have a liability with an API. This is the everyday failure a model card prevents: undocumented systems that no one can safely change, audit, or defend.

A model card is the equivalent of the nutrition label on a food package, or the datasheet that ships with an electronic component. A resistor's datasheet tells you its resistance, its tolerance, and the voltage beyond which it burns out — the honest operating envelope. A model card does the same for an AI system: its intended use, its out-of-scope uses, the data it learned from (and the gaps in that data), how it scored in evaluation, how it performed per segment for fairness, the known risks, and — crucially — a named human owner. The format is deliberately short and boring; the value isn't in the prose, it's in forcing someone to write down the answers before shipping, where the empty fields expose the real gaps.

But a card describes intentions, and intentions aren't proof. That's the second half of this pairing: the audit trail. Where the model card says "here's what this system is supposed to do," the audit trail is the flight recorder that logs what it actually did — every prompt in, every response out, every decision, timestamped and retained. Why you need both is the key insight: the card lets you reason about the system in advance; the trail lets you reconstruct a specific incident afterward. When that refund-approval goes wrong from the opening story, the card tells the reviewer "this was never meant to auto-approve" and the trail proves exactly which input triggered which output at 3:47pm. One without the other leaves you half-blind. The common mistake is logging everything into an ordinary mutable database and calling it an audit trail — but if anyone (including an attacker or a panicked engineer) can quietly edit a past entry, it proves nothing. That's why real audit trails are append-only and often tamper-evident, a property you'll build with hash-chaining in the practice ladder below.

A model card documents what a model is for, its data, its limits, and its evaluations — the artifact that makes a system reviewable. Pair it with an audit trail (every prompt/response logged, from W14) so decisions are traceable after the fact.

the card reasons FORWARD (before); the trail reconstructs BACKWARD (after) Model card intended & out-of-scope use training data + known gaps eval + per-segment fairness risks, mitigations, owner → reason about it in advance Audit trail (append-only) prompt, response, decision timestamp · retained hash-chained → tamper-evident → reconstruct one incident after the fact both together = accountable need BOTH Card = intentions; trail = proof. The model card lets you reason about a system before it ships; the append-only audit trail lets you reconstruct exactly what happened afterward — one without the other leaves you half-blind.
🗺️ How to read this diagram

Read the two boxes side by side — left is written before launch, right is written continuously as the system runs — then follow both arrows down to the shared payoff.

  • The left blue box is the model card: intended and out-of-scope use, training data and its gaps, evaluation with per-segment fairness, and a named owner. It captures intentions, so you can reason about the system in advance.
  • The right purple box is the audit trail: every prompt, response, and decision, timestamped and retained. It's append-only and hash-chained so it's tamper-evident — that's what lets it reconstruct a specific incident afterward.
  • Both arrows converge on the green bar: you need both. The card tells a reviewer "this was never meant to do that"; the trail proves exactly which input caused which output.

In short: the card reasons forward, the trail reconstructs backward — accountability needs the pair.

Example code for learning — review, test, and adapt it before running against real or production systems. Commands can create, change, or delete resources. See the Terms & Disclaimer.
Lab RT5.1 · A model card skeleton
MODEL_CARD.md# MODEL_CARD.md
## Model: support-triage-classifier v3
- **Intended use:** classify inbound support tickets by severity. NOT for
  automated account actions.
- **Out-of-scope:** legal/medical advice; any irreversible action without review.
- **Training data:** 12k internal tickets (2023-24), PII-scrubbed. Known gap:
  under-represents enterprise-tier tickets.
- **Evaluation:** accuracy 0.91 overall; see fairness section for per-segment.
- **Fairness:** measured across ticket language + region; max gap 3.2% (below
  our 5% threshold). Re-audited each release.
- **Risks & mitigations:** indirect injection via ticket body -> input guardrail
  + isolation (RT4). Human review for severity=critical.
- **Owner / contact:** platform-safety@company; last review 2026-09.
▶ How this works

A model card is a short document that says what an AI system is for, what data it used, its limits, and how it's evaluated — the artifact that makes a system reviewable and accountable. This is a filled-in skeleton you can copy for any project. It's plain Markdown, not code; the ## and - just format headings and bullets.

  1. Intended use / Out-of-scope — states exactly what the model should do (triage tickets by severity) and, just as importantly, what it must not do (no automated account actions, no legal/medical advice). Drawing the boundary is half the safety.
  2. Training data — where the data came from, that PII was scrubbed, and a known gap (under-represents enterprise tickets). Honest limitations are a feature of a good card, not a weakness.
  3. Evaluation / Fairness — an overall accuracy number plus a per-segment fairness check with a stated threshold (max gap 3.2%, below the 5% limit), re-run every release. Aggregate scores can hide that a model fails one group.
  4. Risks & mitigations / Owner — names each real risk (indirect injection via the ticket body) and the exact defense from RT4 (input guardrail + isolation), plus a named owner and review date so someone is accountable.

Try this: Write one of these for a course project before you ship it. If any line is hard to fill in (What's out of scope? Who owns it? What's the fairness gap?), that's a gap in the project, not just the doc.

Bias & fairness auditing expert

Here is the trap that catches good teams. Your model reports 91% accuracy, the dashboard is green, everyone celebrates, and you ship. Six months later a journalist shows that it approves 70% of applications from one group and 35% from another. Both facts are true at once: the aggregate looked fine because the large, well-served group drowned out the small, badly-served one in the average. A single headline number is a blender — it purées every group into one smooth score and hides exactly the disparity that gets you sued. Bias auditing is the discipline of refusing to be fooled by that average.

The core move is simple and you already have the instinct for it: don't ask "how well does it work?" — ask "how well does it work for each group?" Break your evaluation data into segments (by language, region, or protected-attribute proxies) and compute the metric separately for each. It's the same reason a doctor checks blood pressure in both arms rather than averaging them: the average can be normal while one side is dangerous. A model that's excellent overall but consistently worse for one demographic isn't "mostly fine" — it's discriminatory, and increasingly, illegally so.

To turn that instinct into a defensible number, fairness work leans on standard, court-tested metrics rather than gut feeling. The classic one is the four-fifths rule (also called the 80% rule), borrowed from decades of US employment-discrimination law: take the group the model favors most as the benchmark, and if any other group's selection rate falls below 80% of that benchmark, you have a disparate impact flag worth investigating. It's not a verdict — a sub-0.8 ratio can have a legitimate explanation — but it's a defensible tripwire that says "stop and look here," which you'll implement in the practice ladder. The essential discipline, and the mistake teams make, is treating this as a launch-day formality run once. Data drifts, populations shift, and a model that was fair at launch can drift unfair. So you set a threshold, measure it every release, and record the result in the model card — turning fairness from a one-time hope into a monitored, documented property.

Measure outcomes across segments (language, region, demographic proxies) — an aggregate metric can hide that a model works well for one group and poorly for another. Set a fairness threshold, measure every release, and record it in the model card.

one green number hides the gap; split by group and apply the four-fifths rule Aggregate accuracy 0.91 ✓ looks fine split Group A rate 0.66 Group B rate 0.33 reference = most-favored rate (A = 0.66) four-fifths line = 0.80 × reference B/A = 0.50 < 0.8 DISPARATE IMPACT flag The average is a blender. A 0.91 aggregate can look green while one group is served far worse; measuring the selection rate per group and applying the four-fifths (80%) rule surfaces the disparity the average hid.
🗺️ How to read this diagram

Start at the green box on the left, follow the "split" arrow rightward, then read the two group rows and the verdict on the far right.

  • The green box is the tempting single number — 0.91 accuracy, dashboard green. On its own it says nothing about who the model serves badly.
  • The two white rows are the same evaluation split by group: Group A's selection rate is 0.66, Group B's is 0.33. The dashed line marks the four-fifths rule — take the most-favored rate (A = 0.66) as the reference and draw the tripwire at 80% of it.
  • The red row and red box are the payoff: B's ratio against A is 0.50, below 0.8, so the four-fifths rule raises a disparate-impact flag — a defensible signal to investigate and document, not an automatic verdict.

In short: don't ask "how well does it work?" — ask "for each group?" and check the 80% line every release.

The AI incident runbook expert

It's 2am and your agent is doing something it shouldn't. Maybe a prompt injection has it leaking other customers' data; maybe a model update quietly regressed and it's giving dangerous advice. The pager goes off. In that moment, the worst possible thing is a room full of smart people improvising — arguing about whether to pull the whole service down, hunting for who has the access to do it, no one writing anything down. Panic doesn't scale, and improvisation under pressure is how a contained problem becomes a headline. The fix is the same one hospitals, fire departments, and airlines figured out long ago: when the stakes are high and adrenaline is running, you don't rely on judgment — you run a checklist.

An incident runbook is that checklist for the day your AI system misbehaves. It's written calmly, in advance, precisely so that the frightened 2am version of you doesn't have to think — just execute. The value isn't the document; it's that the hard decisions (What's our threshold for pulling the plug? Who's allowed to? What do we owe customers?) were made when everyone was rested and rational, not mid-crisis. The steps below map onto the same phases every mature incident process uses, adapted for AI:

Two ideas make this more than a to-do list. First, containment comes before understanding — the instinct to "just figure out what's wrong first" is exactly backwards; you hit the kill switch while the damage clock is still running, then investigate the stopped system safely. Second, the loop closes: every incident makes the runbook and the model card better, so your governance compounds instead of decaying. The mistake that undoes all of this is declaring victory too early — "we patched it, incident over" — without eradicating the root cause or writing down what happened. That's why the exercises below gate an incident from closing until Detect, Contain, Eradicate, and Document are all genuinely done.

contain BEFORE you understand; the Review step loops back to improve the runbook 1 · Detect alerts (W14) 2 · Contain kill switch 3 · Assess audit trail 4 · Remediate fix + test 5 · Review blameless ↑ stop the bleeding first Review feeds lessons back into the model card + runbook — governance compounds Five steps, and Contain comes before Assess. You hit the kill switch while the damage clock still runs, then investigate the stopped system — and the dashed loop from Review back to Detect is why every incident leaves the runbook and model card stronger.
🗺️ How to read this diagram

Follow the solid arrows left to right through the five steps, then note the dashed arrow that loops from the last box back to the first.

  • The five boxes are the phases in order: Detect (alerts from W14/O4), Contain (the red box — the pre-built kill switch), Assess (use the audit trail), Remediate (fix the failed layer plus a regression test), and Review (a blameless postmortem).
  • Notice that the red Contain box sits before the blue Assess box: the "↑ stop the bleeding first" note marks the counterintuitive rule — you contain before you understand, so the damage stops while you investigate safely.
  • The dashed muted arrow from Review back to Detect is the closing loop: each incident's lessons feed the model card and the runbook, so governance compounds instead of decaying.

In short: contain first, assess second, and always close the loop — an incident isn't over until it has made the system better.

When something goes wrong

  1. Detect: monitoring/alerts (W14, O4) flag anomalous behavior or a breach.
  2. Contain: hit the kill switch — disable the feature/agent alias/tool (W14).
  3. Assess: what happened, blast radius, who/what was affected (audit trail).
  4. Remediate: fix the layer that failed (RT4); add a regression test (RT3).
  5. Review: blameless postmortem + update the model card and runbook.

Exercise RT5.1 — Govern a project

Context: Governing a real project ties the whole track together: you classify its tier, document it, and plan for the day it misbehaves — including naming the kill switch before you need it.

Your task: For a course project, classify its EU AI Act tier, write a model card, and draft a one-page incident runbook naming the kill switch — and if it's high-risk, list the extra obligations you'd owe.

Requirements:

  • Classify the project into an EU AI Act tier with justification
  • Write a model card covering purpose, data, limits, and evaluations
  • Draft a one-page incident runbook that explicitly names the kill switch
  • If the project is high-risk, list the extra obligations (bias audit, human oversight, documentation, audit trail)

💡 Hint: Naming the kill switch concretely — the exact toggle or action that stops the system — is what separates a real runbook from a wish.

🪜 Practice ladder beginner → industry

Six graded exercises, easy to real-world. Try each before opening its solution.

Exercise 1 · Classify a system into an EU AI Act tierBeginner

Context: Under the EU AI Act, a system's risk tier sets its obligations — and classifying early shapes the whole design. Credit scoring and hiring are high-risk; a chatbot is limited; a spam filter is minimal; social scoring is banned.

Your task: Write risk_tier(use_case) that maps a use case to unacceptable | high | limited | minimal using the lesson's examples.

Requirements:

  • Map social scoring → unacceptable, credit scoring / hiring / medical → high, chatbot → limited, spam filter → minimal
  • Default unknown use cases cautiously (e.g. to limited)
  • Return both the tier and its obligations
  • Obligations reflect the tier: high → conformity assessment, docs, human oversight; limited → transparency (disclose it's AI); minimal → few requirements; unacceptable → banned
  • Note that high-risk (credit/hiring) makes documentation, testing, oversight, and audit requirements, not extras — directly relevant to FICO-style use cases

💡 Hint: Two lookup tables — use case to tier, tier to obligations — keep the policy explicit and easy to audit.

Show solution

Classifying early shapes the whole design:

TIERS = {
    "social_scoring": "unacceptable",
    "credit_scoring": "high", "hiring": "high", "medical": "high",
    "chatbot": "limited",
    "spam_filter": "minimal",
}
OBLIGATION = {
    "unacceptable": "banned",
    "high": "conformity assessment, docs, human oversight",
    "limited": "transparency (disclose it's AI)",
    "minimal": "few requirements",
}

def risk_tier(use_case):
    tier = TIERS.get(use_case, "limited")   # default cautiously
    return tier, OBLIGATION[tier]

print(risk_tier("credit_scoring"))  # ('high', 'conformity assessment, docs, human oversight')
print(risk_tier("chatbot"))         # ('limited', "transparency (disclose it's AI)")

A credit or hiring model being high-risk means documentation, testing, human oversight and audit are requirements, not extras — directly relevant to FICO-style use cases.

Exercise 2 · Write a model card as dataIntermediate

Context: A model card documents purpose, data, limits, and evals so a system is reviewable. Encoding it as validated data means an incomplete card can fail CI, just like a missing test.

Your task: Define a model_card dict with the required fields and a validator that fails if any required section is missing or empty.

Requirements:

  • Include required fields: name, intended use, out-of-scope, training data, limitations, evaluations, and owner
  • Populate a realistic example card with concrete values
  • validate(card) collects any required key that is missing or empty
  • Raise an error naming the missing sections, or return valid when complete
  • Make the point that the card as validated data lets an incomplete card fail CI

💡 Hint: The validator is a list comprehension over the required keys checking for falsy values; the discipline is in treating documentation like a test.

Show solution

The card is the artifact that makes a system auditable:

REQUIRED = ["name", "intended_use", "out_of_scope", "training_data",
            "limitations", "evaluations", "owner"]

card = {
    "name": "refund-classifier-v3",
    "intended_use": "Triage refund requests for human agents.",
    "out_of_scope": "Auto-approving refunds without review.",
    "training_data": "12k anonymized 2024 tickets; English only.",
    "limitations": "Lower recall on non-English; no PII redaction upstream.",
    "evaluations": {"accuracy": 0.91, "false_approve_rate": 0.02},
    "owner": "trust-and-safety@acme",
}

def validate(card):
    missing = [k for k in REQUIRED if not card.get(k)]
    if missing:
        raise ValueError(f"model card incomplete: {missing}")
    return "valid"

print(validate(card))   # valid

Encoding the card as validated data means an incomplete card can fail CI, just like a missing test.

Exercise 3 · An append-only audit trailAdvanced

Context: Audit trails make a system reviewable after the fact, and hash-chaining gives cheap tamper-evidence without a database: each entry chains a hash of the previous one, so any edit breaks the chain from that point forward.

Your task: Build an append-only log where each entry chains a hash of the previous one, and show verification passing, then failing after a forged edit.

Requirements:

  • Each entry stores its event plus a hash computed from the previous hash and the event contents
  • The first entry chains from a fixed genesis value
  • Hash deterministically (e.g. sha256 over the previous hash plus a canonical JSON of the event)
  • verify() recomputes the chain and returns True when intact
  • Demonstrate verification returning True, then False after forging an earlier entry
  • Note that any edit breaks the chain from that point on, proving the recorded decisions are the ones actually made

💡 Hint: Serialize each event with sorted keys before hashing so the hash is stable, and verify by walking the chain forward from genesis recomputing each link.

Show solution

Hash-chaining gives cheap tamper-evidence without a database:

import hashlib, json

def _h(prev, entry):
    return hashlib.sha256((prev + json.dumps(entry, sort_keys=True)).encode()).hexdigest()

class AuditLog:
    def __init__(self):
        self.entries = []
    def add(self, event):
        prev = self.entries[-1]["hash"] if self.entries else "GENESIS"
        self.entries.append({"event": event, "hash": _h(prev, event)})
    def verify(self):
        prev = "GENESIS"
        for e in self.entries:
            if e["hash"] != _h(prev, e["event"]):
                return False
            prev = e["hash"]
        return True

log = AuditLog()
log.add({"action": "decision", "id": 1, "outcome": "approve"})
log.add({"action": "decision", "id": 2, "outcome": "deny"})
print(log.verify())                       # True
log.entries[0]["event"]["outcome"] = "deny"   # forge
print(log.verify())                       # False

Any edit breaks the chain from that point forward, so the log can prove the recorded decisions are the ones actually made.

Exercise 4 · Bias & fairness audit (offline metrics)Expert

Context: Fairness auditing uses standard, defensible metrics on your own eval data. The four-fifths rule — any group's selection rate below 80% of the most-favored group's — is the classic disparate-impact flag.

Your task: Given labeled outcomes per group, compute the selection rate per group and apply the four-fifths (80%) rule disparate-impact check, flagging groups below the threshold.

Requirements:

  • selection_rates(rows) computes approved/total per group from (group, approved) rows
  • Take the most-favored group's rate as the reference
  • Compute each group's ratio against that reference
  • Flag any group whose ratio is below 0.8 as DISPARATE IMPACT, others as OK
  • Demonstrate a group falling below the threshold being flagged
  • Note that a sub-0.8 ratio is a signal to investigate, mitigate, and document in the model card

💡 Hint: Two passes: aggregate rates per group, then divide every rate by the maximum rate and compare against 0.8.

Show solution

Standard, defensible fairness metrics on your own eval data:

def selection_rates(rows):
    # rows: list of (group, approved:bool)
    agg = {}
    for g, ok in rows:
        n, k = agg.get(g, (0, 0))
        agg[g] = (n + 1, k + int(ok))
    return {g: k / n for g, (n, k) in agg.items()}

def four_fifths(rates):
    ref = max(rates.values())        # most-favored group
    flags = {g: r / ref for g, r in rates.items()}
    return {g: (ratio, "OK" if ratio >= 0.8 else "DISPARATE IMPACT")
            for g, ratio in flags.items()}

rows = [("A", True), ("A", True), ("A", False),
        ("B", True), ("B", False), ("B", False)]
rates = selection_rates(rows)
print(rates)                 # {'A': 0.666..., 'B': 0.333...}
for g, (ratio, verdict) in four_fifths(rates).items():
    print(g, f"{ratio:.2f}", verdict)   # B 0.50 DISPARATE IMPACT

A ratio below 0.8 versus the most-favored group is the classic disparate-impact flag — a signal to investigate, mitigate, and document in the model card.

Exercise 5 · An AI incident runbook (as a checklist)Professional

Context: When a live system misbehaves you need a runbook. Encoding the incident phases as an ordered checklist with a closure gate stops the common failure mode of "we patched it" without eradication or a written record.

Your task: Encode the incident phases as an ordered checklist with a gate that won't let you close an incident until the detect / contain / eradicate / document steps are all done.

Requirements:

  • Define the ordered list of phases (detect, triage, contain, eradicate, recover, document, postmortem)
  • Track completed phases for an incident
  • complete(phase) validates the phase name before recording it
  • can_close() returns whether the required phases are all done and which are missing
  • Require at least detect, contain, eradicate, and document before closure is allowed
  • Demonstrate a close being refused with missing phases, then allowed once they're complete

💡 Hint: A set of completed phases and a required subset is the whole model; can_close is just a set difference against the required phases.

Show solution

A machine-checkable runbook keeps incident response disciplined:

PHASES = ["detect", "triage_severity", "contain", "eradicate",
          "recover", "document", "postmortem"]

class Incident:
    def __init__(self, title):
        self.title = title
        self.done = set()
    def complete(self, phase):
        assert phase in PHASES, f"unknown phase {phase}"
        self.done.add(phase)
    def can_close(self):
        required = {"detect", "contain", "eradicate", "document"}
        missing = required - self.done
        return (not missing), sorted(missing)

inc = Incident("prompt-injection leak in support bot")
for p in ["detect", "triage_severity", "contain"]:
    inc.complete(p)
print(inc.can_close())     # (False, ['document', 'eradicate'])
inc.complete("eradicate"); inc.complete("document")
print(inc.can_close())     # (True, [])

Gating closure on the required phases stops the common failure mode of "we patched it" without eradication or a written record.

Exercise 6 · A pre-deployment governance gateIndustry scenario

Context: One governance gate encodes the org's release policy for high-risk AI: a regulated system can't ship until its tier is classified, the model card validates, a bias audit passed, and an audit log is enabled — enforced by the pipeline, not left to memory.

Your task: Write governance_gate(system) returning pass/fail with the list of unmet obligations, so a regulated system can't ship until every obligation is satisfied.

Requirements:

  • Fail if the tier isn't classified (or is unacceptable) or the model card isn't valid
  • For high-risk systems, additionally require a passed bias audit and configured human oversight
  • Require an enabled audit trail regardless of tier
  • Return a (passed, unmet) pair listing every unmet obligation
  • Demonstrate a ready system passing and a not-ready one failing with its specific gaps
  • Make the point that high-risk systems carry extra blocking obligations so accountability is enforced by the pipeline

💡 Hint: Accumulate unmet obligations into a list and gate on it being empty; the high-risk branch simply adds more required checks.

Show solution

One gate that encodes the org's release policy for high-risk AI:

def governance_gate(system):
    unmet = []
    if system.get("tier") not in {"minimal", "limited", "high"}:
        unmet.append("tier not classified (or unacceptable)")
    if not system.get("model_card_valid"):
        unmet.append("model card incomplete")
    if system.get("tier") == "high":
        if not system.get("bias_audit_passed"):
            unmet.append("bias audit not passed (required for high-risk)")
        if not system.get("human_oversight"):
            unmet.append("human oversight not configured (required for high-risk)")
    if not system.get("audit_log_enabled"):
        unmet.append("audit trail not enabled")
    return (not unmet), unmet

ready = {"tier": "high", "model_card_valid": True, "bias_audit_passed": True,
         "human_oversight": True, "audit_log_enabled": True}
notready = {"tier": "high", "model_card_valid": True, "bias_audit_passed": False,
            "human_oversight": False, "audit_log_enabled": True}
print(governance_gate(ready))     # (True, [])
print(governance_gate(notready))  # (False, ['bias audit...', 'human oversight...'])

High-risk systems carry extra obligations (bias audit, human oversight); the gate makes them blocking, so accountability is enforced by the pipeline, not left to memory.

✓ Checkpoint — you can move on when you can…

  • Explain the governance a live AI system needs.
  • Place a system in the EU AI Act tiers and state its obligations.
  • Write a model card and keep an audit trail.
  • Audit for bias and run an AI incident with a kill switch.

Knowledge check check yourself

✓ Knowledge check

What are the EU AI Act risk tiers described in the lesson, and what obligation does the high-risk tier carry?

Show answer
The tiers are Unacceptable (e.g. social scoring — banned), High-risk (e.g. credit scoring, hiring, medical), Limited (e.g. chatbots — transparency/disclosure that it's AI), and Minimal (e.g. spam filters — few requirements). High-risk systems require a conformity assessment, documentation, human oversight, testing, and audit obligations — not optional extras — so classifying a system early shapes the whole design.
✓ Knowledge check

What is a model card, and what are the five steps of the AI incident runbook the lesson prescribes?

Show answer
A model card is a short document stating a model's intended use and out-of-scope uses, training data and known gaps, evaluation and per-segment fairness results, and risks/mitigations plus a named owner — the artifact that makes a system reviewable, paired with an audit trail of logged prompts/responses. The incident runbook steps are: Detect (monitoring/alerts flag anomalies or a breach), Contain (hit the kill switch to disable the feature/agent/tool), Assess (what happened and the blast radius, using the audit trail), Remediate (fix the failed layer and add a regression test), and Review (a blameless postmortem that updates the model card and runbook).
© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in