2885 words
14 min read

watsonx.governance Enforcement Tracking — Sampled Compliance and the Unevidenced Run

By · Solutions Architect · Docker Captain · IBM Champion
Dark stacked slabs with cyan-lit gaps, watsonx.governance evidence sampling

Sixteen months. That is how far Regulation (EU) 2026/1744 moved the AI Act’s high-risk deadline when it entered into force on 27 July 2026, pushing standalone Annex III obligations from 2 August 2026 out to 2 December 2027. The deferral moved the deadline. It did not move the record, and sampled compliance is the shape of what is left: governance evidence collected in windows, agent behavior that runs without one. I reviewed the configuration and the evidence model for IBM watsonx.governance Enforcement Tracking, which shipped on 11 August 2026, against the question an auditor actually asks.

This failure shape is older than agents. In banking it was hourly configuration snapshots, and the snapshot became the definition of what the configuration was, because nothing between snapshots existed on paper. In telecom it was a five-minute polling interval on the network management system, and every incident timeline quietly rounded to five minutes. The interval always wins. When the interval is the only record, the interval becomes the truth, and everything between two samples becomes testimony instead of artifact. I wrote about the same gap on the infrastructure side in the Apply Gate your auditor will ask about.

What sampled compliance looks like in a running agent#

Here is how most teams ship a containerized agent today.

# kubernetes 1.30 — claims-triage agent as most teams ship it
apiVersion: apps/v1
kind: Deployment
metadata:
name: claims-triage-agent
spec:
replicas: 3
selector:
matchLabels:
app: claims-triage-agent
template:
metadata:
labels:
app: claims-triage-agent
spec:
containers:
- name: agent
image: registry.internal/claims-triage-agent:1.4.2
env:
- name: ORCHESTRATE_ENDPOINT
valueFrom:
secretKeyRef:
name: wxo-credentials
key: endpoint

Nothing on that manifest connects a single execution to a governance record. The agent runs, it writes to stdout, and the only durable statement about its behavior is whatever the evaluation schedule captured. Ask for run 4192 and you get a shrug and a log query against whatever retention the cluster happens to have.

The change is small and it is structural.

# kubernetes 1.30 — same agent, every execution addressable
apiVersion: apps/v1
kind: Deployment
metadata:
name: claims-triage-agent
labels:
ai.use-case-id: uc-claims-triage-eu
ai.policy-version: "2026.08.1"
spec:
replicas: 3
selector:
matchLabels:
app: claims-triage-agent
template:
metadata:
labels:
app: claims-triage-agent
ai.use-case-id: uc-claims-triage-eu
ai.policy-version: "2026.08.1"
spec:
containers:
- name: agent
image: registry.internal/claims-triage-agent:1.4.2
env:
- name: ORCHESTRATE_ENDPOINT
valueFrom:
secretKeyRef:
name: wxo-credentials
key: endpoint
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://otel-collector.observability:4317
- name: OTEL_RESOURCE_ATTRIBUTES
value: ai.use_case.id=uc-claims-triage-eu,ai.policy.version=2026.08.1

Two additions. The workload now carries the same use-case identifier the governance system uses, and every execution emits a span under that identifier with the policy version that was live at the time. You are not storing prompts or outputs. You are storing the fact that a run occurred, under which policy, touching which tools. That is the join key, and without it the two systems can never be reconciled at all.

Twenty years of production infrastructure and this pattern has arrived in three different decades of stack: snapshot intervals in banking, SNMP polling in telecom, and a change-management record sampling a pipeline that fired hundreds of times a day in a Series D environment. Each time the fix was the same and each time it looked like overhead until the first audit.

The interval is the record. Everything between two samples is a story.

Why this keeps happening#

The regulation asks for two different things and vendors ship the easier one first, because it is the one with a clean product surface.

