What happens to one thing the child says, as data: the steps a turn takes, where Jev is asked something, and where a turn can end in a fixed line instead of an answer. The website draws its diagram from this, and tests/conversation.rs runs the real pipeline into every exit listed here, so the picture cannot show a step or an ending the code does not have.

This is a description of Conversation::respond, not the thing that runs it: the order of the steps is the order of the code, and a test that disagrees fails.

9use crate::types::{Direction, Fallback};

Where a step happens.

12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum Place {

On the child's tablet, in the Rust core.

15    Tablet,

The language model, through the household's gateway.

17    Model,

Jev, asked by the service that holds the key.

19    Jev,
20}

What Jev is asked at a step.

23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub struct JevCheck {

Which way the message travels past the guard; None for a question that is not a check.

26    pub direction: Option<Direction>,

The question, in plain words.

28    pub asks: &'static str,
29}

A way a step can end the turn, and what the child hears instead.

32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct Exit {

Why, in plain words. Unique within its step: the tests find the scenario by it.

35    pub cause: &'static str,
36    pub then: Fallback,

What the parents' log shows.

38    pub parents_see: &'static str,
39}
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub struct Step {
43    pub id: &'static str,
44    pub place: Place,
45    pub what: &'static str,
46    pub jev: Option<JevCheck>,

Whether the step happens only when the child showed a picture.

48    pub only_with_pictures: bool,
49    pub exits: &'static [Exit],

What the step writes in the parents' log when it passes, as the event's name.

51    pub logs: &'static str,
52}
54const REFUSED: Exit = Exit { cause: "refused", then: Fallback::ChildRefused, parents_see: "the refusal and its reason" };
55const GROWN_UP: Exit = Exit {
56    cause: "refused: she is hurt, unsafe or asked to keep a secret",
57    then: Fallback::NeedsAGrownUp,
58    parents_see: "the refusal, shown first",
59};
60const JEV_DOWN: Exit = Exit { cause: "Jev cannot be reached", then: Fallback::GuardUnavailable, parents_see: "a failure at the check" };

The turn, in order.

63pub const TURN: [Step; 9] = [
64    Step {
65        id: "keep-pictures",
66        place: Place::Tablet,
67        what: "Any picture she shows is kept before anything is sent anywhere.",
68        jev: None,
69        only_with_pictures: true,
70        exits: &[Exit { cause: "a picture cannot be kept", then: Fallback::LogUnavailable, parents_see: "nothing: the log is what broke" }],
71        logs: "",
72    },
73    Step {
74        id: "log-heard",
75        place: Place::Tablet,
76        what: "What she said is written to the parents' log, before the guard or the model sees it.",
77        jev: None,
78        only_with_pictures: false,
79        exits: &[Exit { cause: "the log cannot be written", then: Fallback::LogUnavailable, parents_see: "nothing: the log is what broke" }],
80        logs: "Heard",
81    },
82    Step {
83        id: "check-words",
84        place: Place::Jev,
85        what: "Jev is asked whether what she said is fit for a child of her age to say to the cat.",
86        jev: Some(JevCheck { direction: Some(Direction::FromChild), asks: "May this be said?" }),
87        only_with_pictures: false,
88        exits: &[REFUSED, GROWN_UP, JEV_DOWN],
89        logs: "Guarded",
90    },
91    Step {
92        id: "describe-picture",
93        place: Place::Model,
94        what: "A picture is first described in plain words by a model call that has no persona.",
95        jev: None,
96        only_with_pictures: true,
97        exits: &[Exit { cause: "the model cannot be reached", then: Fallback::ModelUnavailable, parents_see: "a failure at the model" }],
98        logs: "PictureSeen",
99    },
100    Step {
101        id: "check-picture",
102        place: Place::Jev,
103        what: "Jev reads only words, so the description is judged exactly as her speech is.",
104        jev: Some(JevCheck { direction: Some(Direction::FromChild), asks: "May this be said?" }),
105        only_with_pictures: true,
106        exits: &[REFUSED, GROWN_UP, JEV_DOWN],
107        logs: "Guarded",
108    },
109    Step {
110        id: "recall",
111        place: Place::Jev,
112        what: "What the cat remembers is searched by meaning. When more than four memories fit, Jev orders them; fewer, and nothing is asked. This only adds: it never ends a turn.",
113        jev: Some(JevCheck { direction: None, asks: "Which memory helps most?" }),
114        only_with_pictures: false,
115        exits: &[],
116        logs: "Recalled",
117    },
118    Step {
119        id: "model-writes",
120        place: Place::Model,
121        what: "The model writes a reply, from the parents' prompt, the memories and a window of the chat.",
122        jev: None,
123        only_with_pictures: false,
124        exits: &[
125            Exit { cause: "the model cannot be reached", then: Fallback::ModelUnavailable, parents_see: "a failure at the model" },
126            Exit { cause: "the allowance for thinking is used up", then: Fallback::Resting, parents_see: "a failure at the model, said as a rest" },
127        ],
128        logs: "ModelWrote",
129    },
130    Step {
131        id: "check-answer",
132        place: Place::Jev,
133        what: "Jev is asked whether what the model wrote is fit for her to hear.",
134        jev: Some(JevCheck { direction: Some(Direction::ToChild), asks: "May this be heard?" }),
135        only_with_pictures: false,
136        exits: &[
137            Exit { cause: "refused", then: Fallback::AnswerRefused, parents_see: "what the model wrote, and the refusal" },
138            JEV_DOWN,
139        ],
140        logs: "Guarded",
141    },
142    Step {
143        id: "say",
144        place: Place::Tablet,
145        what: "The tablet speaks the answer.",
146        jev: None,
147        only_with_pictures: false,
148        exits: &[],
149        logs: "Said",
150    },
151];

