1# Chapter 6: rules, or how to decide without deciding 2 3Somewhere in every program like this there is a function full of `if`s. 4*If* Jev cannot answer it, refuse. *If* it is a yes-or-no question, show 5Jev's answer. *If* it needs options, call the LLM, *unless*... and so on, 6until nobody can say what happens to a question without running it in their 7head. This package is what that function became instead: **a list of rules, 8and an engine that runs them.** 9 10A *fact* is something known about the question: can Jev judge it, what kind 11of question is it, is it several questions. A *rule* is a few tests on facts 12and what to do when they all pass. The engine looks at what is known and 13says what to do next. Here is every rule the site runs, drawn by the site 14itself: 15 16 17 18That picture is `/rules.svg`, drawn live from this package, so it is always 19the network that runs. Read it left to right: the facts, one test on a fact 20per box, the joins where a rule's tests meet, and the rules. Click it to see 21it bigger. 22 23> **Try it.** <https://lmjtfy.fun/rules> is the same drawing 24> with every fact clickable. Set `answerable` to yes, `kind` to pick, and 25> watch "draft options" light up: that is the moment the LLM would be 26> called. 27 28## The rules, in words 29 30Rule order is priority: of the rules that hold, the first with something 31left to do decides. 32 33| Rule | When | Then | 34| --- | --- | --- | 35| refuse | Jev cannot judge it | Say "No. That's not a question I can answer", and stop. | 36| answer yes or no | one question, read as yes-or-no, Jev's yes is known | Show Jev's yes: **Yes.**, **No.**, or **Yes?** / **No?** when the likelier answer is under 70%. | 37| grade it | one question, read as how-much, a general scale will do, Jev's degree is known | Show Jev's degree, from "Not at all" to "Extremely". | 38| give the odds | one question, read as how-likely, Jev's chance is known | Show the chance as a percentage, **28%.**, and say it is a Noul. | 39| draft a scale | read as how-much, but it needs its own scale ("how hot is the sun") | Ask the LLM to write the levels. | 40| draft options | read as a pick | Ask the LLM to write the options. | 41| split it up | several questions | Ask the LLM to write each one. | 42| judge the drafts | the LLM wrote something | Ask Jev to judge it. | 43| show the answers | Jev judged it | Show them. | 44| list it | Jev can judge it, and it is fit to show strangers | Put it on the public feed. | 45 46Two readings can hold at once. Jev answers "what kind of question is this?" 47with a probability for each kind, and the runner-up counts too when it gets 48at least 30%. Then the rules of both kinds hold and both are answered: "is 49C++ better than C#?" comes back as a yes-or-no and as a pick. 50 51## Rete, briefly 52 53A rules engine with many rules could test every rule against the facts each 54time a fact changes. A Rete network (Forgy, 1979) does less: rules that 55start with the same tests share them, so each distinct test is one node 56(an *alpha*), and each rule is a chain of *joins* over those nodes, shared 57for as long as two rules begin alike. When a fact arrives, only the nodes 58that test it change, and only the joins below them are looked at again. 59 60```mermaid 61flowchart LR 62 F1["fact: answerable"] --> A1["answerable = yes"] 63 F1 --> A0["answerable = no"] 64 F2["fact: reads Noul"] --> A2["reads Noul = yes"] 65 A0 --> R0["rule: refuse"] 66 A1 --> J1(("join")) 67 A2 --> J1 68 J1 --> R1["rule: answer yes or no"] 69``` 70 71> **Aside: the one trick.** A textbook engine fetches a fact when a rule 72> first needs it, one at a time. That would be slow and expensive here, 73> because each fact from Jev is a network round trip. So this engine does 74> something sneakier: it collects *every* Jev fact that *any* rule still 75> alive is waiting on, and asks for them all in one request (`Next::Ask`). 76> Jev answers several questions for barely more than one, so the first 77> request usually settles the whole question. 78 79## How the page draws it 80 81Under every answer, the page draws this network marked with the question 82just asked, and it fills in as the answers arrive: 83 84- The Jev facts sit in one frame, because they came in one request. Each 85 shows the number Jev gave, not the yes or no it was read as. 86- Filled is what a rule that fired stood on. Outlined was learned and turned 87 out not to be needed. Dashed is a test that failed. 88- A rule that holds is pink, and the ones that decided a step are numbered 89 in the order they did. 90- A line runs from a rule back round to a fact when the rule's effect is the 91 call that teaches it. That loop is what the engine runs. 92 93## For the people who maintain it 94 95A fact is something known about the query (`Fact`): whether Jev can answer 96it, which kinds of question it reads as (four facts, one per `Kind`: Noul, 97Choice, Score, Chance), whether it is several, whether it needs a scale 98written for it, Jev's own answer read as yes-or-no, as how-much and as a 99chance, whether it is fit to show, whether the LLM drafted anything, whether 100Jev judged any of it. A rule (`RULES`) is a list of tests on facts and what 101follows when they all hold: the query ends outright, something is done that 102costs a call and teaches another fact, or something is noted that decides no 103step (an answer to show, or that the question may go on the feed). 104 105`Network::compile` merges the rules: one alpha node per distinct test, and 106for each rule a chain of joins, shared by rules that begin with the same 107tests. `Network::next` says what to do given what is known: 108 109| `Next` | When | 110| --- | --- | 111| `End` | A rule that ends the query outright holds (Jev cannot answer it). | 112| `Do` | A rule holds whose effect has not been done yet. | 113| `Ask` | No rule decides yet. Every Jev fact that a rule not yet failed is waiting on, to be asked for in one request. | 114| `Done` | No rule has anything left to do and nothing more can be learned. What to show is in the notes (`Network::shows`). | 115 116`Network::decide` is `next` with the rule that said so, which is how the 117page numbers the rules in the order they decided. `Network::alpha` and 118`Network::join` give each node's `State` (holds, fails, waits), and 119`Network::used` says which of the nodes that hold a fired rule stands on. 120`apps/lmjtfy/src/diagram.rs` draws all of it. 121 122## In this folder 123 124| Path | What | 125| --- | --- | 126| [src/](src/) | The engine and the rules. | 127| [Cargo.toml](Cargo.toml) | The crate. It depends on nothing but `serde`. | 128 129← Previous: [Chapter 5, packages/](../) · Up: [packages](../) · Next: [Chapter 6½, rules/src/](src/) →