1# Chapter 23: jev-facts — everything a rule is waiting on, in one envelope
2
3Suppose you are deciding what to do with something, and your decision is a
4set of rules: *if it is safe and it only reads, let it through; if it
5deletes, ask first*. Each rule stands on **facts** (is it safe? does it
6read? does it delete?), and the facts are things only Jev can tell you.
7
8The slow way is to ask as you go. Rule one wants "safe", so you ask Jev and
9wait. It also wants "reads", so you ask again and wait again. Three rules,
10five facts, five round trips.
11
12A rules engine that knows its rules can do better. Before it asks anything,
13it can look at every rule still in the running and collect **every fact any
14of them is waiting on**. Jev answers many questions in one request for the
15price of one wait. So the engine says "I want these five", and this crate
16puts five questions in one envelope, sends nothing itself, and when the
17answers come back, reads each one as the fact it teaches.
18
19That is all `jev-facts` is: the piece between "these facts are wanted" and
20"these facts are known".
21
22```mermaid
23sequenceDiagram
24  participant E as A rules engine (rete, or your own)
25  participant F as jev-facts
26  participant J as Jev
27  E->>F: wanted(facts): safe, reads, deletes, load
28  F-->>E: Prepared: one request, three questions
29  E->>J: the request (sent however the host sends)
30  J-->>E: the response
31  E->>F: prepared.judged(response), then learn(...)
32  F-->>E: safe = no, reads = no, deletes = yes, load = 0.3
33```
34
35Four facts, three questions. That is not a mistake: "reads" and "deletes"
36are two readings of *one* question, "what does the command do?". They share
37an id, the question is asked once, and each fact takes its own value out of
38the one answer.
39
40A host says what its facts are by implementing one trait:
41
42```rust
43impl jev_facts::Source for Command {
44    type Fact = Fact;
45    type Value = Value;
46    fn question_id(&self, fact: Fact) -> String { /* "safe", "act", "load" */ }
47    fn question(&self, fact: Fact) -> Result<Question, ProtocolError> { /* the Noul, Choice or Score */ }
48    fn learned(&self, fact: Fact, judged: &Judged) -> Option<Value> { /* what an answer makes it */ }
49}
50```
51
52> **Aside: it does not know what a rules engine is.** Nothing here depends
53> on one. The engine these projects use is `rete` (in the `rustcrates`
54> repository), whose `Network::next` returns `Next::Ask(facts)`: exactly
55> the list `wanted` takes. But `rete` knows nothing of Jev, and this crate
56> knows nothing of `rete`. A host with three hand-written `if`s can use it
57> just the same. The two meet in the host, in about ten lines.
58
59> **Aside: it does not send anything either.** `wanted` hands back a
60> `Prepared`: the request body, exactly as it will go, and the most it can
61> cost. The host sends it with whichever client it has (`jev-worker` on a
62> Cloudflare Worker, `jev-http` on a server). That is why a page can show
63> the request while Jev is still thinking, and why the tests here need no
64> network.
65
66> **Try it.** `cargo test -p jev-facts`. The tests are a small domain of
67> their own, a shell command with four facts. Read
68> `every_wanted_fact_goes_in_one_request_and_a_shared_question_once`
69> first; then make `learned` read the wrong type and watch
70> `an_answer_of_the_wrong_type_teaches_nothing` name the question.
71
72## For the people who maintain it
73
74`learn` is all or nothing: every fact with its value, or the first fact
75that was not taught (`Unlearned::NotAsked` when the request had no such
76question, `Unlearned::WrongType` when the answer is not the type asked). A
77host never records half an answer.
78
79`prepare` is the same step for questions that are not facts (lmjtfy's
80second request asks questions a language model drafted): ids and questions
81in, a `Prepared` out.
82
83### In this folder
84
85| Path | What |
86| --- | --- |
87| [src/lib.rs](src/lib.rs) | `Source`, `Judged`, `Part`, `Prepared`, `prepare`, `wanted`, `learn`, `Unlearned`. |
88| [src/tests.rs](src/tests.rs) | The command domain and six tests. |
89| [Cargo.toml](Cargo.toml) | Depends on `jev-protocol` only. |
90
91← Previous: [Chapter 22¾: jev-ui/assets](../jev-ui/assets/) · Up: [jevcrates](../) · The end of the guide. [Back to Chapter 16: jevcrates](../)