What Do EU AI Act Articles 9 Through 15 Require in Your Code? The Definitive Technical Reference

Articles 9 through 15 are the technical backbone of the EU AI Act. They define what high-risk AI systems must do for risk management, data governance, documentation, record-keeping, transparency, human oversight, and robustness. This guide breaks each article into engineering terms with code examples, compliance checks, and a standards crosswalk to ISO 42001 and NIST AI RMF.

Key Takeaways

What Does Article 9 Require for Risk Management?

Article 9 requires that you establish and implement a risk management system covering the entire lifecycle of your high-risk AI system. You must identify and analyze potential harms, implement mitigation measures, and continuously monitor risks as the system operates. The regulation does not mandate a specific methodology but requires that risk management be documented, systematic, and updated throughout the system's lifecycle.

In practice, this means five things in your codebase: threat modeling (identify how the system could cause harm), risk classification (document severity and likelihood for each risk), mitigation strategies (implement controls for risks above your tolerance threshold), monitoring and alerting (detect when risks are materializing in production), and lifecycle updates (rerun risk analysis on new releases, distribution shift, or vulnerabilities).

Code example: risk classification

from air_blackbox import scan_code, risk_level

agent_code = """
from langchain import LLMChain
from some_tool import access_credit_database

class LoanApprovalAgent:
    def approve_loan(self, applicant_data):
        # RISK: This agent has access to credit data
        # Severity: HIGH (financial harm to individuals)
        # Likelihood: MEDIUM (human review exists but intermittent)
        credit_score = access_credit_database(applicant_data['id'])

        # Guard rail: log every decision for audit
        self.logger.info(f"Loan decision: {applicant_data['name']}")

        # Mitigation: require human approval for borderline cases
        if 600 < credit_score < 700:
            return {"decision": "HOLD", "reason": "Requires human review"}

        return {"decision": "APPROVED" if credit_score > 700 else "DENIED"}
"""

# Scan returns findings aligned with Article 9
results = scan_code(agent_code)
for finding in results.article_9_findings:
    print(f"Risk: {finding.description}")
    print(f"Severity: {finding.severity}")
    print(f"Mitigation: {finding.mitigation_found}")

The pattern: identify the risk (high-stakes financial decision), classify it (HIGH severity, MEDIUM likelihood), implement a guard rail (logging), and a mitigation (human review trigger for borderline cases).

What Does Article 10 Require for Data Governance?

Article 10 requires that training data, validation data, and test data for high-risk AI systems meet strict quality standards. You must document where your data came from, check it for bias and discrimination, ensure it is representative of the populations your system will serve, and continue assessing data quality in production. If real-world data diverges significantly from training distribution, your risk assessments need updating.

The concrete technical obligations are: data sourcing documentation (provenance, collection methods, exclusions), bias testing (per-group performance on protected characteristics), data quality metrics (label agreement, missing values, freshness), representativeness assessment (compare training distribution to deployment population), and drift monitoring (statistical tests comparing live data to training data).

Code example: data governance and drift detection

import pandas as pd
from sklearn.metrics import confusion_matrix
import hashlib

class DataGovernance:
    def __init__(self):
        self.data_lineage = {}
        self.bias_report = {}

    def document_dataset(self, df, source, collection_date, annotators=None):
        """Record where data came from and how it was created."""
        data_hash = hashlib.sha256(
            pd.util.hash_pandas_object(df, index=True).values
        ).hexdigest()

        self.data_lineage[data_hash] = {
            "source": source,
            "collection_date": collection_date,
            "row_count": len(df),
            "missing_values": df.isnull().sum().to_dict(),
            "annotators": annotators,
        }

    def measure_fairness(self, y_true, y_pred, protected_attr):
        """Measure performance disparity across protected groups."""
        results = {}
        for group in protected_attr.unique():
            mask = protected_attr == group
            cm = confusion_matrix(y_true[mask], y_pred[mask])
            fpr = cm[0, 1] / (cm[0, 0] + cm[0, 1])
            results[group] = {"false_positive_rate": fpr}
        self.bias_report = results
        return results

    def check_drift(self, current_data, training_data, threshold=0.1):
        """Detect when live data diverges from training distribution."""
        from scipy.stats import ks_2samp
        for col in current_data.columns:
            stat, p_value = ks_2samp(current_data[col], training_data[col])
            if p_value < threshold:
                print(f"DRIFT DETECTED: {col} p-value={p_value}")

