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