Zurück zu The LedgerEngineering

The four-eyes principle: from regulation to system architecture

Almost every compliance system claims to support 'four-eyes review'. Most ship a checkbox. Here is what it takes to make the principle survive contact with a real organisation.

Antoine Bedaton
Antoine Bedaton
08. Jan. 20267 Min. Lesezeit
The four-eyes principle: from regulation to system architecture

Part of our complete guide to negative news screening for Swiss banks. This post is the deep dive on the architecture of four-eyes review; the guide covers the end-to-end picture.

The four-eyes principle is one of those ideas that sounds simple until you ship it. Two people must approve. Done, right? Every word in that sentence hides a design decision.

The principle itself shows up in regulation as a control objective rather than an implementation. The Basel Committee's Principles for the Sound Management of Operational Risk (revised 2021) treat segregation of duties as a baseline expectation, alongside the older Framework for Internal Control Systems in Banking Organisations (1998). Find both in the BCBS publications index. ISO 27001 lists segregation of duties as a control. Swiss financial institutions inherit it through general internal-control obligations. None of these documents tell you how to build it. The implementation is yours.

"Two people"

The first thing that breaks is the question of who counts as a person. In a small private bank, the answer is "an individual employee with a unique login". In a larger organisation with shared service desks, contractors, and rotating analysts, you quickly need to specify:

  • Two people with different employee IDs, not just different sessions.
  • Two people who are not the same person at different times. One analyst should not be able to be both submitter and reviewer by switching accounts.
  • Two people whose relationship satisfies a separation rule. Typically the reviewer cannot report directly to the submitter, and cannot have submitted the original investigation themselves.

We model this with a users.eligible_to_review_for(investigation) predicate that runs server-side at approval time. The first version is usually one SQL query. The version that survives contact with real organisations turns into a join across the user directory, the org chart, and the investigation's history.

Roles are not the same as policies

In practice, two organisations with identical job titles can have opposite policies on who is allowed to approve what. A "compliance officer" at one institution can approve any investigation; at another, the same title cannot approve investigations they have personally reviewed earlier in the workflow. Building eligibility rules around job titles alone tends to fail. Make the rules data-driven instead, based on the directory, the org graph, and the investigation's history.

A subtle issue most teams discover after deployment: the HR system that holds the org chart usually lags reality by a couple of weeks. People change managers, departments, or employment status, and the system of record catches up later. Eligibility rules that depend on real-time org data have to plan for staleness.

"Must approve"

The second thing that breaks is the question of what is being approved.

A first-cut implementation lets the reviewer approve "the investigation". This is wrong. By the time the reviewer looks at it, the submitter may have edited the evidence, added notes, or changed the recommendation. The reviewer is approving a moving target.

The correct unit of approval is a frozen snapshot. When the submitter clicks "submit for approval", the system captures the full state of the investigation (decision, evidence list, evidence hashes, notes), seals it, and the frozen artifact is what the reviewer sees and approves. The hash-chain implementation is what makes the seal verifiable years later without trusting the database.

If the submitter wants to change anything afterward, it requires a new submission and a new approval cycle. This sounds heavy. It is what auditors expect, and it is what makes the audit log defensible.

A workable state machine

A state machine that holds up under audit usually looks something like this:

  • DRAFT: submitter is working
  • SUBMITTED_FOR_REVIEW: frozen snapshot exists, awaiting reviewer assignment
  • UNDER_REVIEW: a reviewer has claimed it
  • APPROVED / REJECTED / ESCALATED: terminal states with the snapshot preserved
  • WITHDRAWN: the submitter pulled the submission before review

A few transitions tend to matter more than they look:

  • UNDER_REVIEWSUBMITTED_FOR_REVIEW. The reviewer un-claims. Needed when reviewers rotate shifts.
  • REJECTEDDRAFT. Rejection requires a comment. The submitter can rework and resubmit, but a new snapshot starts a new approval cycle, and the prior rejected snapshot stays in the audit trail.
  • APPROVED → ∅. Approved is genuinely terminal. There is no edit-after-approve path. Remediation requires a new investigation.

Every state transition is a row in the audit log with a timestamp, an actor, a reason, and a hash of the snapshot. That table is what survives the five-year audit.

What the UI hides

The reviewer's UI shows a clean diff: submitter's recommendation, the evidence, their notes. What the UI hides is the guard logic underneath:

  • The reviewer's identity is fetched server-side from the OIDC token. The client cannot specify "I am reviewer X".
  • Eligibility is re-checked at every state transition, not only at submission. Org structure can shift between submission and approval.
  • The "approve" button is only enabled once the reviewer has actually loaded each piece of evidence. This is measured server-side via signed view events. Client-side counters can be faked; server-side ones cannot.

The hardest part: exception handling

Approvals are not the hard problem. Exceptions are.

The textbook flow is submitter → reviewer → approval. Real life adds:

  • Vacation delegation. A reviewer goes on leave, and a delegate takes over the queue. The delegation has to expire automatically, log who delegated to whom, and not break separation rules (the delegate cannot already have a conflict of interest with any pending item).
  • Emergency override. A regulator-driven escalation arrives outside business hours and the duty officer has to act now. Who is "the reviewer of last resort", and how does the system enforce that the override path stays exceptional and logged?
  • Reviewer unavailable. The assigned reviewer leaves the firm before approving a pending investigation. The investigation has to be reassigned, and any partial review has to remain attributed to the original reviewer in the audit log.
  • Conflict discovered late. Submitter and reviewer were eligible at submission. An org change three days later creates a reporting line between them. The pending approval should flag, not auto-approve.

These are best modelled as explicit transitions, not as exceptions. They get their own audit log entries, their own reason codes, and their own eligibility checks. This is more code than people expect. It is also exactly what auditors look for when they ask "show me a difficult case".

Escalation

The principle says "two people". The reality is that when those two people disagree, something has to happen. Disputes that go to email are disputes that disappear from the audit trail.

A workable escalation pattern: if the reviewer rejects, the submitter can escalate to a third party (typically the head of compliance or a designated escalation queue). The third party sees the original snapshot, the rejection reason, and the submitter's counter-argument. Their decision is binding and is logged with a tertiary_review flag.

The third party cannot have been involved in either the submission or the review. The eligibility predicate runs again with stricter rules.

What examiners ask for

A common question during a regulatory examination is some version of: "show me a case where the reviewer disagreed with the submitter, and walk me through what happened". An institution that can answer this cleanly with a system trace is in a much better position than one that has to reconstruct from email threads and shared inboxes. The audit drill protocol is one way to test whether yours can.

Things worth designing in early

Two patterns we recommend building from day one rather than retrofitting:

  1. Snapshot diffing. When a submitter resubmits after a rejection, reviewers want to see what changed. Without a diff, the reviewer has to read the entire investigation from scratch every time.
  2. Reason codes, not free text. Rejection and escalation reasons are far more useful as structured codes (with optional free text) than as pure narrative. Reporting becomes possible. Trend analysis becomes possible. Audit becomes possible.

The four-eyes principle is one line of regulation. Implementing it defensibly is closer to a thousand lines of code, three database tables, and several months of conversations with compliance officers about what "different person" actually means in their organisation. (How NNSFlow implements this end-to-end.)

#architecture#workflow#AML#approvals