Skip to content
Spurvik Book a DPO walkthrough

Spurvik Insights, October 2026

Engineering and regulatory deep-dives

Three interactive notes on meeting the EU AI Act without breaking the GDPR. Every claim cites its article; every figure runs the real logic.

SDK v1.0 live npm i @spurvik/sdk npx @spurvik/sdk check latest.tgz
Article 15 min The GDPR vs. EU AI Act paradox GDPR Art. 5, 25, 32 · AI Act Art. 12, 26(6) Article 24 min Deterministic pre-flight routing with System-One AI Act Art. 12, 14(4) Article 35 min From Spurvik to Terra OAMP in six stages AI Act Art. 11, 12, 14, 17, 50(1)

The GDPR vs. EU AI Act Paradox: Why Standard LLM Observability Violates One Law to Comply with Another

Teams preparing for Art. 12 reuse their tracing stack. By default it keeps what data protection law wants kept least: the raw prompt.

Time since go-live
Conversations per day
User promptHi, I'm Mette Hansen, CPR 120485-1234. I'm in hospital this week.
Default tracing setupCaptures prompt, completion, tool calls and user_id
masking opt-in
Vendor trace store180,000plain-text transcripts
Spurvik SDK, in processHMAC-SHA256 with your key; text dropped from memory
SDK v1.0
Your EU event store180,000sealed events, 0 transcripts

Fig. 1.1Where personal data sits at rest after go-liveINS-01 · rev 2026.10

Day 180 is the six-month floor in Art. 19(1) and 26(6). At 1,000 conversations a day, a default setup then holds 180,000 plain-text transcripts: names, CPR numbers, diagnoses, whatever users typed.Fair note. LangSmith and Helicone offer masking, self-hosting and EU regions. Teams must configure them; the default logs raw text. Based on public documentation, October 2026.

§What each law asks

EU AI Act record

Art. 12(1)
Automatic event logs over the system’s lifetime
Art. 19(1), 26(6)
Keep them at least six months
Art. 26(6)
“unless provided otherwise in … Union law on the protection of personal data”

Art. 12(3) asks for input data only for remote biometric identification.

GDPR minimise

Art. 5(1)(c)
Only what is necessary
Art. 5(1)(e)
Identifiable no longer than necessary
Art. 25(2)
Necessary data only, by default
Art. 32(1)(a)
Pseudonymisation as a security measure
Together: record events, keep them six months, hold no more personal data than that needs.

§The precise claim

Stated purposeKeep transcripts six months “to comply with Art. 12”
Necessity, Art. 5(1)(c)Does Art. 12 need the text? For most high-risk systems, no.
Resultfails necessityArt. 26(6) points back to the GDPR.

Storing prompts is not unlawful in itself; with a lawful basis and short retention, many teams keep them for debugging. The conflict starts when the AI Act becomes the reason to keep them. And users volunteer Art. 9 health data (“I’m in hospital this week”), so free text cannot be bounded in advance. Only what you keep can.

A compliant log proves what happened. It does not need to hold what was said.

§Keyed HMAC: prove it, keep nothing said

HMAC-SHA256: 64 hex = 32 bytes 0 of 64 changed text stored: 0 bytes

Fig. 1.2One character changed, an unrelated digestINS-02 · rev 2026.10

Same text and key, same digest. So a disputed transcript is verified by recomputing, without the log ever holding it. The key matters: a plain SHA-256 of a CPR number is enumerable in seconds; without your key, the HMAC is not.Key custody. Keep the key in a KMS apart from the logs, rotate it, and record key_version.

Before: typical tracing callfull text at rest
// Captured on every request, kept for the store's retention period
tracer.log({
  user_id: session.userId,
  prompt: messages.at(-1).content,
  completion: result.text,
  tools: result.toolCalls,
});
After: keyed-HMAC eventno text leaves
import { createHmac } from "node:crypto";

const seal = (s: string) =>
  createHmac("sha256", process.env.SPURVIK_HMAC_KEY!)
    .update(s.normalize("NFC"))
    .digest("hex"); // 64 hex characters

events.write({
  schema: "spurvik.art12.event.v1",
  system_id: "support-assistant@4.2.0",
  input_digest: seal(prompt),
  output_digest: seal(result.text),
  router_action: decision.enforcedAction,
  art50_notice_shown: true,
  occurred_at: new Date().toISOString(),
});

One precision a DPO will ask for: a keyed-HMAC digest is pseudonymised data under GDPR Art. 4(5), not anonymous, while the key exists. Treat the store as personal data. What shrinks is what you hold, digests instead of transcripts. That is all “zero-PII” means here: no raw personal data persisted.Erasure. Destroying a key version makes its digests unlinkable, and unverifiable. Align key lifetimes with retention.

§What the record holds

spurvik.art12.event.v1 SDK v1.0

FieldWhyPersonal data?
occurred_atOrdering, period of useNo
system_id, model_refWhich version acted (Art. 72)No
input_digest, output_digestVerify a disputed transcriptPseudonymised, Art. 4(5)
router_actionGate decision, e.g. ask_human (Art. 14)No
reviewer_idWho approved, where oversight appliedEmployee data
art50_notice_shownArt. 50(1) notice displayedNo
key_version, retention_untilRotation; the six-month clockNo

SDK v1.0 writes these sealed events today, into a store you choose in the EU. Hosted fra1 retention: planned

§Timing

Art. 50 transparencyapplies
Today

Regulation (EU) 2026/1744 set that date. Choosing a record format now costs less than deleting six months of transcripts later.

§Questions for engineering

  • Which systems write prompt text to logs, where, and for how long?
  • Where “AI Act compliance” justifies retention, does that article need the text?
  • Who holds the HMAC key, and how is it rotated?
  • Can you verify a disputed transcript without storing it?