Skip to content
AIAssuranceLabs
Menu

AI risk assessment under Article 9: building the risk management file

This guide builds the risk management file that Art. 9(1) requires: a hazard register with a scope statement per risk, an acceptance criterion per hazard recorded before testing, measures in the Art. 9(5) order, and a testing plan with a prior metric and threshold per risk. The file is reviewed under PR-17-QMS v1.0, its tests run under PR-15-ROB v1.0, and its record set follows prEN 18228Enquiry, at enquiry stage. The reader ends with a register, a plan and a check that fails on any risk lacking a measure, a residual judgement or a prior threshold.

What the obligation asks for

Art. 9(1) of Regulation (EU) 2024/1689 requires the provider of a high-risk AI system to establish, implement, document and maintain a risk management system. Art. 9(2) defines that system as a continuous iterative process, planned and run through the entire lifecycle and reviewed and updated regularly and systematically, with four steps: identification and analysis of the known and reasonably foreseeable risks to health, safety or fundamental rights under the intended purpose (point (a)), estimation and evaluation of the risks that may emerge under the intended purpose and under reasonably foreseeable misuse (point (b)), evaluation of other risks on the basis of post-market monitoring data under Art. 72 (point (c)), and adoption of appropriate and targeted risk management measures (point (d)). Art. 9(3) fixes the scope: the risks concerned are only those the provider can reasonably mitigate or eliminate through the development or design of the system or through adequate technical information, so the file states per risk which of those three routes applies or why none does. The Art. 9 obligation record splits the article into six testable, eleven documentation and six process elements; this guide builds the eleven documentation elements as one file and leaves each testable element with a test reference that PR-15-ROB v1.0 executes. The duty applies from the Annex III application date Deferred for a system classified under Art. 6(2) and from the Annex I date Deferred for a system under Art. 6(1); Regulation (EU) 2026/1744 moved those dates and left the content of Art. 9 unchanged, as each regulation entry records.

Six further paragraphs shape the content of the file. Art. 9(4) requires the measures under point (d) to give due consideration to the effects and the possible interaction of the combined application of the Section 2 requirements, Art. 10 to Art. 15, so that risks are minimised more effectively and the measures stay in balance. Art. 9(5) requires that the residual risk of each hazard and the overall residual risk are judged to be acceptable, and orders the measures: elimination or reduction as far as technically feasible through design and development (point (a)), then mitigation and control measures for the risks that cannot be eliminated (point (b)), then the Art. 13 information and, where appropriate, training for deployers (point (c)), with due consideration to the technical knowledge, experience, education and training expected of the deployer and to the presumable context of use. Art. 9(6) requires testing that identifies the most appropriate and targeted measures and shows that the system performs consistently for its intended purpose and meets the Section 2 requirements; Art. 9(7) allows testing in real-world conditions under Art. 60; Art. 9(8) requires the tests to run, as appropriate, at any time during development and in any event before placing on the market or putting into service, against prior defined metrics and probabilistic thresholds that are appropriate to the intended purpose. Art. 9(9) requires consideration of whether the system is likely to have an adverse impact on persons under the age of 18 and, as appropriate, on other vulnerable groups. Art. 9(10) lets a provider subject to internal risk management requirements under other Union law make the Art. 9(1) to 9(9) aspects part of, or combine them with, the procedures established under that law, which the file shows as a mapping rather than a second register.

Regulation (EU) 2024/1689 sets no numeric threshold in Art. 9. Art. 9(8) leaves the metric and threshold values to the provider with the single condition that they are appropriate to the intended purpose, and Art. 9(5) gives no acceptance level for residual risk. Every value in the file is therefore the provider's prior definition, justified against the context of use, and the structure it sits in comes from the source hierarchy the obligation record states. No harmonised standard for Art. 9 is cited in the Official Journal as of the anchor date, so no presumption of conformity exists at the first level. The second level is prEN 18228Enquiry, the JTC 21 draft at enquiry stage, which supplies the requirements for the identification, estimation, evaluation and mitigation steps and the records that show the cycle ran; its clause content can change before publication. The third level is ISO/IEC 23894:2023Published, published, which applies ISO 31000 risk management to AI with AI-specific risk sources and a lifecycle mapping. The fifth level is NIST AI RMF 1.0Published, published, whose Map, Measure and Manage functions give a structure for the register, the metric selection rationale and the residual risk decision record. The sixth level is the state of the art, which the provider justifies and documents per value. None of these documents publishes a numeric acceptance level for residual risk, a threshold or a required estimation scale.

