#[allow(clippy::wildcard_imports)]
use super::*;
use lean_ctx::core::context_admission::capture::{AdmissionCapture, Delivered};
use lean_ctx::core::context_admission::receipt_store::{self, ReceiptRecord, ReceiptSubject};
fn delivered_text(result: &Result<CallToolResult, ErrorData>) -> (String, bool) {
match result {
Ok(result) => {
let text = result
.content
.iter()
.filter_map(|block| block.as_text().map(|text| text.text.as_str()))
.collect::<Vec<_>>()
.join("\n");
(text, result.is_error == Some(true))
}
Err(error) => (error.message.to_string(), true),
}
}
fn result_digest(result: &Result<CallToolResult, ErrorData>) -> lean_ctx_protocol::Sha256Digest {
let value = match result {
Ok(result) => serde_json::to_value(result),
Err(error) => serde_json::to_value(error),
}
.unwrap_or(serde_json::Value::Null);
receipt_store::output_digest(&serde_json::to_vec(&value).unwrap_or_default())
}
fn settle(
record: &ReceiptRecord,
mandatory: bool,
result: Result<CallToolResult, ErrorData>,
) -> Result<CallToolResult, ErrorData> {
if record.withholds(mandatory) {
Ok(CallToolResult::error(vec![
rmcp::model::ContentBlock::text(receipt_store::not_persisted_notice()),
]))
} else {
result
}
}
impl LeanCtxServer {
pub(super) async fn finish_gateway_receipt(
&self,
capture: std::sync::Arc<AdmissionCapture>,
result: Result<CallToolResult, ErrorData>,
tool: &str,
) -> Result<CallToolResult, ErrorData> {
let duty = receipt_store::Duty::of(&capture);
if capture.is_empty() && !duty.mandatory {
return result;
}
let (text, is_error) = delivered_text(&result);
let agent_id = self.agent_id.read().await.clone();
let project_root = self
.session
.read()
.await
.project_root
.clone()
.unwrap_or_else(|| ".".to_owned());
let tool = tool.to_owned();
let presenter_ref = lean_ctx::core::archive::presented::shown_presenter_reference();
let mandatory = duty.mandatory;
let delivery = receipt_store::trace::Delivery::mcp(&tool, duty.snapshot())
.prepared_as(result_digest(&result));
let record = tokio::task::spawn_blocking(move || {
let delivered = Delivered {
tokens: lean_ctx::core::tokens::count_tokens(&text) as u64,
text: &text,
is_error,
};
let subject = ReceiptSubject {
tool: &tool,
agent_id: agent_id.as_deref(),
presenter_ref: presenter_ref.as_deref(),
project_root: &project_root,
delivery: &delivery,
};
receipt_store::record_delivery(&capture, &subject, &delivered, &duty)
})
.await
.unwrap_or(ReceiptRecord::Missing { security: false });
tracing::debug!("context gateway receipt: {}", record.summary());
if record.security() {
self.publish_value_snapshot().await;
}
let result = settle(&record, mandatory, result);
if let Some(prepared) = record.into_prepared() {
let returned = result_digest(&result);
let _ = tokio::task::spawn_blocking(move || prepared.returned_to_transport(&returned))
.await;
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
const CONTENT: &str = "pub fn delivered_body() -> u32 { 41 }";
fn returned_as(text: &str, admitted: bool) -> ((String, bool), ReceiptRecord) {
let duty = receipt_store::Duty::at_entry();
let capture = AdmissionCapture::for_call(duty.snapshot().clone());
if admitted {
lean_ctx::core::context_admission::capture::ADMISSIONS
.sync_scope(Some(capture.clone()), || {
lean_ctx::core::context_admission::admit_context_source(text)
})
.expect("a clean source is admitted");
}
let delivery = receipt_store::trace::Delivery::mcp("ctx_read", duty.snapshot());
let record = receipt_store::record_delivery(
&capture,
&ReceiptSubject {
tool: "ctx_read",
agent_id: None,
presenter_ref: None,
project_root: "/project",
delivery: &delivery,
},
&Delivered {
text,
is_error: false,
tokens: 9,
},
&duty,
);
let left = delivered_text(&settle(
&record,
duty.mandatory,
Ok(CallToolResult::success(vec![
rmcp::model::ContentBlock::text(text),
])),
));
(left, record)
}
fn returned() -> (String, bool) {
returned_as(CONTENT, true).0
}
fn break_receipt_store() {
let gateway = lean_ctx::core::data_dir::lean_ctx_data_dir()
.expect("data dir")
.join("gateway");
let _ = std::fs::remove_dir_all(&gateway);
std::fs::create_dir_all(gateway.parent().expect("data dir")).expect("data dir");
std::fs::write(&gateway, b"not a directory").expect("blocked store");
}
struct OneMegabyteStore;
impl OneMegabyteStore {
fn set() -> Self {
lean_ctx::test_env::set_var("LEAN_CTX_GATEWAY_STORE_MAX_MB", "1");
Self
}
fn fill() -> std::path::PathBuf {
let gateway = lean_ctx::core::data_dir::lean_ctx_data_dir()
.expect("data dir")
.join("gateway");
std::fs::create_dir_all(gateway.join("receipts")).expect("store");
let filler = gateway.join("receipts").join("earlier-evidence.bin");
std::fs::write(&filler, vec![b'e'; 600 * 1024]).expect("filler");
use lean_ctx::core::context_admission::receipt_store::retention;
let pass = retention::maintain_in(
&gateway,
std::time::SystemTime::now(),
retention::Policy::current(),
)
.expect("pass");
assert!(pass.full && retention::proven_full(&gateway), "{pass:?}");
filler
}
}
impl Drop for OneMegabyteStore {
fn drop(&mut self) {
lean_ctx::test_env::remove_var("LEAN_CTX_GATEWAY_STORE_MAX_MB");
}
}
#[test]
fn a_full_store_refuses_new_receipts_and_keeps_the_stored_ones() {
let _env = lean_ctx::core::data_dir::test_env_lock();
let _community = lean_ctx::core::policy::runtime::TestPolicyOverride::set(None);
{
let _data = lean_ctx::core::data_dir::isolated_data_dir();
let _ceiling = OneMegabyteStore::set();
OneMegabyteStore::fill();
let (left, record) = returned_as(CONTENT, true);
assert_eq!(left, (CONTENT.to_owned(), false), "developer mode delivers");
assert!(
matches!(record, ReceiptRecord::Missing { .. }),
"a refused receipt is missing, never claimed: {record:?}"
);
}
let _data = lean_ctx::core::data_dir::isolated_data_dir();
let _ceiling = OneMegabyteStore::set();
let config = lean_ctx::core::paths::config_dir_read_only().expect("config dir");
std::fs::create_dir_all(&config).expect("config dir");
std::fs::write(
config.join("config.toml"),
"[context_gateway]\nmode = \"governed\"\n",
)
.expect("config");
let (left, record) = returned_as(CONTENT, true);
assert_eq!(left, (CONTENT.to_owned(), false), "store has room");
let ReceiptRecord::Stored { digest: kept, .. } = &record else {
panic!("a receipt that fits is stored: {record:?}");
};
let filler = OneMegabyteStore::fill();
let (left, record) = returned_as("pub fn another_body() -> u32 { 42 }", true);
assert_eq!(
left,
(receipt_store::not_persisted_notice(), true),
"a governed release without its receipt is withheld"
);
assert!(
matches!(record, ReceiptRecord::Missing { .. }),
"{record:?}"
);
assert!(filler.exists());
receipt_store::load(kept.hex()).expect("the earlier receipt is still verified");
assert!(matches!(
receipt_store::trace::load(kept),
receipt_store::trace::StoredTrace::Bound { .. }
));
let usage = receipt_store::store_usage(1)
.expect("store")
.expect("measurable");
assert!(
usage.bytes + receipt_store::capacity::LIFECYCLE_RESERVE > 1_048_576,
"the operator's view says full: {usage:?}"
);
}
#[test]
fn a_result_without_its_mandatory_receipt_is_not_returned() {
let _env = lean_ctx::core::data_dir::test_env_lock();
let _community = lean_ctx::core::policy::runtime::TestPolicyOverride::set(None);
{
let _data = lean_ctx::core::data_dir::isolated_data_dir();
break_receipt_store();
assert_eq!(returned(), (CONTENT.to_owned(), false), "developer mode");
}
let _data = lean_ctx::core::data_dir::isolated_data_dir();
let config = lean_ctx::core::paths::config_dir_read_only().expect("config dir");
std::fs::create_dir_all(&config).expect("config dir");
std::fs::write(
config.join("config.toml"),
"[context_gateway]\nmode = \"governed\"\n",
)
.expect("config");
assert_eq!(returned(), (CONTENT.to_owned(), false), "store writable");
let (left, record) = returned_as(CONTENT, false);
assert_eq!(left, (CONTENT.to_owned(), false));
let ReceiptRecord::Stored { digest, .. } = &record else {
panic!("an unsourced result is receipted: {record:?}");
};
let stored = receipt_store::load(digest.hex()).expect("verified receipt");
let reasons = &stored.receipt.decisions[0].reason_codes;
assert_eq!(reasons[0].as_str(), "delivery.no_source_decision");
let receipt_store::trace::StoredTrace::Bound {
digest: trace,
sidecar,
} = receipt_store::trace::load(digest)
else {
panic!("the mandatory receipt has its sidecar");
};
assert!(sidecar.unsourced);
let anchors = receipt_store::AuditAnchors::load();
let anchor = anchors.of(digest.hex()).expect("anchored");
assert_eq!(anchor.trace.as_deref(), Some(trace.as_str()));
assert_eq!(
sidecar.release_prepared.channel,
receipt_store::trace::Channel::McpTransport
);
assert_eq!(
sidecar.policy_snapshot.as_deref(),
stored
.receipt
.policy
.as_ref()
.map(|policy| policy.digest.hex())
);
assert_eq!(
receipt_store::observed::load(digest),
receipt_store::observed::StoredObservation::Absent
);
let recovery_id = "5".repeat(64);
receipt_store::references::note_recovery(&recovery_id);
let stub = format!("{CONTENT}\n[recover with {recovery_id}]");
let (_, record) = returned_as(&stub, true);
let ReceiptRecord::Stored { digest, .. } = &record else {
panic!("receipted: {record:?}");
};
let receipt_store::trace::StoredTrace::Bound { sidecar, .. } =
receipt_store::trace::load(digest)
else {
panic!("the mandatory receipt has its sidecar");
};
assert_eq!(sidecar.recovery, vec![recovery_id]);
let duty = receipt_store::Duty::at_entry();
let capture = AdmissionCapture::for_call(duty.snapshot().clone());
lean_ctx::core::context_admission::capture::ADMISSIONS
.sync_scope(Some(capture.clone()), || {
lean_ctx::core::context_admission::admit_context_source(CONTENT).map(|_| {
lean_ctx::core::context_admission::capture::note_source_id("vendor/remote.rs");
})
})
.expect("a clean source is admitted");
let (named, _) = capture.source_references();
assert_eq!(
named.into_iter().map(|(_, name)| name).collect::<Vec<_>>(),
[lean_ctx::core::context_admission::capture::SourceName::Id(
"vendor/remote.rs".to_owned()
)]
);
let duty = receipt_store::Duty::at_entry();
let capture = AdmissionCapture::for_call(duty.snapshot().clone());
lean_ctx::core::context_admission::capture::ADMISSIONS
.sync_scope(Some(capture.clone()), || {
lean_ctx::core::context_admission::carrier::ReleaseGate::current().media(64)
})
.expect_err("withheld");
let delivery = receipt_store::trace::Delivery::mcp("ctx_read", duty.snapshot());
let record = receipt_store::record_delivery(
&capture,
&ReceiptSubject {
tool: "ctx_read",
agent_id: None,
presenter_ref: None,
project_root: "/project",
delivery: &delivery,
},
&Delivered {
text: "the source was withheld",
is_error: true,
tokens: 4,
},
&duty,
);
let ReceiptRecord::Stored { digest, .. } = &record else {
panic!("a withheld source is receipted: {record:?}");
};
let receipt_store::trace::StoredTrace::Bound { sidecar, .. } =
receipt_store::trace::load(digest)
else {
panic!("the mandatory receipt has its sidecar");
};
let named: Vec<_> = sidecar
.objects
.iter()
.map(|object| &object.source)
.collect();
assert_eq!(named, [&Some(receipt_store::trace::SourceRef::Withheld)]);
break_receipt_store();
let (text, is_error) = returned();
assert!(is_error, "{text}");
assert!(text.contains(receipt_store::NOT_PERSISTED_CODE), "{text}");
assert!(!text.contains("delivered_body"), "{text}");
let ((text, is_error), _) = returned_as(CONTENT, false);
assert!(is_error && !text.contains("delivered_body"), "{text}");
let notice = receipt_store::not_persisted_notice();
let (left, record) = returned_as(¬ice, false);
assert_eq!(left, (notice, false));
assert_eq!(
record,
ReceiptRecord::ContentFree(receipt_store::ContentFree::GatewayNotice)
);
}
#[tokio::test]
async fn the_prepared_bytes_of_an_mcp_result_are_the_whole_result() {
let _env = lean_ctx::core::data_dir::test_env_lock();
let _community = lean_ctx::core::policy::runtime::TestPolicyOverride::set(None);
let data = lean_ctx::core::data_dir::isolated_data_dir();
let config = lean_ctx::core::paths::config_dir_read_only().expect("config dir");
std::fs::create_dir_all(&config).expect("config dir");
std::fs::write(
config.join("config.toml"),
"[context_gateway]\nmode = \"governed\"\n",
)
.expect("config");
let project = data.path().join("project");
std::fs::create_dir_all(&project).expect("project dir");
let root = project.to_string_lossy().into_owned();
let server = LeanCtxServer::new_with_project_root(Some(&root));
let duty = receipt_store::Duty::at_entry();
let capture = AdmissionCapture::for_call(duty.snapshot().clone());
lean_ctx::core::context_admission::capture::ADMISSIONS
.sync_scope(Some(capture.clone()), || {
lean_ctx::core::context_admission::admit_context_source(CONTENT)
})
.expect("a clean source is admitted");
let mut result = CallToolResult::success(vec![rmcp::model::ContentBlock::text(CONTENT)]);
result.structured_content = Some(serde_json::json!({ "rows": ["beside the text"] }));
let left = server
.finish_gateway_receipt(capture, Ok(result.clone()), "ctx_read")
.await
.expect("delivered");
assert_eq!(left, result);
let (_, stored) = receipt_store::latest(&root, 1)
.into_iter()
.next()
.expect("receipted");
let stored = stored.expect("verified receipt");
let receipt_store::trace::StoredTrace::Bound { sidecar, .. } =
receipt_store::trace::load(&stored.digest)
else {
panic!("the mandatory receipt has its sidecar");
};
assert_ne!(
sidecar.release_prepared.bytes,
receipt_store::output_digest(CONTENT.as_bytes()),
"the structured content is bound, not only the text"
);
assert!(
matches!(
receipt_store::observed::load(&stored.digest),
receipt_store::observed::StoredObservation::Bound { .. }
),
"the whole result that left is the one prepared"
);
}
}