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

Dispute Resolution Workbench

·6 min read·Kingsley Onoh·View on GitHub

Project

Dispute Resolution Workbench

Proof type

Business proof

Best for

Founder / operator

Source

GitHub available

Inspect

One Queue for Finance Exceptions That Nobody Owns

The Situation

Finance disputes rarely start as clean tickets. One begins as an invoice mismatch. Another appears as a missed contract obligation. A third shows up when a payment reconciliation job cannot match money moving through a gateway and a ledger. A fourth is buried in a webhook dead-letter queue after a delivery failed overnight.

The business problem is ownership. Each upstream tool sees its own exception. None of them owns the full case.

The Workbench was built for that gap. It gives finance operators one tenant-scoped console for disputes, exceptions, correlation review, SLA tracking, resolution playbooks, notifications, and audit export. The core loop works locally even when every integration is disabled. Manual disputes and exceptions still run through the same queue as adapter-driven exceptions.

The PRD and README anchor the problem with a concrete target: dispute resolution can move from about 18 days to 4 days, with $40K+ annual recovery for a 100-person SaaS cost base. That number is not a guarantee. It is the business case for why the queue exists.

The Cost of Doing Nothing

The cost is not only the disputed amount. It is the time spent proving what happened.

A finance operator may need to open an invoice tool, a contract tracker, a bank reconciliation report, a webhook replay tool, a Slack thread, and a spreadsheet before they can answer one question: who owns this exception?

That delay turns small disputes into stale disputes. Credits expire. Counterparties argue from different evidence. Internal teams lose the timeline. When the case finally closes, someone still has to rebuild the audit packet by hand.

For a SaaS company with 100 people, the project target of $40K+ annual recovery is a reasonable floor. That combines recoverable dispute value, avoided leakage, and time not spent stitching together evidence. The bigger risk is softer but more expensive: a finance team that cannot prove the chain from exception to resolution.

What I Built

I built a tenant-scoped finance operations console in Clojure and Pedestal. It accepts manual exceptions, pulls discrepancies from invoice and transaction reconciliation systems, consumes contract breach signals, polls webhook dead letters, and exposes a signed Hub ingress endpoint for routed exceptions.

Every exception enters the same domain pipeline. The Workbench normalizes it, checks same-tenant duplicate source references, resolves the counterparty, scores possible dispute matches, and either creates a new dispute or opens a correlation decision for an operator.

The hard part was resisting the clean demo. A score over the review threshold is not truth. It is work. The system creates a pending correlation record and lets an operator accept or reject it unless an explicitly configured auto-merge policy clears the higher band.

The resolution side is separate. The Workbench owns dispute state and auditability. Workflow Engine owns execution. Notification Hub owns delivery. Both integrations are feature-flagged, so the queue still works as a standalone product.

System Flow

Architecture diagramScroll on small screens

Data Model

Architecture diagramScroll on small screens

Architecture Layers

Architecture diagramScroll on small screens

The Decision Log

Decision Alternative Rejected Why
Clojure and Pedestal CRUD framework with controller-heavy routing The product is data moving through tenant, status, audit, and correlation rules. Interceptors make that path explicit.
Pending correlation decisions Attach every high-scoring exception automatically Wrong attachment poisons the audit trail. Review-band confidence should create operator work, not mutate the case.
Hiccup and HTMX UI Single-page app Finance operators need forms, queues, detail views, and downloads. Server-rendered pages keep the workflow simple.
Feature-flagged integrations Require every ecosystem service to run Manual dispute creation and audit export must still work with Hub, Workflow, adapters, and NATS disabled.
Frozen tenant snapshot in PDF reports Live tenant lookup during export Audit packets need stable identity even after a tenant changes its display name, address, or branding.
Testcontainers upstream stub In-memory adapter fake Adapter correctness includes HTTP paths, headers, cursor query params, and stored source refs. Those need a real local boundary.

Ecosystem Integration

The Workbench sits between the finance systems already in the portfolio. Invoice discrepancies can flow from the Invoice Reconciliation Engine, while payment mismatches, contract breaches, and webhook delivery failures enter through the same exception boundary.

The outbound side is deliberately thinner. Resolution playbooks run through the Workflow Automation Engine, and dispute lifecycle alerts go through the Event-Driven Notification Hub. Everything is feature-flagged, so the system runs standalone when the ecosystem is off.

Results

The shipped code covers the local operations loop: adapter ingestion, manual exceptions, duplicate protection, correlation review, assignment, status transitions, Workflow Engine resolution, Hub event capture, stale-source alerts, and audit PDF generation.

The latest verification recorded 160 tests, 869 assertions, 0 failures. A separate performance guard proves the dashboard keeps totals while rendering only 50 open dispute links from a five-figure backlog. That matters because an operations console should not fall over because the queue did its job and accumulated work.

Before the Workbench, the operator has fragments: invoice discrepancies, contract breaches, payment mismatches, delivery failures, and manual notes. After it, they have a case with an owner, a timeline, resolution state, emitted events, and an exportable audit packet.

The current limit is persistence maturity. Domain state is process-local while the Datomic schema and validators are present. The next production hardening step would move mutations behind durable Datomic transactions without changing the public case workflow.

#clojure#pedestal#datomic#finance-operations#audit

The full system record for Dispute Resolution Workbench

Get Notified

New system breakdown? You'll know first.