Inputs

The inputs are the risk management file inputs of PR-17-QMS v1.0 and the preparation inputs of PR-15-ROB v1.0 that the testing plan feeds. The full tables are on the QMS protocol page and the robustness protocol page.

  • The intended-purpose statement and the instructions for use, with the operating conditions, the known circumstances and the deployer knowledge assumptions the provider states under Art. 13(3).
  • The release history of the high-risk AI system with version ids, so that each register version and each test run can name the system version it belongs to.
  • Model access at a fixed version for the test runs, with the version hash and the interface specification.
  • The held-out set and any condition-specific sets, with a provenance record per set, or the data from which PR-15-ROB v1.0 assembles them.
  • The post-market monitoring plan and the analysis records of the current cycle, where the system is already in service.
  • The dataset documentation under Art. 10, the human oversight measures under Art. 14 and the cybersecurity risk assessment under Art. 15(5), for the Art. 9(4) interaction analysis.
  • Where Art. 9(10) applies: the index of the sectoral risk management procedure the provider runs under other Union law.
  • A shell with python and the PyYAML parser installed, for the check in the last step.

Procedure

Each step names the article paragraph, the standard clause or the protocol step it derives from and the record it produces. Code blocks follow the steps they belong to. Every system name, risk id, measure, score, threshold and count in the examples is synthetic.

  1. Open the file with the system, version, intended purpose, lifecycle plan, review trigger and an empty review log.

    Record file header: system, version, intended purpose, Annex route, lifecycle plan, review trigger, review log

    [Regulation (EU) 2024/1689, Art. 9(1) and 9(2); ISO/IEC 23894:2023 §6.6 monitoring and review; PR-17-QMS step 24]

  2. Identify the known and reasonably foreseeable risks to health, safety or fundamental rights under the intended purpose. Record one hazard per row.

    Record hazard register: one row per risk with hazard, harm, affected persons and the intended-purpose condition under which it was identified

    [Regulation (EU) 2024/1689, Art. 9(2)(a); prEN 18228, enquiry stage, clause on risk identification; ISO/IEC 23894:2023 §6.4.2 and Annex B; NIST AI RMF 1.0, Map 5.1]

  3. List the reasonably foreseeable misuse conditions for each hazard. State the expected behaviour of the system under each condition.

    Record misuse condition list per hazard: condition, expected behaviour of the system under it

    [Regulation (EU) 2024/1689, Art. 9(2)(b); ISO/IEC 23894:2023 Annex B risk sources; PR-17-QMS step 30]

  4. State for each risk whether design, development or adequate technical information can reasonably mitigate or eliminate it. Keep an out-of-scope risk in the register with its reason.

    Record scope statement per risk: in scope through design, development or technical information, or out of scope with the reason

    [Regulation (EU) 2024/1689, Art. 9(3); PR-17-QMS step 25]

  5. Write the estimation and evaluation method once. Apply it to every hazard and record the pre-measure risk value.

    Record estimation method sheet and a pre-measure risk value per hazard

    [Regulation (EU) 2024/1689, Art. 9(2)(b); ISO/IEC 23894:2023 §6.4.3 risk analysis and §6.4.4 risk evaluation; PR-17-QMS step 27]

  6. Record the acceptance criterion for each hazard and for the overall residual risk, with its rationale, before any test runs.

    Record acceptance-criteria record: hazard id, criterion, rationale, register version in which it was set; one overall row

    [Regulation (EU) 2024/1689, Art. 9(5); ISO/IEC 23894:2023 §6.3.4 risk criteria; NIST AI RMF 1.0, Manage 1.3; PR-17-QMS step 26]

  7. Select the measures for each hazard in the Art. 9(5) order. Design and development come first, then mitigation and control, then Art. 13 information and deployer training.

    Record measure list per hazard: measure id, type (a), (b) or (c), description, deployer knowledge and context assumption

    [Regulation (EU) 2024/1689, Art. 9(2)(d) and 9(5)(a) to (c); ISO/IEC 23894:2023 §6.5.3 risk treatment plans; PR-17-QMS step 31]

  8. Record how each measure interacts with the measures under Art. 10 to Art. 15, and the balance chosen.

    Record interaction sheet: measure, Section 2 requirement it touches, effect on the other measures, balance chosen

    [Regulation (EU) 2024/1689, Art. 9(4); PR-17-QMS step 35]

  9. Record whether the system is likely to adversely affect persons under the age of 18 or other vulnerable groups. Add group cases where the answer is yes.

    Record vulnerable-groups consideration record: outcome, groups named, group cases added to the test set

    [Regulation (EU) 2024/1689, Art. 9(9); PR-17-QMS step 33; PR-15-ROB step 5]

  10. Write the testing plan. Give each risk at least one test with a metric and a probabilistic threshold recorded before the first run.

    Record testing plan: one row per test with risk id, condition, metric, probabilistic threshold, test set, the register version in which the threshold was set and the register version of the first run

    [Regulation (EU) 2024/1689, Art. 9(6) and 9(8); prEN 18228, enquiry stage, clause on risk evaluation records; NIST AI RMF 1.0, Measure 1.1; PR-15-ROB steps 4, 8 and 9; PR-17-QMS step 29]

  11. Where real-world testing is planned, document it under Art. 60. Where Art. 9(10) applies, map each Art. 9 paragraph to the sectoral procedure element that holds it.

    Record Art. 60 real-world testing plan where used; Art. 9(10) mapping from each Art. 9 paragraph to the sectoral procedure element where used

    [Regulation (EU) 2024/1689, Art. 9(7) and 9(10); PR-17-QMS step 24]

  12. Run the completeness check. After the tests run, record the residual risk value and judgement per hazard and overall. File the report id per test.

    Record check output; residual risk value and judgement per hazard and overall; cross-reference from each test to its risk-driven test report id

    [Regulation (EU) 2024/1689, Art. 9(5) and 9(8); PR-15-ROB steps 35, 36 and 43; PR-17-QMS steps 32 and 36; AIAssuranceLabs procedure]

