Capstone · 2026 Working system · pre-registered results Invite-only access

AegisVeritas

Two bidders. One owner.

A system that finds bidders in Kenyan public procurement that look independent but are linked to each other or to a debarred party, before the contract is signed. It reads open award, ownership and contact records, ranks supplier pairs by how likely they are to share an owner, and shows the evidence behind every flag. A person always decides.

Role
Sole engineer and researcher
Context
BSc Software Engineering (ML) capstone, African Leadership University
Supervisor
Kevin Sebineza
Stack
FastAPI, PostgreSQL, Neo4j, LightGBM, Next.js
e-GP bid opening · pre-award check
Simulated e-GP bid-opening screen: AegisVeritas warns the evaluation committee that two of three bidders may be under common control, with the evidence and a recommended action
At bid opening, a simulated e-GP screen sends one tender's bidders to AegisVeritas; the check and its answer are real, returned in 0.64 s. Real records, firm names masked.
0.146vs 0.067
Average precision on 7,884 held-back Kenyan pairs, against the Adamic-Adar baseline.
Pre-registered · passed
0.85vs 0.57
AUC on Estonian firms the model never saw, checked against Estonia's open ownership register.
Pre-registered · passed
25of 100
Real links among the top 100 flags. Picking pairs at random finds about 2.
Kenyan holdout
210×
More often, owner-linked pairs share a P.O. Box in road-authority registers the model never saw. p = 1.0e-42.
Corroborated · post hoc
01 · Problem

What the committee can't see

A debarred company rarely bids under its own name. It bids through a clean-looking company that shares a director, owner, phone number or address with it.

A name check passes that company, because there is no name to match. Two "competing" bidders can also belong to the same person, so the committee compares them, picks the cheaper one and signs, and the competition was never real. Kenya's tender documents already ask bidders to declare common control, but an evaluation committee sees one tender at a time, and the links are spread across tens of thousands of firms.

Six names, one group
Rockey Africa LimitedAerospace AviationEva-Top AgenciesSony Commercial AgenciesBeta Trading CompanyMadujey Global Services

Debarred together by the African Development Bank in 2021 for fraud in tenders on a Kenyan education project. On a tender table, nothing connects the names. The affiliates were found by tracing common officers.

Source: African Development Bank press release, debarments effective 5 August 2021
The rule exists. Nobody can check it.
57%

of contracts went to firms that did not say who owns them: 14,819 of 25,994. When ownership is declared, it sits in records no committee can search across the whole market in the time it has.

Source: PPRA annual report, reported by Business Daily, 5 August 2026
02 · System

What I built

A full system, not a notebook: a data pipeline over Kenya's public procurement records, a screening service, an evidence engine that retrains and gates itself, and an investigator-facing web app. It runs on a laptop-class machine with Docker Compose.

Sources
Procurement recordsKenya's PPIP portal, PPRA award files, OCDS and BODS
Adverse listsWorld Bank, AfDB, OpenSanctions, ICIJ, EACC gazette
Data
Ingestion and entity resolutionOne-command pipeline; checksums and code commit recorded per run
PostgreSQL + Neo4jRelational store and the ownership graph
Intelligence
Evidence engineScores supplier pairs; trains, gates and publishes on a schedule
Risk engineList match, then shortest path to a listed party, then model or rules
Access
FastAPIJWT, roles, row-level security, hash-chained audit log
Next.js app and e-GP checkReview queue, evidence cards, pre-award tender check
01

Bidder screening

Checks a supplier against sanctions and debarment lists, then follows owners and directors two steps out to find exposure a name check misses.

02

Review queue and evidence cards

A short list of supplier pairs for an investigator, each with its evidence, how strong that kind of evidence has proven, and what to check next.

03

Pre-award tender check

Takes the bidders on one tender and reports any links between them in seconds, the way Kenya's e-GP system would call it at bid opening.

04

Ownership path tracing

Draws the path from a supplier to the listed party on an investigation canvas.

05

Tamper-evident audit trail

Every screening, decision and tender check is appended to a SHA-256 hash chain. Changing any past entry breaks the chain, and the app can verify it.

06

Role-based access

Only investigator, auditor and admin roles see named pairs. Each institution sees only its own data, enforced by PostgreSQL row-level security.

03 · Method

My first approach failed

The proposal asked "is this one firm bad?" After the data was cleaned, only 18 confirmed Kenyan cases remained, and 11 of them had fewer than three recorded links.

No graph model beat a baseline that only looked at company size. The labels decide what is possible, so after a supervision meeting I changed the question to "are these two firms under one control?" For that question, the ownership details Kenyan awards must disclose give 12,441 labelled links. Kenya has no open ownership register to test hidden links against, so I also validated the method in Estonia, where both procurement data and beneficial ownership are public.

