Storage-layer trigger-enforced retention — not config-file aspiration. Replay the proof in three curl calls.
Article 12 of Regulation (EU) 2024/1689 sets the floor for AI system log retention. The relevant text:
"Deployers shall keep the logs automatically generated by that high-risk AI system to the extent such logs are under their control, for a period appropriate to the intended purpose of the high-risk AI system, of at least six months, unless provided otherwise in applicable Union or national law…"
Six months is the minimum. Sectoral rules push it longer — financial-services anti-money-laundering retention runs five to ten years, healthcare runs longer, public-sector procurement archive runs ten. So a serious AiEGIS deployment commits to a 5-year retention floor by default and lets the deployer extend.
The standard pattern when a vendor claims a retention period is one of three:
retention_days: 1825 sits in a settings file. An ops engineer with sudo can flip it tomorrow. The page claim survives; the actual retention does not.DELETE, then running the prune so the gap looks scheduled.All three pass an auditor walkthrough. None of them survive an adversary with database credentials.
The AiEGIS Grid audit ledger lives in a SQLite table called grid_ledger. Two triggers, attached at CREATE TABLE time, reject any attempt to DELETE or UPDATE a row:
CREATE TRIGGER trg_grid_ledger_no_delete
BEFORE DELETE ON grid_ledger
BEGIN
SELECT RAISE(ABORT, 'grid_ledger is append-only');
END;
CREATE TRIGGER trg_grid_ledger_no_update
BEFORE UPDATE ON grid_ledger
BEGIN
SELECT RAISE(ABORT, 'grid_ledger is append-only');
END;
Every row also carries a prev_hash and an event_hash, so the ledger is structurally a hash chain. A successful tamper would have to bypass the trigger, recompute the chain, and re-sign every downstream row. The trigger blocks the first step.
Three curl calls. Any auditor can run them right now.
curl -s https://aiegis.ie/grid/ledger/retention
# returns:
# {"retention_floor_days":1825,
# "append_only_enforced":true,
# "triggers_present":["trg_grid_ledger_no_delete","trg_grid_ledger_no_update"],
# "ledger_size":198,
# "satisfies_floor":true,
# ...}
The same endpoint returns the exact trigger names from sqlite_master. An auditor can cross-check against the table-creation DDL we publish; if the trigger were removed the verifier response would no longer list it.
An operator with shell access to the database can try:
sqlite3 /opt/agent_platform/agents.db \
"UPDATE grid_ledger SET payload_json='TAMPER' WHERE seq=1;"
# returns:
# Error: stepping, grid_ledger is append-only (19)
# exit 1
SQLite error code 19 is SQLITE_CONSTRAINT. The same call with DELETE returns the same error from the sibling trigger. There is no application-layer flag to flip, no DBA-mode bypass, no "trust me" config flag. The storage engine refuses.
Article 26§6 of the same Regulation requires deployers to keep automatically-generated logs for "at least six months." A 5-year floor is 10x the minimum and well within most sectoral overlays. Signed evidence manifests for any period are produced by GET /api/policy/evidence?org_id=…&from=…&to=…, signed against the public key published at /.well-known/aegis-evidence-pubkey.pem. The full per-sub-paragraph Article 26 mapping is at /article-26-walkthrough; the machine-readable version is /audit/article26-mapping.json.
Storage-layer enforcement on a single SQLite file protects against in-process tampering. It does not by itself protect against:
rm on the SQLite file can destroy the ledger; the trigger has no opinion. Mitigation: append-only filesystem mounts and off-host replication (out-of-scope for this post).The point is not that storage-layer triggers solve every threat. The point is that they raise the floor from "trust the config file" to "the database itself refuses." That gap is the difference between a paperwork-only Article 12 attestation and one that survives an adversarial review.
If your audit log can be rewritten by the operator, your audit log isn't evidence in any jurisdiction that takes the EU AI Act seriously. EU AI Act fines run up to 7% of global revenue. An auditor walking into your environment with sqlite3 and seeing the trigger reject their probe is the answer to "show me." A config file saying retention_days: 1825 is not.
Run the curl. Try the tamper. The behaviour is publicly verifiable on a production endpoint, today.