Framework registry & evidence bases
A framework in Brutor is data, not code: a catalog of dated obligations, each shown against evidence statements that name a resolver from one shared library. The same resolver with the same parameters gives the same answer under every framework that cites it — one evidence log, many audits.
The registry
Section titled “The registry”| Framework | Id | Kind | Verified against instrument | Obligations |
|---|---|---|---|---|
| EU AI Act | eu-ai-act |
regulation | yes | 28 |
| ISO/IEC 42001:2023 | iso-42001 |
standard | yes | 15 |
| SOC 2 | soc2 |
attestation | yes | 10 |
| HIPAA Security Rule | hipaa |
regulation | yes | 7 |
| GDPR | gdpr |
regulation | yes | 8 |
| DORA | dora |
regulation | no | 4 |
| NIS2 | nis2 |
regulation | no | 2 |
| NIST AI RMF 1.0 | nist-ai-rmf |
voluntary | no | 6 |
| Colorado AI Act | colorado |
regulation | no | 4 |
| Korea AI Framework Act | korea |
regulation | no | 3 |
| Brazil PL 2338 | brazil |
regulation (bill) | no | 1 |
A catalog with verified_against_instrument: false renders a “verify against the
published instrument before relying on this” banner in the console and on its docs page.
A framework carries: id, title, kind (regulation | standard | attestation | voluntary), jurisdiction, reference, versions[] (catalog version with effective
range), a role vocabulary and a classification vocabulary (and the profile fields
they are read from), obligations[], deadline_rules (incident classification → time),
retention_floors (classification → days, * = any), verified_against_instrument, and
an optional tag_key linking it to compliance tagging.
Each obligation carries key, title, reference, applies_from (per catalog version),
summary, applicability filters (classifications, roles, neutral-core flags, GPAI track),
a needs_review note where the platform cannot decide alone, an obligation-level limit,
aliases for renamed keys — and evidence[]:
@dataclass(frozen=True)class EvidenceSpec: key: str statement: str basis: Literal["recomputed", "judged", "indicator", "declared"] resolver: str # shared resolver id, or judge.<template> params: Mapping[str, Any] # e.g. {"floor_days": 183}, {"tag": "hipaa.phi"} applies_to_kinds: FrozenSet[str] | None = None limit: str | None = None # what this statement does NOT showA static test asserts that every resolver named in every catalog exists, and every catalog date is pinned by a test.
Enabling a framework for a tenant (Compliance → Frameworks, or
PATCH /v1/admin/compliance/frameworks/{id} with {"enabled": true}) is the same switch
as adding its tag key to the tenant’s tagging profile.
The compliance profile
Section titled “The compliance profile”Every AI System has one compliance profile (Compliance → Profiles, or
PUT /v1/admin/compliance/ai-systems/{id}/profile): a neutral core plus a
frameworks block keyed by registry id.
{ "core": { "operator_role": "builder", "jurisdictions": ["EU", "US"], "entities": { "provider": "Example Insurance SE", "deployer": "Example Insurance SE" }, "dates": { "put_into_service": "2026-03-01" }, "external_registrations": [{ "framework_id": "eu-ai-act", "registry": "EU database", "id": "EUDB-0000" }], "sensitivity": { "personal_data": true, "special_category": false, "phi": false, "financial": true, "minors": false }, "interacts_with_natural_persons": true, "generates_synthetic_content": false, "automated_decisions_about_persons": true, "two_phase_actions": null, "inference_records": null, "salt_digests": null, "oversight_assignment": "Claims operations duty lead", "notes": "Scope confirmed by the AI governance board, 2026-08" }, "frameworks": { "eu-ai-act": { "role": "provider_and_deployer", "risk_tier": "high", "annex": "annex_iii", "qms_reference": "QMS-7" }, "gdpr": { "role": "controller", "dpbd_reference": "DPbD-2026" }, "soc2": { "in_scope": true } }}operator_role is one of builder, operator, vendor_of, reseller. The EU AI Act block is validated strictly (role, risk_tier, in_scope, annex, annex_iii_area, conformity_assessment and the declared references); every other block is validated against its
catalog’s role and classification vocabularies, and otherwise holds the fields that
catalog’s DECLARED statements cite (scalars or short lists). The EU AI Act role and
risk_tier are written through to the resource group’s legacy columns. null switches
mean “default: on when high-risk in any framework” (options).
Every save seals an ai.brutor.declaration record whose payload digest covers the
saved profile, so each DECLARED statement cites a sealed declaration. A save the core cannot
seal is still saved, and the response says sealed: false with the error.
An obligation’s applicability per system is applies, not_applicable or
undetermined — an undeclared role, classification or flag can never rule an obligation
out.
Four bases
Section titled “Four bases”| Basis | How it is established | Can be met? |
|---|---|---|
| recomputed | derived by a resolver from the tenant log, the run ledger and configuration | yes — met, not_met, not_evaluable, undetermined |
| judged | a tier-B model template over a deterministic, disclosed sample, stated with human agreement | yes, and always shown with its agreement; never summed with recomputed |
| indicator | movement over time, never a threshold | never — status indicator |
| declared | an operator statement, sealed but not checked | never — status declared |
Statement statuses: met, not_met, not_evaluable (nothing to measure), undetermined
(a declaration or input is missing, or could not be established), indicator, declared.
An obligation cell in the matrix shows the worst status of its statements, ranked
not_met < undetermined < not_evaluable < met < indicator < declared, beside
per-basis counts that are never merged.
Every StatementResult carries key, statement, basis, resolver, params, status, n, m, detail, limit, citations (up to 20 record ids), catalog_version, window_start, window_end, evaluated_at, facts (sub-counts, never merged into n/m) and refs (non-record pointers
such as evidence pointers, tree heads, contracts). The default window is 30 days.
The shared resolver library
Section titled “The shared resolver library”Resolvers are framework-neutral and live in the Control Plane
(app/services/compliance/resolvers/). They never return met on missing inputs, count
n of m rather than percentages, and never raise — an internal failure is not_evaluable
with the reason.
| Resolver | Basis | Computes | Does not show |
|---|---|---|---|
records.every_verdict_sealed |
recomputed | governed actions in the window that should carry a sealed record (the consequential rule) and do — n of m; refusals sealed of refusals; backfilled records reported separately |
actions not routed through the gateway; integrity is not completeness |
records.witnessed |
recomputed | tree heads covering the system’s records in the window that are graded witnessed/plural, of all such heads; records older than an hour with no covering head ⇒ not_met; plural and self-witnessed counts disclosed |
a witness-observed time; a same-operator witness is self-attested |
records.chain_complete |
recomputed | awaiting_human records closed by a human or expiry record, planned records confirmed, and contract promotions matched by epoch_boundary records |
chains the gateway never opened |
records.integrity_verified |
recomputed | audit row chains touching the system’s rows recompute intact (a signed checkpoint covers them, or every gap is a declared prune); forged/broken ⇒ not_met |
that a row was accurate when written |
retention.floor |
recomputed | effective retention ≥ floor_days, and no prune younger than the floor in the window; scope: documentation checks documentation artefacts |
record ids, statements and heads are permanent anyway; policies kept outside the platform |
retention.declared_prunes |
recomputed | every gap in the retained logs is a declared prune | the pruned content |
oversight.override_available |
recomputed | run:abort held by someone, approval gates on state-changing grants, an oversight assignment declared |
that the assigned people are competent |
oversight.exercised |
recomputed | approval requests raised, decided by a human, and lapsed (requested n, decided m, lapsed k) | the quality of the human decision |
oversight.not_rubber_stamp |
indicator | approval latency and denial-rate drift status | that a decision was considered |
authz.out_of_grant_refused |
recomputed | out-of-grant actions were only ever denied; the contract hash on every record equals the contract in force at its time |
the grant itself is a declaration |
authz.least_privilege_declared |
declared | grants, capability filters and argument policies bound, sealed | whether the grants are the least needed |
authz.human_identity_verified |
recomputed | approvals decided by authenticated principals (2FA where policy requires) | who sat at the keyboard |
access.sensitive_reads_recorded |
recomputed | actions carrying tag params.tag (e.g. hipaa.phi) with a record, n of m |
untagged traffic is not in the denominator |
monitoring.daily_health |
recomputed | health / liveness / drift evaluated every day of the window | what a human did with the findings |
monitoring.suspend_available |
recomputed | autonomy suspension and run-abort controls available; every use sealed | whether they were used when they should have been |
change.promotions_sealed |
recomputed | every contract promotion has an epoch_boundary record naming its approver |
the quality of the specification or the replay suite |
change.no_unapproved_widening |
recomputed | the lifecycle gate’s no-unapproved-widening rule held over the window | upstream changes (a vendor’s model) — shown as drift |
notice.before_first_turn |
recomputed | per conversation: the notice record precedes the first assistant-turn record in time and log order, n of m (transparency) | conversations outside the Brutor portal |
notice.text_declared |
declared | notice text digest sealed; surface declared | whether the text is understood |
synthetic.marking_declared |
declared | content-marking approach declared | content-level marking is not provided |
incidents.reported_within_deadline |
recomputed | reported_at − became_aware_at ≤ the framework’s deadline rule, n of m |
deadlines are shown, not enforced; awareness time is operator-entered |
incidents.register_exists |
recomputed | an incident register is kept; open incidents past deadline = 0 | incidents nobody recorded |
evidence.pointer_on_file |
recomputed | an unexpired evidence pointer of kind params.kind (risk_assessment, data_governance, impact_assessment, eval_report, red_team_report, dpia) |
the content of the document |
dependencies.contributing_assessed |
recomputed | every declared dependency of the system is assessed at (at least) the tier the system is evaluated at — a shared service by the registry at its effective tier, an external agent by its supplier (evidenced by supplier_information on the edge) — or carries a sealed separability rationale, n of m edges |
undeclared delegation (a composition finding, not an input); the external supplier’s assessment itself |
dependencies.supplier_information_on_file |
recomputed | every dependency supplied by another legal entity (every external agent; a shared service with supplier_legal_entity) has an unexpired supplier_information pointer attached to that edge, pinned by hash, n of m |
the terms of the agreement |
docs.technical_documentation |
recomputed | a documentation export exists for the active contract version, digest sealed | the adequacy of the skeleton |
docs.registration_recorded |
declared | an external registration id is recorded | the registry entry is not queried |
profile.field_declared |
declared | a profile field (params.path, e.g. frameworks.eu-ai-act.qms_reference) is declared |
organisational duties the gateway cannot observe |
judge.<template> |
judged | a tier-B template over sampled runs, with agreement — no_manipulation, notice_clear, per_instructions, approval_rationale |
stated with human agreement, never merged with recomputed rows |
New frameworks compose these; a genuinely new obligation adds one resolver.
Composite systems
Section titled “Composite systems”A system that contributes to another system’s decision is assessed with it (RFC 0022; the
Commission’s draft high-risk classification guidelines, May 2026). Under a catalog that
sets composite_classification — the EU AI Act does — every system is evaluated at its
effective tier: the highest of its own declared tier and the tier of every system that
declares a contributing dependency on it, carried along chains (A → B → C). The declared
tier stays on the profile as the owner’s claim; applicability, statements and retention
floors use the effective one, and the Obligations board, the matrix and the per-system
obligations view show both (risk_tier_evaluated / risk_tier_declared with the systems
that raised it). A catalog without the flag evaluates declared tiers only — the rule is
registry data, not code, so a final text that differs changes a flag, not the platform.
A dependency declared not to contribute to the decision needs a separability rationale,
and the rationale is sealed as an ai.brutor.declaration record (context state: separability, authority = the dependency edge) — the same sealing as every profile save.
The record id and time are on the edge and shown on both systems; changing or withdrawing
the claim clears them (a changed claim is sealed again). A claim the core could not seal is
saved but unsealed, raises a capture_gap inbox item, and does not satisfy
dependencies.contributing_assessed until a later save seals it.
Version in force
Section titled “Version in force”Catalog versions carry effective ranges (effective_to is exclusive). A statement is
evaluated against the catalog text in force on the action’s date, and reports and
bundles record the catalog_version they were computed under. The EU AI Act has two:
2024-08 (until 27 July 2026) and 2026-09 (the Digital Omnibus dates). Obligations
introduced by a later version (introduced_in) do not exist in an earlier replay; renamed
keys resolve through aliases.
Retention floors
Section titled “Retention floors”Retention floors are framework data. For each AI System:
effective retention = max( tenant policy, max over the system's active frameworks of floor )A framework is active for a system when the tenant has it enabled and the system’s
profile does not declare it out of scope; the floor is the catalog’s floor for the system’s
classification — under a catalog with composite classification (the EU AI Act) the
system’s effective tier, see composite systems — (EU AI Act
high-risk: 183 days; SOC 2: 365 days for any system,
the default attestation period). A registry framework without a catalog contributes its
registry retention_floor_days. A policy of keep already satisfies any floor.
The retention sweeper runs per tenant, so the tenant-level policy is raised to the largest
floor of any of its systems — keeping more than one system needs is the only safe
direction. Body scrubbing is not a record floor: record bodies and the row hashes records
cite are untouched by it. GET /v1/admin/compliance/retention shows the composition
(policy, floor, effective, which frameworks raised it); retention.floor recomputes
against the effective value and the declared prunes.

