use poly_kv::policy::CompressionPolicy;
use poly_kv::receipt::{
now_unix, BlockInjectionTrace, InjectionReceipt, PoolBuildReceipt, ShellMaterializeReceipt,
};
use poly_kv::AgentId;
use poly_kv::Digest;
#[test]
fn test_pool_build_receipt_round_trip_serialize_deserialize() {
let receipt = PoolBuildReceipt::new(
Digest::from_hex_unchecked("abc123"),
vec![
Digest::from_hex_unchecked("layer0_digest"),
Digest::from_hex_unchecked("layer1_digest"),
],
Digest::from_hex_unchecked("codebook_digest"),
Digest::from_hex_unchecked("rotation_digest"),
100,
42,
10_000,
500_000,
CompressionPolicy::default_two_tier(),
42,
now_unix(),
);
assert!(receipt.validate().is_ok());
let json = serde_json::to_string(&receipt).unwrap();
let deser: PoolBuildReceipt = serde_json::from_str(&json).unwrap();
assert_eq!(receipt.pool_digest, deser.pool_digest);
assert_eq!(receipt.layer_digests, deser.layer_digests);
assert_eq!(receipt.total_tokens, deser.total_tokens);
assert_eq!(receipt.fib_build_ms, deser.fib_build_ms);
assert_eq!(receipt.pool_size_bytes, deser.pool_size_bytes);
assert_eq!(receipt.raw_size_bytes, deser.raw_size_bytes);
assert_eq!(receipt.compression_ratio, deser.compression_ratio);
assert_eq!(receipt.seeded_with, deser.seeded_with);
assert_eq!(receipt.built_at_unix, deser.built_at_unix);
assert_eq!(receipt.schema_version, deser.schema_version);
assert_eq!(receipt.codebook_digest, deser.codebook_digest);
assert_eq!(receipt.rotation_digest, deser.rotation_digest);
}
#[test]
fn test_shell_materialize_receipt_round_trip() {
let receipt = ShellMaterializeReceipt::new(
AgentId::new("agent_1"),
Digest::from_hex_unchecked("pool_abc"),
Digest::from_hex_unchecked("shell_xyz"),
50,
5_000,
10,
now_unix(),
);
assert!(receipt.validate().is_ok());
let json = serde_json::to_string(&receipt).unwrap();
let deser: ShellMaterializeReceipt = serde_json::from_str(&json).unwrap();
assert_eq!(receipt.agent_id, deser.agent_id);
assert_eq!(receipt.pool_digest, deser.pool_digest);
assert_eq!(receipt.shell_digest, deser.shell_digest);
assert_eq!(receipt.num_unique_tokens, deser.num_unique_tokens);
assert_eq!(receipt.shell_size_bytes, deser.shell_size_bytes);
assert_eq!(receipt.materialize_ms, deser.materialize_ms);
assert_eq!(receipt.materialized_at_unix, deser.materialized_at_unix);
}
#[test]
fn test_injection_receipt_round_trip() {
let traces = vec![
BlockInjectionTrace {
layer: 0,
source: "pool".into(),
source_digest: Digest::from_hex_unchecked("abc"),
target_position: 0,
},
BlockInjectionTrace {
layer: 0,
source: "shell".into(),
source_digest: Digest::from_hex_unchecked("def"),
target_position: 1,
},
];
let receipt = InjectionReceipt::new(
AgentId::new("agent_1"),
Digest::from_hex_unchecked("pool_abc"),
Digest::from_hex_unchecked("shell_xyz"),
2,
traces,
now_unix(),
);
assert!(receipt.validate().is_ok());
let json = serde_json::to_string(&receipt).unwrap();
let deser: InjectionReceipt = serde_json::from_str(&json).unwrap();
assert_eq!(receipt.agent_id, deser.agent_id);
assert_eq!(receipt.pool_digest, deser.pool_digest);
assert_eq!(receipt.shell_digest, deser.shell_digest);
assert_eq!(receipt.blocks_injected, deser.blocks_injected);
assert_eq!(receipt.block_traces.len(), deser.block_traces.len());
assert_eq!(receipt.block_traces[0].source, deser.block_traces[0].source);
}
#[test]
fn test_receipt_digest_is_content_addressed() {
let receipt1 = PoolBuildReceipt::new(
Digest::from_hex_unchecked("abc"),
vec![Digest::from_hex_unchecked("l0")],
Digest::from_hex_unchecked("cb"),
Digest::from_hex_unchecked("rot"),
10,
100,
500,
5000,
CompressionPolicy::default_two_tier(),
42,
now_unix(),
);
let receipt2 = PoolBuildReceipt::new(
Digest::from_hex_unchecked("abc"),
vec![Digest::from_hex_unchecked("l0")],
Digest::from_hex_unchecked("cb"),
Digest::from_hex_unchecked("rot"),
10,
100,
500,
5000,
CompressionPolicy::default_two_tier(),
42,
now_unix(),
);
let d1 = receipt1.digest().unwrap();
let d2 = receipt2.digest().unwrap();
assert_eq!(d1, d2, "Identical receipts must have identical digests");
let receipt3 = PoolBuildReceipt::new(
Digest::from_hex_unchecked("xyz"),
vec![Digest::from_hex_unchecked("l0")],
Digest::from_hex_unchecked("cb"),
Digest::from_hex_unchecked("rot"),
10,
100,
500,
5000,
CompressionPolicy::default_two_tier(),
42,
now_unix(),
);
let d3 = receipt3.digest().unwrap();
assert_ne!(d1, d3, "Different receipts must have different digests");
}
#[test]
fn test_invalid_receipt_schema_rejected() {
let mut receipt = PoolBuildReceipt::new(
Digest::from_hex_unchecked("abc"),
vec![],
Digest::from_hex_unchecked(""),
Digest::from_hex_unchecked(""),
0,
0,
0,
0,
CompressionPolicy::default_two_tier(),
0,
now_unix(),
);
receipt.schema_version = "bad_version".into();
assert!(receipt.validate().is_err());
}