Three kinds of evidence, one probability

Candidate pairs are firms that win from the same buyer within 30 days, or that share a disclosed record. Each pair gets evidence from three channels, each a log-likelihood ratio, combined Fellegi-Sunter style so every part of the score stays explainable. A contact shared by many firms counts for less, and the behaviour model is capped so it can never outweigh an ID match.

How much each clue multiplies the odds that two firms share an owner

Starting weights in the evidence engine, log scale. They are replaced by weights learned from investigators' verdicts.

Learned behaviour model (LightGBM)Record match
Show as table
EvidenceOdds multiplierLog-likelihood ratio
Same owner, matched by ID number×1,0006.9
Same director, matched by ID number×2005.3
Behaves like one company (behaviour model, cap)up to ×55±4.0
Same phone or email×503.9
Same address or P.O. Box×102.3
Owner with the same name only×51.6
Behaviour model

LightGBM on 20 award-pattern features, trained on Kenyan and Estonian pairs, with isotonic calibration. Calibration error 0.010. Thirteen models were compared; none beat it.

Knows when to abstain

Silent on pairs where a firm has fewer than 3 awards, and on pairs unlike its training data. Refusing to judge is a result, not a failure.

Gated releases

A retrained model goes live only if it beats both the baseline and the current live model on a fixed holdout. The rule is in the code.

04 · Results

Results

Tests marked pre-registered had their protocol and pass mark committed to GitHub before the run, so the rules could not move after the results were seen. The baseline throughout is Adamic-Adar, the standard link-prediction score.

Pre-registered · passed

Estonia: firms the model never saw

AUC, with true owners hidden from the model and answers checked against Estonia's open register. 0.5 is a coin flip.

AegisVeritasLightGBM
0.85
Adamic-Adarbaseline
0.57
Show as table
MethodAUC
AegisVeritas (LightGBM)0.85
Adamic-Adar0.57
Pre-registered test estonia-v1
Pre-registered · passed

Estonia: the whole system

Share of all register-linked pairs found in the top 1,000, before and after adding register candidates to behaviour.

Recallearlier system
4%
Recallfull system
32%
Precisionearlier system
6%
Precisionfull system
51%
Full systemEarlier system
Show as table
Top 1,000EarlierFull system
Recall4%32%
Precision6%51%
Pre-registered test system-v1
Pre-registered · passed

Kenya: held-back supplier pairs

Average precision on 7,884 pairs the model never trained on, only 178 truly linked. Reproduced on a full retrain.

AegisVeritaslive model
0.146
Adamic-Adarbaseline
0.067
Randombase rate
0.023
Show as table
MethodAverage precision
AegisVeritas, Estonia + Kenya pooled0.146
Kenya only0.144
Adamic-Adar0.067
Estonia only (failed)0.065
Random (base rate)0.023
Pre-registered test kenya-transfer-v1; calibration error 0.010
Kenyan holdout

What a reviewer gets

Each square is one supplier pair. Filled squares are real links.

AegisVeritas top 100
25 linked

100 random pairs
about 2 linked

Precision at 100 = 0.25, about 11 times the 2.3% base rate (178 of 7,884)
Corroborated · not pre-registered

A register the model never saw

KeRRA, the rural roads authority, publishes contractor registers that list each firm's P.O. Box. The model flags pairs from ownership records only; the registers were never part of its data. This check was run after the detector was built.

Owner-linked pairs30 of 253
11.86%
Same-buyer controls5 of 8,852
0.056%

