th.
Architecture Decision: Use a hash-chained structure where each entry references the hash of the previous entry. This creates a tamper-evident ledger. Logs should be serialized as JSONL (JSON Lines) for efficient streaming and storage compatibility.
Implementation:
import { createHash } from 'crypto';
import { appendFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
export interface AuditLogEntry {
id: string;
timestamp: string;
systemId: string;
inputPayloadHash: string;
outputPayloadHash: string;
previousHash: string;
signature: string;
}
export class ImmutableAuditLogger {
private readonly retentionPeriodMs: number = 6 * 30 * 24 * 60 * 60 * 1000; // 6 months
private readonly logDir: string;
private readonly signingKey: string;
constructor(config: { logDir: string; signingKey: string }) {
this.logDir = config.logDir;
this.signingKey = config.signingKey;
if (!existsSync(this.logDir)) {
mkdirSync(this.logDir, { recursive: true });
}
}
public recordInference(
systemId: string,
input: unknown,
output: unknown
): AuditLogEntry {
const lastHash = this.getLastHash();
const entry: AuditLogEntry = {
id: crypto.randomUUID(),
timestamp: new Date().toISOString(),
systemId,
inputPayloadHash: this.hashPayload(input),
outputPayloadHash: this.hashPayload(output),
previousHash: lastHash,
signature: '' // Placeholder
};
entry.signature = this.signEntry(entry);
this.persist(entry);
this.enforceRetention();
return entry;
}
private hashPayload(payload: unknown): string {
return createHash('sha256')
.update(JSON.stringify(payload))
.digest('hex');
}
private signEntry(entry: AuditLogEntry): string {
const content = `${entry.id}:${entry.timestamp}:${entry.previousHash}`;
return createHash('sha256')
.update(content + this.signingKey)
.digest('hex');
}
private getLastHash(): string {
const logFile = join(this.logDir, 'audit.log');
if (!existsSync(logFile)) return 'genesis';
const content = appendFileSync(logFile, { encoding: 'utf8' });
const lines = content.trim().split('\n');
if (lines.length === 0) return 'genesis';
const lastEntry: AuditLogEntry = JSON.parse(lines[lines.length - 1]);
return lastEntry.signature;
}
private persist(entry: AuditLogEntry): void {
const logFile = join(this.logDir, 'audit.log');
appendFileSync(logFile, JSON.stringify(entry) + '\n');
}
private enforceRetention(): void {
const logFile = join(this.logDir, 'audit.log');
if (!existsSync(logFile)) return;
const content = appendFileSync(logFile, { encoding: 'utf8' });
const lines = content.trim().split('\n');
const cutoff = Date.now() - this.retentionPeriodMs;
const validLines = lines.filter(line => {
const entry = JSON.parse(line);
return new Date(entry.timestamp).getTime() > cutoff;
});
// In production, use atomic write to prevent corruption
// This is a simplified representation
if (validLines.length < lines.length) {
// Write valid lines back
}
}
}
Rationale:
- Hash Chaining: Ensures that modifying any historical entry breaks the chain, providing immediate detection of tampering.
- Payload Hashing: Stores hashes of inputs/outputs rather than raw data where possible, reducing PII exposure while maintaining traceability.
- Retention Enforcement: Automated cleanup ensures compliance with the six-month requirement without indefinite storage growth.
- JSONL Format: Allows for efficient appending and parsing by standard log aggregation tools.
2. Conformity Assessment Documentation
The conformity assessment requires a comprehensive technical file. This is not a one-time document but a living artifact that must reflect the system's design, risk management, and data governance.
Structure:
- System Description: Intended purpose, architecture, and interaction with users.
- Risk Management: Identification of risks and mitigation measures.
- Data Governance: Details on training, validation, and testing datasets.
- Technical Specifications: Algorithms, parameters, and limitations.
Implementation Strategy: Maintain this documentation in a version-controlled repository alongside the codebase. Use a template that maps directly to Annex IV requirements. Automate the extraction of metadata where possible, such as model versions and dataset hashes.
3. Post-Market Monitoring Plan
Post-market monitoring is a continuous obligation. It involves collecting feedback, analyzing performance drift, and reporting serious incidents.
Implementation:
- Feedback Ingestion: Create endpoints to receive user feedback and error reports.
- Drift Detection: Implement statistical tests to compare live input distributions against training data.
- Incident Reporting: Define thresholds for automatic escalation to the compliance team.
export class PostMarketMonitor {
private readonly incidentThreshold: number;
private readonly feedbackStore: FeedbackRepository;
constructor(config: { incidentThreshold: number; feedbackStore: FeedbackRepository }) {
this.incidentThreshold = config.incidentThreshold;
this.feedbackStore = config.feedbackStore;
}
public async analyzeFeedback(systemId: string): Promise<MonitoringReport> {
const recentFeedback = await this.feedbackStore.getRecent(systemId, '30d');
const errorRate = this.calculateErrorRate(recentFeedback);
const driftScore = await this.detectDrift(systemId);
if (errorRate > this.incidentThreshold) {
await this.triggerIncident(systemId, 'High error rate detected');
}
return {
systemId,
errorRate,
driftScore,
status: errorRate > this.incidentThreshold ? 'ALERT' : 'NORMAL'
};
}
private async triggerIncident(systemId: string, reason: string): Promise<void> {
// Notify compliance team and log incident
console.warn(`INCIDENT: ${systemId} - ${reason}`);
}
}
Pitfall Guide
-
The "Pause Button" Fallacy
- Explanation: Halting compliance work because the deadline moved to 2027.
- Fix: Align engineering sprints with procurement requirements. Treat procurement gates as hard deadlines regardless of regulatory dates.
-
Logging Without Cryptographic Integrity
- Explanation: Storing logs in a database without hash chaining or signatures, leaving them vulnerable to undetected modification.
- Fix: Implement hash-chained JSONL logs with digital signatures as shown in the Core Solution.
-
Ignoring Retention Policies
- Explanation: Retaining logs indefinitely or failing to enforce the six-month minimum, leading to storage bloat or compliance gaps.
- Fix: Implement automated retention enforcement that prunes logs older than six months while preserving the chain integrity of remaining entries.
-
Conflating Annex I and Annex III
- Explanation: Applying the wrong deadline or requirements based on misclassification. Annex I systems (regulated products) have a different timeline and may involve notified body involvement.
- Fix: Conduct a rigorous classification review. Annex I moves to August 2028; Annex III moves to December 2027. Ensure the correct obligations are mapped.
-
Procurement Blindness
- Explanation: Engineering builds compliance features, but Sales and Procurement are unaware, leading to missed opportunities in RFPs.
- Fix: Establish a cross-functional sync. Engineering must provide a "readiness report" to Sales that can be used in vendor questionnaires.
-
Traceability Gaps
- Explanation: Logs that record outputs but cannot be linked back to specific inputs or system versions.
- Fix: Ensure every log entry includes correlation IDs, input hashes, output hashes, and system version metadata.
-
Performance Overhead of Logging
- Explanation: Synchronous logging blocking inference latency due to heavy hashing or I/O operations.
- Fix: Use asynchronous logging pipelines. Hash payloads in memory and persist to storage via a background worker or message queue to minimize impact on inference latency.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Enterprise EU Sales Target | Full logging + Docs + Monitoring | Procurement requires evidence by 2026; missing this blocks revenue. | High dev effort, critical for revenue. |
| Internal Tool / Non-EU Market | Minimal logging + Docs | No external procurement pressure; focus on risk mitigation. | Low dev effort, operational efficiency. |
| Annex I Product (Regulated) | Aug 2028 Focus + Notified Body Prep | Deadline is later, but notified body involvement requires early engagement. | Medium dev effort, long lead time. |
| Legacy System Migration | Refactor for Logging + Docs | Technical debt makes compliance harder; address before deadline. | High refactoring cost, reduces future risk. |
Configuration Template
Use this JSONL schema for Article 12 log entries to ensure compliance and traceability.
{
"id": "uuid-v4",
"timestamp": "ISO-8601",
"systemId": "string",
"version": "string",
"inputPayloadHash": "sha256-hex",
"outputPayloadHash": "sha256-hex",
"previousHash": "sha256-hex",
"signature": "sha256-hex",
"metadata": {
"correlationId": "string",
"userSegment": "string",
"latencyMs": "number"
}
}
Quick Start Guide
- Identify High-Risk Systems: Run a classification audit to flag all Annex III systems requiring immediate attention.
- Integrate Logger: Add the
ImmutableAuditLogger to your inference pipeline. Ensure inputs and outputs are hashed and chained.
- Generate Readiness Artifact: Compile your logging configuration, technical file draft, and monitoring plan into a single readiness report.
- Engage Procurement: Submit the readiness report to your procurement or sales team to address vendor questionnaires and secure enterprise deals.