Example for steps 2 to 10. The register below holds one synthetic risk of a synthetic application-ranking system, demo-screen. The register carries a register_version; a threshold or a criterion counts as prior when the register version in which it was set is lower than the register version of the first run, which the check in step 12 compares. In the file itself the acceptance-criteria record carries a date, and step 26 of PR-17-QMS v1.0 reads that date against the first run. The measure type values follow the three points of Art. 9(5); the scores follow the synthetic method sheet EM-01, which the Act does not prescribe. Every id, description, score and threshold is synthetic.

# Synthetic example: risk-register.yaml for demo-screen 1.2.0, one risk shown
system: demo-screen
version: "1.2.0"
register_version: 4
intended_purpose: ranking of applications to a benefit scheme for human review
lifecycle:
  review_trigger: [release, post-market analysis record, serious incident]
  last_review_register_version: 3
risks:
  - id: H-04
    hazard: applications submitted in an assistive document format receive a systematically lower score
    harm: unjustified rejection of an eligible applicant
    identified_under: applications in the formats listed in the instructions for use, section 3.1
    foreseeable_misuse:
      - id: M-04-1
        condition: deployer applies the score as the sole decision without the review step in the instructions for use
        expected_behaviour: a score below the confidence bound routes to human review and the output states the reason
    affected_groups:
      - group: applicants using assistive document formats
        art_9_9_consideration: likely adverse impact; group cases added to the held-out set
    scope_art_9_3: in scope; mitigable through design (format normalisation) and technical information (instructions for use)
    estimation_method: EM-01, semi-quantitative, likelihood 1 to 5 by severity 1 to 5
    pre_measure_risk: { likelihood: 4, severity: 4, score: 16 }
    measures:
      - id: RM-04-a
        type: art-9-5-a-design
        measure: format normalisation stage before feature extraction; training set augmented with assistive-format samples
      - id: RM-04-b
        type: art-9-5-b-mitigation
        measure: confidence bound; a score below it routes to human review with the reason shown
      - id: RM-04-c
        type: art-9-5-c-information
        measure: instructions for use section 4.2 states the review step; deployer training module DT-02
        deployer_assumption: caseworker with the scheme training the deployer states in its onboarding record
    interaction_art_9_4: normalisation changes the input distribution documented under Art. 10; the review route adds an Art. 14 measure; interaction sheet IA-04
    acceptance_criterion:
      id: ACR-04
      criterion: residual score at or below 8 and every test for H-04 met
      set_in_register_version: 2
    acceptance_rationale: severity stays at 4 because a rejection reaches an eligible person; likelihood 2 rests on T-04-a and T-04-b meeting their thresholds
    residual_risk: { likelihood: 2, severity: 4, score: 8 }
    residual_judgement: acceptable     # acceptable | not-acceptable | open
    tests:
      - id: T-04-a
        metric: false-rejection rate on the assistive-format subset of the held-out set
        threshold: "at or below 0.02 at the one-sided 95 percent upper confidence bound"
        threshold_set_in_register_version: 2
        first_run_register_version: 3
        result: met
        report: RTR-0012       # risk-driven test report (PR-15-ROB output)
      - id: T-04-b
        metric: share of M-04-1 runs in which the review route activates
        threshold: "equal to 1.00 over the misuse case set"
        threshold_set_in_register_version: 2
        first_run_register_version: 3
        result: met
        report: RTR-0012
