okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

dawntest: the retrieval fixture installs no extensions955c14d

main
6.3 KiB203 linesraw
1//// Trace actual BEAM reads and decodes: E2E cannot observe discarded matches,
2//// sparse keyset query counts, or how many source and node rows were decoded.
3
4import albedo/daemon/conversation
5import albedo/daemon/store
6import albedo/harness/extensions/lcm/graph
7import albedo/harness/runtime
8import albedo/harness/search
9import albedo/harness/tool
10import albedo/openai_api/types
11import gleam/dynamic/decode
12import gleam/erlang/process
13import gleam/list
14import gleam/option.{None}
15import gleeunit/should
16import sqlight
17
18pub type Counts {
19  Counts(pages: Int, decoded: Int, sources: Int, nodes: Int, kept: Int)
20}
21
22@external(erlang, "albedo_retrieval_test_support", "measure")
23fn measure(owner: process.Pid, run: fn() -> a) -> #(a, Counts)
24
25@external(erlang, "albedo_conversation", "pack")
26fn pack(input: types.Input) -> BitArray
27
28fn fixture() -> #(runtime.Runtime, store.Store) {
29  // No extensions: this module measures store, search, graph and tool reads
30  // directly, so the default install would put 43 extensions' initialisers
31  // and schema migrations inside runtime.start's 10s start ack for tables
32  // none of the queries touch. The two schemas the queries need are created
33  // below.
34  let assert Ok(host) = runtime.start_with_extensions(":memory:", [])
35  let ledger = runtime.ledger(host)
36  let assert Ok(_) = conversation.initialise(ledger)
37  let assert Ok(_) = graph.initialise(ledger)
38  let _ =
39    list.each(["wanted", "other"], fn(session) {
40      let assert Ok(_) =
41        conversation.create(
42          ledger,
43          conversation.Info(
44            session,
45            "fixture",
46            "/tmp",
47            "fixture",
48            "fixture",
49            types.Responses,
50            conversation.Idle,
51            None,
52            None,
53          ),
54        )
55    })
56  #(host, ledger)
57}
58
59fn insert(ledger: store.Store, session: String, seq: Int, text: String) -> Nil {
60  let assert Ok(_) =
61    store.write(
62      ledger,
63      "INSERT INTO transcript(seq,session,payload,row_class) VALUES(?,?,?,'user')",
64      [
65        sqlight.int(seq),
66        sqlight.text(session),
67        sqlight.blob(pack(types.User(text))),
68      ],
69    )
70  Nil
71}
72
73pub fn sparse_scoped_search_advances_by_rows_not_global_sequence_gaps_test() -> Nil {
74  let #(host, ledger) = fixture()
75  insert(ledger, "other", 1, "needle")
76  insert(ledger, "wanted", 200_000, "needle older")
77  insert(ledger, "other", 400_000, "needle")
78  insert(ledger, "wanted", 600_000, "needle newer")
79  let #(result, counts) =
80    measure(store.owner(ledger), fn() {
81      search.page(ledger, "wanted", "needle", 0, 700_000, 0, 20)
82    })
83  let assert Ok(page) = result
84  page.count |> should.equal(2)
85  list.map(page.matches, fn(match) { match.seq })
86  |> should.equal([200_000, 600_000])
87  should.be_true(counts.pages <= 4)
88  counts.decoded |> should.equal(2)
89  let #(result, counts) =
90    measure(store.owner(ledger), fn() {
91      search.fold(
92        ledger,
93        search.Beyond("other", "/tmp"),
94        "needle",
95        [],
96        fn(_, _) { True },
97        fn(found, match) { [match.seq, ..found] },
98      )
99    })
100  result |> should.equal(Ok([200_000, 600_000]))
101  should.be_true(counts.pages <= 4)
102  counts.decoded |> should.equal(2)
103  runtime.stop(host)
104}
105
106pub fn exact_search_count_keeps_only_requested_twenty_matches_test() -> Nil {
107  let #(host, ledger) = fixture()
108  let _ =
109    list.each(
110      list.index_map(list.repeat(Nil, 2200), fn(_, index) { index + 1 }),
111      fn(seq) { insert(ledger, "wanted", seq, "needle") },
112    )
113  let #(result, counts) =
114    measure(store.owner(ledger), fn() {
115      search.page(ledger, "wanted", "needle", 0, 3000, 30, 20)
116    })
117  let assert Ok(page) = result
118  page.count |> should.equal(2200)
119  list.length(page.matches) |> should.equal(20)
120  counts.decoded |> should.equal(2200)
121  should.be_true(counts.pages * 20 < 2200)
122  counts.kept |> should.equal(20)
123  runtime.stop(host)
124}
125
126pub fn node_listing_decodes_only_page_and_source_read_stops_after_page_test() -> Nil {
127  let #(host, ledger) = fixture()
128  let _ =
129    list.each(
130      list.index_map(list.repeat(Nil, 300), fn(_, index) { index + 1 }),
131      fn(seq) { insert(ledger, "wanted", seq, "body") },
132    )
133  let assert Ok(_) =
134    graph.save_leaves(
135      ledger,
136      "wanted",
137      list.map(
138        list.index_map(list.repeat(Nil, 45), fn(_, index) { index + 1 }),
139        fn(seq) { graph.Leaf(seq, seq, "summary") },
140      ),
141    )
142  // Positive control: the tracer observes the old full node-read operation.
143  let #(all, control) =
144    measure(store.owner(ledger), fn() {
145      store.query(ledger, fn(db) {
146        store.rows(
147          db,
148          "SELECT id,depth,first_seq,last_seq,summary FROM lcm_compaction_node WHERE session=? ORDER BY id",
149          [sqlight.text("wanted")],
150          decode.field(0, decode.int, decode.success),
151        )
152      })
153    })
154  let assert Ok(all) = all
155  list.length(all) |> should.equal(45)
156  control.nodes |> should.equal(45)
157  let #(page, counts) =
158    measure(store.owner(ledger), fn() {
159      graph.list_page(ledger, "wanted", 7, 5)
160    })
161  let assert Ok(page) = page
162  page.total |> should.equal(45)
163  counts.nodes |> should.equal(7)
164  let assert Ok(snapshot) = conversation.snapshot(ledger, "wanted")
165  let #(page, counts) =
166    measure(store.owner(ledger), fn() {
167      tool.source_page(ledger, snapshot, 200, 300, "row", 0, 1)
168    })
169  let assert Ok(#("[", 1, True)) = page
170  should.be_true(counts.sources <= 101)
171  let #(page, counts) =
172    measure(store.owner(ledger), fn() {
173      tool.source_page(ledger, snapshot, 1, 300, "row", 0, 1)
174    })
175  let assert Ok(#("[", 1, True)) = page
176  should.be_true(counts.sources > 0 && counts.sources < 300)
177  runtime.stop(host)
178}
179
180pub fn excluded_global_rows_advance_cross_session_cursor_without_decoding_test() -> Nil {
181  let #(host, ledger) = fixture()
182  insert(ledger, "wanted", 1, "needle")
183  let _ =
184    list.each(
185      list.index_map(list.repeat(Nil, 2200), fn(_, index) { index + 2 }),
186      fn(seq) { insert(ledger, "other", seq, "needle") },
187    )
188  let #(result, counts) =
189    measure(store.owner(ledger), fn() {
190      search.fold(
191        ledger,
192        search.Beyond("other", "/tmp"),
193        "needle",
194        [],
195        fn(_, _) { True },
196        fn(found, match) { [match.seq, ..found] },
197      )
198    })
199  result |> should.equal(Ok([1]))
200  should.be_true(counts.pages * 20 < 2200)
201  counts.decoded |> should.equal(1)
202  runtime.stop(host)
203}