Your first Annex IV dossier¶
The Annex IV dossier is the single artefact a Market Surveillance Authority can ask for. Lex Custis generates it on demand.
Step 1 — pick a date range¶
Go to /compliance. The top card is "Annex IV regulator dossier
(Art. 11 + 12 + 15 + 53 + 73)".
Pick a Period start and Period end. For a demo org with seeded data, set start = 90 days ago, end = today.
Step 2 — click "Download Annex IV dossier (.zip)"¶
The request hits GET /api/v1/compliance/dossier?period_start=…&period_end=….
Bundling takes a few seconds for a small period; longer periods scale
with log volume.
You'll get a file named like:
Step 3 — inspect the zip¶
Unzip and you'll see eight files:
dossier_acme_hr_tech_20260101_20260331/
├── annex_iv.pdf # Art. 11 technical documentation (or .html
│ if WeasyPrint's system deps are missing)
├── audit_log_period.jsonl # Art. 12 event log, HMAC-chained
├── integrity_attestation.json # Chain verification status at bundle time
├── metrics.json # Art. 15 aggregates over the period
├── provider_manifest.json # Art. 53 upstream GPAI trail
├── incidents.json # Art. 73 incidents detected in period
└── MANIFEST.json # Bundle metadata + SHA-256 per file
What's in each¶
annex_iv.pdf — the technical-documentation PDF. Covers cover
page, system description, data governance, interaction summary, human
oversight, bias monitoring, integrity verification, risk assessment.
(Commercial edition extends this with deployer-specific intended-purpose and
FRIA sections.)
audit_log_period.jsonl — one JSON line per audit entry in the
period, ordered by sequence number. Each line includes
previous_hash, current_hash, and every field that went into the
HMAC payload. A regulator can re-verify the chain offline using
python -m lex_custis.verify_dossier (v0.2 CLI) or by implementing the
spec in architecture/hash-chain.md.
integrity_attestation.json — the result of
audit_service.verify_chain() at the moment the bundle was built:
{
"format": "lex-custis/integrity-attestation/v1",
"organization_id": "...",
"organization_name": "Acme HR-tech",
"bundled_at": "2026-04-21T07:15:00+00:00",
"verified": true,
"total_entries": 847,
"entries_checked": 847,
"first_broken_at": null,
"message": "All 847 entries verified successfully.",
"regulation": "EU AI Act (Regulation 2024/1689), Art. 12 — automatic record-keeping"
}
metrics.json — Art. 15 aggregates: confidence min / avg / max, PII
detection rate, bias-flag rate, human-oversight rate. For the period.
provider_manifest.json — distinct (provider, model) pairs used
to serve inferences in the period, with call counts, first- and
last-seen timestamps, and a pointer to the upstream Art. 53 disclosure
for each provider.
incidents.json — full list of Art. 73 incidents detected in the
period, each with classification, SLA status, submission reference if
reported.
MANIFEST.json — the listing a regulator will verify first:
{
"format": "lex-custis/annex-iv-dossier/v1",
"organization_id": "...",
"period_start": "2026-01-01T00:00:00+00:00",
"period_end": "2026-03-31T23:59:59+00:00",
"generated_at": "2026-04-21T07:15:00+00:00",
"generated_by_user_id": "...",
"files": [
{"name": "annex_iv.pdf", "size_bytes": 283415, "sha256": "…"},
{"name": "audit_log_period.jsonl", "size_bytes": 1128345, "sha256": "…"},
…
],
"regulation_coverage": {
"art_11": "annex_iv.pdf (technical documentation)",
"art_12": "audit_log_period.jsonl (automatic event logs)",
"art_15": "metrics.json (accuracy/confidence/bias aggregates)",
"art_53": "provider_manifest.json (upstream GPAI trail)",
"art_73": "incidents.json (serious incidents in period)"
},
"integrity_verified_at_bundle_time": true
}
In commercial editions the MANIFEST.json itself is signed (ed25519) and
timestamped (RFC-3161). The OSS bundle is unsigned — you'll sign it
out-of-band if you need non-repudiation for a regulator in v0.1.
Step 4 — verify offline¶
A regulator (or your own audit team) can verify integrity without touching your live infrastructure:
- Read
audit_log_period.jsonlin order ofsequence_number. - Confirm each entry's
previous_hash== the prior entry'scurrent_hash(first entry's prev =sha256(b"LEX_CUSTIS_GENESIS")). - Recompute each entry's HMAC using the per-org key (held outside the DB, typically in KMS / Vault).
current_hashmust equal the recomputed HMAC.
See architecture/hash-chain.md for the exact payload canonicalisation.
Step 5 — what to do with it¶
Depending on audience:
- Regulator request. Attach directly to your response. The MSA
wants the
MANIFEST.jsonand the underlying files. - Big-4 audit. Give them the zip + read access to a fresh instance so they can reproduce.
- Your own DPO. Schedule a quarterly review with the zip as input and a PMM plan as output.
- Your customer's DPO (if you're a provider and they're a deployer). Share as part of Art. 13 transparency obligation.
What the dossier does not (yet) cover¶
- Art. 9 risk register — deferred to v0.2 / commercial edition.
- Art. 10 dataset registry — deferred.
- Art. 27 FRIA — wizard in commercial edition.
- RFC-3161 timestamping / ed25519 signature on MANIFEST.json — commercial edition.
Cross-reference with the compliance matrix to plan what else you still owe.