209.9 times more often than same-buyer controls, and at least 63.8 times at the cautious end of the 95% interval (Fisher's exact test, p = 1.0e-42). Against random pairs from the same region: 118.6 times, at least 23.2 times (p = 2.7e-27). A shared box shows a relationship, not wrongdoing.

Source: KeRRA contractor registers (22 files, 20 regions); verification report of 30 October 2026, section 5

The Kenyan labels come from disclosed ownership, so the Kenyan result shows that award behaviour can recover links that were disclosed. Estonia's official register is what supports the claim for hidden links.

05 · What failed

Reported in full

Failed and withdrawn results sit in the results ledger next to the ones that passed. They are the reason the passing results are worth believing.

0.065

A model trained on Estonia alone failed in Kenya

On the Kenyan holdout it scored 0.065 and 0.058 (raw and normalised), no better than the 0.067 baseline.

Markets differ. Each country needs its own labels, so the live model learns from Kenyan data.
2×

An outside test on road-contractor registers missed its pass mark

The pre-registered KeRRA test found no signal at its primary endpoint, twice: with the pair model and with the evidence engine.

The system now refuses to judge pairs unlike its training data.
0.075

My own safety gate caught a weaker model running live

The engine-2 model used importance weighting that was never tested, and a step-shaped calibrator.

Engine-3 trains exactly the model that was tested, and scores 0.146.
0.87

A result I withdrew

An Estonia-to-Kenya AUC of 0.87 turned out to have read the synthetic sample market, not real data.

Withdrawn and replaced by the real-data runs above.
242× → 209.9×

Every number rerun after submission

The submitted figures came from a run on an older database that still held duplicate company records. After a clean rebuild, concealed pairs went from 3,976 to 3,916 and the P.O. Box ratio from 242 to 209.9 times. The submission is tagged in git, and every run is kept.

The conclusion is unchanged; the page reports the rerun.
06 · Engineering

Built to be trusted

Because it names firms, the system has to be correct, explainable and hard to misuse. The tests, timings and design choices below come from the technical report.

665
backend tests passing; 81% to 97% line coverage in the engine, screening and service code
80/80
browser tests across Chromium, Firefox and WebKit, laptop and phone sizes
54/54
system checks: every endpoint and page of the running stack, on real data
155 req/s
with 10 clients at once and 0 failed requests
Performance
WorkloadResult
API calls on real datamedian 1 to 7 ms
Screening a companymedian 36 ms
Tender check, 2 biddersmedian 70 ms
Full retrain and scoring, 1.44 million pairs3 min 45 s
Review queue on a slow phone2.6 s
Algorithms
AlgorithmWhy
Breadth-first searchShortest path to a listed party, skipping buyers
Union-findFirm groups, so no group crosses the holdout
Sliding time windowCandidate pairs: same buyer within 30 days
Fellegi-Sunter fusionCombine evidence, keep each part explainable
SHA-256 hash chainTamper-evident audit log
Design

Seven data connectors implement one abstract connector; two risk models share one interface, so the graph model can be swapped for rules. The screening orchestrator depends on interfaces, not on Neo4j or PyTorch, so a baseline can replace the model with no other change.

Responsible by design

A person always decides, as Kenya's Data Protection Act requires. The API serves links by kind and date, never people's names. Firm names can be masked as stable codes for recordings. The system is not on the open internet, because its findings name firms that have not been found to do anything wrong. Invited evaluators reach it through Cloudflare Access, behind a one-time code and an app account.

Python 3.11FastAPISQLAlchemy 2.0 asyncPostgreSQL 15Neo4j 5Redis + CeleryLightGBMscikit-learnPyTorch GeometricNext.js 14TypeScriptTailwindPlaywrightpytestDocker Compose
07 · Screens

The product

The review queue, evidence card and e-GP screens run on real records with firm names masked as stable codes. The screening, investigation and audit screens use an invented demo company, and the people named in them are invented too.

review queue
Review queue listing supplier pairs ranked by likelihood of common control, firm names masked
Review queue: 10,867 leads and 12,441 disclosed links, ranked by likelihood of common control. Real records, names masked.
evidence card
Evidence card for one supplier pair: the kinds of evidence, how strong each proved, what to check next, and the verdict form
Evidence card: each kind of evidence and how strong it proved, what to check next, and a verdict saved to the audit log.
screening · demo data
Screening result for an invented demo company: a direct sanctions-list match with the factors behind the score
Screening: a direct list match, with every factor behind the score and its source. Invented demo company.
investigation · demo data
Investigation canvas showing the ownership network of an invented demo company, two hops out
Investigation canvas: the ownership and award network, two hops out. Invented company and people.
audit log
Audit log with the hash chain verified intact across 91 entries
Audit log: every screening, verdict and tender check, hash-chained and verified in the app.
See it working

The system is invite-only. Evaluators and recruiters can ask for a guided session.

Request access

Walkthrough

A recorded tour of the system: screening, the review queue, an evidence card and the pre-award tender check.

08 · Limits and next

A reason to look, not an accusation

Known limitations

Hidden links in Kenya are not yet proven: there is no public register to check against. 75 of the top 100 Kenyan pairs are not confirmed links; some may be hidden links and some will be innocent. Pairs where a firm has fewer than 3 awards (770,624 candidates) are not scored. Suppliers are matched by normalised name, so two different firms with the same name would be treated as one, and entity resolution precision has not yet been measured on a hand-checked sample. A 9,000-firm stress test ran out of memory, so scoring moves to batches next.

Now and next

Invite-only access has been live since 28 October 2026. Expert evaluation is under way: practitioners complete guided tasks in the app and a questionnaire that includes the System Usability Scale, under ALU ethics approval SEPT26-BEL-070. Next is a pilot with an organisation that works with procurement authorities.

When the public pays for competition, it should get competition.