mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Always use streamed remote compaction for supported providers (#44255)
## What changed - Route manual and automatic remote compaction through the v2 implementation. - Retire the `remote_compaction_v2` feature toggle while continuing to advertise it in the model client beta features header. - Migrate compaction tests from `/responses/compact` to streamed `/responses` requests with `compaction_trigger` items and remove legacy parity coverage. ## Testing Add streamed compaction coverage for tool search output trimming and session base instruction token estimates. Update app-server tests to verify started/completed notifications for both local and streamed remote compaction. GitOrigin-RevId: cea392a6166a9b116ff83708fd9126d5546476e4
This commit is contained in:
1 parent
2617ed2e1c
commit
3dc1e2a584
25 files changed
+675
-5635
No files matched your search
@@ -1,7 +1,7 @@
|
||||
//! End-to-end compaction flow tests.
|
||||
//!
|
||||
//! Phases:
|
||||
//! 1) Arrange: mock responses/compact endpoints + config.
|
||||
//! 1) Arrange: mock Responses endpoints + config.
|
||||
//! 2) Act: start a thread and submit multiple turns to trigger auto-compaction.
|
||||
//! 3) Assert: verify item/started + item/completed notifications for context compaction.
|
||||
|
||||
@@ -30,14 +30,12 @@ use codex_app_server_protocol::TurnStartParams;
|
||||
use codex_app_server_protocol::TurnStartResponse;
|
||||
use codex_app_server_protocol::UserInput as V2UserInput;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_utils_absolute_path::test_support::PathExt;
|
||||
use core_test_support::responses;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use test_case::test_case;
|
||||
use tokio::time::timeout;
|
||||
|
||||
// macOS and Windows Bazel CI can spend tens of seconds starting app-server
|
||||
@@ -50,8 +48,16 @@ const AUTO_COMPACT_LIMIT: i64 = 1_000;
|
||||
const COMPACT_PROMPT: &str = "Summarize the conversation.";
|
||||
const INVALID_REQUEST_ERROR_CODE: i64 = -32600;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum CompactionRoute {
|
||||
Local,
|
||||
Remote,
|
||||
}
|
||||
|
||||
#[test_case(CompactionRoute::Local; "local")]
|
||||
#[test_case(CompactionRoute::Remote; "streamed remote")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn auto_compaction_local_emits_started_and_completed_items() -> Result<()> {
|
||||
async fn auto_compaction_emits_started_and_completed_items(route: CompactionRoute) -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
@@ -63,99 +69,39 @@ async fn auto_compaction_local_emits_started_and_completed_items() -> Result<()>
|
||||
responses::ev_assistant_message("m2", "SECOND_REPLY"),
|
||||
responses::ev_completed_with_tokens("r2", /*total_tokens*/ 330_000),
|
||||
]);
|
||||
let summary = match route {
|
||||
CompactionRoute::Local => responses::ev_assistant_message("m3", "LOCAL_SUMMARY"),
|
||||
CompactionRoute::Remote => serde_json::json!({
|
||||
"type": "response.output_item.done",
|
||||
"item": {
|
||||
"type": "compaction",
|
||||
"encrypted_content": "ENCRYPTED_COMPACTION_SUMMARY",
|
||||
},
|
||||
}),
|
||||
};
|
||||
let sse3 = responses::sse(vec![
|
||||
responses::ev_assistant_message("m3", "LOCAL_SUMMARY"),
|
||||
summary,
|
||||
responses::ev_completed_with_tokens("r3", /*total_tokens*/ 200),
|
||||
]);
|
||||
let sse4 = responses::sse(vec![
|
||||
responses::ev_assistant_message("m4", "FINAL_REPLY"),
|
||||
responses::ev_completed_with_tokens("r4", /*total_tokens*/ 120),
|
||||
]);
|
||||
responses::mount_sse_sequence(&server, vec![sse1, sse2, sse3, sse4]).await;
|
||||
let requests = responses::mount_sse_sequence(&server, vec![sse1, sse2, sse3, sse4]).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
compaction_config(&server.uri(), AUTO_COMPACT_LIMIT).write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
.build_initialized_with_timeout(DEFAULT_READ_TIMEOUT)
|
||||
.await?;
|
||||
|
||||
let thread_id = start_thread(&mut mcp).await?;
|
||||
for message in ["first", "second", "third"] {
|
||||
send_turn_and_wait(&mut mcp, &thread_id, message).await?;
|
||||
let mut config = compaction_config(&server.uri(), /*auto_compact_limit*/ 200_000);
|
||||
if let CompactionRoute::Remote = route {
|
||||
config = config
|
||||
.with_provider_name("OpenAI")
|
||||
.with_provider_config("requires_openai_auth = true");
|
||||
write_chatgpt_auth(
|
||||
codex_home.path(),
|
||||
ChatGptAuthFixture::new("access-chatgpt").plan_type("pro"),
|
||||
AuthCredentialsStoreMode::File,
|
||||
)?;
|
||||
}
|
||||
|
||||
let started = wait_for_context_compaction_started(&mut mcp).await?;
|
||||
let completed = wait_for_context_compaction_completed(&mut mcp).await?;
|
||||
|
||||
let ThreadItem::ContextCompaction { id: started_id } = started.item else {
|
||||
unreachable!("started item should be context compaction");
|
||||
};
|
||||
let ThreadItem::ContextCompaction { id: completed_id } = completed.item else {
|
||||
unreachable!("completed item should be context compaction");
|
||||
};
|
||||
|
||||
assert_eq!(started.thread_id, thread_id);
|
||||
assert_eq!(completed.thread_id, thread_id);
|
||||
assert_eq!(started_id, completed_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn auto_compaction_remote_emits_started_and_completed_items() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
const REMOTE_AUTO_COMPACT_LIMIT: i64 = 200_000;
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let sse1 = responses::sse(vec![
|
||||
responses::ev_assistant_message("m1", "FIRST_REPLY"),
|
||||
responses::ev_completed_with_tokens("r1", /*total_tokens*/ 70_000),
|
||||
]);
|
||||
let sse2 = responses::sse(vec![
|
||||
responses::ev_assistant_message("m2", "SECOND_REPLY"),
|
||||
responses::ev_completed_with_tokens("r2", /*total_tokens*/ 330_000),
|
||||
]);
|
||||
let sse3 = responses::sse(vec![
|
||||
responses::ev_assistant_message("m3", "FINAL_REPLY"),
|
||||
responses::ev_completed_with_tokens("r3", /*total_tokens*/ 120),
|
||||
]);
|
||||
let responses_log = responses::mount_sse_sequence(&server, vec![sse1, sse2, sse3]).await;
|
||||
|
||||
let compacted_history = vec![
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: "assistant".to_string(),
|
||||
content: vec![ContentItem::OutputText {
|
||||
text: "REMOTE_COMPACT_SUMMARY".to_string(),
|
||||
}],
|
||||
phase: None,
|
||||
internal_chat_message_metadata_passthrough: None,
|
||||
},
|
||||
ResponseItem::Compaction {
|
||||
id: None,
|
||||
encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(),
|
||||
internal_chat_message_metadata_passthrough: None,
|
||||
},
|
||||
];
|
||||
let compact_mock = responses::mount_compact_json_once(
|
||||
&server,
|
||||
serde_json::json!({ "output": compacted_history }),
|
||||
)
|
||||
.await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
compaction_config(&server.uri(), REMOTE_AUTO_COMPACT_LIMIT)
|
||||
.disable_feature(Feature::RemoteCompactionV2)
|
||||
.with_provider_name("OpenAI")
|
||||
.with_provider_config("requires_openai_auth = true")
|
||||
.write(codex_home.path())?;
|
||||
write_chatgpt_auth(
|
||||
codex_home.path(),
|
||||
ChatGptAuthFixture::new("access-chatgpt").plan_type("pro"),
|
||||
AuthCredentialsStoreMode::File,
|
||||
)?;
|
||||
config.write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -182,65 +128,31 @@ async fn auto_compaction_remote_emits_started_and_completed_items() -> Result<()
|
||||
assert_eq!(completed.thread_id, thread_id);
|
||||
assert_eq!(started_id, completed_id);
|
||||
|
||||
let compact_requests = compact_mock.requests();
|
||||
assert_eq!(compact_requests.len(), 1);
|
||||
assert_eq!(compact_requests[0].path(), "/v1/responses/compact");
|
||||
|
||||
let response_requests = responses_log.requests();
|
||||
assert_eq!(response_requests.len(), 3);
|
||||
let turn_metadata = response_requests
|
||||
.iter()
|
||||
.map(|request| {
|
||||
request
|
||||
.header("x-codex-turn-metadata")
|
||||
.as_deref()
|
||||
.map(parse_json_header)
|
||||
.expect("turn request should include turn metadata")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for (request, metadata) in response_requests.iter().zip(&turn_metadata) {
|
||||
assert_eq!(metadata["request_kind"].as_str(), Some("turn"));
|
||||
assert!(
|
||||
metadata["turn_id"]
|
||||
.as_str()
|
||||
.is_some_and(|turn_id| !turn_id.is_empty()),
|
||||
"turn request should carry a non-empty turn id"
|
||||
);
|
||||
assert_eq!(
|
||||
metadata["window_id"].as_str(),
|
||||
request.header("x-codex-window-id").as_deref()
|
||||
);
|
||||
assert!(metadata.get("compaction").is_none());
|
||||
let requests = requests.requests();
|
||||
assert_eq!(requests.len(), 4);
|
||||
let compact_request = &requests[2];
|
||||
assert_eq!(compact_request.path(), "/v1/responses");
|
||||
match route {
|
||||
CompactionRoute::Local => {
|
||||
assert!(
|
||||
compact_request
|
||||
.inputs_of_type("compaction_trigger")
|
||||
.is_empty()
|
||||
);
|
||||
assert!(compact_request.body_contains_text(COMPACT_PROMPT));
|
||||
}
|
||||
CompactionRoute::Remote => {
|
||||
assert_eq!(
|
||||
compact_request.inputs_of_type("compaction_trigger").len(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
requests[3].inputs_of_type("compaction")[0]["encrypted_content"],
|
||||
"ENCRYPTED_COMPACTION_SUMMARY"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let compact_metadata = compact_requests[0]
|
||||
.header("x-codex-turn-metadata")
|
||||
.as_deref()
|
||||
.map(parse_json_header)
|
||||
.expect("compact request should include turn metadata");
|
||||
assert_eq!(
|
||||
compact_metadata["request_kind"].as_str(),
|
||||
Some("compaction")
|
||||
);
|
||||
assert_eq!(
|
||||
compact_metadata["compaction"],
|
||||
serde_json::json!({
|
||||
"trigger": "auto",
|
||||
"reason": "context_limit",
|
||||
"implementation": "responses_compact",
|
||||
"phase": "pre_turn",
|
||||
"strategy": "memento",
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
compact_metadata["turn_id"], turn_metadata[2]["turn_id"],
|
||||
"pre-turn compaction should carry the current turn id"
|
||||
);
|
||||
assert_eq!(
|
||||
compact_metadata["window_id"].as_str(),
|
||||
compact_requests[0].header("x-codex-window-id").as_deref()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -522,10 +434,6 @@ async fn wait_for_context_compaction_completed(
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_json_header(value: &str) -> serde_json::Value {
|
||||
serde_json::from_str(value).expect("turn metadata should be JSON")
|
||||
}
|
||||
|
||||
fn compaction_config(server_uri: &str, auto_compact_limit: i64) -> MockResponsesConfig {
|
||||
MockResponsesConfig::new(server_uri)
|
||||
.with_root_config(&format!(
|
||||
|
||||
@@ -385,7 +385,26 @@ async fn parent_response(
|
||||
State(state): State<Arc<MockResponsesState>>,
|
||||
Json(request): Json<Value>,
|
||||
) -> impl IntoResponse {
|
||||
let events = if request["model"] == "gpt-5.6-luna" {
|
||||
let events = if request["input"].as_array().is_some_and(|input| {
|
||||
input
|
||||
.last()
|
||||
.is_some_and(|item| item["type"] == "compaction_trigger")
|
||||
}) {
|
||||
assert!(state.compact_root_after_answer);
|
||||
assert!(request.to_string().contains("guardian-user-input"));
|
||||
vec![
|
||||
responses::ev_response_created("root-compaction"),
|
||||
json!({
|
||||
"type": "response.output_item.done",
|
||||
"item": {
|
||||
"type": "compaction",
|
||||
"id": "cmp_root",
|
||||
"encrypted_content": "opaque root summary",
|
||||
},
|
||||
}),
|
||||
responses::ev_completed("root-compaction"),
|
||||
]
|
||||
} else if request["model"] == "gpt-5.6-luna" {
|
||||
luna_response(&state, request).await
|
||||
} else if request
|
||||
.pointer("/client_metadata/x-openai-subagent")
|
||||
@@ -712,30 +731,53 @@ async fn guardian_v2_routes_scoped_tool_approvals(
|
||||
let responses_url = format!("http://{}", listener.local_addr()?);
|
||||
let router = Router::new()
|
||||
.route("/v1/responses", get(luna_websocket).post(parent_response))
|
||||
.route("/v1/responses/compact", post(|Json(request): Json<Value>| async move {
|
||||
assert!(request.to_string().contains("guardian-user-input"));
|
||||
Json(json!({"output": [{"type": "compaction", "id": "cmp_root", "encrypted_content": "opaque root summary"}]}))
|
||||
}))
|
||||
.route(
|
||||
"/metrics",
|
||||
post(
|
||||
|State(state): State<Arc<MockResponsesState>>, body: String| async move {
|
||||
if matches!(state.transcript_content, TranscriptContent::MixedEvidence) {
|
||||
let payload: Value = serde_json::from_str(&body).expect("OTLP JSON");
|
||||
for metric in payload["resourceMetrics"].as_array().into_iter().flatten()
|
||||
.flat_map(|resource| resource["scopeMetrics"].as_array().into_iter().flatten())
|
||||
for metric in payload["resourceMetrics"]
|
||||
.as_array()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.flat_map(|resource| {
|
||||
resource["scopeMetrics"].as_array().into_iter().flatten()
|
||||
})
|
||||
.flat_map(|scope| scope["metrics"].as_array().into_iter().flatten())
|
||||
.filter(|metric| matches!(metric["name"].as_str(), Some("codex.guardian.context.request_tokens" | "codex.guardian.context.section_cost")))
|
||||
.filter(|metric| {
|
||||
matches!(
|
||||
metric["name"].as_str(),
|
||||
Some(
|
||||
"codex.guardian.context.request_tokens"
|
||||
| "codex.guardian.context.section_cost"
|
||||
)
|
||||
)
|
||||
})
|
||||
{
|
||||
let name = metric["name"].as_str().expect("context metric name");
|
||||
for point in metric["histogram"]["dataPoints"].as_array().into_iter().flatten() {
|
||||
let attributes = point["attributes"].as_array().expect("metric attributes");
|
||||
for point in metric["histogram"]["dataPoints"]
|
||||
.as_array()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
let attributes =
|
||||
point["attributes"].as_array().expect("metric attributes");
|
||||
for target in ["sync", "async"] {
|
||||
if attributes.iter().any(|attr| attr["key"] == "target" && attr["value"]["stringValue"] == target) {
|
||||
let mut bounds = state.context_metric_bounds.lock().expect("context metric bounds");
|
||||
if attributes.iter().any(|attr| {
|
||||
attr["key"] == "target"
|
||||
&& attr["value"]["stringValue"] == target
|
||||
}) {
|
||||
let mut bounds = state
|
||||
.context_metric_bounds
|
||||
.lock()
|
||||
.expect("context metric bounds");
|
||||
bounds.insert(
|
||||
(name.to_owned(), target.to_owned()),
|
||||
point["explicitBounds"].as_array().and_then(|bounds| bounds.last()).and_then(Value::as_f64),
|
||||
point["explicitBounds"]
|
||||
.as_array()
|
||||
.and_then(|bounds| bounds.last())
|
||||
.and_then(Value::as_f64),
|
||||
);
|
||||
if bounds.len() == 4 {
|
||||
state.context_metrics_recorded.notify_one();
|
||||
@@ -852,7 +894,6 @@ async fn guardian_v2_routes_scoped_tool_approvals(
|
||||
if matches!(lifecycle, ThreadLifecycle::RootUserInputCompaction) {
|
||||
mock_config = mock_config
|
||||
.with_provider_name("OpenAI")
|
||||
.disable_feature(Feature::RemoteCompactionV2)
|
||||
.disable_feature(Feature::TokenBudget)
|
||||
.disable_feature(Feature::EnableRequestCompression);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ use axum::Router;
|
||||
use axum::extract::State;
|
||||
use axum::http::header;
|
||||
use axum::routing::get;
|
||||
use axum::routing::post;
|
||||
use codex_app_server_protocol::ApprovalsReviewer;
|
||||
use codex_app_server_protocol::AskForApproval;
|
||||
use codex_app_server_protocol::GuardianApprovalReview;
|
||||
@@ -184,12 +183,33 @@ async fn guardians_retain_evidence_after_compaction_and_discard_it_after_rollbac
|
||||
get(luna_websocket).post({
|
||||
let parent_requests = Arc::clone(&parent_requests);
|
||||
let review_requests = Arc::clone(&review_requests);
|
||||
let compact_requests = Arc::clone(&compact_requests);
|
||||
let checkpoint = checkpoint.clone();
|
||||
move |State(classifier): State<Arc<MockResponsesState>>,
|
||||
Json(request): Json<Value>| {
|
||||
let parent_requests = Arc::clone(&parent_requests);
|
||||
let review_requests = Arc::clone(&review_requests);
|
||||
let compact_requests = Arc::clone(&compact_requests);
|
||||
let checkpoint = checkpoint.clone();
|
||||
async move {
|
||||
let events = if request["model"] == "gpt-5.6-luna" {
|
||||
let events = if request["input"].as_array().is_some_and(|input| {
|
||||
input
|
||||
.iter()
|
||||
.any(|item| item["type"] == "compaction_trigger")
|
||||
}) {
|
||||
compact_requests
|
||||
.lock()
|
||||
.expect("request log lock")
|
||||
.push(request);
|
||||
vec![
|
||||
responses::ev_assistant_message("summary", SUMMARY),
|
||||
json!({
|
||||
"type": "response.output_item.done",
|
||||
"item": checkpoint,
|
||||
}),
|
||||
responses::ev_completed("compact"),
|
||||
]
|
||||
} else if request["model"] == "gpt-5.6-luna" {
|
||||
luna_response(&classifier, request).await
|
||||
} else if request["client_metadata"]["x-openai-subagent"] == "guardian" {
|
||||
review_requests
|
||||
@@ -243,29 +263,6 @@ async fn guardians_retain_evidence_after_compaction_and_discard_it_after_rollbac
|
||||
}
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
"/v1/responses/compact",
|
||||
post({
|
||||
let compact_requests = Arc::clone(&compact_requests);
|
||||
let checkpoint = checkpoint.clone();
|
||||
move |Json(request): Json<Value>| {
|
||||
let compact_requests = Arc::clone(&compact_requests);
|
||||
let checkpoint = checkpoint.clone();
|
||||
async move {
|
||||
compact_requests
|
||||
.lock()
|
||||
.expect("request log lock")
|
||||
.push(request);
|
||||
Json(json!({"output": [
|
||||
{"type": "message", "role": "assistant", "content": [
|
||||
{"type": "output_text", "text": SUMMARY}
|
||||
]},
|
||||
checkpoint
|
||||
]}))
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
.with_state(Arc::clone(&classifier));
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await?;
|
||||
let responses_url = format!("http://{}", listener.local_addr()?);
|
||||
@@ -288,7 +285,7 @@ async fn guardians_retain_evidence_after_compaction_and_discard_it_after_rollbac
|
||||
.enable_feature(Feature::GuardianApproval)
|
||||
.enable_feature(Feature::GuardianReuseParentCompaction)
|
||||
.disable_feature(Feature::EnableRequestCompression)
|
||||
.disable_feature(Feature::RemoteCompactionV2)
|
||||
.enable_feature(Feature::RemoteCompactionV2)
|
||||
.disable_feature(Feature::TokenBudget)
|
||||
.with_extra_config(&format!(
|
||||
"[mcp_servers.{TEST_SERVER_NAME}]\nurl = \"{mcp_url}/mcp\"\ndefault_tools_approval_mode = \"prompt\"\n\n[features.guardianv2]\nenabled = true\nthread_context = {thread_context_enabled}\npersist_scores = true\nreuse_parent_compaction = {reuse_parent_compaction}\n\n[features.guardianv2.review_scope]\ncomputer_use_only = false"
|
||||
@@ -616,9 +613,16 @@ async fn guardians_retain_evidence_after_compaction_and_discard_it_after_rollbac
|
||||
let output = output["output"].as_str().expect("tool output text");
|
||||
assert!(output.contains(&expected_output), "{output}");
|
||||
} else {
|
||||
let parent_input = serde_json::to_string(&parent[index * 2 + 1]["input"])?;
|
||||
assert!(!parent_input.contains(RESTRICTION));
|
||||
let parent_items = parent[index * 2 + 1]["input"]
|
||||
.as_array()
|
||||
.expect("request input array");
|
||||
let parent_input = serde_json::to_string(parent_items)?;
|
||||
// V2 keeps bounded user history while replacing old tool output with a checkpoint.
|
||||
assert_eq!(parent_input.contains(RESTRICTION), index <= 3);
|
||||
assert!(!parent_input.contains(EVIDENCE));
|
||||
assert!(!parent_items.iter().any(|item| {
|
||||
item["type"] == "function_call_output" && item["call_id"] == "inspect-1"
|
||||
}));
|
||||
if index <= 3 {
|
||||
assert!(sync_text.contains(RESTRICTION));
|
||||
if matches!(context_path, ContextPath::ThreadOwned) {
|
||||
@@ -652,7 +656,7 @@ async fn guardians_retain_evidence_after_compaction_and_discard_it_after_rollbac
|
||||
compact_output.contains(&expected_output),
|
||||
"{compact_output}"
|
||||
);
|
||||
assert!(parent_input.contains(SUMMARY));
|
||||
assert!(parent_items.contains(&checkpoint));
|
||||
if matches!(context_path, ContextPath::ThreadOwned) {
|
||||
assert!(
|
||||
content.contains(RESTRICTION),
|
||||
@@ -662,7 +666,8 @@ async fn guardians_retain_evidence_after_compaction_and_discard_it_after_rollbac
|
||||
!transcript.contains(&expected_output),
|
||||
"raw tool result must not survive the parent checkpoint"
|
||||
);
|
||||
assert!(transcript.contains(SUMMARY));
|
||||
assert!(transcript.contains(RESTRICTION));
|
||||
assert!(!transcript.contains(SUMMARY));
|
||||
} else {
|
||||
assert!(
|
||||
transcript.contains(RESTRICTION),
|
||||
|
||||
Reference in new issue
Block a user