governance = DataGovernance()
governance.document_dataset(
    train_df,
    source="Company HR records Jan-Dec 2025",
    collection_date="2025-12-31",
    annotators=["[email protected]", "[email protected]"]
)

What Does Article 11 Require for Technical Documentation?

Article 11 requires comprehensive technical documentation sufficient for regulators, conformity assessors, and your own teams to understand how the system works, what assumptions it makes, and what its limitations are. The documentation must cover the system's purpose, algorithm architecture, training process, performance metrics, known limitations, and risk mitigations. This is the model card, data sheet, and architecture document combined.

In engineering terms, you need four documents: architecture and algorithm documentation (model type, structure, mathematical formulation), training process documentation (hyperparameters, optimization, convergence criteria), evaluation and performance documentation (accuracy, fairness metrics, per-group breakdowns), and limitations and failure modes (conditions where the system performs poorly).

Code example: automated documentation generation

import json
from datetime import datetime

class ModelCard:
    def __init__(self, model_name, version):
        self.name = model_name
        self.version = version
        self.created_date = datetime.now().isoformat()

    def document_architecture(self, model_object):
        return {
            "model_type": type(model_object).__name__,
            "parameters": model_object.count_params()
                          if hasattr(model_object, 'count_params') else "N/A",
            "layers": str(model_object) if hasattr(model_object, '__str__')
                     else "See architecture diagram",
        }

    def document_training(self, training_config):
        return {
            "dataset": training_config.get("data_source"),
            "training_steps": training_config.get("epochs"),
            "batch_size": training_config.get("batch_size"),
            "optimizer": training_config.get("optimizer"),
            "learning_rate": training_config.get("learning_rate"),
            "loss_function": training_config.get("loss"),
        }

    def document_evaluation(self, metrics_dict):
        return {
            "overall_accuracy": metrics_dict.get("accuracy"),
            "precision": metrics_dict.get("precision"),
            "recall": metrics_dict.get("recall"),
            "fairness_gap": metrics_dict.get("max_fairness_disparity"),
            "robustness_score": metrics_dict.get("adversarial_accuracy"),
        }

    def document_limitations(self, known_issues):
        return {
            "performance_by_group": known_issues.get("disparities"),
            "failure_modes": known_issues.get("edge_cases"),
            "data_requirements": known_issues.get("distribution_assumptions"),
        }

    def to_json(self):
        return json.dumps(self.__dict__, indent=2, default=str)

# Generate and save for Article 11 compliance
card = ModelCard("BiasDetector", "1.0.0")
card.architecture = card.document_architecture(model)
card.training = card.document_training(training_cfg)
card.evaluation = card.document_evaluation(test_metrics)
card.limitations = card.document_limitations(known_issues)
with open("technical_documentation.json", "w") as f:
    f.write(card.to_json())

What Does Article 12 Require for Record-Keeping?

Article 12 requires that high-risk AI systems automatically keep tamper-proof records of their operation, sufficient to demonstrate compliance and enable auditing. Records must be retained for at least three years. Critically, these records must be tamper-evident: if a regulator requests logs, they must have confidence the logs are genuine and unchanged. This is where HMAC-SHA256 cryptographic chains enter the picture.

Three technical capabilities are required: comprehensive logging (every input, prediction, override, and error with metadata), tamper-evidence (HMAC-SHA256 chains where each record signs the previous one, making modification detectable), and long-term retention (immutable storage for at least three years).

Code example: HMAC-SHA256 tamper-proof audit chain

import hmac
import hashlib
import json
from datetime import datetime
import uuid

