Evaluating records
POST /rules/evaluate runs a static scope once per record you name. Each record is read as the
caller with its related records and the scope’s knowledge, the rules decide, and their proposals
come back. With apply: true they are written, as the caller.
Only a static scope with data.over
can be evaluated.
Request
Section titled “Request”{ "scope": "invoice-routing", "ids": ["inv-big", "inv-small", "nope"], "apply": false }| Key | Meaning |
|---|---|
scope | the static scope |
ids | the records’ keys (the scope’s over.key): between 1 and rules.evaluate.maxids, 100 by default |
apply | write what the rules propose. Needs the apply action; without it the call needs evaluate and writes nothing |
input, facts | facts added to every record’s, as for execute |
A dry evaluation
Section titled “A dry evaluation”With the rules of rules/routing/route.grl:
rule Senior "large invoices go to a senior reviewer, with a task" salience 10 { when in.Double("invoice.total", 0.0) > 1000.0 then act.Set("review_tier", "senior"); act.Create("shop", "task", map.Of("id", "t-" + in.Str("invoice.id", ""), "subject", "review " + in.Str("invoice.id", "") + " for " + in.Str("customer.segment", "a customer"))); out.Set("tier", "senior");}
rule Auto "small invoices are approved" salience 5 { when in.Double("invoice.total", 0.0) <= 1000.0 then act.Set("review_tier", "auto"); out.Set("tier", "auto");}the call answers 200:
{ "scope": "invoice-routing", "stamp": "sha256:84853064e9fe118a5c7c4882e0dc5fa321305e2b941d6304cbf1642b3db8efb8", "principal": { "id": "u-shop-owner", "ptyp": "user" }, "apply": false, "records": [ { "key": "inv-big", "out": { "tier": "senior" }, "findings": [], "actions": [ { "op": "set", "field": "review_tier", "value": "senior", "rule": "Senior", "cycle": 1 }, { "op": "create", "source": "shop", "entity": "task", "fields": { "id": "t-inv-big", "subject": "review inv-big for gold" }, "rule": "Senior", "cycle": 1 } ] }, { "key": "inv-small", "out": { "tier": "auto" }, "findings": [], "actions": [ { "op": "set", "field": "review_tier", "value": "auto", "rule": "Auto", "cycle": 1 } ] } ], "missing": ["nope"]}missing lists the keys that found no record the caller may read: a key that does not exist and
a record the caller’s access hides look the same.
Applying
Section titled “Applying”The same call with "apply": true, for inv-big:
{ "scope": "invoice-routing", "stamp": "sha256:84853064e9fe118a5c7c4882e0dc5fa321305e2b941d6304cbf1642b3db8efb8", "principal": { "id": "u-shop-owner", "ptyp": "user" }, "apply": true, "records": [ { "key": "inv-big", "out": { "tier": "senior" }, "findings": [], "actions": [ "… as above …" ], "applied": [ { "source": "shop", "op": "update", "entity": "invoice", "key": "inv-big", "fields": { "review_tier": "senior" }, "before": { "review_tier": null } }, { "source": "shop", "op": "create", "entity": "task", "fields": { "id": "t-inv-big", "subject": "review inv-big for gold" } } ] } ]}applied is what was written, in order, after no-ops were dropped; an update of the record being
evaluated carries before, the fields’ values as they were read. data.svc records the caller as
the writer of each.
Each record’s result
Section titled “Each record’s result”| Field | What it is |
|---|---|
key | the record |
out, findings, actions | as for execute: the decision, the findings, the proposals |
applied | with apply: each write made |
conflict | the record changed after it was read, twice: it was decided again once, and changed again |
partial | the record’s writes span sources and a later one failed: what applied before it stays applied |
error | {code, message} when the record could not be decided or written |
One record’s failure never fails the call: the call answers 200, and each record says what
happened to it.
error.code | Means |
|---|---|
rules-execution-failed, rules-execution-timeout | a rule failed or ran out of time on this record; out holds what was written before |
rules-write-not-declared | a proposal the scope’s writes do not allow; none of the record’s proposals is applied, dry or not |
rules-write-conflict | with conflict: true, as above |
rules-write-partial | with partial: true, as above |
rules-source-denied | the source refused the caller this write |
rules-source-unavailable | the source could not be reached |
What refuses the call
Section titled “What refuses the call”| Status | Code | Why |
|---|---|---|
400 | rules-facts-invalid | no ids, or more than rules.evaluate.maxids; a scope without data.over; facts the scope does not take, or named like the record (over.as), a related record or a knowledge read |
403 | rules-access-denied | the caller may not evaluate, or not apply |
404 | rules-scope-not-found | no static scope of that name |
403 / 503 | rules-source-denied / rules-source-unavailable | the scope’s knowledge could not be read |