Confidence and readings¶
Every value in a recognition result arrived with some amount of doubt attached to it. How that doubt is reported is a decision, and this page is the argument for the decision that was taken.
Two things follow from it. Confidence is published as a band and never as a number. A field read more than once is published once per reading, rather than collapsed into a winner.
Why a band and not a number¶
The engine produces a probability for each value it reads. Publishing that number would be the obvious thing to do, and it would be worse than what the service does instead.
A recognition probability is not a calibrated percentage. It is a score a model produced about its own output. It does not mean that 97 out of 100 values scored at 97 are correct. Nothing in the pipeline makes that true, and nothing measures whether it is.
A caller who sees 0.97 builds a threshold on it anyway. That is what a
number invites: somebody writes if (confidence > 0.95) and ships it, and the
threshold now carries a claim nobody ever supported. When the model changes,
the distribution behind the number moves and the threshold silently starts
meaning something else.
The result therefore publishes high, medium or low, and the boundaries
are fixed: high from 90, medium from 60, and low below that. A value
whose probability the engine did not report reads low rather than being
absent. Absence is the one answer that would let a consumer treat unknown as
fine.
Three bands are about as much as the underlying number honestly supports. They are enough to sort a queue, to route a document for review, or to color a cell in a report. That is what a caller actually does with confidence.
What a band is about¶
A band describes the reading, not the document and not the holder.
A low band on a surname says the characters were hard to make out. It does
not say the surname is wrong, and it does not say the document is forged. It
is not an authenticity signal of any kind.
The reverse matters as much. A well-made counterfeit produces a high band on
every field. Its print is clean, so it reads cleanly. Confidence measures
legibility.
The document's own type match carries its own band,
document.type_confidence. It answers a different question again: how sure
the engine is that this page is the kind of document it says it is.
Why one field has several readings¶
A document prints the same fact in more than one place, and sometimes in more than one script. The engine reads each of them.
The response keeps them apart. fields carries one entry per reading, and
each entry names the language it was read under. A Greek passport prints the
holder's surname in Greek and again transliterated into Latin, and both
entries are published, each with its own band.
Collapsing them would throw away the only thing that makes a disagreement visible. Two readings of one name that differ are a signal; one value chosen by us for reasons the caller cannot inspect is not.
This is why an entry's id and not its name is the unique value. name
repeats across the readings of one field, on purpose, and a consumer keying on
it keeps whichever arrived last.
The curated blocks beside the list — holder and document — carry one value
each, in Latin. A great many consumers want exactly that, and should not have
to walk a list to get it. The list is there when the choice matters.
Why the picture gets one verdict¶
quality.overall is a single word about the uploaded picture, and there is no
breakdown beside it.
An earlier shape published the engine's own list of checks. Each check was
named by an integer, and those integers have no verified map to anything a
person can read. A caller was handed check_7: fail and could act on none of
it. Not on which check it was, not on what would satisfy it, not on whether it
mattered.
One verdict a caller can act on is worth more than a list they cannot. A scan
whose quality reads fail is a scan to re-photograph, and that is the whole
of what the breakdown would have told them.
The same reasoning governs the machine-readable zone. Its verdict is a status and one sentence naming what did not check out, rather than a table of per-digit results. What the sentence names is enough to act on. The zone itself is published verbatim for anyone who wants to re-run the arithmetic.
Why not_checked is not pass¶
Both quality.overall and authenticity.overall can read not_checked, and
that value exists to avoid a lie.
A scan read back from storage carries no engine output. The result is rebuilt from what was written down when the scan ran. The engine's assessment of the picture was not part of it. The picture itself was never kept, so nothing is left to assess.
Reporting that as pass would vouch for a photograph this process never saw.
A consumer reading a stored scan would be told the picture was good enough, on
the authority of nobody.
not_checked says the honest thing: nothing measured this. It is a third
answer, distinct from both pass and fail, and code that branches on
quality has to handle it. That is the cost of the honesty, and it is small.
authenticity.overall reads not_checked for a different reason. This
service performs recognition, and recognition is not authentication. Nothing
here inspects security features, and a field that would report on them says so
rather than staying silent.
What to do with a low band¶
A band is an input to your own policy, and the policy is yours because the consequences are.
A document that decides a small refund and a document that opens an account do not deserve the same threshold. No default we could choose would be right for both. What the service can do is report legibility honestly and leave the decision where the risk is.
Two things are worth pairing with the band. The machine-readable zone's verdict is an independent check on the same values, and it is arithmetic rather than opinion. And a second reading of the same field, where one exists, is a second opinion the engine already gave you.