Build A Live Model
A live Grid model combines editable inputs, external data, formulas, and realtime updates.
Build A Live Model
A live Grid model combines editable inputs, external data, formulas, and realtime updates.
Pattern
Input or external value changes
-> dependent formulas update
-> rules may fire
-> workbook surfaces show the new state
Event Connectors
Event connectors normalize provider updates into source events. Examples include market data, weather, Firebase, ElectricSQL, and webhook-driven monitor events.
Treat connector-fed cells like any other input: keep their names stable, add type tags when the meaning matters, and use fallback formulas for data that may arrive late.
Connector-fed tables can remain ordinary relational Grid models too. Author the
same SELECT, keyed join, calculation, filter, and grouping you would use for a
snapshot:
table PaidOrders = SELECT customer_id, product_id, amount AS revenue
FROM Orders
WHERE status = "paid"
table LiveMargins = SELECT o.customer_id,
o.revenue * (1 - COALESCE(p.cost_rate, 0)) AS margin,
p.category
FROM PaidOrders AS o
LEFT JOIN Products AS p ON o.product_id = p.product_id
WHERE o.revenue > 0
AND (p.category IN ("software", "services") OR p.category IS NULL)
table MarginByCategory = SELECT category, SUM(margin) AS margin
FROM LiveMargins
GROUP BY category
Grid keeps the admitted relation current from source-row changes, including edits on either side of the join. The resulting tables still feed normal cells, rules, and rendered surfaces. Unsupported query shapes retain their authored Workbook evaluation path instead of silently changing meaning.
There is no second Live Model language and no operator-specific save command.
An ordinary authored table Name = <relation> becomes live automatically when
it is backed by changing sources and belongs to the documented fragment.
Redeploying a changed definition performs a checked replacement. Removing the
definition from source removes its compiler-owned target during reconciliation;
an operator may also use dropLiveModel for an explicit owned-only drop.
The maintained set fragment includes UNION ALL, UNION DISTINCT, and binary
INTERSECT/EXCEPT with or without ALL. Grid tracks their value
multiplicities through the same Live Model plan; duplicate-count changes only
publish when they change the visible multiset. Broad or unaddressable changes
fall back to an exact atomic rebuild.
Inspect The Live Contract
Every admitted relational Live Model is visible through the model manifest at
runtime.liveModels and directly at:
GET /api/models/<model-id>/live-models
The descriptor is a read-only projection of the same durable catalog and checkpoint used by execution. It reports:
- the source schemas and ordered source revision vector;
- a definition version and opaque plan digest (never provider SQL);
- the committed target schema and revision;
- the source high-water and last-applied checkpoint;
current,stale, orfailedfreshness;- the last physical refresh strategy and bounded failure text, if any.
Inspection never refreshes the model. stale therefore means a source has
advanced past the committed checkpoint; failed retains that checkpoint and
the last successful refresh while exposing the later failed attempt. Ordinary
connector and table mutation paths normally settle back to current before
publishing dependent cells and rendered surfaces.
Inspection is capped at 50,000 definitions/sources/observations. The direct
endpoint fails closed above that bound; the manifest retains its other runtime
metadata and reports runtime.liveModels.inspectionError.
Read And Explain
Every operational read chooses its freshness contract:
readLiveModel(modelId, {
name: "MarginByCategory",
policy: "requireCurrent",
page: { offset: { offset: 0, limit: 100 } }
})
requireCurrent refreshes the dependency chain and either returns a current
committed generation or fails. allowStale never initiates work; it returns the
last committed generation together with its exact source high-water and
freshness.
Use:
explainLiveModel(modelId, "MarginByCategory")
to see the admitted delta strategy, the strategy selected for the last refresh, the current/successful checkpoints, and any exact fallback reason. Fallback reasons distinguish schema change, broad change without row identity, delta-budget overflow, and unavailable incremental state. A broad fallback is an atomic fresh rebuild. A relational shape outside the supported fragment is not given a Live Plan at all and continues to use its authored Workbook semantics.
Dense Range Connectors
Dense range connectors update a rectangular block at once. Use them when an external source naturally sends a table or time-series frame instead of one event per symbol.
Downstream formulas can point at the range directly:
prices = A1:D50
latest_close = INDEX(prices, ROWS(prices), 4)
External Functions
Use external functions when the model should fetch or compute something on demand:
rate = FX_RATE("EUR", "USD") DEFAULT 1.08
quote = HTTP_JSON("https://api.example.com/quote") DEFAULT {}
score ~= ML_SCORE([margin, churn_risk, tenure]) DEFAULT 0
Use DEFAULT, IFERROR, or WITH ... ELSE so the rest of the model stays
readable while the external value is pending or unavailable. See
../language/external-functions.md.
Reactive Rules
Use rules when the model should act on live state:
WHEN risk_score > 0.8 THEN
status = "review"
flagged_at = NOW()
END
For recurring checks, use EVERY; for one-shot moments, use AT. See
../language/rules-and-schedules.md.