Companion film
Rules that act
Cross an operating threshold and see the model escalate review work automatically.
19 secGrid 0.61.0
Open film page →Guided build · 13
React to conditions, retain deliberate operational state, and choose explicit timing and missed-run behavior.
You will finish with: An operational playbook with predicate and transition rules, atomic writes, durable state, and three timing contracts.
An operational playbook that derives current status, reacts to live conditions, records durable events, and handles recurring and one-shot schedules deliberately. You will start from the canonical Rulebook Operations example and test each trigger in a copy you can safely change.
By the end, you will know when a formula is enough, when a rule should act, and how Grid preserves operational state across evaluation waves, model reloads, and runtime restarts.
Open Grid and paste the canonical Rulebook Operations source from the linked example into a new model. Its five authored source values begin at:
A1 = 0
A2 = 0
A3 = FALSE
A4 = 0pct
A5 = "clear"
The first three outputs are ordinary formulas:
B1 = A3 THEN "frozen" ELSE A2 > 0 THEN "incident" ELSE "normal"
B2 = A4 > 5pct THEN "gap-open" ELSE "steady"
B3 = A1 > 100 THEN "heavy-flow" ELSE "steady-flow"
| Binding | Expected value |
|---|---|
B1 |
"normal" |
B2 |
"steady" |
B3 |
"steady-flow" |
The model also captures its first successful evaluation:
H1 = NOW() ONCE
H1 should contain that evaluation's timestamp. It is not a recurring clock: an unchanged ONCE assignment keeps the captured value through same-model replacement and runtime-host restart.
The other targets are owned only by rules. C1:F2 begin as BLANK until their rules fire,
unless this model identity already has persisted scheduler state. G1:G2 are also blank on a
fresh identity admitted before 2026-12-31T23:59:00Z; at or after that moment, their BACKFILL
policy admits the one-shot close immediately.
Checkpoint:
B1:B3match the table andH1contains a timestamp. On a fresh model identity,C1:F2have no value before their first trigger or tick. Before the declared year-end moment,G1:G2are blank as well; afterward, expect the one-shot values described in step 5.
Keep A3 = FALSE and change A1 from 0 to 125:
WHEN A1 > 100 AND A3 = FALSE THEN
C1 = "risk-review"
C2 = NOW()
END
The settled predicate is true, so Grid commits both actions as one rule wave.
| Binding | Expected value |
|---|---|
B3 |
"heavy-flow" |
C1 |
"risk-review" |
C2 |
The rule's firing timestamp |
Change A1 again while the predicate remains true. The rule is eligible again, and C2 receives the later firing time.
This is predicate behavior, not transition behavior. A predicate rule is evaluated when one of its dependencies is touched and may fire whenever its newly settled result is true. Use BECOMES TRUE when only the false-to-true transition should act.
Change A3 to TRUE. B1 becomes "frozen", but the existing values in C1 and C2 remain.
A rule write is sticky operational state. Making the trigger false does not undo an earlier write. This is useful when the model must remember that a review was requested, rather than merely describe whether review conditions are true now.
Now change A5 to "degraded":
WHEN A2 > 0 OR A5 = "degraded" THEN
C3 = "ops-paged"
C4 = NOW()
END
Checkpoint:
B1 = "frozen", whileC1still reads"risk-review".C3 = "ops-paged"andC4contains this rule's firing timestamp.
Use a formula for a value that should continuously describe current inputs. Use a rule for an event or fact that should persist. If operational state must clear later, author a separate rule with the intended reset behavior.
Change A4 from 0pct to 6pct:
WHEN A4 > 5pct THEN
D1:D3 = ROW_INDEX
END
Expected results:
| Binding | Expected value |
|---|---|
B2 |
"gap-open" |
D1 |
1 |
D2 |
2 |
D3 |
3 |
Grid broadcasts the expression over the finite range and commits the writes as one atomic rule wave. Every action expression in a wave reads the same pre-commit snapshot. Dependent formulas recompute only after the rule's writes commit.
The model contains an interval, a cron schedule, and a one-shot moment:
EVERY duration"PT15M" SKIP MISSED THEN
E1 = E1 + 1
E2 = NOW()
END
EVERY cron"0 * * * *" BACKFILL THEN
F1 = F1 + 1
F2 = "hourly-reconciliation"
END
AT dt"2026-12-31T23:59:00Z" BACKFILL THEN
G1 = TRUE
G2 = "year-end-close"
END
On their next admitted occurrences:
E1 and stamps E2.F1 and labels the reconciliation in F2.AT block fires once at its declared UTC timestamp.The missed-run policies make downtime behavior explicit:
SKIP MISSED ignores interval occurrences that passed while the runtime was down and resumes at the next future tick.BACKFILL performs one catch-up wave after missed work, even if several occurrences passed.AT timestamp is already past when an unfired model is admitted, BACKFILL runs that block once.Exact counter values and timestamps depend on the runtime clock and its persisted scheduler state. Treat these as observation checkpoints, not fixed fixture values. In a disposable training copy, you can temporarily change PT15M to PT10S, observe a future tick, and then restore the canonical interval.
Checkpoint: after one newly admitted interval tick,
E1has increased by one andE2contains that tick's time. A restarted model may begin from previously persisted values rather thanBLANK.
The canonical example deliberately demonstrates rule-only targets. For a production copy, give counters an explicit rule-owned base:
STATE E1 = 0
STATE F1 = 0
STATE declares the rule system as owner and supplies the initial or reset base. Later rule writes become sticky revisions over that base.
Do not write to B1, B2, or B3 from a rule. Those bindings already have ordinary formulas, and a rule write would durably shadow the formula until RESET and earn GRID_MIXED_OWNERSHIP. If a rule is intended to override a computed binding, mark the base formula default; otherwise keep one owner per target.
The canonical A1:A5 bindings are authored source assignments. If an API or UI client must write them externally, replace those declarations with input bindings rather than treating ordinary formulas as a write surface.
Page operations only when the combined condition changes from false to true. Add an explicit counter and replace the existing paging rule with:
STATE PageCount = 0
WHEN (A2 > 0 OR A5 = "degraded") BECOMES TRUE THEN
PageCount += 1
C3 = "ops-paged"
C4 = NOW()
END
Begin with A2 = 0 and A5 = "clear". Then verify this sequence:
A2 to 1 increments PageCount to 1.A2 again while the expression remains true does not increment it.A2 = 0, then change A5 to "degraded"; PageCount becomes 2.A transition rule establishes its initial observation without firing. If this copy reused persisted rule state, use a fresh model identity before treating the first count as a fixed checkpoint.
For a later production extension that performs external effects, choose an explicit admission policy such as SERIAL QUEUE 100 OVERFLOW LATEST. External delivery is at least once across replay, so effect receivers should deduplicate by execution identity when the business action must happen exactly once.
1, 2, and 3 in one committed wave.SKIP MISSED, BACKFILL, and ONCE.STATE base.GRID_MIXED_OWNERSHIP warning.