This is a technology demonstration, not a medical device
Synthetic data only. No real patients, no real prescriptions, and nothing here is clinical advice. The catalogues are public reference data and the gate is a software invariant, not a regulatory approval.
This project quotes ISMP, the FDA, the Joint Commission and 21 CFR. It is not affiliated with, endorsed by, or reviewed by any of them. Those citations establish that read-back is an existing requirement; they establish nothing about this software.
Do not enter real patient data into this application.
Prescription intake that proves it did not mishear
High recognizer certainty does not protect against two medicines that sound alike.
The mechanism and the business case
A recognizer can be certain and wrong: for example, the caller says hydromorphone and it returns morphine at certainty 1.00. Readback asks which of the listed names was meant whenever a drug name falls in a look-alike pair published by ISMP, and a yes does not answer it, however confident the recognizer was. It writes nothing a validator or the caller has not proved.
Who pays: a pharmacy or telepharmacy service, per verified order. That is our hypothesis, not yet validated with buyers.
Who gets the order: the pharmacist, with every value's spoken words, timecodes and proof attached, before anything is dispensed.
The 14-second replay
One synthesised call runs through the shipped gate twice. Both columns read the drug name back; they differ by one flag, the pair rule, and only the column with the rule on needs a spoken name as the answer.
Ground truth for this replay
The caller said
hydromorphone
The recognizer heard
morphinecertainty 1.00
Both drugs exist, both pass a catalogue lookup, and both are opioid pain medicines dosed differently, which is why a swap between them is dangerous.
0.0/13.6 s
Session open on short-lived tokens, patient already named; the drug comes nextCaller says the drug nameRecognizer finalises the turn at 1.00 certaintyGate reads the published pair tablePair rule on: asks which of the two. Pair rule off: reads morphine backCaller answers: names hydromorphone with the pair rule, says yes without itPair rule on: hydromorphone written. Pair rule off: morphine written
session clock 5.0s / 18.6s
Pair rule onshipped
Will ask which of the two names was meant, and wait for a name
RE-ASK at certainty 1.00: Hydromorphone or Morphine? Only a spoken name answers
hydromorphone written: the drug that was said
Pair rule offcomparison only
Will read morphine back and take a yes
Reads morphine back at certainty 1.00; a yes will confirm it
morphine written, where hydromorphone was said
Pair rule on
The shipped policy. The drug name sits in a published pair, so the read-back names both drugs and only a spoken name answers it. A yes does not.
What the agent will say
morphine and hydromorphone are on a published confused-drug-names list. Which: morphine, M-O-R, or hydromorphone, H-Y-D? Answer with a name.
decided by the same gate function, reason code E_LASA_HIT
What the caller will answer
“Hydromorphone.”
read as E_CALLER_NAMED_LASA_PARTNER
What entered the order
Nothing until a name is said
The agent will ask which of the two drugs was meant, and wait for a name.
Nothing yet
Waiting for the caller to say one of the two names. A plain yes here is answered with E_LASA_NAMED_ANSWER_REQUIRED and writes nothing.
hydromorphone 2 mg/mL injection, intravenous
The caller said hydromorphone, which corrected the recognizer, and that is what was ordered. Certainty was 1.00 the whole time; the question, not the number, caught it. Had the caller said yes by reflex, nothing would have been written: E_LASA_NAMED_ANSWER_REQUIRED.
Pair rule off
The same policy with one flag changed: the pair check is off. The drug name is still read back, because the shipped policy reads back every drug name, and a yes confirms it.
What the agent will say
Confirming the drug name: morphine. Correct?
decided by the same gate function, reason code E_READ_BACK_REQUIRED
What the caller will answer
“Yes.”
read as C_CALLER_AFFIRMED
What entered the order
morphine 2 mg/mL injection, intravenous will enter after a yes
The agent will read the heard name back and accept a yes.
Nothing yet
Waiting for a yes or a no to the read-back.
morphine 2 mg/mL injection, intravenous
Morphine was ordered where hydromorphone was spoken. The read-back happened and the caller said yes: a caller who expects to hear a name can confirm the one read to them. Certainty was 1.00, the catalogue lookup passed, and no threshold catches it.
Playing without sound, because browsers only allow sound after a click. Press play to hear it.
No one is speaking.
Show how this was decidedThe field card: what proves the value, the recognizer’s certainty and the spoken words with their timecodes
The gate has not been asked anything yet
Every proposed value passes through one decision function before it can enter the order. Its verdict, and the reason code behind it, appears here as it happens.
Drug nameCriticalattempt 1
morphine
heard as "Morphine"
Not yet decided by the gateLook-alike paircatalogue
Recognizer heard
“Morphine”
0:06.80–0:07.62
Recorded as
morphine
What proves this value
Independently verified
ndc_catalog
product.txt lookup: proprietary_name or nonproprietary_name exact match
morphine sulfate is present in the built catalogue as a nonproprietary name
matchedColumn
nonproprietary_name
saltStripped
morphine sulfate
Proved by existence in the built NDC catalogue. There is no check digit here.
What the recognizer claims about itself
Recognizer said, of itself1.00 on its least certain word
field threshold 0.95 marked on the track
This name is on a published look-alike list, so this number will not decide it. The gate has not decided yet.
Proof decides first; the recognizer's own certainty comes second.
The spoken words this value came from
computed in the browser from the STT socket, so it is client-supplied
span 6800-7620 msturn 21 wordsmean 1.00
Transcript as shown to the operator: “Morphine two milligrams IV every four hours as needed.” (formatted turn)
What the pair rule catches, and what it costs
The replay is one call. Measured over 20 seeded pair mishearings, each answered by a reflex yes, the two columns end the same way every time.
Pair rule offwrong drug written
20/20
Pair rule onwrong drug written
0/20
npx tsx scripts/measure/ab-gate.tsn = 20, text candidates
Pair rule on, cost of its questionlonger than a plain read-back, per name it asks about
9.4 s
About 11.8 s against 2.5 s, at the desktop synthesiser's rate; the agent's own voice has not been timed. The coverage run put it to 21 of 59 correctly heard names.
Sentences to try on a live call, a guided tour, one-button scenarios on the shipped gate, the keyterms A/B and recorded audio.
Say these three things
On the live call, these three sentences show the three ways a value is proved or stopped. The outcome and reason code beside each one come from the shipped gate function, run on this page.
Say
What the gate does
Why
“Lisinopril, ten milligrams, one tablet by mouth once daily, thirty tablets.”
RE-ASKE_READ_BACK_REQUIRED
Each value is read back once. Say yes and it is written; the order commits when every critical field is proved.
“Hydromorphone, two milligrams.”
RE-ASKE_LASA_HIT
Asked again even if the recognizer is certain, naming every drug the published list pairs with it. Answer with the name; a yes does not confirm it.
“Prescriber NPI one two three four five six seven eight nine zero.”
REFUSEDE_VALIDATOR_CHECKSUM
Refused by arithmetic before anyone reads it back, then asked for digit by digit.
The 90-second tour
1
Open the replay. 15 s
It starts by itself. At the decision the banner reads RE-ASK with E_LASA_HIT at certainty 1.00, candidates Hydromorphone / Morphine.
The shipped arm asks which of the two drugs was meant and writes hydromorphone only after the caller names it. The same policy with the pair rule switched off reads morphine back, takes a yes, and orders morphine.
Start a live call and say: Hydromorphone, two milligrams. 20 s · needs a microphone
Observed on production with a synthesised caller, not yet with a human voice: the agent names hydromorphone and every drug the published list pairs with it, and waits for a name, not a yes. The gate banner names E_LASA_HIT.
ShowingA published look-alike name at full certaintyE_LASA_HIT
The recognizer reported 1.00 and every check passed. The published pair table is read before the threshold, so the gate asks anyway.
Each button replays one synthesised situation through the shipped gate and the shipped validators. The label of the scenario on screen sits in the header above, so what is being shown is never a guess.
What the caller said
hydromorphone
What the recognizer returned
morphine
This is the scenario the product exists for. The ask happens at the ceiling of certainty, where raising a threshold could not have produced it.
Drug nameCriticalattempt 1
morphine
heard as "Morphine"
Confirm aloud: look-alike paircatalogue
Recognizer heard
“Morphine”
0:06.80–0:07.18
Recorded as
morphine
Look-alike pairNeeds the name, not a yes
Heard asmorphineconfusable withhydromorphone
source ISMP-2023 · ISMP List of Confused Drug Names, updated through February 2023: HYDROmorphone - morphine
What proves this value
Independently verified
ndc_catalog
product.txt lookup: proprietary_name or nonproprietary_name exact match
morphine sulfate is present in the built catalogue as a nonproprietary name
matchedColumn
nonproprietary_name
Proved by existence in the built NDC catalogue. There is no check digit here.
What the recognizer claims about itself
Recognizer said, of itself1.00 on its least certain word
field threshold 0.95 marked on the track
Outranked on this field by a published look-alike pair. This number is not what decides here.
The published pair decides this field, even though the recognizer was above threshold.
The spoken words this value came from
computed in the browser from the STT socket, so it is client-supplied
span 6800-7180 msturn 21 wordsmean 1.00
Transcript as shown to the operator: “Morphine two milligrams.” (formatted turn)
The keyterms A/B, and why only one arm can be run
The shipped list carries clinic, prescriber, dosage and route words, never a drug name the pair check examines. A list that names pair members would bias the recognizer toward the very strings the read-back then confirms, so that arm is described and never run.
Where this A/B comes from
A competitor invites the reader to try it: ask for your hydrochlorothiazide, then delete the list and publish again. The invitation is a good one, and the vendor documents the biasing effect; we have not measured it. One of the two arms, though, is a configuration this product will not ship, so the switch below shows what each list does to the read-back instead of offering both as settings.
What this deployment sends as keyterms
Mercy Family Clinic
Northside Pharmacy
Lakeview Medical Group
Riverbend Health Center
Doctor Alvarez
Doctor Whitfield
Terms in the list this deployment sends
92
Of those terms sit on the published pair table
0
Both counts are computed in this page from the list the deployment builds (buildKeyterms in src/lasa), and make keyterms-purity fails the build if a pair member enters it.
What the recognizer is pushed toward
Clinic and prescriber names, dosage forms, units, route words and the spelling alphabet. Not one of these is a string the pair check examines.
What a read-back then proves
The recognizer's output on a drug name owes nothing to the rules that verify it, so a confirmation is evidence about what the caller said.
The shipped arm is the one the recorded sets were measured on: every result file under eval/ carries keyterms 0 for the recognizer socket, and the identity context that does go in is sampled below.
Why the biased arm is invalid, not merely worse
Keyterms bias the recognizer toward exactly the strings listed. Put a pair member in the list and the recognizer returns that string more readily; the read-back then asks the caller to confirm the string the configuration suggested. The confirmation still happens, and it still proves nothing the configuration did not already assume. That is what makes the second arm invalid as a product option rather than merely worse.
Both columns are read off the built lists and the curated pair table on this page. Nothing here opens a socket or sends audio, so the comparison costs no credit and needs no microphone.
Recorded audio
No recorded live session has been published yet, so the replay above is the synthesised one. When a recorded call is published it plays here with its real audio.