use std::collections::HashSet;
use serde_json::Value;
pub fn history_trim_is_valid(retained: &[Value]) -> bool {
let produced = tool_use_ids(retained);
for message in retained {
for block in content_blocks(message) {
if block_type(block) == Some("tool_result") {
if let Some(id) = block.get("tool_use_id").and_then(Value::as_str) {
if !produced.contains(id) {
return false; }
}
}
}
}
true
}
fn tool_use_ids(messages: &[Value]) -> HashSet<&str> {
let mut ids = HashSet::new();
for message in messages {
for block in content_blocks(message) {
if block_type(block) == Some("tool_use") {
if let Some(id) = block.get("id").and_then(Value::as_str) {
ids.insert(id);
}
}
}
}
ids
}
fn content_blocks(message: &Value) -> &[Value] {
message
.get("content")
.and_then(Value::as_array)
.map(Vec::as_slice)
.unwrap_or(&[])
}
fn block_type(block: &Value) -> Option<&str> {
block.get("type").and_then(Value::as_str)
}
pub fn reorder_is_structurally_valid(original: &Value, rewritten: &Value) -> bool {
if !non_system_keys_are_identical(original, rewritten) {
return false;
}
let (Some(a), Some(b)) = (
original.get("system").and_then(Value::as_array),
rewritten.get("system").and_then(Value::as_array),
) else {
return false;
};
is_permutation(a, b)
}
pub fn insert_is_structurally_valid(original: &Value, rewritten: &Value) -> bool {
if !non_system_keys_are_identical(original, rewritten) {
return false;
}
let (Some(a), Some(b)) = (
original.get("system").and_then(Value::as_array),
rewritten.get("system").and_then(Value::as_array),
) else {
return false;
};
a.len() == b.len()
&& a.iter()
.zip(b.iter())
.all(|(before, after)| differs_only_by_added_cache_control(before, after))
}
fn non_system_keys_are_identical(original: &Value, rewritten: &Value) -> bool {
let (Some(a), Some(b)) = (original.as_object(), rewritten.as_object()) else {
return false;
};
if a.len() != b.len() {
return false;
}
a.iter().all(|(k, v)| k == "system" || b.get(k) == Some(v))
&& b.keys().all(|k| a.contains_key(k))
}
fn is_permutation(a: &[Value], b: &[Value]) -> bool {
if a.len() != b.len() {
return false;
}
let mut claimed = vec![false; b.len()];
for block in a {
match b
.iter()
.enumerate()
.position(|(i, candidate)| !claimed[i] && candidate == block)
{
Some(i) => claimed[i] = true,
None => return false,
}
}
true
}
fn differs_only_by_added_cache_control(before: &Value, after: &Value) -> bool {
let (Some(a), Some(b)) = (before.as_object(), after.as_object()) else {
return before == after;
};
if !a.iter().all(|(k, v)| b.get(k) == Some(v)) {
return false;
}
b.keys().all(|k| a.contains_key(k) || k == "cache_control")
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn tool_use(id: &str) -> Value {
json!({ "role": "assistant", "content": [ { "type": "tool_use", "id": id, "name": "search", "input": {} } ] })
}
fn tool_result(id: &str) -> Value {
json!({ "role": "user", "content": [ { "type": "tool_result", "tool_use_id": id, "content": "ok" } ] })
}
#[test]
fn matched_tool_pair_in_the_tail_is_valid() {
let retained = vec![tool_use("toolu_1"), tool_result("toolu_1")];
assert!(history_trim_is_valid(&retained));
}
#[test]
fn orphaned_tool_result_is_invalid() {
let retained = vec![tool_result("toolu_9")];
assert!(!history_trim_is_valid(&retained));
}
#[test]
fn plain_text_history_is_always_valid() {
let retained = vec![
json!({ "role": "user", "content": "hi" }),
json!({ "role": "assistant", "content": "hello" }),
];
assert!(history_trim_is_valid(&retained));
}
#[test]
fn a_result_before_its_use_in_the_tail_is_still_valid() {
let retained = vec![tool_result("toolu_2"), tool_use("toolu_2")];
assert!(history_trim_is_valid(&retained));
}
fn blk(t: &str) -> Value {
json!({ "type": "text", "text": t })
}
fn doc(system: Vec<Value>) -> Value {
json!({
"model": "claude-opus-4-8",
"system": system,
"messages": [ tool_use("toolu_1"), tool_result("toolu_1") ]
})
}
#[test]
fn a_genuine_permutation_validates() {
let before = doc(vec![blk("a"), blk("b"), blk("c")]);
let after = doc(vec![blk("b"), blk("c"), blk("a")]);
assert!(reorder_is_structurally_valid(&before, &after));
}
#[test]
fn a_dropped_block_does_not_validate() {
let before = doc(vec![blk("a"), blk("b")]);
let after = doc(vec![blk("b")]);
assert!(!reorder_is_structurally_valid(&before, &after));
}
#[test]
fn a_duplicated_block_does_not_validate() {
let before = doc(vec![blk("a"), blk("b")]);
let after = doc(vec![blk("a"), blk("a")]);
assert!(!reorder_is_structurally_valid(&before, &after));
}
#[test]
fn duplicate_blocks_are_matched_by_multiplicity_not_membership() {
let before = doc(vec![blk("a"), blk("a"), blk("b")]);
assert!(reorder_is_structurally_valid(
&before,
&doc(vec![blk("b"), blk("a"), blk("a")])
));
assert!(!reorder_is_structurally_valid(
&before,
&doc(vec![blk("a"), blk("b"), blk("b")])
));
}
#[test]
fn an_edited_block_does_not_validate() {
let before = doc(vec![blk("a"), blk("b")]);
let after = doc(vec![blk("b"), blk("a ")]); assert!(!reorder_is_structurally_valid(&before, &after));
}
#[test]
fn touching_messages_does_not_validate() {
let before = doc(vec![blk("a")]);
let mut after = before.clone();
after["messages"] = json!([tool_result("toolu_1")]); assert!(!reorder_is_structurally_valid(&before, &after));
assert!(!insert_is_structurally_valid(&before, &after));
}
#[test]
fn touching_any_other_top_level_key_does_not_validate() {
let before = doc(vec![blk("a")]);
let mut after = before.clone();
after["model"] = json!("claude-haiku-4-5");
assert!(!reorder_is_structurally_valid(&before, &after));
let mut added = before.clone();
added["temperature"] = json!(0.5);
assert!(!reorder_is_structurally_valid(&before, &added));
}
#[test]
fn adding_one_cache_control_marker_validates() {
let before = doc(vec![blk("a"), blk("b")]);
let mut after = before.clone();
after["system"][1]["cache_control"] = json!({ "type": "ephemeral" });
assert!(insert_is_structurally_valid(&before, &after));
}
#[test]
fn insert_that_reorders_does_not_validate() {
let before = doc(vec![blk("a"), blk("b")]);
let after = doc(vec![blk("b"), blk("a")]);
assert!(!insert_is_structurally_valid(&before, &after));
}
#[test]
fn displacing_an_existing_marker_does_not_validate() {
let mut before = doc(vec![blk("a")]);
before["system"][0]["cache_control"] = json!({ "type": "ephemeral", "ttl": "1h" });
let mut after = before.clone();
after["system"][0]["cache_control"] = json!({ "type": "ephemeral" });
assert!(!insert_is_structurally_valid(&before, &after));
}
#[test]
fn editing_text_while_adding_a_marker_does_not_validate() {
let before = doc(vec![blk("a")]);
let mut after = before.clone();
after["system"][0]["text"] = json!("a!");
after["system"][0]["cache_control"] = json!({ "type": "ephemeral" });
assert!(!insert_is_structurally_valid(&before, &after));
}
#[test]
fn a_string_valued_system_never_validates_for_either_mechanism() {
let before = json!({ "system": "plain", "messages": [] });
let after = json!({ "system": [ blk("plain") ], "messages": [] });
assert!(!reorder_is_structurally_valid(&before, &after));
assert!(!insert_is_structurally_valid(&before, &after));
}
}