Inspiration

Patient-assistance programs give free medication to people who can't afford it. Applications arrive through a few channels: faxes land in an email inbox as PDFs through fax-to-email tools like RightFax, physical mail is scanned by the ops team and hits the same inbox as PDFs, and web submissions come in as JSON. Each one then crawls through siloed systems and human agents, checked against a stack of rules — a slow, manual process.

The usual AI fix, asking a language model for the answer, trades one problem for another. The answer can change between runs, and nobody can audit it. I wanted AI where it's strong, which is reading messy paperwork, and I wanted the decision itself to stay fixed, explainable and repeatable.

What it does

Verdikt is an "AI in, deterministic out" decision pipeline. A scanned enrollment bundle goes in. A cited decision and a reply letter come out, and a human approves it before anything is sent.

  1. Ingest: a vision model reads the scanned pages into structured fields.
  2. Triage: NVIDIA Nemotron Nano classifies the case and routes it.
  3. Decide: retrieval finds the relevant program rules. Each rule is a structured formula, and the verdict comes from evaluating those formulas, not from a model's opinion. Where a rule has no formula, Nemotron Super reasons about it, and the case is flagged for a closer look.
  4. Deliver: the reply letter is merged from a frozen, human-approved template. No model is involved in producing it.
  5. Remember: every step is written to a hash-chained, tamper-evident audit trail. A reviewer can open any case and replay the full timeline: the extracted fields, the rules that fired, the citations and the letter.

The impact: an enrollment bundle that today crawls through siloed systems and multiple human hand-offs becomes one cited, human-approved decision in a single run. That's not a hypothetical workflow — it maps directly onto the intake operations I've seen inside specialty-pharma hubs, which is Verdikt's commercial path.

How I built it

Models (all on Nebius Token Factory, one endpoint and one API key)

  • Ingest: MiniCPM-V 4.5 reads every page of the packet into the program's fields. NVIDIA Nemotron-3.5-Super-VL can read the same pages as a second, independent reader, and any field the two disagree on goes to a human reviewer.
  • Triage: NVIDIA Nemotron Nano classifies each case (new intake, refill, appeal, missing info) and routes it. A rule-based classifier takes over if the model is unavailable.
  • Retrieve: Qwen3-Embedding-8B finds the program's human-authored rules that apply to the case.
  • Rules: NVIDIA Nemotron Super turns each plain-language rule into a structured formula when the rule is written, and the author reviews it before saving. At run time, code evaluates those formulas, and Nemotron Super reasons only over rules that don't have one yet. When every rule a case needs has a formula, no model makes the decision, and the audit trail records it.
  • Form setup: Nemotron Super labels the fields of a new PDF form template, with MiniCPM-V reading pages that are scanned images.
  • Deliver: no model. The reply letter is merged from a frozen, human-approved template and held until a reviewer approves it.

The model writes the logic once, under human review. Code applies it to every case.

  • The app is Python (FastAPI, Postgres, MinIO, Redis) in Docker Compose.
  • The demo program is the fictional CardioVita assistance program at Alderwood Specialty Pharmacy: a 105-field form and 9 eligibility rules.
  • A reviewer queue shows every case stage by stage, with the original PDF beside the extracted fields.
  • Verdikt grew out of an existing document-generation platform that I significantly extended during the submission period. The decision pipeline, review queue, rule formulas and demo seed were built in that period.

Challenges I ran into

  • Scans lie. The model once read the drug name as "Cardiovalta", and a strict text match then denied a valid application. I added a similar_to rule operator that allows a bounded number of character edits. It's still deterministic and still shown in the case trace: edit_distance(extracted, expected) ≤ 2.

  • Plausible nonsense. The extractor sometimes copied the date of birth into the signature date, and took the prescriber's name from the facility box. I added a section-aware merge, where the page with the most fields in a section owns that section, and it rejects signature dates that can't be real.

  • Same file, different answers. Early runs flipped between approve and deny. After fixing the causes above, the same scan approved five out of five times on my final deployment. That's a small sample, not proof.

Accomplishments that I'm proud of

  • The verdict is reproducible and cited. Every approve or deny points to the exact rules that fired and the values they saw.
  • The audit trail is hash-chained and replayable: every AI, human and system step links to the one before it, so a case history can be audited end to end but not quietly rewritten.
  • It works on real scans: a 105-field scanned bundle goes from upload to a reviewable decision and reply letter in a single run.
  • The letter step uses no model at all, so what a human approved is exactly what is sent.
  • A test suite of 921 passing tests, plus a one-command demo seed that rebuilds the whole Alderwood tenant on an empty install. The full architecture and engineering write-up behind the build is at verdikt.aismith.ai/engineering.

What I learned

Use the model only where the input is genuinely messy, and put a rule in front of every decision that matters. Making the verdict reproducible made the AI parts easier to trust. When something went wrong, I could see exactly which field was misread and fix it in one place.

What's next for Verdikt

More programs per tenant, a second read of critical fields, and reviewer corrections that feed back into better extraction. Beyond PAP, the goal is multi-tenant decision infrastructure for intake pipelines generally — anywhere AI reads the documents but the decision has to stay deterministic, cited and human-reviewed.

Built With

Share this project:

Updates

Submission history