← HomeРусская версия

Case study · Company due diligence

RISK — company due diligence with an explained risk signal

Before a deal, a business needs to understand its counterparty, identify material concerns and document the basis for its choice. RISK turns public company data into a traffic-light signal and a structured report: what is known, what is missing and what needs a closer look.

My role
Original product: concept, architecture, Python core, AI pipeline and frontend
Status
Live public demo with fresh checks and saved reports
Format
Russian companies and sole proprietors; demo interface in Russian

The business problem

Choosing a supplier or business partner means more than confirming that the company exists. A buyer needs to understand the available evidence, recognise warning signs and decide which questions to resolve before signing a contract or paying an advance.

In Russia, company registration records, filed financial statements, commercial court cases and enforcement records provide part of that picture. They are spread across sources and use different structures. A list of records still leaves the user with the work of interpreting them in the context of a proposed deal.

RISK accepts an INN, the Russian tax identification number of a company or registered sole proprietor. Checko, a business-data aggregator, supplies the underlying public registry and business information. The product organises it into a reviewable assessment rather than treating a registry lookup as the decision itself.

Decision support in its local context

In Russian tax practice, how a counterparty was chosen and whether a transaction actually took place matter. RISK helps document the basis for that decision; it does not provide a legal opinion or certify compliance.

A focused first product

The core workflow is deliberately small: one tax ID, a bounded set of data requests and one report. A live company check covers registration, finances, a limited selection of court cases, enforcement records and public procurement contracts. Sole proprietors have a separate, narrower data profile.

Accounts, billing, continuous monitoring and exhaustive investigations are outside the public demo. These boundaries keep the cost and response size manageable. The report must show missing sources and sample limits so that a smaller scope cannot be mistaken for a clean bill of health.

From tax ID to an explained assessment

  1. Collect and normaliseThe Python API validates the tax ID and fetches Checko data. The core normalises the responses, retaining reporting periods and parties’ roles in court cases. Missing values, unavailable sources and confirmed zero values remain distinct.
  2. Calculate the signalDeterministic Python rules produce the public green, yellow or red assessment from the available evidence. Its card shows the reasons, additional concerns and assessment coverage.
  3. Generate the explanationFor a live check, the LLM receives the prepared data, the calculated assessment and server-side analysis instructions. One streaming call produces the explanation, supporting facts, limitations and follow-up questions. The model does not choose the live traffic-light colour.
  4. Check for contradictionsAfter generation, programmatic checks look for defined conflicts with the input and the calculated colour. A detected conflict prevents the report from completing successfully. These checks reduce specific failure modes; they do not verify every sentence.

Domain expertise and my ownership

Expert methodology
The assessment is based on a professional methodology supplied by a domain expert on the client side and also used in commercial Legicon. It informs the server-side analysis instructions and assessment logic. I do not claim authorship of that methodology or publish its private rules.
Product and engineering
I built the original RISK product: the concept, user workflow, architecture, data integration and normalisation, Python core and API, LLM requests and report-generation pipeline. I developed the interface and owned testing and deployment. I continue to develop the demo with AI coding agents, retaining product decisions and code review.
The later commercial product
Legicon later reused this core. Another developer extended the commercial application layer, including its interface, accounts, email, pricing, billing and payments. That later work is a separate contribution.

Product decisions and interface evolution

A signal with reasons and limits
A traffic light makes the result easy to scan, but colour alone hides uncertainty. The product therefore shows what was assessed and why the signal was produced. Green is not a guarantee that every possible risk has been ruled out.
Stable signal, flexible explanation
An LLM can apply the same methodology, but the public demo computes the traffic-light signal in Python. This makes the result reproducible, avoids variation in model-based assessments and keeps the demo’s cost predictable. The model receives the calculated signal and the same criteria, then explains the reasons, data gaps and follow-up checks. In the extended saved reports, the model could produce the colour itself; the result is checked against the same deterministic engine.
A dedicated interface for the task
Early iterations used general-purpose chat interfaces, including LibreChat. I replaced them with a dedicated Nuxt frontend built around the due-diligence workflow: a tax ID, collection progress, an assessment and a report. The Python/FastAPI core remained.
Show a result before asking for input
A saved report opens immediately, so visitors can understand the product without finding a Russian tax ID or waiting for generation. Its date and mode distinguish the example from a fresh check.

Scope, cost and uncertainty

The live demo uses fewer sources than the extended profile behind the saved examples. Compression also selects a bounded subset of records. More data would increase cost and latency, so coverage and omissions are part of the result.

A fresh lookup can still return old reporting periods or incomplete records. The LLM can misstate a fact even when its input is structured. Source dates, explicit unknowns and output checks make the limitations inspectable; they cannot eliminate them.

Validation and testing

  • Core tests cover normalisation, assessment rules, unknown values and inapplicable indicators. API tests cover result delivery and external-service failures.
  • Fixed datasets exercise request-size limits and consistent public traffic-light calculation across live and saved modes.
  • Before publication, saved reports are checked against their source data for amounts, dates, court roles and unsupported conclusions. Reading actual model outputs complements automated checks.

This makes the result easier to audit: the user can inspect reasons, source coverage and report limitations. It does not turn an AI report into a legal opinion or independently verify the underlying registries.

What the live demo does

The public site supports a fresh tax-ID check and five saved reports covering different assessment colours. The examples use data collected in early October 2026; opening them makes no new Checko or LLM request.

Fresh checks show data-collection progress, then the assessment and a streamed report. Abuse protection and daily limits bound public usage: 20 checks per IP and 100 overall. The demo interface and reports are in Russian; the English portfolio explains the workflow and its boundaries.

Where human judgment starts

The useful outcome is a clearer set of facts and questions before a commercial decision. Contract terms, the counterparty’s capacity to deliver and evidence of actual performance still require human review. RISK helps prepare that review; responsibility for the deal stays with the business.

Technical summary

Backend and core
Python, FastAPI and legicon_engine: normalisation, assessment, LLM input preparation and output checks.
AI and data
Checko business data; one streamed LLM call through OpenRouter per live check; server-side methodology profiles.
Frontend and delivery
Nuxt, Vue and frontend TypeScript; SSE, SQLite for usage limits, Docker Compose and nginx. Builds run on Cabrio; the public runtime runs on Beget.

Want to talk about work like this?

Email or Telegram — I am happy to walk through any of the decisions above.