class TamperProofAuditLog:
    """Article 12: Tamper-proof logging with HMAC-SHA256 chains."""

    def __init__(self, secret_key):
        self.secret_key = secret_key.encode()
        self.chain = []
        self.last_signature = None

    def log_decision(self, event_type, model_name, input_data,
                     output, user_id, confidence=None):
        entry = {
            "id": str(uuid.uuid4()),
            "timestamp": datetime.utcnow().isoformat(),
            "event_type": event_type,
            "model_version": model_name,
            "user_id": user_id,
            "input_hash": hashlib.sha256(
                json.dumps(input_data, sort_keys=True).encode()
            ).hexdigest(),
            "output": output,
            "confidence": confidence,
            "previous_signature": self.last_signature,
        }

        entry_string = json.dumps(entry, sort_keys=True)
        signature = hmac.new(
            self.secret_key, entry_string.encode(), hashlib.sha256
        ).hexdigest()

        entry["signature"] = signature
        self.chain.append(entry)
        self.last_signature = signature
        return entry

    def verify_chain_integrity(self):
        """Detect if any log entry has been tampered with."""
        for i, entry in enumerate(self.chain):
            stored_signature = entry.pop("signature")
            entry_string = json.dumps(entry, sort_keys=True)
            expected = hmac.new(
                self.secret_key, entry_string.encode(), hashlib.sha256
            ).hexdigest()

            if stored_signature != expected:
                return False, f"Entry {i} has been modified"

            if i > 0 and entry["previous_signature"] != self.chain[i-1]["signature"]:
                return False, f"Entry {i} is not linked correctly"

            entry["signature"] = stored_signature
        return True, "Chain is intact"

# Usage
logger = TamperProofAuditLog(secret_key="your-secret-from-kms")
logger.log_decision(
    event_type="loan_approval_decision",
    model_name="CreditRisk-v2.1",
    input_data={"credit_score": 750, "income": 80000},
    output="APPROVED", user_id="agent-001", confidence=0.92
)
is_valid, message = logger.verify_chain_integrity()
print(f"Audit log valid: {is_valid} - {message}")

Why standard logs fail Article 12: Datadog, Splunk, and CloudWatch lack tamper-evidence, completeness detection, and structured auditability. Anyone with write access can alter records. HMAC chains make modification detectable. See our deep dive: Integrity Is Not Completeness.

What Does Article 14 Require for Human Oversight?

Article 14 requires that high-risk AI systems be designed so humans can understand what the AI recommends, why it recommends it, and can override or reject the recommendation. The human must have the authority, the information, and the technical capability to intervene at any point. This breaks down into five technical obligations: explainability, confidence thresholds that trigger review, override mechanisms, monitoring of override rates, and access controls for reviewers.

Code example: human review gate

from enum import Enum
from datetime import datetime
import logging

class DecisionGate(Enum):
    APPROVED = "approved"
    HELD_FOR_REVIEW = "held_for_review"
    REJECTED = "rejected"

class HumanOversightGate:
    """Article 14: Require human review for high-risk decisions."""

    def __init__(self, confidence_threshold=0.85):
        self.confidence_threshold = confidence_threshold
        self.review_queue = []
        self.override_log = []
        self.logger = logging.getLogger(__name__)

    def evaluate_decision(self, model_output, confidence,
                         feature_importance, case_id):
        if confidence < self.confidence_threshold:
            return self.require_review(
                case_id, model_output, confidence,
                reason=f"Confidence {confidence} below {self.confidence_threshold}",
                explanation=feature_importance
            )
        return DecisionGate.APPROVED

    def require_review(self, case_id, recommendation, confidence,
                      reason, explanation):
        review_item = {
            "case_id": case_id,
            "recommendation": recommendation,
            "confidence": confidence,
            "reason_for_review": reason,
            "explanation": explanation,
            "created_at": datetime.utcnow().isoformat(),
            "reviewed": False,
        }
        self.review_queue.append(review_item)
        self.logger.info(f"Case {case_id} requires human review: {reason}")
        return DecisionGate.HELD_FOR_REVIEW

    def human_review(self, case_id, reviewer_id, final_decision, notes):
        """Human makes the final decision. AI does not override."""
        review_item = next(
            (item for item in self.review_queue
             if item["case_id"] == case_id), None
        )
        if not review_item:
            raise ValueError(f"Case {case_id} not found")

        review_item["reviewed"] = True
        review_item["reviewer_id"] = reviewer_id
        review_item["final_decision"] = final_decision
        review_item["reviewed_at"] = datetime.utcnow().isoformat()

        if final_decision != review_item["recommendation"]:
            self.override_log.append({
                "case_id": case_id,
                "ai_recommendation": review_item["recommendation"],
                "human_decision": final_decision,
                "reviewer_id": reviewer_id,
            })
        return final_decision

    def get_override_rate(self):
        total = len([i for i in self.review_queue if i["reviewed"]])
        overrides = len(self.override_log)
        return (overrides / total * 100) if total > 0 else 0

