No silent staleness
Every answer says how current it is, and why when it isn't. Filter to fresh answers only, or have a write wait for its answer.
freshness: "stale" · stale_reasonA live graph of a company's records: contacts, tickets, accounts, invoices and orders, linked to each other and to the systems they sync from. Every few seconds one record changes, the records its judgment reads light up, and it gets a new answer.
01How it works
You keep your records in sync and say what you want to know about them. Everything between a change to your data and an answer you can act on is a system of its own. Here is each one, on one account.
Animated walkthrough of the seven parts of the system, one at a time: the records you keep in sync; the question with its recipe, version and settings; change tracking, which decides what each write affects; the compiled context and its size class; the engine, batched, priced against a budget and probed for changes; the answer on the record with its freshness, provenance, queries and subscriptions; and over time, calibration from outcomes, the evaluation log and shadow runs for new versions.
It learns, keeps everything, and changes safely. Outcomes arrive from writes you already make; a nightly fit is used only if it beats the raw numbers. Every evaluation is kept with its context. A new version is judged in shadow before you confirm it.
One account, one question. The same runs for every record in the namespace, every time something a recipe reads changes.
Start from a starter. Point it at your records, adjust the recipe.
Is this ticket urgent?
subject, first message, latest 3 replies, the plan
Which team should take it?
the same ticket, in the same engine request
Does this post break a rule?
title and text · likes and replies re-run nothing
Will this account cancel within 30 days?
its latest 8 tickets and 180 days of invoices
How good is this lead, 1 to 5?
company, role, what they wrote, size and source
Does a person need to look at this?
the item, its summary and category
dry_run shows the definition and its cost before anything is created
The first version is always the same: when a row changes, call a model and save what it said. It works until the answer depends on other records, until the model quietly changes, and until someone asks how often it's right. Vainona is that first version, finished.
One question about 120 accounts: will this account cancel in the next 30 days? Below, a month of activity plays in about half a minute. On the left, the usual shortcut: call a model every time an account row changes. On the right, Vainona.
Animated comparison. The same stream of events plays on two grids of 120 accounts. On the left, a model is called whenever an account row changes: a new ticket or a paid invoice never touches the row, so the saved answer goes out of date; a login heartbeat and a burst of notes each cost model calls; a cancellation teaches nothing; a model change goes unnoticed. On the right, Vainona knows the answer depends on the account, its tickets and its invoices: the ticket gets the account answered again, the heartbeat is skipped, the burst is answered once, the cancellation is recorded as an outcome, and the model change is detected and recorded.
Same events, same 120 accounts. Vainona knows what each answer depends on, so it runs only when that changes, and it learns from what happens next.
03Guarantees
Six rules the system is built around. Each one is a field you can read, not a promise in a footnote, and each card below is the rule running.
Every answer says how current it is, and why when it isn't. Filter to fresh answers only, or have a write wait for its answer.
freshness: "stale" · stale_reasonWhen the model behind Jev changes, a new epoch starts and every answer records it. A pinned version never moves, and a retired one fails by name.
engine_version: "current+2026-09-28.1"Calibration sits beside the engine's probability, never over it. Thresholds and ranking read the raw number, so a refit never flips a decision on its own.
p: 0.87 · calibrated.p: 0.81Every computation is kept as an evaluation, with the exact context the engine read. Nothing is overwritten, so any answer can be explained later.
evaluation_id: "ev_01JB7KQ2"A backfill shows its cost and duration before you confirm. Every engine request is priced before it's sent, and judging pauses at your budget instead of passing it.
estimate.cost_usd · budget_pausedawaiting your confirm · v3 still answering
Question versions are immutable. A new one is judged on a sample beside the old one, at no charge, and reports what it would move before you switch.
threshold_flips: { to_true: 38, to_false: 3 }04The SDK
A judgment is a question and a recipe: the fields and related records the engine reads. The recipe decides what an answer costs, how accurate it is and when it's judged again. Turn the knobs and watch both.
await ns.judgments.create({ name: "churn_risk", type: "bool", question: "Will this account cancel within the next 30 days?", applies_to: { "attributes.kind": "account" }, context: { fields: ["state.name", "attributes.plan"], related: { tickets: { match: { "attributes.kind": "ticket" }, join: { theirs: "attributes.account_id", mine: "id" }, last_n: 8, fields: ["created_at", "state.subject", "state.status"], }, invoices: { match: { "attributes.kind": "invoice" }, join: { theirs: "attributes.account_id", mine: "id" }, window: "180d", aggregate: { count: true, latest: ["state.status"] }, }, }, }, horizon: "30d", engine: { name: "jev", version: "current" }, freshness: { policy: "on_change" },});tickets = { # each account's latest 8 tickets "match": {"attributes.kind": "ticket"}, "join": {"theirs": "attributes.account_id", "mine": "id"}, "last_n": 8, "fields": ["created_at", "state.subject", "state.status"],}invoices = { # and 180 days of invoices "match": {"attributes.kind": "invoice"}, "join": {"theirs": "attributes.account_id", "mine": "id"}, "window": "180d", "aggregate": {"count": True, "latest": ["state.status"]},} ns.judgments.create( name="churn_risk", type="bool", question="Will this account cancel within the next 30 days?", applies_to={"attributes.kind": "account"}, context={ "fields": ["state.name", "attributes.plan"], "related": {"tickets": tickets, "invoices": invoices}, }, horizon="30d", engine={"name": "jev", "version": "current"}, freshness={"policy": "on_change"},){ "state.name": "Brightline", "attributes.plan": "enterprise", "related.invoices": { "count": 6, "latest(state.status)": "paid" }, "related.tickets": [ { "created_at": "2026-09-28T14:02:11Z", "state.subject": "Third outage this week", "state.status": "open" }, { "created_at": "2026-09-21T09:40:52Z", "state.subject": "Export keeps timing out", "state.status": "open" }, { "created_at": "2026-09-02T16:11:07Z", "state.subject": "SSO login loop", "state.status": "solved" }, { "created_at": "2026-08-19T11:03:44Z", "state.subject": "Invite link expired", "state.status": "solved" }, { "created_at": "2026-08-04T08:27:19Z", "state.subject": "Webhook retries", "state.status": "solved" }, { "created_at": "2026-07-22T15:48:03Z", "state.subject": "Add a seat", "state.status": "solved" }, { "created_at": "2026-07-09T10:12:31Z", "state.subject": "Dashboard slow on Mondays", "state.status": "solved" }, { "created_at": "2026-06-30T13:55:20Z", "state.subject": "API key rotation", "state.status": "solved" } ]}A write to the account, a ticket or an invoice is checked against this. If what the engine would see is unchanged, the answer is reused without calling it.
ns.write({ upsert })Keep documents in sync. Answers follow in seconds.ns.query({ rank_by })Filter and rank on answers like any column.ns.subscriptions.create()Entered and exited events, by webhook or feed.ns.outcomes.append()What actually happened. Calibration learns from it.05Calibration
An engine's probability is its own confidence, and confidence isn't being right. Outcomes, what actually happened, measure it on your data and correct it, so you can say how often an action above a threshold will be wrong.
| raw | calibrated | |
|---|---|---|
| calibration error | 0.159 | 0.008 |
| log loss | 0.441 | 0.344 |
| accuracy | 80.1% | 83.7% |
Calibration cut this judgment's error by 22% since it started, on 1,240 outcomes.
Thresholds read the raw number. Calibration tells you what it means, and the recommender picks one from a target.
at_risk · p ≥ 0.60
The engine says 0.60. On your accounts that comes true 47% of the time.
194 of 1,240 accounts are flagged. 63% of them go on to churn.
46% of the accounts that churn are flagged.
current+2026-09-28.1 · fitted from replay
A new epoch starts its own headline. The chart keeps the old one beside it.
06Numbers
Every figure here comes from a run we can name. Latency was measured on staging on 28 and 29 September 2026, so it's a small deployment's number, not a guarantee. Engine quality is re-checked every day against a suite built to be hard.
Answer fresh after a write
1.6s
p90, one write at a time, on a one-field recipe. p50 was 1.3 s and the slowest of 200 was 2.4 s.
Jev current · yes/no accuracy
82.6%
On a golden set built to be hard: 40% easy, 40% medium, 20% hard. Calibration error 0.017 before any outcomes. Re-run daily and after every change we detect.
Model probes a day
2,880
Every 30 seconds we ask Jev the same questions and compare 10-minute averages. A change starts a new epoch, recorded on every answer from then on.
07Pricing
A judgment is one answer over its compiled context, counted by size. An unchanged record isn't judged again, a reused answer isn't billed, failed evaluations aren't billed, and every plan has the whole product. Plans set a monthly minimum and what else they include.
= 5,100,000 judgments · $1,275 of usage at the graduated tiers
For one product, paid from prepaid credit.
$1,275 of usage, above the $19.00 minimum. The invoice is $1,275.
Start on DeveloperFor teams that act on the answers, paid as usage grows.
$1,275 of usage, above the $499 minimum. The invoice is $1,275.
For platforms and regulated teams.
$1,275 of usage. The invoice is the minimum, $2,500.
Talk to us08Start
An API key, one starter judgment and three writes. Your first answers land in the free quickstart namespace a couple of minutes from now. Nothing to deploy.