Values
Every directional read, cell read and pattern read returns a Value. It is either a hit or a miss,
it knows why it missed, and it carries the provenance of the hit.
out.Set("loanAmount", bbox.Doc().Right("Loan Amount").Currency());// read coercionHit or miss
Section titled “Hit or miss”Found() → bool · Missing() → bool
Section titled “Found() → bool · Missing() → bool”Whether a value was extracted.
rule LoanAmountPresent "the amount must be readable" salience 20 { when bbox.Doc().Right("Loan Amount").Missing() then findings.Critical("LoanAmountPresent", "extraction", strings.Sprintf("Loan amount not found: %s", bbox.Doc().Right("Loan Amount").Reason()));}Reason() → string
Section titled “Reason() → string”Explains a miss: which stage failed, rather than an empty string that could mean any of four things — label not found, label found but nothing beside it, value found but the coercion rejected it, or scope excluded it.
This is the first thing to put in a finding when an extraction fails, and the first thing to log when a rule silently produces nothing.
Why() → string
Section titled “Why() → string”Renders the provenance of a hit: what text matched as the label, on which page, at what distance.
Reason explains a failure; Why explains a success. When a rule extracted the wrong value —
matched the label in the footer rather than the body — Why is what tells you.
rule TraceAmountRead "record where the amount came from" salience 5 { when bbox.Doc().Right("Loan Amount").Found() then log.Debug("loan amount provenance", "why", bbox.Doc().Right("Loan Amount").Why());}Reading the value
Section titled “Reading the value”Str() → string
Section titled “Str() → string”The extracted text, or "".
Num() → float64
Section titled “Num() → float64”The value as a number, or 0.
Thousands separators and a leading currency sign are stripped before parsing, so a bare "$1,234"
reads as 1234 rather than as zero.
Coercions
Section titled “Coercions”Each returns another Value, so they compose with Found(), Or() and Str().
Currency() → Value
Section titled “Currency() → Value”Strips currency symbols and thousands separators, leaving a bare number. Accounting parentheses are handled.
Replaces a hand-escaped regular expression that the production corpus repeated 328 times.
rule CaptureLoanAmount "the amount, as a bare number" { when bbox.Doc().Right("Loan Amount").Found() then out.Set("loanAmount", bbox.Doc().Right("Loan Amount").Currency());}Number() → Value
Section titled “Number() → Value”Extracts the first number in the value.
Percent() → Value
Section titled “Percent() → Value”Extracts a percentage as a bare number.
A %-suffixed number is preferred wherever it sits in the value; only when the value contains no
% does the first bare number win. That ordering matters on a line like "Rate 6.125% (APR 6.310%)".
Date() → Value
Section titled “Date() → Value”Normalises to YYYY-MM-DD.
A value that does not parse is a miss, not a zero date. The corpus guarded dates with
!= "0001-01-01" in seven places before this existed; with a miss there is no sentinel to compare
against — ask Found().
YesNo() → Value
Section titled “YesNo() → Value”Normalises an affirmative or negative to "Yes" or "No".
Single-letter forms count: a form’s answer column is routinely a lone Y or N.
TitleCase() → Value
Section titled “TitleCase() → Value”Title-cases the value.
Text() → Value
Section titled “Text() → Value”Trims the value. Present for symmetry — reads already trim — so a chain can be written uniformly.
Match(pattern) → Value
Section titled “Match(pattern) → Value”Keeps only the first substring matching the pattern.
| Parameter | Type | Meaning |
|---|---|---|
pattern | string | A regular expression |
The last resort, kept so the coercion set above can stay closed. Reaching for it repeatedly is a signal that a coercion is missing — worth reporting rather than working around.
Fallbacks
Section titled “Fallbacks”Or(fallback) → Value
Section titled “Or(fallback) → Value”Substitutes a fallback when the read missed.
| Parameter | Type | Meaning |
|---|---|---|
fallback | string | The value to use instead |
The result is found — but it carries no confidence, because it was supplied rather than extracted. That distinction survives into the output, so a downstream consumer can still tell a default from a reading.
rule PropertyTypeWithDefault "unstated property type is single family" { when in.Has("application") then out.Set("propertyType", bbox.Doc().Right("Property Type").Or("Single Family"));}Use it where the absence has a defined meaning. Where absence is a problem, raise a finding instead — a default quietly papers over a document you could not read.
Confidence and metadata
Section titled “Confidence and metadata”Confidence() → float64
Section titled “Confidence() → float64”The computed extraction confidence, from 0 to 1.
A real score, not a constant: label edit distance, value OCR confidence, alignment and proximity all contribute. It is worth gating on.
rule LowConfidenceAmount "the amount was read, but not clearly" { when bbox.Doc().Right("Loan Amount").Found() && bbox.Doc().Right("Loan Amount").Confidence() < 0.8 then findings.Warn("LowConfidenceAmount", "extraction", strings.Sprintf("Loan amount read at %s confidence", to.Fixed(bbox.Doc().Right("Loan Amount").Confidence(), 2)));}Attributes() → map
Section titled “Attributes() → map”The metadata a delivery profile may surface. The engine never inspects these; they ride along with
out.Set and a profile decides which reach the caller.
EngineValue() → any
Section titled “EngineValue() → any”Lets the engine carry the extracted text without a conversion at the call site.
A miss becomes null, which is what makes out.Set skip it — so writing a missing value does
not put an empty string in your output where a consumer would read it as data. You rarely call this
directly; it is why out.Set(path, someRead) behaves correctly.
The pattern worth keeping
Section titled “The pattern worth keeping”A read that missed and a read that found an empty string are different, and the API keeps them
different at every step: Missing() distinguishes them, Reason() explains which stage failed,
Or() marks a supplied value as unscored, and EngineValue() keeps a miss out of the output
entirely.
The one thing that collapses the distinction is Str() — a miss and an empty hit both give "".
Guard with Found() before Str() whenever the difference matters.
See also
Section titled “See also”- Document — the reads that produce a Value
- Tables and forms — cells and fields are Values too
to— conversion — converting after the coercion