Personal AI Research

Crimes of the 1%: A Sourced Database of Financial Crime Among the Ultra-Wealthy

A database that holds corporate and executive-level financial crime against its actual enforcement outcome — and what it takes to make "sourced" mean something more specific than a link at the bottom of the page.

July – October 2026 · Live at crimes.davidirving.dev

What it does

The database catalogs corporate and executive-level financial crime — fraud, market manipulation, tax evasion, state capture — against the actual enforcement outcome on record: criminal conviction, settlement, deferred prosecution, or litigation still in progress. Built the same way as the OSINT tracker: solo, in Google AI Studio, React and TypeScript on the frontend, Firebase/Firestore for persistence, Gemini for the analysis features.

Sourced by design, checked against the record

Every case carries one or more citations, each classified by a fixed document-type category — DOJ filing, SEC order, court judgment, CFPB enforcement, EPA record, ICIJ archive, investigative report, official statement — instead of a single unlabeled link. Spot-checking a handful of the seeded cases against the public record holds up: real settlement figures, real citations, the right order of magnitude for each penalty.

Each entry also converts its financial penalty into a worker-wage-equivalent figure — roughly how many years of an average salary the number represents — so a penalty in the billions turns into something with a felt sense of scale, alongside a companion dashboard that breaks the dataset down by sector and enforcement outcome, computed live from the actual case data rather than pre-baked.

The dashboard makes a specific point of visually separating genuinely computed figures from illustrative ones: two tiles pulled straight from the dataset get a solid border and a "From Dataset" label, and two comparison figures included purely to give a sense of scale — average household savings, average lifetime earnings — get a dashed border and an explicit "Illustrative" label instead. It's a small UI detail, but it's the actual mechanism behind "honest by design," not just a claim about it.

From Dataset Total penalties computed live from case data Illustrative Avg. household savings for scale only — not case-derived

Same card style, one deliberate visual tell — so "honest by design" is a mechanism a reader can actually see, not just a claim.

Two Gemini lenses, one real schema trick

An AI Fact-Finder modal takes a free-text question, sends the current case list into the prompt, and asks Gemini to answer "based on the provided dataset and verified public records" — returning both a written answer and a list of matching case IDs, which the interface cross-references to show clickable source cards rather than leaving the reader to trust unlinked prose.

An AI Patterns modal looks across the dataset for recurring sectors, common enforcement types, and systemic regulatory gaps, structured into an executive summary, several named patterns each with a supporting statistic, and a bulleted list of observed gaps. Both modals use Gemini's structured-output schema feature rather than asking for JSON in plain language and hoping the formatting holds — a real reliability choice, not just careful prompt wording.

A submission path that's honest about what it is

A case-submission form lets anyone paste a source document's text plus a URL, and Gemini extracts a structured record from it using the same schema-constrained approach as the two analysis modals. It publishes immediately — there's no moderation queue, and the interface doesn't imply one — tagged with a clearly visible "AI-generated, unreviewed" disclosure badge.

That badge's wording was chosen deliberately, not as a generic disclaimer: it specifically avoids implying that any human review took place, because the relevant EU AI Act provision's editorial-review exemption only applies where genuine, substantive human review actually happens — which this automated pipeline doesn't do. Saying less than that would have been the easier, and less accurate, choice.

A Firestore security fix, found the same way twice

This project shared the exact same class of vulnerability as its sibling OSINT tracker: Firestore rules that allowed open read and write access, with the frontend authenticating against Firestore directly using a necessarily-public client configuration instead of going through the backend for anything. Once that pattern had been found and fixed in the OSINT project, it got checked here deliberately, rather than assumed to be fine because nothing had gone wrong yet — and it was the same bug. Fixed the same way: migrated to the Firebase Admin SDK, closed the rules outright, and moved every real read and write behind the Express API instead of trusting the client.

Real, proactive legal compliance work sits alongside that fix, for the same underlying reason: an Impressum citing the specific Austrian Mediengesetz §25 disclosure that applies to a "große Website," and a privacy policy — both added because the project names real public figures and that carries real obligations, not because anyone asked or a regulator came calling.

The crawler that only pretended to crawl

The "four times a day" case crawler turned out to be a local template picker: it assembled plausible-looking cases, not found ones. Like its sibling project, it also ran for its first week on an API key that was the literal text "Not found.". In August it was rewritten as a real search-based harvester that fails closed: a new case is published only if its cited URL is one the search actually returned, not one the model typed, and a code-level duplicate check replaced a prompt that merely asked the model not to repeat itself.

The same citation trap as the OSINT tracker followed: combining search with structured output silently drops the citations, so for five days no real case could pass the gate. Search and extraction are now separate calls. Scheduling moved from an in-process timer, which died whenever the host scaled to zero, to an external scheduler that wakes the service four times a day. The public AI endpoints, each a billed model call, gained the rate limit the crawler trigger already had.

Every record now carries a visible provenance label, "Seed / curated" or "AI-generated, unreviewed", instead of leaving the difference to be inferred. Two cases were removed as out of scope for a financial-crime database, and one of them turned out to be using another case's photo.

October: no invented amounts, sources that last, and deep time

A case found by the AI now shows a penalty only when its source text states one, exactly as written. The stored value is read from that text, never from the model's separate number, which had disagreed with its own text. If the source page can be read, the figure must also appear on it. A case without a stated amount says "Not disclosed".

The source check became stricter and fairer at the same time. Government sites refuse requests from cloud servers, so the old check rejected almost every real case: in two weeks, 5 of 62 searches published anything. A readable source must now name the company or person in its main text, and a page that refuses the check counts only on an official site whose address names them. The search citations were Google redirect links that expire within days, which had left 35 published cases with a dead source. 17 were found again and passed the same checks; the other 18 now say plainly that the link no longer works.

Every model call now counts against a monthly budget spread across the month, and only the scheduler can start a case search. The inequality dashboard also gained a deep-time view: how far back a worker on the site's illustrative $10,000 a year would have had to start working, without a break, to earn a case's recorded amount.

The Deep-Time Payroll panel: Meta's $17.1 billion settlement would take a worker on $10,000 a year 1.7 million years, so they would have had to clock in before the earliest evidence of controlled fire. A timeline runs from 100 million years ago on the left to today on the right, above a leaderboard of the deepest-time cases.

Deep-Time Payroll: Meta's $17.1 billion settlement equals 1.7 million years of non-stop work, so the worker clocks in before the earliest evidence of controlled fire.

What actually mattered

Getting Gemini to return a clean, schema-constrained structure is close to table stakes now. What actually took real effort was everything around that: keeping "computed from the dataset" visually distinct from "illustrative for scale" instead of letting the two blur together, labeling AI-generated content for what it honestly is instead of what would be more convenient to imply, and treating a security pattern found once as something to go check for deliberately elsewhere — not a one-off fire that got put out and forgotten.

None of that shows up as a feature you can screenshot. It's the difference between a database that looks trustworthy and one that's actually built to survive someone checking.

Personal AI Research Gemini API Firestore Application Security