okami.mom/albedo

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

nekomimi.petfix: guard closed child mail and remove inherited shim generationsff92766

main
2.7 KiB102 linesraw
1/// E2E cannot pause admission just before its transaction; this catches close winning that race.
2import albedo/daemon/conversation
3import albedo/daemon/family
4import albedo/daemon/mail
5import albedo/daemon/store
6import albedo/harness/runtime
7import albedo/openai_api/types
8import gleam/dynamic/decode
9import gleam/option.{None, Some}
10import gleeunit/should
11
12@external(erlang, "albedo_runtime_test_support", "temporary_database")
13fn temporary_database() -> String
14
15@external(erlang, "albedo_runtime_test_support", "cleanup")
16fn cleanup(path: String) -> Nil
17
18pub fn close_before_mail_commit_rolls_back_turn_and_preserves_letter_test() -> Nil {
19  let path = temporary_database()
20  let assert Ok(host) = runtime.start(path)
21  let ledger = runtime.ledger(host)
22  let assert Ok(_) = conversation.initialise(ledger)
23  let assert Ok(_) = family.initialise(ledger)
24  let assert Ok(_) = mail.initialise(ledger)
25  let parent =
26    conversation.Info(
27      "parent",
28      "parent",
29      "/tmp",
30      "provider",
31      "model",
32      types.Responses,
33      conversation.Idle,
34      None,
35      None,
36    )
37  let assert Ok(_) = conversation.create(ledger, parent)
38  let assert Ok(_) =
39    conversation.create(ledger, conversation.Info(..parent, id: "child"))
40  let assert Ok(_) =
41    store.query(ledger, fn(connection) {
42      family.link_in(connection, "child", "parent", "child")
43    })
44  let assert Ok(_) =
45    mail.post(
46      ledger,
47      "closed-letter",
48      "child",
49      Some("parent"),
50      "parent",
51      mail.Task,
52      "task",
53    )
54  let assert Ok(open_letter) =
55    mail.post(
56      ledger,
57      "open-letter",
58      "parent",
59      None,
60      "outside",
61      mail.Message,
62      "open",
63    )
64  let assert Ok(_) = family.close(ledger, "child")
65
66  // This is the commit an already-admitted letter would attempt after close.
67  conversation.commit_operations(
68    ledger,
69    "child",
70    [types.User("task")],
71    conversation.Model,
72    None,
73    ["closed-letter"],
74    [],
75    "turn",
76    "/tmp",
77  )
78  |> should.equal(Error("session is closed"))
79  conversation.load(ledger, "child") |> should.equal(Ok([]))
80  mail.undelivered(ledger, "closed-letter") |> should.be_true
81  store.read(
82    ledger,
83    "SELECT count(*) FROM input_turns",
84    [],
85    decode.field(0, decode.int, decode.success),
86  )
87  |> should.equal(Ok([0]))
88  // Closed recipients must be excluded before the dispatcher's limit.
89  mail.pending(ledger, 1) |> should.equal(Ok([open_letter]))
90
91  // The closed family flag does not prohibit manual chat with no letters.
92  conversation.commit(
93    ledger,
94    "child",
95    [types.User("manual")],
96    conversation.Idle,
97  )
98  |> should.be_ok
99  mail.undelivered(ledger, "closed-letter") |> should.be_true
100  runtime.stop(host)
101  cleanup(path)
102}