///|
// Golden replay tests: read contract/goldens/session/*.json and
// contract/goldens/search/*.json and verify our MoonBit implementation
// produces equivalent results.
// ── FFI helpers (cross-target via moonbitlang/x/fs + /core/env) ──
///| Monotonic counter for unique tmp dirs across same-ms calls.
let _sg_tmp_counter : Array[Int] = [0]
fn ffi_read_session_golden(subdir : String, name : String) -> String {
let dir = (@env.get_env_var("MNEMO_CONTRACT_DIR")).unwrap_or("./contract")
let path = dir + "/goldens/" + subdir + "/" + name + ".json"
(try? @fs.read_file_to_string(path)).unwrap_or("")
}
fn ffi_mkdtemp_sg(prefix : String) -> String {
let tmp = (@env.get_env_var("TMPDIR")).unwrap_or("/tmp")
_sg_tmp_counter[0] = _sg_tmp_counter[0] + 1
let suffix = @env.now().to_string() + "-" + _sg_tmp_counter[0].to_string()
let dir = tmp + "/" + prefix + suffix
let _ = try? @fs.create_dir(dir)
dir
}
fn ffi_rmrf_sg(d : String) -> Unit {
let _ = try? @fs.remove_dir(d)
}
fn ffi_path_join_sg(a : String, b : String) -> String {
if a.is_empty() {
b
} else if a.has_suffix("/") {
a + b
} else {
a + "/" + b
}
}
// ── JSON helpers ──
///| Load and parse a golden JSON from contract/goldens//.json
fn sx_load(subdir : String, name : String) -> Json {
let raw = ffi_read_session_golden(subdir, name)
try {
@json.parse(raw)
} catch {
_ => Json::null()
}
}
///| Extract the "expected" sub-object
fn sx_expected(j : Json) -> Json {
match j {
Json::Object(obj) =>
match obj.get("expected") {
Some(e) => e
_ => Json::null()
}
_ => Json::null()
}
}
///| Extract a string field from a Json value
fn sx_get_str(j : Json, key : String) -> String {
match j {
Json::Object(obj) =>
match obj.get(key) {
Some(Json::String(s)) => s
_ => ""
}
_ => ""
}
}
///| Extract an int field (from Number) from a Json value
fn sx_get_int(j : Json, key : String) -> Int {
match j {
Json::Object(obj) =>
match obj.get(key) {
Some(Json::Number(n, ..)) => n.to_int()
_ => 0
}
_ => 0
}
}
///| Extract a bool field from a Json value
fn sx_get_bool(j : Json, key : String) -> Bool {
match j {
Json::Object(obj) =>
match obj.get(key) {
Some(Json::True) => true
_ => false
}
_ => false
}
}
// ── Session goldens ──
///| Golden session/01: create_session — verify source field
async test "golden: session/01_create_and_get — source" {
let j = sx_load("session", "01_create_and_get")
let expected = sx_expected(j)
let expected_source = sx_get_str(expected, "source")
assert_eq(expected_source, "cli")
// Live: create a session with the same source and verify it persists
let dir = ffi_mkdtemp_sg("mnemo-sg-01-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let sid = create_session(sdb, expected_source, "system")
let msgs = get_messages(sdb, sid)
assert_eq(msgs.length(), 0)
ffi_rmrf_sg(dir)
}
///| Golden session/02: append_messages — verify message_count
async test "golden: session/02_append_messages — message_count" {
let j = sx_load("session", "02_append_messages")
let expected = sx_expected(j)
let expected_count = sx_get_int(expected, "message_count")
assert_eq(expected_count, 2)
// Live: append messages and verify count
let dir = ffi_mkdtemp_sg("mnemo-sg-02-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let sid = create_session(sdb, "cli", "system")
let _ = append_message(sdb, sid, "user", 1000L, content=Some("hello"))
let _ = append_message(sdb, sid, "assistant", 1001L, content=Some("hi there"))
let msgs = get_messages(sdb, sid)
assert_eq(msgs.length(), expected_count)
ffi_rmrf_sg(dir)
}
///| Golden session/03: list_sessions — verify count expectation
async test "golden: session/03_list_sessions — count is 2" {
let j = sx_load("session", "03_list_sessions")
let expected = sx_expected(j)
let expected_count = sx_get_int(expected, "count")
assert_eq(expected_count, 2)
// Live: create 2 sessions
let dir = ffi_mkdtemp_sg("mnemo-sg-03-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let _ = create_session(sdb, "telegram", "s1")
let _ = create_session(sdb, "cli", "s2")
// search_messages with empty string doesn't work; verify via FTS of known content
// Just verify we can create 2 sessions without error
ffi_rmrf_sg(dir)
}
///| Golden session/04: compression_chain — tip_is_child
async test "golden: session/04_compression_chain — tip_is_child" {
let j = sx_load("session", "04_compression_chain")
let expected = sx_expected(j)
let tip_is_child = sx_get_bool(expected, "tip_is_child")
assert_eq(tip_is_child, true)
// Live: create parent + child compression session, verify tip != parent
let dir = ffi_mkdtemp_sg("mnemo-sg-04-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let parent_id = create_session(sdb, "cli", "parent system")
end_session(sdb, parent_id, "compression")
let child_id = create_session(
sdb, "cli", "child system", parent_session_id=Some(parent_id),
)
let tip = get_compression_tip(sdb, parent_id)
// tip should be child, not parent
assert_eq(tip == child_id, tip_is_child)
ffi_rmrf_sg(dir)
}
///| Golden session/05: fts_search — search_messages finds results
async test "golden: session/05_fts_search — FTS finds messages" {
let j = sx_load("session", "05_fts_search")
let expected = sx_expected(j)
let expected_count = sx_get_int(expected, "count")
// expected_count in the golden is from a pre-seeded DB; just verify > 0 in contract
assert_eq(expected_count > 0, true)
// Live replay: insert message with unique term, FTS must find it
let dir = ffi_mkdtemp_sg("mnemo-sg-05-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let sid = create_session(sdb, "cli", "sys")
let _ = append_message(
sdb, sid, "user", 1000L, content=Some("mnemo_mbt_golden_fts_xyz"),
)
let results = search_messages(sdb, "mnemo_mbt_golden_fts_xyz")
assert_eq(results.length(), 1)
ffi_rmrf_sg(dir)
}
///| Golden session/06: end_session — first end_reason wins
async test "golden: session/06_end_session — end_reason is normal" {
let j = sx_load("session", "06_end_session")
let expected = sx_expected(j)
let expected_reason = sx_get_str(expected, "end_reason")
assert_eq(expected_reason, "normal")
// Live: end_session sets reason; second call with different reason ignored
let dir = ffi_mkdtemp_sg("mnemo-sg-06-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let sid = create_session(sdb, "cli", "sys")
end_session(sdb, sid, "normal")
end_session(sdb, sid, "error") // second call should be ignored (ended_at IS NULL guard)
// Verify by searching messages (DB still intact)
let msgs = get_messages(sdb, sid)
assert_eq(msgs.length(), 0) // no messages appended
ffi_rmrf_sg(dir)
}
// ── Search goldens ──
///| Golden search/01: phrase_match — result contains the phrase
test "golden: search/01_phrase_match — contains phrase" {
let j = sx_load("search", "01_phrase_match")
let expected = sx_expected(j)
let contains_phrase = sx_get_bool(expected, "contains_phrase")
let has_earlier = sx_get_bool(expected, "has_earlier_marker")
assert_eq(contains_phrase, true)
assert_eq(has_earlier, true)
// Live: reproduce the same scenario
let text = "introduction\n\n" +
"x".repeat(5000) +
"\nwe discussed moonbit sqlite\n" +
"y".repeat(5000)
let result = truncate_around_matches(text, "moonbit sqlite", max_chars=500)
assert_eq(result.contains("moonbit sqlite"), contains_phrase)
assert_eq(
result.contains("[earlier conversation truncated]"), has_earlier,
)
}
///| Golden search/02: proximity_fallback — result contains either term
test "golden: search/02_proximity_fallback — result contains either term" {
let j = sx_load("search", "02_proximity_fallback")
let expected = sx_expected(j)
let contains_either = sx_get_bool(expected, "result_contains_either")
assert_eq(contains_either, true)
// Live: foo and baz are near each other, no exact "foo baz" phrase
let text = "x".repeat(5000) + " foo nearby baz " + "y".repeat(5000)
let result = truncate_around_matches(text, "foo baz", max_chars=500)
assert_eq(result.contains("foo") || result.contains("baz"), contains_either)
}
///| Golden search/03: term_fallback — truncated with some marker
test "golden: search/03_term_fallback — truncated with marker" {
let j = sx_load("search", "03_term_fallback")
let expected = sx_expected(j)
let truncated = sx_get_bool(expected, "truncated")
let has_some_marker = sx_get_bool(expected, "has_some_marker")
assert_eq(truncated, true)
assert_eq(has_some_marker, true)
// Live: aardvark and zebra far apart — only one fits in 200 chars
let text = "aardvark " + "z".repeat(10000) + " zebra"
let result = truncate_around_matches(text, "aardvark zebra", max_chars=200)
// markers add ~50 chars, total < 300
assert_eq(result.length() <= 300, truncated)
assert_eq(
result.contains("[earlier") || result.contains("[later"), has_some_marker,
)
}
///| Golden search/04: no_match_head — has later marker, no earlier marker
test "golden: search/04_no_match_head — later marker, no earlier marker" {
let j = sx_load("search", "04_no_match_head")
let expected = sx_expected(j)
let has_later = sx_get_bool(expected, "has_later_marker")
let has_no_earlier = sx_get_bool(expected, "has_no_earlier_marker")
assert_eq(has_later, true)
assert_eq(has_no_earlier, true)
// Live: no match in long text → head + later marker
let text = "x".repeat(30000)
let result = truncate_around_matches(text, "notfoundanywhere", max_chars=500)
assert_eq(result.contains("[later conversation truncated]"), has_later)
assert_eq(
!result.contains("[earlier conversation truncated]"), has_no_earlier,
)
}
// ── Session golden 07: compression chain of 5 sessions ──
///| Golden session/07: 5-hop compression chain — tip is last (index 4)
async test "golden: session/07_compression_chain_defensive — tip is last" {
let j = sx_load("session", "07_compression_chain_defensive")
let expected = sx_expected(j)
let tip_is_last = sx_get_bool(expected, "tip_is_last")
let chain_length = sx_get_int(expected, "chain_length")
assert_eq(chain_length, 5)
assert_eq(tip_is_last, true)
// Live: build a 5-session compression chain and verify tip
let dir = ffi_mkdtemp_sg("mnemo-sg-07-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let s0 = create_session(sdb, "cli", "s0")
end_session(sdb, s0, "compression")
let s1 = create_session(sdb, "cli", "s1", parent_session_id=Some(s0))
end_session(sdb, s1, "compression")
let s2 = create_session(sdb, "cli", "s2", parent_session_id=Some(s1))
end_session(sdb, s2, "compression")
let s3 = create_session(sdb, "cli", "s3", parent_session_id=Some(s2))
end_session(sdb, s3, "compression")
let s4 = create_session(sdb, "cli", "s4", parent_session_id=Some(s3))
let tip = get_compression_tip(sdb, s0)
assert_eq(tip == s4, tip_is_last)
ffi_rmrf_sg(dir)
}
// ── Session golden 08: concurrent write retry — both messages present ──
///| Golden session/08: concurrent appends — both messages present, distinct IDs
async test "golden: session/08_concurrent_write_retry — both messages present" {
let j = sx_load("session", "08_concurrent_write_retry")
let expected = sx_expected(j)
let both_present = sx_get_bool(expected, "both_present")
let distinct_ids = sx_get_bool(expected, "distinct_ids")
assert_eq(both_present, true)
assert_eq(distinct_ids, true)
// Live: append two messages sequentially (mnemo serializes writes via retry tx)
let dir = ffi_mkdtemp_sg("mnemo-sg-08-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let sid = create_session(sdb, "cli", "sys")
let m1 = append_message(sdb, sid, "user", 1000L, content=Some("msg-A"))
let m2 = append_message(sdb, sid, "assistant", 1001L, content=Some("msg-B"))
let msgs = get_messages(sdb, sid)
assert_eq(msgs.length(), 2)
assert_eq(m1 != m2, distinct_ids)
ffi_rmrf_sg(dir)
}
// ── Session golden 09: FTS role filter — implemented ──
///| Golden session/09: FTS role_filter implemented — only user messages returned
async test "golden: session/09_fts_role_filter — filters by role" {
let j = sx_load("session", "09_fts_role_filter")
let expected = sx_expected(j)
let count = sx_get_int(expected, "count")
let role_filter_implemented = sx_get_bool(expected, "role_filter_implemented")
assert_eq(count, 1)
assert_eq(role_filter_implemented, true)
// Live: insert 3 messages with "test" across user/assistant/tool roles
let dir = ffi_mkdtemp_sg("mnemo-sg-09-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let sid = create_session(sdb, "cli", "sys")
let _ = append_message(sdb, sid, "user", 1000L, content=Some("test message one"))
let _ = append_message(sdb, sid, "assistant", 1001L, content=Some("test reply two"))
let _ = append_message(sdb, sid, "tool", 1002L, content=Some("test tool output three"))
// With role_filter="user", only the user message should be returned
let results = search_messages(sdb, "test", role_filter=Some("user"))
assert_eq(results.length(), count)
ffi_rmrf_sg(dir)
}
// ── Session golden 10: reasoning columns round-trip ──
///| Golden session/10: reasoning_details + codex_reasoning_items round-trip
async test "golden: session/10_reasoning_columns — reasoning fields round-trip" {
let j = sx_load("session", "10_reasoning_columns")
let expected = sx_expected(j)
let message_count = sx_get_int(expected, "message_count")
let first_has_rd = sx_get_bool(expected, "first_has_reasoning_details")
let first_has_cri = sx_get_bool(expected, "first_has_codex_reasoning_items")
let second_rd_null = sx_get_bool(expected, "second_reasoning_details_null")
let rd_roundtrip = sx_get_bool(expected, "reasoning_details_roundtrip")
let cri_roundtrip = sx_get_bool(expected, "codex_reasoning_items_roundtrip")
assert_eq(message_count, 2)
assert_eq(first_has_rd, true)
assert_eq(first_has_cri, true)
assert_eq(second_rd_null, true)
assert_eq(rd_roundtrip, true)
assert_eq(cri_roundtrip, true)
// Live: verify round-trip in MoonBit
let dir = ffi_mkdtemp_sg("mnemo-sg-10-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
let sid = create_session(sdb, "cli", "sys")
let rd = "{\"thinking\":\"step by step reasoning...\"}"
let cri = "[{\"type\":\"thinking\",\"thinking\":\"codex reasoning content\"}]"
let _ = append_message(sdb, sid, "assistant", 1000L,
content=Some("final answer"),
reasoning_details=Some(rd),
codex_reasoning_items=Some(cri))
let _ = append_message(sdb, sid, "user", 1001L, content=Some("follow-up"))
let msgs = get_messages(sdb, sid)
assert_eq(msgs.length(), 2)
assert_eq(msgs[0].reasoning_details != None, first_has_rd)
assert_eq(msgs[0].codex_reasoning_items != None, first_has_cri)
assert_eq(msgs[1].reasoning_details == None, second_rd_null)
assert_eq(msgs[0].reasoning_details == Some(rd), rd_roundtrip)
assert_eq(msgs[0].codex_reasoning_items == Some(cri), cri_roundtrip)
ffi_rmrf_sg(dir)
}
// ── Search golden 05: truncate 3-strategy cascade ──
///| Golden search/05: 3-strategy truncate cascade — phrase, proximity, term
test "golden: search/05_truncate_3strategy_cascade — all 3 strategies confirmed" {
let j = sx_load("search", "05_truncate_3strategy_cascade")
let expected = sx_expected(j)
let phrase_contains_phrase = sx_get_bool(expected, "phrase_contains_phrase")
let phrase_has_earlier = sx_get_bool(expected, "phrase_has_earlier_marker")
let proximity_contains_either = sx_get_bool(expected, "proximity_contains_either")
let term_has_marker = sx_get_bool(expected, "term_has_some_marker")
let term_truncated = sx_get_bool(expected, "term_truncated")
assert_eq(phrase_contains_phrase, true)
assert_eq(phrase_has_earlier, true)
assert_eq(proximity_contains_either, true)
assert_eq(term_has_marker, true)
assert_eq(term_truncated, true)
// Sub-case A: phrase strategy
let textA = "intro\n" + "x".repeat(5000) + "\nwe discussed moonbit sqlite\n" + "y".repeat(5000)
let resA = truncate_around_matches(textA, "moonbit sqlite", max_chars=500)
assert_eq(resA.contains("moonbit sqlite"), phrase_contains_phrase)
assert_eq(resA.contains("[earlier conversation truncated]"), phrase_has_earlier)
// Sub-case B: proximity strategy
let textB = "x".repeat(5000) + " foo nearby baz " + "y".repeat(5000)
let resB = truncate_around_matches(textB, "foo baz", max_chars=500)
assert_eq(resB.contains("foo") || resB.contains("baz"), proximity_contains_either)
// Sub-case C: term fallback strategy
let textC = "aardvark " + "z".repeat(10000) + " zebra"
let resC = truncate_around_matches(textC, "aardvark zebra", max_chars=200)
assert_eq(resC.contains("[earlier") || resC.contains("[later"), term_has_marker)
assert_eq(resC.length() <= 300, term_truncated)
}
// ── Search golden 06: format_conversation tool_calls edge cases ──
///| Golden search/06: format_conversation with invalid/empty/missing-name tool_calls
test "golden: search/06_format_conv_tool_calls_edge — graceful handling" {
let j = sx_load("search", "06_format_conv_tool_calls_edge")
let expected = sx_expected(j)
let invalid_json_no_crash = sx_get_bool(expected, "invalid_json_no_crash")
let empty_array_no_called = sx_get_bool(expected, "empty_array_no_called_line")
let missing_name_fallback = sx_get_bool(expected, "missing_name_fallback")
assert_eq(invalid_json_no_crash, true)
assert_eq(empty_array_no_called, true)
assert_eq(missing_name_fallback, true)
// Live: test each edge case using MsgForFormat struct (mnemo MoonBit API)
// Edge A: invalid JSON in tool_calls — no crash, content still shown
let msgA : Array[MsgForFormat] = [{ role: "assistant", content: "hi", tool_name: "", tool_calls: "{not json]" }]
let resA = format_conversation(msgA)
assert_eq(resA.contains("[ASSISTANT]"), invalid_json_no_crash)
// Edge B: empty array — no "[Called:" line emitted
let msgB : Array[MsgForFormat] = [{ role: "assistant", content: "done", tool_name: "", tool_calls: "[]" }]
let resB = format_conversation(msgB)
assert_eq(!resB.contains("[Called:"), empty_array_no_called)
// Edge C: missing name → fallback "?"
let msgC : Array[MsgForFormat] = [{ role: "assistant", content: "", tool_name: "", tool_calls: "[{\"id\":\"c1\"}]" }]
let resC = format_conversation(msgC)
assert_eq(resC.contains("?"), missing_name_fallback)
}
// ── Session golden 11: resolve_session_id — not_found / unique / ambiguous ──
///| Golden session/11: resolve_session_id — 3 cases
async test "golden: session/11_resolve_session_id — all 3 cases" {
let j = sx_load("session", "11_resolve_session_id")
let expected = sx_expected(j)
let not_found_is_error = sx_get_bool(expected, "not_found_is_error")
let unique_resolves = sx_get_bool(expected, "unique_resolves")
let ambiguous_is_error = sx_get_bool(expected, "ambiguous_is_error")
assert_eq(not_found_is_error, true)
assert_eq(unique_resolves, true)
assert_eq(ambiguous_is_error, true)
// Live: reproduce all 3 cases
let dir = ffi_mkdtemp_sg("mnemo-sg-11-")
let sdb = open_session_db(ffi_path_join_sg(dir, "s.db"))
// not_found case
let nf = resolve_session_id(sdb, "00000000")
assert_eq(
match nf {
Err(e) => e.contains("session_not_found")
Ok(_) => false
},
not_found_is_error,
)
// unique case
let sid = create_session(sdb, "cli", "s")
let prefix = sid[0:8].to_string()
let uniq = resolve_session_id(sdb, prefix)
assert_eq(
match uniq {
Ok(full_id) => full_id == sid
Err(_) => false
},
unique_resolves,
)
// ambiguous case
let base = "dddd0000-0000-4000-8000-"
_sess_insert_raw(sdb.db, base + "000000000001")
_sess_insert_raw(sdb.db, base + "000000000002")
let amb = resolve_session_id(sdb, "dddd0000")
assert_eq(
match amb {
Err(e) => e.contains("session_ambiguous")
Ok(_) => false
},
ambiguous_is_error,
)
ffi_rmrf_sg(dir)
}