Article 12 of the AI Act requires high-risk systems to automatically record events across the lifetime of the system, with three stated purposes: identifying risk situations under Article 79, feeding post-market monitoring under Article 72, and supporting deployer oversight under Article 26, paragraph 5. Article 19 sets the retention floor for providers at six months, longer where other Union or national law applies, and Article 26, paragraph 6 places a parallel six-month duty on deployers for the logs under their control. Article 18 puts technical documentation on a ten-year clock. None of those clauses describes a threshold check. They describe a per-event record with a retention obligation attached.

Enforcement Tracking, per IBM’s announcement of 11 August 2026, connects watsonx Orchestrate to watsonx.governance, associates agents with governance use cases and controls, retrieves evaluation metrics on a scheduled basis for production agents, evaluates agents still in development on demand, and writes pass or breach results against business-set thresholds directly into the governance record. Hallucination, helpfulness and toxicity are the named metrics. That is a control attestation pipeline, automated, and it removes the quarterly scramble of assembling evidence by hand.

The second thing is harder to productize because it is specific to your deployment. A vendor cannot know your correlation identifier, your policy versioning scheme, or which of your systems holds the execution ledger. So it stays where it has always stayed. The vendor shipped the evidence pipeline. The join key is still yours.

Risk and blast radius#

Direct exposure runs through retention and traceability rather than through the metrics themselves. If your agent falls inside Annex III, the Article 12 record has to exist and the Article 19 and Article 26, paragraph 6 floors mean six months of it has to still be there when someone asks. A threshold snapshot taken on a schedule does not satisfy a per-event recording obligation, and no amount of dashboard polish converts one into the other. Penalty tiers under the Act put transparency and high-risk breaches at up to 15 million euro or 3% of worldwide turnover, with prohibited practices at 35 million euro or 7%.

Read what the deferral actually deferred, because the headline flattens it. Annex III systems moved to 2 December 2027 and high-risk AI embedded in already-regulated products under Annex I moved to 2 August 2028. Article 50 transparency duties did not move at all; they took effect on 2 August 2026 as originally scheduled, alongside the prohibited-practices regime that has applied since February 2025 and the GPAI obligations running since August 2025. The Omnibus attached one new near-term date to them: systems already on the market before 2 August 2026 have until 2 December 2026 to carry machine-readable marking of AI-generated content. Sixteen months of relief on Annex III. Fourteen weeks on the marking obligation. And the stated reason for the delay was procedural rather than political: the CEN and CENELEC harmonised standards were not finished and several Member States had not designated their competent authorities. A deadline that moved because the referee was late is not a signal that the rules got softer.

Systemic exposure is the part the deferral headline hides. Systems already placed on the EU market before the new deadlines are grandfathered out of full high-risk compliance unless they are later substantially modified, and regulators have not yet defined that threshold. For an agent that reasons over changing context, calls tools dynamically, and gets its prompts and models updated on a normal release cadence, “substantially modified” is not a rhetorical question. It is an evidentiary one, and answering it requires a change record joined to an execution record. Sampling cannot produce that answer in either direction.

Before assuming Article 26, paragraph 6 is your ceiling, check which side of Article 25 you are standing on. A deployer who puts their own name or trademark on a high-risk system, or substantially modifies one already placed on the market, is treated as its provider. Assemble agents on a vendor platform, ship them under your own brand, and the provider obligations follow: the Article 12 recording capability and the Article 19 retention floor, not merely the deployer’s duty to keep whatever the platform hands you. The original provider is relieved of them at that moment and owes you cooperation instead. The platform did not transfer the obligation. It transferred the role.

Then the arithmetic. An agent invoked every five minutes executes 288 times a day, or 8,640 times over thirty days. Against a daily metrics synchronisation, that month closes with 30 evidence records covering 8,640 executions, or 0.35% of runs individually evidenced. Tighten the schedule to hourly and you get 720 records against 8,640 runs, which is 8.3%. The schedule is the right design for attesting a control. It is the wrong artifact for reconstructing an incident.

A deferral you cannot document is not a deferral.

Options compared#

