<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Audit on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/audit/</link><description>Recent content in Audit on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 08 Sep 2026 07:30:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/audit/index.xml" rel="self" type="application/rss+xml"/><item><title>Virtual keys, budgets and limits in LiteLLM: the layer that decides who gets the GPU, and the four things the documentation gets wrong</title><link>https://blog.lo0.es/en/posts/litellm-virtual-keys-budgets-limits/</link><pubDate>Tue, 08 Sep 2026 07:30:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/litellm-virtual-keys-budgets-limits/</guid><description>&lt;blockquote>
&lt;p>Third article in the operational track of the control layer. The &lt;a href="https://blog.lo0.es/en/posts/litellm-langfuse-operational-pair/">pair with Langfuse&lt;/a> covered observability, and &lt;a href="https://blog.lo0.es/en/posts/litellm-day-2-high-availability/">day 2 of the proxy&lt;/a> covered availability. Here it is governance: who can call, which model, how much and on what budget. The economic model behind those figures is in &lt;a href="https://blog.lo0.es/en/posts/finops-multi-tenancy-gpu-cluster-who-pays/">FinOps and multi-tenancy with LiteLLM&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>On a platform running on your own GPUs there is no provider invoice to put consumption in order. Capacity is fixed, known and shared, so someone has to impose the allocation, and that someone is the gateway.&lt;/p>
&lt;p>&lt;strong>The hierarchy has six levels&lt;/strong>: organisation, team, team member, internal user, key and end customer, plus the project and tag scopes. Each level&amp;rsquo;s budgets are evaluated &lt;strong>independently and all of them have to pass&lt;/strong>. They neither add up nor cancel each other out, with one exception.&lt;/p>
&lt;p>&lt;strong>The exception is in the code and it is the most important governance trap in the system.&lt;/strong> A key that belongs to a team suppresses the check of its owner&amp;rsquo;s personal budget, unless &lt;code>apply_user_budget_to_team_keys&lt;/code> is enabled. A user with a hundred-euro cap who works with their team&amp;rsquo;s key spends whatever the team allows.&lt;/p>
&lt;p>&lt;strong>Rotating a key preserves its spend.&lt;/strong> &lt;code>/key/regenerate&lt;/code> does an UPDATE on the same row changing the hash, so &lt;code>spend&lt;/code>, &lt;code>max_budget&lt;/code> and the budget window remain intact. It accepts a grace period, stored in a table of its own, and if the period&amp;rsquo;s format is wrong it is ignored without blocking anything.&lt;/p>
&lt;p>&lt;strong>The v3 limiter is already the default&lt;/strong> in 1.100.0, and you go back to the previous one with an environment variable. Its window is sliding, sixty seconds, anchored to the first request, and the counters are incremented with Lua scripts inside Redis using Redis&amp;rsquo;s own timestamp to close the race between replicas.&lt;/p>
&lt;p>And four points where the official documentation does not match the code, verified against tag v1.100.0: &lt;strong>an exhausted budget returns 429&lt;/strong>, not 400; &lt;strong>the audited actions are six&lt;/strong>, not three; &lt;code>/key/info&lt;/code> and &lt;code>/key/list&lt;/code> are &lt;strong>GET&lt;/strong>, not POST; and the v3 limiter carries a docstring saying it is not production-ready while it is the one loaded by default.&lt;/p>
&lt;h2 id="you-are-here-the-gateway-as-an-administrative-boundary">You are here: the gateway as an administrative boundary&lt;/h2>
&lt;p>Without this layer, an in-house inference platform has a single mode of operation: whoever knows the URL consumes. It works while there is one team. It stops working the day there are three, or the day someone connects an agent that fires twenty calls per interaction and wrecks everyone else&amp;rsquo;s time to first token.&lt;/p>
&lt;p>The two questions this layer answers are different and have to be kept apart. The &lt;strong>capacity&lt;/strong> one is instantaneous: how many requests and how many tokens per minute each consumer can push, so the fleet does not saturate and latency stays within the service agreement. The &lt;strong>cost&lt;/strong> one is cumulative: how much each consumer has spent this month against its budget. They are configured in the same place, applied at different moments and fail in different ways.&lt;/p>
&lt;h2 id="the-analogy-the-buildings-key-ring">The analogy: the building&amp;rsquo;s key ring&lt;/h2>
&lt;p>An office building hands out keys at three levels. The master opens everything and the building manager has it. The floor keys open a whole floor and each tenant company has one. And the office keys open one office.&lt;/p>
&lt;p>Three properties of that system are the ones that matter here. A key is replaced without changing the lock of the whole building, and the tenant keeps their parking space and their electricity meter: that is rotation preserving the spend. A lost key is cancelled from the central panel without collecting anything physical: that is blocking from the interface. And the record of who took out each key and when lives in a separate book, which is what you show an inspector: that is the audit table.&lt;/p>
&lt;p>The analogy breaks at one point, and that point is where this system&amp;rsquo;s governance flaw lives. In the building, having a floor key does not cancel the office&amp;rsquo;s consumption limit. In LiteLLM, it does.&lt;/p>
&lt;h2 id="the-hierarchy-and-the-line-that-breaks-it">The hierarchy, and the line that breaks it&lt;/h2>
&lt;p>The levels and their management endpoints:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Level&lt;/th>
&lt;th>Endpoints&lt;/th>
&lt;th>Budget&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Organisation&lt;/td>
&lt;td>&lt;code>/organization/new&lt;/code>, &lt;code>/organization/member_add&lt;/code>, …&lt;/td>
&lt;td>&lt;code>max_budget&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Team&lt;/td>
&lt;td>&lt;code>/team/new&lt;/code>, &lt;code>/team/member_add&lt;/code>, &lt;code>/team/block&lt;/code>, …&lt;/td>
&lt;td>&lt;code>max_budget&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Team member&lt;/td>
&lt;td>&lt;code>/team/member_add&lt;/code> with &lt;code>max_budget_in_team&lt;/code>&lt;/td>
&lt;td>Its own row in the budgets table&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Internal user&lt;/td>
&lt;td>&lt;code>/user/new&lt;/code>, &lt;code>/user/update&lt;/code>, …&lt;/td>
&lt;td>&lt;code>max_budget&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Key&lt;/td>
&lt;td>&lt;code>/key/generate&lt;/code>, &lt;code>/key/update&lt;/code>, …&lt;/td>
&lt;td>&lt;code>max_budget&lt;/code>, &lt;code>soft_budget&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>End customer&lt;/td>
&lt;td>&lt;code>/customer/new&lt;/code>, and the parallel &lt;code>/end_user/*&lt;/code> set&lt;/td>
&lt;td>&lt;code>max_budget&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The default behaviour is the right one for a multi-tenant platform: each scope carries its own counter and the check of each one is independent of the rest. A request passes if all of them pass.&lt;/p>
&lt;p>And then there is this condition, which lives in the authorisation checks:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">is_team_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">team_object&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">team_object&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">team_id&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">is_team_key&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">general_settings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;apply_user_budget_to_team_keys&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Translated: when the key belongs to a team, the check of the budget of the user who owns that key &lt;strong>returns without evaluating anything&lt;/strong>. The personal cap exists in the database, is visible in the interface, and is not applied.&lt;/p>
&lt;p>For a deployment where personal budgets are decorative, it makes no difference. For one where the per-person cap is the control that was shown to someone as a guarantee that a user cannot overrun the platform, it is a hole. The line that closes it is one:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">general_settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">apply_user_budget_to_team_keys&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="virtual-keys-the-complete-life-cycle">Virtual keys: the complete life cycle&lt;/h2>
&lt;p>The endpoints all exist and some of them are not where you expect:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Route&lt;/th>
&lt;th>Method&lt;/th>
&lt;th>What for&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>/key/generate&lt;/code>&lt;/td>
&lt;td>POST&lt;/td>
&lt;td>Create&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>/key/update&lt;/code>&lt;/td>
&lt;td>POST&lt;/td>
&lt;td>Modify&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>/key/info&lt;/code>&lt;/td>
&lt;td>&lt;strong>GET&lt;/strong>&lt;/td>
&lt;td>Query one&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>/key/list&lt;/code>&lt;/td>
&lt;td>&lt;strong>GET&lt;/strong>&lt;/td>
&lt;td>List&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>/key/delete&lt;/code>&lt;/td>
&lt;td>POST&lt;/td>
&lt;td>Delete&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>/key/regenerate&lt;/code>&lt;/td>
&lt;td>POST&lt;/td>
&lt;td>Rotate&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>/key/block&lt;/code>, &lt;code>/key/unblock&lt;/code>&lt;/td>
&lt;td>POST&lt;/td>
&lt;td>Suspend and reactivate&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>/key/health&lt;/code>&lt;/td>
&lt;td>POST&lt;/td>
&lt;td>Check that key&amp;rsquo;s callbacks&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The two marked in bold are GET, and several examples in the documentation suggest otherwise. &lt;code>/key/health&lt;/code> is not what its name suggests either: it does not validate the key or its budget, it checks the logging callbacks associated with it.&lt;/p>
&lt;p>There are many creation parameters, and these are the ones that govern:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -X POST &lt;span class="s1">&amp;#39;https://gateway.interno/key/generate&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H &lt;span class="s1">&amp;#39;Authorization: Bearer sk-...&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="s1">&amp;#39;{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;key_alias&amp;#34;: &amp;#34;equipo-datos-notebooks&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;team_id&amp;#34;: &amp;#34;t-datos&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;models&amp;#34;: [&amp;#34;llama-70b&amp;#34;, &amp;#34;qwen-30b&amp;#34;],
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;max_budget&amp;#34;: 250,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;budget_duration&amp;#34;: &amp;#34;30d&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;tpm_limit&amp;#34;: 400000,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;rpm_limit&amp;#34;: 600,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;max_parallel_requests&amp;#34;: 8,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;duration&amp;#34;: &amp;#34;90d&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;tags&amp;#34;: [&amp;#34;produccion&amp;#34;, &amp;#34;notebooks&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> }&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Alongside those there are controls that are rarely used and solve specific problems: &lt;code>model_max_budget&lt;/code> to set a per-model cap within the same key, &lt;code>model_tpm_limit&lt;/code> and &lt;code>model_rpm_limit&lt;/code> for the same thing with capacity, &lt;code>enforced_params&lt;/code> to require certain keys to always arrive with given fields, &lt;code>allowed_routes&lt;/code> so an application key cannot touch the management endpoints, and &lt;code>blocked&lt;/code> to be born suspended.&lt;/p>
&lt;h3 id="how-they-are-stored">How they are stored&lt;/h3>
&lt;p>A key&amp;rsquo;s hash is a single-pass hexadecimal SHA-256, with no salt and no derivation function:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">hashed_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hashlib&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sha256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encode&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">hexdigest&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The row lives in &lt;code>LiteLLM_VerificationToken&lt;/code>, with the hash as primary key, and it contains the accumulated spend, the limits, the expiry, the allowed models and the rest of the configuration.&lt;/p>
&lt;p>Two consequences to be clear about before an audit. The first is that this hash is not designed to resist a dictionary attack against the database, and the code itself acknowledges it in a comment about encryption key derivation, where it admits that a single-pass unsalted SHA-256 is not a derivation function and that moving to HKDF would be more defensible in an audit. The real mitigation is that virtual keys are generated with enough entropy, not the strength of the hash. The second is that &lt;code>LITELLM_SALT_KEY&lt;/code> &lt;strong>plays no part here&lt;/strong>: that variable encrypts the stored provider credentials, not the virtual keys.&lt;/p>
&lt;p>There is a trap around that variable that takes down a whole deployment. If it is not defined, it &lt;strong>falls back to the master key&lt;/strong>. Rotating &lt;code>LITELLM_MASTER_KEY&lt;/code> without having first set your own &lt;code>LITELLM_SALT_KEY&lt;/code> leaves every stored provider credential unreadable, and the failure does not block: it logs an error and returns null, so the symptom shows up as models that stop authenticating with no explanation. Setting &lt;code>LITELLM_SALT_KEY&lt;/code> on day one, and never touching it, is one of the things that saves the most grief.&lt;/p>
&lt;h3 id="rotation">Rotation&lt;/h3>
&lt;p>&lt;code>/key/regenerate&lt;/code> does not create a new key and delete the old one. It updates the same row changing the hash, so &lt;strong>the accumulated spend, the maximum budget and the reset window are preserved&lt;/strong>. For a monthly chargeback this is exactly what you want: rotating mid-month does not zero the counter.&lt;/p>
&lt;p>It also accepts a grace period, so the old key remains valid while consumers update:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -X POST &lt;span class="s1">&amp;#39;https://gateway.interno/key/sk-vieja/regenerate&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H &lt;span class="s1">&amp;#39;Authorization: Bearer sk-...&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="s1">&amp;#39;{&amp;#34;grace_period&amp;#34;: &amp;#34;24h&amp;#34;}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The old hash is stored in a separate table with its revocation date. Without that parameter, revocation is immediate, and the default value can be set with &lt;code>LITELLM_KEY_ROTATION_GRACE_PERIOD&lt;/code>.&lt;/p>
&lt;p>A detail with teeth: if the period&amp;rsquo;s format is wrong, the system logs a warning and &lt;strong>continues with no grace period&lt;/strong>. The rotation completes, the old key dies on the spot, and all that is left is a log line. In an automated rotation procedure, that combination of &amp;ldquo;carry on&amp;rdquo; and &amp;ldquo;warn in the log&amp;rdquo; is what produces the outage at three in the morning.&lt;/p>
&lt;h2 id="what-exactly-happens-when-a-budget-runs-out">What exactly happens when a budget runs out&lt;/h2>
&lt;p>The code raises &lt;code>BudgetExceededError&lt;/code> with &lt;strong>status 429&lt;/strong>. The documentation says 400 in one place, and there the code wins. Its being a 429 has a practical implication: OpenAI clients retry automatically on a 429, so an exhausted budget turns into a retry storm against a gateway that is going to keep rejecting. Internal clients should distinguish the reason, which travels in the message.&lt;/p>
&lt;p>The messages are templates and state the scope, the spend and the cap:&lt;/p>
&lt;pre tabindex="0">&lt;code>Budget has been exceeded! Key=&amp;lt;clave&amp;gt; Current cost: &amp;lt;gasto&amp;gt;, Max budget: &amp;lt;tope&amp;gt;
Budget has been exceeded! Team=&amp;lt;equipo&amp;gt; Current cost: &amp;lt;gasto&amp;gt;, Max budget: &amp;lt;tope&amp;gt;
ExceededBudget: User=&amp;lt;usuario&amp;gt; over budget. Spend=&amp;lt;gasto&amp;gt;, Budget=&amp;lt;tope&amp;gt;
ExceededBudget: End User=&amp;lt;cliente&amp;gt; over budget. Spend=&amp;lt;gasto&amp;gt;, Budget=&amp;lt;tope&amp;gt;
Budget has been exceeded! Organization=&amp;lt;org&amp;gt; ...
Budget has been exceeded! Tag=&amp;lt;etiqueta&amp;gt; ...
&lt;/code>&lt;/pre>&lt;p>Two clarifications about the comparison. It is &lt;code>spend &amp;gt;= cap&lt;/code>, with the equals sign included, so landing exactly on the cap already blocks. And the soft budget, &lt;code>soft_budget&lt;/code>, &lt;strong>blocks nothing&lt;/strong>: it only writes a log line when it is crossed. It serves to warn, not to contain, and building an alert on top of it is the right way to use it.&lt;/p>
&lt;p>The rest of the rejections, with their codes:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Situation&lt;/th>
&lt;th>Code&lt;/th>
&lt;th>Behaviour&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Budget exhausted&lt;/td>
&lt;td>429&lt;/td>
&lt;td>Message with scope, spend and cap&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Expired key&lt;/td>
&lt;td>401&lt;/td>
&lt;td>It also deletes the cache entry, so the expiry takes effect across the whole fleet without waiting for the TTL&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Model not allowed&lt;/td>
&lt;td>403&lt;/td>
&lt;td>Different error type depending on the scope: key, team, user, organisation or project&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Blocked key&lt;/td>
&lt;td>Generic exception&lt;/td>
&lt;td>&lt;code>Key is blocked. Update via /key/unblock if you're an admin.&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The last row is an inconsistency in the project worth knowing about: blocking raises an exception with no explicit type or code, while expiry and model access do carry them. Any alert that discriminates by error type will not see blocks the way it sees the rest.&lt;/p>
&lt;p>A useful note about allowed models: the check accepts both the alias and the underlying model, so a key authorised for &lt;code>llama-70b&lt;/code> can call it by its alias or by its real name with no additional configuration.&lt;/p>
&lt;h2 id="capacity-limits-the-v3-limiter">Capacity limits: the v3 limiter&lt;/h2>
&lt;p>This is the most significant silent change of the year in this layer. In 1.100.0, the limiter loaded by default is the third version. Going back to the previous one has to be asked for explicitly:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">LEGACY_MULTI_INSTANCE_RATE_LIMITING&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There is no flag to turn it on, only to turn it off. And it carries a contradiction worth knowing before trusting it: the file itself still opens with a comment saying it is under development and not production-ready, while it is the one running. The design is avowedly inspired by Envoy&amp;rsquo;s.&lt;/p>
&lt;p>&lt;strong>The window is sliding and lasts sixty seconds&lt;/strong>, configurable with &lt;code>LITELLM_RATE_LIMIT_WINDOW_SIZE&lt;/code>. It is not an exact rolling log nor a clock-aligned window: it anchors to the first request and resets once the window size has elapsed from that moment. For one-minute limits, the difference from a calendar window shows up at the edges and rarely matters.&lt;/p>
&lt;p>What does matter is Redis. The counters are incremented with Lua scripts executed inside Redis, using Redis&amp;rsquo;s own timestamp and not the pod&amp;rsquo;s, precisely so window resets are deterministic across replicas and to close the race between checking and counting. Without Redis, &lt;strong>each pod counts on its own and the effective limit is multiplied by the number of pods&lt;/strong>. A limit of 600 requests per minute with five replicas is a limit of 3,000.&lt;/p>
&lt;p>There is an inherent imprecision in the token limits that Redis does not solve. The number of output tokens is not known until the response finishes, so the limiter counts with an estimate before the call and reconciles afterwards. The possible excess is, per in-flight request, the difference between the estimate and the real figure. With high concurrency and long responses, that allows the cap to be exceeded within a window. To protect the fleet, the concurrent request limit (&lt;code>max_parallel_requests&lt;/code>) is a more direct instrument than tokens per minute.&lt;/p>
&lt;h3 id="what-the-client-sees">What the client sees&lt;/h3>
&lt;p>When limited, a 429 with the message giving the scope, the current limit, what is left and when it resets. And three headers: &lt;code>retry-after&lt;/code> with the window size, that is &lt;code>60&lt;/code> by default, plus &lt;code>rate_limit_type&lt;/code> and &lt;code>reset_at&lt;/code>.&lt;/p>
&lt;p>On the success path, the informational headers use a nested format of their own:&lt;/p>
&lt;pre tabindex="0">&lt;code>x-ratelimit-api_key-remaining-requests
x-ratelimit-api_key-limit-tokens
x-ratelimit-team-remaining-requests
&lt;/code>&lt;/pre>&lt;p>&lt;strong>They are not the standard names&lt;/strong> &lt;code>x-ratelimit-limit-requests&lt;/code> that OpenAI and compatibles emit, so a client expecting the usual format will find nothing. There is also an open issue about these headers being lost on streaming responses, which is most of an assistant&amp;rsquo;s traffic.&lt;/p>
&lt;h2 id="identity-beyond-the-static-key">Identity: beyond the static key&lt;/h2>
&lt;p>Handing out keys by hand works with three teams and stops working with thirty. The two routes for connecting the gateway to corporate identity:&lt;/p>
&lt;p>&lt;strong>JWT.&lt;/strong> It is enabled with &lt;code>enable_jwt_auth&lt;/code> and configured with the &lt;code>litellm_jwtauth&lt;/code> block, which maps token fields to LiteLLM entities: the team comes from &lt;code>team_id_jwt_field&lt;/code>, the user from &lt;code>user_id_jwt_field&lt;/code>, the organisation from &lt;code>org_id_jwt_field&lt;/code>. It supports dot notation for nested claims, automatic creation of users and teams with &lt;code>user_id_upsert&lt;/code> and &lt;code>team_id_upsert&lt;/code>, role-based access control with &lt;code>enforce_rbac&lt;/code>, per-team model restriction with &lt;code>enforce_team_based_model_access&lt;/code>, and several issuers at once. The issuer&amp;rsquo;s public key is cached with a TTL of 600 seconds by default.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">general_settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enable_jwt_auth&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">litellm_jwtauth&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">team_id_jwt_field&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;groups&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">user_id_jwt_field&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;sub&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">user_email_jwt_field&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enforce_rbac&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enforce_team_based_model_access&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">team_id_upsert&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>OIDC for the admin interface.&lt;/strong> With Keycloak you use the generic provider, and the variables are &lt;code>PROXY_BASE_URL&lt;/code>, &lt;code>GENERIC_CLIENT_ID&lt;/code>, &lt;code>GENERIC_CLIENT_SECRET&lt;/code>, &lt;code>GENERIC_AUTHORIZATION_ENDPOINT&lt;/code>, &lt;code>GENERIC_TOKEN_ENDPOINT&lt;/code>, &lt;code>GENERIC_USERINFO_ENDPOINT&lt;/code>, plus a set of attributes to map the identifier, the email, the name and the role, and &lt;code>GENERIC_ROLE_MAPPINGS_*&lt;/code> to translate Keycloak groups into LiteLLM roles. Login is rate-limited and sessions have a TTL of their own.&lt;/p>
&lt;p>For automatic provisioning there is SCIM in the enterprise version, with base &lt;code>/scim/v2&lt;/code>, and deprovisioning a user blocks their keys and takes them out of the authentication cache. That part is not in the open tree, so it cannot be verified against the code.&lt;/p>
&lt;p>This fits with the identity work already covered in &lt;a href="https://blog.lo0.es/en/posts/hardening-secrets-sovereign-llm-stack-defence-in-depth/">hardening and secrets of the sovereign stack&lt;/a> and in the article on &lt;a href="https://blog.lo0.es/en/posts/mcp-grows-up-authentication-keycloak/">MCP authentication with Keycloak&lt;/a>, which uses the same issuer.&lt;/p>
&lt;h2 id="audit-what-gets-recorded">Audit: what gets recorded&lt;/h2>
&lt;p>The table is &lt;code>LiteLLM_AuditLog&lt;/code> and its columns are what you would expect from a change log:&lt;/p>
&lt;pre tabindex="0">&lt;code>id, updated_at, changed_by, changed_by_api_key,
action, table_name, object_id, before_value, updated_values
&lt;/code>&lt;/pre>&lt;p>It stores the previous value and the new one, and attributes the change to an actor and to the key it was made with.&lt;/p>
&lt;p>Three clarifications the documentation does not capture well.&lt;/p>
&lt;p>&lt;strong>The actions are six, in the past tense&lt;/strong>: &lt;code>created&lt;/code>, &lt;code>updated&lt;/code>, &lt;code>deleted&lt;/code>, &lt;code>blocked&lt;/code>, &lt;code>unblocked&lt;/code> and &lt;code>rotated&lt;/code>. The documentation mentions three. That blocking, unblocking and rotation are actions in their own right is exactly what is needed to reconstruct a credential&amp;rsquo;s life cycle for an auditor.&lt;/p>
&lt;p>&lt;strong>The scope is wider than advertised.&lt;/strong> Besides teams, users, keys and models, changes to the proxy configuration and to the SSO configuration are audited. A change of identity issuer is recorded.&lt;/p>
&lt;p>&lt;strong>The default depends on the licence.&lt;/strong> The resolution order is &lt;code>litellm_settings.store_audit_logs&lt;/code>, then the variable &lt;code>LITELLM_STORE_AUDIT_LOGS&lt;/code>, and if neither is set, it stays &lt;strong>enabled in enterprise and disabled in the open version&lt;/strong>. An OSS deployment that assumes there is an audit trail does not have one:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">litellm_settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">store_audit_logs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Two more pieces for a serious chain of evidence. The actor attribution can be passed with the &lt;code>LiteLLM-Changed-By&lt;/code> header, and its use is restricted by the key&amp;rsquo;s or the team&amp;rsquo;s configuration, so any caller cannot forge it. And the events can be shipped out with &lt;code>audit_log_callbacks&lt;/code> and its S3 parameters, which is what allows depositing them in an immutable store with object lock.&lt;/p>
&lt;p>That last part is what turns the record into evidence. The Postgres table is mutable by anyone with database access, and as of September 2026 it has no indexes, so querying it by date range over a long history will not be comfortable either.&lt;/p>
&lt;h2 id="what-this-demonstrates-to-an-auditor-and-what-it-does-not">What this demonstrates to an auditor, and what it does not&lt;/h2>
&lt;p>This is the part that decides whether the setup is good enough for a regulated customer. With everything above configured, the platform sustains without difficulty:&lt;/p>
&lt;p>&lt;strong>Access control via corporate identity&lt;/strong>, with onboarding and offboarding in the identity provider and not in the gateway, and with the role determining which models are reachable. &lt;strong>Segregation between tenants&lt;/strong>, with independent counters per organisation, team and person. &lt;strong>Traceability of administrative changes&lt;/strong>, with actor, time, previous value and new value, exportable to an immutable store. And &lt;strong>demonstrable consumption limits&lt;/strong>, with the evidence of the rejection in the spend log.&lt;/p>
&lt;p>What it does not cover, and has to be solved elsewhere:&lt;/p>
&lt;p>&lt;strong>The record of the interactions&lt;/strong> is not this. The audit table records configuration changes, not model calls. The calls are in the spend log and in the traces, and traces are best-effort, which is the discussion in the &lt;a href="https://blog.lo0.es/en/posts/litellm-langfuse-operational-pair/">first article in the series&lt;/a>.&lt;/p>
&lt;p>&lt;strong>The integrity of the record&lt;/strong> is not something Postgres provides. Without export to immutable storage, the evidence is only as strong as the database permissions.&lt;/p>
&lt;p>&lt;strong>The content of the prompts&lt;/strong> is a separate problem, with its own personal-data treatment and its own decision about whether it is stored, masked or not logged at all.&lt;/p>
&lt;p>And a warning about the control that tends to be shown first: while &lt;code>apply_user_budget_to_team_keys&lt;/code> is not enabled, the per-person cap is not being applied to team keys. Showing that field in the interface as proof of a control that is not executed is the kind of finding a competent auditor discovers. The complete control mapping is in &lt;a href="https://blog.lo0.es/en/posts/technical-controls-ens-iso-42001-eu-ai-act-cross-mapping/">ENS, ISO 42001 and the EU AI Act&lt;/a>.&lt;/p>
&lt;h2 id="checklist">Checklist&lt;/h2>
&lt;ol>
&lt;li>&lt;code>apply_user_budget_to_team_keys: true&lt;/code> if personal budgets have to be enforced.&lt;/li>
&lt;li>&lt;code>LITELLM_SALT_KEY&lt;/code> set on day one, different from the master key and never rotated lightly.&lt;/li>
&lt;li>&lt;code>store_audit_logs: true&lt;/code> explicitly, without trusting the default.&lt;/li>
&lt;li>&lt;code>audit_log_callbacks&lt;/code> towards an immutable store if an audit has to be sustained.&lt;/li>
&lt;li>Redis mandatory if there is more than one replica, or the limits get multiplied by the number of pods.&lt;/li>
&lt;li>&lt;code>max_parallel_requests&lt;/code> per key, on top of the per-minute limits, to protect the fleet from a runaway agent.&lt;/li>
&lt;li>&lt;code>allowed_routes&lt;/code> on application keys, so they cannot reach the management endpoints.&lt;/li>
&lt;li>&lt;code>soft_budget&lt;/code> with an alert on top, understanding that it does not block.&lt;/li>
&lt;li>Rotation with a verified &lt;code>grace_period&lt;/code>, because an invalid format revokes on the spot.&lt;/li>
&lt;li>JWT against Keycloak as soon as there are more than a handful of teams, with &lt;code>enforce_rbac&lt;/code> and &lt;code>enforce_team_based_model_access&lt;/code>.&lt;/li>
&lt;/ol>
&lt;h2 id="traps-and-things-that-are-not-what-they-look-like">Traps and things that are not what they look like&lt;/h2>
&lt;p>&lt;strong>A user&amp;rsquo;s cap is not enforced.&lt;/strong> They are using a team key and &lt;code>apply_user_budget_to_team_keys&lt;/code> is missing.&lt;/p>
&lt;p>&lt;strong>Clients retry in a loop against an exhausted budget.&lt;/strong> The code is 429 and the OpenAI libraries retry 429s automatically.&lt;/p>
&lt;p>&lt;strong>The soft budget has stopped nothing.&lt;/strong> It does not block, it only logs.&lt;/p>
&lt;p>&lt;strong>The per-minute limits are enforced at double or triple.&lt;/strong> There is no Redis, and each replica keeps its own count.&lt;/p>
&lt;p>&lt;strong>The client does not see the limit headers.&lt;/strong> The names are nested and proprietary, and in streaming there is an open issue where they get lost.&lt;/p>
&lt;p>&lt;strong>There is no audit log.&lt;/strong> It is an OSS deployment and the default there is disabled.&lt;/p>
&lt;p>&lt;strong>The models stop authenticating after rotating the master key.&lt;/strong> There was no fixed &lt;code>LITELLM_SALT_KEY&lt;/code>, and the encrypted provider credentials can no longer be decrypted.&lt;/p>
&lt;p>&lt;strong>The rotation cut the service on the spot.&lt;/strong> The &lt;code>grace_period&lt;/code> carried a format the system did not understand and it carried on without it.&lt;/p>
&lt;p>&lt;strong>Blocking a key does not fire the alert.&lt;/strong> It is raised as a generic exception, without the type that expiry and model access do carry.&lt;/p>
&lt;h2 id="closing">Closing&lt;/h2>
&lt;p>The keys and budgets layer is the one that turns a shared URL into a platform with tenants. It is well solved in LiteLLM and has more depth than the documentation suggests, with per-model budgets inside a key, multiple budget windows, per-tag limits and rotation that preserves the history.&lt;/p>
&lt;p>Out of the whole article, two things take the attention. The &lt;code>apply_user_budget_to_team_keys&lt;/code> line, because it is the difference between having a control and believing you have one. And setting &lt;code>LITELLM_SALT_KEY&lt;/code>, because its default turns a routine rotation of the master key into an outage that is hard to diagnose. Both are one line of configuration and both are discovered late.&lt;/p>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/humans-agents-same-gateway-priority-traffic-separation/">Humans and agents on the same gateway&lt;/a> — what happens to these limits when the caller is an agentic loop, and why &lt;code>max_parallel_requests&lt;/code> is only applied on the key.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/litellm-langfuse-operational-pair/">LiteLLM and Langfuse: the operational pair&lt;/a> — where the traces of all this end up, and why the audit record cannot lean on them.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/litellm-day-2-high-availability/">LiteLLM on day 2: high availability&lt;/a> — the Redis taken as given here, and the Postgres arithmetic that sustains the spend table.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/finops-multi-tenancy-gpu-cluster-who-pays/">FinOps and GPU multi-tenancy with LiteLLM&lt;/a> — where the figures that go into &lt;code>max_budget&lt;/code> come from, and the difference between showback and chargeback.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/gpu-hour-to-cost-per-token-on-prem-vs-cloud/">From GPU-hour to cost per token and per request&lt;/a> — the conversion that gives meaning to a budget in euros on your own GPU.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/technical-controls-ens-iso-42001-eu-ai-act-cross-mapping/">Technical controls: ENS, ISO 42001 and the EU AI Act&lt;/a> — the complete mapping, of which this article covers the access control and administrative traceability part.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/hardening-secrets-sovereign-llm-stack-defence-in-depth/">Hardening and secrets of the sovereign stack&lt;/a> — the management of &lt;code>LITELLM_SALT_KEY&lt;/code> and of the rest of the deployment&amp;rsquo;s secrets.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/mcp-grows-up-authentication-keycloak/">When MCP grows: authentication with Keycloak&lt;/a> — the same identity issuer, applied to the platform&amp;rsquo;s other front door.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/keycloak-identity-plane-ai-platform/">Keycloak in an AI platform&lt;/a> — the alternative to these keys, and why a long-lived key decouples identity from the provider.&lt;/li>
&lt;/ul>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>LiteLLM, &lt;em>Virtual Keys&lt;/em> (parámetros de creación, ciclo de vida, rotación): &lt;a href="https://docs.litellm.ai/docs/proxy/virtual_keys">https://docs.litellm.ai/docs/proxy/virtual_keys&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;em>Budgets, Rate Limits&lt;/em> (jerarquía, presupuestos por nivel, clientes finales): &lt;a href="https://docs.litellm.ai/docs/proxy/users">https://docs.litellm.ai/docs/proxy/users&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;em>JWT Token Auth&lt;/em> (bloque &lt;code>litellm_jwtauth&lt;/code> y todos sus campos): &lt;a href="https://docs.litellm.ai/docs/proxy/token_auth">https://docs.litellm.ai/docs/proxy/token_auth&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;em>Audit Logs&lt;/em> y administración múltiple (la cabecera &lt;code>LiteLLM-Changed-By&lt;/code>): &lt;a href="https://docs.litellm.ai/docs/proxy/multiple_admins">https://docs.litellm.ai/docs/proxy/multiple_admins&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;em>SCIM&lt;/em> (aprovisionamiento automático, versión enterprise): &lt;a href="https://docs.litellm.ai/docs/tutorials/scim_litellm">https://docs.litellm.ai/docs/tutorials/scim_litellm&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;code>litellm/proxy/auth/auth_checks.py&lt;/code> en la etiqueta v1.100.0 (la condición de &lt;code>apply_user_budget_to_team_keys&lt;/code> y los mensajes de presupuesto agotado): &lt;a href="https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/auth/auth_checks.py">https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/auth/auth_checks.py&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;code>litellm/proxy/management_endpoints/key_management_endpoints.py&lt;/code> en v1.100.0 (rutas, rotación sobre la misma fila, periodo de gracia): &lt;a href="https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/management_endpoints/key_management_endpoints.py">https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/management_endpoints/key_management_endpoints.py&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;code>litellm/proxy/hooks/parallel_request_limiter_v3.py&lt;/code> y &lt;code>litellm/proxy/hooks/__init__.py&lt;/code> en v1.100.0 (el limitador v3 como valor por defecto, la ventana, los scripts Lua): &lt;a href="https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/hooks/parallel_request_limiter_v3.py">https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/hooks/parallel_request_limiter_v3.py&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;code>litellm/exceptions.py&lt;/code> en v1.100.0 (&lt;code>BudgetExceededError&lt;/code> con código 429): &lt;a href="https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/exceptions.py">https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/exceptions.py&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;code>litellm/proxy/common_utils/encrypt_decrypt_utils.py&lt;/code> en v1.100.0 (&lt;code>LITELLM_SALT_KEY&lt;/code> cayendo en la clave maestra, y el comentario sobre la derivación de claves): &lt;a href="https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/common_utils/encrypt_decrypt_utils.py">https://github.com/BerriAI/litellm/blob/v1.100.0/litellm/proxy/common_utils/encrypt_decrypt_utils.py&lt;/a>.&lt;/li>
&lt;li>LiteLLM, &lt;code>schema.prisma&lt;/code> en v1.100.0 (&lt;code>LiteLLM_VerificationToken&lt;/code>, &lt;code>LiteLLM_AuditLog&lt;/code>, la tabla de claves deprecadas): &lt;a href="https://github.com/BerriAI/litellm/blob/v1.100.0/schema.prisma">https://github.com/BerriAI/litellm/blob/v1.100.0/schema.prisma&lt;/a>.&lt;/li>
&lt;li>LiteLLM, issue #27748 — cabeceras &lt;code>x-ratelimit-*&lt;/code> perdidas en respuestas en streaming con el limitador v3: &lt;a href="https://github.com/BerriAI/litellm/issues/27748">https://github.com/BerriAI/litellm/issues/27748&lt;/a>.&lt;/li>
&lt;/ul></description></item><item><title>ISO/IEC 42001: the operations manual for the AI system — how the AIMS fits over the on-premise LLM platform described in this blog</title><link>https://blog.lo0.es/en/posts/iso-42001-aims-on-premise-llm-platform/</link><pubDate>Mon, 01 Jun 2026 06:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/iso-42001-aims-on-premise-llm-platform/</guid><description>&lt;blockquote>
&lt;p>This post closes an asymmetry the blog had been accumulating: we have described in detail the technical platform (&lt;a href="https://blog.lo0.es/en/posts/anatomy-on-premise-llm-inference-stack-seven-layers/">seven stack layers&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/greenfield-deployment-phases-on-premise-llm-platform/">seven deployment phases&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/five-maturity-levels-platform-under-llm/">five maturity levels&lt;/a>), the operational pipeline (&lt;a href="https://blog.lo0.es/en/posts/six-stage-llmops-pipeline-architecture-and-deep-dive/">six LLMOps stages&lt;/a>), the data pieces (&lt;a href="https://blog.lo0.es/en/posts/rag-corpus-curation-active-librarian/">corpus curation&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">versioning&lt;/a>), the eval / safety pieces (&lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">evals&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">guardrails&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/llm-guard-anatomy-scanners-langfuse-vllm-litellm/">LLM Guard&lt;/a>) and the observe pieces (&lt;a href="https://blog.lo0.es/en/posts/llm-tracing-opentelemetry-genai/">OTel GenAI tracing&lt;/a>). What had not appeared is the governance layer a regulated client asks for on top of all that. ISO/IEC 42001 is that layer.&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>ISO/IEC 42001:2023 is the first certifiable international standard that defines how an AI system is managed. It is not a technical standard (it does not say &amp;ldquo;use this inference engine&amp;rdquo; or &amp;ldquo;this safety threshold&amp;rdquo;): it is a management standard, a cousin of ISO 27001 and ISO 9001. From both it inherits the Annex SL structure, seven mandatory clauses running through context, leadership, planning, support, operation, performance evaluation and improvement, and it adds an Annex A with 38 AI-specific controls in 9 sections: policies, internal organisation, resources, impact assessment, lifecycle, data, information to interested parties, use, third parties. The thesis of this post is that the technical architecture described in this blog directly covers between 60% and 80% of the A controls with no extra work. The LLMOps pipeline materialises A.6, versioning and curation materialise A.7, guardrails and evals materialise A.9, OTel tracing materialises A.8. The rest is governance discipline that does not appear in the code (a written AI policy, impact assessments per system, a stakeholder register, role decisions between provider/producer/customer, mandatory documentation), and that is precisely what separates a real certification from performative compliance. The post maps the correspondence control by control, cross-references it with the EU AI Act (seven articles directly aligned with 42001: 9, 10, 11, 12, 13, 14, 17), with NIS2 (asset register, incident notification, supply chain) and with ENS (Esquema Nacional de Seguridad, Spain&amp;rsquo;s national security framework, RD 311/2022, Basic/Medium/High categories), lists the seven mandatory minimum documents an auditor asks for, presents the blog&amp;rsquo;s multi-tenant chatbot as a live 42001 checklist, and closes with the five usual traps (confusing 42001 with EU AI Act compliance, over-documenting without measuring, ignoring A.5 until the audit, assuming 27001 covers the AI part, thinking certification is a one-off project rather than a living system).&lt;/p>
&lt;h2 id="the-analogy-the-aircraft-operations-manual">The analogy: the aircraft operations manual&lt;/h2>
&lt;div class="diagram" style="max-width:820px;margin:1.5rem auto;">
&lt;svg viewBox="0 0 820 360" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="ISO 42001 as an aircraft operations manual audited by EASA">
&lt;style>
.i-air{fill:#7aafff;stroke:#444;stroke-width:1.4;rx:8}
.i-man{fill:#ffd76b;stroke:#444;stroke-width:1.4;rx:8}
.i-aud{fill:#a8e6a3;stroke:#444;stroke-width:1.4;rx:8}
.i-ops{fill:#ff8a4c;stroke:#444;stroke-width:1.4;rx:8}
.il{font:600 13px sans-serif;fill:#222}
.is{font:400 11px sans-serif;fill:#555}
.in{font:italic 11px sans-serif;fill:#555}
.iar{stroke:#666;stroke-width:1.6;fill:none;marker-end:url(#mi1)}
&lt;/style>
&lt;defs>&lt;marker id="mi1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#666"/>&lt;/marker>&lt;/defs>
&lt;rect x="20" y="20" width="160" height="60" class="i-air"/>
&lt;text x="100" y="44" text-anchor="middle" class="il">AI system&lt;/text>
&lt;text x="100" y="62" text-anchor="middle" class="is">on-premise LLM platform&lt;/text>
&lt;text x="100" y="76" text-anchor="middle" class="is">(the aircraft)&lt;/text>
&lt;rect x="220" y="20" width="180" height="60" class="i-ops"/>
&lt;text x="310" y="40" text-anchor="middle" class="il">Technical operations&lt;/text>
&lt;text x="310" y="58" text-anchor="middle" class="is">LLMOps pipeline + guardrails +&lt;/text>
&lt;text x="310" y="72" text-anchor="middle" class="is">tracing + retrain (the flights)&lt;/text>
&lt;rect x="440" y="20" width="180" height="60" class="i-man"/>
&lt;text x="530" y="40" text-anchor="middle" class="il">Operations manual&lt;/text>
&lt;text x="530" y="58" text-anchor="middle" class="is">policies + impact assessment +&lt;/text>
&lt;text x="530" y="72" text-anchor="middle" class="is">roles + lineage (ISO 42001)&lt;/text>
&lt;rect x="660" y="20" width="140" height="60" class="i-aud"/>
&lt;text x="730" y="44" text-anchor="middle" class="il">Auditor&lt;/text>
&lt;text x="730" y="62" text-anchor="middle" class="is">certification body&lt;/text>
&lt;text x="730" y="76" text-anchor="middle" class="is">(EASA / Aenor / BSI)&lt;/text>
&lt;path class="iar" d="M180,50 L220,50"/>
&lt;path class="iar" d="M400,50 L440,50"/>
&lt;path class="iar" d="M620,50 L660,50"/>
&lt;rect x="20" y="130" width="780" height="80" class="i-man"/>
&lt;text x="410" y="152" text-anchor="middle" class="il">The 7 Annex SL clauses — the manual's mandatory table of contents&lt;/text>
&lt;text x="410" y="172" text-anchor="middle" class="is">4 Context · 5 Leadership · 6 Planning · 7 Support · 8 Operation · 9 Evaluation · 10 Improvement&lt;/text>
&lt;text x="410" y="190" text-anchor="middle" class="is">Inherited from Annex SL — the same skeleton as ISO 27001 and 9001, which allows management systems to be integrated&lt;/text>
&lt;rect x="20" y="230" width="780" height="80" class="i-aud"/>
&lt;text x="410" y="252" text-anchor="middle" class="il">The 38 Annex A controls — the manual's AI-specific procedures&lt;/text>
&lt;text x="410" y="272" text-anchor="middle" class="is">A.2 Policies · A.3 Org · A.4 Resources · A.5 Impact · A.6 Lifecycle · A.7 Data · A.8 Info to parties · A.9 Use · A.10 Third parties&lt;/text>
&lt;text x="410" y="290" text-anchor="middle" class="is">What separates 42001 from 27001/9001: every control is born from an AI-specific risk (bias, opacity, drift, data supply)&lt;/text>
&lt;text x="410" y="340" text-anchor="middle" class="in">The aircraft flies with its pilots; the manual is audited by the authority. If the manual is incomplete, the aircraft does not certify however well it flies.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;p>A modern aircraft, an A350, a Boeing 787, a drone certified for urban delivery, does not fly because it has good engines. It flies because the organisation that operates it has an Operations Manual approved by the aviation authority (EASA in Europe, the FAA in the US, AESA in Spain as a delegated body). The manual does not contain the engine blueprints, which the manufacturer certifies; it contains the procedures: who is captain on each flight, which checklist is run before each take-off, which periodic inspections happen at 100, 500 and 2,000 flight hours, which external suppliers are authorised to touch which components, what is documented after each incident, what to do when a new alert appears on the panel. The authority does not sit in on every flight: it reads the manual, randomly audits the traceability of past flights against the manual, and if everything adds up, it keeps the certification in place.&lt;/p>
&lt;p>An AI system in production, the multi-tenant chatbot from the &lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">forensic post&lt;/a>, a copilot for lawyers, a credit scoring system, is exactly the same. It flies because the model is good, the LLMOps pipeline is well built, the guardrails catch the bad cases. But it certifies because the organisation operating it has an AIMS (AI Management System) described in an auditable manual. ISO/IEC 42001 is that manual: its mandatory table of contents (Annex SL, seven clauses) and its catalogue of AI-specific controls (Annex A, 38 controls). The auditor does not sit next to the MLOps engineer: they read the AI policy, review the impact assessments of the most recently deployed systems, check that incident retrain is documented, verify third-party contracts, audit a sample of Langfuse traces cross-checked against &lt;code>dataset_hash&lt;/code> and &lt;code>prompt_id&lt;/code>. And if everything adds up, they certify.&lt;/p>
&lt;p>The analogy matters because it frames the right question: 42001 does not certify the model or the code. It certifies the way of operating the complete system. A team can have the best OSS stack in the world and fail the audit because it has no written AI policy and no documented decision about which role (provider vs producer vs customer) it occupies towards its clients. And the reverse: a team with a modest model but with operations-manual discipline can certify without acrobatics.&lt;/p>
&lt;h2 id="isoiec-42001-in-15-seconds">ISO/IEC 42001 in 15 seconds&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Publication&lt;/strong>: December 2023, ISO/IEC JTC 1/SC 42 (the ISO/IEC subcommittee for AI).&lt;/li>
&lt;li>&lt;strong>Status in 2026&lt;/strong>: an active standard, certifiable by accredited bodies (BSI, AENOR, TÜV, Bureau Veritas, A-LIGN, Schellman). Not yet formally recognised as a harmonised standard under the EU AI Act, but it provides the management base to lean on.&lt;/li>
&lt;li>&lt;strong>Compatibility&lt;/strong>: it shares the Annex SL structure with ISO 9001 (quality), 27001 (information security), 27701 (privacy), 22301 (continuity), 20000-1 (IT services). Organisations with integrated management systems (IMS) add it with 20-40% of the effort it would take to implement from scratch.&lt;/li>
&lt;li>&lt;strong>Applicability&lt;/strong>: any organisation that develops, provides, deploys or uses AI systems. It is not limited to developers: a company that consumes a hosted LLM and integrates it into its own product is within scope.&lt;/li>
&lt;li>&lt;strong>Certification&lt;/strong>: a 3-year cycle with an initial audit (Stage 1: documentation review + Stage 2: on-site audit) and annual surveillance audits. Typical cost: 15,000-60,000 € for the initial one depending on size; 6,000-20,000 € per annual surveillance.&lt;/li>
&lt;/ul>
&lt;p>What 42001 does not do:&lt;/p>
&lt;ul>
&lt;li>It does not say which models to use or which thresholds to apply.&lt;/li>
&lt;li>It does not certify the individual model (that is done by specific evaluations such as a NIST AI RMF profile or EU AI Act technical documentation).&lt;/li>
&lt;li>It does not replace the EU AI Act or the GDPR: it is complementary. Implementing it well makes legal compliance easier but does not guarantee it.&lt;/li>
&lt;li>It is not a technical standard for explainability or robustness (those are ISO/IEC 25059, 24029, 23894 and others in the SC 42 family).&lt;/li>
&lt;/ul>
&lt;h2 id="distinction-from-neighbouring-frameworks">Distinction from neighbouring frameworks&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Framework&lt;/th>
&lt;th>Nature&lt;/th>
&lt;th>Scope&lt;/th>
&lt;th>Certifiable&lt;/th>
&lt;th>Overlap with 42001&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>ISO/IEC 42001:2023&lt;/strong>&lt;/td>
&lt;td>Management standard&lt;/td>
&lt;td>AIMS for any AI system&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>EU AI Act&lt;/strong> (Reg. 2024/1689)&lt;/td>
&lt;td>Binding legal regulation&lt;/td>
&lt;td>AI systems in the EU, risk-categorised&lt;/td>
&lt;td>No (it is law)&lt;/td>
&lt;td>Arts 9, 10, 11, 12, 13, 14, 17&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>NIS2&lt;/strong> (Dir. 2022/2555)&lt;/td>
&lt;td>Cybersecurity directive&lt;/td>
&lt;td>Essential/important entities&lt;/td>
&lt;td>Via the national scheme&lt;/td>
&lt;td>Asset register, incident, supply chain&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ENS&lt;/strong> (RD 311/2022)&lt;/td>
&lt;td>Spanish security regulation&lt;/td>
&lt;td>Public sector and its suppliers&lt;/td>
&lt;td>Yes (B/M/A categories)&lt;/td>
&lt;td>Traceability, incident management&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ISO/IEC 27001&lt;/strong>&lt;/td>
&lt;td>Management standard&lt;/td>
&lt;td>Information security&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>Annex SL structure + Annex A overlap&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ISO/IEC 27701&lt;/strong>&lt;/td>
&lt;td>Management standard&lt;/td>
&lt;td>Privacy (extends 27001)&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>PII in training data&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>NIST AI RMF 1.0&lt;/strong>&lt;/td>
&lt;td>Voluntary framework&lt;/td>
&lt;td>AI risk management&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Conceptually aligned, not identical&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ISO/IEC 23894&lt;/strong>&lt;/td>
&lt;td>Technical standard&lt;/td>
&lt;td>AI risk management&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Input to A.5 (impact assessment)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>ISO/IEC 5259&lt;/strong>&lt;/td>
&lt;td>Family&lt;/td>
&lt;td>Data quality for AI&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Input to A.7 (data)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Three distinctions that matter operationally&lt;/strong> and are a recurring source of confusion with clients:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>ISO 42001 ≠ EU AI Act compliance&lt;/strong>. Holding the 42001 certification makes it easier to demonstrate articles 9-17 of the European Regulation, but the Regulation requires things 42001 does not cover directly (CE marking of high-risk systems, registration in the European database, declaration of conformity, specific post-market monitoring). Implementing 42001 first and then filling the AI Act gaps is the standard route.&lt;/li>
&lt;li>&lt;strong>ISO 27001 is not enough&lt;/strong>. 27001 covers confidentiality, integrity and availability of information. The AI side is missing: bias, opacity, model drift, training corpus quality, human evaluation, impact on affected persons. 42001 is a complement, not a substitute. Organisations that already have 27001 in place have an advantage because they share half the documentation.&lt;/li>
&lt;li>&lt;strong>NIS2 ≠ AI safety&lt;/strong>. NIS2 requires registering critical assets, notifying incidents within 24 h, and managing the digital supply chain. AI systems can be within NIS2 scope if they form part of the critical asset (an LLM serving customer support in a financial entity is), but NIS2 does not audit model quality. 42001 does.&lt;/li>
&lt;/ol>
&lt;h2 id="the-seven-clauses-annex-sl-the-mandatory-table-of-contents">The seven clauses (Annex SL): the mandatory table of contents&lt;/h2>
&lt;p>The seven clauses, from clause 4 to clause 10, are common to all modern management standards (Annex SL, also called the &amp;ldquo;High Level Structure&amp;rdquo;). That means an organisation with ISO 9001 or 27001 already in place recognises the structure. Clauses 1-3 are introductory (scope, normative references, terms).&lt;/p>
&lt;h3 id="clause-4--context-of-the-organisation">Clause 4 — Context of the organisation&lt;/h3>
&lt;p>Identify the external context (applicable regulation, customer expectations, social risks) and the internal context (strategy, culture, capabilities). Identify the interested parties and their expectations: customers, regulators, affected persons, employees, suppliers. Define the scope of the AIMS: which AI systems are in and which are out.&lt;/p>
&lt;p>The usual gap: organisations that say &amp;ldquo;all our AI systems are in scope&amp;rdquo; without having enumerated them. The auditor asks for the list. Without a list, there is no scope.&lt;/p>
&lt;h3 id="clause-5--leadership">Clause 5 — Leadership&lt;/h3>
&lt;p>Top management must approve and publish an AI policy, assign roles and responsibilities (typically AI lead, AI risk owner, data officer), and demonstrate commitment through resources, communication and oversight. The policy is an auditable document and must be made available to staff and interested parties.&lt;/p>
&lt;p>The usual gap: a generic AI policy copied off the internet, with no measurables and no concrete objectives. The auditor asks how compliance with it is measured. Without metrics, the policy is theatre.&lt;/p>
&lt;h3 id="clause-6--planning">Clause 6 — Planning&lt;/h3>
&lt;p>Identify risks and opportunities of the AIMS (not of the individual model). Define measurable AI objectives, with deadlines and owners. Plan changes to the AIMS.&lt;/p>
&lt;p>The usual gap: confusing AIMS risks (what happens if we do not document correctly?) with model risks (what happens if the model is biased?). The first belongs here; the second goes to A.5.&lt;/p>
&lt;h3 id="clause-7--support">Clause 7 — Support&lt;/h3>
&lt;p>&lt;strong>Resources&lt;/strong>: human, technical, financial, infrastructure. Competence of personnel (documented training). Awareness of the policy among personnel. Internal and external communication. Documented information (the backbone of the management system: policy, procedures, records, evidence).&lt;/p>
&lt;p>The usual gap: documentation scattered across Confluence/Notion/Drive with no version control and no recorded approvals. The auditor asks about the last change: who approved it? when? on what grounds?&lt;/p>
&lt;h3 id="clause-8--operation">Clause 8 — Operation&lt;/h3>
&lt;p>The most operational clause. It requires:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Operational planning and control&lt;/strong>: how the AI system&amp;rsquo;s lifecycle is managed day to day. → Covered in the blog by the &lt;a href="https://blog.lo0.es/en/posts/six-stage-llmops-pipeline-architecture-and-deep-dive/">six-stage LLMOps pipeline&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Impact assessment&lt;/strong> (linked to A.5).&lt;/li>
&lt;li>&lt;strong>AI system lifecycle management&lt;/strong> (linked to A.6).&lt;/li>
&lt;li>&lt;strong>Data for AI systems&lt;/strong> (linked to A.7).&lt;/li>
&lt;/ul>
&lt;p>This is the clause that materialises in controls A.5, A.6 and A.7. On its own it adds no new requirements: it links to Annex A.&lt;/p>
&lt;h3 id="clause-9--performance-evaluation">Clause 9 — Performance evaluation&lt;/h3>
&lt;p>&lt;strong>Monitoring, measurement, analysis, evaluation&lt;/strong>. Internal audits (planned, with criteria, scope, frequency, recorded results). Management review (typically quarterly or half-yearly, with a mandatory agenda: inputs, evidence, decisions, actions).&lt;/p>
&lt;p>The usual gap: there is OTel tracing + Langfuse + Grafana and plenty of data, but there is no formal management review agenda with documented minutes. The auditor asks for the minutes. Without minutes, there is no review.&lt;/p>
&lt;h3 id="clause-10--improvement">Clause 10 — Improvement&lt;/h3>
&lt;p>&lt;strong>Nonconformity and corrective action&lt;/strong>: when something fails, it is recorded, root cause is analysed, a correction is agreed, effectiveness is verified. Continual improvement: the system evolves deliberately.&lt;/p>
&lt;p>The usual gap: Jira tickets with technical post-mortems but no formal &amp;ldquo;ISO nonconformity&amp;rdquo; record closed out with an effectiveness check. They are two distinct artefacts, even if they can be integrated.&lt;/p>
&lt;h2 id="the-38-annex-a-controls-the-ai-specific-catalogue">The 38 Annex A controls: the AI-specific catalogue&lt;/h2>
&lt;p>Unlike Annex SL (which is common), Annex A is 42001&amp;rsquo;s AI-specific signature. The 38 controls are organised into 9 sections (A.2 to A.10; A.1 is the introduction) covering the AI-specific risks: opacity, bias, drift, corpus quality, impact on affected persons, third-party dependency. Each control has an objective (what it aims to achieve) and implementation guidance in Annex B.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Section&lt;/th>
&lt;th>Focus&lt;/th>
&lt;th># controls&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>A.2&lt;/td>
&lt;td>AI-related policies&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.3&lt;/td>
&lt;td>Internal organisation&lt;/td>
&lt;td>3&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.4&lt;/td>
&lt;td>Resources for AI systems&lt;/td>
&lt;td>6&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.5&lt;/td>
&lt;td>Impact assessment&lt;/td>
&lt;td>5&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.6&lt;/td>
&lt;td>AI system lifecycle&lt;/td>
&lt;td>4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.7&lt;/td>
&lt;td>Data for AI systems&lt;/td>
&lt;td>5&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.8&lt;/td>
&lt;td>Information for interested parties&lt;/td>
&lt;td>4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.9&lt;/td>
&lt;td>Use of AI systems&lt;/td>
&lt;td>3&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A.10&lt;/td>
&lt;td>Third parties and customer relationships&lt;/td>
&lt;td>4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Total&lt;/strong>&lt;/td>
&lt;td>—&lt;/td>
&lt;td>&lt;strong>38&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>What follows is the section-by-section mapping of the controls onto material we have already covered in the blog. The editorial intent is to show which gaps remain once the technical architecture is in place, so that the road to certification does not start from zero.&lt;/p>
&lt;h2 id="cross-mapping-38-controls--blog-posts">Cross-mapping: 38 controls ↔ blog posts&lt;/h2>
&lt;div class="diagram" style="max-width:820px;margin:1.5rem auto;">
&lt;svg viewBox="0 0 820 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Mapping of ISO 42001 Annex A controls onto the blog's on-premise LLM architecture">
&lt;style>
.m-cov{fill:#a8e6a3;stroke:#444;stroke-width:1.4;rx:6}
.m-par{fill:#ffd76b;stroke:#444;stroke-width:1.4;rx:6}
.m-gap{fill:#f4b8b8;stroke:#444;stroke-width:1.4;rx:6}
.m-hdr{fill:#7aafff;stroke:#444;stroke-width:1.4;rx:8}
.ml{font:600 12px sans-serif;fill:#222}
.ms{font:400 10px sans-serif;fill:#444}
.mn{font:italic 10px sans-serif;fill:#555}
&lt;/style>
&lt;rect x="20" y="20" width="780" height="40" class="m-hdr"/>
&lt;text x="410" y="42" text-anchor="middle" class="ml">ISO 42001 Annex A mapped onto the blog's on-premise LLM architecture&lt;/text>
&lt;text x="410" y="55" text-anchor="middle" class="ms">green = covered by code/architecture · yellow = partial · red = governance gap&lt;/text>
&lt;rect x="20" y="80" width="780" height="50" class="m-par"/>
&lt;text x="50" y="100" class="ml">A.2 Policies (2)&lt;/text>
&lt;text x="50" y="116" class="ms">A.2.2 AI policy · A.2.3 Alignment with existing policies&lt;/text>
&lt;text x="500" y="100" class="ml">Status: PARTIAL&lt;/text>
&lt;text x="500" y="116" class="ms">The blog's editorial discipline teaches the angle; a formal written policy per organisation is missing.&lt;/text>
&lt;rect x="20" y="140" width="780" height="50" class="m-gap"/>
&lt;text x="50" y="160" class="ml">A.3 Internal organisation (3)&lt;/text>
&lt;text x="50" y="176" class="ms">A.3.2 Roles and responsibilities · A.3.3 Incident reporting · A.3.4 Stakeholders&lt;/text>
&lt;text x="500" y="160" class="ml">Status: GAP&lt;/text>
&lt;text x="500" y="176" class="ms">Not technical. Requires an organisational decision: AI lead, risk owner, AI committee.&lt;/text>
&lt;rect x="20" y="200" width="780" height="50" class="m-cov"/>
&lt;text x="50" y="220" class="ml">A.4 Resources (6)&lt;/text>
&lt;text x="50" y="236" class="ms">Data, tooling, system, human, financial resources + documentation&lt;/text>
&lt;text x="500" y="220" class="ml">Status: COVERED&lt;/text>
&lt;text x="500" y="236" class="ms">Seven deployment phases + five maturity levels + seven layers + OSS catalogue.&lt;/text>
&lt;rect x="20" y="250" width="780" height="50" class="m-par"/>
&lt;text x="50" y="270" class="ml">A.5 Impact assessment (5)&lt;/text>
&lt;text x="50" y="286" class="ms">AI impact process · documentation · alignment with risks · individuals · society&lt;/text>
&lt;text x="500" y="270" class="ml">Status: PARTIAL&lt;/text>
&lt;text x="500" y="286" class="ms">ISO/IEC 23894 gives the method; a formal per-system impact assessment procedure is missing.&lt;/text>
&lt;rect x="20" y="300" width="780" height="50" class="m-cov"/>
&lt;text x="50" y="320" class="ml">A.6 Lifecycle (4)&lt;/text>
&lt;text x="50" y="336" class="ms">Objectives · design · verification and validation · operation and monitoring · documentation&lt;/text>
&lt;text x="500" y="320" class="ml">Status: COVERED&lt;/text>
&lt;text x="500" y="336" class="ms">Six-stage pipeline + request anatomy + continuous fine-tuning + retrain.&lt;/text>
&lt;rect x="20" y="350" width="780" height="50" class="m-cov"/>
&lt;text x="50" y="370" class="ml">A.7 Data (5)&lt;/text>
&lt;text x="50" y="386" class="ms">Quality · acquisition · provenance · preparation · privacy&lt;/text>
&lt;text x="500" y="370" class="ml">Status: COVERED&lt;/text>
&lt;text x="500" y="386" class="ms">Data versioning + RAG corpus curation + Presidio + LLM Guard Vault.&lt;/text>
&lt;rect x="20" y="400" width="780" height="50" class="m-cov"/>
&lt;text x="50" y="420" class="ml">A.8 Information to parties (4)&lt;/text>
&lt;text x="50" y="436" class="ms">System documentation · information on use · incident communication · external reporting&lt;/text>
&lt;text x="500" y="420" class="ml">Status: COVERED&lt;/text>
&lt;text x="500" y="436" class="ms">OTel GenAI tracing + Langfuse + chunk→trace lineage + guardrail spans.&lt;/text>
&lt;rect x="20" y="450" width="780" height="40" class="m-cov"/>
&lt;text x="50" y="470" class="ml">A.9 Use (3)&lt;/text>
&lt;text x="50" y="484" class="ms">Responsible use processes · use objectives · intended use&lt;/text>
&lt;text x="500" y="470" class="ml">Status: COVERED&lt;/text>
&lt;text x="500" y="484" class="ms">Guardrails + evals + LLM Guard + incident-driven retrain.&lt;/text>
&lt;rect x="20" y="500" width="780" height="40" class="m-cov"/>
&lt;text x="50" y="520" class="ml">A.10 Third parties (4)&lt;/text>
&lt;text x="50" y="534" class="ms">Allocation of responsibilities · supplier · customer · third-party&lt;/text>
&lt;text x="500" y="520" class="ml">Status: COVERED&lt;/text>
&lt;text x="500" y="534" class="ms">OSS vs hyperscalers + OSS catalogue + sovereignty + lock-in analysis.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;h3 id="a2--ai-policies-2-controls-partial">A.2 — AI policies (2 controls): PARTIAL&lt;/h3>
&lt;ul>
&lt;li>A.2.2 AI policy: the organisation must have a documented AI policy, approved by management, reviewed periodically, communicated and available. It covers principles, scope and commitments.&lt;/li>
&lt;li>A.2.3 Alignment with other policies: the AI policy is not an orphan, it aligns with existing security, privacy, quality and ethics policies.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Gap&lt;/strong>: this is not a code matter. The AI policy is a document that the organisation&amp;rsquo;s management approves and signs. The blog teaches a neutral, technical editorial stance (no hype, sovereignty, OSS by default under ENS/NIS2), but that is not any specific organisation&amp;rsquo;s AI policy. Each client has to draft and sign their own.&lt;/p>
&lt;p>&lt;strong>Minimum template&lt;/strong>: 1-2 pages with: principles (transparency, human oversight, fairness, accountability, sustainability), scope (which systems), measurable commitments (annual review, impact assessment before deployment, team training), governance (who approves what).&lt;/p>
&lt;h3 id="a3--internal-organisation-3-controls-gap">A.3 — Internal organisation (3 controls): GAP&lt;/h3>
&lt;ul>
&lt;li>A.3.2 AI roles and responsibilities: roles defined, non-overlapping, communicated. Typically: AI lead, AI risk owner, data steward, AI ethics officer (which may be a single person in small organisations).&lt;/li>
&lt;li>A.3.3 Reporting of AI incidents/concerns: a channel for anyone (internal or external) to report a problem with an AI system, with documented follow-up.&lt;/li>
&lt;li>A.3.4 Identification of stakeholders: a maintained list of stakeholders (customers, affected persons, regulators, partners) and their expectations.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Gap&lt;/strong>: also not technical. An organisational decision. The usual way to cover it is to appoint an AI lead (which may be the CIO, the CTO or a new role depending on size), reuse the security reporting channel (typically already in place because of 27001) by extending it to AI, and maintain a live stakeholder register.&lt;/p>
&lt;h3 id="a4--resources-6-controls-covered">A.4 — Resources (6 controls): COVERED&lt;/h3>
&lt;ul>
&lt;li>A.4.2 Documented information: documentation of the AIMS.&lt;/li>
&lt;li>A.4.3 Data resources: identification and management of the data available for training, evaluation and operation.&lt;/li>
&lt;li>A.4.4 Tooling resources: development, validation and monitoring tools.&lt;/li>
&lt;li>A.4.5 System resources: hardware, infrastructure, compute.&lt;/li>
&lt;li>A.4.6 Human resources: competent personnel.&lt;/li>
&lt;li>A.4.7 Financial resources: budget.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Covered by the blog&lt;/strong> in the three architectural posts:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/anatomy-on-premise-llm-inference-stack-seven-layers/">Anatomy of the stack: seven layers&lt;/a>: A.4.5 system resources, A.4.4 tooling.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/greenfield-deployment-phases-on-premise-llm-platform/">Seven deployment phases&lt;/a>: A.4.5 + A.4.7 (budget implicitly).&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/five-maturity-levels-platform-under-llm/">Five maturity levels&lt;/a>: A.4.5 + A.4.6 (team maturity).&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/oss-catalogue-llmops-six-stages-tool-by-tool/">OSS tooling catalogue&lt;/a>: A.4.4 tooling.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">Data versioning with DVC and lakeFS&lt;/a>: A.4.3 data resources.&lt;/li>
&lt;/ul>
&lt;h3 id="a5--impact-assessment-5-controls-partial">A.5 — Impact assessment (5 controls): PARTIAL&lt;/h3>
&lt;ul>
&lt;li>A.5.2 AI impact assessment process: a documented impact assessment procedure.&lt;/li>
&lt;li>A.5.3 Documentation of AI impact assessments: records of the assessments carried out.&lt;/li>
&lt;li>A.5.4 Alignment with AI risk treatment: the impact assessment&amp;rsquo;s decisions feed risk treatment.&lt;/li>
&lt;li>A.5.5 Impacts on individuals: specific dimensions covering affected persons (rights, discrimination, privacy).&lt;/li>
&lt;li>A.5.6 Societal impacts: dimensions covering society (information, social rights).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Partial&lt;/strong>: the method exists in the ISO/IEC SC 42 family. ISO/IEC 23894:2023 is the technical standard for AI risk management and NIST AI RMF 1.0 is the freely usable American equivalent. But the organisation has to write its procedure and run it per system before deployment. It is not code, it is discipline.&lt;/p>
&lt;p>&lt;strong>Minimum template&lt;/strong> for the impact assessment (3-5 pages per system):&lt;/p>
&lt;ol>
&lt;li>Description of the system (what it does, who it serves, underlying model and stack).&lt;/li>
&lt;li>Stakeholders identified.&lt;/li>
&lt;li>Potential impacts (intended and unintended) on people, groups and society.&lt;/li>
&lt;li>Fairness and robustness metrics applied, with thresholds and results.&lt;/li>
&lt;li>Mitigations applied (guardrails, evals, human oversight, rate limiting).&lt;/li>
&lt;li>Accepted residual risks, with signed justification.&lt;/li>
&lt;li>Review cadence (typically annual, or on substantial change).&lt;/li>
&lt;/ol>
&lt;h3 id="a6--ai-system-lifecycle-4-controls-covered">A.6 — AI system lifecycle (4 controls): COVERED&lt;/h3>
&lt;ul>
&lt;li>A.6.2.2 Objectives for responsible development of AI: responsible development objectives defined per system.&lt;/li>
&lt;li>A.6.2.3 Processes for responsible AI design and development: design and development procedures.&lt;/li>
&lt;li>A.6.2.4 AI system requirements and specifications: formal specification of the system.&lt;/li>
&lt;li>A.6.2.5 Verification and validation: V&amp;amp;V before and during operation.&lt;/li>
&lt;li>A.6.2.6 Deployment: deployment procedures.&lt;/li>
&lt;li>A.6.2.7 Operation and monitoring: continuous operation and monitoring.&lt;/li>
&lt;li>A.6.2.8 Documentation: lifecycle documentation.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Covered by the blog&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/six-stage-llmops-pipeline-architecture-and-deep-dive/">The six-stage LLMOps pipeline&lt;/a>: the complete master map of the lifecycle.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">Anatomy of an LLM request&lt;/a>: the forensic version of how it runs in production.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/continuous-fine-tuning-production-real-traffic-deployed-adapter/">Continuous fine-tuning in production&lt;/a>: the A.6.2.3 + A.6.2.5 + A.6.2.6 + A.6.2.7 discipline in real operation.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">Evals: the layer after tracing&lt;/a>: A.6.2.5 verification and validation.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">Retrain&lt;/a>: A.6.2.7 operation + continuous iteration.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/modern-alignment-dpo-kto-orpo-simpo/">Modern alignment: DPO, KTO, ORPO, SimPO&lt;/a>: A.6.2.3 responsible design.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/mlops-for-llms-landscape-2026/">MLOps landscape 2026&lt;/a>: the tooling landscape.&lt;/li>
&lt;/ul>
&lt;h3 id="a7--data-for-ai-systems-5-controls-covered">A.7 — Data for AI systems (5 controls): COVERED&lt;/h3>
&lt;ul>
&lt;li>A.7.2 Data for development and enhancement of AI: data management policy and procedures for development and improvement.&lt;/li>
&lt;li>A.7.3 Acquisition of data: acquisition procedures (origin, authorisation, quality).&lt;/li>
&lt;li>A.7.4 Quality of data for AI systems: measurable quality criteria.&lt;/li>
&lt;li>A.7.5 Data provenance: data lineage.&lt;/li>
&lt;li>A.7.6 Data preparation: preparation procedures (chunking, anonymisation, labelling).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Covered by the blog&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/rag-corpus-curation-active-librarian/">RAG corpus curation: the active librarian&lt;/a>: A.7.4 + A.7.5 + A.7.6 in detail (five layers: schema, dedup, PII, anti-contamination, lineage).&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">Data versioning: DVC and lakeFS&lt;/a>: A.7.2 + A.7.5 (the four data artefacts versioned with lineage).&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/reranker-hybrid-retrieval-five-chunks-llm-reads/">Reranker and hybrid retrieval&lt;/a>: A.7.6 preparation + filtering.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-guard-anatomy-scanners-langfuse-vllm-litellm/">LLM Guard&lt;/a>: A.7.6 runtime anonymisation with Vault.&lt;/li>
&lt;/ul>
&lt;h3 id="a8--information-for-interested-parties-4-controls-covered">A.8 — Information for interested parties (4 controls): COVERED&lt;/h3>
&lt;ul>
&lt;li>A.8.2 System documentation and information for users: technical documentation available.&lt;/li>
&lt;li>A.8.3 External reporting: the capacity to report to authorities where applicable.&lt;/li>
&lt;li>A.8.4 Communication of incidents to users: notification to users when there is an incident.&lt;/li>
&lt;li>A.8.5 Information for interested parties: information for other stakeholders.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Covered by the blog&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-tracing-opentelemetry-genai/">LLM tracing with OpenTelemetry GenAI&lt;/a>: A.8.2 per-request traceability, A.8.3 the capacity to extract forensic reporting.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/prompt-versioning-contract-five-word-change/">Prompt versioning with Langfuse and MLflow&lt;/a>: A.8.2 documented versioning.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">Guardrails and safety in LLMs&lt;/a>: A.8.4, &lt;code>gen_ai.guardrail.*&lt;/code> spans as the basis for incident notification.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-guard-anatomy-scanners-langfuse-vllm-litellm/">LLM Guard&lt;/a>: A.8.4 incident events for retrain.&lt;/li>
&lt;/ul>
&lt;h3 id="a9--use-of-ai-systems-3-controls-covered">A.9 — Use of AI systems (3 controls): COVERED&lt;/h3>
&lt;ul>
&lt;li>A.9.2 Processes for responsible use of AI: responsible use procedures.&lt;/li>
&lt;li>A.9.3 Objectives for responsible use of AI: objectives.&lt;/li>
&lt;li>A.9.4 Intended use of AI systems: documentation of the intended use.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Covered by the blog&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">Guardrails and safety in LLMs&lt;/a>: A.9.2 + A.9.3 (the four lines of defence).&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/llm-guard-anatomy-scanners-langfuse-vllm-litellm/">LLM Guard&lt;/a>: A.9.2 operational detail.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">Evals: the layer after tracing&lt;/a>: A.9.3 measurement of objectives.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">Retrain&lt;/a>: A.9.2 closed loop.&lt;/li>
&lt;/ul>
&lt;h3 id="a10--third-parties-and-customer-relationships-4-controls-covered">A.10 — Third parties and customer relationships (4 controls): COVERED&lt;/h3>
&lt;ul>
&lt;li>A.10.2 Allocation of responsibilities: distribution of responsibilities between AI roles.&lt;/li>
&lt;li>A.10.3 Suppliers: procedures for AI suppliers.&lt;/li>
&lt;li>A.10.4 Customers: procedures towards customers.&lt;/li>
&lt;li>A.10.5 Third parties: procedures for third parties.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Covered by the blog&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/parallel-catalogue-llmops-stages-open-source-hyperscalers/">The parallel catalogue: OSS vs hyperscalers&lt;/a>: A.10.3 supplier assessment with lock-in and contractual sovereignty analysis.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/oss-catalogue-llmops-six-stages-tool-by-tool/">The OSS catalogue for LLMOps&lt;/a>: A.10.5 third-party inventory (OSS components with licences and governance).&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">Anatomy of an LLM request&lt;/a>: A.10.2 + A.10.4 in the multi-tenant case.&lt;/li>
&lt;/ul>
&lt;h2 id="the-roles-defined-by-the-standard">The roles defined by the standard&lt;/h2>
&lt;p>ISO/IEC 22989:2022 (AI vocabulary, complementary to 42001) defines six roles. Each organisation has to decide which ones it occupies and document it:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Role&lt;/th>
&lt;th>Definition&lt;/th>
&lt;th>Main responsibility&lt;/th>
&lt;th>Example&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>AI provider&lt;/strong>&lt;/td>
&lt;td>Organisation that provides the AI system to others&lt;/td>
&lt;td>Makes the system available&lt;/td>
&lt;td>OpenAI provides GPT-5 via API&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AI producer&lt;/strong>&lt;/td>
&lt;td>Organisation that develops the AI system&lt;/td>
&lt;td>Design, development, validation&lt;/td>
&lt;td>Meta produces Llama 4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AI customer&lt;/strong>&lt;/td>
&lt;td>Organisation that acquires the AI system&lt;/td>
&lt;td>Selection, integration, oversight&lt;/td>
&lt;td>A consultancy integrating an LLM into its own product&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AI partner&lt;/strong>&lt;/td>
&lt;td>Organisation collaborating with another AI role&lt;/td>
&lt;td>Shared&lt;/td>
&lt;td>A GPU hardware manufacturer&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AI subject&lt;/strong>&lt;/td>
&lt;td>Person or group affected by the system&lt;/td>
&lt;td>Recipient of the impact&lt;/td>
&lt;td>The chatbot&amp;rsquo;s end user&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Relevant authority&lt;/strong>&lt;/td>
&lt;td>Regulator with jurisdiction&lt;/td>
&lt;td>External oversight&lt;/td>
&lt;td>AEPD, CNMC, EU AI Act authorities&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>An organisation can occupy several roles at once, which changes the applicable controls. A common pattern in consultancy is: producer + customer + provider towards the end client. The A.10 responsibilities are modulated by the roles.&lt;/p>
&lt;p>&lt;strong>Example role mapping&lt;/strong> for the multi-tenant chatbot from the forensic post:&lt;/p>
&lt;ul>
&lt;li>Base model manufacturer (Llama 4): AI producer of the base model.&lt;/li>
&lt;li>OSS stack operator (the consultancy): AI producer of the LoRA adapter + AI provider of the chatbot to its clients + AI customer of Meta&amp;rsquo;s base model.&lt;/li>
&lt;li>End client (the insurer): AI customer of the chatbot + AI provider of the customer support service.&lt;/li>
&lt;li>The policyholder: AI subject.&lt;/li>
&lt;li>AEPD + EU AI Act authority: relevant authority.&lt;/li>
&lt;/ul>
&lt;p>Each box in the table generates different obligations. The consultancy, being producer of the adapter, must document A.6 (lifecycle) and A.7 (data) for the adapter. Being provider of the chatbot, it must document A.10.4 (customers). Being customer of the base model, it must document A.10.3 (suppliers) and validate that Meta does its part.&lt;/p>
&lt;h2 id="impact-levels-and-proportionality">Impact levels and proportionality&lt;/h2>
&lt;p>42001 does not demand the same rigour of every system. Clause 6.1.2 and control A.5 introduce impact as a modulator. The standard does not define strict categories (unlike the EU AI Act, which does define &amp;ldquo;prohibited / high risk / limited risk / minimal&amp;rdquo;), but it recommends using levels according to severity and probability.&lt;/p>
&lt;p>Industry practice in 2026 aligns the 42001 levels with the EU AI Act categories:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>42001 level&lt;/th>
&lt;th>EU AI Act&lt;/th>
&lt;th>Examples&lt;/th>
&lt;th>Control depth&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>High&lt;/strong>&lt;/td>
&lt;td>High risk (Annex III)&lt;/td>
&lt;td>Credit scoring, HR, health, critical infrastructure&lt;/td>
&lt;td>Exhaustive impact assessment, mandatory human oversight, continuous monitoring, adversarial evals, detailed logging, half-yearly management review&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Medium&lt;/strong>&lt;/td>
&lt;td>Limited risk&lt;/td>
&lt;td>Customer service chatbots that do not automate decisions, productivity assistants&lt;/td>
&lt;td>Standard impact assessment, complete guardrails, annual review&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Low&lt;/strong>&lt;/td>
&lt;td>Minimal risk&lt;/td>
&lt;td>Spam filters, non-personalised content recommendations&lt;/td>
&lt;td>Lightweight impact assessment, basic controls&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>This proportionality is operationally key: implementing 42001 at maximum rigour for a low-risk system is waste; relaxing it on a high-risk one is non-compliance.&lt;/p>
&lt;h2 id="the-seven-minimum-aims-documents">The seven minimum AIMS documents&lt;/h2>
&lt;p>An auditor at Stage 1 (documentation review) asks for between seven and ten documents. The seven essentials:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>AI policy&lt;/strong> (clause 5.2 + A.2.2). 1-2 pages. Approved by management, dated, versioned.&lt;/li>
&lt;li>&lt;strong>AIMS scope&lt;/strong> (clause 4.3). List of AI systems in scope, inclusion criteria.&lt;/li>
&lt;li>&lt;strong>Stakeholder register&lt;/strong> (clause 4.2 + A.3.4). A maintained list with expectations.&lt;/li>
&lt;li>&lt;strong>AIMS risk register&lt;/strong> (clause 6.1). Risks of the management system, not of each model.&lt;/li>
&lt;li>&lt;strong>Impact assessment procedure&lt;/strong> (A.5.2) + records of assessments carried out (A.5.3). The procedure plus one or more assessments done.&lt;/li>
&lt;li>&lt;strong>AI lifecycle procedure&lt;/strong> (A.6.2), which can literally read &amp;ldquo;see the six-stage LLMOps pipeline&amp;rdquo; with references to technical runbooks.&lt;/li>
&lt;li>&lt;strong>Data management procedure&lt;/strong> (A.7.2), covering acquisition, quality, provenance, preparation, anonymisation.&lt;/li>
&lt;/ol>
&lt;p>Common additional documents:&lt;/p>
&lt;ol start="8">
&lt;li>&lt;strong>Responsible use policy&lt;/strong> (A.9.2) with permitted and non-permitted use types.&lt;/li>
&lt;li>&lt;strong>AI third-party management procedure&lt;/strong> (A.10.3, A.10.5) with assessment criteria for AI suppliers.&lt;/li>
&lt;li>Internal audit plan + management review agenda (clauses 9.2 + 9.3).&lt;/li>
&lt;/ol>
&lt;p>For an organisation with a mature &lt;a href="https://blog.lo0.es/en/posts/oss-catalogue-llmops-six-stages-tool-by-tool/">OSS stack&lt;/a>, documents 6 and 7 are references to technical artefacts that already exist (pipeline runbooks, DVC configurations, the PII policy in LLM Guard). The real documentary effort sits in documents 1, 2, 3, 4 and 5.&lt;/p>
&lt;h2 id="applied-case-the-blogs-multi-tenant-chatbot--42001-checklist">Applied case: the blog&amp;rsquo;s multi-tenant chatbot → 42001 checklist&lt;/h2>
&lt;p>We take the system described in the &lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">forensic post&lt;/a>, a multi-tenant customer support chatbot for insurers on an on-premise OSS stack, and walk it as a 42001 auditor would.&lt;/p>
&lt;p>&lt;strong>Clause 4 — Context&lt;/strong>. The AIMS scope includes the chatbot and excludes the internal HR system (a different AI). Stakeholders identified: client insurers, affected policyholders, the AEPD, the EU AI Act authority (once it enters into force on 2 Aug 2026), the supplier Meta (base model), the hardware supplier NVIDIA. → Documented.&lt;/p>
&lt;p>&lt;strong>Clause 5 — Leadership&lt;/strong>. AI policy signed by the CEO, in force. Roles assigned: AI lead (CTO), AI risk owner (CISO), data steward (Head of Data), quarterly AI ethics committee. → Documented.&lt;/p>
&lt;p>&lt;strong>Clause 6 — Planning&lt;/strong>. AIMS risk register: incomplete documentation, team churn, dependency on a single GPU supplier, EU AI Act regulatory change. AIMS objectives for 2026: 42001 certification before Q4, EU AI Act high-risk compliance before 2 Aug. → Documented.&lt;/p>
&lt;p>&lt;strong>Clause 7 — Support&lt;/strong>. Resources: a &lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">4×H100 SXM&lt;/a> cluster + the &lt;a href="https://blog.lo0.es/en/posts/anatomy-on-premise-llm-inference-stack-seven-layers/">seven stack layers&lt;/a>. Competence: 2 MLE + 2 SRE + 1 part-time AI ethics, all with documented training. Communication: AI policy on the intranet + handbook. → Documented.&lt;/p>
&lt;p>&lt;strong>Clause 8 — Operation&lt;/strong>. Operating procedures = the &lt;a href="https://blog.lo0.es/en/posts/six-stage-llmops-pipeline-architecture-and-deep-dive/">six-stage LLMOps pipeline&lt;/a>. Impact assessment run before deployment + annual review + review on substantial change (defined as: base model change, major adapter change, expansion to a new tenant). → Documented.&lt;/p>
&lt;p>&lt;strong>Clause 9 — Evaluation&lt;/strong>. Monitoring: &lt;a href="https://blog.lo0.es/en/posts/llm-tracing-opentelemetry-genai/">Langfuse + Tempo + VictoriaMetrics + Grafana&lt;/a>. Mandatory dashboard metrics: F1 per guardrail category over real traffic, statistical drift, RAG faithfulness, refusal rate. Quarterly internal audit with written criteria. Half-yearly management review with signed minutes. → Documented.&lt;/p>
&lt;p>&lt;strong>Clause 10 — Improvement&lt;/strong>. Incident-driven retrain tickets mapped as nonconformities when severity ≥ HIGH. Documented root cause analysis. Effectiveness verified at the next eval gate. → Documented.&lt;/p>
&lt;p>&lt;strong>Annex A — By section&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>A.2 (Policies): AI policy + responsible use policy. → Documented.&lt;/li>
&lt;li>A.3 (Organisation): roles assigned, reporting channel, stakeholder register. → Documented.&lt;/li>
&lt;li>A.4 (Resources): &lt;a href="https://blog.lo0.es/en/posts/greenfield-deployment-phases-on-premise-llm-platform/">seven deployment phases&lt;/a> + &lt;a href="https://blog.lo0.es/en/posts/oss-catalogue-llmops-six-stages-tool-by-tool/">OSS catalogue&lt;/a> + training plan + annual budget. → Documented.&lt;/li>
&lt;li>A.5 (Impact): procedure + per-system assessments + fairness metrics applied. → Documented.&lt;/li>
&lt;li>A.6 (Lifecycle): &lt;a href="https://blog.lo0.es/en/posts/six-stage-llmops-pipeline-architecture-and-deep-dive/">LLMOps pipeline&lt;/a> + &lt;a href="https://blog.lo0.es/en/posts/continuous-fine-tuning-production-real-traffic-deployed-adapter/">continuous fine-tuning&lt;/a> + &lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">retrain&lt;/a>. → Documented.&lt;/li>
&lt;li>A.7 (Data): &lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">data versioning&lt;/a> + &lt;a href="https://blog.lo0.es/en/posts/rag-corpus-curation-active-librarian/">RAG corpus curation&lt;/a> + &lt;a href="https://blog.lo0.es/en/posts/llm-guard-anatomy-scanners-langfuse-vllm-litellm/">LLM Guard Vault&lt;/a> + Presidio. → Documented.&lt;/li>
&lt;li>A.8 (Information to parties): &lt;a href="https://blog.lo0.es/en/posts/llm-tracing-opentelemetry-genai/">OTel tracing&lt;/a> + Langfuse + &lt;code>gen_ai.guardrail.*&lt;/code> spans + notification to tenants within SLA. → Documented.&lt;/li>
&lt;li>A.9 (Use): &lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">guardrails&lt;/a> + &lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">evals&lt;/a> + responsible use policy. → Documented.&lt;/li>
&lt;li>A.10 (Third parties): &lt;a href="https://blog.lo0.es/en/posts/parallel-catalogue-llmops-stages-open-source-hyperscalers/">OSS vs hyperscalers&lt;/a> with lock-in analysis + Meta contract for the base model + contracts with tenants. → Documented.&lt;/li>
&lt;/ul>
&lt;p>Result of the walkthrough: certifiable. The typical gaps (A.2.2 written policy, A.3 roles, A.5 impact assessment procedure) are covered as formal documents. The operational clauses (8, 9, 10) lean on the blog&amp;rsquo;s technical architecture. The distance between &amp;ldquo;having the architecture&amp;rdquo; and &amp;ldquo;having certification&amp;rdquo; is measured in documentary discipline, not in code.&lt;/p>
&lt;h2 id="cross-mapping-with-the-eu-ai-act-nis2-and-ens">Cross-mapping with the EU AI Act, NIS2 and ENS&lt;/h2>
&lt;h3 id="eu-ai-act-reg-20241689--seven-directly-aligned-articles">EU AI Act (Reg. 2024/1689) — seven directly aligned articles&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>EU AI Act article&lt;/th>
&lt;th>Topic&lt;/th>
&lt;th>Aligned 42001 control&lt;/th>
&lt;th>Applies to&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Art. 9&lt;/td>
&lt;td>Risk management system&lt;/td>
&lt;td>A.5 + clause 6&lt;/td>
&lt;td>High-risk systems&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Art. 10&lt;/td>
&lt;td>Data and data governance&lt;/td>
&lt;td>A.7 (all)&lt;/td>
&lt;td>High-risk systems&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Art. 11&lt;/td>
&lt;td>Technical documentation&lt;/td>
&lt;td>A.6 + A.4.2&lt;/td>
&lt;td>High-risk systems&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Art. 12&lt;/td>
&lt;td>Record-keeping (logs)&lt;/td>
&lt;td>A.8.2 + OTel tracing&lt;/td>
&lt;td>High-risk systems&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Art. 13&lt;/td>
&lt;td>Transparency to deployers&lt;/td>
&lt;td>A.8.5 + A.10.4&lt;/td>
&lt;td>High-risk systems&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Art. 14&lt;/td>
&lt;td>Human oversight&lt;/td>
&lt;td>A.9.2 + documented oversight&lt;/td>
&lt;td>High-risk systems&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Art. 17&lt;/td>
&lt;td>Quality management system&lt;/td>
&lt;td>Clauses 4-10&lt;/td>
&lt;td>High-risk providers&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The main obligations for high-risk systems enter into application on 2 August 2026. Implementing 42001 now builds the management base that deadline demands.&lt;/p>
&lt;p>What is missing for EU AI Act compliance that 42001 does not cover:&lt;/p>
&lt;ul>
&lt;li>CE conformity of high-risk systems (declaration of conformity, marking, registration in the EU database).&lt;/li>
&lt;li>The specific post-market monitoring required by Art. 72.&lt;/li>
&lt;li>Serious incident reporting to authorities within legal deadlines (not only to users).&lt;/li>
&lt;li>Transparency obligations towards users for limited-risk systems (Art. 50): chatbots, deepfakes, generated content.&lt;/li>
&lt;li>The Art. 5 prohibitions (social scoring, manipulation, real-time biometrics with exceptions).&lt;/li>
&lt;/ul>
&lt;h3 id="nis2-dir-20222555--three-pillars-with-overlap">NIS2 (Dir. 2022/2555) — three pillars with overlap&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Asset register&lt;/strong> (Art. 21.2.f): AI systems within NIS2 scope must be in the asset inventory. → Overlaps with A.4 + clause 4.3 (scope).&lt;/li>
&lt;li>&lt;strong>Incident notification&lt;/strong> (Art. 23): significant incidents are notified within 24 h (initial alert) + 72 h (detailed report). → Overlaps with A.3.3 (reporting) + clause 10 (improvement).&lt;/li>
&lt;li>&lt;strong>Supply chain security&lt;/strong> (Art. 21.2.d): security assessment of the digital supply chain. → Overlaps with A.10.3 (suppliers).&lt;/li>
&lt;/ul>
&lt;p>For essential NIS2 entities that also use AI systems, 42001 covers the AI-specific part that NIS2 requires by inference but does not spell out.&lt;/p>
&lt;h3 id="ens-rd-3112022">ENS (RD 311/2022)&lt;/h3>
&lt;p>The Spanish Esquema Nacional de Seguridad already expressly addresses AI in its Annex II (ENS controls). The Basic/Medium/High categories align with the 42001 impact levels. The ENS controls on traceability (op.exp.8), activity logging (op.exp.10) and incident management (op.exp.7) are covered by the same technical artefacts as A.8 and A.5 of 42001. An organisation certified at ENS High category with AI systems is a reasonable effort away from adding 42001.&lt;/p>
&lt;h2 id="the-five-usual-certification-traps">The five usual certification traps&lt;/h2>
&lt;p>&lt;strong>Trap 1 — Confusing 42001 with EU AI Act compliance.&lt;/strong> Passing the 42001 audit does not imply conformity with the European Regulation. They are distinct universes with a 60-70% overlap. The trap surfaces when the client asks for CE marking of the high-risk system and the organisation produces only the 42001 certificate.&lt;/p>
&lt;p>&lt;strong>Trap 2 — Over-documenting.&lt;/strong> Two-hundred-page manuals with procedures copied from templates, with no measurables and no evidence of application. The auditor asks for the last execution of the procedure; with no records, the procedures are ornament. The practical rule: prefer short documents referencing live technical artefacts to long self-contained ones.&lt;/p>
&lt;p>&lt;strong>Trap 3 — Under-measuring.&lt;/strong> Defining AIMS objectives with no operational metrics. &amp;ldquo;Improve model quality&amp;rdquo; is a null objective; &amp;ldquo;F1 per guardrail category ≥ 0.85 over real traffic, measured weekly, reviewed quarterly in the management review&amp;rdquo; is an auditable objective. The blog has insisted on this in every post on &lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">evals&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">guardrails&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">retrain&lt;/a>.&lt;/p>
&lt;p>&lt;strong>Trap 4 — Ignoring A.5 until audit day.&lt;/strong> The impact assessment is the most underrated control and the first one the auditor asks for. Without per-system assessments carried out before deployment, there is no way to demonstrate A.5. The trap surfaces when there is no longer time to produce credible retrospective assessments.&lt;/p>
&lt;p>&lt;strong>Trap 5 — Assuming 27001 covers the AI part.&lt;/strong> Organisations that already have 27001 sometimes think &amp;ldquo;we have half of it done&amp;rdquo;. That is true for Annex SL (structure) and for A.5/A.6/A.7 of 27001 (not of 42001) as far as infosec goes. It is false for A.5 of 42001 (impact assessment), A.7 of 42001 (AI-specific data quality), A.9 (responsible use) and A.10.4 (AI customers). You have to add, not assume.&lt;/p>
&lt;h2 id="what-we-have-not-covered-upcoming-posts">What we have not covered (upcoming posts)&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Concrete templates&lt;/strong> of the seven mandatory documents, with drafting examples and metrics. Material for a post along the lines of &amp;ldquo;The AIMS manual in 7 documents&amp;rdquo; with a reference frame.&lt;/li>
&lt;li>&lt;strong>Detailed article-by-article mapping to the EU AI Act&lt;/strong> with the checklist of technical evidence derivable from the blog&amp;rsquo;s OSS stack. Especially Arts 11 (technical documentation), 14 (human oversight) and 72 (post-market monitoring).&lt;/li>
&lt;li>&lt;strong>The combined ENS High category + 42001 case&lt;/strong>: which ENS controls are covered by which AIMS artefacts, avoiding duplication.&lt;/li>
&lt;li>&lt;strong>NIST AI RMF 1.0 vs 42001 comparison&lt;/strong>: many international clients ask for both. How the same artefacts are recycled to satisfy the two frameworks.&lt;/li>
&lt;li>&lt;strong>42001 for LLM agents and MCP&lt;/strong>: the new dimensions that emerge when the AI system is agentic (excessive agency, tool use, graduated autonomy). The &lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">guardrails&lt;/a> post introduced line 3 (tool GR); 42001 has open gaps in this terrain and SC 42 is working on addenda.&lt;/li>
&lt;/ul>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>ISO/IEC 42001:2023&lt;/strong> — &lt;em>Information technology — Artificial intelligence — Management system&lt;/em>. ISO. &lt;a href="https://www.iso.org/standard/81230.html">https://www.iso.org/standard/81230.html&lt;/a>.&lt;/li>
&lt;li>&lt;strong>ISO/IEC 22989:2022&lt;/strong> — &lt;em>Information technology — Artificial intelligence — Artificial intelligence concepts and terminology&lt;/em>. Define los roles AI provider/producer/customer/partner/subject.&lt;/li>
&lt;li>&lt;strong>ISO/IEC 23894:2023&lt;/strong> — &lt;em>Information technology — Artificial intelligence — Guidance on risk management&lt;/em>. Insumo de A.5.&lt;/li>
&lt;li>&lt;strong>ISO/IEC 38507:2022&lt;/strong> — &lt;em>Governance implications of the use of AI by organizations&lt;/em>. Complemento de gobierno.&lt;/li>
&lt;li>&lt;strong>ISO/IEC 5259&lt;/strong> — &lt;em>Data quality for analytics and machine learning&lt;/em> (familia). Insumo de A.7.&lt;/li>
&lt;li>&lt;strong>EU AI Act (Regulation 2024/1689)&lt;/strong> — texto consolidado en EUR-Lex. Entrada en vigor de obligaciones de alto riesgo: 2 ago 2026.&lt;/li>
&lt;li>&lt;strong>NIS2 (Directive 2022/2555)&lt;/strong> — texto consolidado en EUR-Lex.&lt;/li>
&lt;li>&lt;strong>ENS — Real Decreto 311/2022&lt;/strong> — Esquema Nacional de Seguridad, BOE-A-2022-7191.&lt;/li>
&lt;li>&lt;strong>NIST AI RMF 1.0&lt;/strong> (2023) — &lt;a href="https://www.nist.gov/itl/ai-risk-management-framework">https://www.nist.gov/itl/ai-risk-management-framework&lt;/a>.&lt;/li>
&lt;li>&lt;strong>EUR-Lex EU AI Act consolidated text&lt;/strong> — &lt;a href="https://eur-lex.europa.eu/eli/reg/2024/1689">https://eur-lex.europa.eu/eli/reg/2024/1689&lt;/a>.&lt;/li>
&lt;li>A-LIGN / BSI / Schellman — blogs sobre experiencia de auditoría 42001 con casos reales 2024-2025.&lt;/li>
&lt;/ul>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/hardening-secrets-sovereign-llm-stack-defence-in-depth/">Hardening and secrets in the sovereign LLM stack: defence in depth&lt;/a> — the operational security controls that hold up the AIMS.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/six-stage-llmops-pipeline-architecture-and-deep-dive/">The six-stage LLMOps pipeline&lt;/a> — the operating procedure that materialises A.6 lifecycle with no extra work.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">Anatomy of an LLM request in production&lt;/a> — the forensic case walked through as a 42001 checklist in the &amp;ldquo;applied case&amp;rdquo; section of this post.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/anatomy-on-premise-llm-inference-stack-seven-layers/">Seven layers of the on-premise LLM inference stack&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/greenfield-deployment-phases-on-premise-llm-platform/">seven deployment phases&lt;/a> — direct material for A.4 resources.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/five-maturity-levels-platform-under-llm/">Five maturity levels of the platform&lt;/a> — how to justify the proportionality of the controls against the existing maturity level.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">Data versioning with DVC and lakeFS&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/rag-corpus-curation-active-librarian/">RAG corpus curation&lt;/a> — A.7 data covered in detail.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/llm-tracing-opentelemetry-genai/">LLM tracing with OpenTelemetry GenAI&lt;/a> — A.8 information to interested parties through standardised traceability.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">Guardrails and safety in LLMs&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/llm-guard-anatomy-scanners-langfuse-vllm-litellm/">LLM Guard&lt;/a> — A.9 responsible use.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">Evals: the layer after tracing&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/llm-as-judge-exam-marker-not-oracle/">LLM-as-judge&lt;/a> — A.6.2.5 verification and validation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">Retrain: closing the feedback → dataset → adapter loop&lt;/a> — clause 10 continual improvement + the incident-driven loop that feeds formal nonconformities.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/parallel-catalogue-llmops-stages-open-source-hyperscalers/">The parallel catalogue: OSS vs hyperscalers&lt;/a> — A.10.3 supplier assessment with a structural analysis of lock-in and contractual sovereignty; a direct input to the AI supplier register.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/oss-catalogue-llmops-six-stages-tool-by-tool/">The OSS catalogue for LLMOps&lt;/a> — A.10.5 inventory of OSS third parties with documented licence, governance and maturity.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/mlops-for-llms-landscape-2026/">LLM-specific MLOps in 2026: the landscape&lt;/a> — the operational context in which the AIMS runs and is audited.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/eu-ai-act-technical-dossier-on-premise-llm-architecture/">EU AI Act: the technical dossier, article by article&lt;/a> — the sister post on Regulation (EU) 2024/1689; it moves from the management system down to the directly applicable legal obligations, with deadlines, penalties and a control-to-article mapping.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/technical-controls-ens-iso-42001-eu-ai-act-cross-mapping/">Technical controls: the cross-mapping of ENS × ISO 42001 × EU AI Act&lt;/a> — the third post of the governance trilogy; it goes down to the detail of the 25 technical controls common to the three frameworks, with the master table of triple compliance and the labelling of evidence.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/incident-response-runbooks-llm-inference-kafka-keep/">Incident response runbooks for LLMs with Keep + Kafka&lt;/a> — the operational materialisation of clause 10 (continual improvement) and the WORM trace A.8.2 demands: every incident opens a nonconformity, triggers a postmortem, updates the runbook and is recorded in the Kafka &lt;code>audit.actions&lt;/code> topic.&lt;/p>
&lt;/li>
&lt;/ul></description></item></channel></rss>