The investigation engines
Three parallel checks (documentation completeness, correspondent verification, and the flag engines), each a platform finding, each gated by what the letter turned out to be.
Once stage one has decided what a letter is, three independent checks run in parallel. Each is an instantiation of the platform’s four steps. Each emits a VerificationFinding. Each is gated on the classification, so a hardship letter doesn’t trigger a fraud investigation and a fraud claim triggers all of it. Their requirements come from three subject-matter-expert matrices (a red-flag list, an investigation checklist, and a documentation rule sheet) and all three live as versioned YAML registries the experts can revise without a release.
Documentation completeness
The question: does the account hold at least one original account-level document that proves the debt can be collected, and does that document carry the fields it needs to?
The rules are keyed on product type and seller. For each combination, an “any one of” set of acceptable document types, and for each type the fields it must contain. An exclusion matrix records where a document that is normally acceptable is not (because a particular originator never mailed it to the consumer) and what the substitute is, sometimes bounded by a date on the account. The registry encodes all of it; the engine is doc_checker over the document inventory, then per-candidate field completeness through the vision extractor, then a decision: complete, incomplete, or complete-with-new-documents.
The last outcome exists because customers sometimes enclose their own copy of an agreement. It can be matched in as evidence, but any document the model matched, rather than the index, requires an explicit colleague tick before it counts. This is the fail-closed rule at its most concrete.
A later cross-project discovery: the records product’s pre-legal document rules are the same seller-and-product-keyed shape, and they added a date-window check. A statement is valid only if its date falls in a window anchored on the account’s charge-off, not merely because it exists. That check was adopted here, and two places where the two rule sets disagreed went to the experts as questions rather than being resolved by guess.
Correspondent verification
Two parts.
Identity match. The vision extractor pulls the identity claims from the letter; the fetch registry pulls the system-of-record values; a deterministic weighted matcher compares them (string similarity for names, normalised tokens for addresses, exact match for references and dates) into a score and a three-way outcome: verified, needs review, failed. The thresholds are tuned for a false-accept rate as close to zero as the false-reject rate will bear, in that order, because a wrong “verified” is a data breach. Third-party correspondence (a law firm, a debt-management company) is detected as its own class and verified on authority to act, raising a flag either way.
The investigation checklist. Each row of the expert checklist is a gated step: which data source, which fields, what to check, which dispute reasons it applies to, which engine runs it. Steps over account data go through fetch-and-reconcile. Steps over statements go through the statement extractor. Steps over the customer’s own documents go through the presence checker. One finding per step.
Flags
Two engines, one Flag contract: code, severity, confidence, the evidence quote with its document and page, a rationale.
A structured-signal evaluator: the signals computable from account data alone, as deterministic rules over registry fields. One of them doesn’t flag at all; it escalates to a human, because the expert matrix said so.
A statement reader: the shared transaction extractor reads each seller statement once into a normalised list (date, description, merchant, amount, channel, country, posted-or-returned) with a citation per line. Deterministic rules over that list raise the remaining signals. The model never decides fraud. It produces records; code applies thresholds; every flag cites the verbatim statement line.
Alongside these, an operational flag classifier for the letter itself (the category of dispute, a cease-and-desist, a litigation threat, a data request) with deterministic augmentations for statute calculation and regulatory clocks, and a separate high-recall pass for vulnerability and self-harm. That pass is separate because its recall target is non-negotiable and its precision target is not, and one classifier cannot be tuned for both.
What is deliberately not in the code
The thresholds. The expert matrix says “multiple”, “short timeframe”, “several days”. Those are numbers the business owns, they are open questions on the spec, and the engine reads them from config rather than guessing. Until they’re set, the rules that need them emit review.