overall_residual_risk:
  criterion:
    id: ACR-ALL
    criterion: no risk with a residual judgement other than acceptable and no residual score above 8
    set_in_register_version: 2
  judgement: open

Example for step 10. The testing plan below is the flat form of the tests entries, one row per test, which PR-15-ROB v1.0 reads in its step 4 as the threshold register and hazard test map. The threshold_set_in_register_version and first_run_register_version columns carry the prior-definition order. Two rows are wrong on purpose: H-07 is in the plan and not in the register, and its threshold was set in the same register version as its first run. Every value is synthetic.

risk_id,test_id,condition_type,condition,metric,threshold,threshold_set_in_register_version,first_run_register_version,test_set,group_case,report
H-04,T-04-a,operating,assistive document formats,false-rejection rate on the assistive-format subset,at or below 0.02 at the one-sided 95 percent upper confidence bound,2,3,HO-set-7,applicants using assistive document formats,RTR-0012
H-04,T-04-b,misuse,M-04-1 score used as the sole decision,share of runs in which the review route activates,equal to 1.00 over the misuse case set,2,3,MU-set-2,applicants using assistive document formats,RTR-0012
H-04,T-04-c,measure,RM-04-b confidence bound on the H-04 hazard scenarios,activation share on the hazard scenarios,equal to 1.00 over the scenario set,2,3,HZ-set-4,,RTR-0012
H-07,T-07-a,operating,input volume above the stated peak,latency at the 99th percentile,at or below 2.0 seconds,3,3,LD-set-1,,

Example for step 12. The script loads both files and checks that every risk in the register has at least one measure with a type from Art. 9(5)(a) to (c), a scope statement, an acceptance criterion, a residual risk value and a residual judgement that is not open; that every risk has at least one test in the plan; that every test names a metric and a threshold recorded in an earlier register version than its first run; that every plan row refers to a risk in the register; and that the overall residual risk carries a judgement. It prints one line per failure and exits with code 1 when any check fails, so that it can run before each register version is filed. It needs the PyYAML parser.

