lmjtfy.git / packages / rules / README.md
README.mdpreviewREADME.mdsource129 lines · 6.5 KB · raw
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![The rules as a Rete network: facts on the left, the tests on them, the joins, and the rules on the right](https://lmjtfy.fun/rules.svg)
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/) →