Every AI decision below is sealed into a tamper-evident chain. Change a single value and the cryptography breaks, live, in your browser. This is not an animation. It is the real HMAC-SHA256 chain the shipped package writes.
pip install air-blackbox
✓ Nothing leaves this page
The EU AI Act, Article 12, requires high-risk AI systems to automatically record events over the system's lifetime with traceability appropriate to their purpose. Tamper-evidence is not named in the text, it is how you prove that traceability and exceed the floor: it is not enough to have logs, you must be able to show no one changed them after the fact. For Annex III systems like hiring AI, the logs must also record who verified each result. The demo above is what that proof looks like when it is real.
Anyone with write access can edit a plain log and no one can tell. To a regulator or a court, an editable record proves nothing about what the AI actually did.
Every record's hash is computed from the record before it. Alter one field and that record's hash no longer matches, and every record downstream breaks with it. You saw it happen above.
One command bundles the chain with a standalone verify.py. The auditor runs it on plain Python, with no install and no trust in you, and gets a single PASS or FAIL.
When a regulator, client, or board asks what your AI did and whether the record is trustworthy, the answer is a verifiable bundle, not a screenshot and a promise.
No special demo path. The page computes each hash exactly the way the audit chain in the package does, verified byte-for-byte against the Python implementation.
# 1. scan your AI project for gaps (free, runs locally) $ pip install air-blackbox $ air-blackbox comply --scan . -v # 2. export a self-verifying evidence bundle $ air-blackbox export --format evidence --signing-key "$KEY" → .air-evidence-20260601.zip (audit_chain + scan_results + manifest + verify.py) # 3. hand the zip to an auditor. they run, with no install: $ python verify.py --key "$KEY" ✓ PASS - chain intact, 3 records verified # ...tamper with any record and the same command prints: ✗ FAIL - chain broken at record 1
verify.py checks the HMAC chain you see here using only the Python standard library.
Two snippets. The first reproduces the genesis record. The second reproduces a chained record, where the previous hash feeds in as raw bytes, exactly what the inspector shows. Paste either into any Python 3.
$ python3 -c ' import hmac, hashlib, json rec = {"action":"screen_resume","candidate":"Jos\u00e9 R\u00edos","decision":"advance", "model":"gpt-4o","req_id":"REQ-4471","run_id":"txn-001", "timestamp":"2026-06-01T09:14:02Z","version":"1.0.0"} canon = json.dumps(rec, sort_keys=True).encode() # ensure_ascii=True print(hmac.new(b"demo-key-2026", b"genesis" + canon, hashlib.sha256).hexdigest())' → 3406857a358925c0c92df41800ba682e06ef16be1f0d395a5c59a3de82fe6abe # = txn-001's chain_hash on the card above. note: json escapes the unicode name.
$ python3 -c ' import hmac, hashlib, json prev = bytes.fromhex( # the hex from record 1, as RAW bytes "3406857a358925c0c92df41800ba682e06ef16be1f0d395a5c59a3de82fe6abe") rec = {"action":"rank_candidates","candidate":"Jos\u00e9 R\u00edos","decision":"shortlist", "model":"gpt-4o","percentile":88,"run_id":"txn-002", "timestamp":"2026-06-01T09:14:05Z","version":"1.0.0"} canon = json.dumps(rec, sort_keys=True).encode() print(hmac.new(b"demo-key-2026", prev + canon, hashlib.sha256).hexdigest())' → 3475b0db67e73bec0929d9845521b78a5e063ade4b3a6d287e7cb2c5d70de5ab # = txn-002's chain_hash. THIS is why editing record 1 also breaks record 2.