Storage figures below are back-of-envelope from stated unit sizes, not measured: trace metadata at about 1.5 KB per span, full payload capture at about 1 MB per run average for a tool-calling agent, hash digest at about 150 bytes.

ApproachEvidence granularityStorage per 1M runsQuestion it answers at auditFit
Scheduled enforcement tracking (watsonx.governance)One record per evaluation windowUnder 10 MBWere thresholds met at time TControl attestation. Required baseline, not the event record
Per-execution trace metadata (OpenTelemetry)One span per run, no payload~1.5 GBDid run X occur, when, under which policy, touching which toolsThe reconciliation layer. Cheapest path to Article 12 traceability
Full request and response archivalEvery prompt and output~1 TBWhat exactly did the agent say and doHighest fidelity, highest GDPR and cost exposure
Sampled payload capture (1% plus all breaches)Statistical, full on breach~15 GBWhat does a normal run look like, plus every bad one in fullPragmatic middle for non-regulated estates
Hash-chained execution digestOne signed digest per run~150 MBHas the record been altered since it was writtenTamper-evidence for regulated or contested estates

Most teams need rows one and two together. Row one without row two is a control with no event behind it.

Framework: reconciling the execution ledger with the evidence ledger#

Layer 1: use-case binding and execution inventory (week 1)#

Start inside watsonx.governance, because that is where the identifier everything else joins to gets defined. Connect the watsonx Orchestrate instance, associate each agent with the AI use case and the controls it has to satisfy, and set the thresholds the business is prepared to defend in front of an auditor.

Two options in that configuration change what the control is worth, and both are easy to leave on their defaults. Agents still in development can be evaluated on demand before they ship, which moves a threshold breach from the first production window back to build time. And a metric that crosses its limit can drive an automated workflow rather than only writing a result into the record. Turn both on. A control that pages someone beats a control that files something.

That is the attestation half, and it is the half a vendor can ship for you. The other half is the identifier itself. Most organizations cannot yet say how many agents are running at all, which is the prerequisite problem behind Agent Sprawl. Give every run an identity carrying the same use-case id watsonx.governance now knows it by: one span per execution, three attributes that matter, no payload.

# opentelemetry-sdk 1.x — one span per agent execution, carrying the governance join key
from opentelemetry import trace
tracer = trace.get_tracer("wxo.agent.claims_triage")
def run_agent(request, ai_use_case_id: str, policy_version: str):
with tracer.start_as_current_span("agent.execution") as span:
span.set_attribute("ai.use_case.id", ai_use_case_id)
span.set_attribute("ai.policy.version", policy_version)
span.set_attribute("ai.agent.id", "claims-triage")
result = agent.invoke(request)
span.set_attribute("ai.tools.invoked", ",".join(result.tool_calls))
span.set_attribute("ai.outcome", result.status)
return result

Ship spans to an OpenTelemetry Collector and land them in a store you control, with retention set to your longest applicable obligation rather than your default. Six months is the AI Act floor. Financial services deployers answer to their own regime under Article 26, paragraph 6, measured in years. Set it at your ceiling now. Raising retention later does not recover what already aged out.

Owner: AI governance lead for the watsonx.governance binding, platform engineer for the spans.

Layer 2: policy binding (week 2)#

The join key belongs in infrastructure, not in a runbook. Terraform tags the agent’s execution role with the same use-case identifier the governance system uses, and a permissions boundary states the blast radius as code.

