ADR-0058: Central register is cross-check only (require ≥1 non-central source)
Status: Accepted Date: 2026-06-15 Supersedes: none Superseded by: none Deciders: Adrian (Soft4U), Claude Opus 4.8
Decision context:
- Latency: none — pure in-memory rule extending the #34 gate.
- Dependency surface: no new packages. Adds a taxonomy + two helpers to
verification_gate.pyand one result field. - Debuggability:
non_central_sourcescount + thecentral_register_onlystatus make a central-only block self-explaining. - Reversibility: branch revert; additive.
- Blast radius: additive; composes with #34's gate (the
<min_independentcheck keeps precedence). - Alternative considered: rely solely on the
is_central_registerflag (rejected — a producer that forgets the flag would let a central-only attribute pass; a name-based fallback closes that).
Context
AMLR §6: the central BO / Transparency Register is a cross-check, never the sole primary source.
The codebase had no central-vs-non-central distinction — SOURCE_TYPE_POINTS lumped BO register, KBO,
and gazette as government_registry, so a UBO could be verified solely from the central register. This
compounded the audit's core finding (register-declared UBOs treated as primary).
Decision
Extend the #34 verification gate with a non-central-source requirement, using the is_central_register
flag already on the #37 VerificationRecord:
- Taxonomy:
CENTRAL_REGISTER_SOURCE_NAMES+is_central(record)= the explicit flag OR a recognised central-register source name (belt-and-suspenders: the flag wins when set; the name catches records where a producer omitted it). - Rule: an attribute is
verifiediffindependent_sources >= min_independent(#34) ANDnon_central_sources >= 1(#35).>= minbut zero non-central → new blocking statuscentral_register_only. So two central registers still block. AttributeGateResultgainsnon_central_sources;statusLiteral gainscentral_register_only.
Consequences
Positive
- Register-declared UBOs are no longer self-sufficient — AMLR cross-check-only mandate enforced; directly counters the "register as primary source" anti-pattern.
Negative
- Stricter: a UBO with only BO-register evidence is a blocking gap (correct).
Neutral
- Relies on
is_central_registerbeing set by producers; the name taxonomy is the fallback. Wiring every producer to set the flag accurately is incremental.
Alternatives Considered
Alternative 1: Rely solely on the is_central_register flag
Rejected as the only mechanism — a producer that forgets the flag would let a central-only attribute pass. The name-based taxonomy is a safety net; the explicit flag still wins.
Alternative 2: Re-label confidence_engine.SOURCE_TYPE_POINTS
Rejected for this issue — that is the scorer, not the gate. The binding cross-check rule belongs in the gate (the enforcement point).