Skip to main content

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.py and one result field.
  • Debuggability: non_central_sources count + the central_register_only status make a central-only block self-explaining.
  • Reversibility: branch revert; additive.
  • Blast radius: additive; composes with #34's gate (the <min_independent check keeps precedence).
  • Alternative considered: rely solely on the is_central_register flag (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 verified iff independent_sources >= min_independent (#34) AND non_central_sources >= 1 (#35). >= min but zero non-central → new blocking status central_register_only. So two central registers still block.
  • AttributeGateResult gains non_central_sources; status Literal gains central_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_register being 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).