# terraform 1.x, aws provider 5.x — bound the agent's execution role, carry the governance join key
resource "aws_iam_role" "agent_execution" {
name = "wxo-agent-claims-triage"
permissions_boundary = aws_iam_policy.agent_boundary.arn
assume_role_policy = data.aws_iam_policy_document.agent_trust.json
tags = {
ai_use_case_id = var.ai_use_case_id # same key on every span and every evidence record
policy_version = var.policy_version
}
}
resource "aws_iam_policy" "agent_boundary" {
name = "wxo-agent-boundary"
policy = data.aws_iam_policy_document.agent_boundary.json
}
data "aws_iam_policy_document" "agent_trust" {
statement {
effect = "Allow"
actions = ["sts:AssumeRoleWithWebIdentity"]
principals {
type = "Federated"
identifiers = [var.oidc_provider_arn]
}
condition {
test = "StringEquals"
variable = "${var.oidc_provider_host}:sub"
values = ["system:serviceaccount:default:claims-triage-agent"]
}
}
}
variable "ai_use_case_id" { type = string }
variable "policy_version" { type = string }
variable "oidc_provider_arn" { type = string }
variable "oidc_provider_host" { type = string }
data "aws_iam_policy_document" "agent_boundary" {
statement {
effect = "Allow"
actions = ["s3:GetObject"]
resources = ["arn:aws:s3:::claims-reference/*"]
}
statement {
effect = "Deny"
actions = ["iam:*", "sts:AssumeRole"]
resources = ["*"]
}
}

If the estate runs HCP Terraform or Terraform Enterprise, gate the plan before the apply. Sentinel reads the plan directly, so a role provisioned without the governance tag never reaches state.

