#![allow(clippy::panic, clippy::unwrap_used, clippy::expect_used)]
use chrono::Utc;
use meerkat_core::lifecycle::{InputId, RunId};
use meerkat_core::types::SessionId;
use meerkat_runtime::{
ContinuationInput, EphemeralRuntimeDriver, Input, InputDurability, InputHeader,
InputLifecycleEvent, InputLifecycleState, InputOrigin, InputVisibility, LogicalRuntimeId,
MeerkatMachine, PeerConvention, PeerInput, PostAdmissionSignal, PromptInput,
ResponseProgressPhase, ResponseTerminalStatus, RuntimeControlPlane, RuntimeDriver,
RuntimeDriverError, RuntimeEvent, RuntimeState, SessionServiceRuntimeExt,
classify_runtime_lifecycle_state,
};
fn make_prompt_input(text: &str) -> Input {
Input::Prompt(PromptInput {
injected_context: Vec::new(),
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Operator,
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
content: text.into(),
typed_turn_appends: Vec::new(),
turn_metadata: None,
})
}
#[allow(dead_code)]
fn make_prompt_input_with_handling_mode(
text: &str,
handling_mode: meerkat_core::types::HandlingMode,
) -> Input {
Input::Prompt(PromptInput {
injected_context: Vec::new(),
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Operator,
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
content: text.into(),
typed_turn_appends: Vec::new(),
turn_metadata: Some(
meerkat_core::lifecycle::run_primitive::RuntimeTurnMetadata {
handling_mode: Some(handling_mode),
..Default::default()
},
),
})
}
fn runtime_state_is_terminal_by_authority(state: RuntimeState) -> bool {
match classify_runtime_lifecycle_state(state) {
Ok(facts) => facts.is_terminal(),
Err(error) => panic!("generated runtime lifecycle classification failed: {error}"),
}
}
fn make_peer_terminal(body: &str) -> Input {
Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "550e8400-e29b-41d4-a716-446655440000".into(),
display_identity: Some("Peer 1".into()),
runtime_id: None,
},
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::ResponseTerminal {
request_id: "018f6f79-7a82-7c4e-a552-a3b86f9630f1".into(),
status: ResponseTerminalStatus::Completed,
}),
content: body.into(),
payload: Some(serde_json::json!({"body": body})),
handling_mode: None,
})
}
fn make_peer_progress() -> Input {
Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "550e8400-e29b-41d4-a716-446655440000".into(),
display_identity: Some("Peer 1".into()),
runtime_id: None,
},
durability: InputDurability::Ephemeral,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::ResponseProgress {
request_id: "req-1".into(),
phase: ResponseProgressPhase::InProgress,
}),
content: "working...".into(),
payload: Some(serde_json::json!({"progress": "working"})),
handling_mode: None,
})
}
fn make_continuation() -> Input {
Input::Continuation(ContinuationInput::detached_background_op_completed())
}
fn assert_queue_projection_alignment(driver: &EphemeralRuntimeDriver) {
assert_eq!(driver.queue().input_ids(), driver.queue_lane().as_slice());
assert_eq!(
driver.steer_queue().input_ids(),
driver.steer_lane().as_slice()
);
}
fn bind_running(driver: &mut EphemeralRuntimeDriver, run_id: RunId, pre_run_phase: RuntimeState) {
assert_eq!(driver.runtime_state(), pre_run_phase);
driver.contract_begin_run_authority(run_id).unwrap();
assert_eq!(driver.runtime_state(), RuntimeState::Running);
assert_eq!(driver.pre_run_phase(), Some(pre_run_phase));
}
async fn registered_machine() -> (MeerkatMachine, SessionId, LogicalRuntimeId) {
let machine = MeerkatMachine::ephemeral();
let session_id = SessionId::new();
let runtime_id = LogicalRuntimeId::for_session(&session_id);
machine
.register_session(session_id.clone())
.await
.expect("register session");
(machine, session_id, runtime_id)
}
async fn accept_on_machine(
machine: &MeerkatMachine,
session_id: &SessionId,
input: Input,
) -> InputId {
let input_id = input.id().clone();
let outcome = SessionServiceRuntimeExt::accept_input(machine, session_id, input)
.await
.unwrap();
assert!(outcome.is_accepted());
input_id
}
#[tokio::test]
async fn accept_prompt_idle_queues_and_wakes() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = make_prompt_input("hello");
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_accepted());
assert_eq!(
driver.take_post_admission_signal(),
PostAdmissionSignal::WakeLoop
);
assert_eq!(driver.queue().len(), 1);
assert_queue_projection_alignment(&driver);
}
#[tokio::test]
async fn accept_prompt_running_queues_and_wakes() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
bind_running(&mut driver, RunId::new(), RuntimeState::Idle);
let input = make_prompt_input("hello");
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_accepted());
assert!(!driver.take_wake_requested());
}
#[tokio::test]
async fn accept_peer_terminal_idle_wakes() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = make_peer_terminal("done");
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_accepted());
assert_eq!(
driver.take_post_admission_signal(),
PostAdmissionSignal::WakeLoop
);
}
#[tokio::test]
async fn accept_peer_terminal_running_queues_wake_for_next_idle() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
bind_running(&mut driver, RunId::new(), RuntimeState::Idle);
let input = make_peer_terminal("done");
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_accepted());
assert!(driver.take_wake_requested());
}
#[tokio::test]
async fn accept_progress_policy_no_wake_but_idle_admission_wakes() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = make_peer_progress();
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_accepted());
let signal = driver.take_post_admission_signal();
assert_eq!(
signal,
PostAdmissionSignal::WakeLoop,
"ResponseProgress should stage on the checkpoint lane and use the generated idle admission wake"
);
assert!(signal.should_wake());
}
#[tokio::test]
async fn accept_continuation_idle_wakes_and_requests_processing() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = make_continuation();
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_accepted());
assert_eq!(
driver.take_post_admission_signal(),
PostAdmissionSignal::RequestImmediateProcessing
);
assert_eq!(driver.steer_queue().len(), 1);
assert_queue_projection_alignment(&driver);
}
#[tokio::test]
async fn dedup_by_idempotency() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let key = meerkat_runtime::identifiers::IdempotencyKey::new("req-1");
let mut input1 = make_prompt_input("hello");
if let Input::Prompt(ref mut p) = input1 {
p.header.idempotency_key = Some(key.clone());
}
let result1 = driver.accept_input(input1).await.unwrap();
assert!(result1.is_accepted());
let mut input2 = make_prompt_input("hello again");
if let Input::Prompt(ref mut p) = input2 {
p.header.idempotency_key = Some(key);
}
let result2 = driver.accept_input(input2).await.unwrap();
assert!(result2.is_deduplicated());
}
#[tokio::test]
async fn reject_derived_prompt() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = Input::Prompt(PromptInput {
injected_context: Vec::new(),
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::System,
durability: InputDurability::Derived,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
content: "hi".into(),
typed_turn_appends: Vec::new(),
turn_metadata: None,
});
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_rejected());
}
#[tokio::test]
async fn retire_without_attached_loop_abandons_queued_work() {
let (machine, session_id, _runtime_id) = registered_machine().await;
accept_on_machine(&machine, &session_id, make_prompt_input("a")).await;
accept_on_machine(&machine, &session_id, make_prompt_input("b")).await;
let report = SessionServiceRuntimeExt::retire_runtime(&machine, &session_id)
.await
.unwrap();
assert_eq!(report.inputs_abandoned, 2);
assert_eq!(report.inputs_pending_drain, 0);
assert_eq!(
SessionServiceRuntimeExt::runtime_state(&machine, &session_id)
.await
.unwrap(),
RuntimeState::Retired
);
assert!(
SessionServiceRuntimeExt::list_active_inputs(&machine, &session_id)
.await
.unwrap()
.is_empty()
);
}
#[tokio::test]
async fn reset_abandons_and_drains() {
let (machine, session_id, _runtime_id) = registered_machine().await;
accept_on_machine(&machine, &session_id, make_prompt_input("a")).await;
let report = SessionServiceRuntimeExt::reset_runtime(&machine, &session_id)
.await
.unwrap();
assert_eq!(report.inputs_abandoned, 1);
assert!(
SessionServiceRuntimeExt::list_active_inputs(&machine, &session_id)
.await
.unwrap()
.is_empty()
);
}
#[tokio::test]
async fn destroy_transitions_to_terminal() {
let (machine, session_id, runtime_id) = registered_machine().await;
accept_on_machine(&machine, &session_id, make_prompt_input("a")).await;
let report = RuntimeControlPlane::destroy(&machine, &runtime_id)
.await
.unwrap();
assert_eq!(report.inputs_abandoned, 1);
let state = RuntimeControlPlane::runtime_state(&machine, &runtime_id)
.await
.unwrap();
assert!(runtime_state_is_terminal_by_authority(state));
}
#[tokio::test]
async fn reset_after_retire_returns_runtime_to_idle() {
let (machine, session_id, _runtime_id) = registered_machine().await;
SessionServiceRuntimeExt::retire_runtime(&machine, &session_id)
.await
.unwrap();
assert_eq!(
SessionServiceRuntimeExt::runtime_state(&machine, &session_id)
.await
.unwrap(),
RuntimeState::Retired
);
let report = SessionServiceRuntimeExt::reset_runtime(&machine, &session_id)
.await
.unwrap();
assert_eq!(report.inputs_abandoned, 0);
assert_eq!(
SessionServiceRuntimeExt::runtime_state(&machine, &session_id)
.await
.unwrap(),
RuntimeState::Idle
);
let accepted =
SessionServiceRuntimeExt::accept_input(&machine, &session_id, make_prompt_input("hello"))
.await
.unwrap();
assert!(
accepted.is_accepted(),
"reset runtime should accept new input"
);
}
#[tokio::test]
async fn recovery_counts_queued_as_recovered() -> Result<(), RuntimeDriverError> {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = make_prompt_input("hello");
let input_id = input.id().clone();
driver.accept_input(input).await.unwrap();
assert!(driver.input_state(&input_id).is_some());
assert_eq!(
driver.input_phase(&input_id),
Some(InputLifecycleState::Queued)
);
driver.clear_queue_projections();
let report = driver.recover_ephemeral()?;
assert_eq!(report.inputs_recovered, 1);
assert_eq!(report.inputs_requeued, 0); assert_eq!(driver.queue().input_ids(), vec![input_id]);
assert_queue_projection_alignment(&driver);
Ok(())
}
#[tokio::test]
async fn retired_rejects_input() {
let (machine, session_id, _runtime_id) = registered_machine().await;
SessionServiceRuntimeExt::retire_runtime(&machine, &session_id)
.await
.unwrap();
let result =
SessionServiceRuntimeExt::accept_input(&machine, &session_id, make_prompt_input("hello"))
.await;
assert!(result.is_err());
}
#[tokio::test]
async fn events_emitted_for_lifecycle() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
driver
.accept_input(make_prompt_input("hello"))
.await
.unwrap();
let events = driver.drain_events();
assert!(!events.is_empty());
let has_accepted = events.iter().any(|e| {
matches!(
&e.event,
RuntimeEvent::InputLifecycle(InputLifecycleEvent::Accepted { .. })
)
});
let has_queued = events.iter().any(|e| {
matches!(
&e.event,
RuntimeEvent::InputLifecycle(InputLifecycleEvent::Queued { .. })
)
});
assert!(has_accepted);
assert!(has_queued);
}
#[tokio::test]
async fn progress_peer_staged_boundary() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = make_peer_progress();
let input_id = input.id().clone();
let result = driver.accept_input(input).await.unwrap();
assert!(result.is_accepted());
assert!(driver.input_state(&input_id).is_some());
assert_eq!(
driver.input_phase(&input_id),
Some(InputLifecycleState::Queued)
);
let signal = driver.take_post_admission_signal();
assert_eq!(
signal,
PostAdmissionSignal::WakeLoop,
"ResponseProgress policy remains passive while generated idle admission wakes the loop"
);
assert!(signal.should_wake());
}
#[tokio::test]
async fn destroy_after_retire_succeeds() {
let (machine, session_id, runtime_id) = registered_machine().await;
SessionServiceRuntimeExt::retire_runtime(&machine, &session_id)
.await
.unwrap();
let report = RuntimeControlPlane::destroy(&machine, &runtime_id)
.await
.unwrap();
assert_eq!(report.inputs_abandoned, 0);
assert_eq!(
RuntimeControlPlane::runtime_state(&machine, &runtime_id)
.await
.unwrap(),
RuntimeState::Destroyed
);
}
#[tokio::test]
async fn retired_rejects_new_input_after_machine_retire() {
let (machine, session_id, _runtime_id) = registered_machine().await;
accept_on_machine(&machine, &session_id, make_prompt_input("existing")).await;
SessionServiceRuntimeExt::retire_runtime(&machine, &session_id)
.await
.unwrap();
let result = SessionServiceRuntimeExt::accept_input(
&machine,
&session_id,
make_prompt_input("rejected"),
)
.await;
assert!(result.is_err());
assert!(
SessionServiceRuntimeExt::list_active_inputs(&machine, &session_id)
.await
.unwrap()
.is_empty()
);
}
#[tokio::test]
async fn reset_rejected_while_running() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
driver
.accept_input(make_prompt_input("hello"))
.await
.unwrap();
bind_running(&mut driver, RunId::new(), RuntimeState::Idle);
assert_eq!(driver.runtime_state(), RuntimeState::Running);
}
#[tokio::test]
async fn stop_abandons_all_active_inputs() {
let (machine, session_id, _runtime_id) = registered_machine().await;
let input = make_prompt_input("stop me");
let input_id = input.id().clone();
accept_on_machine(&machine, &session_id, input).await;
machine
.stop_runtime_executor(&session_id, "driver ephemeral stop contract")
.await
.unwrap();
assert_eq!(
SessionServiceRuntimeExt::runtime_state(&machine, &session_id)
.await
.unwrap(),
RuntimeState::Stopped
);
assert!(
SessionServiceRuntimeExt::list_active_inputs(&machine, &session_id)
.await
.unwrap()
.is_empty()
);
let stored = SessionServiceRuntimeExt::input_state(&machine, &session_id, &input_id)
.await
.unwrap()
.unwrap();
assert!(
stored.seed.terminal_outcome.is_some(),
"seed must carry the DSL-owned terminal outcome"
);
}
#[tokio::test]
async fn destroy_with_queued_inputs_abandons_all() {
let (machine, session_id, runtime_id) = registered_machine().await;
accept_on_machine(&machine, &session_id, make_prompt_input("a")).await;
accept_on_machine(&machine, &session_id, make_prompt_input("b")).await;
let report = RuntimeControlPlane::destroy(&machine, &runtime_id)
.await
.unwrap();
assert_eq!(report.inputs_abandoned, 2);
let state = RuntimeControlPlane::runtime_state(&machine, &runtime_id)
.await
.unwrap();
assert!(runtime_state_is_terminal_by_authority(state));
assert!(
SessionServiceRuntimeExt::list_active_inputs(&machine, &session_id)
.await
.unwrap()
.is_empty()
);
}
#[tokio::test]
async fn accept_peer_response_progress_with_handling_mode_returns_rejected() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "550e8400-e29b-41d4-a716-446655440000".into(),
display_identity: Some("Peer 1".into()),
runtime_id: None,
},
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::ResponseProgress {
request_id: "req-1".into(),
phase: ResponseProgressPhase::InProgress,
}),
content: "working".into(),
payload: Some(serde_json::json!({"progress": "working"})),
handling_mode: Some(meerkat_core::types::HandlingMode::Queue),
});
let outcome = driver.accept_input(input).await.unwrap();
assert!(
outcome.is_rejected(),
"ResponseProgress with handling_mode must be rejected"
);
}
#[tokio::test]
async fn accept_peer_response_terminal_with_handling_mode_returns_accepted() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "550e8400-e29b-41d4-a716-446655440000".into(),
display_identity: Some("Peer 1".into()),
runtime_id: None,
},
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::ResponseTerminal {
request_id: "018f6f79-7a82-7c4e-a552-a3b86f9630f1".into(),
status: ResponseTerminalStatus::Completed,
}),
content: "done".into(),
payload: Some(serde_json::json!({"ok": true})),
handling_mode: Some(meerkat_core::types::HandlingMode::Steer),
});
let outcome = driver.accept_input(input).await.unwrap();
assert!(
outcome.is_accepted(),
"ResponseTerminal with handling_mode=Steer must be accepted"
);
}
#[tokio::test]
async fn accept_peer_response_terminal_defers_context_projection_to_machine_batch()
-> Result<(), String> {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = make_peer_terminal("done");
let outcome = driver.accept_input(input).await.unwrap();
let meerkat_runtime::AcceptOutcome::Accepted { input_id, .. } = outcome else {
return Err("expected terminal peer response to be accepted".to_string());
};
let projection = driver
.admitted_primitive_projection(&input_id)
.ok_or_else(|| "accepted input should have primitive projection".to_string())?;
assert!(
projection.append.is_some(),
"terminal peer response must carry its typed comms notice append so the mandatory \
requester reaction turn has model-visible content"
);
assert!(
projection.context_append.is_none(),
"terminal peer response context must be projected by the machine-selected runtime batch"
);
Ok(())
}
#[tokio::test]
async fn accept_peer_response_terminal_with_empty_request_id_returns_rejected() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "550e8400-e29b-41d4-a716-446655440000".into(),
display_identity: Some("Peer 1".into()),
runtime_id: None,
},
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::ResponseTerminal {
request_id: " ".into(),
status: ResponseTerminalStatus::Completed,
}),
content: "done".into(),
payload: Some(serde_json::json!({"ok": true})),
handling_mode: None,
});
let outcome = driver.accept_input(input).await.unwrap();
assert!(
outcome.is_rejected(),
"ResponseTerminal with empty request_id must fail closed at admission"
);
}
#[tokio::test]
async fn accept_peer_message_with_steer_handling_mode_returns_accepted() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let input = Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "peer-1".into(),
display_identity: None,
runtime_id: None,
},
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::Message),
content: "hi".into(),
payload: None,
handling_mode: Some(meerkat_core::types::HandlingMode::Steer),
});
let outcome = driver.accept_input(input).await.unwrap();
assert!(
outcome.is_accepted(),
"Message with handling_mode=Steer must be accepted"
);
if let meerkat_runtime::AcceptOutcome::Accepted { policy, .. } = outcome {
assert_eq!(
policy.routing_disposition,
meerkat_runtime::RoutingDisposition::Steer
);
}
}
#[test]
fn post_admission_signal_ordering() {
assert!(PostAdmissionSignal::None < PostAdmissionSignal::WakeLoop);
assert!(PostAdmissionSignal::WakeLoop < PostAdmissionSignal::InterruptYielding);
assert!(
PostAdmissionSignal::InterruptYielding < PostAdmissionSignal::RequestImmediateProcessing
);
}
#[test]
fn post_admission_signal_should_wake() {
assert!(!PostAdmissionSignal::None.should_wake());
assert!(PostAdmissionSignal::WakeLoop.should_wake());
assert!(PostAdmissionSignal::InterruptYielding.should_wake());
assert!(PostAdmissionSignal::RequestImmediateProcessing.should_wake());
}
#[test]
fn post_admission_signal_should_interrupt_yielding() {
assert!(!PostAdmissionSignal::None.should_interrupt_yielding());
assert!(!PostAdmissionSignal::WakeLoop.should_interrupt_yielding());
assert!(PostAdmissionSignal::InterruptYielding.should_interrupt_yielding());
assert!(PostAdmissionSignal::RequestImmediateProcessing.should_interrupt_yielding());
}
#[test]
fn post_admission_signal_should_process_immediately() {
assert!(!PostAdmissionSignal::None.should_process_immediately());
assert!(!PostAdmissionSignal::WakeLoop.should_process_immediately());
assert!(!PostAdmissionSignal::InterruptYielding.should_process_immediately());
assert!(PostAdmissionSignal::RequestImmediateProcessing.should_process_immediately());
}
#[tokio::test]
async fn post_admission_signal_accumulates_strongest() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let prompt = make_prompt_input("hello");
let outcome = driver.accept_input(prompt).await.unwrap();
assert!(outcome.is_accepted());
assert_eq!(
driver.take_post_admission_signal(),
PostAdmissionSignal::WakeLoop
);
}
#[tokio::test]
async fn post_admission_signal_steer_is_request_immediate() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let steer_input = Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "p".into(),
display_identity: None,
runtime_id: None,
},
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::Message),
content: "urgent".into(),
payload: None,
handling_mode: Some(meerkat_core::types::HandlingMode::Steer),
});
let outcome = driver.accept_input(steer_input).await.unwrap();
assert!(outcome.is_accepted());
assert_eq!(
driver.take_post_admission_signal(),
PostAdmissionSignal::RequestImmediateProcessing
);
}
#[tokio::test]
async fn post_admission_signal_queue_peer_message_while_running_interrupts_yielding() {
let mut driver = EphemeralRuntimeDriver::new(LogicalRuntimeId::new("test"));
let prompt = make_prompt_input("start");
let _ = driver.accept_input(prompt).await.unwrap();
let _ = driver.take_post_admission_signal();
bind_running(&mut driver, RunId::new(), RuntimeState::Idle);
let peer = Input::Peer(PeerInput {
injected_context: Vec::new(),
sender_taint: None,
header: InputHeader {
id: InputId::new(),
timestamp: Utc::now(),
source: InputOrigin::Peer {
peer_id: "p".into(),
display_identity: None,
runtime_id: None,
},
durability: InputDurability::Durable,
visibility: InputVisibility::default(),
idempotency_key: None,
supersession_key: None,
correlation_id: None,
},
convention: Some(PeerConvention::Message),
content: "interrupt me".into(),
payload: None,
handling_mode: None,
});
let outcome = driver.accept_input(peer).await.unwrap();
assert!(outcome.is_accepted());
let signal = driver.take_post_admission_signal();
assert_eq!(
signal,
PostAdmissionSignal::InterruptYielding,
"queue-mode peer message while running should request cooperative interrupt, got {signal:?}"
);
}
#[test]
fn post_admission_signal_request_immediate_ordering() {
assert!(PostAdmissionSignal::None < PostAdmissionSignal::WakeLoop);
assert!(PostAdmissionSignal::WakeLoop < PostAdmissionSignal::InterruptYielding);
assert!(
PostAdmissionSignal::InterruptYielding < PostAdmissionSignal::RequestImmediateProcessing
);
assert!(!PostAdmissionSignal::WakeLoop.should_process_immediately());
assert!(!PostAdmissionSignal::InterruptYielding.should_process_immediately());
assert!(PostAdmissionSignal::RequestImmediateProcessing.should_process_immediately());
}
#[test]
fn post_admission_signal_dsl_effect_carries_typed_variant() {
use meerkat_runtime::meerkat_machine::dsl::{MeerkatMachineEffect, PostAdmissionSignalKind};
fn map(signal: PostAdmissionSignalKind) -> PostAdmissionSignal {
match signal {
PostAdmissionSignalKind::WakeLoop => PostAdmissionSignal::WakeLoop,
PostAdmissionSignalKind::InterruptYielding => PostAdmissionSignal::InterruptYielding,
PostAdmissionSignalKind::RequestImmediateProcessing => {
PostAdmissionSignal::RequestImmediateProcessing
}
}
}
for (variant, expected) in [
(
PostAdmissionSignalKind::WakeLoop,
PostAdmissionSignal::WakeLoop,
),
(
PostAdmissionSignalKind::InterruptYielding,
PostAdmissionSignal::InterruptYielding,
),
(
PostAdmissionSignalKind::RequestImmediateProcessing,
PostAdmissionSignal::RequestImmediateProcessing,
),
] {
let effect = MeerkatMachineEffect::PostAdmissionSignal { signal: variant };
let MeerkatMachineEffect::PostAdmissionSignal { signal } = effect else {
panic!("constructed effect did not round-trip as PostAdmissionSignal");
};
assert_eq!(map(signal), expected);
}
}