About Clarion · live on real CFPB data

The complaint-intelligence layer that shows its work.

Every classification is either backed by a verbatim quote from the original complaint or it isn't made at all — and every human decision that overrides it is permanently, immutably recorded with the reason why.

About this project

What Clarion is

Clarion turns messy, free-text complaints into a controlled taxonomy your team can actually trust — because every classification either points to the exact sentence that justifies it, or it doesn't get made. Built on the public CFPB Consumer Complaint Database as a live, working proof: real ingestion, real classification, real human review, running in production today at signal.prateekmulye.dev.

What we offer

Evidence-grounded classification
Every category we assign is backed by a verbatim quote from the complaint. If the evidence doesn't hold up under a strict, deterministic check, we don't guess — we route it to a human instead.
A human review queue that closes the loop
Low-confidence and contradictory cases go to a keyboard-driven triage queue. Every accept or correction is transactional, idempotent, and — for corrections — requires a written reason, which also becomes a new training example for our evaluation suite.
An audit trail you can actually stand behind
Every classification, every review decision, and every model/prompt version is written to an append-only log with no update or delete path, enforced at the database level.
Bring your own model, bring your own data source
Clarion's classification engine is written against swappable adapters — plug in your own LLM provider and your own complaint feed without touching pipeline code. ROADMAP file-drop / SAP QM source adapters are specced, not yet shipped — today's only live source adapter is the CFPB API
Trend intelligence with honest denominators
See how failure modes move over time, compare your data against a live national baseline, and know immediately when that comparison isn't representative — when the national baseline is stale, the page says so before it shows you a number.
Company names, resolved the honest way
Bank names change — mergers, rebrands, charter conversions. Clarion cross-references FDIC's own free public institution records to link a bank's historical names to its current one, and shows exactly which names came from FDIC versus Clarion's own spelling normalization. We never guess: an ambiguous match is left unmerged rather than silently combined. ROADMAP Exact/normalized matches only today — fuzzy or multi-hop merger-chain matching (e.g. bank A renamed to B, B later absorbed into C) is a deliberately deferred, human-reviewed upgrade, not yet built.

FDIC BankFind institution + name-history data, fetched 2026-08-31. Refreshes daily; used only to link company names already present in Clarion's own corpus, never to add new ones.

How it works

1

Ingest

A complaint narrative comes in through a source adapter (today: the CFPB public API).

2

Scrub

Personally identifying details (emails, phone numbers, SSNs, account numbers) are redacted before the narrative is stored or sent to any model.

3

Classify

An LLM proposes a taxonomy code and the verbatim spans that support it.

4

Ground or abstain

Every span is checked, in code, against the scrubbed narrative. Any span that doesn't match exactly — no fuzzy matching — downgrades the whole result to "abstained" and sends it to review.

5

Review

A human confirms or corrects the classification. Corrections require a written reason and become new evaluation examples.

6

Log

Every step above is written to a permanent, append-only record — nothing is ever silently overwritten.

7

Learn

Trends and leaderboard views surface how failure modes shift over time, compared against a live national baseline.

For developers

Architecture & API show

Implementation detail for engineers evaluating the system — collapsed by default. The product story above stands without it.

Architecture

Clarion's ingestion and classification are written against two swappable behaviours — Clarion.Ingest.Source and Clarion.LLM.Adapter — so a new complaint source or a customer's own LLM provider is a config change, not a pipeline rewrite. That same seam is the data-residency story: a customer can point classification at their own model, keeping regulated text inside their own boundary.

Data quality

Company names are lightly normalized before ranking — CFPB's own company field can carry more than one spelling of the same registered legal entity (a stray comma, "N.A." vs "NA"). Clarion merges those, and additionally cross-references FDIC's free public institution records to link a bank's own prior names and the institutions it directly absorbed. It still does not merge a company's separately-chartered bank subsidiary with its parent holding company — those remain distinct rows, since that would require a fuzzy registry match Clarion deliberately defers to human review rather than guessing. Rows with more than one merged spelling show a "N variants" disclosure on the leaderboard listing exactly which raw strings were combined, and where each came from.

API access

Live — read-only

Clarion's second production surface: a read-only GraphQL API running in-process next to this app, over the same database, with the same evidence-grounding guarantees — callable from your own code instead of a screen.

Browse the schema, run queries, see real results — no setup.

Endpoint, for code /api/graphql

POST a GraphQL query from curl, Python, a notebook, or any client.

Three fields available today

  • taxonomy(version) The controlled failure-mode taxonomy Clarion classifies against — codes, human labels, descriptions.
  • trends(dimension, interval, since, until) The same aggregate counts behind the /trends page.
  • complaint(id) One classified complaint: its evidence-grounded classification, the verbatim quotes that support it, and its review status.

Guardrails

Max query depth

8

Max query complexity

200

Rate limit

30/min per IP

Query timeout

5s

ROADMAP A deliberately narrow first cut. Not in it yet: browsing or searching complaints from GraphQL, organization aggregates, the national-baseline series, an API-key tier, and the audit-trail field — all specced in docs/10_GRAPHQL_API.md, none shipped.

Example query

{
  taxonomy { code label description }
  trends(dimension: FAILURE_MODE, interval: MONTH) {
    periodStart label count
  }
  complaint(id: "1") {
    receivedOn
    classification {
      taxonomyLabel
      status
      evidence { quote }
    }
  }
}

The complaint(id) example always resolves to the same real, evidence-grounded record, so it keeps working over time. There's no way yet to browse other complaint IDs from GraphQL itself — that's the next field on the list.

Source

Private repository; access on request for evaluation.

Security

What protects your data

Clarion is a server-rendered analytics product. This is the honest posture for an app of that shape — each item below is a property the system holds today, not a marketing aspiration.

In transit
TLS 1.3, terminated by Caddy with auto-renewed certificates. Port 80 serves only a redirect to HTTPS and the certificate-renewal handshake; no content is ever served in plaintext.
At rest, on disk
The Oracle Cloud volumes holding the database and event log are AES-256 encrypted at rest by default — there is no unencrypted option. Keys are cloud-managed today.
Passwords
Never stored. Only a bcrypt hash (per-password salt, work factor) is kept; the plaintext is discarded the moment it's hashed.
Session & reset tokens
Opaque random values — only their hash lives in the database, so a database or backup disclosure can't be replayed into a live session or a working reset link. Sessions are revocable and expire on a hard 14-day ceiling; reset links are single-use and expire in 20 minutes.
Abuse resistance
Login and password-reset endpoints are rate-limited; authentication responses are constant-time and generic, so they never reveal whether an account exists. The review console sits behind both app auth and a second HTTP-auth layer.
Accountability
Every reviewer decision is written to an append-only log, enforced by a database trigger with no update or delete path, bound to the authenticated identity — corrections capture a written reason and nothing is ever silently overwritten.
Data minimization
CFPB personal information is scrubbed before storage and before any model call; embeddings derive only from the scrubbed text.

Why we don't say "end-to-end encrypted"

End-to-end encryption means only the endpoints hold the keys and the server can't read the content. Clarion's server must read every narrative in plaintext — to scrub PII, generate embeddings, run semantic search, classify against the taxonomy, and render the console. The server is a designed reader of the data, so end-to-end encryption isn't merely missing here — it's architecturally incompatible with what the product does. Claiming it would be false. What we do provide — TLS in transit, AES-256 at rest, hashed credentials and tokens — is the correct, honest 2026-grade posture for an app of this shape.