Every place the app asks Jev something, in the code. Three are steps of a turn; the others (a fact to remember, a chat summary) happen after it, off to the side (reflect.rs).

155#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156pub struct JevUse {
157    pub id: &'static str,
158    pub asks: &'static str,

What happens when Jev cannot answer.

160    pub on_failure: &'static str,
161}
163pub const JEV_USES: [JevUse; 6] = [
164    JevUse { id: "check-words", asks: "Is what she said fit for her age, and what is it about?", on_failure: "refused: the cat says a fixed line" },
165    JevUse { id: "check-picture", asks: "The same two questions, of the words that describe her picture.", on_failure: "refused: the cat says a fixed line" },
166    JevUse { id: "check-answer", asks: "The same two questions, of what the model wrote.", on_failure: "refused: she hears a fixed line instead" },
167    JevUse { id: "check-fact", asks: "The same two questions, of a fact the cat is about to remember about her.", on_failure: "the fact is not kept, and the log says so" },
168    JevUse { id: "check-summary", asks: "The same two questions, of the summary that stands in for a long chat.", on_failure: "the chat is left as it was" },
169    JevUse { id: "rank-memories", asks: "Which of these remembered things helps most with what she just said?", on_failure: "the cat remembers by meaning alone" },
170];

Things that are not Jev, so the page does not credit it with them.

173pub const NOT_JEV: [(&str, &str); 6] = [
174    ("Writing the cat's words", "The language model does, through the household's gateway. Jev never writes text."),
175    ("Understanding speech", "The tablet turns her voice into text before anything else happens."),
176    ("Reading pictures", "A model call describes a picture in words; Jev only judges those words."),
177    ("Finding memories by meaning", "A separate embedding model on the household's own machine turns text into vectors; Jev only orders the shortlist."),
178    ("The allowance and the bedtime", "Plain rules in the core: minutes a day and quiet hours."),
179    ("The parents' log", "Written by the core before each step. Jev is not asked to remember anything."),
180];
182#[cfg(test)]
183mod tests {
184    use super::*;
185
186    #[test]
187    fn ids_are_unique_and_causes_are_unique_within_a_step() {
188        for (i, a) in TURN.iter().enumerate() {
189            assert!(TURN.iter().skip(i + 1).all(|b| b.id != a.id), "{}", a.id);
190            for (j, x) in a.exits.iter().enumerate() {
191                assert!(a.exits.iter().skip(j + 1).all(|y| y.cause != x.cause), "{} {}", a.id, x.cause);
192            }
193        }
194    }
195
196    #[test]
197    fn every_fixed_line_the_cat_can_say_is_an_exit_of_some_step() {
198        for fallback in Fallback::ALL {
199            assert!(TURN.iter().any(|s| s.exits.iter().any(|e| e.then == fallback)), "{fallback:?} ends no step");
200        }
201    }
202
203    #[test]
204    fn a_step_that_asks_jev_is_placed_at_jev_and_the_others_are_not() {
205        for step in TURN {
206            assert_eq!(step.jev.is_some(), step.place == Place::Jev, "{}", step.id);
207        }
208    }
209
210    #[test]
211    fn every_jev_step_of_the_turn_is_a_use_and_every_use_has_a_failure() {
212        for step in TURN.iter().filter(|s| s.jev.is_some()) {
213            let id = if step.id == "recall" { "rank-memories" } else { step.id };
214            assert!(JEV_USES.iter().any(|u| u.id == id), "{}", step.id);
215        }
216        assert!(JEV_USES.iter().all(|u| !u.on_failure.is_empty()));
217    }
218}