# Synthetic example: check risk-register.yaml and testing-plan.csv for Art. 9 completeness.
import csv
import sys
import yaml

JUDGEMENTS = {"acceptable", "not-acceptable"}
MEASURE_TYPES = {"art-9-5-a-design", "art-9-5-b-mitigation", "art-9-5-c-information"}

with open("risk-register.yaml", encoding="utf-8") as f:
    register = yaml.safe_load(f)
with open("testing-plan.csv", newline="", encoding="utf-8") as f:
    plan = list(csv.DictReader(f))


def prior(row, set_key, run_key):
    """A threshold is prior when it was set in an earlier register version than its first run."""
    try:
        return int(row[set_key]) < int(row[run_key])
    except (KeyError, TypeError, ValueError):
        return False


risks = {r["id"]: r for r in register.get("risks") or []}
plan_by_risk = {}
for row in plan:
    plan_by_risk.setdefault(row["risk_id"], []).append(row)

failures = []
for rid, r in risks.items():
    types = {m.get("type") for m in r.get("measures") or []}
    if not types:
        failures.append((rid, "no measure"))
    elif not types <= MEASURE_TYPES:
        failures.append((rid, "measure type outside Art. 9(5)(a) to (c)"))
    if not r.get("scope_art_9_3"):
        failures.append((rid, "no Art. 9(3) scope statement"))
    if not (r.get("acceptance_criterion") or {}).get("criterion"):
        failures.append((rid, "no acceptance criterion"))
    if "residual_risk" not in r:
        failures.append((rid, "no residual risk value"))
    if r.get("residual_judgement") not in JUDGEMENTS:
        failures.append((rid, "residual judgement missing or open"))
    if not plan_by_risk.get(rid):
        failures.append((rid, "no test in the plan"))

for t in plan:
    rid, tid = t["risk_id"], t["test_id"]
    if rid not in risks:
        failures.append((rid, "%s: test refers to a risk that is not in the register" % tid))
    if not t.get("metric") or not t.get("threshold"):
        failures.append((rid, "%s: no metric or no threshold" % tid))
    if not prior(t, "threshold_set_in_register_version", "first_run_register_version"):
        failures.append((rid, "%s: threshold not set before the first run" % tid))

overall = register.get("overall_residual_risk") or {}
if overall.get("judgement") not in JUDGEMENTS:
    failures.append(("overall", "overall residual risk judgement missing or open"))

for rid, reason in failures:
    print("FAIL (%s) %s" % (rid, reason))
print("%d risks in the register, %d plan rows, %d failures" % (len(risks), len(plan), len(failures)))
sys.exit(1 if failures else 0)

On the synthetic files above the script reports three failures: H-07 refers to a risk that is not in the register, the threshold of T-07-a was set in the same register version as its first run, and the overall residual risk judgement is open. The register is then one risk complete and the plan carries one orphan row, which becomes a gap register row in the preparation steps of PR-17-QMS v1.0. Every count is an output of this example, never a requirement of the Act.

A pitfall that vendor documentation omits

Risk-register templates and GRC tooling deliver Art. 9 as a likelihood-by-severity table with a mitigation column, and the threshold column, where one exists, is filled after the test result is known. Art. 9(8) asks for prior defined metrics and probabilistic thresholds, and the Art. 9 obligation record names the resulting finding: metrics and thresholds are set after the test results are known, so the prior definition cannot be shown. Step 29 of PR-17-QMS v1.0 reads the date on each metric and threshold against the run date, and step 26 reads the date on each acceptance criterion the same way; a register that carries the threshold and the result in one undated row fails both checks whatever the result says. The same record names two neighbours of that finding: measures described in the file without a test that shows their effect on the risk they address, which Art. 9(5)(a) and (b) and step 31 of the same protocol turn into a measure verification table, and reasonably foreseeable misuse stated as one general sentence with no scenario list and no test case, which step 30 checks against a misuse condition table. A template with one residual score per row and no overall row misses the second half of Art. 9(5), which asks for the overall residual risk of the system to be judged acceptable as well; the register above carries an overall row for that reason, and the check fails while it is open.