# sentinel policy — refuse a plan that provisions an agent role with no governance use case
import "tfplan/v2" as tfplan
required_tag = "ai_use_case_id"
agent_roles = filter tfplan.resource_changes as _, rc {
rc.type is "aws_iam_role" and
rc.mode is "managed" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
main = rule {
all agent_roles as _, rc {
rc.change.after.tags[required_tag] else "" is not ""
}
}

That catches the resource at provision time. The second gate catches the workload at admission time, because a correctly tagged role says nothing about whether the pod that assumes it emits anything.

# opa 1.x / conftest — block agent deploys that cannot be joined to a governance use case
package agent.evidence
deny contains msg if {
input.kind == "Deployment"
not input.metadata.labels["ai.use-case-id"]
msg := "missing ai.use-case-id label: runs cannot be joined to governance evidence"
}
deny contains msg if {
input.kind == "Deployment"
some c in input.spec.template.spec.containers
not otlp_configured(c)
msg := sprintf("container %q has no OTEL_EXPORTER_OTLP_ENDPOINT: executions will not be recorded", [c.name])
}
otlp_configured(c) if {
some e in c.env
e.name == "OTEL_EXPORTER_OTLP_ENDPOINT"
}

Owner: security engineer.

Layer 3: reconciled audit (week 3 onward)#

Two ledgers, one key, one number that tells you whether the record has holes in it.

# prometheus 2.x — alert when agent runs have no matching governance evidence record
groups:
- name: agent-evidence-coverage
interval: 5m
rules:
- record: agent:runs_unevidenced:ratio1h
expr: |
1 - (
sum by (ai_use_case_id) (increase(agent_runs_evidenced_total[1h]))
/
clamp_min(sum by (ai_use_case_id) (increase(agent_runs_total[1h])), 1)
)
- alert: AgentEvidenceCoverageBelowFloor
expr: agent:runs_unevidenced:ratio1h > 0.05
for: 15m
labels:
severity: page
control: eu-ai-act-art-12
annotations:
summary: Agent runs without a matching governance evidence record
description: >
{{ $value | humanizePercentage }} of runs for use case
{{ $labels.ai_use_case_id }} have no evidence record in the last hour.

The alert does not say the agent misbehaved. It says the record has a hole in it, which is the failure you cannot fix retroactively. Put the same ratio on a Grafana panel beside your evaluation metrics, so the governance lead reads both in one frame. Quality tells you how the agent behaved. Coverage tells you whether you can prove it.

Owner: SRE, with the AI governance lead setting the floor.

Tradeoffs#

Adoption friction is real and it is mostly week one. Instrumenting spans across every agent path takes a sprint, the OTLP collector and its retention tier need a budget line, and someone has to own a versioning scheme for policies that was previously implicit. At roughly 1.5 KB per span you are looking at about 1.5 GB per million executions before compression, which is a rounding error next to any observability bill you already pay.

Ignoring it costs asymmetrically. The evidence you did not collect cannot be reconstructed after the request arrives, and the request arrives at the worst possible moment: a complaint, an incident, a due-diligence questionnaire, a market surveillance authority asking under Article 26, paragraph 6. The sixteen-month deferral makes this feel optional. It is the opposite. Sixteen months is exactly how long you now have to accumulate the record that proves your system was not substantially modified.

The closing argument#

Adopt Enforcement Tracking for what it is. It automates the control attestation, it writes pass and breach evidence without a human assembling screenshots, and for teams currently maintaining governance evidence by hand it removes real work on day one. Hold on treating it as the audit trail, because a threshold snapshot and a per-event record are different artifacts with different retention clocks. The gap is not a defect in the release; it is the part that was always going to be specific to your deployment, and the join key was always going to be yours to define. The storage is cheap. The reconstruction is not.

Sources#

Discussion#

If you have wired agent executions to a governance record, or you have decided the sampled attestation is enough for your risk profile, drop a comment on the post. Counterarguments are welcome and the comment thread is where I respond first. For longer back-and-forth with senior practitioners, join the discussion on Discord.


Vladimir Mikhalev

Docker Captain  ·  IBM Champion  ·  AWS Community Builder

The Verdict — production-tested analysis on YouTube.

The Verdict

Inconvenient truths about shipping in the AI era

Container security, platform engineering, and the agentic shift — tested in production, argued without the hype. The verdict reaches your inbox the moment there's one worth sending.

Related Posts

Same category
  1. 1
    The Intake Gate Your CISO Is Missing — 300 Million AI Chat Messages Were Public by Default
    AI & MLOps · Half of AI-enabled apps on major backends carry severe misconfigurations. Inside the 300M-message Firebase breach and a 3-layer protocol to stop Agent Sprawl.
  2. 2
    Docker MCP — Turn GPT into a Real DevOps Assistant (Slack, GitHub, Stripe)
    AI & MLOps · Turn GPT into a real DevOps assistant with Docker MCP. How AI agents automate Slack, GitHub, Stripe, and more — securely and at scale.
  3. 3
    Why AI Fails Without DevOps — What No One Tells You
    AI & MLOps · Without DevOps, AI fails fast. Learn how containers, CI/CD, and GitOps keep LLMs and ML systems like OpenAI and Hugging Face running at scale.
  4. 4
    Install Ollama Using Docker Compose
    AI & MLOps · Deploy Ollama locally with Docker Compose and Traefik. Step-by-step guide for setting up LLMs with HTTPS, domain routing, and secure container orchestration.

Random Posts

Random
  1. 1
    Install OTRS Using Docker Compose
    Self-Hosting · Learn how to deploy OTRS Helpdesk with Docker Compose, secured by Traefik and Let's Encrypt. Step-by-step guide for Ubuntu-based self-hosted ticketing.
  2. 2
    Configure Exchange Server 2019
    SysAdmin & IT Pro · Learn how to configure Exchange Server 2019 with step-by-step instructions for mailbox databases, DNS records, certificates, send connectors, and more.
  3. 3
    Minimize Programs on Windows 10 Startup
    SysAdmin & IT Pro · Learn how to automatically start programs minimized on Windows 10 startup. Step-by-step guide using Task Manager, Startup folder, and shortcut settings.
  4. 4
    Docker supply chain hardening — from Scout D to OpenSSF 7.8 on a 730K-pull image
    DevOps & Cloud · How I hardened a 1M-pull public Docker image from Scout grade D to OpenSSF Scorecard 7.8 — multi-stage build, cosign, SLSA provenance, non-root default.
watsonx.governance Enforcement Tracking — Sampled Compliance and the Unevidenced Run
https://heyvaldemar.com/watsonx-governance-enforcement-tracking-sampled-compliance/
Author
Vladimir Mikhalev
Published
2026-08-24
License
CC BY-NC-SA 4.0