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](../)