Repository navigation
feat(compliance): the EU AI Act and ISO/IEC 42001, mapped clause by clause - #78
Merged
Merged
Conversation
…lause The evidence pack has mapped to SOC 2 since it existed. That is one framework, and the buyers this product is for are asked about more than one — so the document now speaks to the three it can defend, with four rules enforced by tests rather than by good intentions: 1. **"Contributes to", never "satisfies".** Every clause names what the evidence does *and what it does not cover*. A clause with a contribution and no gap reads as a claim that the evidence closes it; a test fails the build if one is missing. 2. **Who the duty falls on is recorded.** Article 12 is largely the *provider's* obligation (build the system so it can log); Article 26 is the *deployer's* (keep the logs, monitor the system). Haldir's customer is usually the deployer, and collapsing the two tells someone they have met an obligation belonging to whoever built the model. 3. **High-risk is a precondition, stated as one.** Arts 12 and 26 attach to systems classified high-risk under Annex III. Haldir cannot classify a system and does not pretend to. 4. **Only clauses that can be cited are cited.** A.6.2.x is miscatalogued by more than one vendor; the mapping uses the numbers confirmed across published catalogues and leaves the rest out. A wrong control number in an evidence pack is worse than a missing one. `haldir_frameworks.py` holds the mapping; `framework_report()` renders it for the pack and groups the readiness score's existing seven checks by the clauses they speak to — no second scoring engine, no second set of signals. A clause nothing measures is reported `measured: false` rather than scored, because most of the Act and most of Annex A is organisational and a number invented for it would be the overclaim the module exists to prevent. The mappings render in both forms (markdown and HTML), so the auditor-readable document carries the gaps next to the contributions. The signature section moves to 10 in both, and the numbering assertions move with it. Tests: `tests/test_frameworks.py` — clauses reference only real pack sections (this caught `proxy` and `alerting` while it was being written; `alerting` is the *score* key for the `webhooks` section), checks map to clauses that exist, every regulatory clause states its gap, the provider/deployer split survives, Article 26(6)'s six-month floor stays recorded, unmeasured clauses carry no state, and pass wins over fail for a clause with two checks. Verified: 1116 tests, flake8, mypy over 31 files, both rendered forms checked, digest stable with the new section inside it. Co-Authored-By: Claude Code <noreply@anthropic.com>
This was referenced Oct 4, 2026
`mypy.ini` again — both sides add modules to one explicit list. Resolved by union (client_ip, registry, frameworks all present) rather than by picking a side, and `openapi.json` regenerated. Co-Authored-By: Claude Code <noreply@anthropic.com>
main moved when #77 landed after my first merge, and GitHub recomputes the merge against the current base — so the conflict returned. Same union resolution on `mypy.ini`, spec regenerated, suite run. Co-Authored-By: Claude Code <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #77 (the register adds the
agent_registersection this maps). Merge that first, then retarget tomain.The evidence pack has mapped to SOC 2 since it existed. That is one framework, and the buyers this product is for get asked about more than one. This adds the two that matter, mapped at the clause level with four rules enforced by tests rather than intentions:
test_every_regulatory_clause_states_what_it_does_not_coverfails the build if one is missing.Shape
haldir_frameworks.pyframework_report()frameworkssection — inside the signed digest, and static, so it cannot drift on its ownUnmeasured clauses are reported, not scored. Most of the Act and most of Annex A is organisational; a clause nothing measures returns
measured: falsewith no state. A number invented for it would be exactly the overclaim this module exists to prevent.Verification
tests/test_frameworks.pyalso checks the direction that bit while writing it: every section a clause references is a real pack section (it caughtproxyandalerting— the latter is the score key for thewebhookssection, which is exactly how that slip happens)Sources for the clause citations: EU AI Act Art. 12 logging mandate, Art. 26(6) deployer retention, ISO 42001 Annex A control catalogue.
🤖 Generated with Claude Code