~/About~/Foundry~/Blueprint~/Journal~/Projects
Book a Call
Foundry

Vendor Performance Intelligence Engine

·8 min read·Kingsley Onoh·View on GitHub

A Continuous Risk Score for Every Vendor a CPO Has on the Books

The Situation

The vendor's risk band crossed from low to high six weeks ago. Nobody noticed. The contract auto-renewed for another 24 months last week, and the procurement officer is now staring at the invoice that just arrived: 12 percent over the rate the supplier quoted in the original SOW, with line items the goods receipts never confirmed.

This is the loop a Chief Procurement Officer at a mid-market manufacturer runs every quarter. Annual vendor spend lands somewhere between €5 million and €40 million, spread across 200 to 500 active suppliers. Each supplier sends signals constantly: invoices that pay late or short, contract obligations that breach SLA, webhooks that fail signature validation, payment reconciliations that don't match. None of those signals live in the same system. Most of them live in spreadsheets. Some of them live in nobody's spreadsheet at all.

The CPO renews vendors on tribal knowledge. "Acme has been good to us for ten years." That sentence has zero supporting evidence in the data, even when the data is right there.

The Cost of Doing Nothing

Industry benchmarks put supplier-related cost overruns at 5 to 15 percent of total vendor spend for mid-market manufacturers running on manual reviews. On €10M of annual spend, that's €500K to €1.5M a year leaking through quietly auto-renewed contracts, undetected discrepancy patterns, and price drift that nobody flagged in time.

The labor cost is smaller but real. A procurement analyst who builds quarterly vendor reviews from scratch spends 30 to 50 hours per cycle pulling exports from finance, contracts, payments, and ticketing systems, then coercing them into a deck. At €40 to €60 per hour loaded, that's €5K to €12K per analyst per year, spent on work that produces a snapshot of vendor health that's already three weeks stale by the time the deck is approved.

Both numbers are dwarfed by the cost of a missed band crossing. A vendor whose reliability is degrading week-over-week is a vendor about to miss a delivery, breach an SLA, or invoice for work that wasn't done. The CPO who sees the crossing the week it happens has options. The CPO who sees it six months later, after the auto-renewal lapsed, has a grievance.

What I Built

A scoring engine that ingests behavioral signals from across the procurement ecosystem, runs them through a tenant-configurable composite scorer, and emits a single 0-100 risk score per vendor with a band classification (low / medium / high / critical) plus the top five signals contributing to it. Every signal lands as an append-only row, every score row is derived from those signals, and every band crossing fires an alert through the notification hub.

What was hard: the engine has to work standalone, but it also has to plug into seven other systems that I had already built. Pulling vendor signals from Invoice Reconciliation, Contract Lifecycle, Webhook Ingestion, and Transaction Reconciliation meant designing an adapter layer that could survive any of those systems being down, slow, or feature-flagged off. Every ecosystem integration is {SERVICE}_ENABLED=false by default. Someone cloning the repo and running docker compose up gets a fully functional product with zero ecosystem dependencies, falling back to manual POST /api/signals ingestion.

System Flow

Data Model

Architecture Layers

The Decision Log

Decision Alternative Rejected Why
Append-only vendor_signals partitioned by month Mutable signals with updated_at Audit-grade source of truth. Corrections insert a new row and mark the prior one superseded. The DB-level trigger blocks UPDATE on every column except status along the legal transitions.
Frozen JSONB delivery_payload on every alert Re-query tenants and vendors at dispatch time A Sidekiq retry can fire days after the alert was created. If the tenant renamed itself in between, the email must show the legal name that was current when the band crossed, not the current one. The dispatcher reads the column and never the source rows.
Native Postgres declarative partitioning pg_partman extension The PRD originally specified pg_partman, but the operational cost is a custom Postgres image and an extra extension to harden. Native PARTITION BY RANGE (recorded_at) plus a daily Sidekiq job that runs CREATE TABLE ... PARTITION OF covers the same ground with no extra dependency.
Tenant-configurable scoring rules with category weights Hard-coded scorer One CPO weights financial signals at 50 percent. Another weights contractual signals higher because they're in regulated industries. Weights, band thresholds, time-decay half-life, and signal overrides are all per-tenant rows, with one active rule at a time.
4-rung vendor resolver cascade (tax_id at 1.00 confidence, then normalized name at 0.85, then Levenshtein distance ≤2 at 0.70, then new vendor at 1.00) Single-pass exact-string match with operator-queue fallback for misses Invoices from "Acme GmbH", "ACME Gmbh, Hauptstr 10", and "acme gmbh / DE-87654321" all describe the same supplier. A single-pass match queues every variant as a pending alias and the operator drowns. The cascade auto-confirms 60-70 percent of inbound aliases at confidence ≥0.85 and only the genuinely ambiguous ones reach the human review queue.

Ecosystem Integration

This engine is the procurement risk consumer in a 15-system portfolio. Vendor signals flow in from four upstream systems through a feature-flagged adapter layer: invoice discrepancies and overdue payments arrive from a purchase-order matching engine, obligation breaches and contract terminations stream in over NATS from a contract obligation tracker, webhook delivery failure rates pull from a webhook ingestion gateway, and band-crossing alerts route outbound through the notification hub for email and Telegram delivery, with HIGH and CRITICAL crossings firing escalation runs through a workflow orchestrator. All seven ecosystem connections are feature-flagged and the system runs standalone with no ecosystem dependencies.

Results

The engine ships with 947 unit and integration tests, 70 system tests, and a separate end-to-end suite running against a real Puma server. The scoring path takes under 132 milliseconds at p95 against a target budget of 500. A band crossing reaches the notification hub at 511 milliseconds p95 against a 2-second target. All four report generators (vendor scorecard PDF, portfolio risk CSV/PDF, retender candidates CSV, trend analysis CSV/PDF) finish in under 2.6 seconds against a 30-second target.

For a CPO running €10M of annual spend, replacing quarterly manual reviews with continuous scoring means spotting a degrading vendor weeks before the renewal decision instead of months after it. Same-week visibility on band crossings is the difference between cancelling a renewal and writing a grievance letter. On the labor side, the analyst who used to spend 40 hours per quarter pulling cross-system exports now opens a generated portfolio risk report and starts work at the conclusions, recovering roughly €5K to €10K per analyst per year.

The most useful output of this engine for a CPO has little to do with the scoring algorithm itself. The capture-once-render-forever discipline around alerts and reports does more work than the math does. A score, and every alert it triggered six months ago, can be reprinted today byte-equivalent after the tenant has renamed itself twice and the vendor has been merged into another. Procurement runs on paperwork that has to survive an auditor; the scoring loop only matters if the record of what it said is still trustworthy a year later, after both sides of the contract have moved on.

#ruby#rails#postgresql#sidekiq#hotwire#procurement#supplier-risk

The full system record for Vendor Performance Intelligence Engine

Get Notified

New system breakdown? You'll know first.