Engineers

Immutable AI decision log with hash chaining

How to build an append-only, hash-chained record of AI decisions — with periodic anchoring, auditable correction, and vendor-independent export.

e.works Labs TeamTechnology · Innovation · Automation5 min read

The executive article "Audit trail for decisions made with AI" covers the why: without an auditable trail, a company can't explain an automated decision when questioned by a regulator, a customer, or a court. This piece covers the how: building that trail so it resists alteration, even by someone with administrative access to the database.

Why an ordinary log isn't enough

A traditional log in a relational database — a table that allows UPDATE and DELETE — proves nothing in an audit. Anyone with admin access can alter a record after the fact and leave no trace of the change. For AI decisions that affect people, the standard needs to be stronger: a log where any retroactive change is mathematically detectable.

Append-only structure with hash chaining

The core technique is simple: each log entry includes the hash of the previous entry, forming a chain. Altering any entry in the middle of the chain changes its hash, which breaks the reference of the following entry, making the alteration detectable during an integrity check.

import hashlib
import json

def hash_entry(entry: dict, previous_hash: str) -> str:
    payload = json.dumps(entry, sort_keys=True) + previous_hash
    return hashlib.sha256(payload.encode()).hexdigest()

def log_decision(decision: dict, previous_hash: str) -> dict:
    entry = {
        "id": decision["id"],
        "timestamp": decision["timestamp"],
        "use_case": decision["use_case"],
        "subject_id": decision["subject_id"],
        "model_input": decision["model_input"],
        "model_output": decision["model_output"],
        "model_version": decision["model_version"],
        "previous_hash": previous_hash,
    }
    entry["hash"] = hash_entry(entry, previous_hash)
    return entry

Each new decision references the hash of the one before it. The first entry in the chain uses a fixed, known genesis hash. Verifying the integrity of the entire chain means walking it, recomputing the hashes and comparing them against stored values — an O(n) operation that can run as a periodic job.

Periodic anchoring

Hash chaining proves internal integrity — that the chain hasn't been altered after being written — but it doesn't, by itself, prove when the chain existed. If the entire chain sits under the company's exclusive control, someone with full database access could, in theory, recompute the whole chain from scratch.

Periodic anchoring solves this by publishing the chain's hash, at regular intervals (daily or weekly), to a destination outside the company's exclusive control: a timestamping service (RFC 3161), a public ledger, or simply a signed report sent to a third party (external auditor, e-notary). From the moment of publication, any attempt to rewrite the chain up to that point conflicts with the published anchor.

Day 1: hash of chain up to entry 4,200 -> published to timestamping service
Day 2: hash of chain up to entry 4,850 -> published
...

Correction without breaking the chain

AI decisions sometimes need correction — a record was created with wrong data, a risk classification changed after review. In an append-only log, correction never overwrites the original record; it's added as a new compensating record that references the record it corrects:

{
  "id": "dec-9931",
  "type": "correction",
  "corrects_id": "dec-8420",
  "reason": "risk reclassification after human review",
  "previous_value": {"risk": "medium"},
  "corrected_value": {"risk": "high"},
  "timestamp": "2026-05-18T14:02:00Z",
  "previous_hash": "a1f3...",
  "hash": "9be0..."
}

This preserves the full history: any query on the original record shows its value as of the moment of the decision, while a query on current state follows the chain of corrections to the prevailing value. Nothing is deleted, and the reason for the correction is recorded alongside the corrected data.

Retention aligned with the business document

The decision log shouldn't have an arbitrary retention policy defined by engineering. Retention needs to mirror what the AI committee and legal defined as the holding period for that type of decision — often tied to the applicable legal statute of limitations or to the lifecycle of the relationship with the data subject.

That means the log schema needs to carry, per entry, the use case and, by extension, the applicable retention policy — not a single global window for the whole system. A purge job removes expired entries while preserving chain integrity (for example, replacing the content with an "expired by retention" marker that keeps the original hash — a pruning-with-proof technique, analogous to what blockchains do to reduce chain size without losing verifiability).

Queries by decision, period and data subject

Without proper indexing, a hash chain is great for integrity proof and terrible for operational queries. The design needs to separate the two responsibilities: the immutable chain is the source of truth for integrity, and a query index (by decision id, by data subject, by time range, by use case) is rebuilt from it, and can be rebuilt from scratch at any time without risk — because the chain is the authority, not the index.

CREATE INDEX idx_log_subject ON query_index (subject_id, timestamp);
CREATE INDEX idx_log_use_case ON query_index (use_case, timestamp);

Export for audit and vendor independence

A frequently overlooked requirement: the audit trail needs to survive a change of AI infrastructure vendor. That means the export format cannot be proprietary to a specific platform. A robust export format includes, per entry, every field needed for independent chain verification — without depending on any specific system to recompute the hashes:

export.jsonl:
{"id": "...", "hash": "...", "previous_hash": "...", "payload": {...}}
{"id": "...", "hash": "...", "previous_hash": "...", "payload": {...}}

An external auditor should be able to download this file and verify the chain's integrity with a simple script, without access to the source system.

What to do on Monday

  • Check whether your current AI decision log allows UPDATE or DELETE on existing records; if it does, that's the most urgent fix.
  • Implement hash chaining on your highest-risk decision log first, then extend to the rest.
  • Define the external anchoring mechanism and cadence before declaring the log "auditable."
  • Write the export format and test it with a script independent of the source system, confirming the chain validates outside the platform.

Further reading

Executive track:

ShareLinkedInX

Read next

Put it to work

From the article to practice: use this in your company

The capabilities described in this article are available on the e.works platform at eworks.cloud. You choose where your company's data lives: on e.works infrastructure, managed and protected on AWS, or in your own on-premises environment.

  • e.works infrastructure on AWS

    A managed environment protected by e.works on AWS, with encryption, per-company isolation, backup and high availability.

  • On-premises, in your environment

    The same platform running in your company's data center or private cloud, when data sovereignty requires that nothing leaves your perimeter.

In either model your data stays yours — with access control, audit logging, configurable retention and guaranteed availability.

Newsletter

Technical and strategic content, once a month

Analysis on automation, industrial data and technology adoption. No spam.