The model answers about blocks, never writes them
Laya never produces the text to redact or the rectangle to draw. It receives the OCR lines and answers yes/no questions about each one, with a probability. The rectangle always comes from OCR; the text always comes from OCR. The model can only say which of the lines it was shown look sensitive. This removes a whole class of failure. A model that writes text can hallucinate a phone number that isn’t on the page. A model that only answers questions about existing lines can’t.A fixed answer shape
Every answer is one probability per question per line, so there is nothing to parse and nothing malformed to repair. Redact still checks the one thing that could go wrong: ifdecide() returns a different number of results than lines, the run fails instead of guessing which result belongs to which line.
For each line, the most likely question at or above 0.5 becomes a candidate, with its probability as the confidence (Decision questions).
Each candidate then goes through validateCandidateForEvidence.
Rules get the last word on labels
validateCandidateForEvidence re-derives the label from the block’s text with plain rules: an @ makes it an email, “account” plus digits makes it an account, a house number plus “Road” makes it an address, and so on.
For most labels the model’s choice is simply replaced by what the rule finds.
A name is kept only if the text looks like two to four capitalised words.
Anything no rule supports is dropped, except other.
The test document’s disclaimer lines are always dropped.
Every suggestion shows a fixed explanation per label, so a reviewer never reads invented reasoning.
This is a strong position: the model decides which blocks deserve attention, and deterministic code decides what kind of thing they are.
The cost is reach: a sensitive value no rule recognises, such as a name in lowercase, is dropped even if the model was right.
That is the trade Redact makes, because a wrong label shown with confidence misleads a reviewer more than a missing one.