`in` — reading facts
in reads the facts handed to the execution. Every top-level key of the input is also bound under
its own name, so order["total"] works directly — in is what you use when you want a read that
cannot raise, a default, or a dotted path.
That distinction is the whole point of the namespace. A bare fact access on a key that is not there is an error; every function here returns a default instead.
Presence and equality
Section titled “Presence and equality”in.Has(path) → bool
Section titled “in.Has(path) → bool”Reports whether anything is present at path.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
rule RequireApplication "nothing to do without an application" salience 100 { when !in.Has("application") then findings.Critical("RequireApplication", "input", "No application supplied"); Complete();}in.Eq(path, value) → bool
Section titled “in.Eq(path, value) → bool”Reports whether the fact at path equals value. False when absent — which is the point: it
cannot raise, so it needs no guard.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
value | string | The string to compare against |
rule OpenOrdersOnly "only process open orders" { when in.Eq("order.status", "open") then out.Set("processed", true);}Written as order["status"] == "open", the same test raises when status is absent. in.Eq is
the form that survives incomplete input, which on extracted documents is most input.
in.EqInt(path, value) → bool
Section titled “in.EqInt(path, value) → bool”Reports whether the integer fact at path equals value. False when absent.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
value | int64 | The whole number to compare against |
Prefer this over in.EqNum for anything conceptually a whole number — a page number, a count,
a term in months — so the literal at the call site is a bare 1 rather than 1.0.
rule FirstPageOnly "classification runs on page one" { when in.EqInt("page", 1) then out.Set("classified", true);}in.EqNum(path, value) → bool
Section titled “in.EqNum(path, value) → bool”Reports whether the numeric fact at path equals value. False when absent.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
value | float64 | The number to compare against |
rule ExactRate "the rate is exactly the promotional one" { when in.EqNum("loan.rate", 6.125) then out.Set("promotional", true);}Typed reads
Section titled “Typed reads”Each takes a default and returns it when the path is absent or the value will not convert. None of them raise.
in.Str(path, def) → string
Section titled “in.Str(path, def) → string”| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
def | string | Returned when absent |
rule DefaultChannel "unstated channel is 'branch'" { when in.Has("application") then out.Set("channel", in.Str("application.channel", "branch"));}in.Int(path, def) → int64
Section titled “in.Int(path, def) → int64”| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
def | int64 | Returned when absent |
in.Double(path, def) → float64
Section titled “in.Double(path, def) → float64”| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
def | float64 | Returned when absent |
The same decimal-point rule applies to the default: write 0.0, not 0.
in.Bool(path, def) → bool
Section titled “in.Bool(path, def) → bool”| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
def | bool | Returned when absent |
in.Date(path) → Date
Section titled “in.Date(path) → Date”Returns the date at path, or the zero date.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
There is no sentinel to compare against: an absent or unparseable date is IsZero(), not the
literal 0001-01-01 you might be tempted to test for.
A Date offers three methods:
| Method | Returns |
|---|---|
IsZero() | Whether the date is absent or unparseable — the test to use |
String() | The canonical YYYY-MM-DD rendering |
Time() | The underlying time, for the time namespace’s arithmetic and comparisons |
Time() is the bridge: time.DaysBetween and time.IsBefore take times, so a date read from a
fact reaches them through it.
rule ApplicationAge "applications older than 90 days are stale" { when !in.Date("application.date").IsZero() && time.DaysBetween(in.Date("application.date").Time(), time.Now()) > 90 then findings.Warn("ApplicationAge", "freshness", "Application is more than 90 days old");}rule ApplicationDated "the application carries a readable date" { when !in.Date("application.date").IsZero() then out.Set("applicationDate", in.Date("application.date"));}in.Value(path) → Value
Section titled “in.Value(path) → Value”Returns the typed value at path, or Null. The general form — use it when you want to ask the
value about itself rather than convert it immediately.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
What a fact Value offers
Section titled “What a fact Value offers”This is the engine’s own Value, distinct from the
document read Value that bbox.Doc().Right(...) returns. Both
in.Value and out.Value produce it.
| Method | Returns |
|---|---|
IsNull() | Whether the value is absent |
Kind() | The value’s type, for diagnostics |
Str() | Text. Numbers and dates in canonical form; a null is "" |
Int() | An integer, parsing or truncating as needed |
Double() | A float |
Bool() | A boolean, read leniently so the Yes/No encoding used across document extraction lands correctly |
Date() | A Date, parsing a string if needed. A non-date returns the zero date |
Map() | The nested object, or nil |
Rows() | The table rows, or nil |
Any() | The underlying value |
Equal(other) | Equality, comparing across numeric kinds — so an integer 1 equals a float 1 |
Attributes() | The producer’s metadata, or nil |
WithAttr(name, val) | A copy carrying one more attribute |
WithAttrs(attrs) | A copy with the given attributes merged over any existing ones. The map is copied, so yours stays yours |
Equal comparing across numeric kinds is the useful one: it removes the integer-versus-float trap
that catches direct comparisons elsewhere in the language.
The two With* methods return copies rather than mutating, so the result has to be captured —
pass it to out.SetValue, or it is discarded.
rule TagProvenance "mark this value as derived rather than read" { when in.Has("computed.ratio") then out.SetValue("ratio", in.Value("computed.ratio").WithAttr("source", "computed"));}in.Map(path) → map
Section titled “in.Map(path) → map”Returns the map at path, or nil.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
in.Rows(path) → list of map
Section titled “in.Rows(path) → list of map”Returns the table rows at path, or nil.
| Parameter | Type | Meaning |
|---|---|---|
path | string | The fact name, or a dotted path |
rule HasLineItems "the input carried line items" { when array.Len(to.List(in.Rows("invoice.lines"))) > 0 then out.Set("lineCount", array.Len(to.List(in.Rows("invoice.lines"))));}Dotted paths
Section titled “Dotted paths”Every path argument accepts a dotted path — application.borrower.name — reaching into nested
maps without a chain of accessors.
Dotted-path reads are off by default and enabled per deployment. Where they are off, a dotted string is read as a single flat key, which is worth knowing because it fails quietly: the read returns your default rather than erroring. If a nested read is unexpectedly returning the default, that is the first thing to check.
Older forms
Section titled “Older forms”These still work, so rules written against them keep running. They are listed so you recognise them in an inherited ruleset; write new rules against the forms above.
| Older form | Write instead | Why |
|---|---|---|
in.Get(key) | in.Value(path) | Returns a typed value rather than a bare any |
in.GetStr(key) | in.Str(path, def) | Takes a default |
in.GetInt(key) | in.Int(path, def) | Takes a default |
in.GetFloat(key) | in.Double(path, def) | Takes a default |
in.GetBool(key) | in.Bool(path, def) | Takes a default |
in.GetMap(key) | in.Map(path) | Same shape, current name |
in.MemSet / MemGet / MemGetStr / MemGetRows / MemDelete / MemClear | out.Set | Scratch memory predates the output collector; what a rule computes belongs in the output |
in.GetMemAsMap() | out.Set | Returns a deep-copied snapshot, which is expensive and rarely what was wanted |
in.NewMapWithValues(k, v, …) | map.Of(k, v, …), or out.Set | Every use in the production corpus was building an output envelope inline |
The scratch-memory family is the one worth migrating deliberately. It was how rules passed values
to each other before out existed; using it now means a value that later rules can read but the
caller never receives.
See also
Section titled “See also”- Reading facts — the same surface as a guide
- Writing output — the other half of the pair
to— conversion — converting what you read