A similarity score cannot represent the word "not." It cannot represent "is-a." And it cannot represent "unless the therapy was completed more than twelve months before randomization." Those three things are what a clinical trial's eligibility criteria are actually made of, and no larger language model adds them, because they are not language problems. They are logic problems. For three years the patient-matching field has been trying to make the model a better judge of who gets into a trial. We think that is the wrong layer, and we built a deterministic eligibility reasoning engine to show why.
The stakes are not abstract. A day of enrollment delay costs roughly $800K in lost prescription sales (Tufts CSDD Impact Report, 2024), and the number climbs to $840K/day in oncology and $1.4M/day in cardiovascular trials (Tufts CSDD). Around 80% of trials miss their enrollment timelines (industry consensus, 2025), the average screen failure costs about $1,200 (Antidote.me, 2025), and the procedures packed into a single protocol are up 139% since 2005 (IQVIA, 2026). Into that pressure walks patient-matching AI that reads a clinical note as text and confuses words that look alike but mean different medical things. Published evaluations show models making exactly this error (Fierce Biotech, 2025). We built TrialProof (veriprajna.com/demos/clinical-trial-recruitment-ai) to compute the verdict instead of predicting it, and the demo runs entirely on synthetic patient records so the mechanism is visible without touching real PHI.
Why a better model doesn't close the gap
Consider the canonical mistake. A trial excludes prior "cardiac catheterization." A patient's note says "central venous catheter placement." To a vector-similarity matcher these are two cardiovascular catheter procedures sitting close together in embedding space, so it scores them high and excludes a patient who was eligible. The trouble is that closeness is the wrong relationship. What the criterion needs to know is whether one concept is-a kind of the other, and in the SNOMED-CT hierarchy Central venous catheterization (392230005) and Cardiac catheterization (41976001) sit on different branches. No subsumption path connects them. Both are real SCTIDs you can check on any public SNOMED browser.
The curated SNOMED-CT subgraph the engine queries: central venous catheterization and cardiac catheterization sit on separate branches, so no is-a path connects them (24 concepts, 22 is-a relations; curated concepts with no public code drawn dashed).
A bigger model can be more fluent about catheters and still not represent "is-a," because fluency is not a hierarchy. So we stopped asking the model to decide. In TrialProof the model does one job, the one it does well: it reads the messy prose and proposes candidate facts, each tied to the verbatim span it read them from. Everything after that is deterministic code over the ontology. The agents advise on extraction; deterministic code decides eligibility, and no LLM can override the verdict. (The model is provider-swappable and advisory only. We deliberately never surface which one, because swapping it must not change an answer.)
Watch one criterion compute
Here is a criterion a similarity score cannot even encode: "no prior platinum-based therapy, unless given as adjuvant or neoadjuvant and completed more than twelve months before randomization." On a synthetic oncology chart (P-101), the note records four cycles of carboplatin and pemetrexed given as adjuvant therapy, last infused 03/2025, against a randomization date of 04/2026. Watch the engine reason it out.
The EXCL-PLAT trace on P-101: the engine confirms Carboplatin (386905003) is-a platinum-containing agent, computes the interval at 13 months (> 12? True), and returns ELIGIBLE because the adjuvant exception is satisfied.
Four steps, each one checkable. It reads the prohibition and its exception. It walks the graph to confirm carboplatin is-a platinum-containing agent. It does the date arithmetic: interval = 13 months, past the 12-month ceiling. Exception satisfied, verdict ELIGIBLE. Now change one word in the record. On a second synthetic chart the same platinum therapy was given with palliative intent, so the exception does not apply and the engine returns EXCLUDED. Same criterion, opposite verdicts, both correct. The fair lexical baseline we score against cannot tell the two apart: it returns a similarity of 0.144 on the first and 0.141 on the second, guesses ELIGIBLE for both, and shows no provenance a reviewer could re-derive. That is the difference between a score and a computation.
The same deterministic layer catches the errors a text matcher never sees. A note reading "no evidence of diabetes" that a vector model matches to "diabetes" at similarity 1.0 gets its negated mention stripped by an adversarial verifier before it reaches the decision. A "family history of breast cancer" wrongly attributed to the patient is rejected at the verify stage on the subject check. A hallucinated drug the extractor proposes with no supporting note span is rejected because the span-present check fails. In each case the engine records which check fired and why.
The number clinical operations actually cares about
None of this is a leaderboard flex, and we are careful about scope. Re-running the demo's own harness on a fixed, labeled gold set of 13 cases drawn from 7 synthetic patients across 2 synthetic protocols, TrialProof scores 100% decision accuracy against the baseline's 53.8%. The baseline is not a straw man: it is a real TF-IDF cosine-similarity method whose decision threshold we cross-validated to its own advantage (t = 0.6932), and it still loses three eligible patients where TrialProof loses none.
The 13-case labeled gold set: 100% vs 53.8% decision accuracy, 0 eligible patients lost vs 3, and 100% vs 0% auditable-trace coverage, scored against the cross-validated lexical baseline.
On a fixed 13-case labeled gold set, the eligibility engine loses zero eligible patients where a fair, cross-validated vector baseline loses three. In recruitment, the number that matters is not a benchmark rank. It is the patients you did not throw away.
Why the moat doesn't erode as models improve
Here is the part that survives the next model release. Every decision the engine emits carries a reproducible reasoning trace, and re-running the whole gold set produces byte-identical output on every pass (13 of 13). The baseline carries a trace on 0% of its decisions, because a similarity score has nothing to show. When a required lab or vital is missing from the record, the engine returns NEEDS-REVIEW and names the specific missing element instead of guessing, and it routed two such cases to a coordinator on the gold set. Coordinators abandon tools that cry wolf. An honest abstention is how you keep their trust. And every verdict stays inspectable: click the cardiac-catheterization criterion from the start of this piece and its full trace opens.
A criterion trace a reviewer can re-derive: the engine checks whether Central venous catheterization (392230005) is-a Cardiac catheterization (41976001), finds no subsumption path, and returns ELIGIBLE, naming the SCTIDs and the deontic operation.
Every one of those decisions exports as a CDISC SDTM IE record in JSON and CSV, one row per patient and criterion, carrying the verdict, the reasoning trace, the SCTIDs, and the deontic operation. That is the artifact regulatory affairs asks for, and it is why we think provenance and a deterministic gate are a durable position rather than a feature a foundation model will absorb. A better base model makes the extraction cleaner. It does not make "is-a," "not," and "unless" representable in a score, and it does not hand a reviewer a trace that is identical on every re-run. The FDA's January 2026 Clinical Decision Support guidance points the same way: a matching aid a clinician can inspect and override, not an oracle. (TrialProof is a demonstration of that architecture, not a cleared device, and it does not make clinical decisions.)
We think eligibility belongs in code you can audit, not in a model you have to believe, and the running demo is at veriprajna.com/demos/clinical-trial-recruitment-ai. If you own patient matching at a sponsor or CRO, we would genuinely like to hear how your current setup handles it. When your matcher marks a patient excluded, can a coordinator open the reason and see the specific rule and the concept IDs that decided it, or does the tool hand back a score and a rank with nothing underneath? The failure mode is industry-wide, and we suspect the honest answers are less comfortable than the dashboards suggest.