# Usage
gate = HumanOversightGate(confidence_threshold=0.80)
status = gate.evaluate_decision(
    model_output="DENIED", confidence=0.72,
    feature_importance=importance, case_id="loan-12345"
)
if status == DecisionGate.HELD_FOR_REVIEW:
    gate.human_review("loan-12345", "[email protected]", "APPROVED",
                      "Strong credit history despite low model score")

What Does Article 15 Require for Accuracy and Robustness?

Article 15 requires high-risk AI systems to achieve and maintain appropriate accuracy, robustness, and cybersecurity. Your AI must work correctly under normal conditions, fail gracefully under adversarial conditions, and be protected against attack and misuse. The regulation does not specify exact accuracy thresholds (these depend on the use case) but requires you to measure accuracy, document it, test robustness, and implement security controls including adversarial testing and prompt injection defense.

Three technical areas: accuracy and performance (per-group metrics with a performance floor below which the system should not operate), robustness testing (adversarial inputs, distribution shift, missing data, boundary conditions), and cybersecurity (prompt injection defense, input validation, secure access controls).

Code example: robustness and injection testing

import numpy as np
from air_blackbox import check_prompt_injection

class RobustnessTest:
    """Article 15: Test accuracy, robustness, and cybersecurity."""

    def __init__(self, model, X_test, y_test):
        self.model = model
        self.X_test = X_test
        self.y_test = y_test
        self.results = {}

    def test_accuracy(self):
        predictions = self.model.predict(self.X_test)
        accuracy = (predictions == self.y_test).mean()
        self.results["accuracy"] = accuracy
        return accuracy

    def test_adversarial_robustness(self, perturbation=0.1):
        X_perturbed = self.X_test + np.random.normal(
            0, perturbation, self.X_test.shape)
        predictions = self.model.predict(X_perturbed)
        adv_accuracy = (predictions == self.y_test).mean()
        drop = self.results["accuracy"] - adv_accuracy
        self.results["adversarial_accuracy"] = adv_accuracy
        self.results["robustness_drop"] = drop
        if drop > 0.15:
            print(f"WARNING: Accuracy dropped {drop*100:.1f}% under perturbation")
        return adv_accuracy

    def test_edge_cases(self):
        cases = {
            "all_zeros": np.zeros_like(self.X_test[:1]),
            "all_ones": np.ones_like(self.X_test[:1]),
            "max_values": np.max(self.X_test) * np.ones_like(self.X_test[:1]),
        }
        for name, inp in cases.items():
            try:
                self.model.predict(inp)
                self.results[f"edge_{name}"] = "handled"
            except Exception as e:
                self.results[f"edge_{name}"] = f"error: {e}"

# Run tests
test = RobustnessTest(model, X_test, y_test)
print(f"Baseline: {test.test_accuracy():.2%}")
print(f"Adversarial: {test.test_adversarial_robustness():.2%}")
test.test_edge_cases()

How Do Articles 9 Through 15 Work Together?

Articles 9-15 are not independent requirements - they form a connected governance framework where each article feeds the next. Article 9 risk analysis identifies what can go wrong. Articles 10 and 11 ensure the system is built safely with trusted data and thorough documentation. Article 12 adds accountability with tamper-evident logging. Article 14 puts humans in control. Article 15 ensures quality and security. When a regulator audits your system, they walk through all six in sequence.

ArticleResponsibilityOutcome
Article 9Identify and manage risksRisk register with mitigation strategies
Article 10Ensure training data is trustworthyData sheet with bias testing and representativeness
Article 11Document the system comprehensivelyTechnical documentation and model card
Article 12Keep tamper-proof recordsHMAC-SHA256 audit trail, 3-year retention
Article 14Enable human oversightReview gates, override mechanisms, monitoring
Article 15Ensure accuracy, robustness, securityPerformance metrics, adversarial testing, injection defense

