EU AI Act Art.12: Logging Obligations as an Operational Compliance System — Event Classification, Retention Architecture, and Python LoggingEventRegistry (2026)
Article 12 of the EU AI Act is the audit trail backbone of high-risk AI compliance. But most implementation guides stop at "enable logs." Art.12 requires something more precise: a classification system that distinguishes which events are legally mandatory, a retention architecture that separates operational logs from archival records, and a retrieval mechanism that can produce MSA-ready evidence packages under a market surveillance investigation timeline.
The August 2, 2026 deadline applies to all high-risk AI systems placed on the EU market or put into service on or after that date. Systems placed on the market before 2026 that receive substantial modifications under Art.11(4) must also comply. Every provider that has not built Art.12-compliant logging before market placement is deploying a non-compliant system.
This guide covers the full Art.12 operational system: what paragraphs 1–3 actually require, the Event Classification Matrix distinguishing mandatory from recommended logging, how to build a Python LoggingEventRegistry that operationalises compliance, SIEM integration patterns for Art.12 audit trails, the six-month vs. ten-year retention split, and the cross-reference map connecting Art.12 to Art.9, Art.11, Art.13, and Art.14.
What Art.12 Actually Requires: The Three-Paragraph Architecture
Art.12 contains three paragraphs, each creating a distinct obligation layer:
Art.12(1) — Automatic logging capability: High-risk AI systems must be designed and developed with capabilities enabling the automatic recording of events ("logs") throughout the system's lifetime. The word "automatic" eliminates discretionary logging — events within scope must be captured without human decision at the time of capture.
Art.12(2) — Specific event categories: The logging capabilities must ensure, to the degree appropriate to the intended purpose, the ability to: (a) record the period of each use; (b) reference the input data for which the search, detection, recommendation, or decision was made, wherever feasible with regard to data protection; (c) identify persons involved in the verification of results where human oversight is mandated under Art.14; (d) identify major changes in the system functionality and version.
Art.12(3) — Retention obligations: For high-risk AI systems used by public authorities or financial institutions, the logs are kept by those entities for at least six months, or for any other period established in applicable EU or national law. Providers deploying systems to operators must contractually ensure log retention — the legal obligation falls on the operator, but the provider must ensure the technical capability exists.
The critical insight: Art.12(1) is a design obligation (build the capability), Art.12(2) is a content obligation (capture specific event types), and Art.12(3) is a retention obligation (preserve specific logs for specific actors). A system that logs everything but doesn't retain it for the right parties fails Art.12(3). A system that retains logs but doesn't capture Art.12(2)(a)–(d) events fails Art.12(2).
The Event Classification Matrix: Mandatory vs. Recommended
Not every log event has the same compliance status under Art.12. The matrix below distinguishes mandatory events (required by Art.12(2) text), structurally required events (implied by Art.9/Art.14 obligations that feed Art.12), and recommended events (operational best practice that survives MSA scrutiny).
| Event Category | Art.12 Status | Source Paragraph | Evidence Function |
|---|---|---|---|
| Session start / end timestamps | Mandatory | Art.12(2)(a) | Proves "period of each use" |
| Input data reference (hash/ID, not content) | Mandatory where feasible | Art.12(2)(b) | Links decision to input set |
| Human oversight verification (Art.14 decisions) | Mandatory | Art.12(2)(c) | Documents human-in-the-loop events |
| Major version/functionality changes | Mandatory | Art.12(2)(d) | Ties to Art.11(4) substantial modification |
| Risk score changes (Art.9 RMS outputs) | Structurally required | Art.9 + Art.12(1) | Demonstrates Art.9 runtime execution |
| Model inference outputs (decision type, confidence) | Structurally required | Art.13 + Art.12(1) | Supports transparency obligation |
| Data quality flags (Art.10 triggers) | Structurally required | Art.10 + Art.12(1) | Links data governance to decisions |
| Configuration changes (thresholds, parameters) | Recommended | Art.12(2)(d) scope | MSA audit evidence |
| Access events (who queried the system) | Recommended | Art.14 scope | Operator accountability chain |
| Error and exception events | Recommended | Art.9(6) scope | Demonstrates incident detection capability |
| Model update events (minor, below substantial modification threshold) | Recommended | Art.11 scope | Version tracking for non-substantial changes |
| Monitoring alert events | Recommended | Art.9(8) scope | Post-market monitoring evidence |
The distinction between mandatory and recommended matters for system design. Mandatory events must be captured even when the system is under load, even when storage is constrained, and even when the input data itself cannot be retained due to GDPR. The feasibility qualifier in Art.12(2)(b) applies only to the input data content — the input reference (a hash, an ID, a timestamp) must always be logged.
Python LoggingEventRegistry Implementation
The LoggingEventRegistry is the operational core of Art.12 compliance. It classifies incoming events, applies retention tagging, and provides MSA package generation:
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Optional, Dict, Any, List
import hashlib
import json
import uuid
class EventMandatoryStatus(Enum):
MANDATORY = "mandatory" # Art.12(2) explicit text
STRUCTURAL = "structural" # Art.9/Art.14/Art.13 implied
RECOMMENDED = "recommended" # Best practice, not legally mandated
class RetentionTier(Enum):
OPERATIONAL = "operational" # 6 months (Art.12(3) minimum)
ARCHIVAL = "archival" # 10 years (Art.11(3) technical documentation)
EPHEMERAL = "ephemeral" # Session-only, GDPR-driven deletion
@dataclass
class Art12Event:
event_id: str
event_type: str
mandatory_status: EventMandatoryStatus
retention_tier: RetentionTier
timestamp: datetime
session_id: str
input_reference: Optional[str] # Hash, not content (Art.12(2)(b))
human_oversight_actor: Optional[str] # Art.12(2)(c)
version_reference: Optional[str] # Art.12(2)(d)
payload: Dict[str, Any] = field(default_factory=dict)
art12_paragraph: str = ""
class LoggingEventRegistry:
"""Art.12-compliant event logging registry for high-risk AI systems."""
# Event type → (mandatory_status, retention_tier, art12_paragraph)
EVENT_CLASSIFICATION: Dict[str, tuple] = {
"session.start": (EventMandatoryStatus.MANDATORY, RetentionTier.OPERATIONAL, "Art.12(2)(a)"),
"session.end": (EventMandatoryStatus.MANDATORY, RetentionTier.OPERATIONAL, "Art.12(2)(a)"),
"input.reference": (EventMandatoryStatus.MANDATORY, RetentionTier.OPERATIONAL, "Art.12(2)(b)"),
"human_oversight.decision": (EventMandatoryStatus.MANDATORY, RetentionTier.OPERATIONAL, "Art.12(2)(c)"),
"human_oversight.override": (EventMandatoryStatus.MANDATORY, RetentionTier.ARCHIVAL, "Art.12(2)(c)"),
"system.version_change": (EventMandatoryStatus.MANDATORY, RetentionTier.ARCHIVAL, "Art.12(2)(d)"),
"system.major_functionality_change": (EventMandatoryStatus.MANDATORY, RetentionTier.ARCHIVAL, "Art.12(2)(d)"),
"risk_score.change": (EventMandatoryStatus.STRUCTURAL, RetentionTier.OPERATIONAL, "Art.9+Art.12(1)"),
"model.inference": (EventMandatoryStatus.STRUCTURAL, RetentionTier.OPERATIONAL, "Art.13+Art.12(1)"),
"data_quality.flag": (EventMandatoryStatus.STRUCTURAL, RetentionTier.OPERATIONAL, "Art.10+Art.12(1)"),
"config.change": (EventMandatoryStatus.RECOMMENDED, RetentionTier.OPERATIONAL, "Art.12(2)(d) scope"),
"access.query": (EventMandatoryStatus.RECOMMENDED, RetentionTier.OPERATIONAL, "Art.14 scope"),
"system.error": (EventMandatoryStatus.RECOMMENDED, RetentionTier.OPERATIONAL, "Art.9(6) scope"),
"model.minor_update": (EventMandatoryStatus.RECOMMENDED, RetentionTier.OPERATIONAL, "Art.11 scope"),
"monitoring.alert": (EventMandatoryStatus.RECOMMENDED, RetentionTier.OPERATIONAL, "Art.9(8) scope"),
}
def __init__(self, system_id: str, system_version: str):
self.system_id = system_id
self.system_version = system_version
self.events: List[Art12Event] = []
self._current_session_id: Optional[str] = None
def start_session(self) -> str:
"""Art.12(2)(a): Record period of each use — session start."""
self._current_session_id = str(uuid.uuid4())
self.log_event(
event_type="session.start",
payload={"system_id": self.system_id, "version": self.system_version}
)
return self._current_session_id
def end_session(self) -> None:
"""Art.12(2)(a): Record period of each use — session end."""
self.log_event(event_type="session.end", payload={})
self._current_session_id = None
def log_input_reference(self, input_data: Any) -> str:
"""Art.12(2)(b): Log input reference (hash, not content) where feasible."""
input_bytes = json.dumps(input_data, sort_keys=True, default=str).encode()
input_hash = hashlib.sha256(input_bytes).hexdigest()
self.log_event(
event_type="input.reference",
input_reference=input_hash,
payload={"input_hash": input_hash, "input_type": type(input_data).__name__}
)
return input_hash
def log_human_oversight(
self,
actor_id: str,
decision: str,
override: bool = False,
rationale: str = ""
) -> None:
"""Art.12(2)(c): Record persons involved in human oversight verification."""
event_type = "human_oversight.override" if override else "human_oversight.decision"
self.log_event(
event_type=event_type,
human_oversight_actor=actor_id,
payload={
"decision": decision,
"override": override,
"rationale": rationale,
"art14_triggered": True
}
)
def log_version_change(
self,
new_version: str,
change_type: str,
is_substantial_modification: bool
) -> None:
"""Art.12(2)(d): Record major changes in system functionality and version."""
event_type = (
"system.major_functionality_change"
if is_substantial_modification
else "system.version_change"
)
self.log_event(
event_type=event_type,
version_reference=new_version,
payload={
"previous_version": self.system_version,
"new_version": new_version,
"change_type": change_type,
"substantial_modification": is_substantial_modification,
"art11_4_triggered": is_substantial_modification
}
)
if is_substantial_modification:
self.system_version = new_version
def log_event(
self,
event_type: str,
input_reference: Optional[str] = None,
human_oversight_actor: Optional[str] = None,
version_reference: Optional[str] = None,
payload: Optional[Dict] = None
) -> Art12Event:
classification = self.EVENT_CLASSIFICATION.get(event_type)
if classification is None:
mandatory_status = EventMandatoryStatus.RECOMMENDED
retention_tier = RetentionTier.OPERATIONAL
art12_paragraph = "unclassified"
else:
mandatory_status, retention_tier, art12_paragraph = classification
event = Art12Event(
event_id=str(uuid.uuid4()),
event_type=event_type,
mandatory_status=mandatory_status,
retention_tier=retention_tier,
timestamp=datetime.now(timezone.utc),
session_id=self._current_session_id or "no-session",
input_reference=input_reference,
human_oversight_actor=human_oversight_actor,
version_reference=version_reference,
payload=payload or {},
art12_paragraph=art12_paragraph
)
self.events.append(event)
return event
def get_mandatory_events(self) -> List[Art12Event]:
"""Return only Art.12(2)-mandatory events for MSA audit package."""
return [e for e in self.events if e.mandatory_status == EventMandatoryStatus.MANDATORY]
def generate_msa_evidence_package(self, investigation_period: tuple) -> Dict:
"""Generate MSA-ready evidence package for a specific investigation period."""
start_dt, end_dt = investigation_period
period_events = [
e for e in self.events
if start_dt <= e.timestamp <= end_dt
]
mandatory_in_period = [
e for e in period_events
if e.mandatory_status == EventMandatoryStatus.MANDATORY
]
return {
"package_id": str(uuid.uuid4()),
"system_id": self.system_id,
"investigation_period": {
"start": start_dt.isoformat(),
"end": end_dt.isoformat()
},
"art12_compliance_summary": {
"total_events": len(period_events),
"mandatory_events": len(mandatory_in_period),
"session_coverage": self._verify_session_coverage(period_events),
"human_oversight_events": len([
e for e in mandatory_in_period
if "human_oversight" in e.event_type
]),
"version_change_events": len([
e for e in mandatory_in_period
if "version_change" in e.event_type or "functionality_change" in e.event_type
])
},
"events": [
{
"event_id": e.event_id,
"event_type": e.event_type,
"timestamp": e.timestamp.isoformat(),
"art12_paragraph": e.art12_paragraph,
"mandatory_status": e.mandatory_status.value,
"session_id": e.session_id,
"input_reference": e.input_reference,
"human_oversight_actor": e.human_oversight_actor,
"version_reference": e.version_reference
}
for e in mandatory_in_period
]
}
def _verify_session_coverage(self, events: List[Art12Event]) -> bool:
"""Verify every session.start has a corresponding session.end."""
sessions_started = {e.session_id for e in events if e.event_type == "session.start"}
sessions_ended = {e.session_id for e in events if e.event_type == "session.end"}
return sessions_started == sessions_ended
The generate_msa_evidence_package method is the operational payoff: when a market surveillance authority initiates an investigation, your legal team can extract the Art.12(2) mandatory events for the investigation period in a structured JSON package that maps each event to its Art.12 paragraph source.
SIEM Integration Architecture for Art.12 Compliance
Most production high-risk AI deployments already have a SIEM. Art.12 compliance does not require a separate logging stack — but it requires that your SIEM configuration captures Art.12(2) event categories as structured data, not raw application logs.
The integration pattern uses three layers:
Layer 1 — Structured log emission: The LoggingEventRegistry emits events in a structured format (JSON) with Art.12 classification metadata. Each event includes mandatory_status and art12_paragraph fields that SIEM parsing rules can use for filtering and alerting.
Layer 2 — SIEM ingestion with Art.12 tagging: Configure your SIEM (Elastic SIEM, Splunk, Wazuh, Graylog) to parse the art12_paragraph field and apply a retention policy tag. Art.12 mandatory events get a retention=6m tag; Art.11(3) archival events (version changes, substantial modifications) get a retention=10y tag.
import structlog
import json
from typing import Dict, Any
class Art12SIEMEmitter:
"""Emits Art.12-tagged log events in structured format for SIEM ingestion."""
def __init__(self, registry: LoggingEventRegistry, siem_destination: str = "stdout"):
self.registry = registry
self.siem_destination = siem_destination
self.logger = structlog.get_logger().bind(
system_id=registry.system_id,
log_schema="art12_v1"
)
def emit(self, event: Art12Event) -> None:
"""Emit event as structured log entry with Art.12 compliance metadata."""
log_entry = {
"event_id": event.event_id,
"event_type": event.event_type,
"timestamp": event.timestamp.isoformat(),
"session_id": event.session_id,
"system_id": self.registry.system_id,
"system_version": self.registry.system_version,
# Art.12 classification fields — used by SIEM retention policy engine
"art12_paragraph": event.art12_paragraph,
"art12_mandatory_status": event.mandatory_status.value,
"art12_retention_tier": event.retention_tier.value,
# Art.12(2)(b): input reference
"input_reference": event.input_reference,
# Art.12(2)(c): human oversight
"human_oversight_actor": event.human_oversight_actor,
# Art.12(2)(d): version reference
"version_reference": event.version_reference,
# Event payload (non-PII, MSA-visible)
"payload": event.payload
}
self.logger.info("art12_event", **log_entry)
def emit_all_pending(self) -> int:
"""Emit all unemitted events from registry. Returns count emitted."""
emitted = 0
for event in self.registry.events:
self.emit(event)
emitted += 1
return emitted
Layer 3 — Retention policy enforcement: Configure SIEM retention policies per tag:
| Retention Tag | SIEM Policy | Legal Source | Verification |
|---|---|---|---|
art12_retention_tier: operational | 6 months minimum | Art.12(3) | MSA audit readiness |
art12_retention_tier: archival | 10 years | Art.11(3) + Art.12(2)(d) | Substantial modification record |
art12_retention_tier: ephemeral | GDPR-driven deletion | GDPR Art.5(1)(e) | Data minimisation compliance |
The key architectural decision is where the 6-month vs. 10-year boundary falls. Version change events (system.version_change, system.major_functionality_change) are archival-tier by default in the LoggingEventRegistry because they feed Art.11(3) technical documentation retention. All other Art.12(2) mandatory events are operational-tier (6-month minimum).
The Six-Month vs. Ten-Year Retention Split
The retention architecture creates two separate storage tiers with different performance and cost profiles:
Tier 1 — Operational logs (6-month minimum):
- All Art.12(2)(a)–(c) mandatory events
- All structural events (Art.9, Art.13, Art.14 feeds)
- Recommended events (access, errors, monitoring)
- Hot storage: fast retrieval for MSA investigations
- GDPR-compliant deletion at retention boundary
Tier 2 — Archival records (10-year):
- Art.12(2)(d) version and functionality change events
- Human oversight override events (elevated risk significance)
- Substantial modification records (Art.11(4) triggers)
- Cold storage: cost-optimised, slower retrieval acceptable
- Immutable storage preferred (WORM, object lock)
from datetime import timedelta
from typing import List, Tuple
class Art12RetentionManager:
"""Manages Art.12 log retention enforcement and GDPR-compliant deletion."""
OPERATIONAL_RETENTION = timedelta(days=183) # 6 months (conservative)
ARCHIVAL_RETENTION = timedelta(days=3650) # 10 years (Art.11(3))
def __init__(self, registry: LoggingEventRegistry):
self.registry = registry
def get_retention_deadline(self, event: Art12Event) -> datetime:
"""Return the earliest deletion-safe date for an event."""
if event.retention_tier == RetentionTier.ARCHIVAL:
return event.timestamp + self.ARCHIVAL_RETENTION
elif event.retention_tier == RetentionTier.OPERATIONAL:
return event.timestamp + self.OPERATIONAL_RETENTION
else: # EPHEMERAL — GDPR-driven, no fixed Art.12 minimum
return event.timestamp # Delete at GDPR-defined boundary
def identify_expired_events(self, reference_date: datetime) -> Tuple[List[Art12Event], List[Art12Event]]:
"""
Returns (safe_to_delete, must_retain) based on Art.12 retention requirements.
Note: safe_to_delete still requires GDPR legal basis check before deletion.
"""
safe_to_delete = []
must_retain = []
for event in self.registry.events:
deadline = self.get_retention_deadline(event)
if reference_date > deadline:
safe_to_delete.append(event)
else:
must_retain.append(event)
return safe_to_delete, must_retain
def generate_retention_compliance_report(self) -> Dict:
"""Generate Art.12 retention compliance report for MSA evidence."""
now = datetime.now(timezone.utc)
operational_events = [e for e in self.registry.events if e.retention_tier == RetentionTier.OPERATIONAL]
archival_events = [e for e in self.registry.events if e.retention_tier == RetentionTier.ARCHIVAL]
return {
"report_date": now.isoformat(),
"system_id": self.registry.system_id,
"retention_tiers": {
"operational": {
"count": len(operational_events),
"minimum_retention_days": self.OPERATIONAL_RETENTION.days,
"legal_source": "Art.12(3)"
},
"archival": {
"count": len(archival_events),
"minimum_retention_days": self.ARCHIVAL_RETENTION.days,
"legal_source": "Art.11(3) + Art.12(2)(d)"
}
}
}
The identify_expired_events method returns events that have passed their Art.12 retention deadline — but deletion still requires a separate GDPR legal basis check. Art.12 retention and GDPR data minimisation create a compliance window: you must not delete before the Art.12 deadline, and you should delete after the GDPR retention period ends. For personal data embedded in logs (user IDs, input references linked to natural persons), this window may be narrower than the Art.12 six-month minimum.
The GDPR × Art.12 Retention Conflict: Operational Resolution
Art.12 requires retention; GDPR Art.5(1)(e) requires storage limitation. The conflict resolves through three design patterns:
Pattern 1 — Reference logging, not content logging: Log the SHA-256 hash of input data (Art.12(2)(b) compliant) rather than the data itself. The hash is not personal data under GDPR Recital 26 if the original data cannot be reconstructed from it. The log_input_reference method in the LoggingEventRegistry implements this pattern by default.
Pattern 2 — Pseudonymisation of actor IDs: Art.12(2)(c) requires identifying persons involved in human oversight. Pseudonymise actor IDs (store actor_hash rather than actor_name) and maintain the pseudonymisation key separately under GDPR Art.25 data protection by design. The MSA can request de-pseudonymisation under Art.58 GDPR supervisory authority cooperation mechanisms.
Pattern 3 — Tiered deletion by data category: Design your log schema so that PII-adjacent fields (actor IDs, input references linked to natural persons) can be selectively deleted at the GDPR retention boundary without invalidating the structural Art.12 log record. A log record with a null actor_id field (post-GDPR deletion) still proves the human oversight event occurred at a specific timestamp — the Art.12(2)(c) obligation is met even without the PII content.
Art.12 × Art.11 × Art.9 × Art.13 × Art.14 Cross-Reference System
Art.12 does not operate in isolation. The logging obligation is the evidence layer that makes other Art.9–15 obligations verifiable:
| Art.12 Event Type | Feeds | Compliance Function |
|---|---|---|
session.start/end (Art.12(2)(a)) | Art.9(6) testing records | Proves operational use period in post-market monitoring |
input.reference (Art.12(2)(b)) | Art.10 data governance | Links production inputs to training data distribution analysis |
human_oversight.decision (Art.12(2)(c)) | Art.14 human oversight | Documents human-in-the-loop compliance at decision point |
system.version_change (Art.12(2)(d)) | Art.11(4) substantial modification | Feeds technical documentation update obligation |
risk_score.change | Art.9 RMS runtime | Proves risk management system executed during operational use |
model.inference | Art.13 transparency | Supports output traceability for transparency obligation |
data_quality.flag | Art.10(3) bias monitoring | Evidence for bias detection and correction measures |
monitoring.alert | Art.9(8) post-market | Post-market monitoring system activation evidence |
The cross-reference table reveals why Art.12 logging is not just a standalone obligation: it is the audit evidence layer for the entire Art.9–15 compliance stack. An MSA investigating a high-risk AI incident will look at Art.12 logs first — they are the primary evidence source for whether Art.9 (risk management), Art.14 (human oversight), and Art.13 (transparency) obligations were actually implemented in the operational system.
MSA Investigation Readiness: The Six-Point Evidence Checklist
When a market surveillance authority initiates an investigation under Art.74–80 of the EU AI Act, Art.12 logs become the primary evidence set. Your investigation readiness depends on six operational capabilities:
Checklist Point 1 — Session coverage completeness: Can you produce a complete list of all sessions (start/end pairs) for the investigation period? Gaps in session coverage suggest logging system failures that may constitute Art.12(1) violations.
Checklist Point 2 — Input reference retrievability: Can you retrieve input references (hashes) for every inference decision in the investigation period? Missing input references for Art.12(2)(b) mandatory events indicate structural non-compliance.
Checklist Point 3 — Human oversight chain: For every Art.14-mandated human review in the investigation period, can you produce the human_oversight.decision event with actor ID, decision outcome, and timestamp? Gaps here directly evidence Art.12(2)(c) non-compliance.
Checklist Point 4 — Version history completeness: Can you produce a complete version change log for the investigation period? If a substantial modification occurred and the system.major_functionality_change event is missing, this constitutes both Art.12(2)(d) and Art.11(4) non-compliance.
Checklist Point 5 — Retention verification: Can you demonstrate that all Art.12(3) mandatory retention periods were met? The MSA will check whether logs were deleted before the six-month minimum.
Checklist Point 6 — Package generation time: The MSA investigation timeline is tight. Can you generate a structured evidence package within 24 hours of an investigation notice? The generate_msa_evidence_package method is the technical implementation of this requirement.
SME Logging Considerations
Micro and small enterprises operating high-risk AI systems benefit from the Art.11(2) documentation simplification but have no equivalent simplification under Art.12. The logging obligation in Art.12(2) applies in full regardless of operator size.
The practical SME minimum viable Art.12 implementation:
| Event Category | SME Minimum | Storage Estimate |
|---|---|---|
| Session start/end | JSON log per session | ~200 bytes/session |
| Input reference | SHA-256 hash | ~64 bytes/inference |
| Human oversight | Decision record + actor ID | ~500 bytes/decision |
| Version change | Structured change record | ~1 KB/change |
For a system processing 1,000 inferences per day with 50 human oversight decisions, the six-month operational log volume is approximately 15 MB — trivially storable on any infrastructure. The cost barrier to Art.12 compliance is architectural (building the classification system), not storage (the data volumes are small).
Implementation Checklist — 20 Points
Art.12(1) — Capability design:
- Automatic logging enabled from system initialisation, not user activation
- Logging cannot be disabled by operator without provider notification
- Logging functions in degraded system states (failover, maintenance)
- Log emission is synchronous for mandatory events (no drop-on-backpressure)
Art.12(2) — Event coverage:
- Session start/end captured for every operational use period
- Input references (hashes) logged for every inference call where feasible
- Human oversight decisions captured with actor ID and timestamp
- Version change events logged for every minor update, major change, and substantial modification
Art.12(3) — Retention architecture:
- Operational logs retained for minimum 6 months (183 days conservative)
- Archival events (version changes) retained for 10 years
- GDPR-compliant deletion process maintains Art.12 structural records after PII deletion
- Retention policy enforced automatically, not by manual deletion workflow
SIEM integration:
- Art.12 classification metadata (
mandatory_status,art12_paragraph) emitted in structured format - SIEM retention policies configured per
retention_tierfield - Alert configured for mandatory event emission failures
MSA readiness:
-
generate_msa_evidence_packagetested for a representative investigation period - Evidence package generation time < 24 hours from request
- Human oversight chain complete for all Art.14-mandated decisions in test period
- Version history complete and linked to Art.11(4) technical documentation updates
- Retention compliance report can be generated on demand
Common Failure Modes
Failure 1 — Logging the wrong events as mandatory: Treating all log events as Art.12(2) mandatory creates an unmanageable MSA evidence set. Use the Event Classification Matrix to separate mandatory from recommended events from system design time.
Failure 2 — Content logging instead of reference logging: Logging input data content (not hashes) creates a GDPR retention conflict that cannot be resolved. The log_input_reference pattern (hash, not content) satisfies Art.12(2)(b) without creating personal data retention obligations.
Failure 3 — Missing version change logging for minor updates: Art.12(2)(d) requires logging "major changes in system functionality and version." In practice, log every version change — the classification as major vs. minor can be determined later, and missing a log is worse than over-logging.
Failure 4 — Session gaps in the operational log: Every inference session must have a paired start/end event. Gaps in session coverage are the most visible Art.12(1) non-compliance signal in an MSA audit.
Failure 5 — No MSA package generation capability: If you cannot extract Art.12 mandatory events in a structured format within 24 hours, you are operationally non-compliant even if the logs technically exist. Build generate_msa_evidence_package before market placement, not after an investigation notice.
See Also
- EU AI Act Art.11: Technical Documentation Lifecycle 2026 — Art.12(2)(d) version change events feed directly into Art.11(4) substantial modification triggers and the 10-year technical documentation retention obligation
- EU AI Act Art.13: Transparency Disclosure Management 2026 — IFU version changes are Art.12(2)(d) major changes; Art.13 generates mandatory Art.12 log events on every substantial modification
See also: EU AI Act Art.9: Risk Management System as a Living Document — FMEA Integration, Runtime Monitoring, and RMS Version Control (2026) — Art.12 operational logs are the primary evidence source for Art.9 risk management system runtime execution.