The threshold values themselves have no source in the Act. Art. 9(8) names the two conditions a threshold meets, prior definition and appropriateness to the intended purpose, and no value; Art. 9(5) names acceptability and no level. The value in the example, a false-rejection rate bound on one subgroup at a stated confidence, is the provider's choice at level 6 of the source hierarchy, justified in the target justification record that step 9 of PR-15-ROB v1.0 writes per metric, with the level and the document it rests on; prEN 18228Enquiry, at enquiry stage, structures the record and publishes no number, and the Limitations section of the same protocol states that a measurement against a threshold cannot show that the threshold is the appropriate one for the intended purpose. That judgement belongs to the provider under Art. 9(5) and 9(8), and to its notified body and counsel where a conformity assessment follows.

What the result shows and what it does not

The register, the testing plan and the check output show, for one system version at one register version, that each recorded risk has a scope statement, measures of the three Art. 9(5) types, an acceptance criterion and a threshold per test recorded before the first run, a residual judgement, and a test report id where a run took place. They do not show that the risk management system operates as the continuous iterative process Art. 9(2) requires: the review log fills only when the review trigger fires, and PR-17-QMS v1.0 reviews the file at one point in the lifecycle and cannot show that the system operated between reviews or that it will operate after one. The check reads structure, so a hazard register that omits a reasonably foreseeable risk passes it; identification is the provider's work under Art. 9(2)(a), and no check of a register can show that the register is complete. A test result recorded against a threshold holds for the model version, the test sets and the conditions in the environment manifest and the condition register of PR-15-ROB v1.0, and a change to any of them invalidates it; the protocol cannot show that the threshold is the appropriate one, and a statistical result carries its confidence interval and sample size and is not a proof. The result is evidence for the provider's own verification under Annex VI point 2 or for the notified body's assessment under Annex VII; the residual risk acceptance judgement under Art. 9(5) remains with the provider, their notified body where one is required, and their counsel. The QMS gap analysis service reviews the file under the first protocol, the robustness and adversarial testing service executes the tests under the second, and the scope limits of both are on what we cannot do.

Related pages

The quality management system that holds this file under Art. 17(1)(g) is built on the Art. 17 QMS documentation guide; the obligation, both protocols, the related guides on the traceability matrix and on robustness testing, and the hubs for the two roles this guide serves are listed below.

Obligations
Protocols
Related guides
ICP hubs

Questions

What is an EU AI Act risk assessment?

Regulation (EU) 2024/1689 has no article titled risk assessment; the nearest obligation is the Art. 9 risk management system, which the provider of a high-risk AI system runs across the lifecycle: identification and analysis of the known and reasonably foreseeable risks, estimation and evaluation under the intended purpose and under foreseeable misuse, evaluation of post-market data, and targeted measures. Art. 9(5) requires the residual risk per hazard and overall to be judged acceptable; Art. 9(8) requires testing against prior defined metrics and thresholds, whose values the provider sets and justifies.

What does an EU AI Act assessment consist of?

Regulation (EU) 2024/1689 names several assessments with different subjects and actors. The Art. 6 classification decides whether a system is high-risk. The Art. 9 risk management system identifies, evaluates, treats and tests the risks of a high-risk AI system. The Art. 27 fundamental rights impact assessment is the deployer's record before first use of certain Annex III systems. The Art. 43 conformity assessment, under Annex VI or Annex VII, verifies the system against Chapter III Section 2 before the CE marking.

Every inquiry receives a reply within 24 hours. Scope and availability are discussed per request.

Ask about scopehello@aiassurancelabs.com