How Does the EU AI Act Map to ISO 42001 and NIST AI RMF?

If you operate internationally or in regulated sectors, you may need to comply with ISO 42001 (AI Management System) or NIST AI Risk Management Framework alongside the EU AI Act. The three frameworks align closely. Implementing Articles 9-15 gets you most of the way to all three frameworks simultaneously - the documents you create (risk register, data sheet, technical documentation, audit logs) become artifacts for all three.

EU AI Act ArticleISO 42001 SectionNIST AI RMF Function
Article 9: Risk ManagementClause 8.2: Risk managementGOVERN: Risk management framework
Article 10: Data GovernanceClause 8.4: Data managementMEASURE: Data quality assessment
Article 11: DocumentationClause 8.3: Model managementMEASURE: Model documentation
Article 12: Audit LogsClause 8.5: MonitoringGOVERN: Audit and accountability
Article 14: Human OversightClause 8.6: Human oversightGOVERN: Human review mechanisms
Article 15: RobustnessClause 8.7: Performance evaluationMEASURE: Performance and robustness

AIR Blackbox maps scan findings to all three frameworks from a single command: air-blackbox comply --scan . -v outputs EU AI Act article, ISO 42001 clause, and NIST AI RMF function for every finding.

How Do You Scan Your Code for Articles 9-15 Compliance?

Install AIR Blackbox and run a compliance scan with two commands. The scanner checks all seven articles and gives you a detailed report of what passes, what warns, and what fails - with specific fix hints and code locations for every finding.

pip install air-blackbox
air-blackbox comply --scan . -v

After implementing fixes, re-scan and iterate. Add the scan to your CI/CD pipeline to maintain compliance as your code evolves:

# Fail the build if critical findings are present
air-blackbox comply --scan . --fail-on FAIL

Scan your project against Articles 9-15

Find compliance gaps before an auditor does. One command, all seven articles.

pip install air-blackbox
air-blackbox comply --scan . -v

View on GitHub · PyPI · Compliance Mapping

Related guides

Frequently Asked Questions

What do EU AI Act Articles 9 through 15 require? +

Articles 9-15 define the technical obligations for high-risk AI systems: risk management (9), data governance (10), technical documentation (11), tamper-evident record-keeping (12), transparency (13), human oversight (14), and accuracy, robustness, and cybersecurity (15). Together they form a complete governance framework enforced from August 2, 2026.

What is Article 12 record-keeping for AI systems? +

Article 12 requires that high-risk AI systems automatically keep tamper-proof records of their operation for at least three years. HMAC-SHA256 audit chains satisfy this by creating cryptographic links between records so that any modification becomes immediately detectable.

How does the EU AI Act map to ISO 42001 and NIST AI RMF? +

The three frameworks align closely. Article 9 maps to ISO 42001 Clause 8.2 and NIST GOVERN. Article 10 maps to Clause 8.4 and NIST MEASURE. Article 12 maps to Clause 8.5 and NIST GOVERN. Implementing Articles 9-15 gets you most of the way to all three frameworks simultaneously.

What tools can check for Articles 9-15 compliance? +

AIR Blackbox is an open-source scanner that checks Python AI projects against 51+ requirements across Articles 9 through 15. Install with pip install air-blackbox and run air-blackbox comply --scan . -v. It maps findings to EU AI Act, ISO 42001, NIST AI RMF, and Colorado SB 24-205.

What is Article 14 human oversight for AI systems? +

Article 14 requires that high-risk AI systems enable human oversight. Humans must understand what the AI recommends and why, override or reject recommendations, and have the authority and technical capability to intervene. This includes explainability, confidence thresholds, override mechanisms, and monitoring of override rates.

Jason Shotwell

Creator of AIR Blackbox

Builder of open-source AI governance tooling. AIR Blackbox has 14,000+ PyPI downloads and has been validated by deepset (Haystack) and Ludwig maintainers. Jason builds compliance infrastructure for teams shipping AI agents into production and designs the cryptographic audit chain specification (SPEC.md).

Last updated: April 17, 2026. This article is reviewed and updated monthly to reflect the latest regulatory developments and scanner capabilities.